Development record
A runner takes one model per machine, so a model matrix cannot be configured: internal/core/runner/config.go keeps a single Model per enabled runner, readable only from the machine layer, and roles name runners rather than models. Building one intent with several opencode-served models, or reviewing it with several runner-served reviewers, would mean rewriting the person's machine file between copies, and two copies could never run at once. itd-2610161733316518 needs it.
A runner takes one model per machine, so a model matrix cannot be configured: internal/core/runner/config.go keeps a single Model per enabled runner, readable only from the machine layer, and roles name runners rather than models. Building one intent with several opencode-served models, or reviewing it with several runner-served reviewers, would mean rewriting the person's machine file between copies, and two copies could never run at once. itd-2610161733316518 needs it.
The grammar chosen (2026-10-17)
The override keeps one flag and one parser and gains a runner rung:
--route <role>=runner:<name>[@<provider>/<model>]. The runner: prefix marks
the rung, and no tier is spelt with a colon, so every route the tier rung
admitted reads as it did. @ keeps its meaning of where the model comes from:
a provider connection on the tier rung, a provider's model on the runner rung.
Without @ the runner keeps its machine model. Three alternatives were
rejected. A bare runner name in the tier's place (implementer=opencode@...)
puts a runner and a tier in one slot with nothing to tell them apart. The runner
in the connection's place (implementer=frontier@runner:opencode/...) needs a
tier that chooses nothing. A separate --runner flag is the second override the
remedy rules out. Runners are dispatched only by the build loop's step today, so
the rung is honoured on abcd implement step; a delegating verb, which sends its
agent to the harness or a provider, refuses it, and the step refuses a tier route.
Frontmatter
| id | iss-2610161801358637 |
|---|---|
| type | issue |
| lifecycle | resolved |
| severity | minor |
.abcd/work/issues/resolved/iss-2610161801358637-a-runner-takes-one-model-per-machine-so.md
open on GitHub ↗ · commit history ↗
References1
- itd-2610161733316518One task done across a model matrix, re-runnablyrelated
mentions3
- dcn-26102221552385152026-10-22 — Decided by the technical facilitator on delegation (coordinator ruling, 2026-10-22): an explicit implement step --route that names the claude runner for a model the machine pins, given in the flag or as claude's own model, is refused before anything is written (exit 2), naming runner.opencode.model as the route that holds a pin. This matches how --route already refuses every condition the configuration shows it cannot run (a runner the machine does not enable, a model its provider does not list, a tier route), and keeps the person's explicit request from being handed to the host behind their back. A machine route to claude for a pinned model, which nobody asked for on that step, keeps claude's launch-time refusal and the recorded fallback to the host (iss-2610161801358637).
- dcn-26102807431601342026-10-28 — Route-runner-model r2 (iss-2610161801358637), rebased onto local-pin-r2: a route record's override joins run-state version 16 with a route's pins, and drain-state version 2 with a judge route's pins, rather than taking version 17. Grounds: r2 already joined the override to the pins' version while neither was released, version 16 is still unreleased (local-pin-r2 lands just before r2), and a version holds the unreleased additions that land together; a file of version 15 or lower carrying override is refused, as before. If a release writes version 16 before r2 lands, r2 moves the override to version 17 before it lands.
- spc-2610161949559050a-product-thinker-who-wants-to-know