Skip to content
Agentic Control Plane

Ask before a force-push or other risky command in Claude Code

One command installs a hook that checks every tool call Claude Code makes before it runs: Bash, Edit, Write, WebFetch, MCP. Safe calls pass and are logged. Risky ones wait for your OK. You can read the whole session afterwards, with what each call cost.

Claude Code already has permission modes, a sandbox, and allowlists. ACP adds the three things they do not give you: a record of every call that someone other than the agent can read, rules that stay the same across every harness and every machine, and a safety floor that holds a force-push or a destructive SQL statement for a human even in auto mode or with --dangerously-skip-permissions.

Install

macOS · Linux · WSL
curl -fsSL https://agenticcontrolplane.com/install.sh | bash
Windows · PowerShell
irm https://agenticcontrolplane.com/install.ps1 | iex
A real recording, nothing mocked. The middle shows every file the one command wrote. Piping a script to bash deserves that. The recording predates a change on 2026-09-23: today the safety floor holds a force-push for your OK instead of blocking it after you approve, so the same run now ends with two allows and one ask.

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 / Ask first / Never per tool. Underneath, the safety floor in every mode: rm -rf on home or system folders always blocked; force-push, destructive SQL, and curl | sh held for your OK. 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 up to 5 agents · full install below

The installer detects Claude Code and installs the ACP plugin from its plugin marketplace. The plugin registers hooks for PreToolUse and PostToolUse (and session start and end). On an older Claude Code that has no plugin support, it writes the hook to ~/.acp/govern.mjs and registers it in ~/.claude/settings.json instead. Restart Claude Code (Ctrl+C, then claude --continue) and every tool call goes through the hook.

By default the installer opens your browser to create a workspace. Decisions come from the ACP API, every call lands in one Activity log, and the cost X-ray sits beside it. Free up to 5 agents. This is the mode to pick if you run more than one machine or more than one harness, because the rules live in one place.

Prefer fully on-device? Add --local. No browser, no account, nothing leaves your machine. Decisions are made by ~/.acp/decide.mjs against ~/.acp/policy.json (Allow, Ask first, or Never per tool, plus the safety floor), and every call is logged to ~/.acp/audit.jsonl. The trade is that the log stays on that one machine: no shared Activity view, no cost X-ray, no tiers, nothing to compare across agents. Re-run without --local any time to connect; the local record uploads once and keeps its timestamps.

How it works

Claude Code’s hook system runs a command before and after every tool call. ACP’s hook is one Node script, govern.mjs, registered for both events.

  • PreToolUse runs before the tool does. The hook POSTs the tool name, its input, the session ID, and the session’s tier to https://api.agenticcontrolplane.com/govern/tool-use. The gateway applies the safety floor, your rules, scopes, rate limits, and plan limits, and answers allow, ask, or deny. On deny the hook returns permissionDecision: deny and Claude Code never runs the call. On ask, Claude Code shows you the prompt in the session.
  • PostToolUse runs after the tool returns. The hook POSTs the tool output (cut at 200KB) to /govern/tool-output, along with the model turns from the session transcript it has not priced yet. The gateway scans the output for PII, prompt injection, and secrets, and flags findings in the audit log. It does not change the output on this path.

The hook gives the gateway 4 seconds. If no answer comes, the hook decides on its own (see below).

What leaves your machine, connected mode: the tool name and input (for Bash, the command text), the session ID and tier, tool output up to 200KB, and token counts and model names from the transcript. Credentials that appear in a command’s arguments are redacted before the record is stored. Your prompts and the model’s replies are not sent. In --local mode nothing is sent.

Default mode and the safety floor

A new workspace starts in audit mode: every call is recorded, the safety floor applies, and your own rules do not block anything yet. Run /acp-enforce in Claude Code, or flip it on the Policies page, when you have watched the log for a few days and know what your sessions do.

The safety floor is on in every mode, with or without rules:

  • Held for your OK: a force-push (--force, -f, or a +refspec), destructive SQL handed to psql, mysql, mariadb, or sqlite3 (DROP, TRUNCATE, DELETE without WHERE), a download piped into a shell (curl ... | sh), and a recursive delete outside the working directory.
  • Always blocked, no approval reaches it: rm -rf of home, root, or a system directory, mkfs, dd to a raw disk, a fork bomb.

In Claude Code a safety-floor hold appears as a prompt in your session (workspace owner or admin at the keyboard). Holds from your own Ask-first rules, and every hold in an unattended session, go to the console Approvals page and to the owner’s email; approve there, then ask the agent to retry. The floor reads shell command text only, so an MCP tool that deletes a database does not reach it; write a rule for that tool. An owner or admin can switch the floor off on the Policies page.

Full recipes, including what the floor does not catch: Rules that stop the scary things.

When ACP is unreachable

The answer depends on whether anyone is watching the session.

  • Interactive session (you at the terminal, including auto mode): the call runs and Claude Code prints [ACP] UNGOVERNED: gateway unreachable. The lapse goes to ~/.acp/lapse.log and is reported to the gateway on the session’s next governed call, so the gap shows in your audit log instead of disappearing. We do not freeze your session because our gateway had a bad minute.
  • Unattended session (subagent, background, claude -p, CI, --dangerously-skip-permissions): the call is blocked until the gateway answers. Nobody is there to read a warning, so the block is the safety net.
  • Both cases: the safety floor still applies on the machine, and a policy deny always blocks.

To make interactive sessions fail closed too, run echo closed > ~/.acp/failmode (or set ACP_FAIL_MODE=closed) on that machine (plugin 0.30.1 and later). The hook that Cursor, Codex and other harnesses use reads the same setting. A burst of parallel calls can be rate-limited by the gateway; that is not an outage. The hook reports it as a deny with a retry-after, and the agent is told to retry the same call.

What gets installed and where

Path Contents
ACP plugin (Claude Code’s plugin directory) The hook script govern.mjs, the /acp-* slash commands, and the bundled ACP MCP server. Installed with claude plugin install agentic-control-plane@acp.
~/.acp/credentials Your API key, written after the browser sign-in (connected mode).
~/.acp/decide.mjs, ~/.acp/policy.json, ~/.acp/audit.jsonl The on-device engine, your local rules, and the local log (--local mode; the engine is also the offline fallback in connected mode).
~/.acp/bin/claude-acp Optional launcher that routes model calls through ACP so they are metered and policy-checked.
~/.claude/CLAUDE.md A short directive telling agents that the hook is active and to launch claude-acp for priced sessions.
~/.acp/govern.mjs and ~/.claude/settings.json Fallback only, for a Claude Code without plugin support: the hook script and its PreToolUse and PostToolUse entries.

The installer is safe to re-run. It updates the plugin when a newer version exists, removes any older direct hook entries so a call is not checked twice, and leaves your other hooks alone. Check what is active with claude plugin list.

Why not auto mode plus a sandbox

Auto mode, the sandbox, and allowlists are good, and ACP does not replace them. They are per harness, per machine, and the agent’s own harness evaluates them. Three things they leave open:

  1. No record anyone else can read. The sandbox stops a bad write; it does not tell you on Monday what the overnight run did. ACP writes every call to one log with the decision and the cost.
  2. Rules that differ by harness. If you also run Codex, Cursor, or opencode, each has its own permission model and its own config file. ACP’s rules are the same keys on every harness, set once.
  3. The hold is a model’s call. Auto mode’s classifier blocks a force-push by default, but that is a model deciding, in one harness, and a block can be cleared in conversation by naming the branch. The safety floor is a pattern match in a hook, the same on every harness: a force-push asks a person in every permission mode. It is still a hook, so disableAllHooks or removing the hook entry switches it off.

If you only ever run one Claude Code session on one laptop and read it as it goes, you may not need ACP. The case gets stronger with each unattended run and each extra harness.

What you will see in the dashboard

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

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

The Activity log shows each call with its identity, scopes, decision, latency, PII findings, and, for subagent runs, the chain back to the session that spawned it. The Sessions view (toggle at the top of Activity, or /sessions in Claude Code) shows one run call by call with its cost.

Setting up rules

Rules are keyed by tool and command: Bash.rm, Bash.git.push, Bash.curl.api.github.com, Edit. A rule on a shorter key covers everything under it, and the most specific key wins. Three places a rule can live:

  1. Workspace rules (Policies → Tools): apply to every session. Make Bash.rm Ask first for everyone here.
  2. Tier rules (Policies → Agents): separate rules for interactive, subagent, and background. This is how you let your own sessions push while an overnight run cannot.
  3. User rules (Policies page): overrides per person.

The most restrictive rule wins. From inside Claude Code, /acp-ask Bash.git.push, /acp-deny Bash.rm, and /acp-allow Bash.npm write interactive-tier rules; the hook prints a link you confirm with one tap, so a stray or injected command cannot change policy on its own. Tier rules for unattended sessions are a console job.

How Claude Code sessions map to tiers: a normal session, including auto mode, is interactive. A Task-spawned subagent is subagent. --dangerously-skip-permissions, claude -p, SDK-driven runs, and CI are background.

For an unattended run, the setup that holds up is in rules, section 5: set Bash.rm, Bash.git.push, Bash.curl, and your database clients to Never for background and subagent, leave interactive on Ask first, and keep production credentials out of the agent’s environment.

Limitations

What ACP’s Claude Code integration cannot do today:

  • --dangerously-skip-permissions removes the prompts, not the hooks. The session runs in bypassPermissions, which auto-allows everything Claude Code itself would have asked about. PreToolUse hooks still fire (the hook sees permission_mode: "bypassPermissions"), and an ACP deny still blocks. What you lose is the human in the loop, so the rules you wrote beforehand are the only thing standing. What the flag turns off
  • The hook cannot rewrite a call or its output. PreToolUse can allow, ask, or deny; it cannot change the tool input. PostToolUse can flag findings; it cannot redact the output before the model reads it. Tool-result redaction runs on the proxy path (claude-acp), where ACP sits between Claude Code and the model.
  • Subagent attribution is partial. When Claude Code spawns a subagent with subagent_type: "Explore", ACP records the spawn with that name. The subagent’s own Bash and Read calls show as the subagent tier without the parent’s name, because the hook payload does not carry it. We have asked upstream.
  • The gateway timeout is fixed at 4 seconds. A slower answer counts as unreachable and follows the rules in the section above.
  • The floor reads shell commands only. An MCP tool or a Write that does something destructive is covered by your rules, not by the floor.
  • Offline work needs --local. Connected mode with no network behaves as “unreachable” above: interactive calls run with a warning, unattended calls are blocked. For a machine that is offline by design, install with --local; rules are evaluated on the machine and nothing is sent.

Troubleshooting

Hook is not firing. Restart Claude Code completely (Ctrl+C, then claude --continue). Hooks are read at session start. Check claude plugin list shows agentic-control-plane.

Every tool call is blocked. Either the session is an unattended tier and the gateway is unreachable, or a rule is denying the calls. The block message says which: [ACP] Gateway unreachable or [ACP] Denied by policy. For a rejected key, check that ~/.acp/credentials exists and re-run the installer to sign in again.

govern.mjs: command not found. The hook runs node. Make sure Node 18 or newer is on the PATH for non-interactive shells (zshrc or bashrc, not only zlogin).

Hook fires but nothing appears in the dashboard. The Activity page is scoped to one workspace. If you have several, switch in the top-right dropdown and check which workspace your key belongs to.

--dangerously-skip-permissions was used and there is a gap in the audit log. Not expected: hooks fire in bypass mode too. A gap means the hook itself did not run. Check claude plugin list, or on the fallback path that the PreToolUse entry is still in ~/.claude/settings.json and ~/.acp/govern.mjs exists.

Add the cost X-ray

The hook sees tool calls, not tokens. But Claude Code hands it the session transcript path on every PostToolUse, and the transcript records each model turn’s input, cache-read, cache-write, and output tokens with the model name. The hook reads the turns it has not reported yet and sends them with the tool-output report it already makes. ACP prices each turn at list rates, cache included, and writes it beside the tool calls. A plain claude session gets the cost X-ray with no launcher and no env var, and it works on a Max subscription (the figures are what the same tokens would cost through the API, not a charge).

Two things still need the proxy path: policy on the model call itself (denied tool_use blocks stripped before the harness sees them, tool-result redaction) and the declared tool surface, which is read from request bodies. For those, set ANTHROPIC_BASE_URL=https://api.agenticcontrolplane.com/anthropic with your ACP key (gsk_...) as ANTHROPIC_AUTH_TOKEN, or launch with claude-acp, which the installer writes.

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 who ran it, the decision, latency, and, for subagent runs, the chain back to the session that spawned them. With --local the same record goes to ~/.acp/audit.jsonl on your machine instead.

Can I block specific Claude Code tools or commands?

Yes. Rules are keyed by tool and command (Bash.rm, Bash.git.push, Bash.curl.api.github.com) and set to Allow, Ask first, or Never. Workspace rules apply to everyone; tier rules apply to interactive, subagent, or background sessions; user rules override per person. The most restrictive rule wins. A deny is returned to the PreToolUse hook and Claude Code never runs the call. A new workspace starts in audit mode, where rules are recorded but not enforced until you run /acp-enforce.

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

No. The flag turns off Claude Code’s own permission prompts, not its hooks. PreToolUse hooks fire in every permission mode, and an ACP deny still blocks the call. ACP reports such sessions as the background tier, so you can give them stricter rules than your interactive sessions. What the flag removes is the human confirmation step, so the rules you wrote beforehand are the whole boundary.

What happens if the governance service is unreachable?

It depends on who is watching. In an interactive session the call runs and Claude Code prints a loud UNGOVERNED warning; the lapse is logged locally and reported when the gateway is back. In unattended sessions (subagent, background, claude -p, CI) the call is blocked until the gateway answers. The safety floor applies in both cases, and a policy deny always blocks. To block interactive calls during an outage too, run echo closed > ~/.acp/failmode on that machine.

Can ACP show what my Claude Code sessions cost?

Yes, from the hook alone. Claude Code hands the PostToolUse hook the path to the session transcript, which records every model turn’s tokens and model. The hook reports the turns it has not seen yet and ACP prices them at list rates, cache reads and writes included. No launcher, no env var, and it works on a Max subscription (the figures are API-rate equivalents, not charges). The claude-acp launcher is still there if you want policy on the model calls themselves.

Protected in 3 steps

Out of the box, ACP records every tool call your agents make. A short safety floor applies in every mode: catastrophic commands (rm -rf on your home or system folders, disk wipes) are always blocked, and force-push, destructive SQL, piping a download into a shell, and deleting outside your project are held for your approval. Your own rules (ask first / never) start applying when you turn on enforce. No rule can loosen the floor; a workspace owner or admin can switch it off on the Policies page (you were asked at install). With --local the always-blocked list is narrower: rm -rf on your home or root, disk wipes, fork bombs.

  1. 1
    Install. One command, then approve this machine in the browser. curl -fsSL https://agenticcontrolplane.com/install.sh | bash
  2. 2
    Turn on your rules. Run /acp-enforce in your agent. The starter rules start applying: rm and keychain reads are held for your approval (you approve on the console Approvals page or from the approval email); everything else keeps running and is recorded. Add your own with /acp-ask Bash.curl, /acp-deny Bash.git.push, /acp-allow Bash.npm, or on the Policies page. With --local there is no mode switch: the rules in ~/.acp/policy.json apply from the first call, and the starter file asks before rm, curl, git push, chmod and chown.
  3. 3
    See it work. Ask your agent to do something risky, for example git push --force on a scratch repo. ACP holds the call for your approval; the call and your answer land in the audit log (/acp-why for the last hold, the console Activity page, or ~/.acp/audit.jsonl with --local). In Claude Code, a safety-floor hold is a prompt you answer right in the session (workspace owner or admin); holds from your own rules are approved on the console Approvals page or from the approval email, then ask the agent to retry.

Copy-paste rules for the things people are most afraid of (force-push, prod database, rm -rf, a secret in a curl, overnight runs, a cost cap): Rules that stop the scary things.