langgraph-guardrail
Policy enforcement and guardrails for LangGraph AI agents.
Define what your agent can and can't do in a simple YAML file. Every tool call gets checked before it executes. Dangerous actions get blocked. Suspicious actions get escalated for human approval. Every decision is recorded in a tamper-evident audit log.
Why
AI agents can now take real actions — send emails, query databases, call APIs, delete accounts. Without guardrails, a single misaligned decision can cost real money or leak real data. langgraph-guardrail gives you a single chokepoint where every action is checked against your rules, paused for human approval when needed, and cryptographically logged.
Install
pip install langgraph-guardrail
For LangGraph integration (uses interrupt() for human-in-the-loop):
pip install "langgraph-guardrail[langgraph]"
Requires Python 3.10+.
Quick Start
1. Create a policy file (policy.yaml):
version: "1"
tools:
query_data:
action: allow
send_email:
action: require_approval
reason: "External emails need human review"
delete_account:
action: block
reason: "Account deletion is forbidden for autonomous agents"
2. Load it and check tool calls:
from langgraph_guard import load_policy, guarded_tool_call, GovernanceBlockedError
policy = load_policy("policy.yaml")
try:
result = guarded_tool_call(
"delete_account",
{"user_id": 123},
policy,
my_delete_function,
)
except GovernanceBlockedError as e:
print(f"Blocked: {e}")
# -> Blocked: Tool 'delete_account' is blocked by policy: Account deletion...
LangGraph Integration
Use GuardNode inside any LangGraph graph for native human-in-the-loop:
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import END, START, StateGraph
from langgraph.types import Command
from langgraph_guard import load_policy, prompt_cli
from langgraph_guard.integrations.langgraph import GuardNode
policy = load_policy("policy.yaml")
guard = GuardNode(policy)
def send_email_node(state):
return {"result": guard.run("send_email", state["args"], _real_send_email)}
builder = StateGraph(State)
builder.add_node("send_email", send_email_node)
builder.add_edge(START, "send_email")
builder.add_edge("send_email", END)
graph = builder.compile(checkpointer=MemorySaver())
config = {"configurable": {"thread_id": "user-1"}}
# First pass — pauses at interrupt()
result = graph.invoke(initial_state, config=config)
# Human approves
payload = result["__interrupt__"][0].value
approved = prompt_cli(payload["tool_name"], payload["args"], payload.get("reason", ""))
# Resume the graph
final = graph.invoke(Command(resume=approved), config=config)
The graph pauses at the exact tool call, saves state to the checkpointer, and resumes seamlessly with the human's decision.
Audit Trail
Every decision is recorded in a hash-chained JSONL log. Tampering with any entry breaks the chain and is detected.
from langgraph_guard import AuditLog
from langgraph_guard.integrations.langgraph import GuardNode
audit = AuditLog("audit.jsonl")
guard = GuardNode(policy, audit=audit)
# After running your agent:
ok, failed_at = audit.verify()
assert ok, f"Tampering detected at sequence {failed_at}"
for entry in audit.tail(10):
print(f"{entry.sequence} | {entry.tool_name} | {entry.decision}")
Each entry stores its own SHA-256 hash and the hash of the previous entry. If anyone edits, removes, or reorders entries, verify() reports the exact sequence number where the chain breaks.
Policy Schema
version: "1"
tools:
<tool_name>:
action: allow | block | require_approval
reason: "optional explanation shown to humans and logs"
allow— the tool runs immediatelyblock— the tool never runs; the agent receives aBLOCKEDmessagerequire_approval— the graph pauses; a human decides, then the graph resumes
API Reference
load_policy(path: str) -> dict[str, ToolPolicy]
Load a YAML policy file. Raises PolicyError if malformed.
guarded_tool_call(tool_name, args, policy, tool_fn) -> Any
Execute a tool following policy. Raises:
GovernanceBlockedErrorif the policy saysblockApprovalRequiredErrorif the policy saysrequire_approvalToolNotFoundErrorif the tool isn't in the policy
GuardNode(policy, audit=None)
LangGraph integration. .run(tool_name, args, tool_fn) behaves like guarded_tool_call but uses interrupt() for approvals.
AuditLog(path)
Hash-chained audit log. Methods:
.append(tool_name, args, decision, reason="")— write an entry.verify() -> (bool, Optional[int])— check integrity.tail(n=10) -> list[AuditEntry]— recent entries
prompt_cli(tool_name, args, reason="") -> bool
Interactive terminal approval prompt.
Demos
examples/demo_mock.py— deterministic, shows all three branches in 10 secondsexamples/demo_agent.py— real LLM (Ollama) decides which tool to callexamples/demo_interrupt.py— full interrupt/resume flow with audit logging
Development
git clone https://github.com/Yuvarajunakal/langgraph-guardrail.git
cd langgraph-guardrail
python -m venv venv
venv\Scripts\activate # Windows
pip install -e ".[dev]"
pytest tests/ -v
Status
Alpha — the core API is stable, but expect additions. See CHANGELOG.md for what's shipped.
License
MIT — see LICENSE.
Metadata
Release files for langgraph-guardrail 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| langgraph_guardrail-0.1.2.tar.gz | 13.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| langgraph_guardrail-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 24.0 kB
Release files / langgraph_guardrail-0.1.2.tar.gz
| Download URL | langgraph_guardrail-0.1.2.tar.gz |
|---|---|
| Size | 13.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
554ed1e9d3a1a096bc452c67988ea2661accfaec85aa3ba357bbb2312c88b1e0
|
|
BLAKE2b-256 checksum How to use checksums |
ee7165f9c03bc18c0142c140aaf371893ab61c58217d267f560c95d1f50dde43
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|
Release files / langgraph_guardrail-0.1.2-py3-none-any.whl
| Download URL | langgraph_guardrail-0.1.2-py3-none-any.whl |
|---|---|
| Size | 10.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a1cfedfbf237f6fc9f71e4e3abf68e3676430fbf242d8e50940a1c2994550d35
|
|
BLAKE2b-256 checksum How to use checksums |
25858b78d5260759c1b23319d64fe8de81cc36733a8d8565992939c844a82ad9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.14.7
|