{"id":638,"date":"2026-03-21T22:52:58","date_gmt":"2026-03-21T14:52:58","guid":{"rendered":"https:\/\/pa.yingzhi8.cn\/index.php\/2026\/03\/21\/tools-acp-agents\/"},"modified":"2026-03-23T18:04:39","modified_gmt":"2026-03-23T10:04:39","slug":"tools-acp-agents","status":"publish","type":"post","link":"https:\/\/pa.yingzhi8.cn\/index.php\/2026\/03\/21\/tools-acp-agents\/","title":{"rendered":"ACP Agents"},"content":{"rendered":"<h1>ACP Agents<\/h1>\n<h1>ACP agents<\/h1>\n<p><a href=\"https:\/\/agentclientprotocol.com\/\">Agent Client Protocol (ACP)<\/a> sessions let OpenClaw run external coding harnesses (for example Pi, Claude Code, Codex, OpenCode, and Gemini CLI) through an ACP backend plugin.<\/p>\n<p>If you ask OpenClaw in plain language to &#8220;run this in Codex&#8221; or &#8220;start Claude Code in a thread&#8221;, OpenClaw should route that request to the ACP runtime (not the native sub-agent runtime).<\/p>\n<h2>Fast operator flow<\/h2>\n<p>Use this when you want a practical <code>\/acp<\/code> runbook:<\/p>\n<ol>\n<li>Spawn a session:<br \/>\n   * <code>\/acp spawn codex --mode persistent --thread auto<\/code><\/li>\n<li>Work in the bound thread (or target that session key explicitly).<\/li>\n<li>Check runtime state:<br \/>\n   * <code>\/acp status<\/code><\/li>\n<li>Tune runtime options as needed:<br \/>\n   * <code>\/acp model &lt;provider\/model&gt;<\/code><br \/>\n   * <code>\/acp permissions &lt;profile&gt;<\/code><br \/>\n   * <code>\/acp timeout &lt;seconds&gt;<\/code><\/li>\n<li>Nudge an active session without replacing context:<br \/>\n   * <code>\/acp steer tighten logging and continue<\/code><\/li>\n<li>Stop work:<br \/>\n   * <code>\/acp cancel<\/code> (stop current turn), or<br \/>\n   * <code>\/acp close<\/code> (close session + remove bindings)<\/li>\n<\/ol>\n<h2>Quick start for humans<\/h2>\n<p>Examples of natural requests:<\/p>\n<ul>\n<li>&#8220;Start a persistent Codex session in a thread here and keep it focused.&#8221;<\/li>\n<li>&#8220;Run this as a one-shot Claude Code ACP session and summarize the result.&#8221;<\/li>\n<li>&#8220;Use Gemini CLI for this task in a thread, then keep follow-ups in that same thread.&#8221;<\/li>\n<\/ul>\n<p>What OpenClaw should do:<\/p>\n<ol>\n<li>Pick <code>runtime: \"acp\"<\/code>.<\/li>\n<li>Resolve the requested harness target (<code>agentId<\/code>, for example <code>codex<\/code>).<\/li>\n<li>If thread binding is requested and the current channel supports it, bind the ACP session to the thread.<\/li>\n<li>Route follow-up thread messages to that same ACP session until unfocused\/closed\/expired.<\/li>\n<\/ol>\n<h2>ACP versus sub-agents<\/h2>\n<p>Use ACP when you want an external harness runtime. Use sub-agents when you want OpenClaw-native delegated runs.<\/p>\n<table>\n<thead>\n<tr>\n<th>Area<\/th>\n<th>ACP session<\/th>\n<th>Sub-agent run<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Runtime<\/td>\n<td>ACP backend plugin (for example acpx)<\/td>\n<td>OpenClaw native sub-agent runtime<\/td>\n<\/tr>\n<tr>\n<td>Session key<\/td>\n<td><code>agent:&lt;agentId&gt;:acp:&lt;uuid&gt;<\/code><\/td>\n<td><code>agent:&lt;agentId&gt;:subagent:&lt;uuid&gt;<\/code><\/td>\n<\/tr>\n<tr>\n<td>Main commands<\/td>\n<td><code>\/acp ...<\/code><\/td>\n<td><code>\/subagents ...<\/code><\/td>\n<\/tr>\n<tr>\n<td>Spawn tool<\/td>\n<td><code>sessions_spawn<\/code> with <code>runtime:\"acp\"<\/code><\/td>\n<td><code>sessions_spawn<\/code> (default runtime)<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>See also <a href=\"\/tools\/subagents\">Sub-agents<\/a>.<\/p>\n<h2>Thread-bound sessions (channel-agnostic)<\/h2>\n<p>When thread bindings are enabled for a channel adapter, ACP sessions can be bound to threads:<\/p>\n<ul>\n<li>OpenClaw binds a thread to a target ACP session.<\/li>\n<li>Follow-up messages in that thread route to the bound ACP session.<\/li>\n<li>ACP output is delivered back to the same thread.<\/li>\n<li>Unfocus\/close\/archive\/idle-timeout or max-age expiry removes the binding.<\/li>\n<\/ul>\n<p>Thread binding support is adapter-specific. If the active channel adapter does not support thread bindings, OpenClaw returns a clear unsupported\/unavailable message.<\/p>\n<p>Required feature flags for thread-bound ACP:<\/p>\n<ul>\n<li><code>acp.enabled=true<\/code><\/li>\n<li><code>acp.dispatch.enabled<\/code> is on by default (set <code>false<\/code> to pause ACP dispatch)<\/li>\n<li>Channel-adapter ACP thread-spawn flag enabled (adapter-specific)<\/li>\n<li>Discord: <code>channels.discord.threadBindings.spawnAcpSessions=true<\/code><\/li>\n<li>Telegram: <code>channels.telegram.threadBindings.spawnAcpSessions=true<\/code><\/li>\n<\/ul>\n<h3>Thread supporting channels<\/h3>\n<ul>\n<li>Any channel adapter that exposes session\/thread binding capability.<\/li>\n<li>Current built-in support:<\/li>\n<li>Discord threads\/channels<\/li>\n<li>Telegram topics (forum topics in groups\/supergroups and DM topics)<\/li>\n<li>Plugin channels can add support through the same binding interface.<\/li>\n<\/ul>\n<h2>Channel specific settings<\/h2>\n<p>For non-ephemeral workflows, configure persistent ACP bindings in top-level <code>bindings[]<\/code> entries.<\/p>\n<h3>Binding model<\/h3>\n<ul>\n<li><code>bindings[].type=\"acp\"<\/code> marks a persistent ACP conversation binding.<\/li>\n<li><code>bindings[].match<\/code> identifies the target conversation:<\/li>\n<li>Discord channel or thread: <code>match.channel=\"discord\"<\/code> + <code>match.peer.id=\"&lt;channelOrThreadId&gt;\"<\/code><\/li>\n<li>Telegram forum topic: <code>match.channel=\"telegram\"<\/code> + <code>match.peer.id=\"&lt;chatId&gt;:topic:&lt;topicId&gt;\"<\/code><\/li>\n<li><code>bindings[].agentId<\/code> is the owning OpenClaw agent id.<\/li>\n<li>Optional ACP overrides live under <code>bindings[].acp<\/code>:<\/li>\n<li><code>mode<\/code> (<code>persistent<\/code> or <code>oneshot<\/code>)<\/li>\n<li><code>label<\/code><\/li>\n<li><code>cwd<\/code><\/li>\n<li><code>backend<\/code><\/li>\n<\/ul>\n<h3>Runtime defaults per agent<\/h3>\n<p>Use <code>agents.list[].runtime<\/code> to define ACP defaults once per agent:<\/p>\n<ul>\n<li><code>agents.list[].runtime.type=\"acp\"<\/code><\/li>\n<li><code>agents.list[].runtime.acp.agent<\/code> (harness id, for example <code>codex<\/code> or <code>claude<\/code>)<\/li>\n<li><code>agents.list[].runtime.acp.backend<\/code><\/li>\n<li><code>agents.list[].runtime.acp.mode<\/code><\/li>\n<li><code>agents.list[].runtime.acp.cwd<\/code><\/li>\n<\/ul>\n<p>Override precedence for ACP bound sessions:<\/p>\n<ol>\n<li><code>bindings[].acp.*<\/code><\/li>\n<li><code>agents.list[].runtime.acp.*<\/code><\/li>\n<li>global ACP defaults (for example <code>acp.backend<\/code>)<\/li>\n<\/ol>\n<p>Example:<\/p>\n<p>&#8220;`json5  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\n{<br \/>\n  agents: {<br \/>\n    list: [<br \/>\n      {<br \/>\n        id: &#8220;codex&#8221;,<br \/>\n        runtime: {<br \/>\n          type: &#8220;acp&#8221;,<br \/>\n          acp: {<br \/>\n            agent: &#8220;codex&#8221;,<br \/>\n            backend: &#8220;acpx&#8221;,<br \/>\n            mode: &#8220;persistent&#8221;,<br \/>\n            cwd: &#8220;\/workspace\/openclaw&#8221;,<br \/>\n          },<br \/>\n        },<br \/>\n      },<br \/>\n      {<br \/>\n        id: &#8220;claude&#8221;,<br \/>\n        runtime: {<br \/>\n          type: &#8220;acp&#8221;,<br \/>\n          acp: { agent: &#8220;claude&#8221;, backend: &#8220;acpx&#8221;, mode: &#8220;persistent&#8221; },<br \/>\n        },<br \/>\n      },<br \/>\n    ],<br \/>\n  },<br \/>\n  bindings: [<br \/>\n    {<br \/>\n      type: &#8220;acp&#8221;,<br \/>\n      agentId: &#8220;codex&#8221;,<br \/>\n      match: {<br \/>\n        channel: &#8220;discord&#8221;,<br \/>\n        accountId: &#8220;default&#8221;,<br \/>\n        peer: { kind: &#8220;channel&#8221;, id: &#8220;222222222222222222&#8221; },<br \/>\n      },<br \/>\n      acp: { label: &#8220;codex-main&#8221; },<br \/>\n    },<br \/>\n    {<br \/>\n      type: &#8220;acp&#8221;,<br \/>\n      agentId: &#8220;claude&#8221;,<br \/>\n      match: {<br \/>\n        channel: &#8220;telegram&#8221;,<br \/>\n        accountId: &#8220;default&#8221;,<br \/>\n        peer: { kind: &#8220;group&#8221;, id: &#8220;-1001234567890:topic:42&#8221; },<br \/>\n      },<br \/>\n      acp: { cwd: &#8220;\/workspace\/repo-b&#8221; },<br \/>\n    },<br \/>\n    {<br \/>\n      type: &#8220;route&#8221;,<br \/>\n      agentId: &#8220;main&#8221;,<br \/>\n      match: { channel: &#8220;discord&#8221;, accountId: &#8220;default&#8221; },<br \/>\n    },<br \/>\n    {<br \/>\n      type: &#8220;route&#8221;,<br \/>\n      agentId: &#8220;main&#8221;,<br \/>\n      match: { channel: &#8220;telegram&#8221;, accountId: &#8220;default&#8221; },<br \/>\n    },<br \/>\n  ],<br \/>\n  channels: {<br \/>\n    discord: {<br \/>\n      guilds: {<br \/>\n        &#8220;111111111111111111&#8221;: {<br \/>\n          channels: {<br \/>\n            &#8220;222222222222222222&#8221;: { requireMention: false },<br \/>\n          },<br \/>\n        },<br \/>\n      },<br \/>\n    },<br \/>\n    telegram: {<br \/>\n      groups: {<br \/>\n        &#8220;-1001234567890&#8221;: {<br \/>\n          topics: { &#8220;42&#8221;: { requireMention: false } },<br \/>\n        },<br \/>\n      },<br \/>\n    },<br \/>\n  },<br \/>\n}<\/p>\n<pre><code>\nBehavior:\n\n* OpenClaw ensures the configured ACP session exists before use.\n* Messages in that channel or topic route to the configured ACP session.\n* In bound conversations, `\/new` and `\/reset` reset the same ACP session key in place.\n* Temporary runtime bindings (for example created by thread-focus flows) still apply where present.\n\n## Start ACP sessions (interfaces)\n\n### From `sessions_spawn`\n\nUse `runtime: \"acp\"` to start an ACP session from an agent turn or tool call.\n\n```json  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}\n{\n  \"task\": \"Open the repo and summarize failing tests\",\n  \"runtime\": \"acp\",\n  \"agentId\": \"codex\",\n  \"thread\": true,\n  \"mode\": \"session\"\n}\n<\/code><\/pre>\n<p>Notes:<\/p>\n<ul>\n<li><code>runtime<\/code> defaults to <code>subagent<\/code>, so set <code>runtime: \"acp\"<\/code> explicitly for ACP sessions.<\/li>\n<li>If <code>agentId<\/code> is omitted, OpenClaw uses <code>acp.defaultAgent<\/code> when configured.<\/li>\n<li><code>mode: \"session\"<\/code> requires <code>thread: true<\/code> to keep a persistent bound conversation.<\/li>\n<\/ul>\n<p>Interface details:<\/p>\n<ul>\n<li><code>task<\/code> (required): initial prompt sent to the ACP session.<\/li>\n<li><code>runtime<\/code> (required for ACP): must be <code>\"acp\"<\/code>.<\/li>\n<li><code>agentId<\/code> (optional): ACP target harness id. Falls back to <code>acp.defaultAgent<\/code> if set.<\/li>\n<li><code>thread<\/code> (optional, default <code>false<\/code>): request thread binding flow where supported.<\/li>\n<li><code>mode<\/code> (optional): <code>run<\/code> (one-shot) or <code>session<\/code> (persistent).<\/li>\n<li>default is <code>run<\/code><\/li>\n<li>if <code>thread: true<\/code> and mode omitted, OpenClaw may default to persistent behavior per runtime path<\/li>\n<li><code>mode: \"session\"<\/code> requires <code>thread: true<\/code><\/li>\n<li><code>cwd<\/code> (optional): requested runtime working directory (validated by backend\/runtime policy).<\/li>\n<li><code>label<\/code> (optional): operator-facing label used in session\/banner text.<\/li>\n<li><code>resumeSessionId<\/code> (optional): resume an existing ACP session instead of creating a new one. The agent replays its conversation history via <code>session\/load<\/code>. Requires <code>runtime: \"acp\"<\/code>.<\/li>\n<li><code>streamTo<\/code> (optional): <code>\"parent\"<\/code> streams initial ACP run progress summaries back to the requester session as system events.<\/li>\n<li>When available, accepted responses include <code>streamLogPath<\/code> pointing to a session-scoped JSONL log (<code>&lt;sessionId&gt;.acp-stream.jsonl<\/code>) you can tail for full relay history.<\/li>\n<\/ul>\n<h3>Resume an existing session<\/h3>\n<p>Use <code>resumeSessionId<\/code> to continue a previous ACP session instead of starting fresh. The agent replays its conversation history via <code>session\/load<\/code>, so it picks up with full context of what came before.<\/p>\n<p>&#8220;`json  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\n{<br \/>\n  &#8220;task&#8221;: &#8220;Continue where we left off \u2014 fix the remaining test failures&#8221;,<br \/>\n  &#8220;runtime&#8221;: &#8220;acp&#8221;,<br \/>\n  &#8220;agentId&#8221;: &#8220;codex&#8221;,<br \/>\n  &#8220;resumeSessionId&#8221;: &#8220;&#8221;<br \/>\n}<\/p>\n<pre><code>\nCommon use cases:\n\n* Hand off a Codex session from your laptop to your phone \u2014 tell your agent to pick up where you left off\n* Continue a coding session you started interactively in the CLI, now headlessly through your agent\n* Pick up work that was interrupted by a gateway restart or idle timeout\n\nNotes:\n\n* `resumeSessionId` requires `runtime: \"acp\"` \u2014 returns an error if used with the sub-agent runtime.\n* `resumeSessionId` restores the upstream ACP conversation history; `thread` and `mode` still apply normally to the new OpenClaw session you are creating, so `mode: \"session\"` still requires `thread: true`.\n* The target agent must support `session\/load` (Codex and Claude Code do).\n* If the session ID isn't found, the spawn fails with a clear error \u2014 no silent fallback to a new session.\n\n### Operator smoke test\n\nUse this after a gateway deploy when you want a quick live check that ACP spawn\nis actually working end-to-end, not just passing unit tests.\n\nRecommended gate:\n\n1. Verify the deployed gateway version\/commit on the target host.\n2. Confirm the deployed source includes the ACP lineage acceptance in\n   `src\/gateway\/sessions-patch.ts` (`subagent:* or acp:* sessions`).\n3. Open a temporary ACPX bridge session to a live agent (for example\n   `razor(main)` on `jpclawhq`).\n4. Ask that agent to call `sessions_spawn` with:\n   * `runtime: \"acp\"`\n   * `agentId: \"codex\"`\n   * `mode: \"run\"`\n   * task: `Reply with exactly LIVE-ACP-SPAWN-OK`\n5. Verify the agent reports:\n   * `accepted=yes`\n   * a real `childSessionKey`\n   * no validator error\n6. Clean up the temporary ACPX bridge session.\n\nExample prompt to the live agent:\n\n```text  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}\nUse the sessions_spawn tool now with runtime: \"acp\", agentId: \"codex\", and mode: \"run\".\nSet the task to: \"Reply with exactly LIVE-ACP-SPAWN-OK\".\nThen report only: accepted=&lt;yes\/no&gt;; childSessionKey=&lt;value or none&gt;; error=&lt;exact text or none&gt;.\n<\/code><\/pre>\n<p>Notes:<\/p>\n<ul>\n<li>Keep this smoke test on <code>mode: \"run\"<\/code> unless you are intentionally testing<br \/>\n  thread-bound persistent ACP sessions.<\/li>\n<li>Do not require <code>streamTo: \"parent\"<\/code> for the basic gate. That path depends on<br \/>\n  requester\/session capabilities and is a separate integration check.<\/li>\n<li>Treat thread-bound <code>mode: \"session\"<\/code> testing as a second, richer integration<br \/>\n  pass from a real Discord thread or Telegram topic.<\/li>\n<\/ul>\n<h2>Sandbox compatibility<\/h2>\n<p>ACP sessions currently run on the host runtime, not inside the OpenClaw sandbox.<\/p>\n<p>Current limitations:<\/p>\n<ul>\n<li>If the requester session is sandboxed, ACP spawns are blocked for both <code>sessions_spawn({ runtime: \"acp\" })<\/code> and <code>\/acp spawn<\/code>.<\/li>\n<li>Error: <code>Sandboxed sessions cannot spawn ACP sessions because runtime=\"acp\" runs on the host. Use runtime=\"subagent\" from sandboxed sessions.<\/code><\/li>\n<li><code>sessions_spawn<\/code> with <code>runtime: \"acp\"<\/code> does not support <code>sandbox: \"require\"<\/code>.<\/li>\n<li>Error: <code>sessions_spawn sandbox=\"require\" is unsupported for runtime=\"acp\" because ACP sessions run outside the sandbox. Use runtime=\"subagent\" or sandbox=\"inherit\".<\/code><\/li>\n<\/ul>\n<p>Use <code>runtime: \"subagent\"<\/code> when you need sandbox-enforced execution.<\/p>\n<h3>From <code>\/acp<\/code> command<\/h3>\n<p>Use <code>\/acp spawn<\/code> for explicit operator control from chat when needed.<\/p>\n<p>&#8220;`text  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\n\/acp spawn codex &#8211;mode persistent &#8211;thread auto<br \/>\n\/acp spawn codex &#8211;mode oneshot &#8211;thread off<br \/>\n\/acp spawn codex &#8211;thread here<\/p>\n<pre><code>\nKey flags:\n\n* `--mode persistent|oneshot`\n* `--thread auto|here|off`\n* `--cwd &lt;absolute-path&gt;`\n* `--label &lt;name&gt;`\n\nSee [Slash Commands](\/tools\/slash-commands).\n\n## Session target resolution\n\nMost `\/acp` actions accept an optional session target (`session-key`, `session-id`, or `session-label`).\n\nResolution order:\n\n1. Explicit target argument (or `--session` for `\/acp steer`)\n   * tries key\n   * then UUID-shaped session id\n   * then label\n2. Current thread binding (if this conversation\/thread is bound to an ACP session)\n3. Current requester session fallback\n\nIf no target resolves, OpenClaw returns a clear error (`Unable to resolve session target: ...`).\n\n## Spawn thread modes\n\n`\/acp spawn` supports `--thread auto|here|off`.\n\n| Mode   | Behavior                                                                                            |\n| ------ | --------------------------------------------------------------------------------------------------- |\n| `auto` | In an active thread: bind that thread. Outside a thread: create\/bind a child thread when supported. |\n| `here` | Require current active thread; fail if not in one.                                                  |\n| `off`  | No binding. Session starts unbound.                                                                 |\n\nNotes:\n\n* On non-thread binding surfaces, default behavior is effectively `off`.\n* Thread-bound spawn requires channel policy support:\n  * Discord: `channels.discord.threadBindings.spawnAcpSessions=true`\n  * Telegram: `channels.telegram.threadBindings.spawnAcpSessions=true`\n\n## ACP controls\n\nAvailable command family:\n\n* `\/acp spawn`\n* `\/acp cancel`\n* `\/acp steer`\n* `\/acp close`\n* `\/acp status`\n* `\/acp set-mode`\n* `\/acp set`\n* `\/acp cwd`\n* `\/acp permissions`\n* `\/acp timeout`\n* `\/acp model`\n* `\/acp reset-options`\n* `\/acp sessions`\n* `\/acp doctor`\n* `\/acp install`\n\n`\/acp status` shows the effective runtime options and, when available, both runtime-level and backend-level session identifiers.\n\nSome controls depend on backend capabilities. If a backend does not support a control, OpenClaw returns a clear unsupported-control error.\n\n## ACP command cookbook\n\n| Command              | What it does                                              | Example                                                        |\n| -------------------- | --------------------------------------------------------- | -------------------------------------------------------------- |\n| `\/acp spawn`         | Create ACP session; optional thread bind.                 | `\/acp spawn codex --mode persistent --thread auto --cwd \/repo` |\n| `\/acp cancel`        | Cancel in-flight turn for target session.                 | `\/acp cancel agent:codex:acp:&lt;uuid&gt;`                           |\n| `\/acp steer`         | Send steer instruction to running session.                | `\/acp steer --session support inbox prioritize failing tests`  |\n| `\/acp close`         | Close session and unbind thread targets.                  | `\/acp close`                                                   |\n| `\/acp status`        | Show backend, mode, state, runtime options, capabilities. | `\/acp status`                                                  |\n| `\/acp set-mode`      | Set runtime mode for target session.                      | `\/acp set-mode plan`                                           |\n| `\/acp set`           | Generic runtime config option write.                      | `\/acp set model openai\/gpt-5.2`                                |\n| `\/acp cwd`           | Set runtime working directory override.                   | `\/acp cwd \/Users\/user\/Projects\/repo`                           |\n| `\/acp permissions`   | Set approval policy profile.                              | `\/acp permissions strict`                                      |\n| `\/acp timeout`       | Set runtime timeout (seconds).                            | `\/acp timeout 120`                                             |\n| `\/acp model`         | Set runtime model override.                               | `\/acp model anthropic\/claude-opus-4-6`                         |\n| `\/acp reset-options` | Remove session runtime option overrides.                  | `\/acp reset-options`                                           |\n| `\/acp sessions`      | List recent ACP sessions from store.                      | `\/acp sessions`                                                |\n| `\/acp doctor`        | Backend health, capabilities, actionable fixes.           | `\/acp doctor`                                                  |\n| `\/acp install`       | Print deterministic install and enable steps.             | `\/acp install`                                                 |\n\n`\/acp sessions` reads the store for the current bound or requester session. Commands that accept `session-key`, `session-id`, or `session-label` tokens resolve targets through gateway session discovery, including custom per-agent `session.store` roots.\n\n## Runtime options mapping\n\n`\/acp` has convenience commands and a generic setter.\n\nEquivalent operations:\n\n* `\/acp model &lt;id&gt;` maps to runtime config key `model`.\n* `\/acp permissions &lt;profile&gt;` maps to runtime config key `approval_policy`.\n* `\/acp timeout &lt;seconds&gt;` maps to runtime config key `timeout`.\n* `\/acp cwd &lt;path&gt;` updates runtime cwd override directly.\n* `\/acp set &lt;key&gt; &lt;value&gt;` is the generic path.\n  * Special case: `key=cwd` uses the cwd override path.\n* `\/acp reset-options` clears all runtime overrides for target session.\n\n## acpx harness support (current)\n\nCurrent acpx built-in harness aliases:\n\n* `pi`\n* `claude`\n* `codex`\n* `opencode`\n* `gemini`\n* `kimi`\n\nWhen OpenClaw uses the acpx backend, prefer these values for `agentId` unless your acpx config defines custom agent aliases.\n\nDirect acpx CLI usage can also target arbitrary adapters via `--agent &lt;command&gt;`, but that raw escape hatch is an acpx CLI feature (not the normal OpenClaw `agentId` path).\n\n## Required config\n\nCore ACP baseline:\n\n```json5  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}\n{\n  acp: {\n    enabled: true,\n    \/\/ Optional. Default is true; set false to pause ACP dispatch while keeping \/acp controls.\n    dispatch: { enabled: true },\n    backend: \"acpx\",\n    defaultAgent: \"codex\",\n    allowedAgents: [\"pi\", \"claude\", \"codex\", \"opencode\", \"gemini\", \"kimi\"],\n    maxConcurrentSessions: 8,\n    stream: {\n      coalesceIdleMs: 300,\n      maxChunkChars: 1200,\n    },\n    runtime: {\n      ttlMinutes: 120,\n    },\n  },\n}\n<\/code><\/pre>\n<p>Thread binding config is channel-adapter specific. Example for Discord:<\/p>\n<p>&#8220;`json5  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\n{<br \/>\n  session: {<br \/>\n    threadBindings: {<br \/>\n      enabled: true,<br \/>\n      idleHours: 24,<br \/>\n      maxAgeHours: 0,<br \/>\n    },<br \/>\n  },<br \/>\n  channels: {<br \/>\n    discord: {<br \/>\n      threadBindings: {<br \/>\n        enabled: true,<br \/>\n        spawnAcpSessions: true,<br \/>\n      },<br \/>\n    },<br \/>\n  },<br \/>\n}<\/p>\n<pre><code>\nIf thread-bound ACP spawn does not work, verify the adapter feature flag first:\n\n* Discord: `channels.discord.threadBindings.spawnAcpSessions=true`\n\nSee [Configuration Reference](\/gateway\/configuration-reference).\n\n## Plugin setup for acpx backend\n\nInstall and enable plugin:\n\n```bash  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}\nopenclaw plugins install acpx\nopenclaw config set plugins.entries.acpx.enabled true\n<\/code><\/pre>\n<p>Local workspace install during development:<\/p>\n<p>&#8220;`bash  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\nopenclaw plugins install .\/extensions\/acpx<\/p>\n<pre><code>\nThen verify backend health:\n\n```text  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}\n\/acp doctor\n<\/code><\/pre>\n<h3>acpx command and version configuration<\/h3>\n<p>By default, the acpx plugin (published as <code>@openclaw\/acpx<\/code>) uses the plugin-local pinned binary:<\/p>\n<ol>\n<li>Command defaults to <code>extensions\/acpx\/node_modules\/.bin\/acpx<\/code>.<\/li>\n<li>Expected version defaults to the extension pin.<\/li>\n<li>Startup registers ACP backend immediately as not-ready.<\/li>\n<li>A background ensure job verifies <code>acpx --version<\/code>.<\/li>\n<li>If the plugin-local binary is missing or mismatched, it runs:<br \/>\n   <code>npm install --omit=dev --no-save acpx@&lt;pinned&gt;<\/code> and re-verifies.<\/li>\n<\/ol>\n<p>You can override command\/version in plugin config:<\/p>\n<p>&#8220;`json  theme={&#8220;theme&#8221;:{&#8220;light&#8221;:&#8221;min-light&#8221;,&#8221;dark&#8221;:&#8221;min-dark&#8221;}}<br \/>\n{<br \/>\n  &#8220;plugins&#8221;: {<br \/>\n    &#8220;entries&#8221;: {<br \/>\n      &#8220;acpx&#8221;: {<br \/>\n        &#8220;enabled&#8221;: true,<br \/>\n        &#8220;config&#8221;: {<br \/>\n          &#8220;command&#8221;: &#8220;..\/acpx\/dist\/cli.js&#8221;,<br \/>\n          &#8220;expectedVersion&#8221;: &#8220;any&#8221;<br \/>\n        }<br \/>\n      }<br \/>\n    }<br \/>\n  }<br \/>\n}<\/p>\n<pre><code>\nNotes:\n\n* `command` accepts an absolute path, relative path, or command name (`acpx`).\n* Relative paths resolve from OpenClaw workspace directory.\n* `expectedVersion: \"any\"` disables strict version matching.\n* When `command` points to a custom binary\/path, plugin-local auto-install is disabled.\n* OpenClaw startup remains non-blocking while the backend health check runs.\n\nSee [Plugins](\/tools\/plugin).\n\n## Permission configuration\n\nACP sessions run non-interactively \u2014 there is no TTY to approve or deny file-write and shell-exec permission prompts. The acpx plugin provides two config keys that control how permissions are handled:\n\n### `permissionMode`\n\nControls which operations the harness agent can perform without prompting.\n\n| Value           | Behavior                                                  |\n| --------------- | --------------------------------------------------------- |\n| `approve-all`   | Auto-approve all file writes and shell commands.          |\n| `approve-reads` | Auto-approve reads only; writes and exec require prompts. |\n| `deny-all`      | Deny all permission prompts.                              |\n\n### `nonInteractivePermissions`\n\nControls what happens when a permission prompt would be shown but no interactive TTY is available (which is always the case for ACP sessions).\n\n| Value  | Behavior                                                          |\n| ------ | ----------------------------------------------------------------- |\n| `fail` | Abort the session with `AcpRuntimeError`. **(default)**           |\n| `deny` | Silently deny the permission and continue (graceful degradation). |\n\n### Configuration\n\nSet via plugin config:\n\n```bash  theme={\"theme\":{\"light\":\"min-light\",\"dark\":\"min-dark\"}}\nopenclaw config set plugins.entries.acpx.config.permissionMode approve-all\nopenclaw config set plugins.entries.acpx.config.nonInteractivePermissions fail\n<\/code><\/pre>\n<p>Restart the gateway after changing these values.<\/p>\n<blockquote>\n<p><strong>Important:<\/strong> OpenClaw currently defaults to <code>permissionMode=approve-reads<\/code> and <code>nonInteractivePermissions=fail<\/code>. In non-interactive ACP sessions, any write or exec that triggers a permission prompt can fail with <code>AcpRuntimeError: Permission prompt unavailable in non-interactive mode<\/code>.<\/p>\n<p>If you need to restrict permissions, set <code>nonInteractivePermissions<\/code> to <code>deny<\/code> so sessions degrade gracefully instead of crashing.<\/p>\n<\/blockquote>\n<h2>Troubleshooting<\/h2>\n<table>\n<thead>\n<tr>\n<th>Symptom<\/th>\n<th>Likely cause<\/th>\n<th>Fix<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><code>ACP runtime backend is not configured<\/code><\/td>\n<td>Backend plugin missing or disabled.<\/td>\n<td>Install and enable backend plugin, then run <code>\/acp doctor<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>ACP is disabled by policy (acp.enabled=false)<\/code><\/td>\n<td>ACP globally disabled.<\/td>\n<td>Set <code>acp.enabled=true<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>ACP dispatch is disabled by policy (acp.dispatch.enabled=false)<\/code><\/td>\n<td>Dispatch from normal thread messages disabled.<\/td>\n<td>Set <code>acp.dispatch.enabled=true<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>ACP agent \"&lt;id&gt;\" is not allowed by policy<\/code><\/td>\n<td>Agent not in allowlist.<\/td>\n<td>Use allowed <code>agentId<\/code> or update <code>acp.allowedAgents<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>Unable to resolve session target: ...<\/code><\/td>\n<td>Bad key\/id\/label token.<\/td>\n<td>Run <code>\/acp sessions<\/code>, copy exact key\/label, retry.<\/td>\n<\/tr>\n<tr>\n<td><code>--thread here requires running \/acp spawn inside an active ... thread<\/code><\/td>\n<td><code>--thread here<\/code> used outside a thread context.<\/td>\n<td>Move to target thread or use <code>--thread auto<\/code>\/<code>off<\/code>.<\/td>\n<\/tr>\n<tr>\n<td><code>Only &lt;user-id&gt; can rebind this thread.<\/code><\/td>\n<td>Another user owns thread binding.<\/td>\n<td>Rebind as owner or use a different thread.<\/td>\n<\/tr>\n<tr>\n<td><code>Thread bindings are unavailable for &lt;channel&gt;.<\/code><\/td>\n<td>Adapter lacks thread binding capability.<\/td>\n<td>Use <code>--thread off<\/code> or move to supported adapter\/channel.<\/td>\n<\/tr>\n<tr>\n<td><code>Sandboxed sessions cannot spawn ACP sessions ...<\/code><\/td>\n<td>ACP runtime is host-side; requester session is sandboxed.<\/td>\n<td>Use <code>runtime=\"subagent\"<\/code> from sandboxed sessions, or run ACP spawn from a non-sandboxed session.<\/td>\n<\/tr>\n<tr>\n<td><code>sessions_spawn sandbox=\"require\" is unsupported for runtime=\"acp\" ...<\/code><\/td>\n<td><code>sandbox=\"require\"<\/code> requested for ACP runtime.<\/td>\n<td>Use <code>runtime=\"subagent\"<\/code> for required sandboxing, or use ACP with <code>sandbox=\"inherit\"<\/code> from a non-sandboxed session.<\/td>\n<\/tr>\n<tr>\n<td>Missing ACP metadata for bound session<\/td>\n<td>Stale\/deleted ACP session metadata.<\/td>\n<td>Recreate with <code>\/acp spawn<\/code>, then rebind\/focus thread.<\/td>\n<\/tr>\n<tr>\n<td><code>AcpRuntimeError: Permission prompt unavailable in non-interactive mode<\/code><\/td>\n<td><code>permissionMode<\/code> blocks writes\/exec in non-interactive ACP session.<\/td>\n<td>Set <code>plugins.entries.acpx.config.permissionMode<\/code> to <code>approve-all<\/code> and restart gateway. See <a href=\"#permission-configuration\">Permission configuration<\/a>.<\/td>\n<\/tr>\n<tr>\n<td>ACP session fails early with little output<\/td>\n<td>Permission prompts are blocked by <code>permissionMode<\/code>\/<code>nonInteractivePermissions<\/code>.<\/td>\n<td>Check gateway logs for <code>AcpRuntimeError<\/code>. For full permissions, set <code>permissionMode=approve-all<\/code>; for graceful degradation, set <code>nonInteractivePermissions=deny<\/code>.<\/td>\n<\/tr>\n<tr>\n<td>ACP session stalls indefinitely after completing work<\/td>\n<td>Harness process finished but ACP session did not report completion.<\/td>\n<td>Monitor with <code>ps aux | grep acpx<\/code>; kill stale processes manually.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n","protected":false},"excerpt":{"rendered":"<p>ACP Agents ACP agents Agent Client Protocol (ACP) sessi [&hellip;]<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-638","post","type-post","status-publish","format-standard","hentry","category-docs"],"_links":{"self":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts\/638","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/comments?post=638"}],"version-history":[{"count":4,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts\/638\/revisions"}],"predecessor-version":[{"id":8852,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/posts\/638\/revisions\/8852"}],"wp:attachment":[{"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/media?parent=638"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/categories?post=638"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pa.yingzhi8.cn\/index.php\/wp-json\/wp\/v2\/tags?post=638"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}