Run fully offline (air-gap)
Surfaces used: Python / Node SDK in Local mode, self-hosted gateway Modes supported: Local Tiers: Free (baseline), Self-Hosted enterprise for full air-gap deployment Status: Local-mode SDK is GA. Self-Hosted air-gap deployment is Preview.
What you'll do
Run Control Zero with zero outbound calls. Policy lives in a signed YAML file on disk. Audit writes to a local file (or your own internal log sink). No telemetry, no dashboard calls, no license check-ins.
Why this is the right path for you
- If your environment is disconnected (classified, regulated, or just offline by policy) and you cannot call
api.controlzero.ai, this is for you. - For a single developer or a small offline workload, the SDK in Local mode is enough.
- For an organization running air-gapped, you want the Self-Hosted deployment: the dashboard, audit store, and signing infrastructure, all inside your boundary.
When NOT to use this approach
If you have internet egress and just want privacy, you do not need air-gap. Hosted mode already keeps prompts in-memory and only stores redacted audit metadata. Air-gap is for environments where outbound is not allowed, not just not preferred.
5-minute setup (single developer, Local mode)
pip install control-zero
Create policy.yaml:
rules:
- id: block-shell-execute
deny: 'shell:execute'
reason: 'Destructive shell commands are not allowed.'
- id: allow-everything-else
allow: '*'
reason: 'Default-allow for everything else.'
# DLP rules scan tool args for sensitive data. Built-in patterns
# (AWS keys, GitHub tokens, SSNs, etc.) are always active. Add custom
# patterns here.
dlp_rules:
- id: block-internal-codes
pattern: 'PROJ-[A-Z]{3}-\d{6}'
category: custom
action: block
reason: 'Internal project codes must not leave the agent.'
Use it:
from controlzero import Client
cz = Client(mode="local", policy_path="./policy.yaml")
decision = cz.guard(tool="shell", arguments={"command": "rm -rf /"})
assert not decision.allowed
Audit writes to ~/.controlzero/audit.log (override with audit_path=).
Verify no network calls
# Block egress as a smoke test
sudo pfctl -e # or your firewall of choice
python your_app.py
The SDK should continue to work: policy is local, audit is local, nothing reaches out.
5-minute setup (Self-Hosted air-gap) Preview
Self-Hosted gives you the full experience -- dashboard, policy signing, audit store -- all inside your boundary. It is in Preview; you receive a versioned container bundle with signed checksums and install into your own cluster.
Short version:
# On a jump host with the bundle
tar xzf controlzero-selfhosted-<version>.tar.gz
cd controlzero-selfhosted
./install.sh --air-gap --registry registry.internal/controlzero
You end up with:
- Backend, gateway, dashboard, audit store, policy signing -- all local containers.
- No outbound calls. License validation is offline via a signed manifest.
- Policy bundles signed by your own org key; SDKs verify locally.
To pilot, contact us. You will get a bundle, an install runbook, and a named support contact.
Verifying it's working
- With egress blocked, run the SDK smoke test above. Policy evaluation and audit must continue.
- For Self-Hosted: run
./controlzeroctl healthcheckinside the cluster. All components should reportokwith no outbound attempts. - Confirm the audit file (Local mode) or dashboard (Self-Hosted) grows as traffic flows.
Common follow-ups
- "I want the full Python guide" -> Govern an AI app in Python
- "I want the same offline pattern in Node" -> Govern an AI app in Node.js
- "I want to pilot Self-Hosted" -> Self-Hosted
- "How does local mode actually work?" -> Run fully offline (Local mode)
Reference
- Surface pages: Python SDK, Node.js SDK, Local-only mode, Self-Hosted
- Concepts: Policies
- API: API reference