Skip to content
Browse documentation

Integrating LangChain

Wrap your tool array once with `guard.wrap()`. Every tool call, including ones you add next month, is governed at the boundary.

The integration point is the tool-executor boundary, not each tool. Wrapping individual tools is the most common integration mistake — the tool someone adds in a hurry next month is the one that ends up ungoverned.

Install

TerminalShell
$ pip install cirvix

Wrap the tool list

agent.pyPython
from langchain.agents import AgentExecutorfrom cirvix.integrations.langchain import guard tools = guard.wrap(    my_langchain_tools,    agent="pr-triage",    environment=os.environ.get("CIRVIX_ENV", "local"),    policy_dir="./policies",) executor = AgentExecutor(agent=agent, tools=tools)result = executor.invoke({"input": "Summarize PR #4821"})

Denials become observations, not crashes

A denied call raises CirvixDenied at the tool boundary, which the wrapper converts into a tool observation the agent's next planning step can see — the same denial shape as every other SDK and the CLI.

Denial shapePython
# Observation returned to the agent, not an unhandled exception:{    "error": "cirvix.policy.denied",    "policy": "deny-dotenv-read",    "reason": "Reading .env* is denied outside an approved secrets flow.",    "remediation": 'secrets.get("STRIPE_KEY")',}
Note
LangGraph nodes wrap the same way — guard.wrap() on a node's tool list rather than the whole graph.
Edit this page on GitHub
Was this page helpful?