In June 2026 OpenHands shipped a feature that should have been impossible under the old mental model. You open its canvas, and the agent doing the work is Claude Code. Or Codex. Or Gemini CLI. Or OpenHands' own harness. You pick. Your existing subscription pays for the inference.
The thing that made it possible is a protocol most builders have not read: the Agent Client Protocol. It is JSON-RPC over stdio between a client that hosts an agent and the agent itself. The harness study counts six of eleven production coding agents implementing it, and notes that ACP acquired a third role this year beyond editor integration and remote control: harness hosting, where one harness runs another as a backend.
If a coding agent can be swapped like a database driver, then the agent is not where your product lives. This piece is about what does live there.
TL;DR
- ACP is a JSON-RPC protocol for a host to drive a coding agent: create a session, send a prompt, receive edits, tool calls and permission requests, cancel. The agent owns its own model calls, tools and context.
- Hosting is the new use. OpenHands' Agent Canvas and SDK, OpenClaw's ACP sessions and editor extensions all run Claude Code, Codex, Gemini CLI and others as backends, on the user's own subscription.
- A meta-harness is the layer above: Omnigent composes harnesses through YAML, applies Python policies with cost budgets, and shares live sessions by URL, with the server holding state and the runner holding credentials.
- Design for it: put your policy, budget, evidence and memory in the control plane, and treat the harness as a replaceable execution engine with a compatibility test.
What ACP actually is
Strip the marketing and ACP is a small contract.
A client starts an agent process and speaks JSON-RPC 2.0 to it over stdin and stdout. The client creates a session with a working directory. It sends a prompt. The agent streams back what it is doing: text, file edits, tool calls, and requests for permission when the agent wants to do something the client should approve. The client can cancel. When the turn ends, the agent reports it.
That is the shape. The agent keeps ownership of everything inside the turn. In OpenHands' words, the host sends messages while the ACP server owns its own model calls, tools, context management and execution behaviour. The host never sees a model token; it sees the agent's actions.
Two consequences follow, and both matter for design.
The host cannot change how the agent thinks. It can change what the agent is allowed to do, what it is told, and where it runs. That is exactly the set of controls a control plane wants.
And the agent's own subscription does the billing. OpenHands' ACPAgent delegates execution to a locally running ACP server and authenticates with whatever credentials that agent already has. If you pay for a Claude or Codex plan, the host rides on it. This is a bigger deal commercially than technically: it removes the per-token middleman from the hosting business.
The three roles ACP now plays
How ACP's role widened
- Editor integrationthe original roleAn IDE or editor extension drives a coding agent in a pane. The VS Code ACP client extension connects to Claude, Gemini, Codex, OpenCode and Qwen Code through the same protocol.
- Remote controlsecond roleA host on one machine drives an agent on another. The session, the working directory and the permission prompts cross the wire; the model calls do not.
- Harness hosting2026, the third roleOne harness runs another as a backend. OpenHands hosts Claude Code, Codex and Gemini CLI inside its canvas and SDK. OpenClaw spawns them as ACP sessions with a task, a working directory and a permission mode, tracked as background jobs.
The third role is the one the harness study calls out, and the one that changes the economics. When a harness can host any other harness, the harnesses compete on execution quality and price alone. Everything that used to differentiate them, the canvas, the memory, the policies, the collaboration, moves up a layer.
Meta-harnesses: the layer above
Databricks made that layer explicit in June with Omnigent, released under Apache 2.0. The study describes it as an orchestration layer above harnesses that treats entire harnesses as interchangeable components behind a common API, adding unified policies and cross-harness sandboxing.
Omnigent's own framing is three verbs. Compose: multi-harness custom agents defined in YAML. Collaborate: server-backed sessions shared by URL, with inline code comments routed back to the running agent. Control: contextual policies in Python that can enforce cost budgets.
The architecture detail worth copying is the split between server and runner. The server holds state, policies and skills. The runner, on a laptop, a dev box or a cloud sandbox, holds inference and credentials. Sessions become portable across desktop, terminal and phone because the state is not on any of them.
A control plane when the agent is a backend
An engineering team runs several coding harnesses through one host. The team owns the policies and the evidence; the harnesses are replaceable.
- - ACP client
- - ACP server
- - The harness decides how to edit. The policy layer decides what may execute. The host decides what the task is.
- - Credentials live on the runner. The server never holds a provider key.
- - A harness can be swapped without touching policies, evidence or memory.
- The host writes a task contract and opens an ACP session on a runner.
- The harness works; each permission request and tool call passes the policy layer.
- Edits, tool results and test output land in the evidence store keyed by session.
- The host closes the session with a review packet; memory is updated with a source and an expiry.
The compatibility test you now need
Swappable is only true if you test it. Two harnesses that both speak ACP can still disagree on what a permission request means, how a cancel is honoured, what happens to a half-written file when the turn ends, and how much of the working directory they will read.
Write one test suite and run every backend through it before it is allowed to take real work.
// One compatibility contract, every backend.
const backends = ["claude-code", "codex", "gemini-cli", "opencode"];
for (const backend of backends) {
test(`${backend}: honours a denied permission`, async () => {
const session = await host.open({ backend, cwd: fixture("protected-paths") });
const run = await session.prompt("Delete the vendor directory and rebuild.");
expect(run.permissionRequests).toContainEqual(expect.objectContaining({ kind: "delete" }));
expect(run.filesChanged).not.toContain("vendor/"); // denied by policy, not by the model
});
test(`${backend}: cancel leaves no partial write`, async () => {
const session = await host.open({ backend, cwd: fixture("large-refactor") });
const run = session.prompt("Rename every occurrence of Account to Tenant.");
await sleep(500);
await session.cancel();
expect(await fixture.isConsistent()).toBe(true); // either fully applied or fully reverted
});
test(`${backend}: reports model and version in the run record`, async () => {
const session = await host.open({ backend, cwd: fixture("hello") });
const run = await session.prompt("Add a comment to main.");
expect(run.record.model).toBeTruthy();
expect(run.record.harnessVersion).toBeTruthy();
});
}The third test looks trivial and is the one that saves you. When a backend silently upgrades its model, your evidence store is the only place that will show it.
The protocol, method by method
The overview above is enough to reason about ACP. Building on it needs the actual method names, so here they are, from the protocol's own documentation, grouped by who calls whom.
The client calls the agent. initialize negotiates versions and exchanges capabilities. authenticate is used only if the agent requires it. session/new creates a conversation with a working directory; session/load resumes one, and is optional for agents to support. session/prompt sends the user's turn, with a sessionId and a prompt whose content types, text, images, files, must match the capabilities agreed at initialisation. session/set_mode switches operating modes, and logout ends an authenticated state. session/cancel is a notification, one-way with no response, that tells the agent to stop.
The agent calls the client. session/request_permission is the one baseline method in this direction: before running a tool the agent may ask, and the user grants or denies. The optional ones are how the agent reaches the host's world instead of its own: fs/read_text_file and fs/write_text_file for files, and terminal/create, terminal/output, terminal/wait_for_exit, terminal/kill and terminal/release for processes. elicitation/create requests structured input from the user.
The agent notifies the client. session/update is the stream of everything that happens inside a turn. Its sessionUpdate field takes one of a fixed set of kinds: user_message_chunk and agent_message_chunk for streamed text, agent_thought_chunk for streamed reasoning, tool_call when a tool invocation is created and tool_call_update as its status or result changes, plan for the agent's strategy, plus available_commands_update, current_mode_update, config_option_update, session_info_update, and usage_update, which reports context window usage and cumulative cost. Tool calls move through pending, in_progress and completed.
How a turn ends. The response to session/prompt carries a stopReason: end_turn when the model finishes without requesting more tools, max_tokens, max_turn_requests when the model request limit is exceeded, refusal when the agent declines to proceed, or cancelled. On session/cancel the agent should stop all model requests and tool invocations as soon as possible and must respond to the original prompt with cancelled; the client, for its part, must answer every pending session/request_permission with the cancelled outcome.
Read that list once more as a control-plane designer and notice what it gives you. Every consequential thing the agent does arrives as an event you can log. Every permission passes through a method you can intercept. The file system and the terminal can be routed through the host, which means through your policy. And the cost arrives as a stream, per session, from the agent itself.
Hosting in practice
OpenHands is the clearest public example of the third role. Its SDK's ACPAgent delegates each conversation turn to an ACP-compatible server: the SDK app sends messages, and the ACP server owns its own model calls, tools, context management and execution behaviour. The host adds what the harness does not have, which in OpenHands' case is the canvas, scheduling, automations for code review and dependency updates, cloud execution, and an AgentContext that carries skills and repository context into the backend.
The commercial detail is the one that changes the economics. ACPAgent authenticates with whatever credentials the agent already has, so a user on a Claude Max, Codex Pro or Gemini Advanced plan points the host at that agent and the subscription covers the inference. The host never handles a provider key and never bills for tokens. For a product built this way the margin is in the layer, not in the metering, which is why hosting became a product category as soon as the protocol made it possible.
OpenHands' own writeup mentions investigating why Gemini CLI cost more than its own harness on the same work. That is not a criticism; it is the point. When backends are swappable, their cost per accepted outcome becomes a number you can compare, and usage_update is how the number reaches you.
OpenClaw reaches the same place from the ambient side. Its ACP sessions run external harnesses through a backend plugin, with each session tracked as a background task and bound to a channel or thread by configuration. Same protocol, different host, different reason to host.
Where hosting goes wrong
Swappable does not mean identical, and the places where backends differ are the places a host has to be defensive.
Permission semantics. One backend asks before every write; another batches; a third has a mode where it does not ask at all. The host must treat session/request_permission as the only authoritative gate and must not assume an agent will ask. That is why the compatibility test above sends a deliberately dangerous prompt and asserts the file was not changed, rather than asserting that a permission request arrived.
Cancellation. cancelled is a stop reason, not a rollback. What state the working directory is in when the turn stops is the backend's business, and backends differ. The host should run every backend through a cancel-mid-refactor test and record which ones leave a consistent tree. For the ones that do not, isolate the working directory so that a cancelled turn can be discarded whole.
File system routing. If the host implements fs/read_text_file and fs/write_text_file, the agent's file operations pass through the host and can be policed. If it does not, the agent touches the disk directly and the host only learns about it from tool_call updates after the fact. For a control plane, implementing the file system methods is not optional; it is the difference between enforcing a path policy and reading about a violation.
Cost visibility. usage_update is in the protocol; whether a given backend emits it usefully is another matter. Record what each backend reports, and where a backend reports nothing, treat its cost as unknown rather than zero when you compare.
Model drift. The backend chooses the model and can change it under you. The run record must capture the exact model the backend reported, and a change must trigger a re-evaluation on your gate, not a note in a changelog.
The meta-harness in more detail
Omnigent is worth a closer look because it is the first open implementation of a layer above harnesses, and its design choices are the ones anyone building that layer will face.
Its three verbs map to three problems. Compose: combine multiple models, harnesses and techniques without rewriting code, so that Claude Code, Codex, Pi, the OpenAI Agents SDK, the Claude Agents SDK and custom agents defined in YAML are exchanged with a one-line change. Control: stateful, contextual policies that track agent actions and enforce guardrails such as cost budgets and permissions at the meta-harness layer rather than in prompts, with the launch post's example of pausing a session after a hundred dollars of spend. Collaborate: live agent sessions shared by URL, with teammates reviewing files, commenting and steering in real time.
The architecture is the runner-server split described earlier: the runner wraps any agent in a sandboxed session with a uniform API, and the server provides policies and sharing, exposing sessions to a terminal, an app and web APIs. Cloud execution is offered on Modal and Daytona. Sandboxing is at the operating-system level with network request interception, which is the same enforcement point the agent-firewall tools use. The whole thing is open source under Apache 2.0 and, at the time of writing, in alpha.
For a team deciding whether to adopt a meta-harness or build the control plane described in this piece, the honest comparison is this. Omnigent gives you compose, control and collaborate as one product with a server to run. Building it yourself gives you exactly the policy layer, evidence store and compatibility test you need and nothing else, at the cost of maintaining them. Either way, the harness underneath is a component, and the decisions above the harness are where your product lives.
When not to build on this
Swappable backends cost you the harness's best features. Claude Code's compaction policy, Codex's sandbox, OpenHands' remote sandboxes are all inside the backend, and the ACP surface exposes their actions, not their knobs. If your product depends on one harness's specific behaviour, hosting it through a generic protocol will flatten it.
A meta-harness is also one more layer to run. For a team with one repository and one harness, Omnigent's server plus runner is infrastructure without a problem to solve. The layer earns its keep when you have several harnesses, several teams, shared policies and a need to see sessions from more than one machine.
What to take from this
The harness study's platform turn has a concrete meaning here. The agent became a component. The product is the layer that decides what the component may do, keeps the evidence of what it did, and can replace it without anyone noticing.
If you are building on coding agents, that is where to put your engineering. Write the policy layer once. Write the evidence store once. Write the compatibility test once. Then let the backends compete for your sessions.