ZLAR is a deterministic execution governance layer for AI agents.
It intercepts agent tool calls, evaluates them against signed policy, routes decisions to humans when required, and produces cryptographic proof that governance happened. No AI in the enforcement path. The gate pattern-matches. It cannot be persuaded.
- A gate that sits between the agent and real-world actions
- Deterministic policy enforcement — regex rules or Cedar formal policy, never reasoning
- Human-in-the-loop escalation via Telegram (approve/deny from your phone)
- Hash-chained, Ed25519-signed audit trail on every decision
- Governed Action Receipts — portable proof that an action was governed, with semantic validation beyond the signature check
- SDK membrane — a programming model where agents cannot be constructed without a live gate connection
- Cryptographic delegation chains for multi-agent systems
- Framework-agnostic: Claude Code, Cursor, Windsurf, any MCP client, AuthZEN 1.0 PDP interface
- Not a monitoring dashboard that watches after the fact
- Not an AI that judges whether an action "seems safe"
- Not a trust scoring system that builds a reputation for agents
- Not a sandbox at the architectural level — ZLAR governs the decision, not the execution environment. Optional macOS Seatbelt wrapping is available as a containment layer below the gate when
etc/sandbox/profiles are present - Not tied to any model provider — the entity that sells agents cannot credibly govern them
- The product in 90 seconds:
docs/the-moment.md— what it feels like to be in the loop. - Implementers:
spec/governed-action-receipt-v1.md— build a compatible receipt producer or verifier in an afternoon. - If an agent took an action that affected you:
docs/if-an-agent-affected-you.md— how to find, verify, and contest.
git clone https://github.com/ZLAR-AI/ZLAR.git
cd ZLAR && bash install.shInstalls with deny-heavy defaults. Your agent is governed in under 60 seconds.
~/.zlar/bin/zlar doctor # verify everything works
~/.zlar/bin/zlar status # see what's governedAdd human approval via Telegram: ~/.zlar/bin/zlar telegram
Something not working? See Troubleshooting or run zlar doctor.
Agent issues tool call (shell command, file write, API request)
|
+-- Gate intercepts at execution boundary
|
+-- Loads Ed25519-signed policy (agents cannot modify their own rules)
|
+-- Evaluates: which rule matches?
| +-- allow -> tool executes, audit entry + receipt written
| +-- deny -> tool blocked, audit entry + receipt written
| +-- ask -> human notified via Telegram, action denied immediately
| +-- agent retries -> gate checks for human response
| +-- human approved -> executes on retry, receipt records "authorized by human"
| +-- human denied -> blocked on retry, receipt records "denied by human"
| +-- no response -> blocked (fail-closed, silence is not consent)
|
+-- Hash-chained audit entry records the decision
+-- Governed Action Receipt provides portable proof
Two enforcement surfaces share the same policy and audit trail:
- Bash gate (
bin/zlar-gate) — hooks into Claude Code, Cursor, Windsurf. Pure bash. Zero dependencies beyond jq and openssl. - MCP gate (
mcp-gate/gate.mjs) — TCP proxy between any MCP client and server. Interceptstools/callJSON-RPC messages. Per-entry Ed25519 signing, policy signature verification, standing approvals. Evaluates JSON regex policy by default; can evaluate Cedar formal policy whenZLAR_POLICY_ENGINE=cedaror=both.
The agent does not volunteer to be governed. It is governed by architecture.
The receipt is the portable proof that a governed action was evaluated by deterministic policy and decided by the stated authority.
# Generate a receipt from an audit event
bin/zlar-receipt --last --key ~/.zlar-signing.key --pubkey ~/.zlar-signing.pub
# Verify it — anyone with the public key can do this
bin/zlar-verify receipt.json --pubkey key.pubVALID
Signature valid. Action "Bash" in domain "file" was deny by policy at 2026-04-05T21:00:00.000Z.
A receipt proves:
- A specific action was attempted by an AI agent
- Deterministic policy was evaluated against that action
- The decision was made by the stated authority (policy rule or human)
- The record has not been tampered with since creation
- The receipt is anchored to the audit hash chain
Receipts are cross-gate compatible — a bash-gate receipt verifies with the Node.js verifier and vice versa. The detail is hashed, not exposed — you can share a receipt with an auditor without revealing the command.
Every gate decision writes a hash-chained, Ed25519-signed audit entry:
{
"ts": "2026-04-05T09:14:22Z",
"agent_id": "claude-code",
"domain": "file",
"action": "git push origin main",
"outcome": "denied",
"rule": "R014",
"authorizer": "human:7662799203",
"prev_hash": "a1b2c3...",
"signature_algorithm": "Ed25519",
"signature": "mOiZF8E3MKFeyuRw..."
}authorizer: "human:7662799203"— a specific human made this decision. Non-repudiable.prev_hash— SHA-256 of the previous entry. Tamper with any record and every subsequent hash breaks.signature— Ed25519 over SHA-256 of the canonical entry. Every entry is individually signed.
This is not the agent's account of what it did. This is the infrastructure's record of what happened.
If the enforcement layer uses intelligence, the enforcement layer can be attacked with intelligence. If the enforcement layer is deterministic, the only attack is against the policy itself — which is a human artifact, signed with Ed25519, stored outside agent context. The absence of intelligence in the gate is the security property.
An enforcement layer that uses reasoning to evaluate actions can be subverted by reasoning-based attacks. The enforcement layer's capability becomes its vulnerability.
Signatures alone are not enough. Every signed-payload system that skipped semantic validation got burned: X.509 basicConstraints bypasses (24 years), JWT algorithm confusion (11 years), SAML wrapping attacks (14 years). ZLAR runs a semantic validator (lib/semantic-validator.mjs) after signature verification and before trust — cross-field invariants that signatures cannot check: rule-outcome consistency (deny-only rules cannot produce allow), authorizer-outcome coherence (a policy authorizer cannot produce an "authorized" outcome; that requires a human), delegation chain integrity, and temporal bounds. Signatures prove the bytes haven't changed. Semantic validation proves those bytes make sense.
The first component in the call chain that can return "allow" must be outside the governed agent's writable or influenceable space. If the agent can modify, disable, or redirect that first-allow point, governance is cosmetic — the agent has not been governed, it has been presented with a governance-shaped surface it can route around.
The full principle is documented in signal/DOCTRINE.md. signal/PROOF.md is a line-referenced proof by exhaustive case analysis that no unauthorized action can execute on a gate-governed path. ADR-006 sets out why the entity that sells agents cannot credibly govern them.
- Compromised signing key — an attacker with the key can sign a permissive policy. Mitigation: key never lives on the agent's machine. Rotation invalidates prior signatures.
- Compromised gate binary — if replaced, all enforcement is lost. Mitigation: R012 blocks agents from modifying their own governance. Host-level IDS is the defense layer below the gate.
- Actions the gate cannot see — channels that bypass the hook or proxy. The gate governs tool calls. OS-level containment governs everything else.
A security tool should state its own boundaries, not just its competitors' failures.
Status: cedar-poc/e23.cedar is a complete, schema-validated Cedar ruleset for OSFI Guideline E-23 (Model Risk Management, effective May 1, 2027). It is not in the default MCP gate load path. Using it as a runtime enforcement layer requires extending lib/cedar-evaluator.mjs to populate the extended ToolCall fields from application input, and loading e23.cedar alongside the base rules. This wiring is tracked for v2.8. Validation is exercised by cedar-poc/test-e23.mjs against its own schema.
The ruleset implements ten rules. Each cites a specific E-23 principle.
What the ruleset covers:
- Kill switches (KS-001, KS-002) — burst-denial detection, and autonomous-action blocks in production below a configurable confidence threshold. E-23 Principle 2.3.
- Position limits (PL-001, PL-002, PL-003) — tier-based caps, absolute caps, counterparty validation against hallucinated account numbers. E-23 Principle 2.3.
- Pre-execution checks (PEC-001, PEC-002, PEC-003) — risk-tiered access; Tier 1 agents restricted to read-only actions. E-23 Principle 2.2.
- Environment gates (EC-001) — broader thresholds in dev/staging, tighter in production. E-23 Principle 3.4.
- Third-party model controls (TP-001) — unidentified models treated as Tier 1 regardless of declared tier. E-23 Principle 3.6.
The schema extends the base Cedar model with bank-risk vocabulary (risk_tier, amount, counterparty, is_irreversible, confidence, session_deny_count).
The bash and MCP gates intercept agents from outside. The SDK membrane (@zlar/sdk, sdk/membrane/) is a programming model in which agents are constructed inside governance — not wrapped by it.
import { ZlarAgent, ZlarDeniedError } from '@zlar/sdk';
// If the gate daemon is unreachable, construction throws.
// There is no code path that produces an ungoverned agent instance.
const agent = await ZlarAgent.connect({ agentId: 'my-agent' });
// Every tool call evaluates policy before the function runs.
const result = await agent.gate('Bash', { command: 'ls -la' }, async () => {
return execSync('ls -la').toString();
});
// Or wrap a whole executor map at once.
const governed = agent.wrapTools({
bash: (input) => execSync(input.command).toString(),
read_file: (input) => fs.readFileSync(input.path, 'utf8'),
});ZlarAgent.connect() opens a JSON-RPC 2.0 connection to the gate daemon (sdk/daemon/) over a Unix socket. If the daemon is unreachable, construction throws ZlarDaemonUnreachableError — there is no code path that produces an ungoverned agent instance. See ADR-006 for the architectural reasoning.
Multi-agent delegation chains. The SDK ships cryptographic delegation chain support for orchestrator/worker patterns. Each agent receives a per-session Ed25519 keypair; the daemon issues a signed root token via the register RPC; each parent signs its child's token with its own key. The daemon verifies the full chain cryptographically before any policy evaluation — an invalid chain fails closed with rule: chain:verify in the audit trail, and no policy rule is ever consulted.
AuthZEN 1.0 standards interface. sdk/authzen/server.mjs implements the OpenID Foundation AuthZEN 1.0 Final Specification (January 2026) — a standards-compliant Policy Decision Point at POST /access/v1/evaluation (single) and POST /access/v1/evaluations (batch). Any AuthZEN-aware PEP can call it. Default port 8181.
HTTP hook adapter. sdk/hook-adapter/server.mjs bridges Claude Code's HTTP hook protocol to the gate daemon. It always returns HTTP 200 with a valid JSON body — Claude Code treats non-2xx responses as fail-open, so the adapter handles every error condition internally and returns 200 + deny for any failure mode.
| Layer | Component | What it does |
|---|---|---|
| Enforcement | zlar-gate |
Policy engine. Intercepts tool calls, classifies, evaluates signed rules, writes audit trail and receipts. |
| Enforcement | mcp-gate |
TCP proxy for MCP. Same policy, same audit format, per-entry signing, standing approvals. Optional Cedar engine via ZLAR_POLICY_ENGINE. |
| Evidence | lib/receipt.mjs |
Governed Action Receipt generation and verification (v0 inline and v1 envelope formats). Cross-gate compatible. |
| Evidence | lib/semantic-validator.mjs |
Cross-field validation after signature verification. Rule-outcome consistency, authorizer coherence, delegation chain integrity, temporal bounds. Closes X.509/JWT/SAML-class attacks. |
| Evidence | bin/zlar-verify |
Standalone receipt verifier. Anyone can verify with just the public key. Runs semantic validation automatically on v1 receipts. |
| Observation | zlar-witness |
Sequence detection from audit trail. Detected, not enforced. |
| Observation | zlar-digest |
Governance summary. Decisions, latency, sequences, novelty. |
| Identity | zlar-agents |
Per-agent policy bindings, standing approvals, delegation depth limits. |
| Identity | Agent manifest | Capability boundary per agent. Narrows policy, never widens. (Invariants) |
| Policy | zlar-policy |
CLI for Ed25519-signed policy rules. Keygen, sign, verify. |
| Compliance | cedar-poc/zlar.cedar |
Cedar formal policy for the base gate ruleset (R002, R003, R005, R006, R007, R012, R014, R016). Evaluated by the MCP gate when Cedar engine is enabled. |
| Compliance | cedar-poc/e23.cedar |
Cedar ruleset implementing 10 rules for OSFI Guideline E-23 (Model Risk Management). Not in default load path — see OSFI E-23 section. |
| Session | lib/session-state.sh |
Velocity, loop detection, denial bursts. Thin counters, not reasoning. |
| Human | lib/human-invariants.sh |
Protects the human: decision cap (H6), deliberation floor (H15), approval rate monitoring (H14), capacity tracking (H13), authenticity checks (H17). Per-human state, not per-session. |
| Adapters | adapters/ |
Framework hooks for Claude Code, Cursor, Windsurf. |
| SDK | sdk/membrane |
Programming model for agents built inside governance. ZlarAgent.connect() requires a live daemon at construction. Wraps tool calls with policy evaluation before execution. |
| SDK | sdk/daemon |
Long-lived gate daemon. Unix socket, JSON-RPC 2.0, delegation chain issuer, agent registration. |
| SDK | sdk/authzen |
OpenID Foundation AuthZEN 1.0 Policy Decision Point. POST /access/v1/evaluation for standards-compliant authorization requests. |
| SDK | sdk/hook-adapter |
HTTP hook bridge for Claude Code. Always returns HTTP 200 (Claude Code treats non-2xx as fail-open). |
The canonical entrypoint runs every test suite and prints the total assertion count. CI runs this on every push. It is the single source of truth for the "1000+ assertions" badge.
bash tests/count-assertions.sh # run all 28 files, print summary
bash tests/count-assertions.sh --detail # also show per-file pass counts
bash tests/count-assertions.sh --badge # print shields.io badge URLCurrent state (v2.7.1): 28 files, 1022 assertions, 0 failures.
The tests need bash, jq, and an OpenSSL with Ed25519 support (LibreSSL
on macOS does not qualify — use brew install openssl@3 and put it on PATH
first). node is optional — .mjs test files will be skipped gracefully if
node is not available. python3 is optional — canonicalization cross-check
will be skipped gracefully if python3 is not available.
# Core governance (bash)
bash tests/test-receipt.sh # Receipt generation and cross-gate verification
bash tests/test-manifest.sh # Manifest CLI and schema invariants
bash tests/test-agent-identity.sh # Agent identity, risk tiers, authorization levels
bash tests/test-human-invariants.sh # Human invariant enforcement (H6, H13, H14, H15, H17)
bash tests/test-perimeter-closure.sh # Policy rules, sandbox, path sanitization
bash tests/test-crypto.sh # Cryptographic abstraction layer
bash tests/test-session-state.sh # Session counters
bash tests/test-standing-approvals.sh # Standing approval matching
bash tests/test-approval-binding.sh # Approval binding (action fingerprint)
bash tests/test-inbox-hmac.sh # Inbox HMAC verification
bash tests/test-doctor.sh # Installation health checks
bash tests/test-policy-loading.sh # Policy load fail-closed corpus
bash tests/test-witness.sh # Sequence detection from audit
bash tests/test-canary.sh # Canary pending-file lifecycle
# Canonicalization (cross-language verification)
node tests/test-canonicalization.mjs # 62 vectors across Node and jq -S -c
python3 tests/verify-canonicalization.py # 28 vectors cross-checked in Python
# Receipt v1 envelope format and semantic validation
node tests/test-receipt-v1.mjs # v1 create/sign/verify/tamper/universal
node tests/test-semantic-validation.mjs # Layer 4: rule-outcome, authorizer, temporal, delegation
# MCP gate
node mcp-gate/test.mjs # Base gate tests
node mcp-gate/test-hardened.mjs # Policy verification, signing, fail-closed, standing approvals
node mcp-gate/test-receipt.mjs # Receipt generation, verification, delegation chains
node mcp-gate/test-cedar.mjs # Cedar P1/P2 rules, gate action mapping
# Cedar policy verification
node cedar-poc/test.mjs # Cedar base rules
node cedar-poc/test-e23.mjs # Cedar E-23 risk-tiered governance
# SDK layer
node sdk/daemon/test.mjs # Daemon lifecycle
node sdk/membrane/test.mjs # Membrane boundary enforcement
node sdk/authzen/test.mjs # AuthZen integration
node sdk/hook-adapter/test.mjs # Hook adapter HTTP surface| Dependency | Minimum | Required for | Install |
|---|---|---|---|
| bash | 4.0+ | Gate engine | brew install bash (macOS) / default on Linux |
| jq | 1.6+ | Policy evaluation | brew install jq / apt install jq |
| openssl | 3.x | Ed25519 signing | brew install openssl@3 / apt install openssl |
| Node.js | 18+ | MCP gate, receipt verification | Optional — bash gate works without it |
| Telegram | — | Human approval channel | Optional — without it, blocked actions are instant-denied |
CI-tested platforms: Ubuntu 22.04+ and macOS 14+ (matrix on every push). Debian 12+ is supported but not gated by CI — maintainers verify manually.
Run zlar doctor after installation to verify all dependencies.
bin/ Gate, receipt tools, witness, digest, registry, policy CLI
lib/ Shared libraries (crypto, session state, agent identity, receipt, human invariants)
adapters/ Framework hooks (claude-code, cursor, windsurf)
mcp-gate/ MCP TCP proxy gate (Node.js)
etc/ Policy, manifests, signing keys, standing approvals, receipt schema
tests/ Test suites (14 bash + 13 Node.js + 1 Python, 1000+ assertions)
Run all: bash tests/count-assertions.sh
docs/ Architecture decisions, manifest invariants, operations
docs/adr/ Architecture Decision Records
signal/ Agent-facing signal layer (thesis, origin, proof)
cedar-poc/ Cedar formal policy verification
Architectural choices are documented as ADRs:
| ADR | Decision |
|---|---|
| 001 | Deterministic enforcement, not AI |
| 002 | Bash as implementation language |
| 003 | Fail-closed as default |
| 004 | Ed25519 for signing |
| 005 | Manifest narrows policy, never widens |
| 006 | Structural independence from governed system |
| 007 | Receipt v1 envelope format (versioned, no alg negotiation) |
- docs/troubleshooting.md — Common issues and fixes
- GOVERNANCE.md — How decisions are made, how invariants are amended
- SECURITY.md — Vulnerability disclosure, security principles
- CONTRIBUTING.md — How to contribute
- ADOPTERS.md — Who is using ZLAR
- LEGAL.md — Regulatory classification, liability, data processing
- signal/THESIS.md — Why intelligence in the monitor fails
- signal/ORIGIN.md — Why ZLAR exists
- signal/PROOF.md — No unauthorized action can execute on the governed path
Apache 2.0. See LICENSE.
Built by ZLAR Inc.