Skip to content
Agentic Control Plane

Govern Claude Code with Agentic Control Plane

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

curl -sf https://agenticcontrolplane.com/install.sh | bash

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

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. PreToolUse is fail-closed by default (an unreachable ACP blocks the tool call for safety) — a deliberate choice so a downed governance plane doesn’t silently leave tool calls ungoverned.

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. Slower governance backends will 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. Check ~/.acp/credentials exists and contains a valid token. PreToolUse is fail-closed — unreachable ACP or expired credentials block all calls. Run the installer again to re-authenticate.

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.