Skip to content

Fix or retire opencode as a builder harness (broken launch on opencode 1.x + no render-gate profile) #1339

Description

@mohidmakhdoomi

Summary

opencode is a registered builder harness but is broken end-to-end. A builder configured with
shell.builder: "opencode" launches, immediately exits 0, and shows the relaunch screen
("Agent exited at your request. Press Enter to relaunch, or close this terminal.") — so it never
actually runs. This issue is to either fix opencode as a builder or retire it (sibling of #1338,
"Retire Gemini CLI as a builder harness"). Original support was added in #178 (closed).

Surfaced during manual testing of Spec 1313 (afx send mailbox delivery).

Reproduction

// .codev/config.local.json
{ "shell": { "builder": "opencode" } }
afx spawn --task "I am testing, please sit idle."

Observed: the new task builder instantly prints
Agent exited at your request. Press Enter to relaunch, or close this terminal. and never starts.

Root cause — CLI-contract drift (verified)

The builder launch script (packages/codev/src/agent-farm/commands/spawn-worktree.ts:875) passes the
initial prompt as a positional argument — the claude/codex convention:

# .builder-start.sh (generated)
opencode  "$(cat '/…/.builders/task-XXXX/.builder-prompt.txt')"

OPENCODE_HARNESS.buildScriptRoleInjection returns an empty fragment (opencode's role injection is
file-based via the opencode.json it writes — { "instructions": [".builder-role.md"] }), so the prompt
falls through to Codev's generic positional form.

But opencode 1.18.11's positional slot is a project path, not a prompt:

opencode [project]        start opencode tui                       [default]
opencode run [message..]  run opencode with a message
Positionals:
  project  path to start opencode in                               [string]
Options:
  --prompt  prompt to use                                          [string]

So opencode tries to cd into a directory named after the entire prompt text, fails, and exits 0.
Confirmed directly:

$ opencode "You are a Builder. Read codev/roles/builder.md for your full role definition."
Error: Failed to change directory to <cwd>/You are a Builder. Read codev/roles/builder.md…
EXIT=0

The launch loop treats exit 0 as a clean/user-requested exit → the relaunch screen. This is the
worst failure mode: it looks like a healthy idle builder, not an error. The OPENCODE_HARNESS was
written against an older opencode CLI (a bare positional was an initial prompt); opencode's CLI has since
moved prompts to opencode run "<msg>" (headless) or opencode --prompt "<msg>" (TUI with initial prompt).

Secondary gap — no render-gate profile (Spec 1313)

Even if the launch were fixed, afx send to an opencode builder would always hold no-profile:
PROFILES_BY_HARNESS in packages/codev/src/agent-farm/servers/gate-profiles.ts is { claude, codex }
only (agy is matched directly). detectHarnessFromCommand recognizes opencode, but it isn't in the
profile registry, so resolveProfile returns nullno-profile. A working opencode builder would
therefore be undeliverable-to until an opencode gate profile is measured and added.

Decision: fix or retire

Option A — Fix opencode as a builder

  1. Correct the launch invocation. Deliver the prompt via opencode --prompt "<prompt>" (TUI with an
    initial prompt) instead of the positional slot. This needs a harness-level "prompt delivery form" seam
    (today the generic script appends "$(cat prompt)" positionally for every harness) or an
    opencode-specific launch template.
  2. Add an opencode render-gate profile to gate-profiles.ts (marker glyph, region-end patterns,
    placeholder intensity/color rule) — empirically measured like claude/codex/agy — so afx send can
    deliver instead of holding no-profile.
  3. Verify file-based role injection (opencode.json instructions: [".builder-role.md"]) is still
    honored by current opencode.
  4. Verify resume / context-reset (harness.session, supportsContextReset) against opencode's
    --continue / --session.
  5. Guard against CLI drift — a version-bump smoke test that a spawned opencode builder actually reaches
    an interactive prompt with the role + task applied.

Option B — Retire opencode as a builder (mirrors #1338)

  1. Remove OPENCODE_HARNESS from BUILTIN_HARNESSES and the opencode branch from
    detectHarnessFromCommand (packages/codev/src/agent-farm/utils/harness.ts).
  2. Make shell.builder: "opencode" fail fast at spawn with a clear "unsupported harness" error
    instead of silently launching a broken relaunch loop. (Related: Harden harness resolution: unrecognized override command defaults to claude harness (residual --resume crash-loop) #1062 — an unrecognized command
    falls back to the claude harness; opencode is currently recognized, so it launches with the wrong
    invocation rather than falling back.)
  3. Remove opencode from any docs / config references; annotate Support opencode as an alternative to Claude Code #178 as reverted.

Acceptance criteria

  • A decision is recorded (fix vs retire), and one of the two is implemented and verified live — not
    just unit-green:
    • Fix: afx spawn --task "…" with shell.builder: "opencode" reaches a working interactive
      opencode builder with the role + task applied, and afx send to it delivers (not no-profile).
    • Retire: shell.builder: "opencode" is rejected at spawn with a helpful error; no silent
      relaunch loop; no dangling opencode harness references in code or docs.
  • The silent exit-0 "Agent exited at your request" loop is gone in both outcomes.

Related

Environment

  • opencode 1.18.11 (/home/user/.opencode/bin/opencode)
  • Found on the Spec 1313 builder branch (builder/spir-1313) during manual testing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/towerArea: Tower server / agent farm CLI

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions