Autonomy, Contained.
LLM proposes commands. Chainwatch enforces policy. No commands are hardcoded.
Chainwatch audit log: every decision recorded, hash chain verified.
Runtime control plane for AI agent safety. Intercepts tool calls at irreversible boundaries — payments, credentials, data destruction, external communication — and enforces deterministic policy decisions.
A single Go binary that wraps agent tool invocations, evaluates deterministic policy, and enforces decisions (allow, deny, require-approval) at boundaries agents cannot bypass.
- Not an ML-based anomaly detector
- Not a logging/observability layer (enforcement, not detection)
- Not an LLM guardrail for prompt content
- Not a permissions system (enforces boundaries, not roles)
- Not a web UI or SaaS product (CLI only)
curl -fsSL https://raw.githubusercontent.com/ppiankov/chainwatch/main/scripts/install.sh | bashDownloads the binary, runs chainwatch init, and verifies with chainwatch doctor.
go install github.com/ppiankov/chainwatch/cmd/chainwatch@latest
chainwatch init# Linux (amd64)
curl -sL https://github.com/ppiankov/chainwatch/releases/latest/download/chainwatch-linux-amd64 -o chainwatch
chmod +x chainwatch && sudo mv chainwatch /usr/local/bin/
# macOS (Apple Silicon)
curl -sL https://github.com/ppiankov/chainwatch/releases/latest/download/chainwatch-darwin-arm64 -o chainwatch
chmod +x chainwatch && sudo mv chainwatch /usr/local/bin/Then bootstrap:
chainwatch init
chainwatch doctorgit clone https://github.com/ppiankov/chainwatch.git
cd chainwatch
go build -o chainwatch ./cmd/chainwatchchainwatch is designed to be used by autonomous agents without plugins or SDKs. Single binary, deterministic policy enforcement, structured JSON output, bounded jobs.
Agents: read SKILL.md for commands, flags, JSON output patterns, and approval workflow.
Key pattern for agents: chainwatch exec --dry-run --profile <p> -- <cmd> to check policy before executing.
# Safe command — allowed
chainwatch exec -- echo "hello world"
# Dangerous command — blocked
chainwatch exec -- rm -rf /
# Decision: deny | Reason: Denylisted: command matches pattern: rm -rf# Enforce a safety profile
chainwatch exec --profile coding-agent -- curl https://api.example.com/data
# Available profiles: coding-agent, research-agent, customer-support, data-analyst, clawbot# One command — creates policy.yaml, denylist.yaml, profiles/
chainwatch init
# With a built-in profile
chainwatch init --profile clawbot
# Verify setup
chainwatch doctorAgent ──► chainwatch ──► Tool
│
┌────┴────┐
│ Policy │ Deterministic rules, thresholds, denylist
│ Engine │ YAML-configurable, hot-reloadable
└────┬────┘
│
allow / deny / require-approval
| Mode | Command | Use Case |
|---|---|---|
| CLI wrapper | chainwatch exec -- <cmd> |
Single agent, simplest setup |
| gRPC server | chainwatch serve |
Multi-agent, SDK integration |
| HTTP proxy | chainwatch proxy |
Intercept agent HTTP traffic |
| LLM intercept | chainwatch intercept |
Extract tool calls from streaming LLM responses |
| MCP server | chainwatch mcp |
Claude Desktop integration |
Enforcement: exec, serve, proxy, intercept, mcp, evaluate
Approval workflow: approve, deny, pending
Emergency override: breakglass create, breakglass consume, breakglass revoke, breakglass list
Audit: audit verify
Policy tools: policy diff, policy simulate, policy gate, certify
Setup: init, doctor, recommend, init-denylist, init-policy, version
Chainwatch uses deterministic YAML-based policy. No ML or statistical models.
# ~/.chainwatch/denylist.yaml
commands:
- "rm -rf"
- "sudo su"
- "curl * | sh"
urls:
- "evil.com"
- "*.onion"
files:
- "~/.ssh/id_rsa"
- "~/.aws/credentials"# ~/.chainwatch/policy.yaml
enforcement_mode: guarded
thresholds:
allow_max: 5
approval_min: 11
rules:
- purpose: "SOC_efficiency"
resource_pattern: "*salary*"
decision: deny
reason: "salary data blocked for SOC purpose"
- purpose: "*"
resource_pattern: "*credentials*"
decision: require_approval
reason: "credential access requires approval"
approval_key: cred_access# Agent hits require_approval → operator approves
chainwatch pending # List pending approvals
chainwatch approve salary_access --ttl 5m # Approve with TTL
chainwatch deny salary_access # Deny
# Emergency override
chainwatch breakglass create --reason "incident response"
chainwatch exec --breakglass <token> -- <cmd>import "github.com/ppiankov/chainwatch/sdk/go/chainwatch"
client, _ := chainwatch.New("localhost:9090")
defer client.Close()
result, _ := client.Evaluate(&model.Action{
Tool: "command",
Resource: "rm -rf /tmp/data",
Operation: "execute",
}, "general", "")
if result.Decision == model.Deny {
fmt.Println("Blocked:", result.Reason)
}from chainwatch_sdk import ChainwatchSDK
cw = ChainwatchSDK()
result = cw.evaluate(tool="command", resource="rm -rf /", operation="execute")
if result["decision"] == "deny":
print(f"Blocked: {result['reason']}")make go-test # Run Go tests with -race
make test # Run Python tests
make fieldtest # Run adversarial test suite (5 rounds)
make bench # Run benchmarks
make fuzz # Run fuzz tests (30s per target)Principiis obsta — resist the beginnings.
- Deterministic policy, not ML predictions
- Enforcement at irreversible boundaries, not after
- The system NEVER asks the model whether an irreversible action is safe
- Monotonic risk: SAFE -> SENSITIVE -> COMMITMENT -> IRREVERSIBLE (one-way)
- Fail-closed: unreachable server = deny
See docs/irreversible-boundaries.md and docs/DESIGN_BASELINE.md.
- CLI-only — no web UI or dashboard
- Single-node — no distributed coordination or multi-tenant support
- Process polling —
execmode uses process-level wrapping, not seccomp/eBPF - Python SDK — subprocess-based (wraps the Go binary, not a native library)
- No content inspection — classification based on resource names, not file contents