aer1-langgraph
AER-1 verifiable workflow receipts for LangGraph multi-agent swarms.
Attach one callback handler to your graph and every run emits a hash-chained,
offline-verifiable verifiable workflow receipt (AER-1, Section 8):
which agent did what, in what order, with per-step hashes and one Merkle root
over the whole swarm. Parallel Send branches are recorded with their true
branch structure, not flattened. No network calls, no behavior changes, the
handler only observes.
Install
pip install aer1-langgraph
Use it (three lines)
from aer1_langgraph import AER1LangGraphHandler
handler = AER1LangGraphHandler(goal="Triage the support queue") # line 1
result = app.invoke({"tickets": [...]}, config={"callbacks": [handler]}) # line 2
receipt = handler.finalize(final_answer=result) # line 3
assert handler.verify(receipt) == [] # VALID
handler.save("receipt.json", workflow=receipt)
That is the whole integration. The receipt is a plain JSON object you can store, ship to an auditor, or render in a UI.
Swarm receipts
Each node execution becomes one receipt step carrying the node name as
agent identity (tool and agent on every step). A three-agent swarm
with two parallel workers produces steps like:
seq=1 tool=router agent=router
seq=2 tool=worker agent=worker branch=worker:9f3a...
seq=3 tool=worker agent=worker branch=worker:41bc...
seq=4 tool=aggregator agent=aggregator
Steps carry run_id, parent_run_id, and the LangGraph checkpoint
namespace, so the true execution graph (who ran in parallel under whom)
is reconstructible from the receipt. handler.swarm_summary() returns
the agent roster, step counts, and branch groups in one call.
Tool calls and model calls inside a node are folded into that node's
step: the step's receipt_hash is SHA-256 over the canonical JSON of
the node name, inputs, outputs, tool calls (name, arguments, output),
model-call summaries, branch metadata, and any error. The hash commits
to what the agent actually did; the receipt stays compact.
What the receipt contains
Workflow level (AER-1 Section 8, Table 2):
type,version,workflow_id,receipt_id,session_idgoal,statussteps: one record per node execution, seq 1..n in completion ordermerkle_root: Section 8.1 root over the ordered step receipt idsoutput_hash: SHA-256 of the final graph outputverify_url: where the verification procedure is documented
Step level (AER-1 Section 8, Table 3, plus swarm fields):
seq,receipt_id,tool(= node name),receipt_hashstarted_at,ended_at,statusagent,run_id,parent_run_id,checkpoint_nstool_calls,llm_calls(folded records)
Verification
handler.verify(receipt) runs the full offline check and returns a
list of failure reasons, empty when valid:
- all Table 2 / Table 3 members present and well-formed
seqvalues exactly 1..n in order, no gaps- no two steps share a
receipt_id(MM-1) merkle_rootmatches the recomputed Section 8.1 root- strict RFC 3339 timestamps, lowercase UUIDs, 64-char hex digests
Tamper with any field and verification fails. Try it:
receipt["steps"][0]["tool"] = ""
assert handler.verify(receipt) != [] # fails, as it should
Notes
- One handler observes one run at a time. Call
handler.reset()or construct a fresh handler before the next run. If a new root graph run starts on a handler that already finished one, it auto-resets so two runs never mix into one receipt. - The
__start__/__end__pseudo-nodes are machinery, not agent work, and are not recorded as steps. Conditional-edge router functions are user code and are recorded. - Steps still in flight when
finalize()runs (interrupted runs) are flushed asstatus: "incomplete"rather than dropped. session_iddefaults to a fresh UUID per handler; pass your own to correlate receipts across runs.verify_urldefaults to the AER-1 specification page; point it at your own verifier in production.
Spec
AER-1: Agent Execution Receipts, draft-zambo-aer1,
https://datatracker.ietf.org/doc/draft-zambo-aer1/
License
Apache-2.0
Metadata
Release files for aer1-langgraph 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| aer1_langgraph-0.1.0.tar.gz | 14.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aer1_langgraph-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 24.4 kB
Release files / aer1_langgraph-0.1.0.tar.gz
| Download URL | aer1_langgraph-0.1.0.tar.gz |
|---|---|
| Size | 14.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7a86925e0738ebd7f25c8e747e7c0724f62f9fc4a6130959ca60f5ededee42af
|
|
BLAKE2b-256 checksum How to use checksums |
d408fb1ed97a3b96ac09664e94899b6d4539c573316ac3561c002d0d0ce00a1b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
rambo-pypi-grab/0.1.0
|
Release files / aer1_langgraph-0.1.0-py3-none-any.whl
| Download URL | aer1_langgraph-0.1.0-py3-none-any.whl |
|---|---|
| Size | 10.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
44e54afa3c764f02e1ab0ab6b411b0cd29fde649094d4f4957bab1140489b7b0
|
|
BLAKE2b-256 checksum How to use checksums |
90edad4734b5cc390e619248d382b144af9fee4a0804e7ed6e124469fb97a313
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
rambo-pypi-grab/0.1.0
|