Skip to content
Metamynd
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_agent_tool wraps the tool, so the only path to the real function that the agent is given goes through the gate. The graph itself is unchanged. The wrapper runs in your own process and is cooperative; the separate gateway process is the enforcement boundary.

01

How it works

Wrap the tool you'd hand to your ToolNode with guard_agent_tool() from the Python reference client. Everything else stays ordinary LangGraph: the model still decides when to call it and the state shape is unchanged. The only new outcome is a refusal, which comes back as that call's ToolMessage (a GovernanceRefusal with its reason code) so the model can explain it and the turn completes.

02

What to notice

  • The tool itself never imports anything governance-related
  • A refusal is the call's result, not an exception: the model reads the reasonCode and can explain it or ask for approval
  • Parallel tool calls are safe: ToolNode runs a turn's sync tools in threads, and with guard_agent_tool one refusal no longer aborts the turn while sibling calls run on unobserved
  • Code that calls a tool itself (not through the model) uses guard_tool instead, which raises GovernanceBlocked — never a value it could mistake for a booking
  • 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 langgraph.prebuilt import ToolNode
from metamynd_client import MetaMyndClient, guard_agent_tool

client = MetaMyndClient.from_env()

# Your tool, unchanged and unaware it is governed.
def book_flight(airline: str, amount: float, route: str) -> dict:
    """Book a flight and charge the corporate card."""
    ...

# The governed one. Give THIS to your ToolNode. A refusal comes back as
# the call's result (a GovernanceRefusal the model reads), never a crash.
governed_book_flight = guard_agent_tool(
    client, "flight-purchase", book_flight,
    lambda airline, amount, route: {"amount": amount, "merchant": airline,
                                    "context": {"riskLevel": "low"}},  # state an honest one
)

# An ordinary LangGraph graph. Nothing about the wiring changes.
tools = ToolNode([governed_book_flight])

Prepare your organisation for the Agentic Economy