CrewCoder is a first-class CrewCode chat and Crew provider implemented by
src/main/agents/crewcoder-bridge.ts. CrewCode is the ACP client: it spawns
crewcoder acp --approval review and translates newline-delimited JSON-RPC 2.0
onto the shared AgentBridge event stream. CrewCoder remains the ACP agent.
CrewCoder-specific usage metadata, permission semantics, reasoning, and tool-call ordering must not change Hermes behavior.
Install or build the crewcoder executable and authenticate its configured
backends through CrewCoder:
crewcoder auth
crewcoder acp --approval reviewCrewCode detects crewcoder on PATH. Settings → Agents can override the
binary path. The provider picker shows one CrewCoder provider; its model
picker spans CrewCoder's configured backends using provider:model ids such as
codex:gpt-5.6-sol and opencode:claude-sonnet-4-6.
The bridge performs this handshake before reporting ready:
initializewith protocol version 1 and text-file capabilities.session/loadwhen CrewCode has a saved native session id; unknown ids fall back tosession/new.session/set_external_directorieswith CrewCode's complete session grant list, including[]when all grants were removed.session/set_modelwhen a model is selected.session/set_reasoning_effortapplies CrewCode's selected effort to CrewCoder's provider client.session/promptruns each turn;session/follow_upqueues an instruction into an active CrewCoder turn, andsession/cancelis an ACP notification.
CrewCoder transcript replay contains user/assistant text only. When CrewCode's richer local transcript exists, provider replay is suppressed. CrewCoder remains a native-resume provider and uses summary-reset for manual compaction because it has no native compact RPC.
| CrewCoder ACP update | CrewCode event |
|---|---|
agent_message_chunk |
text_delta |
agent_thought_chunk |
thinking_delta |
tool_call |
tool_start |
repeated tool_call for the same id |
tool_update |
running tool_call_update |
tool_update |
completed/failed tool_call_update |
tool_end |
CrewCoder emits genuine reasoning, so the Hermes cosmetic-thinking filter must not be applied. Gated tools are announced as pending before the permission request; the bridge tracks tool ids so the later running announcement does not create a duplicate row.
Prompt JSON-RPC errors are emitted as bridge errors and followed by turn_end. ACP's standard
Internal error envelope can carry CrewCoder's actionable provider message in error.data.message;
the bridge prefers that detail instead of appending a misleading generic error after the streamed
failure.
CrewCoder ACP respects CrewCoder's persisted autoCompact setting. CrewCode does not force
compaction or retry context-window failures. When automatic compaction is off, the user explicitly
runs /compact before continuing; this policy does not affect Pi or other providers.
A prompt has a ten-minute inactivity watchdog rather than a wall-clock turn
limit. Every matching ACP update or agent request resets it, and time awaiting a
Build permission decision is excluded. If CrewCoder becomes genuinely silent,
CrewCode sends session/cancel and waits up to ten seconds for the prompt RPC to
settle before emitting the timeout and turn_end. If cancellation itself remains
unresponsive, CrewCode terminates that bridge so its replacement starts cleanly;
a second prompt can never overlap the abandoned CrewCoder turn.
Usage prefers _meta["crewcoder/usage"]: lastInputTokens is the live
contextTokens value and contextWindow is the context limit. Top-level usage
is only the compatibility fallback.
CrewCoder always starts with --approval review; CrewCode applies the current
composer mode when each session/request_permission arrives:
| CrewCode mode | Decision |
|---|---|
| Ask / Plan | cancel the permission request |
| Build | show the permission overlay |
| Full Access | select allow_once automatically |
any mode with toolPolicy: read-only |
cancel the permission request |
CrewCode exposes only Allow once and Reject once for CrewCoder. CrewCoder
remembers allow_always/reject_always internally and then stops asking for that
tool; those remembered decisions would bypass a later live composer-mode change.
Once-only choices preserve the invariant that current mode is always authoritative.
CrewCode ModeLevel (ask, plan, build, full) must never be passed to
CrewCoder's unrelated --mode option (general, plugin, extension).
The bridge advertises fs.readTextFile and fs.writeTextFile:
- local roots read/write the requested absolute path through Node filesystem APIs;
ssh://roots route text I/O through CrewCode's bounded SFTP helpers;- Ask, Plan, and
toolPolicy: read-onlyblock ACP writes; terminal/*is not implemented.
External directories are persisted on CrewCode's Session, passed through bridge startup, and
synchronized into CrewCoder after new/load. CrewCoder validates and persists those roots on the
agent host before authorizing its file tools. Changing the list drops the bridge so the next start
applies the new complete set; an empty set must be sent so removed access cannot survive in the
native CrewCoder session. Synchronization failure leaves the bridge unusable and blocks prompts;
continuing with stale native-session grants would violate the filesystem boundary. CrewCode's
native directory picker is local-only and rejects SSH workspaces rather than misrepresenting a
local path as remote access.
For SSH roots, spawnAgentProcess starts CrewCoder on the remote host. Its bash
tool is therefore local to the spawned CrewCoder process, which means remote for
an SSH workspace.
Current limitation: the local ACP filesystem host reads saved disk bytes. It does not yet query dirty CodeMirror or Writer buffers in the renderer, so an unsaved edit is not visible to CrewCoder until saved. Do not describe local ACP reads as unsaved-buffer aware until a bounded renderer-host request path is implemented.
CrewCoder is not offered for inline editor completion. Each ACP session/new
creates a durable CrewCoder session, which is inappropriate for disposable,
high-frequency ghost-text requests. CrewCoder also does not receive CrewCode MCP
registry entries yet; session/new and session/load send an empty MCP list.
rtk vitest run src/main/agents/crewcoder-bridge.test.ts
rtk vitest run src/main/agents/compaction-meter.test.ts
rtk npm run typecheckManual checks should cover model discovery, streamed text/reasoning, one row per tool id, Build permission prompts held longer than ten minutes, Ask rejection, Full auto-accept, inactivity cancellation, native resume, usage, and an SSH text read/write round trip.