Repository navigation
feat(runner): drive opencode accounts through opencode serve - #216
Conversation
Quest-Claim: 91eed9ed7411e89d
A runner now offers opencode accounts alongside Claude Code ones, covering OpenCode Go, ChatGPT plans, and API-key providers. Each account signs in with `opencode auth login` in its own XDG home; each turn runs `opencode serve` on localhost behind a fresh password inside the job's devShell and drives one session through the SDK, with the kix tools as a remote MCP server and opencode's question tool denied. Limits abort the turn and pause the account. The flake pins opencode for the runner and checks the SDK matches it. Completes quest/m0/kix/opencode.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b2dfa2340e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…count model Provider credentials in the runner's environment could outrank the account's own sign-in, and a project's opencode.json could override the account's --model. Strip credential-named variables from opencode's environment, and pass the account's model in the launch config, which loads after project config. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Landing summaryLands 705a68e as a squash merge. It completes Since the last review round
Decisions (maintainer)
Follow-ups
(Written by Claude Opus 5.5) |
Resolves the opencode adapter (#216) against the job sandbox: opencode now enters the devShell the runner built from the job's revision, through the sandbox's env script, instead of `nix develop` on the checkout. Its commands are not yet confined; wrapping `opencode serve` in sandbox-runtime stays in quest/m0/kix/sandbox.md, which takes over the note from the deleted opencode quest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Completes
quest/m0/kix/opencode.md: a runner now offers opencode accounts alongside Claude Code ones, so jobs can run on an OpenCode Go plan, a ChatGPT plan, or an API key for any provider opencode supports.Behavior
quest runner account add opencode [--model provider/model]runsopencode auth loginin a new account home. That home has its own XDG config, data, cache, and state directories. The account's kind and label come from the providers in that home'sauth.json. Only provider IDs and credential types are read, never the credentials. An OAuth login or OpenCode Go counts as asubscription; anything else is anapi-key. Examples:ChatGPT (opencode)andOpenCode Go (opencode).opencode serveinside the job's devShell. It listens on127.0.0.1on a random port, behind a password made for that turn. The runner drives it through@opencode-ai/sdkv2: it creates or resumes a session, sends one synchronous prompt with the kix system prompt, and streams the session's SSE events as raw output (token deltas are skipped).bypassPermissions). opencode's ownquestiontool is denied, so every question goes through kix'sask. If a project's own rules still ask for a permission, the runner allows it; a strayquestion.askedis rejected.kix-sessions/. Cancel and stop abort the session, then end the server's process group.account_rate_limitretry, a free-tier retry, or a retry whose message names a usage or quota limit makes the runner abort and reportlimited(untilnextfor OpenCode Go). opencode would otherwise sleep until the reset. A finalAPIErrorwith a usage or quota message is also a limit. The reset time comes fromresets_atorresets_in_secondsin the body, or fromretry-after. Brief "rate limit reached" retries are left to opencode.runnerpackage pins opencode next to Claude Code throughQUEST_RUNNER_OPENCODE. A newopencode-sdkflake check keeps@opencode-ai/sdkinpackage.jsonon the same release as the pinnedpkgs.opencode, now 1.19.0 after merging main's nixpkgs bump.Adapterinterface now covers both CLIs.SignedIncarries the provider, andAccount.provideris what goes to kix. The kix service is unchanged.Choices made without asking
/usr/bin/envinside the devShell, sonix developstill reads the user'snix.conf. A small per-launch opencode plugin (ashell.envhook) gives the agent's commands the user's XDG directories back. A devShell that sets its ownXDG_*values does not get them back in agent commands.enabled_providersis limited to the account's own credentials, so opencode's free Zen models and other providers never leak into an account. opencode's environment also dropsOPENCODE_*and credential-named variables (*_API_KEY,*_API_TOKEN,*_AUTH_TOKEN, AWS-style access and session keys,*BEARER_TOKEN*), because some providers prefer an environment key over the stored one. This matches by name, so it is best effort.--modelis added. It is stored in the account's ownopencode.jsonand passed in each launch's config, so it outranks a project'sopencode.json. Without it, the project's choice or opencode's default applies.quest runner account add [cli]takes a positional argument (claudeby default).--consoleis for Claude Code only, and--modelis for opencode only.provideris the first signed-in provider ID, cleaned up to match kix's ID rules.opencode-sdkflake check fails when the nixpkgs pin moves opencode and the SDK does not move with it, as the bump merged from main did. That keeps the server and client on one release, but a Dependabot nix or bun bump will need a paired bump. Dropping the check is the alternative.Validation
just checkandjust testpass after merging main.test/runner.test.ts:opencode servedrives the real runner through a checkpoint, a question, and a resume in the same session. The test checks the password, the MCP bearer header,enabled_providers, the question deny, and the XDG split.limitedwith its reset.account add opencodewith--model.opencode, both 1.18.34 and 1.19.0, and the freeopencode/big-picklemodel. It covered a shell command ($XDG_CONFIG_HOMEcame back as the user's), akix_checkpointMCP call, a resumed session that remembered the first turn, and a stop that aborted asleep 60in about 8 seconds.Not verified here
Signing in to real OpenCode Go and ChatGPT plans and hitting their limits needs real accounts. The kix epic's live rehearsal now lists these checks, including whether ChatGPT plans fall short enough to plan a separate Codex adapter.
Follow-ups
src/runner/claude.ts. Whichever PR merges second resolves the conflict. The sandbox should wrapopencode servetoo, using sandbox-runtime, and check how much of the account home the agent's commands can read. They can still readOPENCODE_SERVER_PASSWORDand the per-turn MCP token, as they can read Claude Code's MCP config today.LIMITinsrc/runner/opencode.ts.🤖 Generated with Claude Code
(Written by Claude Opus 5.5)