Skip to content

Real-coder layer: OpenCode via ACP — full rebuild + auto-wire#168

Merged
seamus-brady merged 1 commit intomainfrom
feature/real-coder-acp
Apr 26, 2026
Merged

Real-coder layer: OpenCode via ACP — full rebuild + auto-wire#168
seamus-brady merged 1 commit intomainfrom
feature/real-coder-acp

Conversation

@seamus-brady
Copy link
Copy Markdown
Owner

Summary

  • Replaces the unfinished REST-based coder integration with an ACP-driven (Agent Client Protocol over JSON-RPC stdio) layer talking to a sandboxed OpenCode 1.14.25 container. ~1500 LOC of REST plumbing out, ~400 LOC of ACP in.
  • dispatch_coder is the cog/PM tool: one OpenCode session per call, async via OTP worker so the cog stays responsive — mid-flight cancel_coder_session is reachable. agent_coder collapses to a thin specialist (frame → dispatch → inspect → land), only registered when [coder] is fully configured.
  • Auto-wire — fresh installs just work: [coder] defaults are populated (image=springdrift-coder:1.14.25, provider=anthropic, model=claude-sonnet-4-6); project_root falls back to cwd; the application auto-builds Containerfile.coder on first boot if the image is missing. Operator only needs ANTHROPIC_API_KEY in .env.

What's in the box

  • coder/acp.gleam — JSON-RPC over stdio bindings; pure decoders pinned against probed shapes
  • coder/manager.gleam — OTP actor with warm container pool, per-dispatch driver, three-stage kill chain, per-task budget enforcement, hourly cost cap, janitor TTL
  • coder/ingest.gleam — completed dispatch → CbrCase (CodePattern, tools_used = ACP tool titles seen during the session) + raw JSON archive in .springdrift/memory/coder/sessions/
  • tools/coder_dispatch.gleam — async-via-worker dispatch_coder + sync cancel_coder_session / list_coder_sessions; budget clamp-and-report against operator ceilings
  • agent/cognitive*.gleamPendingCoderDispatch + CoderDispatchComplete ride the existing WaitingForAgents accumulator; multiple parallel dispatches fold into one rethink

Removed

  • coder/client.gleam REST wrapper, coder/supervisor.gleam per-task slot lifecycle, http_probe_get FFI
  • run_tests / run_build / run_format host-side scaffolding tools
  • coder_start_session / coder_send / coder_end_session tools, replaced by dispatch_coder
  • ProjectCommands type + default_project_commands
  • Three-mode coder agent branching: sandbox-only and no-sandbox legacy modes are gone
  • manager.acquire / manager.send / manager.end_session deprecated compat shims

Test plan

🤖 Generated with Claude Code

Replaces the unfinished REST-based coder integration with an
ACP-driven (Agent Client Protocol over JSON-RPC stdio) layer talking
to a sandboxed OpenCode 1.14.25 container. The cog/PM gets
dispatch_coder as an async tool; agent_coder collapses to a thin
specialist (frame → dispatch → inspect → land); CBR ingest captures
the actual OpenCode tool titles per session.

Layers:

- coder/acp.gleam: JSON-RPC over stdio (open / initialize / session_new /
  session_prompt(_async) / session_cancel / close), pure decoders pinned
  against probed shapes
- coder/manager.gleam: OTP actor — warm container pool, per-dispatch
  driver, three-stage kill chain (ACP cancel → handle close → manager
  teardown), per-task budget enforcement, hourly cost cap, janitor TTL
- coder/ingest.gleam: completed dispatch → CbrCase (CodePattern,
  tools_used = ACP tool titles seen during the session) + raw JSON
  archive in .springdrift/memory/coder/sessions/
- tools/coder_dispatch.gleam: dispatch_coder (async via OTP worker —
  cog stays free), cancel_coder_session, list_coder_sessions; budget
  clamp-and-report against operator ceilings
- tools/coder.gleam: project_status / project_read / project_grep
  host-side tools (verification scaffolding removed; OpenCode runs its
  own tests in-container)
- agents/coder.gleam: single-mode specialist using Group A planner
  tools + project_* + dispatch_coder + builtin
- agent/cognitive*.gleam: PendingCoderDispatch + CoderDispatchComplete
  ride the existing WaitingForAgents accumulator; multiple parallel
  dispatches fold into one rethink

Auto-wire (zero-touch fresh install):

- AppConfig defaults: image=springdrift-coder:1.14.25,
  provider_id=anthropic, model_id=claude-sonnet-4-6
- project_root falls back to cwd at runtime
- Image auto-builds from Containerfile.coder on first boot if missing
- Operator only needs ANTHROPIC_API_KEY in .env

Removed:

- coder/client.gleam (REST wrapper)
- coder/supervisor.gleam (per-task slot lifecycle)
- http_probe_get FFI
- run_tests/run_build/run_format tools (host-side scaffolding)
- coder_start_session/send/end_session tools (replaced by dispatch_coder)
- ProjectCommands type + default_project_commands
- Three-mode coder agent branching (sandbox-only / no-sandbox legacy)
- manager.acquire/send/end_session compat shims

Tests: 2077 passing, build clean, format clean. e2e_test.gleam gated
by SPRINGDRIFT_CODER_E2E=1; scripts/e2e-coder.sh sources .env for all
e2e config.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@seamus-brady seamus-brady merged commit 39538d9 into main Apr 26, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant