agentctl is a local control plane for coding agents. It gates a small set of risky actions, records a trace for every decision, and can replay prior sessions against a different policy.
go install github.com/chocks/agentctl/cmd/agentctl@latest
agentctl versionagentctl stores all of its state under ~/.agentctl/:
policy.yamltraces.jsonlapprovals.jsonl
There is no repo-local policy file and no HTTP server.
Attach to a supported agent. attach bootstraps ~/.agentctl/ and writes a default policy if one does not exist yet.
agentctl attach claude-code
# or
agentctl attach codexVerify the install:
agentctl doctorLaunch the terminal UI:
agentctl ui| Action | What it covers |
|---|---|
install_package |
pip, npm, cargo, go installs |
run_code |
shell execution, script runs |
access_secret |
reading secrets, tokens, credentials |
write_file |
file creation, overwrites, appends |
call_external_api |
outbound HTTP to external services |
Everything else stays out of the control path.
agentctl attach <agent> Configure agent integration and bootstrap ~/.agentctl/
agentctl detach <agent> Remove agent integration
agentctl doctor Check policy, trace store, approvals, and agent status
agentctl gate Evaluate one action from stdin
agentctl trace list Show recent traces
agentctl trace search Search traces
agentctl replay <session_id> Re-evaluate a recorded session
agentctl approval list List approvals
agentctl approval approve <id> Approve a pending escalation
agentctl approval deny <id> Deny a pending escalation
agentctl ui Terminal UI for traces and approvals
agentctl hook claude-code Claude Code PreToolUse hook adapter
agentctl mcp MCP server for Codex and other MCP clients
agentctl loads exactly one policy file: ~/.agentctl/policy.yaml.
- Missing file: built-in safe defaults are used.
- Malformed file:
gate,doctor, andmcpfail loudly. - Hook mode (
agentctl hook claude-code) fails open on malformed policy and writes the error to stderr.
Default policy written by attach:
actions:
install_package:
require_hashes: true
run_code:
block_patterns:
- "| bash"
- "| sh"
- "| python"
network: deny
access_secret:
require_approval: always
max_ttl: 300
write_file:
block_patterns:
- ".env"
- "*.pem"
- "*.key"
call_external_api:
allowed_domains: []allowed_domains: [] means deny all outbound calls. Omitting allowed_domains means no domain restriction.
Record a session under a stable session ID:
echo '{"action":"call_external_api","params":{"url":"https://api.openai.com/v1/responses","method":"POST"},"reason":"call provider"}' \
| agentctl gate --session demo-1Replay that session against the current global policy:
agentctl replay demo-1Or replay against an alternate policy file:
agentctl replay demo-1 --policy ./stricter-policy.yamlmake fmt
make build
make test
make lintMIT. See LICENSE.