Skip to content

fix: launch OpenCode 2 without the --model flag it no longer accepts - #12

Merged
thymikee merged 3 commits into
mainfrom
fix/opencode-2-run
Oct 15, 2026
Merged

thymikee merged 3 commits into
mainfrom
fix/opencode-2-run

Conversation

@thymikee

@thymikee thymikee commented Oct 14, 2026 •

Copy link
Copy Markdown
Member

Problem

After upgrading to OpenCode 2, apex run opencode fails:

ERROR
  Unrecognized flag: --model in command opencode

OpenCode 2's terminal interface has no --model flag (only run and mini do).

Fix

apex run opencode now checks opencode --version (1.18.34 in v1, opencode v2.0.29 in v2):

  • OpenCode 1: unchanged, opencode --model <provider>/<model>.
  • OpenCode 2: opencode --standalone with OPENCODE_CONFIG_CONTENT='{"model":"<provider>/<model>"}'. If you already set OPENCODE_CONFIG_CONTENT, the model is merged into it. If that value isn't a JSON object, apex stops with an error.
    • --standalone is required. By default OpenCode 2 connects to a shared background service, which never sees the child's environment, so it would ignore both the inline model and the gateway key the config references.
    • OpenCode 2 rejects flags placed before a subcommand, so --standalone follows run and mini (apex run opencode -- run "hi" → opencode run --standalone hi). A directory argument still starts the interface with --standalone, and other subcommands (auth list, models, …) are passed through untouched, since most of them reject the flag.
  • The version is read from a line of its own, so an update notice naming another version isn't mistaken for it. If the version can't be read, apex falls back to the v1 launch.

The init summary shows the matching expansion (opencode --standalone (OPENCODE_CONFIG_CONTENT model set) for v2).

Verification

  • npm test: 66/66 pass, including a new test with a fake opencode that reports v1, v2 or an unreadable version.
  • Checked by hand with the real OpenCode 2.0.29: with --standalone, the inline config model was used (exported session showed openai/gpt-5.5 from OPENCODE_CONFIG_CONTENT). Without --standalone, the background service ignored it. apex run --provider callstack opencode -- run … ran on callstack.ai/callstack/Apex.
  • Checked by hand with the real OpenCode 1.18.34: it still gets --model before the subcommand, which v1 accepts.

OpenCode 2's terminal interface dropped --model, so `apex run opencode`
failed with "Unrecognized flag: --model". apex now reads
`opencode --version`: OpenCode 1 keeps --model; OpenCode 2 starts a
private server with --standalone and gets the model through
OPENCODE_CONFIG_CONTENT (merged into any inline config already set).
The shared background service never sees the child's environment, so
--standalone is what makes both the model and the gateway key reach it.
OpenCode 2 only accepts flags after a subcommand, so they follow one
(`opencode run --standalone ...`). The init summary shows the matching
expansion.
Review follow-ups: --standalone goes to the interface, `run` and `mini`
and is left off other subcommands (`auth list` rejected it). The version
is read from a line of its own, init reuses the binary detect found, the
key check is its own function, and each launch carries its summary note.
The inline config is read with the same JSONC parser as config files, so
a comment or trailing comma OpenCode itself accepts no longer stops the
launch. The v2 env is built in launchOptions like Claude's, the version
plumbing helper is gone, and openCodeMajor answers 1 without a binary.
@thymikee
thymikee merged commit 6ab9ea2 into main Oct 15, 2026
3 checks passed
thymikee pushed a commit that referenced this pull request Oct 20, 2026
…version (#13)

* fix: ask the OpenCode binary for --standalone instead of reading its version

The version probe decided the launch from `--version`, but every dev, beta
and source build of *both* OpenCode generations reports `0.0.0-*` (or
`local`), which the regex never matched, so they all fell back to the v1
launch. Verified against the published `@opencode/cli@beta`:

    $ opencode --version
    opencode v0.0.0-beta-19507       <- probe: no match -> major 1
    $ apex run opencode
    Unrecognized flag: --model in command opencode

The whole preview channel hits the exact error PR #12 exists to prevent,
and `0.0.0-*` cannot be classified by version at all: the old `opencode-ai`
package has published over 11k `0.0.0-*` versions too, so "major 0 means
v2" would just move the bug to v1 dev builds.

Probe the capability instead. `--standalone` exists if and only if the
interface is v2, and `--help` says so on all four real binaries, including
the `0.0.0-*` pair no regex can separate: v1 stable, v1 dev, v2 beta and
v2 stable all answer correctly. v1 writes its help to stderr and v2 to
stdout, so both streams are read.

The probe now answers a tri-state: true (OpenCode 2), false (OpenCode 1),
or null (no answer). It never rejects: execFile can throw synchronously (a
.cmd launcher since CVE-2024-27980) and a failed or timed-out --help is no
answer either. On null, `apex run` adds neither --model nor --standalone,
so the assistant still starts on the user's own config, and says so on
stderr rather than guessing a generation and dying on its flag; the init
summary admits the same instead of blindly showing the v1 expansion.

Also scrub OPENCODE_CONFIG_CONTENT in the test fixture: it reached launched
fakes from the developer's shell, the same leak #11 closed for gateway keys.

Docs-only inaccuracies PR #12 merged (the "flags only follow a subcommand"
comment, the `auth list` example) are untouched here and tracked as F6.

* refactor: simplify the probe and its messages per the review of this PR

The fanout review found no bugs; these are its confirmed findings.

- openCodeSupportsStandalone becomes a short async function over
  promisify(execFile): one try/catch covers the callback's error branch
  and what execFile throws synchronously (D2).
- A failing or timed-out --help that printed --standalone is an answer
  after all; the captured streams on the error are read instead of
  thrown away (D1).
- launchOptions owns the unknown-probe sentence as `warning` and says
  "interface", not "version"; commandRun prints it instead of writing
  its own wording of the same state (D6, D9).
- The init summary drops the note when no binary was found: nothing was
  asked, so nothing is unknown (D5).
- runExpansion joins the command tokens instead of repairing a trailing
  space with trimEnd() (D10).
- Tests: the synchronous-throw case uses a path that actually reaches
  execFile (a NUL byte); the probe asserts a failed --help with and
  without the flag in its output; the CLI fake sheds the --version
  plumbing Apex no longer reads and the stderr cases the probe unit
  test already covers (D3, D8).

* chore: tighten comments around the OpenCode probe
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