Two runtimes. One verdict.
The Node and Python evaluators are held to a shared conformance fixture, so an SDK and the gateway cannot quietly disagree about whether an action is allowed.
Node
The common pattern is guard.wrap: put the decision in front of the function you want governed, and leave the function itself alone.
import { guard } from "@cirvix_ai/agent-control"; const readFile = guard.wrap( { action: "read:file", agent_id: "agent-01" }, async (path) => fs.readFile(path, "utf8") ); // Denied calls throw before the body runs. // The decision is recorded either way. await readFile(".env"); // CirvixDenied: deny-dotenv-read
The gateway and the SDK share one decision core, so wrapping a call locally and routing it through the gateway produce the same verdict for the same request.
Python
The Python package (cirvix on PyPI) ships a native evaluator rather than a thin HTTP client, so local policy decisions require no round trip.
from cirvix import guard, CirvixDenied, CirvixHeld, STARTER_RULES def read_file(args): return open(args["path"]).read() # Wrap a tool map, sequence of LangChain/CrewAI tools, or single callable tools = guard.wrap( {"read_file": read_file}, agent="agent-01", rules=STARTER_RULES, ) try: tools["read_file"]({"path": ".env.production"}) except CirvixDenied as err: print(err.policy) # "deny-dotenv-read" print(err.decision_id) # "dec_..."
SDK Capability Matrix: Node.js vs. Python
Both SDKs share the canonical policy evaluator for covered inputs, but runtime capabilities differ fundamentally. Capabilities of one runtime must not be assumed in the other.
| Capability | Node.js (@cirvix_ai/[email protected]) |
Python (cirvix==0.3.1) |
Enforcement Path & Prerequisites |
|---|---|---|---|
| Local Policy Evaluation | Full Support | Full Support | In-memory rule evaluation; default-deny; shared conformance suite. |
Tool Wrapping (guard.wrap) |
Full Support | Supported (Tools) | Intercepts governed tool collections. Unwrapped tools bypass evaluation. |
| Hold Verdicts & Approvers | Full Support | Full Support | Raises CirvixHeld carrying approvers list when a rule matches hold. |
| Argument Transformation | Full Support | Denied by Guard | Python has no transformation engine; calls requiring sanitization are denied. |
| Result Scrubbing & Redaction | Full Support | Unsupported | Node scrubs tool return values on completion. Python returns output unmodified. |
| Secret-Handle Brokering & Vault | Full Support | Unsupported | Node includes local Vault and SecretsClient. Python has no Vault. |
| Audit-Chain Persistence | Opt-in Sink | Unsupported (Callback only) | Node requires passing AuditChain. Python offers only on_decision callback. |
| Built-in Approval Storage | Local JSONL | Unsupported | Node persists approval records. Python has no approval store or release helper. |
| MCP Gateway Transport | Full Support | Unsupported | Requires Node 20+ runtime via cirvix gateway CLI. |
| Telemetry & Remote Shipping | Supported (Configured) | Unsupported | Node includes endpoint Daemon for disk-spooled batch shipping when CIRVIX_API_URL/KEY is configured (disabled by default). Python has no daemon or shipping client (in-process on_decision only). |
Pre-built Ecosystem Plugins (10-Second Setup)
Drop Cirvix governance into leading developer tooling and multi-agent frameworks with zero architectural overhaul.
Custom MCP Gateway Flag
Register the Cirvix gateway as a Model Context Protocol tool provider in one terminal command:
# Auto-registers into Claude Code MCP registry
claude mcp add cirvix -- cirvix gateway --strict
All tool execution requests (bash, file edit, web access) pass through kernel and policy verification before reaching execution.
Silent Background Daemon
Install the official extension from the marketplace (cirvix.agentcontrol) or enable silent daemon boot in settings:
// .vscode/settings.json { "cirvix.daemon.autoStart": true, "cirvix.enforcePolicies": "strict", "cirvix.ipcSocket": "unix:///var/run/cirvix/ipc.sock" }
1-Line Python Middleware
Intercept tool calls, API egress, and state mutations across any Python agent framework with Guard.wrap():
from cirvix import Guard # 1-line wrap for LangChain, LlamaIndex, or CrewAI agents agent = Guard.wrap(raw_agent, agent_id="autonomous-analyst")
Framework Examples
from cirvix import Guard from crewai import Agent, Crew, Task from langchain.agents import create_openai_tools_agent # 1. Wrap LangChain Agent langchain_agent = create_openai_tools_agent(llm, tools, prompt) governed_agent = Guard.wrap(langchain_agent, agent_id="triage-agent") # 2. Wrap CrewAI Crew crew = Crew(agents=[dev_agent], tasks=[refactor_task]) governed_crew = Guard.wrap(crew, agent_id="dev-crew") # Any tool invocation that violates policy throws CirvixDenied # and records a hash-chained (unsigned) entry in the audit log.
Why a shared fixture
Two implementations of the same rule language will drift. The conformance fixture is the thing that stops that: a corpus of requests and expected verdicts that both engines must reproduce exactly.
It earns its keep. When the fixture was first run across both engines it immediately surfaced a real path-canonicalization difference on Windows — a case where the two evaluators would have disagreed about whether a resource matched.
| Guarantee | Enforced by |
|---|---|
| Same request, same verdict, either language | Shared conformance fixture, run in CI |
| SDK and gateway cannot disagree | One decision core, shared by both paths |
audit_only never authorizes | Evaluator, not policy convention |
| Glob patterns stay inside their segment | Literal matcher, covered by the fixture |
Not available
There is no Go, Java, or Ruby SDK today. If your runtime is not Node or Python, use the HTTP gateway or the Node runtime daemon / gateway — it is the same decision core behind a network boundary. We would rather say this plainly than list a language we have not built.
Bring every agent
under control.
Set durable policy, preserve a verifiable record, and give teams a safer way to put intelligent systems to work.