Repository navigation
feat(runtime): production ACP adapter for opencode and Claude Code - #69
Open
FreshlyBrewedCode wants to merge 4 commits into
Open
FreshlyBrewedCode wants to merge 4 commits into
FreshlyBrewedCode wants to merge 4 commits into
Conversation
Turn the finding-13 spike adapter into the production ACP adapter (ADR 0013 §1, §3–§6). It sits beside the opencode adapter; #64 makes it the default. - acp-agents.ts: agent definitions for `claude` (bundled claude-agent-acp, run on the daemon's bun) and `opencode` (`opencode acp`), each with `hostSettings: "ignore" | "include"` (default ignore): - claude: `_meta.claudeCode.options.settingSources: ["project","local"]` - opencode: `XDG_CONFIG_HOME` and `OPENCODE_TEST_HOME` point at empty factory-owned dirs; a factory plugin (`shell.env` hook) hands the host's `XDG_CONFIG_HOME` back to shell commands so gh and git keep their config; the host's `OPENCODE_CONFIG*` variables are dropped - environment scrub of the parent's `CLAUDECODE` / `CLAUDE_*` variables, keeping the credential ones (`CLAUDE_CONFIG_DIR`, OAuth token, provider) - `checkAgents()`: opencode on PATH, Claude login via the bundled CLI's `auth status --json` - acp-adapter.ts: required model (fails before the prompt, naming the agent and a sample of offered ids), permission answered allow_always > allow_once, each `usage_update` forwarded in order as a CUSTOM `acp.usage` chunk with a new `usage` signal, cancel = session/cancel then kill after a grace, kill (and SIGKILL fallback) in finally, agent exit mid-turn fails the step with the exit code and stderr tail - AgentSignal gains `usage` (recorded by #65; the runtime reads past it) - AgentStepChunkError leads with the adapter's message - tests against a fake ACP agent over stdio (AgentSideConnection) - spike runner adapted to the production API, with an `isolation` mode Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Finding 13, addendum 2: Claude's settingSources keeps user skills, plugins and CLAUDE.md out; opencode's OPENCODE_CONFIG_DIR adds rather than hides, so XDG_CONFIG_HOME + a shell.env plugin + OPENCODE_TEST_HOME hide the host's opencode config and home-level skills while gh and git keep theirs. Also the env scrub and the availability check. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
FreshlyBrewedCode
added this pull request to stack #70
October 2, 2026 19:28
ACP's session/new requires an absolute `cwd`, and claude-agent-acp rejects anything else. The default workspace root (`.factory/workspaces`) is relative, so every daemon-allocated run failed its first Claude step with "`cwd` must be an absolute path". The adapter now resolves the step's dir against the daemon's working directory, for the spawn and for session/new. The fake ACP agent validates `cwd` the same way. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
With host settings ignored, claude-agent-acp still reports the user's `model` setting (here `haiku`) as the session's current model, while the Agent SDK, no longer reading user settings, runs its own default. The adapter skipped `session/set_config_option` when the requested model equalled that reported value, so a step asking for `haiku` ran on another model: a live run reported a 1M context window and 0.08 USD for 330 output tokens. The adapter now always sets the model; a reported current value that is not in the offered list is still accepted. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Owner
Author
|
Two fixes landed on this branch from the layer above (#71), both found in live runs through the daemon:
🤖 Generated with Claude Code |
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
This PR turns the finding-13 spike adapter into the production ACP adapter (ADR 0013 §1, §3–§6). It runs beside the opencode adapter, and #64 makes it the default.
src/runtime/acp-agents.ts: the agent definitions and the availability check.claudeAgent()launches the bundled claude-agent-acp on the daemon's own bun.opencodeAgent()launchesopencode acp.acpAgent(kind, { hostSettings })picks one of the two."ignore":_meta.claudeCode.options.settingSources: ["project","local"].XDG_CONFIG_HOMEandOPENCODE_TEST_HOMEpoint at empty directories that factory owns. A factory plugin (acp-opencode-plugin.ts, opencode'sshell.envhook) hands the host'sXDG_CONFIG_HOMEback to every shell command, soghand git keep their config. The host'sOPENCODE_CONFIG*variables are dropped.CLAUDECODEandCLAUDE_*are removed from the agent's environment. The credential variables stay:CLAUDE_CONFIG_DIR,CLAUDE_CODE_OAUTH_TOKENandCLAUDE_CODE_USE_BEDROCK/_VERTEX.checkAgents(kinds)returns{agent, problem}[]. It reports opencode missing from PATH, and Claude not logged in (read from the bundled CLI'sauth status --json).src/runtime/acp-adapter.ts:acpAdapter(definition, { onDiagnostic?, cancelGraceMs? }).allow_always, falling back toallow_once.usage_updatebecomes aCUSTOMacp.usagechunk carrying a newusagesignal (context: {used,size},cost?: {amount,currency}), in arrival order.session/cancel, then a kill after a grace period, and always a kill infinally(SIGKILL if the process lingers).AgentSignalgainsusage. The runtime ignores it for now; feat(events): context and cost per agent step, ACP-aware run detail #65 records it.AgentStepChunkErrornow starts with the adapter's message, soAgentStepFinished.errorreadsAgentStepChunkError: claude has no model "…"instead of a bare stack.spikes/13-acp-agents.tsis adapted to the production API and has a newisolationmode.Tests
bun run checkis green (377 tests). The new unit tests run against a fake ACP agent over stdio, built on the SDK'sAgentSideConnection(test/fixtures/fake-acp-agent.ts). They cover:allow_alwaysanswer;RUN_ERROR;cancelled, an agent that ignores cancel and is killed after the grace period, and a crash mid-turn that carries the exit code and stderr;startRunthat leaves no process behind.Separate tests cover the definitions, the plugin hook and the auth parsing.
Live validation (this host)
run claude sonnethaikutosonnet. One ask (Edit math.ts), answeredallow_always. Structured output on tier 1. Per-step cost 0.039 / 0.027 USD inacp.usagerun opencode opencode/big-picklecancel claude sonnetRunCancelled2 ms, settled 22 ms, 0 of 2 processes alivecancel opencode …RunCancelled2 ms, settled 83 ms, 0 of 1 processes alivebad-modelclaude / opencodeCLAUDE*vars in the parent, 0 passed to the agent. Parent sentinel values appeared 0 times in either agent's shellcheckAgents[]on this host (0.25 s). WithHOMEpointed at an empty dir and opencode off PATH, both problems are reportedIsolation (finding 13, addendum 2):
settingSources: ["project","local"]hides the user's skills, theanthropic-skillsplugin and the userCLAUDE.md. 47 skills are listed withincludeand 14 withignore. The project'sCLAUDE.mdand skills stay.OPENCODE_CONFIG_DIRonly adds a directory; with it set, 715 models were still offered. What hides the host config isXDG_CONFIG_HOME, the plugin andOPENCODE_TEST_HOME:omnirouteprovider is gone);XDG_CONFIG_HOME=/home/karl/.configis restored,gh auth statusis logged in, and git's global config is read;Deviations / notes for later layers
OPENCODE_TEST_HOMEis undocumented. It is a test hook, and it is the only way I found to hide opencode's home-level reads (~/.claude/skills,~/.agents/skills,~/.claude/CLAUDE.md). If opencode drops it, the host's skills come back into runs, but nothing breaks.OPENCODE_DISABLE_CLAUDE_CODE*would also hide the project's Claude files. ADR 0013 §3 left the mechanism to this ticket; test(e2e): live validation of ACP agents, docs and ADR acceptance #67 can fold it into the ADR.CLAUDE_*variables (listed above). This follows ADR §3: "credentials are not settings".hostSettings),agentinAgentAdapterOptions, and callingcheckAgentsat daemon start.usageinAgentStepFinished.prepareWorkspace, and the abort-chain commentary inagent-step.ts.external_directoryandRUN_ERRORscenarios.Closes #63
Part of #62
🤖 Generated with Claude Code