Quickstart · Docs · Discord · Report a bug
Your LangGraph agent calls interrupt(). Now what?
Deliberate turns it into an approval request a non-engineer can actually answer — with notifications, timeouts, structured audit trails, and UIs built for the people who actually sign off.
LangGraph made interrupt() a first-class primitive. That solved the runtime half of human-in-the-loop — the graph pauses, state is checkpointed, and execution resumes with Command(resume=...).
The organizational half is still yours to build:
- Nobody gets notified. The thread sits in the checkpointer. If your approver isn't watching the terminal, they don't know you're waiting on them.
- Nothing times out. A graph paused 3 weeks ago is indistinguishable from one paused 30 seconds ago.
- There's no audit log. State is persisted, but who decided, when, why, with what context — that record doesn't exist unless you build it.
- Your approver is probably not an engineer. But the only interface LangGraph gives them is your Python REPL.
Deliberate fills that gap — everything between your agent paused and your agent resumes.
1. Run Deliberate
git clone https://github.com/beomwookang/deliberate.git
cd deliberate
docker compose upDeliberate is running on http://localhost:4000.
2. Install the SDK (and optionally the MCP server)
pip install deliberate
# Optional: connect Claude Code / Cursor to your Deliberate instance
pip install deliberate-mcp
# or: uvx deliberate-mcp (no install required)3. Wrap your LangGraph node
from deliberate import approval_gate
from langgraph.types import interrupt
@approval_gate(
layout="financial_decision",
notify=["email:[email protected]", "slack:#finance-approvals"],
policy="policies/refund.yaml",
)
def process_refund(state):
return interrupt({
"customer": state.customer,
"amount": state.amount,
"agent_reasoning": state.reasoning,
"evidence": state.evidence,
})That's it. When the graph reaches this node, Deliberate routes the approval, notifies the right person, and waits — then hands the decision back to your graph.
See the full quickstart or grab a working example.
Different decisions need different information architecture. A finance lead approving a refund doesn't need the same layout as a legal reviewer redlining a contract. Deliberate ships with 6 layouts tuned for the domains where HITL matters most.
Need something else? Build a custom layout — layouts are just React components that consume a typed payload schema.
Deliberate is designed to be managed by AI coding assistants, not just humans editing YAML files.
- Admin REST API — Full CRUD for policies, approvers, groups, and API keys. Test a policy against a sample payload before deploying it. See Admin API Reference.
- MCP Server —
pip install deliberate-mcporuvx deliberate-mcp. Connects Claude Code, Cursor, and Windsurf directly to your Deliberate instance. 17 tools covering every admin operation. See MCP Server Guide. - Scoped RBAC — 11 scopes, 4 predefined roles (
agent,readonly,operator,admin), API key formatdlb_ak_*. See RBAC Guide. - llms.txt — Machine-readable project summary at
/llms.txtfor LLM context windows. - OpenAPI — Interactive docs at
GET /docs, machine-readable spec atGET /openapi.json.
- Multi-channel notifications — Slack, Email, or Webhook. Pick one, or fan out to all three.
- Timeouts and escalation — Approver didn't respond in 4h? Auto-escalate to the backup or fail gracefully.
- YAML policy routing — Declare who approves what based on payload. Auto-approve small amounts, require two sign-offs for big ones.
- Admin REST API — Manage policies, approvers, groups, and API keys programmatically. No YAML editing required.
- Audit ledger — Append-only, hash-chained, with JSON/CSV export. Every decision structured and tamper-evident.
- OTLP export — Feed ledger events into Langfuse, Phoenix, or any OTLP-compatible collector.
- Prometheus metrics —
/metricsendpoint with interrupts, decisions, duration, timeouts, escalations. - Approver identity — Magic link email verification. No more
anonymous@in your audit trail. - Mobile-first approver UI — Because your finance lead approves from their phone in meetings.
- LangGraph native — Built directly on
interrupt()andCommand(resume=...). No adapters, no abstractions to learn.
sequenceDiagram
participant Agent as LangGraph Agent
participant Server as Deliberate Server
participant Approver
Agent->>Server: interrupt() + @approval_gate
Server->>Server: Evaluate YAML policy
Server->>Approver: Notify (Slack / Email / Webhook)
Approver->>Server: Open signed approval link
Approver->>Server: Submit structured decision
Server->>Server: Write to append-only ledger
Server->>Agent: Command(resume=decision)
- The SDK captures the payload and posts it to Deliberate's server.
- Deliberate evaluates your YAML policy to resolve approvers, timeout, and escalation rules.
- Notifications fire to the configured channels with a signed JWT approval link.
- The approver opens the link, sees the layout you configured, and submits a structured decision.
- Deliberate writes the decision to the append-only ledger and resumes your graph.
- Your agent picks up exactly where it paused.
The graph state lives in LangGraph's checkpointer. The approval state, audit trail, and policy evaluation live in Deliberate's Postgres. The two stay synchronized through the LangGraph thread ID.
Deliberate isn't a replacement for LangGraph's HITL primitives — it builds on them.
LangGraph gives you interrupt(), Command(resume=...), and a checkpointer. That's the low-level runtime, and it's excellent. What LangGraph deliberately doesn't ship (by design, since every team's notification stack and audit requirements are different) is the layer that turns an interrupted thread into an actual request a human sees, responds to, and leaves a record of.
That layer is Deliberate. Use LangGraph's interrupt() anywhere — Deliberate only kicks in when you wrap a node with @approval_gate. Mix and match as you like.
Deliberate is at v0.1.0 (pre-release). The core flow (SDK → server → notifications → approval UI → resume → ledger) works end-to-end. Self-hosting is supported. Managed cloud is not yet available.
- Quickstart Guide — 15-minute install-to-first-approval
- Admin API Reference — full REST API for managing policies, approvers, groups, and keys
- MCP Server Guide — connect Claude Code or Cursor to your Deliberate instance
- RBAC Guide — scopes, roles, API key lifecycle
- Migration Guide — YAML to database migration (M5)
- Custom Layouts — build your own approval layouts
- Security & Threat Model — STRIDE analysis, key management, production recommendations
- Contributing — development setup and PR process
- Support for non-LangGraph agent frameworks. Our goal is to be the best approval layer for LangGraph specifically.
- BPMN-style multi-step workflows. If you need this, check out Camunda or Temporal.
- LangGraph — the agent runtime Deliberate builds on.
- Langfuse — LLM observability and tracing. Complementary: Langfuse records what the agent did; Deliberate records what the human decided.
- OpenTelemetry GenAI conventions — the spec we align ledger exports to.
We welcome contributions. Start here:
- Join the Discord to ask questions or share what you're building
- Read CONTRIBUTING.md to set up a dev environment
- Report bugs
- Vote on ideas on GitHub Discussions
Good first issues are tagged good-first-issue.
MIT. See LICENSE.





