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_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}"}

Prepare your organisation for the Agentic Economy