Framework Adapters
Each framework below gets governed at the boundary that framework actually exposes — a process-wide hook, or a per-tool wrapper. Pick your framework and language; the rest of this page follows the same shape everywhere: start Netzilo once, then wrap or register your tools as usual.
See Custom Agents first if you haven't installed the SDK or called start() yet.
CrewAI
from netzilo.crewai import govern
govern(config={"server": "...", "pat": "...", "agent_name": "my-agent"})
MyCrew().crew().kickoff(inputs={...}) # governed
CrewAI AMP (the managed runtime) only executes Flow @start/@listen steps, so put govern() inside a @start method instead:
from crewai.flow import Flow, listen, start
class MyFlow(Flow):
@start()
def init_governance(self):
import netzilo, netzilo.crewai
netzilo.crewai.govern(config={"server": "...", "pat": "...", "agent_name": "my-agent"})
@listen(init_governance)
def run(self):
return MyCrew().crew().kickoff(inputs={...})
LangGraph
import netzilo.langgraph
graph = StateGraph(State)
graph.add_node("agent", agent_fn)
graph.add_node("tools", tool_fn)
netzilo.langgraph.govern(graph, config={"server": "...", "pat": "..."}) # call before compile()
app = graph.compile()
app.invoke({...})
For full prompt/response redaction at the chat-model level:
from netzilo.langgraph import govern_model
model = govern_model(ChatAnthropic(model="claude-sonnet-4-6"))
agent = create_react_agent(model, tools) # redaction enforced end-to-end
AutoGen
from netzilo.autogen import handler
from autogen_core import SingleThreadedAgentRuntime
runtime = SingleThreadedAgentRuntime(
intervention_handlers=[handler(config={"server": "...", "pat": "..."})]
)
Strands / Bedrock AgentCore
from netzilo.strands import govern
govern() # config from NETZILO_* env vars; non-blocking
LangChain
from netzilo.langchain import govern, govern_tool
from langchain_core.tools import StructuredTool
govern()
@govern_tool
def get_order_status(order_id: str) -> str:
...
tool = StructuredTool.from_function(func=get_order_status)
Full prompt/response redaction at the chat-model level (Python only):
from netzilo.langchain import govern_model
model = govern_model(ChatAnthropic(model="claude-sonnet-4-6"))
LlamaIndex
from netzilo.llamaindex import govern, govern_tool
from llama_index.core.tools import FunctionTool
govern()
@govern_tool
def get_order_status(order_id: str) -> str:
...
tool = FunctionTool.from_defaults(fn=get_order_status)
OpenAI Agents SDK
from netzilo.openai_agents import govern, govern_tool
from agents import Agent, function_tool
govern()
@function_tool
@govern_tool
def get_order_status(order_id: str) -> str:
"""Look up an order's status."""
...
agent = Agent(name="Support", tools=[get_order_status])
Google ADK
from netzilo.google_adk import govern, govern_tool
from google.adk.tools import FunctionTool
govern()
@govern_tool
def get_order_status(order_id: str) -> str:
...
tool = FunctionTool(get_order_status)
Pydantic AI
from netzilo.pydantic_ai import govern, govern_tool
from pydantic_ai import Agent
govern()
@govern_tool
def get_order_status(order_id: str) -> str:
...
agent = Agent("openai:gpt-4o", tools=[get_order_status])
Semantic Kernel
from netzilo.semantic_kernel import govern, govern_tool
from semantic_kernel.functions import kernel_function
govern()
class OrdersPlugin:
@kernel_function(description="Look up an order's status")
@govern_tool
def get_order_status(self, order_id: str) -> str:
...
smolagents
from netzilo.smolagents import govern, govern_tool
from smolagents import tool
govern()
@tool
@govern_tool
def get_order_status(order_id: str) -> str:
"""Look up an order's status.
Args:
order_id: The order to look up.
"""
...
smolagents can run generated code in a remote sandbox (E2BExecutor / DockerExecutor) instead of locally. Netzilo only governs the local Python executor — tool code re-executed inside a sandbox container never loads the SDK.
Haystack
from netzilo.haystack import govern, govern_tool
from haystack.tools import create_tool_from_function
govern()
@govern_tool
def get_order_status(order_id: str) -> str:
"""Look up an order's status."""
...
tool = create_tool_from_function(get_order_status)
Vercel AI SDK
import { tool } from "ai";
import { z } from "zod";
import { wrapTool } from "netzilo/wrapTool";
const getOrderStatus = wrapTool(
"get_order_status",
async ({ orderId }: { orderId: string }) => fetchOrder(orderId)
);
const orderTool = tool({
description: "Look up an order's status",
parameters: z.object({ orderId: z.string() }),
execute: getOrderStatus,
});
Mastra
import { createTool } from "@mastra/core/tools";
import { z } from "zod";
import { wrapTool } from "netzilo/wrapTool";
const getOrderStatus = wrapTool(
"get_order_status",
async ({ orderId }: { orderId: string }) => fetchOrder(orderId)
);
const orderTool = createTool({
id: "get_order_status",
description: "Look up an order's status",
inputSchema: z.object({ orderId: z.string() }),
execute: async ({ context }) => getOrderStatus(context),
});
Any other framework
Every Python/JS agent framework's "tool" is ultimately a plain function the model calls with arguments. If your framework isn't listed above, gate at that same boundary directly:
from netzilo.tools import govern, govern_tool
govern()
@govern_tool
def get_order_status(order_id: str) -> str:
...
# Register get_order_status with your framework's tool registry exactly as
# you would the original function.
A blocked call raises NetziloBlockedError (Python) / throws NetziloBlockedError (TypeScript) instead of invoking the wrapped function. A tool result that trips a redaction rule (e.g. an AWS key or PII pattern) is returned to the agent already sanitized.
Optional Python extras install a framework alongside netzilo, e.g. pip install netzilo[crewai], netzilo[llamaindex], netzilo[bedrock] — none are required, since every adapter imports its framework lazily.

