OpenCode: a model-routed team, cheap to plan, strong to build
Give each agent its own model so planning and review run on a cheap model and only the build runs on your best one.
Run this workflow
CI-verified, 2/2 fixtures passing.
Build this with your agent
One copy-paste hands Claude Code, Codex, or Cursor the full recipe, steps included, nothing to fetch.
Intended Use
Anyone who wants to route work by difficulty across agents. CI validates that build, plan, and a code-reviewer subagent each pin a provider/model string and that code-reviewer is read-only (edit=deny). No key, no model call. Reviews and builds are fenced. Fill models from `opencode models`.
Not for
- Assuming a subagent is cheap, subagents inherit the caller's model unless you pin their own
- Expecting CI to measure spend, only that each agent pins a provider/model and the reviewer cannot edit
The Stack
Tested Against
opencode@1.17.4opencode.ai/docs (2026-06)node@20.xSide effects & data flow
- Network
- none, local only
- Writes
- ./opencode.json
- Credentials
- none required
Prerequisites
- OpenCode installed
- A provider logged in to actually run it
Steps
- 1
Route models per agent and validate
Pin build to your strong model, plan and a code-reviewer subagent to a cheap one, and deny edit on the reviewer. Invoke the reviewer with @code-reviewer. CI parses opencode.json and asserts each agent names a provider/model and the reviewer is read-only.
cat > opencode.json <<'JSON' { "$schema": "https://opencode.ai/config.json", "agent": { "build": { "mode": "primary", "model": "provider/your-strong-model" }, "plan": { "mode": "primary", "model": "provider/your-cheap-model" }, "code-reviewer": { "description": "Reviews diffs for bugs, security, and performance", "mode": "subagent", "model": "provider/your-cheap-model", "permission": { "edit": "deny" } } } } JSON node -e 'const c=JSON.parse(require("fs").readFileSync("opencode.json","utf8"));const a=c.agent;for(const n of ["build","plan","code-reviewer"]){const m=a[n]&&a[n].model;const parts=m?String(m).split("/"):[];if(parts.length!==2||!parts[0]||!parts[1]){console.log("BAD model for "+n);process.exit(1)}}if(a["code-reviewer"].permission.edit!=="deny"){console.log("BAD: reviewer not read-only");process.exit(1)}console.log("config OK: build/plan/code-reviewer each pin a provider/model, code-reviewer edit=deny")' - 2
Invoke the team (the model step, not checked by CI)
@code-reviewer in a message runs the cheap reviewer; build delegates to it or you Tab between agents. You can bound a quick agent's cost with `steps`. The reviews and builds run models, so CI never claims them.
Eval, 2 fixtures
Last passed: verified todaymodels-routedcontainstimeout 30s · max $0Expected:
config OK: build/plan/code-reviewer each pin a provider/model, code-reviewer edit=denyclean-exitexit_codetimeout 30s · max $0Expected:
0
Results
The biggest cost win in OpenCode: stop paying frontier prices for the parts of the job that do not need them. Watch the effect with `opencode stats --models`.
Did this work for you?
Our CI checks the setup runs. You tell us if the whole thing worked. Tell us straight.
Liked this workflow?
Get new verified workflows in WebAfterAI, three issues a week (Tue, Thu, Sat).