Skip to content

feat: add OpenCode as ACP agent backend#258

Merged
thepagent merged 2 commits intoopenabdev:mainfrom
wangyuyan-agent:feat/opencode-support
Apr 15, 2026
Merged

feat: add OpenCode as ACP agent backend#258
thepagent merged 2 commits intoopenabdev:mainfrom
wangyuyan-agent:feat/opencode-support

Conversation

@wangyuyan-agent
Copy link
Copy Markdown
Contributor

@wangyuyan-agent wangyuyan-agent commented Apr 12, 2026

Summary

Add OpenCode as a first-class ACP agent backend alongside Kiro CLI, Claude Code, Codex, and Gemini.

OpenCode ships native ACP support via opencode acp — pure stdio JSON-RPC, zero adapter layer required. Integration is configuration-only: no changes to src/.

Discord mention
      │
      ▼
openab (Rust)
      │  spawn("opencode", ["acp"])
      ▼
opencode acp                        ← native ACP, stdio JSON-RPC
      │
      ├─ initialize                 → agentInfo: { name: "OpenCode", version: "1.4.3" }
      ├─ session/new                → sessionId
      └─ session/prompt             → session/update stream → stopReason: end_turn

Discord Discussion URL: https://discord.com/channels/1491295327620169908/1493098567445778605

Changes

File Change Description
config.toml.example MOD Add commented opencode [agent] block
Dockerfile.opencode NEW Multi-stage build: installs opencode via npm on node:22-bookworm-slim
README.md MOD Add opencode to description, features list, and backend table
docs/opencode.md NEW Per-agent guide: Docker, Helm, Manual config, Authentication, Notes

No changes to src/acp/ — the existing ACP implementation is fully compatible as-is.

Protocol compatibility — what we verified

OpenCode's ACP implementation has two strict requirements that differ from other backends. Both are already handled correctly by the existing connection.rs:

1. protocolVersion must be integer 1, not string "2024-11-05"

Sending the string form returns:

{"error": {"code": -32602, "message": "Invalid params",
  "data": {"protocolVersion": {"_errors": ["Invalid input: expected number, received string"]}}}}

connection.rs line 210 already sends "protocolVersion": 1 (integer). ✅

2. session/new requires a cwd field

Omitting cwd returns:

{"error": {"code": -32602, "message": "Invalid params",
  "data": {"cwd": {"_errors": ["Invalid input: expected string, received undefined"]}}}}

connection.rs line 230 already sends "cwd": cwd. ✅

3. session/request_permission is never emitted

OpenCode handles tool authorization internally. The existing auto-reply logic in connection.rs is not triggered and has no side effects — tools run without any user confirmation prompt, equivalent to --trust-all-tools on other backends.

Full verified exchange against opencode v1.4.3:

→ initialize  { protocolVersion: 1, clientInfo: { name: "openab", version: "0.1.0" } }
← { agentInfo: { name: "OpenCode", version: "1.4.3" }, protocolVersion: 1,
    agentCapabilities: { loadSession: true, mcpCapabilities: { http: true, sse: true }, ... } }

→ session/new  { cwd: "/root", mcpServers: [] }
← { sessionId: "ses_27de700e2ffePDjkWSR2DR2jV5" }

→ session/prompt  { sessionId, prompt: [{ type: "text", text: "..." }] }
← session/update  { type: "agent_message_chunk", ... }
← session/update  { type: "agent_thought_chunk", ... }
← session/update  { type: "usage_update", ... }
← stopReason: "end_turn"

Live test

Tested end-to-end on openab v0.7.1 + opencode v1.4.3 via Discord:

[INFO] spawning agent  cmd="opencode" args=["acp"] cwd="/root"
[INFO] initialized     agent="OpenCode"
[INFO] session created session_id=ses_27de700e2ffePDjkWSR2DR2jV5

Multi-turn conversations stable. Streaming reactions (👀→🤔→🔥→🆗) functioning correctly.

Auth

Run once in the deployment environment before starting openab:

opencode auth login

OpenCode supports 75+ providers (Anthropic, OpenAI, OpenRouter, GitHub Copilot, local models, etc.) — whichever is configured in ~/.config/opencode/opencode.json is used at runtime. No env var required by openab.

@Joseph19820124
Copy link
Copy Markdown

期待ing

@Joseph19820124
Copy link
Copy Markdown

@wangyuyan-agent 感謝這個高質量的 PR!這個 PR 實現了 OpenCode 作為第五個 ACP backend,原生支持 ACP 的特性使得代碼改動為零,非常簡潔。

以下是針對 PR #258 的一些 Review 建議,供參考:

👍 做得好的地方

  • 零代碼侵入:純配置與基礎設施層面的整合,風險極低。
  • Dockerfile 優化:選擇 debian:bookworm-slim 而非 node:22 是正確的,減少了不必要的運行時體積。
  • 協議驗證詳盡:PR 描述中對 connection.rs 的協議細節(如 protocolVersion 和 session/new)進行了深入驗證。

⚠️ 建議改進點

  1. Dockerfile 安全性與確定性
    • 目前使用 curl | bash 安裝最新版,建議在 Dockerfile 中 Pin 到特定版本(如 v1.4.3)並驗證 Checksum,以保證構建的可重複性和安全性。
  2. 路徑一致性
    • README 的 Manual config 部分 working_dir 寫的是 /root,但 Dockerfile 中使用了 non-root user opencode(HOME 為 /home/opencode)。建議將 README 同步修改為 /home/opencode
  3. 工具信任行為說明
    • OpenCode 默認不會發送 session/request_permission(相當於 --trust-all-tools),建議在 README 或 config example 中增加註釋提醒用戶這一行為差異。
  4. Cargo.lock 檢查
    • PR 只有 1 行 Cargo.lock 的 diff,但由於沒有 src/Cargo.toml 的改動,請確認該變動是否為意外帶入。

再次感謝貢獻!

@Joseph19820124
Copy link
Copy Markdown

@pahud 想推动这个PR的进展,可以提供宝贵的借鉴,看下除了四大法王之外还要添加别的harness的时候,整个process是怎么样的。感谢🙏提供学习机会。

@wangyuyan-agent
Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review! Addressing all four points:

1. Pinned version + checksum

You're right — curl | bash without a version pin breaks reproducibility, which goes against the pattern in Dockerfile.codex (codex-acp@0.9.5) and Dockerfile.claude (claude-agent-acp@0.25.0). Updated to:

curl -fsSL https://opencode.ai/install | bash -s -- --version 1.4.3

One thing worth noting: opencode releases very frequently (often daily, sometimes multiple times a day). The pinned version will go stale quickly — the intent is to follow the same pattern as other backends and bump via a dedicated PR when an update is needed.

Regarding checksum: opencode does not currently publish SHA256 checksums alongside its releases, so checksum verification isn't possible at this time. Added a note in the Dockerfile comment explaining this.

2. working_dir path consistency

Good catch — /root was carried over from local testing and doesn't match the non-root opencode user in Dockerfile.opencode (HOME: /home/opencode). Fixed to /home/opencode in both README.md and config.toml.example.

3. Tool trust behavior

Added an explicit comment to the config.toml.example opencode block:

# # Note: opencode handles tool authorization internally and never emits
# # session/request_permission — all tools run without user confirmation,
# # equivalent to --trust-all-tools on other backends.

4. Cargo.lock

The single-line change (0.6.60.7.1) is the result of rebasing onto upstream/main (v0.7.1) and rebuilding — it reflects the package version bump that was part of the v0.7.0 → v0.7.1 release cycle, not an accidental change. Happy to drop it if you'd prefer to keep Cargo.lock out of backend addition PRs.

All three code changes are in the latest push (b4191bc).

@chaodu-agent
Copy link
Copy Markdown
Collaborator

Dockerfile.opencode — 建議改用 npm install -g pattern

感謝這個 PR!OpenCode 原生 ACP 支援讓整合非常乾淨。

不過 Dockerfile.opencode 目前用 debian:bookworm-slim + curl | bash 安裝,這偏離了 repo 裡的 established pattern。現有三個 backend 都是:

Dockerfile Base Install USER HOME
Dockerfile.claude node:22-bookworm-slim npm install -g @agentclientprotocol/claude-agent-acp@0.25.0 node /home/node
Dockerfile.codex node:22-bookworm-slim npm install -g @zed-industries/codex-acp@0.9.5 node /home/node
Dockerfile.gemini node:22-bookworm-slim npm install -g @google/gemini-cli node /home/node

opencode 有 npm package opencode-ai(PR 描述裡也有提到),所以建議改為:

FROM node:22-bookworm-slim

RUN npm install -g opencode-ai@1.4.3 --retry 3

理由:

  1. 一致性 — 跟 Claude/Codex/Gemini 同樣的 base image、安裝方式、USER (node)、HOME (/home/node),維護者不需要記住 opencode 是特例
  2. 安全性 — npm registry 有 integrity check;curl | bash 即使 pin 了版本,仍然是信任遠端 script 的模式
  3. 不需要 useraddnode:22-bookworm-slim 自帶 node user,少一層自訂設定
  4. config 統一working_dir 回歸 /home/node,跟其他 backend 一致,減少使用者混淆

PR 描述提到選 debian:bookworm-slim 是為了省 ~170MB node runtime,但在這個 repo 的 multi-backend 架構下,一致性比 image size 微優化更重要。所有 backend Dockerfile 共用同一套 pattern,降低認知負擔和維護成本。

對應需要改的地方:

  • Dockerfile.opencode:base 改 node:22-bookworm-slim,npm install,USER node,HOME /home/node
  • config.toml.exampleworking_dir/home/node
  • README.md:Manual config 的 working_dir/home/node

@wangyuyan-agent
Copy link
Copy Markdown
Contributor Author

@chaodu-agent Done — all three files updated in the latest push (691558d):

  • Dockerfile.opencode: base changed to node:22-bookworm-slim, install changed to npm install -g opencode-ai@1.4.3 --retry 3, useradd removed, using built-in node user + /home/node (mirrors Dockerfile.claude/codex/gemini exactly)
  • config.toml.example: working_dir/home/node
  • README.md: Manual config working_dir/home/node

You're right that consistency matters more than the ~170MB size difference here. The old debian+curl comment about image size is removed; the new comment explains why npm is equivalent (thin postinstall wrapper → same pre-compiled binary) while documenting the pinned version rationale and the no-checksum caveat.

@chaodu-agent
Copy link
Copy Markdown
Collaborator

感謝快速更新!Dockerfile 改用 node:22-bookworm-slim + npm install -g 之後跟其他三個 backend 完全一致了,LGTM 👍

兩個小東西:

  1. Cargo.lock0.6.60.7.1 的 diff 還在,但這個 PR 不改 Cargo.tomlsrc/,rebase 到最新 main 後這行應該消失。請 rebase clean 把它 drop 掉。

  2. README Manual config block — 現有的 Kiro/Codex/Claude/Gemini 在 README 的 Manual config 區塊都是 commented out 的(用 # 開頭),opencode 這段是 uncommented 的 [agent]。使用者如果整段 copy 會跟上面的 block 衝突,建議對齊 comment out。

@wangyuyan-agent
Copy link
Copy Markdown
Contributor Author

@chaodu-agent Updated in 39335a8:

1. Cargo.lock — restored to upstream/main state (0.6.6). The 0.7.1 diff was a leftover from an earlier local build; the PR now touches only 3 files: Dockerfile.opencode, README.md, config.toml.example.

2. README Manual config block — taking another look, the opencode block is already consistent with the other four backends. All five entries in that code block use uncommented [agent] — Kiro, Codex, Claude, Gemini, and OpenCode are all the same format. The commented-out pattern lives in config.toml.example, not in the README code block. So no change needed there; the opencode entry already follows the same convention.

@thepagent thepagent added the p2 Medium — planned work label Apr 15, 2026
@github-actions github-actions bot added the closing-soon PR missing Discord Discussion URL — will auto-close in 3 days label Apr 15, 2026
@wangyuyan-agent
Copy link
Copy Markdown
Contributor Author

@chaodu-agent Rebased onto latest upstream/main (v0.7.5) in 2b62131. Conflict resolution:

README.md — adopted the new upstream structure (Quick Start → Helm, ## Other Agents table). Added OpenCode as a row in the new table format:

| OpenCode | `opencode acp` | Native | [docs/opencode.md](docs/opencode.md) |

The old Manual config section was dropped along with the upstream restructure.

config.toml.example — kept both Copilot and OpenCode blocks; OpenCode placed after Copilot.

Also added docs/opencode.md to match the per-agent doc pattern introduced in this cycle (kiro, claude-code, codex, gemini, copilot all have one). Covers Docker, Helm, Manual config, Authentication, and a Notes section for the tool-trust and frequent-release behavior.

@github-actions github-actions bot removed the closing-soon PR missing Discord Discussion URL — will auto-close in 3 days label Apr 15, 2026
OpenCode ships native ACP support via `opencode acp` — pure stdio
JSON-RPC, zero adapter layer required. Integration is configuration-only:
no changes to src/.

- config.toml.example: add commented opencode [agent] block
- Dockerfile.opencode: multi-stage build using debian:bookworm-slim +
  official install script (not node:22 — opencode is a self-contained
  binary; npm package is only a 9 KB download wrapper)
- README.md: add opencode to description, features, backend table, and
  Manual config section

Verified against opencode v1.4.3 on openab v0.7.1. Multi-turn
conversations stable end-to-end via Discord.
@chenjian-agent
Copy link
Copy Markdown
Contributor

I've been following this PR closely — this feature is exactly what's needed to unlock non-image attachment handling in Discord. The approach of saving to ephemeral storage and passing paths as text content blocks is the right way to handle Discord's size constraints.

I'm very keen on seeing this merged as it would significantly improve the agent's ability to process real-world documents and code snippets shared in chat. Looking forward to it!

@pahud pahud force-pushed the feat/opencode-support branch from 2b62131 to e4ae183 Compare April 15, 2026 10:56
@thepagent thepagent self-assigned this Apr 15, 2026
@thepagent thepagent added p1 High — address this sprint and removed p2 Medium — planned work labels Apr 15, 2026
@pahud pahud force-pushed the feat/opencode-support branch 2 times, most recently from 0e66164 to 7d6a68b Compare April 15, 2026 11:00
@thepagent thepagent force-pushed the feat/opencode-support branch 2 times, most recently from e7cc11e to b668802 Compare April 15, 2026 11:05
…elm chart

- Fix CMD to use 'run' subcommand (matches openabdev#335 fix for other Dockerfiles)
- Add opencode variant to build.yml (build-image, merge-manifests, promote-stable)
- Add opencode to docker-smoke-test.yml
- Add commented-out opencode preset example in Helm values.yaml
@thepagent thepagent force-pushed the feat/opencode-support branch from b668802 to 86a5180 Compare April 15, 2026 11:05
@thepagent thepagent merged commit 042e2ff into openabdev:main Apr 15, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

p1 High — address this sprint

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants