openclaw - ✅(Solved) Fix Expose ACP spawn and prompt in the plugin runtime [2 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#65022Fetched 2026-04-12 13:25:58
View on GitHub
Comments
0
Participants
1
Timeline
2
Reactions
0
Participants
Timeline (top)
cross-referenced ×2

Trusted plugins can already orchestrate subagents through api.runtime.subagent.*, but they cannot programmatically start or continue ACP-backed agent sessions from plugin code.

This blocks plugin use cases that need to dispatch long-running coding agents (for example OpenCode, Codex, or Claude Code) from a plugin-managed workflow.

Root Cause

This enables plugin-managed task orchestration systems to:

  • start ACP coding-agent sessions from plugin code
  • bind those sessions into Discord/Telegram/etc. workflows
  • continue the same ACP session over multiple follow-up prompts

Fix Action

Fix / Workaround

This blocks plugin use cases that need to dispatch long-running coding agents (for example OpenCode, Codex, or Claude Code) from a plugin-managed workflow.

This is needed by the downstream task-dispatch plugin, which dispatches coding tasks to ACP-backed agents and manages the task lifecycle around them.

PR fix notes

PR #63176: feat(plugins): expose ACP spawn and prompt in plugin runtime

Description (problem / solution / changelog)

Summary

  • Problem: Plugins can orchestrate subagents via api.runtime.subagent.* (run, waitForRun, getSessionMessages) but have no access to the ACP orchestration path — the more capable agent dispatch mechanism that supports session management, thread-bound delivery, and follow-up prompting.
  • Why it matters: Plugin authors who need to dispatch long-running coding agents (OpenCode, Codex, Claude Code) from chat workflows currently have to fork OpenClaw to access ACP helpers. This is a natural extension of the existing plugin runtime surface — subagent.* provides lower-level orchestration; acp.* provides the higher-level ACP-backed path. Both should be available to trusted plugins.
  • What changed: Add api.runtime.acp.spawn() and api.runtime.acp.prompt() to the plugin runtime, add the corresponding types/mocks, and gate behind plugins.allowAcpSpawn (opt-in, default false).
  • What did NOT change (scope boundary): Default plugin permissions unchanged. Subagent scopes unchanged. Discord thread binding behavior unchanged. ACP is not auto-enabled — requires explicit operator opt-in.

Production-validated: Running 3+ weeks in a Telegram → Discord agent dispatch pipeline, handling real coding tasks through ACP-backed sessions with thread bindings.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Root Cause (if applicable)

N/A — new feature, not a fix.

Regression Test Plan (if applicable)

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/plugins/runtime/index.test.ts
  • Scenario the test should lock in: ACP runtime helpers throw when allowAcpSpawn is disabled (default); delegate to spawnAcpDirect / callGateway when enabled.
  • Why this is the smallest reliable guardrail: The feature is a thin runtime export/gating seam — direct runtime tests lock the contract without needing a full plugin integration harness.
  • Existing test that already covers this (if any): pnpm build catches type/export/config wiring, but not runtime gating behavior.
  • If no new test is added, why not: N/A — two new tests are included.

User-visible / Behavior Changes

  • Plugin authors can call api.runtime.acp.spawn() and api.runtime.acp.prompt() when plugins.allowAcpSpawn: true is set in openclaw.json.
  • Operators who do not set the flag see zero change.
  • New config key: plugins.allowAcpSpawn (boolean, optional, default false).

Diagram (if applicable)

Before:
  Plugin → api.runtime.subagent.run()  → in-process subagent only
  Plugin → ❌ no ACP path available

After:
  Plugin → api.runtime.subagent.run()  → in-process subagent (unchanged)
  Plugin → api.runtime.acp.spawn()     → ACP-backed agent with thread binding
  Plugin → api.runtime.acp.prompt()    → follow-up into existing ACP session

Security Impact (required)

  • New permissions/capabilities? Yes
  • Secrets/tokens handling changed? No
  • New/changed network calls? Yes
  • Command/tool execution surface changed? Yes
  • Data access scope changed? No
  • If any Yes, explain risk + mitigation: This exposes a privileged orchestration capability (ACP agent spawning) to the plugin runtime, gated behind plugins.allowAcpSpawn (default false). The gate is checked on every call — not just at plugin load time. Only trusted plugins on operator-managed instances should enable this. No new scopes are introduced.

Repro + Verification

Environment

  • OS: macOS arm64
  • Runtime/container: Node 22 + pnpm
  • Model/provider: ACP-backed coding agents (OpenCode / Codex / Claude Code)
  • Integration/channel (if any): Telegram main workflow → Discord thread-bound coding agents
  • Relevant config (redacted): plugins.allowAcpSpawn: true

Steps

  1. Install a plugin that needs ACP orchestration (e.g. task-dispatch).
  2. Call api.runtime.acp.spawn() without allowAcpSpawn → clear error.
  3. Set plugins.allowAcpSpawn: true in openclaw.json.
  4. Call api.runtime.acp.spawn(...) → returns { status: "accepted", childSessionKey, runId }.
  5. Call api.runtime.acp.prompt({ sessionKey, text, channel, threadId }) → sends follow-up into the ACP session.

Expected

  • Disabled: throws api.runtime.acp.spawn() requires plugins.allowAcpSpawn: true in openclaw.json
  • Enabled: delegates to spawnAcpDirect / callGateway("agent", ...) and returns valid results

Actual

  • Both paths work as expected.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

pnpm test src/plugins/runtime/index.test.ts — 2 new tests pass (gate disabled → throws, gate enabled → delegates). pnpm build — clean. Production: 3+ weeks running task-dispatch plugin dispatching coding agents from Telegram to Discord threads via ACP.

Human Verification (required)

  • Verified scenarios: disabled gate throws clear error; enabled gate delegates to spawnAcpDirect and callGateway; existing-thread and fresh-thread ACP dispatch flows both work end-to-end in production.
  • Edge cases checked: missing allowAcpSpawn key (treated as false); gateway returning no runId from prompt (falls back to local idempotency key).
  • What you did not verify: every third-party ACP backend permutation; non-Discord delivery paths.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? Yesplugins.allowAcpSpawn (optional, defaults to existing behavior)
  • Migration needed? No — operators opt in by adding the flag
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: Trusted plugins could spawn ACP agents without operator understanding the privilege level.
    • Mitigation: Explicit plugins.allowAcpSpawn gate, default false, clear runtime error message when disabled.
  • Risk: Runtime/API drift between ACP surface and plugin test mocks.
    • Mitigation: Mock updated in same PR; unit tests cover the seam.
  • Risk: acp.prompt falls back to local idempotency key when gateway returns no runId.
    • Mitigation: Documented behavior; callers should treat runId as a correlation ID, not a guaranteed server-side reference.

Changed files

  • extensions/discord/src/monitor/thread-bindings.discord-api.test.ts (modified, +30/-1)
  • extensions/discord/src/monitor/thread-bindings.discord-api.ts (modified, +15/-3)
  • src/config/schema.base.generated.ts (modified, +3/-0)
  • src/config/types.plugins.ts (modified, +6/-0)
  • src/config/zod-schema.ts (modified, +2/-0)
  • src/plugins/runtime/index.test.ts (modified, +132/-0)
  • src/plugins/runtime/index.ts (modified, +10/-0)
  • src/plugins/runtime/runtime-acp.runtime.ts (added, +77/-0)
  • src/plugins/runtime/types-core.ts (modified, +14/-0)
  • test/helpers/plugins/plugin-runtime-mock.ts (modified, +4/-0)
RAW_BUFFERClick to expand / collapse

Summary

Trusted plugins can already orchestrate subagents through api.runtime.subagent.*, but they cannot programmatically start or continue ACP-backed agent sessions from plugin code.

This blocks plugin use cases that need to dispatch long-running coding agents (for example OpenCode, Codex, or Claude Code) from a plugin-managed workflow.

Problem

Today a plugin can do this:

  • api.runtime.subagent.run()
  • api.runtime.subagent.waitForRun()
  • api.runtime.subagent.getSessionMessages()

But it cannot do the ACP equivalents:

  • spawn a new ACP-backed session
  • send a follow-up prompt into an existing ACP session

That means downstream plugins have to fork OpenClaw just to access the ACP orchestration path.

Proposed solution

Expose a gated ACP runtime surface to trusted plugins:

  • api.runtime.acp.spawn()
  • api.runtime.acp.prompt()

with an explicit operator opt-in such as:

  • plugins.allowAcpSpawn: true

Default behavior should remain unchanged for operators who do not enable it.

Why this matters

This enables plugin-managed task orchestration systems to:

  • start ACP coding-agent sessions from plugin code
  • bind those sessions into Discord/Telegram/etc. workflows
  • continue the same ACP session over multiple follow-up prompts

Real downstream use case

This is needed by the downstream task-dispatch plugin, which dispatches coding tasks to ACP-backed agents and manages the task lifecycle around them.

Related PR

  • #63176

extent analysis

TL;DR

Exposing a gated ACP runtime surface to trusted plugins through api.runtime.acp.spawn() and api.runtime.acp.prompt() can address the issue.

Guidance

  • Implement api.runtime.acp.spawn() and api.runtime.acp.prompt() functions to enable trusted plugins to start and continue ACP-backed agent sessions.
  • Add an explicit operator opt-in, such as plugins.allowAcpSpawn: true, to control access to these functions.
  • Update the task-dispatch plugin to utilize the new ACP runtime surface for dispatching coding tasks to ACP-backed agents.
  • Verify that the new functions work as expected by testing them with the task-dispatch plugin and other trusted plugins.

Example

No code example is provided due to the lack of specific implementation details in the issue.

Notes

The proposed solution requires careful consideration of security implications, as it exposes new functionality to trusted plugins. Operators should be aware of the potential risks and benefits before enabling the plugins.allowAcpSpawn option.

Recommendation

Apply the proposed workaround by exposing the gated ACP runtime surface to trusted plugins, as it enables plugin-managed task orchestration systems to start and continue ACP-backed agent sessions, addressing the specific use case of the task-dispatch plugin.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING