Netzilo AI Detection & Response (AIDR) — governance for Python AI agents.
Project description
netzilo (Python)
Netzilo AI Detection & Response(AIDR) for Python
Provides full governance for custom AI agents written in Python
How it works
The Netzilo client is compiled to a native shared library and loaded in-process
via ctypes. Every LLM prompt, model response, and tool call your agent makes can
be evaluated — allowed, blocked, or redacted — against policy pulled live from your
Netzilo management server. No daemon, no sidecar — nothing to stand up.
Install
pip install netzilo
Wheels are published per platform (Linux, macOS, Windows) and are independent of your Python version.
Core API
import netzilo
netzilo.start(server="https://srv.netzilo.com", # management server
pat="nzl_...", # or setup_key="..."
agent_name="my-agent") # non-blocking
netzilo.is_running() # -> bool: True once policy has synced (ready to govern)
netzilo.mcp_gateway_port() # -> int: scanner gateway port in use (auto-picked)
allowed, reason = netzilo.is_allowed("Bash", {"command": "rm -rf /"})
netzilo.report_result("Bash", "<stdout>") # post-tool observability
netzilo.flush() # force-deliver buffered events to management
netzilo.snapshot() # force AIDR behavior-graph snapshot + delivery (else hourly/at-stop)
netzilo.stop() # graceful stop (snapshots graph + flushes events; auto-registered atexit)
Parameters may be passed as keyword args (above) or a single config dict.
config_path defaults to ~/.netzilo-sdk/config.json; ports auto-pick free
ports (governance on by default). is_running() returns True only after the
initial policy sync — poll it before kicking off work.
Evaluation runs inside the process — evaluate() calls the embedded engine
directly, with no HTTP roundtrip and no local port to manage.
Advanced governance (enable_advanced_governance=True)
Framework adapters (below) govern at the tool/LLM-hook layer. Advanced governance adds deep inspection of the agent's own outbound traffic — covering every prompt, response, and tool call (including from subprocesses and libraries you have no hook for), with full content analysis and semantic classification:
netzilo.start(server=..., pat=..., agent_name=..., enable_advanced_governance=True)
It is fully automatic and requires no root and no changes to the host — the
SDK prepares the process so the agent's traffic is inspected and continues to
work normally. Inspected prompts/responses are analyzed and classified, emitting
semantic.event records to your dashboard alongside the usual tool/LLM events.
Default off; the framework adapters govern without it.
Framework adapters
Adapters are submodules of the one netzilo package — no separate installs.
The framework is imported lazily inside each adapter (where it's imported at
all — see below), so pip install netzilo never pulls in a framework you
don't use.
Process-wide hooks
Register once; every tool call and LLM call made through the framework is governed from then on — no per-tool wrapping needed.
# CrewAI — registers before/after tool and LLM hooks process-wide
from netzilo.crewai import govern
govern(config={...})
# LangGraph — wrap nodes before compile()
import netzilo.langgraph
netzilo.langgraph.govern(graph, config={...})
# AutoGen — intervention handler
from netzilo.autogen import handler
runtime = SingleThreadedAgentRuntime(intervention_handlers=[handler(config={...})])
See CrewAI: local vs CrewAI AMP below for CrewAI's two deployment modes.
Tool-decorator frameworks
Where a framework's "tool" is a plain function wrapped by a decorator or a
from_function()-style constructor, govern_tool() wraps the function itself.
Apply it closer to the function than the framework's own decorator so schema
inference still sees the original signature (functools.wraps preserves it):
from netzilo.llamaindex import govern, govern_tool
from llama_index.core.tools import FunctionTool
govern() # starts the embedded client once, at boot
@govern_tool
def get_order_status(order_id: str) -> str:
...
tool = FunctionTool.from_defaults(fn=get_order_status)
The same pattern covers netzilo.langchain, netzilo.openai_agents (OpenAI
Agents SDK), netzilo.google_adk, netzilo.pydantic_ai,
netzilo.semantic_kernel, netzilo.smolagents, and netzilo.haystack — swap
the import and the framework's own tool constructor/decorator, everything else
is the same. netzilo.tools provides the same govern_tool() for any
framework without a dedicated module. netzilo.langchain additionally exposes
govern_model() for full prompt/response redaction at the LangChain chat-model
boundary — see that module's docstring.
Raw LLM clients
For agents calling a provider's SDK directly with no framework in between,
govern_client() patches the one call that sends a prompt so it's gated and
redacted in place, then hands back the same client:
from netzilo.openai_sdk import govern, govern_client
from openai import OpenAI
govern()
client = govern_client(OpenAI())
resp = client.chat.completions.create(
model="gpt-4o", messages=[{"role": "user", "content": "..."}]
)
Also available: netzilo.anthropic_sdk, netzilo.bedrock (AWS Bedrock
runtime), netzilo.gemini (Google GenAI), netzilo.mistral — same
govern() / govern_client() shape for each provider's own client and method.
Hook / middleware integrations
# LiteLLM — a CustomLogger registered into litellm.callbacks
from netzilo.litellm import govern, handler
import litellm
govern()
litellm.callbacks = [handler()]
# MCP — governs tool calls made through a ClientSession
from netzilo.mcp_client import govern, govern_session
session = govern_session(ClientSession(read_stream, write_stream))
# Guardrails AI — Netzilo as a Validator, composes with a Guard's own pipeline
from guardrails import Guard
from netzilo.guardrails import govern, validator
guard = Guard().use(validator(on_fail="fix"))
CrewAI: local vs CrewAI AMP
Local / self-hosted — put govern() once at the top of your entrypoint,
before kickoff(). That's it.
import netzilo.crewai
netzilo.crewai.govern(config={"server": "...", "pat": "...", "agent_name": "my-agent"})
MyCrew().crew().kickoff(inputs={...}) # governed
CrewAI AMP — AMP's managed runtime only executes Flow @start/@listen
methods; it skips module-level code, lifecycle hooks, and tool bodies. So the
same govern() call goes inside a Flow @start step, then your crew runs in
@listen. Deploy with [tool.crewai] type = "flow" in pyproject.toml, and
always create the automation fresh as a flow (the type is locked at creation
— re-pushing cannot convert an existing crew automation).
from crewai.flow import Flow, listen, start
import time
class MyFlow(Flow):
@start()
def init_governance(self):
import netzilo, netzilo.crewai
netzilo.crewai.govern(config={"server": "...", "pat": "...", "agent_name": "my-agent"})
while not netzilo.is_running(): # wait until policy has synced
time.sleep(0.5)
@listen(init_governance)
def run(self):
return MyCrew().crew().kickoff(inputs={...}) # governed
Optional convenience extras pull a framework alongside netzilo, e.g.
pip install netzilo[crewai], netzilo[langgraph], netzilo[llamaindex],
netzilo[bedrock] — see [project.optional-dependencies] in pyproject.toml
for the full list (one per adapter above). None of these are required: every
adapter imports its framework lazily, so the extra is a convenience, not a
dependency of the adapter itself.
Configuration
start() / govern() accept a config dict. Common keys:
| Key | Description |
|---|---|
server |
Your Netzilo management server URL. (management_url is a legacy alias.) |
pat / setup_key |
Credential used to enroll the agent. |
agent_name |
Identifier this agent reports as (used for event attribution). |
config_path |
Local client state (default: ~/.netzilo-sdk/config.json). |
mcp_gateway_port |
Optional; defaults to an auto-picked free port. mcp_gateway_port=0 disables governance. |
enable_advanced_governance |
Optional (default off). Deep inspection of the agent's own outbound traffic with semantic classification. |
log_level / log_file |
Logging verbosity and destination. |
Notes
The native library is bundled inside the wheel; pip selects the correct one for your platform automatically. Adapters ship inside the same wheel as submodules — a single distribution, not per-framework packages.
Netzilo is a commercial product. See https://www.netzilo.com.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file netzilo-4.3.15-py3-none-win_amd64.whl.
File metadata
- Download URL: netzilo-4.3.15-py3-none-win_amd64.whl
- Upload date:
- Size: 26.0 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
915f69d42ec3fbf19e526213f73f16f10eb3eac8d983b6bbe70fe1c24beca3b5
|
|
| MD5 |
5561c25dad5a91101c04f65db49cc1cc
|
|
| BLAKE2b-256 |
5e8e66107bdedc78ffb1398c22e299a99b5e3ede80c78d968b75eeb93dbf5193
|
File details
Details for the file netzilo-4.3.15-py3-none-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: netzilo-4.3.15-py3-none-manylinux_2_28_x86_64.whl
- Upload date:
- Size: 34.5 MB
- Tags: Python 3, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5d0c24ec88f555c9edf47f0ba02504747ee30b6811d3fe4083234f63210b7b43
|
|
| MD5 |
45c78201a78a50d2a00fef1d5d66bdb4
|
|
| BLAKE2b-256 |
dd27d5efdecda7debaf6d4bfae3d569c9d26fdf276824673f5eea016a7da5f41
|
File details
Details for the file netzilo-4.3.15-py3-none-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: netzilo-4.3.15-py3-none-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 31.8 MB
- Tags: Python 3, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8c3c3974639643bf5879b6e395b5a7079377e8d185c38c79ef5be401415927f7
|
|
| MD5 |
c25f0973031c2e08ceae5e09341d767e
|
|
| BLAKE2b-256 |
9546c3a942e52901e29d32598f223e35f3c47efa9c35dc501c80a0c6b6a459ee
|
File details
Details for the file netzilo-4.3.15-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: netzilo-4.3.15-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 23.5 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ad11245756f7d573056c1292f9f36c8bc8af96ed122410a375c29153fcfc8464
|
|
| MD5 |
14d23afcc136e7f8c837d22deefc19cd
|
|
| BLAKE2b-256 |
5b483217892e3b4ecc73c65ba92073ad2dac3729afb6c9f4b553c4a1ee715b76
|
File details
Details for the file netzilo-4.3.15-py3-none-macosx_10_13_x86_64.whl.
File metadata
- Download URL: netzilo-4.3.15-py3-none-macosx_10_13_x86_64.whl
- Upload date:
- Size: 25.4 MB
- Tags: Python 3, macOS 10.13+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dc6a6b20ceccb0abfb1b978410d0a14864f1276edcf8c967a359dccc8f9af304
|
|
| MD5 |
5817c9b66201fce6cc072b7d2512dc6c
|
|
| BLAKE2b-256 |
3c86429eedf2a25ce7959b5d2a80cb489858626e9d01ea7736410a1264d9d971
|