A ccbud sidecar plugin that runs Claude Code and
Codex on Qoder by bridging to the official qodercli --acp agent (Agent
Client Protocol) — using either your Qoder CLI login or a Qoder personal access
token (PAT), with no patching of the CLI. It also exposes an adjustable
thinking depth knob.
ccbud forwards standard OpenAI-Chat requests to this plugin; the plugin launches the
official Qoder CLI in ACP mode, drives a session over stdio, and relays the agent's
streaming output back as a chat.completion stream. Auth, crypto, and inference all
stay inside Qoder's own binary — the plugin only speaks its published protocol.
This is the sanctioned successor to the earlier
qoder-local-bridgeapproach: it replaces reused WASM crypto + direct gateway calls with Qoder's own ACP interface (the same one Zed and other editors use).
@qoder-ai/qodercli ships an official --acp mode ("Starts the agent in ACP
mode") — newline-delimited JSON-RPC 2.0 over stdio, the Agent Client
Protocol. We run it as-shipped and act as the ACP
client:
ccbud host ─POST /v1/chat/completions─▶ qodercli-plugin (Node)
│ 1. OpenAI-Chat messages → one ACP prompt turn
│ 2. session/new + session/prompt
│ 3. stream session/update → chat.completion SSE
│ 4. serve fs/terminal/permission for the agent
▼
qodercli --acp (official CLI; auth + crypto + inference)
• initialize / authenticate (reuses your login)
• session/prompt → agent_message_chunk / tool_call / plan …
src/acp/— the ACP client: launchesqodercli --acp, does the initialize/authenticate handshake, and correlates JSON-RPC requests, responses, andsession/updatenotifications.src/proxy/chatAcp.ts— the OpenAI-Chat ⇄ ACP bridge (prompt building + streaming translation).
Because ACP exposes Qoder as an agent (not a raw completion model), Qoder runs its own tool loop. This plugin runs it in full-agent mode:
- It advertises client
fs/terminalcapabilities and auto-approvessession/request_permission, so Qoder can read/write files and run commands in the workspace (--cwd, default: the process's current directory). - File writes are scoped to the workspace by default; reads and commands are not.
- ccbud's OpenAI-style
tools/function-calls do not round-trip through ACP — Qoder uses its own tools. This bridge is best for chat/ask and agentic edits, not for driving Qoder as a tool-emitting model.
--cwd at a project you're comfortable letting it change.
Credential priority is:
- The Qoder PAT in CC Buddy's existing API Key field. CC Buddy forwards it as
Authorization: Bearer …; olderx-api-keyforwarding is also accepted. QODER_PERSONAL_ACCESS_TOKENin the sidecar environment.- The persisted Qoder CLI login created by
qodercli login.
Each PAT is passed only to the matching qodercli --acp child process. Different
credentials are never reused across Agent processes, and a rejected PAT fails
closed instead of opening or falling back to the interactive login flow. PAT
Agents use a private temporary Qoder config directory (removed on shutdown), and
Agent-run terminal commands cannot inherit or inject the PAT. With no PAT, the ACP
agent restores the persisted CLI login while creating a session and the plugin
invokes qodercli-login only when the agent explicitly requires it. The plugin
never signs in/out and redacts PATs from forwarded Agent output.
Send a reasoning knob on the chat request — OpenAI's reasoning_effort or a
Responses-style reasoning.effort (both accepted). It is normalized to Qoder's
{low, medium, high} and passed to the agent as --reasoning-effort:
{ "model": "Ultimate", "reasoning_effort": "high", "messages": [ ... ] }minimal|none → low, max|ultra|xhigh → high.
- Node.js ≥ 20
@qoder-ai/qodercli(pulled as a dependency; or on PATH / viaQODER_CLI_PATH), signed in withqodercli login
make dist # npm install + bundle the server
node dist/main.mjs serve --port 8899 --cwd /path/to/workspace
curl -N http://127.0.0.1:8899/v1/chat/completions -H 'content-type: application/json' \
-H 'authorization: Bearer <qoder-personal-access-token>' \
-d '{"model":"Auto","stream":true,"messages":[{"role":"user","content":"hi"}]}'Install via ccbud's plugins page → 从 Git 添加 (needs git + Node): ccbud
clones, runs make dist, and registers a Qoder service.
ccbud's runtime.exec is a per-platform binary map. A Node plugin has no native
binary, so each platform points at a small launcher shim (bin/launch.sh,
bin/launch.cmd) that finds node and runs the plugin — so node (≥20) must be
on the PATH ccbud spawns with. The shim prefers dist/main.mjs and falls back to
the TypeScript source, so the plugin still starts (and reports logged_out) before
make dist has run.
| Env | Default | Meaning |
|---|---|---|
QODER_CONFIG_DIR |
~/.qoder |
Qoder config / credentials (also passed to the agent) |
QODER_ACP_CWD |
process cwd | Workspace the agent reads/writes/runs in |
QODER_CLI_PATH |
auto | Override the qodercli launch (bundle path or executable) |
QODER_PERSONAL_ACCESS_TOKEN |
— | Default PAT when the request has no CC Buddy API Key |
POST /v1/chat/completions— OpenAI-Chat (stream + non-stream), thinking depthGET /v1/models— the model aliases (Auto / Ultimate / Performance / Efficient / Lite)GET /healthz,GET /v1/plugin/status,GET /v1/plugin/auth— control plane
All endpoints are loopback-only (Host/Origin are validated) to blunt DNS-rebinding and drive-by browser requests.
ACP is a stable, versioned protocol, so upgrades are far less fragile than the old
bundle-patching approach. If a new @qoder-ai/qodercli changes behavior:
- Handshake fails: check
initialize— the plugin logs the agent'sprotocolVersion/ capabilities. BumpACP_PROTOCOL_VERSIONinsrc/acp/protocol.tsif Qoder advances it. - Empty/odd output: the
session/updatevariants moved — adjustupdateToDelta()insrc/proxy/chatAcp.ts. - Auth loops: confirm the
authMethods[].idthe agent returns still matches whatensureAuth()sends.
This is an unofficial, independent integration — not affiliated with, endorsed by, or supported by Qoder or ccbud.
- Official interface. It drives Qoder only through the documented
qodercli --acpprotocol and your ownqodercli login; it does not patch the CLI, reuse its crypto, or call Qoder's gateway directly. Use is still subject to Qoder's Terms of Service — use an account you control, at your own risk. - Full-agent autonomy. In full-agent mode the plugin auto-approves the agent's
actions, so Qoder can modify files and run commands in
--cwd. Scope it to a project you're comfortable with. - No redistribution of Qoder's code. The GPL-3.0 license (
LICENSE) covers onlysrc/and this repo's build scripts.@qoder-ai/qodercliis proprietary to Qoder, is a normal npm dependency (not included or relicensed here). Nothing here grants rights to Qoder's code or service. - No warranty. Provided "as is" (see
LICENSE).
Working: launches the official qodercli --acp, initialize/auth handshake, control
plane, streaming text + reasoning with adjustable depth, full-agent fs/terminal +
auto-permission, loopback guard, clean shutdown. Verify the streaming inference path
against your own qodercli login. Partial / TODO: session reuse across turns
(sessions are currently created per request), live model listing, and image inputs
beyond data: URLs.
Pure Node standard library at runtime (only dep is the Qoder CLI it drives). Licensed
GPL-3.0-only — see LICENSE. Note the disclaimer above.