Skip to content
Agentic Control Plane

Claude Code Audit Log, Hook & Governance — Install Guide

See, control, and price every tool call Claude Code makes — Bash, Edit, Write, WebFetch, MCP, and the model calls behind them — from one dashboard. One command, no code changes.

Every tool call Claude Code makes — Bash, Edit, Write, WebFetch, MCP — flows through ACP’s PreToolUse and PostToolUse hooks. Logged with identity. Denied when policy says deny. Audited end-to-end through delegation chains when subagents spawn other subagents.

TL;DR

# Free, on-device, no account — decisions run locally from ~/.acp/policy.json:
curl -sf https://agenticcontrolplane.com/install.sh | bash -s -- --local

# Or connect a workspace for team policy, cost X-ray, and a shared console:
curl -sf https://agenticcontrolplane.com/install.sh | bash
A real recording, nothing mocked. Note the middle: every file the one command wrote, on camera. Piping a script to bash deserves that. The run ends on the audit log showing two allows and one deny — governance is mostly saying yes, in writing.

Three things you get the moment it's running — click any to see it full-size:

ACP tool-surface control table: every tool the agent can call, Allow/Deny per tool
ControlEvery tool Claude Code can call, one row each — Allow / Deny per tool. Deny-by-default on rm -rf, force-push, and the rest. Enforced at the call, outside the model.
ACP cost-per-run distribution for one agent across many runs, log scale
PriceRoute model calls through the proxy and every one is metered — each run split loop-vs-leaf and plotted across runs, so you see which step is the bill and which runs blow the budget.
ACP session trace: per-call timeline of one agent run with cost and decision
AuditEvery tool + model call in a run, in order — what ran, what it returned, the policy decision, and what it cost. Exportable.

See your first governed call →Free for individuals · full install below

The script detects Claude Code, writes the hook ~/.acp/govern.mjs, and registers it in ~/.claude/settings.json for both PreToolUse and PostToolUse events. Restart Claude Code (Ctrl+C then claude --continue) and every tool call is governed.

With --local, decisions are made on your machine by ~/.acp/decide.mjs against ~/.acp/policy.json (allow / ask / deny per tool, plus an always-on safety floor), and every call is logged to ~/.acp/audit.jsonl. No browser, no account, nothing leaves your machine. Without the flag, the installer opens your browser to provision a workspace and routes decisions through the ACP API instead. You can start local and re-run without --local any time to upgrade.

How it works

Claude Code’s hook system fires before and after every tool call. ACP installs a single govern.mjs Node script and registers it for both events:

  • PreToolUse — fires before the tool runs. ACP’s hook POSTs the tool name, input, session ID, and agent_tier to https://api.agenticcontrolplane.com/govern/tool-use. Server evaluates the seven-layer governance pipeline (immutable rules, delegation chain, scopes, ABAC, rate limits, plan limits, content scanning). If the response says decision: deny, the hook prints permissionDecision: deny and Claude Code blocks the call.
  • PostToolUse — fires after the tool returns. ACP’s hook POSTs the tool output (truncated at 200KB) to /govern/tool-output. Server scans for PII, prompt injection, and secrets. The response can flag findings into the audit log; output mutation is currently observe-only.

Both hooks have a 4-second timeout. If ACP is unreachable, the hook fails open by default — the call is allowed but every one carries a loud “this ran UNGOVERNED” message. We never brick your agent because our gateway had a bad moment. Compliance-sensitive? Opt into fail-closed (unreachable ACP blocks the call) with echo closed > ~/.acp/failmode or ACP_FAIL_MODE=closed. A policy deny always blocks either way — fail mode only governs infrastructure failures.

What gets installed and where

Path Contents
~/.acp/govern.mjs The hook script — Node, ~200 lines, no dependencies
~/.acp/credentials Your bearer token (set after browser OAuth)
~/.claude/settings.json Adds hooks.PreToolUse and hooks.PostToolUse entries pointing at govern.mjs

The installer is idempotent — re-running it adds the hook entry to settings.json only if missing, and preserves any other hooks you’ve configured. Running on a machine without Claude Code installed is a no-op.

What you’ll see in the dashboard

Open cloud.agenticcontrolplane.com/agents — your Claude Code installation appears in the Detected agents table within seconds of the first hook fire. Each row shows:

  • Client (Claude Code) and the API key label
  • Activity breakdown by tier (interactive, subagent, background) and any named subagents (Explore, Plan, general-purpose)
  • 30-day call count and last-seen timestamp

For deeper investigation, the Activity log shows every individual tool call with its full context: identity, scopes, decision, latency, PII findings, and — for delegated runs — the full chain provenance.

Setting up policy

Three policy axes apply to Claude Code traffic:

  1. Tool policies (Policies → Tool Policies) — workspace-wide tool allowlist and required scopes. Blocks github.repos.delete for everyone? Set it here.
  2. Agent policies (Policies → Agent Policies) — per-tier rules for Claude Code interactive vs subagent vs background. Lock down what background agents can do without restricting your interactive sessions.
  3. User policies (Policies → User Policies) — overrides per identity. Grant Alice access to Stripe-touching agents, restrict Bob.

Most-restrictive wins on conflict. Start in audit mode for a few days to learn what your team actually does, then switch to enforce mode when patterns are clear.

Limitations

Honest list of what ACP’s Claude Code integration cannot do today:

  • --dangerously-skip-permissions bypasses all hooks. Claude Code’s own escape hatch removes hook execution entirely. ACP can’t intercept what Claude Code doesn’t tell it about. This is a Claude Code design choice — not an ACP bug. Mitigation: detect the flag’s use server-side via the absence of expected hook calls, alert when an agent goes silent.
  • Tool input mutation is not yet supported. PreToolUse can deny but cannot rewrite the tool input. PostToolUse can flag findings but cannot redact the output. Both are observe-or-block today. SDK adapter (path 3) will add mutation when shipped.
  • Subagent attribution is partial. When Claude Code spawns a subagent via the Agent tool with subagent_type: "Explore", ACP captures the spawn event with the named type. The Explore subagent’s downstream Bash and Read calls show as generic subagent tier — Claude Code’s hook payload doesn’t propagate parent agent context. We’ve requested this upstream.
  • Hook timeout is fixed at 4 seconds in govern.mjs. A governance response slower than that is treated as unreachable — allowed-but-ungoverned by default, blocked if you’ve opted into fail-closed.
  • No support for offline / air-gapped Claude Code. Hook requires reachable HTTPS to api.agenticcontrolplane.com. Self-hosted GatewayStack supports air-gapped — set ACP_API_BASE env var to point at your instance.

Troubleshooting

Hook isn’t firing. Restart Claude Code completely (Ctrl+C, then claude --continue). Hook registration is read on session start.

Every tool call is being blocked. You’ve opted into fail-closed (~/.acp/failmode says closed) and ACP is unreachable, or a policy is denying the calls — the block message says which. For credential problems, check ~/.acp/credentials exists and run the installer again to re-authenticate. To restore the fail-open default: echo open > ~/.acp/failmode.

govern.mjs: command not found. The hook calls node $HOME/.acp/govern.mjs. Ensure Node 18+ is on PATH for non-interactive shells (zshrc / bashrc, not just zlogin).

Hook fires but nothing appears in the dashboard. Confirm the workspace tied to your token. The Activity page is workspace-scoped — if you have multiple workspaces, switch in the top-right dropdown.

--dangerously-skip-permissions was used and there’s a gap in the audit log. Expected — see Limitations. A future ACP feature will alert on hook silence relative to expected baseline.

Add the cost X-ray

The hook above governs and audits tool calls — it never sees the model’s token usage, so it can’t show cost. To meter spend, prompt-cache hit rate, and the loop-vs-leaf cost X-ray, route Claude Code’s model calls through the ACP proxy: set ANTHROPIC_BASE_URL=https://api.agenticcontrolplane.com/anthropic/v1 and use your ACP key (gsk_...) as ANTHROPIC_AUTH_TOKEN. Same responses, now metered — and the proxy governs the tool-use blocks the model emits as a second layer.

Full walkthrough: Turn on Cost X-Ray.

Frequently asked questions

How do I get an audit log of everything Claude Code did?

Install the hook (curl -sf https://agenticcontrolplane.com/install.sh | bash) and restart Claude Code. Every tool call — Bash, Edit, Write, WebFetch, MCP — then lands in the Activity log with identity, decision, latency, and, for delegated runs, the full chain provenance.

Can I block specific Claude Code tools or commands?

Yes. Tool policies set a workspace-wide allowlist and required scopes; agent policies restrict by tier (interactive vs subagent vs background); user policies override per identity. A policy deny is returned to the PreToolUse hook and Claude Code blocks the call before it runs. Most-restrictive wins on conflict.

Does --dangerously-skip-permissions bypass the hooks?

Yes — Claude Code’s own escape hatch removes hook execution entirely, so ACP can’t intercept those calls. That’s a Claude Code design choice. The mitigation is server-side: detect the silence of expected hook traffic and alert when an agent goes dark.

What happens if the governance service is unreachable?

The hook fails open by default: the call is allowed and loudly flagged as having run ungoverned, so an outage never bricks your agent. Compliance-sensitive teams can opt into fail-closed (echo closed > ~/.acp/failmode), which blocks calls when the check can’t run. A policy deny always blocks either way.

Can ACP show what my Claude Code sessions cost?

The hook alone can’t — it sees tool calls, not token usage. Route Claude Code’s model calls through the ACP proxy (ANTHROPIC_BASE_URL=https://api.agenticcontrolplane.com/anthropic/v1 with your ACP key as the auth token) and every session is metered, split loop-vs-leaf, with prompt-cache hit rates.