Enforcement Coverage by Tool
Supported modes: Hosted Hybrid Local Available in: Free Solo Teams
Control Zero enforces your policy across everything each coding tool exposes through its hook system. We attach to each agent's official pre-execution hook and gate every tool the vendor routes through it, failing closed if a decision is ever uncertain. What's coverable is set by each vendor: coverage is complete within that hook surface, differs by tool, and expands automatically as vendors add hooks. Where a vendor doesn't expose an action to hooks (or its hooks are limited), that's a boundary set by the vendor -- shown plainly and attributed, never hidden, never a Control Zero defect.
How it works
Control Zero governs a coding agent by attaching to that agent's own official pre-execution hook -- the point the vendor provides for an external system to inspect, and approve or deny, an action before it runs:
- Claude Code:
PreToolUse - Gemini CLI:
BeforeTool - Codex CLI, Kiro, Antigravity, Cursor: the vendor's equivalent pre-tool hook
Three facts follow from this design:
- A hook can only gate what the vendor routes through it. If a vendor sends a tool call to its pre-execution hook, Control Zero sees it and decides on it. If a vendor runs an action on a path that never reaches the hook, no external governor -- ours or anyone's -- can gate it. That boundary belongs to the vendor's hook surface, not to Control Zero.
- Vendors expose different surfaces, and they evolve them. Some tools route every action through one hook today; others are still widening their hook coverage. Both are normal points on the same trajectory, and the trajectory is toward more coverage.
- Control Zero is designed to fail closed. When a rule's outcome is ambiguous, Control Zero denies rather than allows. One known exception is being closed: on the exit-code hosts (Gemini / Codex / Claude) a genuine pre-parse error -- unreadable hook input or an unreadable policy file -- currently proceeds rather than denying; that error path is being hardened to fail closed (see the per-row caveats below). See Enforcement Behavior for the exact decision contract.
What Control Zero guarantees
For every tool a vendor exposes to its pre-execution hook and enforces a deny on:
- A Control Zero deny blocks the action before it runs -- not after, not as a warning. A policy you author once produces the same verdict on every surface. Whether that verdict is enforced depends on the vendor's hook honoring a deny: it is on Claude Code and Gemini CLI; it is on Kiro CLI for direct (non-sub-agent) tool calls; and the per-tool exceptions a vendor doesn't yet enforce are listed, attributed, in the table below.
- The decision path aims to fail closed: a matched rule whose outcome is ambiguous denies rather than allows. One known gap remains on the exit-code hosts (Gemini / Codex / Claude): a genuine pre-parse error -- unreadable hook input or an unreadable policy file -- currently exits 0 (proceed) rather than denying. Hardening those error paths to fail closed is in progress and is noted per row.
- We never claim to control what a vendor doesn't expose, or doesn't enforce. The dashboard's audit log shows per-tool coverage attributed to the vendor, so what you see in the product matches what you read here.
This page is the single source of truth for the per-vendor coverage facts below. The same data drives the dashboard's per-row coverage labels, so the documentation and the product never disagree.
Coverage by tool
Coverage is complete within each vendor's hook surface. Where a column reads "vendor-set boundary," that is a limit of what the vendor currently exposes to hooks -- attributed to the vendor, with the reason -- and it lifts automatically as the vendor expands its hooks and we ship the matching adapter update.
| Tool / Surface | What Control Zero enforces | Vendor-set boundary (and why) | Tip to maximize coverage |
|---|---|---|---|
| Claude Code | Complete within Claude Code's hook surface: every tool via PreToolUse. A deny is delivered as a top-level decision: "block" (a deprecated-but-honored alias Claude Code still accepts) plus exit code 2 -- the exit code is the reliable floor. | None material -- Claude Code routes its tools through PreToolUse. | Already complete; keep the hook installed. Use Claude Code >= v2.1.90 for the most reliable hook-decision handling. |
| Gemini CLI | Complete within Gemini CLI's hook surface: every tool via BeforeTool. A matched rule denies via a stdout decision: "deny" and/or exit code 2. | None material on the gate itself -- Gemini CLI routes its tools through BeforeTool. Error-path caveat: Gemini is an exit-code host, and on a genuine pre-parse failure (unreadable / malformed hook input or an unreadable policy) the current hook exits 0, which Gemini reads as proceed (fail-open on that error path). A matched policy rule still denies normally; only the read/parse-error path is affected. Hardening this to fail closed on a genuine error is in progress. | Keep the hook installed. Gemini's own BeforeTool decision: "ask" HITL support landed in PR #21146 (merged 2026-03-21); pin a Gemini CLI build that includes it before relying on ask-style confirmation. |
| Codex CLI | In the interactive TUI, Bash commands are reliably enforced via Codex's PreToolUse hook (deny blocks before the command runs). | Several limits are set by Codex (vendor-attributed, with the upstream issue): (1) apply_patch / MCP deny is not enforced by Codex today -- the hook fires but the write still proceeds (upstream Codex #27833, open); (2) headless codex exec dispatches no hooks at all (upstream Codex #26452, open) -- it fails open and silently, so unattended / CI Codex runs are ungated; (3) Codex does not expose unified_exec or WebSearch to its hook. | Govern Codex in the interactive TUI (where Bash is enforced), not via codex exec, until upstream fixes the headless and apply_patch/MCP deny paths. Add Codex's own command-allowlist as a complementary layer. |
| Kiro CLI | Direct tool calls via preToolUse (a deny blocks via exit code 2). | Sub-agent tool calls are not gated by Kiro -- Kiro does not run preToolUse hooks for sub-agents, so a sub-agent action bypasses the gate (upstream Kiro #7671, open / High; by-design per Kiro #7755). This is why the surface is partial, not fully enforced. | Enforced for direct tool calls today; sub-agent gating lands when Kiro fires hooks for sub-agents. For now, restrict sub-agent tools or use tool-level deniedPaths as a complementary layer. |
| Kiro IDE | Monitored (audit) today: Control Zero records every action on the IDE surface. | Kiro IDE's pre-tool hook does not yet deliver the tool details to the hook (upstream Kiro #6188 / #7500), so a content-aware block is not possible on the IDE surface yet. | Use Kiro CLI for full enforcement today; Control Zero will enforce on the IDE the moment Kiro delivers tool details to the hook. |
| Antigravity IDE -- shell/file enforcement COMING SOON | Monitored (audit) and enforced for the tools Antigravity routes to its PreToolUse hook: reads/searches (e.g. list-dir, view-file) are observed and DLP-scanned. Shell (run_command) and file-write run through Antigravity's own native confirmation dialog and are NOT delivered to the hook, so Control Zero never sees those calls -- it can neither block NOR audit them on Antigravity today. The IDE and the agy CLI share the same ~/.gemini/config/hooks.json contract; the audit log tags each surface (Antigravity IDE / Antigravity CLI). | Antigravity routes only a subset of tools (reads/searches) to PreToolUse; destructive shell/file actions use the native dialog, not the hook, so they are outside Control Zero's view entirely (being validated host-in-loop; tracked for a partner integration so we can enforce shell on Antigravity). | Use Antigravity's native confirmation for shell, and Claude Code or Gemini CLI when you need Control Zero to hard-block + audit shell/file. Control Zero observes only what Antigravity routes to the hook (reads/searches). Install with controlzero install antigravity --surface ide to tag IDE actions. |
| Antigravity CLI (agy) -- shell/file enforcement COMING SOON | Monitored (audit) and enforced for the tools agy routes to PreToolUse (reads/searches, DLP-scanned). agy decides from the stdout JSON decision (the exit code stays 0 -- agy's documented contract is the stdout token, not the exit code); Control Zero always emits an explicit decision (agy reads an empty {} as invalid_args). agy runs shell (run_command) and file-write through its own native confirmation dialog, not the hook, so Control Zero never sees those calls -- it can neither block NOR audit them on agy today. Shares the IDE's hook contract; the audit source distinguishes the two surfaces. | agy routes only a subset (reads/searches) to PreToolUse; shell/file use the native dialog, not the hook, so they are outside Control Zero's view entirely (being validated; tracked for a partner integration). | Use Claude Code or Gemini CLI for hard shell/file enforcement + audit; rely on agy's native confirmation for shell. Pin a recent agy build. Install with controlzero install antigravity --surface cli to tag agy actions. |
| Cursor IDE -- BETA | The Control Zero Cursor adapter is shipped: install it with controlzero install cursor (writes .cursor/hooks.json with failClosed: true). It governs Cursor's own hooks (beforeShellExecution / beforeMCPExecution / beforeReadFile / afterFileEdit), which gate shell, MCP, and file operations. | Cursor enforces only deny on hooks today -- ask and allow are not enforced by Cursor (vendor-confirmed). Cursor hooks also fail open by default on a crashing / timed-out / invalid-output hook unless failClosed: true is set; the Control Zero adapter sets it. The adapter is new (shipped 2026-06-18) and Cursor's hook surface is itself a Cursor beta, so treat coverage as soaking. | Install with controlzero install cursor; it installs failClosed: true and renders an ask / HITL outcome as a deny (fail-safe), since Cursor does not enforce ask. Audit rows carry source = "cursor_ide". |
| Cursor CLI (cursor-agent) -- BETA | The Control Zero Cursor adapter is shipped; the same controlzero install cursor writes the .cursor/hooks.json that the cursor-agent CLI also reads. Cursor CLI's hook coverage (shell, expanding to MCP / file) is BETA. | Same vendor limits as Cursor IDE: only deny is enforced; hooks fail open by default unless installed with failClosed: true (the adapter sets it). A new adapter on a Cursor-beta hook surface, so coverage is soaking; the exact CURSOR_* env marker on a live cursor-agent run is still being validated. | Install with controlzero install cursor; it installs failClosed: true. Audit rows carry source = "cursor_cli". |
What to expect
- Coverage grows automatically. As vendors expand the actions they route through their hooks, and as we ship the matching adapter updates, coverage widens with no policy changes on your side.
- Where an IDE surface is vendor-limited, the matching CLI often has broader coverage. Kiro is the clearest example today: Kiro CLI enforces direct tool calls, while the Kiro IDE surface is monitored-only until the vendor delivers tool details to its IDE hook. Note that Kiro CLI does not yet run hooks for sub-agent tool calls (upstream Kiro #7671), so a sub-agent action can bypass the gate -- this is a vendor boundary, attributed in the table above, and lifts when Kiro fires hooks for sub-agents.
- The dashboard tells you exactly where you stand. Each row in the audit log shows the source (which tool and surface produced the action) and the coverage for that surface, attributed to the vendor. That per-row coverage label is driven by the same data documented on this page.
Related
- Enforcement Behavior -- the decision contract (fail-closed defaults, the four knobs) every surface shares.
- Hook action extraction -- how the hook turns a tool's arguments into a matchable
tool:methodaction string. - Coding hooks guide -- how to install the hook in each supported coding agent.
- Why is my tool denied? -- the fast fix when a policy blocks a tool you expected to allow.