Developers · LangGraph
Govern a LangGraph agent
Governance is not a node in your graph. A step the model chooses is a step the model can be talked out of choosing — which is the exact property that makes a prompt useless as a control. guard_tool wraps the tool, so the only path to the real function goes through the gate. The graph itself is unchanged.
01
How it works
Wrap the tool you'd hand to your ToolNode with guard_tool() from the Python reference client. Everything else about the node stays an ordinary LangGraph node — the model still decides when to call it, the state shape is unchanged, and the only new outcome is a GovernanceBlocked exception when the gate refuses.
02
What to notice
- The tool itself never imports anything governance-related
- A refusal (GovernanceBlocked) belongs back in the conversation state, not swallowed
- Deliberately leave read-only tools ungoverned — deciding which of yours are consequential is a design step nothing does for you
Example
See it in code
langgraph_agent.py
from metamynd_client import MetaMyndClient, guard_tool, GovernanceBlocked
client = MetaMyndClient.from_env()
# Your tool, unchanged and unaware it is governed.
def raise_purchase_order(vendor, amount, items):
...
# The governed one. Give THIS to your ToolNode.
governed_raise_po = guard_tool(
client, "purchase-order", raise_purchase_order,
lambda vendor, amount, items: {"amount": amount, "merchant": vendor},
)
# An ordinary LangGraph node. Nothing about the graph changes.
def call_tool(state):
try:
po = governed_raise_po(vendor="acme-supplies", amount=7_500, items="20x monitor")
return {**state, "result": f"raised {po['po']}"}
except GovernanceBlocked as refused:
# A refusal belongs back in the conversation, not swallowed.
return {**state, "result": f"refused - {refused.verdict.reason_code}"}