Control and graph patterns established practitioner

Stateful graph with branching and human approval

Explicit nodes and edges over typed, checkpointed state: the run branches on a condition, waits for a reviewer, and resumes later from where it stopped.

Established: described the same way by several independent primary sources and in wide production use. LangGraph and Microsoft Agent Framework both ship this shape as their core: a directed graph of nodes over shared state, conditional edges, checkpoints at step boundaries, and an interrupt that waits for a human. Cloudflare Workflows and Temporal give the same durability without the agent vocabulary.

Learning simulation

Input Ticket #482: rename the "Submit" button on the settings page to "Save changes". The short path: classify, implement, verify, ship. Two model calls, no human in the loop, every boundary checkpointed.

A change request enters a risk router. The low-risk edge goes straight to an implement ring, then a verify diamond, then a ship tool and the output. The high-risk edge drops to a plan ring, a checkpoint bar, and a reviewer double ring who can approve into implement, edit back into plan, or decline to the output. A typed state stack sits above the router; verify loops back to implement on failure.read/writelow riskhigh riskhigh riskwaitwaitapproveapproveediteditdeclinedeclinepasspassfail (≤2)fail (≤2)3rd failure3rd failureChange requestTyped staterisk · plan · attemptsRisk routerrules + modelImplementwrite the changePlandraft for reviewCheckpointstate savedReviewerapprove · edit · noVerifytests pass?Open PRdeterministicDone
ready
Every step in words
  1. An event starts the run. The request text goes into typed state as data: it is a ticket anyone could have written.

  2. The rules run first: no auth files, no migration, one file, under 20 lines. No model call was needed. The conditional edge "low risk" is taken; the decision is recorded in state so it can be audited.

  3. Every node boundary saves state and position. It is invisible in the happy path and is what makes the crash scenario boring.

  4. The agent node reads the request from state, finds the button, edits the label and writes state.diff. One model call, with the file in context.

  5. The test suite runs as code. Exit 0, so the conditional edge "pass" is taken. No model was involved in this decision.

  6. A deterministic tool creates the PR with the diff and the trace. It checks for an existing PR for this run id first, so a resume cannot open a second one.

  7. One model call for implement, none for classify. The engineer reviews the PR as usual; the graph never needed a human because the rules said it did not.

The problem it solves

A change request has to be classified, implemented, verified and, when risky, approved by a person who may answer tomorrow. A loop cannot wait a day, and a script cannot decide which path to take.

What the human needs
A reviewer wants to see the plan before risky work starts, approve or edit it on their own time, and trust that the run picks up where it paused.
What the agent does
Each node does one thing and writes to typed state. After each node a checkpoint is saved. A router sends low-risk changes straight to implementation and high-risk ones to a plan and a reviewer; the reviewer node pauses the run until a human answers, then the graph resumes.
What the human sees
The reviewer gets a notification with the plan, approves, edits or declines, and later sees the PR with the full trace. The engineer sees the graph position at any time.

After this page you can

  • Read a graph: nodes do work, edges decide what runs next, state is what they share.
  • Explain what a checkpoint buys: resume after a crash, wait for a human for hours, replay a run.
  • Tell a conditional edge (code decides) from a model decision (the agent decides).
  • See why a human approval step is a node that the run waits at, not a prompt instruction.

How it works

  1. A change request enters as an event and is written into typed state: request, risk, plan, attempts, decision.
  2. A router node classifies the risk. A conditional edge chooses the branch: low risk to implement, high risk to plan.
  3. On the high-risk branch, the plan node drafts a plan, a checkpoint is saved, and the reviewer node pauses the run.
  4. The run can stay paused for hours. When the reviewer answers, the graph resumes from the checkpoint with the decision in state.
  5. The implement node writes the change; the verify node runs tests and returns to implement on failure, at most twice.
  6. The ship node opens a pull request; the run ends. Every node boundary was a checkpoint, so a crash anywhere resumes from the last one.

The baseline scenario in the stage above plays these steps with a worked example. Open "Every step in words" under the stage for the full trace, including why each step happened.

When to use it

  • The work must wait for a person, possibly for hours or days.
  • There are distinct paths and the business needs to know which one was taken.
  • The run must survive a crash or a deploy mid-way.
  • Side effects are real (PRs, deploys, payments) and must not repeat.

When not to

  • A single conversation with a developer present: a loop with a permission mode is enough.
  • The path is always the same: a plain function or a prompt chain.
  • Nobody will maintain the state schema and the checkpoint store.

Trade-offs

Reliability strong Checkpoints, bounded retries and explicit failure edges; the run cannot be lost or loop forever.
Latency middling Machine time is low; human waits dominate and are by design.
Cost strong Few model calls; rules handle the obvious cases and paused runs cost nothing.
Complexity weak A graph, typed state, a checkpointer and idempotent nodes to design and version. The highest engineering cost of the three hero patterns.
Observability strong Position, state and every edge taken are the trace; replay is built in.
Maintainability middling Adding a node is local; changing state shape touches every node and every stored checkpoint.
Security strong Approval is a node the run cannot skip; rules precede the model; side effects are idempotent.
Human control strong The reviewer decides on their own time with the plan in front of them, and the decision is recorded.

Three bars mean strong (or cheap); one bar means weak (or costly). Ratings are editorial and relative to the other patterns in this library, not measurements.

Security posture

Turn on Trust boundaries in the stage to see the zones on the diagram. The controls below sit on the nodes named; the "Break" scenarios show an attack and the control working.

ControlThreatWhere
Rules before the model in the routerDeterministic rules on code facts decide first; the model only breaks ties and cannot lower a rule-assigned risk. A prompt in the request steers the branch. classify[Anthropic]
Human approval as a nodeThe reviewer node is on the high-risk path; the run cannot reach implement without state.decision = approve. Risky changes land without a person seeing them. reviewer[LangChain]
Idempotent side effectsShip checks the run id before creating a PR; every side-effecting node is keyed by run id. Resume after a crash repeats an action. ship[LangChain]
Bounded retriesThe fail edge’s condition closes at the limit and the failure edge escalates. A failing cycle runs up cost. verify[HumanLayer (GitHub)]
Typed stateState has a schema with reducers; writes are validated at the boundary. A node writes malformed data that a later node acts on. state[Microsoft][LangChain]

Failure scenarios

FailureTrigger and effectRecovery
Process crashscenario: crash-resume The worker dies between nodes. In a loop, the run is lost. Resume from the last checkpoint; idempotent side effects.
Verification keeps failingscenario: tests-fail-twice The change breaks a test the agent cannot fix. An unbounded loop. A retry limit on the edge and a failure edge to the reviewer.
Misclassified risk A risky change is routed as low risk. It skips review. Rules before the model; the PR review is a second human look; audit the router’s decisions.
Instructions in the request The ticket body says "skip review". A model-only router might comply. The router’s rules read file paths and sizes, not the ticket’s wishes; the ticket is data.

Architecture and implementation

Inputs

event ChangeRequest
The trigger.
rules RiskRule[]
Deterministic classification rules evaluated before any model.
retryLimit number
Maximum implement–verify cycles.
checkpointer Checkpointer
Durable storage for state and position.

Outputs

pr PullRequest | null
The opened PR, or null when declined.
trace Step[]
Every node run, every edge taken, every pause and resume.
state State
The final state, including the review decision.

State schema

request { id, title, body, author }
The change request, as data.
risk 'low' | 'high' | null
Set by the router; read by the conditional edge.
plan Plan | null
Drafted on the high-risk path; approved, edited or declined by the reviewer.
attempts number
Implement–verify cycles so far; the retry edge closes at 3.
decision 'approve' | 'edit' | 'decline' | null
What the reviewer answered.
diff string | null
The change produced by implement.
lastError string | null
The verify log fed back to implement.
position NodeId
Where the run is; saved with every checkpoint.

Framework-neutral pseudocode

graph = Graph(State)                       # typed state with reducers
graph.node("classify", classify)           # rules, then model for ties
graph.node("plan", plan_agent)
graph.node("review", human_interrupt)      # pauses; resumes with the answer
graph.node("implement", implement_agent)
graph.node("verify", run_tests)
graph.node("ship", open_pr_idempotent)
graph.edge(START, "classify")
graph.conditional("classify", lambda s: "implement" if s.risk == "low" else "plan")
graph.edge("plan", "review")
graph.conditional("review", lambda s: {"approve": "implement", "edit": "plan", "decline": END}[s.decision])
graph.edge("implement", "verify")
graph.conditional("verify", lambda s: "ship" if s.passed else ("implement" if s.attempts < 3 else "review"))
graph.edge("ship", END)
app = graph.compile(checkpointer=durable_store)
app.invoke(event, thread_id=run_id)        # later: app.invoke(Command(resume=answer), thread_id=run_id)

In the frameworks

  • LangGraph StateGraph with a TypedDict/Pydantic state, add_conditional_edges, interrupt() inside the review node, a checkpointer (SQLite/Postgres) and Command(resume=...) to continue. [LangChain]
  • Microsoft Agent Framework WorkflowBuilder with executors and edges; type-validated messages; superstep execution with checkpointing at superstep boundaries; request/response for human input. [Microsoft]
  • Cloudflare Workflows / Agents Durable steps with automatic retries and a persisted wait for a human event; the agent holds state in a Durable Object. [Cloudflare]

Testing

  • Unit-test every conditional edge as a pure function of state.
  • Run the graph with a fake checkpointer and kill it after each node; assert the resumed run produces the same trace and no duplicate side effects.
  • Test the retry limit: three failing verifies end at the reviewer, never at implement.

Evaluation

  • Router accuracy against a labelled set of change requests; false low-risk rate is the metric that matters.
  • Time from request to PR, split into machine time and human wait time.
  • Reviewer edit and decline rates: a high edit rate means the plan node needs better context.

Deployment

  • Use a durable checkpointer from day one; in-memory checkpoints make the demo work and production fail.
  • Key every side effect by run id.
  • Version the graph; a resumed run must load the graph version it started with.

Where it helps in software delivery

  • 2 Requirements and planning strong fit

    The plan node and the reviewer node are a reviewed plan before any work starts: the requirement is restated, scoped and approved by a person, and the approval is recorded in state.

    Example Every risky ticket produces a written plan with files, approach and rollback that the tech lead edits or approves before implementation.

  • 3 Architecture and system design strong fit

    Deciding where the explicit structure belongs is an architecture decision; this pattern is the shape to compare the loop against.

    Example An ADR that records why the review step is a graph node and not a prompt instruction.

  • 4 Development and implementation central to this stage

    The change-request graph is the shape of an agentic development workflow with review built in.

    Example Tickets flow through classify, plan, review, implement, verify, PR.

  • 6 Security and compliance strong fit

    Approval on a defined path with a recorded decision is an audit trail by construction.

    Example Any change touching auth or secrets takes the high-risk branch; the decision and the approver are in the PR.

  • 7 Deployment and release central to this stage

    Release workflows need exactly this: conditional paths, a person who approves, durable waits, idempotent actions.

    Example A release graph that runs checks, waits for the release manager, deploys to a canary, waits for a health signal, then promotes or rolls back.

  • 8 Operations and monitoring strong fit

    Runbook automation with approval before each destructive step and resume after an interruption.

    Example An incident remediation graph: gather evidence, propose, wait for on-call, execute, verify.

Open the SDLC explorer to start from a stage instead.

What the human sees

The interaction patterns a person meets when this architecture runs. The run waits for a person at: Reviewer.

References and provenance

  1. Graphs of nodes and edges over shared state with durable execution and human-in-the-loop are the runtime’s core; it does not abstract architecture.

    framework LangGraph overview, LangChain, undated. Verified 2026-10-18.

  2. interrupt() pauses a run indefinitely at a node with state persisted; Command(resume) continues it.

    framework LangGraph interrupts (human-in-the-loop), LangChain, undated. Verified 2026-10-18.

  3. Checkpointers save state at every superstep, enabling resume, time travel and fault tolerance.

    framework LangGraph persistence, LangChain, undated. Verified 2026-10-18.

  4. Resumed runs replay from state; side effects must be idempotent and node code deterministic.

    framework LangGraph durable execution, LangChain, undated. Verified 2026-10-18.

  5. Workflows are typed graphs of executors and edges with validation at build time and checkpointing at superstep boundaries.

    framework Microsoft Agent Framework workflows: builder and execution, Microsoft, published 2026-10-15. Verified 2026-10-18.

  6. Routing with deterministic checks where possible; add structure only where the task needs it.

    evidence Building effective agents, Anthropic, Erik Schluntz and Barry Zhang, published 2024-12-19. Verified 2026-10-18.

  7. Contact humans with tool calls; launch, pause and resume with simple APIs; own the control flow.

    practitioner 12-Factor Agents: principles for building reliable LLM applications, HumanLayer (GitHub), Dex Horthy, undated. Verified 2026-10-18.

Published 2026-10-18 · observed 2026-10-18 · last verified 2026-10-18 · updated 2026-10-18 · v1 · review status: draft

Evidence kinds: evidence: evidence-backed recommendation from a primary source; convention: established industry convention; several sources agree; framework: how one framework implements it. version-specific; practitioner: a practitioner’s observation, not independently verified; emerging: an emerging technique with thin evidence; editorial: our interpretation.

Share: https://agentsandhumans.ai/agentic/patterns/stateful-graph · the stage's Share button links to a scenario and step; Export downloads the trace as JSON, labelled as a learning simulation.