ACPAgentRunner

ACP Agent Runner

langbot-team / ACPAgentRunner
Plugin0 downloadsAgent Runner1

Run any Agent Client Protocol compatible coding agent as a LangBot AgentRunner.

ACP Agent Runner

acp-agent-runner runs an Agent Client Protocol compatible agent process as a LangBot AgentRunner.

It is a thin runtime adapter:

  • LangBot remains the control plane.
  • The plugin starts an ACP server over stdio, such as npx -y @zed-industries/codex-acp, npx -y @agentclientprotocol/claude-agent-acp, opencode acp, or npx -y @google/gemini-cli --acp.
  • In daemon mode, a user-side langbot-runner-daemon connects outward to the plugin and starts the ACP process on the user's machine.
  • The plugin speaks ACP JSON-RPC: initialize, session/new, session/load or session/resume, and session/prompt.
  • ACP session/update text chunks are streamed back to LangBot.
  • LangBot multimodal input is mapped to ACP prompt content blocks when the selected ACP runtime advertises the matching prompt capability.
  • LangBot tools, knowledge bases, and history are exposed through the SDK-owned run-scoped MCP bridge.

Runner ID

plugin:langbot-team/ACPAgentRunner/default

Configuration

Common local examples:

provider = claude-code
location = local
workspace = /path/to/workspace
provider = codex
location = local
workspace = /path/to/workspace

For custom ACP commands, set provider=custom and acp-command, for example:

provider = custom
location = local
workspace = /path/to/workspace
acp-command = opencode acp

For a user workstation behind NAT, enable the plugin daemon hub and run the user-side daemon:

# Plugin config
daemon-enabled = true
daemon-host = 0.0.0.0
daemon-port = 8766
daemon-token = <shared-token>
cd acp-agent-runner
python daemon.py \
  --url ws://<langbot-public-host>:8766 \
  --daemon-id alice-laptop \
  --token <shared-token>

Then configure the runner:

provider = codex
location = daemon
daemon-id = alice-laptop
workspace = /Users/alice/project

Custom mode is for ACP stdio commands that are not built in, or for users who accept weaker/no ACP session recovery for a specific runtime:

provider = custom
location = local
workspace = /path/to/workspace
acp-command = kimi acp
provider = custom
location = local
workspace = /path/to/workspace
acp-command = agent acp
provider = custom
location = local
workspace = /path/to/workspace
acp-command = goose acp

acp-command must start an ACP JSON-RPC stdio server, not an interactive-only CLI. The runner still calls initialize, then session/resume or session/load when a stored session id exists and the runtime advertises that capability, otherwise session/new. Set reuse-session=false to force a fresh ACP session each run:

provider = custom
location = local
workspace = /path/to/workspace
acp-command = kimi acp
reuse-session = false

Useful options:

  • provider: built-in ACP launch preset. Current presets are limited to ACP runtimes that advertise loadSession or sessionCapabilities.resume and have no known public cross-process resume blocker. Use custom for anything else.
  • location: local, remote-ssh, or daemon.
  • workspace: agent workspace directory. In remote-ssh and daemon modes this path is on the remote/user machine.
  • ssh-target: SSH target for remote-ssh, for example [email protected].
  • ssh-port: SSH port. Defaults to 22.
  • ssh-identity-file: optional private key path on the LangBot host.
  • daemon-id: stable ID of a connected user-side runner daemon for location=daemon.
  • daemon-connect-timeout: seconds to wait for the selected daemon to come online.
  • acp-command: optional command override. Required only for provider=custom.
  • env-json: JSON object merged into the process environment.
  • reuse-session: persists and reuses external.acp_session_id when the ACP agent supports session/resume or session/load.
  • langbot-assets-enabled: injects the LangBot run-scoped MCP bridge into ACP mcpServers.
  • langbot-assets-mode: auto, ephemeral, or gateway. auto currently preserves the existing per-run bridge behavior; gateway registers the run in the SDK-owned long-lived HTTP MCP gateway.
  • langbot-assets-gateway-port: optional fixed port for langbot-assets-mode=gateway. Use a fixed port when another platform such as Dify needs to register the gateway URL.
  • langbot-assets-gateway-public-url: optional externally reachable MCP URL, for example https://example.com/mcp.

Headless ACP permission requests are answered with allow_once by default. LangBot does not yet expose an interactive approval UI for these requests.

Steering (follow-up input)

This runner declares capabilities.steering: true. When a run is still in progress and the user sends another message, LangBot absorbs it into the active run instead of starting a new one. The runner drains these follow-ups at each turn boundary via steering_pull and runs them as additional ACP session/prompt turns that resume the same session (session/resume or session/load). The run emits a single terminal run.completed once no follow-ups remain.

Notes:

  • Follow-ups are injected between turns, not mid-token.
  • Follow-up turns currently carry text only; attachments on follow-ups are not yet forwarded (the first turn still maps full multimodal input as described below).
  • In daemon mode follow-ups are still drained (no message loss), but session continuity across follow-up turns is best-effort.
  • Steering only applies when the run has a conversation scope; otherwise the runner transparently falls back to single-turn execution.

Multimodal Input

The runner accepts LangBot structured input and attachments. It maps them to ACP session/prompt content blocks according to the selected runtime's agentCapabilities.promptCapabilities:

  • inline image base64/data URLs are sent as ACP image blocks only when the runtime advertises image prompt support;
  • inline file base64/data URLs are sent as embedded ACP resource blocks only when the runtime advertises embedded context support;
  • URL-backed images or files are sent as ACP resource_link blocks;
  • unsupported inline attachments are not silently dropped; the prompt receives a short attachment note explaining which content was not sent.

Provider support still depends on the ACP executable being launched. A runtime that does not advertise image prompt support can still handle normal text input and URL resource links, but it will not receive inline image bytes.

Built-in provider commands are intentionally unpinned and assume the selected runtime can run on the target machine. Built-in presets must support ACP session recovery through loadSession or sessionCapabilities.resume; otherwise this runner would silently degrade into single-turn execution after each stdio process exits.

ProviderDefault ACP commandVerified session recovery signal
auggienpx -y @augmentcode/auggie --acploadSession
autohandnpx -y @autohandai/autohand-acploadSession, session/resume
claude-codenpx -y @agentclientprotocol/claude-agent-acploadSession, session/resume
codebuddy-codenpx -y @tencent-ai/codebuddy-code --acploadSession
codexnpx -y @zed-industries/codex-acploadSession, session/resume
deepagentsnpx -y deepagents-acploadSession
dimcodenpx -y dimcode acploadSession, session/resume
diracnpx -y dirac-cli --acploadSession
factory-droidnpx -y droid exec --output-format acp-daemonloadSession, session/resume
gemininpx -y @google/gemini-cli --acploadSession
glm-agentnpx -y glm-acp-agentloadSession, session/resume
kilonpx -y @kilocode/cli acploadSession, session/resume
opencodeopencode acploadSession, session/resume
pi-acpnpx -y pi-acploadSession
qwen-codenpx -y @qwen-code/qwen-code --acp --experimental-skillsloadSession, session/resume

The following ACP-capable or ACP-adjacent CLIs are not built-in presets because they do not currently meet the session recovery bar for this runner:

ProviderReason
agoragenticinitialize reports loadSession: false and no session/resume.
clineHeadless initialize did not complete during verification, so session recovery could not be confirmed.
cursorPublic reports show loadSession: true is advertised, but session/load fails for ACP-created sessions.
github-copilotRegistry npx launch did not start a usable ACP binary during verification.
gooseUpstream docs say ACP providers do not support session resume or fork yet.
kimiPublic issue reports ACP load/switch starts with blank history even though CLI history exists.
langcliNo registry/npm-verifiable ACP stdio package was available during verification.
novaHeadless initialize did not complete during verification, so session recovery could not be confirmed.
qoderPublic report shows ACP-created sessions cannot be loaded across process restarts despite loadSession: true.
sigitPackaged binary could not be verified in the test environment and no public session recovery evidence was found.

Other ACP-compatible runtimes from the public ACP registry can still be used via provider=custom and acp-command. DeepSeek's official Deep Code CLI is not a built-in preset yet because its current public docs describe the interactive deepcode CLI and MCP support, but do not document an ACP stdio mode.

For a remote Claude ACP process over SSH:

provider = claude-code
location = remote-ssh
ssh-target = [email protected]
workspace = /home/yhh/langbot-e2e/acp-workspace

Remote mode does not connect to a long-running ACP TCP service. LangBot starts the ACP process itself over SSH:

LangBot host
  -> ssh user@host "cd <workspace> && exec <acp-command>"
  -> ACP JSON-RPC over ssh stdio

When LangBot assets are enabled, the runner also starts a temporary run-scoped MCP bridge on the LangBot host and adds an SSH reverse tunnel on the same SSH connection:

remote ACP process
  -> http://127.0.0.1:<forwarded-port>/mcp
  -> SSH -R tunnel
  -> LangBot run-scoped MCP bridge

The remote host must allow non-interactive SSH login from the LangBot host and must already have the selected agent runtime installed, authenticated, and available on PATH for non-interactive shells.

Platform notes:

  • Linux remote: default path. The wrapper uses bash -lc, creates the workspace directory, changes into it, then execs acp-command.
  • macOS remote: same as Linux when the remote has bash and the selected agent runtime available to non-interactive SSH sessions. If a Homebrew/npm path is missing, set it through env-json or use an absolute command path.
  • Windows remote: not identical to Linux/macOS. Configure the hidden remote-shell=powershell key manually; the wrapper uses PowerShell to create the workspace and run acp-command. Windows OpenSSH must support reverse forwarding for LangBot MCP assets to work. A first-class Windows UI option is not exposed yet.

If a network policy blocks SSH reverse forwarding, set mcp-bridge-transport=http plus mcp-public-url to a URL reachable from the remote host, or disable LangBot asset injection with langbot-assets-enabled=false.

Run-Scoped LangBot Assets

By default the plugin starts a temporary run-scoped MCP bridge for each run. The bridge URL and token are injected into ACP mcpServers, and the bridge is stopped when the run finishes.

In location=daemon, the ACP process does not call the plugin's MCP bridge directly. The user-side daemon starts a localhost HTTP MCP proxy, injects that local URL into ACP, then forwards MCP JSON-RPC requests over the already-open WebSocket connection back to the plugin. The plugin handles those requests with the current run's AgentRunAPIProxy, so LangBot assets remain scoped by run_id and the Host authorization snapshot. The user's workstation does not need a public IP or inbound port for this path. Runner code should import the SDK proxy from langbot_plugin.api.proxies.agent_run.

To test the long-lived HTTP MCP gateway path with ACP, set:

langbot-assets-enabled = true
langbot-assets-mode = gateway
langbot-assets-gateway-port = 8765

In gateway mode, the SDK starts one process-long HTTP MCP gateway and registers each LangBot run with a short-lived run token. ACP receives the gateway MCP URL and token through mcpServers headers, so the model can call stable LangBot gateway tools without seeing the token. The gateway tool list is stable and includes:

  • langbot_list_assets
  • langbot_get_current_event
  • langbot_history_page
  • langbot_retrieve_knowledge
  • langbot_get_tool_detail
  • langbot_call_tool

The stable tool list is intentionally compatible with platforms such as Dify that cache MCP provider tools. For those platforms, the same gateway can accept the short-lived run_token as a tool argument instead of an HTTP header. Register the provider URL with the /mcp path, for example http://<langbot-host>:8765/mcp or the value configured in langbot-assets-gateway-public-url.

The current LangBot run_id is included in the prompt for diagnostics only. ACP agents should follow MCP tool schemas exactly and should not add run_id to tool calls unless a specific tool schema asks for it.

Complete configuration index

In addition to the common fields described above, the current runner exposes:

  • daemon-connect-timeout for waiting on a selected daemon.
  • langbot-assets-gateway-host, langbot-assets-gateway-port, langbot-assets-gateway-public-url, and langbot-assets-token-ttl for Asset Gateway mode.
  • ssh-connect-timeout, ssh-extra-options, and ssh-identity-file for SSH execution.
  • startup-timeout and initialize-timeout for ACP process startup and handshake deadlines.
  • create-session-if-missing for recovery fallback behavior.
  • streaming for incremental output.
  • append-run-scope-prompt for adding LangBot run-scope guidance.
  • mcp-servers-json for additional MCP server configuration.

Scope

This plugin intentionally does not implement an agent platform, task board, workspace manager, or provider-specific CLI behavior. Provider setup, login, model selection, and tool permission semantics still belong to the ACP agent executable being launched.

Use ACP Agent Runner in Feishu/Lark bots, DingTalk bots, WeCom bots, WeChat bots, QQ bots, Slack bots, Discord bots, Telegram bots, LINE Bots, and Matrix Bots.

Host your bot on LangBot Cloud and connect this extension to the collaboration platforms your team already uses.

Open LangBot Cloud

Comments