JSPM

@controlzero/sdk

1.5.0
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 110
  • Score
    100M100P100Q72409F
  • License Apache-2.0

AI agent governance: policies, audit, and observability for tool calls. Works locally with no signup.

Package Exports

  • @controlzero/sdk
  • @controlzero/sdk/integrations

Readme

controlzero

AI agent governance for Node.js. Policies, audit, and observability for tool calls. Works locally with no signup.

Hello World

import { Client } from '@controlzero/core';

const cz = new Client({
  policy: {
    rules: [
      { deny: 'delete_*', reason: 'Hello World: deletes are blocked' },
      { allow: '*', reason: 'Hello World: everything else is fine' },
    ],
  },
});

console.log(cz.guard('delete_file', { args: { path: '/tmp/foo' } }).decision); // "deny"
console.log(cz.guard('read_file', { args: { path: '/tmp/foo' } }).decision); // "allow"

12 lines. No API key. No signup. Run it.

Install

npm install @controlzero/core
# or
pnpm add @controlzero/core
# or
yarn add @controlzero/core

Why

Your AI agents call tools. Some of those tools should never be called by an agent without a human in the loop. controlzero is the policy layer between the model's output and the tool execution. Decisions are fail-closed by default.

You can use it offline with a local YAML file or JS object. When you want to share policies across a team or get a hosted audit dashboard, sign up at controlzero.ai and set CONTROLZERO_API_KEY.

Quickstart with the CLI

# Use npx if you do not want a global install
npx -y @controlzero/core init

# Or after installing globally:
npm install -g @controlzero/core
controlzero init
controlzero validate
controlzero test delete_file

The generated controlzero.yaml is the tutorial. It ships with annotated rules covering allow lists, deny lists, wildcards, and the catch-all.

Templates available:

  • controlzero init — Hello World template (default)
  • controlzero init -t rag — RAG agent template (block exfiltration)
  • controlzero init -t mcp — MCP server template
  • controlzero init -t cost-cap — model allow-listing and cost guards

Loading a policy

Three ways:

import { Client } from '@controlzero/core';

// From a JavaScript object
const cz1 = new Client({
  policy: {
    rules: [{ deny: 'delete_*' }, { allow: 'read_*' }],
  },
});

// From a YAML file
const cz2 = new Client({ policyFile: './controlzero.yaml' });

// From an environment variable
// (set CONTROLZERO_POLICY_FILE=./controlzero.yaml)
const cz3 = new Client();

If ./controlzero.yaml exists in the current directory, it is picked up automatically. No env var needed.

Policy schema

version: '1'
rules:
  - deny: 'delete_*'
    reason: 'Deletes need human approval'
  - allow: 'search'
  - allow: 'read_*'
  - allow: 'github:list_*'
  - deny: 'github:delete_repo'
  - deny: '*'
    reason: 'Default deny'

Rules are evaluated top to bottom. The first match wins. If no rule matches, the call is denied (fail-closed).

Tamper detection and quarantine

The policy YAML supports a settings: section that controls how the SDK responds when it detects that the local policy file has been modified outside of normal channels (manual edits, unexpected hash changes, etc.):

version: '1'
settings:
  tamper_behavior: warn # Options: warn | deny | deny-all | quarantine
rules:
  - deny: 'delete_*'
  - allow: '*'
Mode Behavior
warn Log a warning but continue evaluating rules normally.
deny Deny the current tool call that triggered the tamper check.
deny-all Deny all tool calls and place the machine in quarantine until recovered.
quarantine Same as deny-all, plus report a tamper alert to the backend dashboard.

Quarantine recovery. When a machine enters quarantine (deny-all or quarantine), every tool call is denied until you re-establish trust with one of these commands:

controlzero enroll
controlzero policy-pull
controlzero sign-policy

Org-level policy signing. When a machine is enrolled via controlzero enroll, it receives the organization's signing public key. Policy bundles pulled from the backend are cryptographically signed and verified by the SDK automatically. No extra configuration is required.

Tamper alert reporting. In quarantine mode, the SDK reports a tamper alert to the Control Zero backend so your team can see it on the dashboard.

Local audit log

When running without an API key, every decision is written to ./controlzero.log with daily rotation. Configure via the client:

const cz = new Client({
  policyFile: './controlzero.yaml',
  logPath: './logs/controlzero.log',
  logRotation: '10 MB',
  logRetention: '30 days',
  logFormat: 'json', // or 'pretty'
});

When CONTROLZERO_API_KEY is set, audit ships to the remote dashboard and these log* options are ignored with a warning.

Hybrid mode

If you set both an API key AND pass a local policy, the local policy overrides the dashboard policy and you get a loud WARN log on init:

WARNING: controlzero: manual policy override detected. ...

For prod environments, opt into strict mode to throw instead:

const cz = new Client({
  apiKey: 'cz_live_...',
  policy: localPolicy,
  strictHosted: true,
});
// throws HybridModeError

Hosted mode

Hosted mode ships dashboard-managed signed policy bundles and remote audit. Pass your project API key to the async factory:

import { Client } from '@controlzero/sdk';

const client = await Client.create({ apiKey: 'cz_live_...' });

The SDK calls /v1/sdk/bootstrap to fetch your project keys, pulls the signed .czpolicy bundle, verifies the signature, decrypts it locally, and enforces every call against the dashboard policy. Audit entries stream to the remote audit trail. The bootstrap keys and bundle are cached under ~/.controlzero/cache/ so restarts work offline.

new Client({ apiKey }) (synchronous) refuses to construct with an API key alone -- it points you at Client.create() since hosted bootstrap is an await-able I/O call.

Coding agent hooks (one command)

Install controlzero as a pre-tool-use hook in your AI coding CLI. Every tool call gets evaluated against your policy before it runs. Audit log lives at ~/.controlzero/audit.log.

# Claude Code
npx -y @controlzero/core install claude-code

# Gemini CLI
npx -y @controlzero/core install gemini

# Codex CLI (Bash-only coverage today; pair with Gateway for full enforcement)
npx -y @controlzero/core install codex

All three write the same global policy at ~/.controlzero/policy.yaml and patch the agent's settings file in place. Run again to update; idempotent.

Agent Settings file Hook event Coverage
Claude Code ~/.claude/settings.json PreToolUse All tool calls
Gemini CLI ~/.gemini/settings.json BeforeTool All tool calls
Codex CLI ~/.codex/hooks.json + config.toml PreToolUse Bash only (apply_patch + MCP bypass)

The Codex coverage gap is upstream (OpenAI's hook system is gated behind a feature flag and only fires for Bash today). Use the Control Zero Gateway as the authoritative gate for non-Bash actions.

Framework examples

Full integration guides at docs.controlzero.ai/sdk/integrations:

  • LangChain.js
  • LangGraph.js
  • OpenAI Agents SDK
  • Anthropic tool use
  • Vercel AI SDK
  • MCP servers
  • Raw HTTP / no framework

License

Apache 2.0