Skip to content

feat: opencode, gemini cli and cursor agent run structured too, through the agent client protocol - #80

Merged
sean-brydon merged 1 commit into
codex-driverfrom
acp-driver
Oct 13, 2026
Merged

sean-brydon merged 1 commit into
codex-driverfrom
acp-driver

Conversation

@sean-brydon

Copy link
Copy Markdown
Collaborator

Stacked on #79 (base codex-driver), which is stacked on #78. Merge in order: #78, #79, then this one. GitHub retargets each to main as the one below merges.

Phase 6 of design/structured-agents/plan.md: a generic ACP driver, behind the same Labs switch (Structured agents).

Driver (internal/box/acpdriver.go, capability driver.acp)

  • Which agents: any agent whose preset has the new acp field, meaning what follows its command to start its ACP server. Built-ins:

    • opencode acp
    • gemini --acp (--experimental-acp is deprecated)
    • cursor-agent acp (works, but isn't in its --help)

    A repo's .berth/config.json can give its own agent one, or add one to a built-in by id. That makes the driver config-driven.

  • Opening a session:

    • initialize, then session/resume when the agent advertises it, session/load when it can load, else session/new
    • authenticate with the advertised method when the agent says auth is required (Cursor Agent, which uses its existing login)
    • the conversation's model goes through session/set_config_option, and a non-bypass mode is set the same way
  • Turns: session/prompt is written without waiting, because its answer is the turn's end (stopReason: end_turn, or cancelled → interrupted, or an error → error). Stop is session/cancel.

  • Modes: the agent's own (its mode config option, or modes with session/set_mode), plus bypassPermissions, where berthd answers.

  • Permissions: session/request_permission gives ask.choices, picked by option kind (allow_once, allow_always, reject_once), because ids differ per agent (opencode once, Cursor allow-once). opencode allows everything unless told otherwise, so it starts with OPENCODE_CONFIG_CONTENT asking for bash, edit and webfetch, and bypass is berthd answering.

  • Anything else the agent asks (fs/*, terminal/*, cursor/create_plan) gets a JSON-RPC error. berthd advertises neither fs nor terminal, so agents use their own tools.

  • Conversation (internal/transcript/acphost.go):

    • prompts from berthd's session/prompt
    • reply chunks gathered into one item at the next event or the turn's end
    • tool calls as steps by kind, with labels updated once the agent says what it runs (conv.retitle)
    • updates replayed by session/load are skipped, because they're already in the log
  • Resume and the conversation list (feat: a structured claude agent's conversation can be resumed, after its agent ends or its session is gone #78) work for ACP conversations: relaunch picks the preset from meta.json.

App

startWork passes driver: "acp" for a pick whose preset has acp, on boxes listing driver.acp. With Ask it starts in the agent's own default mode. These sessions open as conversations. The Labs text names the agents. Also covered: config reference (acp), Labs guide, app API and changelog.

Tests

  • TestAStructuredACPSessionIsDrivenThroughItsProtocol, with a stand-in agent (python3) following the recorded opencode and Cursor messages:
    • authenticate-then-retry
    • the session id reaches the ledger
    • its build/plan modes plus bypass, with a plan-mode turn
    • a permission refused by kind, with the command shown as a step
    • bypass allowing it
    • draft then cancel
    • stop and resume onto the same session id via session/resume
  • All structured tests passed 4/4 under -race.
  • TestAStructuredACPSessionsLogReadsAsItsConversation uses a recorded, anonymised opencode log.
  • TestALiveACPSessionWorks (opt-in BERTH_LIVE_ACP=<preset>, BERTH_LIVE_ACP_MODEL) passed locally against real opencode (opencode/big-pickle, 5.5s) and real Cursor Agent (13.6s, through its authenticate step). Gemini wasn't run because it isn't logged in here.
  • Full go test -race ./..., go vet ./..., app checks and build, tsc -p e2e and the docs build all pass.

That completes phases 0–6. What's left is phase 7 (flows and headless runs onto the drivers) and phase 8 (turning it on by default).

🤖 Generated with Claude Code

…gh the agent client protocol

A generic ACP driver (internal/box/acpdriver.go) runs any agent whose
preset says how it speaks the Agent Client Protocol (AgentPreset.ACP:
opencode "acp", gemini "--acp", cursor-agent "acp"; a repository's own
agent can have one) under `berthd agent-host`:

- it opens the session: initialize, then session/resume or session/load
  with the conversation's id when it is carried on, else session/new,
  calling authenticate first when the agent asks for it (Cursor Agent)
- prompts are session/prompt, whose answer is the turn's end; Stop is
  session/cancel
- the agent's own modes (its mode config option, or session/set_mode)
  are offered with bypass beside them
- permission requests come to the chat as Allow / Always allow / Deny,
  picked by option kind since each agent names them its own way; bypass
  has berthd allow them, and opencode is started asking so that it does
- what else it asks of its client gets an error; streamed chunks make the
  draft and, gathered, the reply in the conversation
  (internal/transcript/acphost.go), with a tool's label updated once the
  agent says what it runs

Boxes list driver.acp; sessions and tasks take driver: "acp". The Labs
switch starts these agents structured too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@vercel

vercel Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
berth Ready Ready Preview Oct 13, 2026 1:22pm UTC
berth-docs Ready Ready Preview Oct 13, 2026 1:22pm UTC

Request Review

@sean-brydon
sean-brydon merged commit 8dcb896 into codex-driver Oct 13, 2026
7 of 8 checks passed
@linear-code

linear-code Bot commented Oct 13, 2026

Copy link
Copy Markdown

ENG-6008

sean-brydon added a commit that referenced this pull request Oct 13, 2026
feat: structured codex and acp agents (lands #79 and #80 on main)

This branch was successfully deployed

2 active deployments
Preview – berth-docs — d7f96d59 Deployed Oct 13, 2026 by vercel[bot]
Preview – berth — d7f96d59 Deployed Oct 13, 2026 by vercel[bot]
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