langgraph-kirokuforms¶
Pause a LangGraph run for a human, and carry on with their answer.
A workflow reaches a step only a person can decide: approve the invoice, check
the extraction, sign off the refund. LangGraph can suspend for that, with
interrupt(). What it deliberately does not do is the human half: how the person
is contacted, what they see, and how their answer gets back.
This library is that half. The review becomes a real page hosted by KirokuForms, the person gets a link, they answer, and the graph resumes with what they submitted.
The reviewer needs no account
Send a review to any email address. They open a link, answer, and that is it. No signup, no seat to buy, so the person who actually knows the answer can be the one who gives it.
Getting an API key¶
The library talks to KirokuForms, so it needs a key for an account there. Create one under Developer in the dashboard:
https://www.kirokuforms.com/dashboard/developer
There is a free tier, so this does not need a card to try.
Only answers are metered. A task you create does not count against anything; the reviewer's completed answer counts as one submission against the account's monthly allowance. The pricing page has the numbers per plan.
Install¶
Not on PyPI yet. From the repository:
The distribution is langgraph-kirokuforms; the import path is kirokuforms.
Needs Python 3.10+ and LangGraph 1.0+ (tested against 1.1.6).
The shape of it¶
from kirokuforms import (
KirokuFormsHITL,
create_kiroku_interrupt_node,
resume_with_answers,
)
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.graph import END, START, StateGraph
client = KirokuFormsHITL(api_key="your-api-key")
review = create_kiroku_interrupt_node(
client,
name="approval",
title="Approve the invoice",
description="Check the amount before we pay it.",
fields=[
{
"type": "radio",
"label": "Approve?",
"name": "approved",
"required": True,
"options": [
{"label": "Approve", "value": "yes"},
{"label": "Reject", "value": "no"},
],
},
],
)
builder = StateGraph(dict)
builder.add_node("review", review)
builder.add_edge(START, "review")
builder.add_edge("review", END)
# A checkpointer is required: interrupt() needs somewhere to suspend into.
graph = builder.compile(checkpointer=InMemorySaver())
config = {"configurable": {"thread_id": "invoice-42"}}
state = graph.invoke({"amount": 1200}, config)
payload = state["__interrupt__"][0].value
print(payload["form_url"]) # send this to the reviewer
Later, once they have answered:
final = graph.invoke(
resume_with_answers(client, payload["kiroku_task_id"]), config
)
final["human_verification"]["result"] # {"approved": "yes"}
What to read next¶
- Suspending a graph covers the re-execution rule, which catches everyone once, and why this library sends an idempotency key.
- Verifying webhooks if your callback endpoint should only trust deliveries that really came from KirokuForms.
- API reference is generated from the source.
- KirokuForms for LangGraph is the product side of this: what the reviewer sees, and what the service does with the answer once it has it.
Where the parts live¶
kirokuforms.graph |
The interrupt node and resume_with_answers |
kirokuforms.kirokuforms |
The REST client: create, poll, list, cancel |
kirokuforms.webhooks |
Signature verification |
LangGraph is imported lazily inside the node, so import kirokuforms works fine
if you only want the REST client.