# Harness Coverage Matrix — What ACP Intercepts on Each Coding Agent

The living cross-harness table: for Claude Code, Codex CLI, Cursor, Hermes, opencode, OpenClaw, pi, Prime Agent, DeepSeek Harness, Grok Build, Antigravity, and Muse Code — what the pre-call check intercepts, whether policy can ask a human, and whether tool output can be rewritten before the model reads it.

# Harness coverage matrix

*This page documents what **ACP** intercepts on each harness. For the companion question — what each harness ships **natively** (approval modes, rules, sandboxing, audit) — see [Which coding agent has the best native controls?](/controls)*

Every harness exposes a different interception surface, and the honest answer to "am I covered?" is per-harness. This page is the living record — updated with every integration we ship. Three questions matter:

1. **What does the pre-call check intercept?** If the hook doesn't fire for a tool, policy never sees it.
2. **Can policy ask a human?** `deny` is easy; a usable control layer needs an approval path.
3. **Can the result be rewritten inline?** Output scanning that can't act is observational — a leaked credential still reaches the model.

<div class="acp-post-wide-table" markdown="1">

| Harness | Install | Pre-call check intercepts | Policy can ask a human? | Result rewritten inline? |
|---|---|---|---|---|
| **Claude Code** | [guide](/integrations/claude-code) | All native tools + MCP | Yes — native `ask` | Yes |
| **DeepSeek Harness (dsh)** | [guide](/integrations/dsh) | Everything — native tools, custom plugins, Code Mode sub-calls | Yes — `ask` feeds dsh's own approval prompt; headless asks deny by design | Yes — `tools/post-execute` can replace result content |
| **Muse Code** (Meta) | [guide](/integrations/muse-code) | Everything — one hook pipeline over native tools | Yes — `PermissionRequest` maps to policy; deny settles the native prompt | Yes — `PostToolUse` block becomes model-visible feedback |
| **pi** (earendil-works) | [guide](/integrations/pi) | Everything — four built-ins + custom tools; no MCP layer to miss | Yes — inline confirm when `ctx.hasUI`, deny when not | Yes — `tool_result` replaces content |
| **Prime Agent** (Prime Intellect) | [guide](/integrations/prime-agent) &middot; [npm: @agenticcontrolplane/prime-agent](https://www.npmjs.com/package/@agenticcontrolplane/prime-agent) | Everything — the ipython kernel and custom tools flow through one `tool_call` event; MCP arrives as Python skills inside the kernel, so there is no second dispatch path | Yes — the prompt is the probe: an `ask` goes through Prime Agent's own confirm, and denies when nothing answers (its `ctx.hasUI` can't be trusted, [contract](/controls/prime-agent)) | Yes — `tool_result` rewrites `content`, `details`, and `isError` |
| **Grok Build** (xAI) | [guide](/integrations/grok-build) | Everything — one hook pipeline over native tools + MCP (`server__tool`), fires in every mode incl. always-approve | Mode-aware — attended asks land on Grok's native prompt; unattended asks deny with the console link | No — only `PreToolUse` blocks; post-hoc flags surface loudly + land in the audit log |
| **Antigravity** (Google) | [guide](/integrations/antigravity) | Everything — one hook registration over native tools + MCP across the CLI, IDE, and app | **Native** — ACP asks map to `force_ask` prompt cards (cached Always-Allows can't pre-empt); headless soft-denies natively | No — `PostToolUse` carries no tool output ([contract](/controls/antigravity)); post-hoc record is audit/completion only |
| **Cursor** | [guide](/integrations/cursor) | Most native tools (some built-ins don't emit; bugs filed) | Yes | No |
| **Hermes Agent** | [guide](/integrations/hermes) | Everything, in-process — native and custom skills | No — `block` only; `ask` maps to block + dashboard approval | No — post hook is observational |
| **opencode** | [npm: acp-opencode](https://www.npmjs.com/package/acp-opencode) | Permission-routed tools + deny-only backstop for the rest | Yes — via the permission system | No |
| **OpenClaw** | [guide](/integrations/openclaw) | Native plugin surface | Yes | No |
| **Codex CLI** | [guide](/integrations/codex) | Bash only; file edits need the MCP supplement | No — `ask` maps to deny + dashboard approval link | No |
| **fx** (Vercel Labs) | [guide](/controls/fx) &middot; [npm: @agenticcontrolplane/fx](https://www.npmjs.com/package/@agenticcontrolplane/fx) | Every approval-gated call fx routes to `session/request_permission` — not a hook over all tool calls | Yes — relays the original prompt to your client for a human decision | No — it's a permission gate on the protocol seam, not an output rewrite |

</div>

A few rows deserve a note. **Claude Code** has been the reference surface since day one. **DeepSeek Harness** was the first harness since to land in the rightmost column on all three questions — its typed interception points (`tools/pre-execute` returning allow/ask/deny, `tools/post-execute` able to replace content) were designed for exactly this, and its headless composition denies unanswerable asks by itself. **Muse Code** joins them: its hooks ship as plugin capabilities (behind an experimental flag today) speaking Claude Code's exact hook contract, verified against the harness's own capability runner — [the write-up](/blog/muse-code-acp-integration) covers where its docs run ahead of the shipped binary.

## What "covered" means here

The same wire contract backs every row: the pre-call check posts to `/govern/tool-use` and maps the server's `allow` / `ask` / `deny` onto whatever the harness can express; the post-call report goes to `/govern/tool-output` for output scanning and the audit trail. One workspace, one policy set, every harness — a deny on Claude Code is a deny on dsh.

Where a harness can't express something (Codex has no ask; Hermes can't rewrite), the plugin degrades explicitly and the row above says so. We'd rather publish the limitation than paper over it — a coverage gap you know about is a policy decision; one you don't is an incident.

## If you're building a harness

The spec that earns the full row: one pipeline every tool dispatch flows through, a typed pre-call decision with allow/ask/deny, a post-call hook that can rewrite what the model sees, and deny-by-default for asks nobody can answer. dsh shipped all four in a developer preview; the write-ups for [Hermes](/blog/hermes-agent-acp-integration) and [dsh](/blog/deepseek-harness-acp-integration) go deeper on why those designs worked.

**fx** (Vercel Labs) is a different shape than the rest of the table: it has no plugin API, so there's no hook over every tool call. The seam is `fx acp` — an Agent Client Protocol server that routes every approval-gated call to the connected client with full raw arguments, and fails closed on error. [`@agenticcontrolplane/fx`](https://www.npmjs.com/package/@agenticcontrolplane/fx) stands there as protocol middleware, not a hook plugin — [what it does](/controls/fx).

*Updated 2026-09-02, with the fx protocol-middleware row. This page changes whenever a harness integration ships or a harness closes a gap.*
