Skip to content

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:

pip install git+https://github.com/ChelseaAIVentures/langgraph-kirokuforms.git

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"}
  • 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.