Files
cleveragents-core/.opencode/models
drew 132a5a2269 feat(auto-agents): centralise model registry under .opencode/models with session-create model stamp
Every agent's model assignment now lives in a single-line text file at
.opencode/models/<name>.txt; default.txt is the 27-agent catch-all.
opencode.json's agent.<name>.model uses
{file:./.opencode/models/<name>.txt} interpolation, and
tools/_opencode_worker.py reads the same files at session-create to
stamp the resolved model on the session record (observability + drift
sentinel; OpenCode does NOT propagate session-level model to
prompt_async — schema for that is undocumented and deferred to Stage
2). 39 .md frontmatter `model:` lines stripped; the two intentional
inheritors (task-implementor, agent-evolution-pool-supervisor) keep
their model-less frontmatter.

Operator workflow for swapping a model is now: edit
.opencode/models/<role>.txt, restart OpenCode so opencode.json's
{file:...} re-resolves, run the dispatcher. Live-swap without restart
was attempted (override on prompt_async); OpenCode 0.x silently
dropped those requests (200 OK, no assistant message) and the
prompt_async override was reverted. The session-create override
remains for observability + drift detection.

End-to-end validation (2026-05-10): dispatch_review.py on PR #25 with
default.txt=openai/gpt-5-mini produced a clean REQUEST_CHANGES review
in 26 s for ~$0.016; dispatch_implementer.py on PR #30 with
tier-qwen-* files remapped to openai/{gpt-5-nano, gpt-5-mini,
gpt-5-codex} ran the full implementation-worker → tier-dispatcher →
estimator-implementation → tier-qwen-med → task-implementor →
git-isolator-util chain in 16 min with model=gpt-5-mini end-to-end.

Also documents the printenv VAR form as the only allowed env-read in
implementation-worker.md and task-implementor.md (live testing
showed the worker burning 2–4 turns on permission-denied
trial-and-error trying printf and echo variants).

Tests: 21 in tests/auto_agents/test_opencode_worker_models.py
(resolver semantics with caplog assertions on every malformed-input
path; session-create body shape; prompt_async body never carries
model; three repo-level invariants — every {file:...} reference
resolves, every .md is wired or in the inheritor allowlist, no .md
has a model: frontmatter). 1027 auto_agents tests pass / 3 skipped.

Note: .opencode/models/default.txt and the three tier-qwen-*.txt
files are committed with their OpenAI swaps in place (gpt-5-mini,
gpt-5-nano, gpt-5-mini, gpt-5-codex respectively) because the
CleverThis HuggingFace endpoints are paused. Revert with `git diff
HEAD~1 -- .opencode/models/*.txt | git apply -R` if/when they come
back.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-10 17:23:06 -04:00
..

.opencode/models/ — Model registry

Each <name>.txt file in this directory contains exactly one model id (e.g. anthropic/claude-haiku-4-5), with no surrounding whitespace except a single trailing newline. These files are the single source of truth for which model each agent uses.

How agents pick their model

Two paths read from this directory; both honour the same convention.

Runtime (dispatcher path)

tools/_opencode_worker.py resolves a model for an agent by:

  1. Looking for .opencode/models/<agent-name>.txt.
  2. If absent, falling back to .opencode/models/default.txt.
  3. Parsing the single line as providerID/modelID and passing it as the model field on POST /session and POST /session/{id}/prompt_async.

This is the path used by dispatch_review.py, dispatch_implementer.py, conflict_drive.py, and any other code that calls _opencode_worker.run_session_blocking. Changes to a .txt file take effect on the next dispatched session — no OpenCode restart needed.

Static (OpenCode config path)

opencode.json declares an agent.<name>.model for every agent that has an explicit assignment, using {file:./.opencode/models/<name>.txt} so OpenCode reads the same file at config-load time. This covers interactive sessions and any Task-tool subagent invocations that bypass the dispatcher API override.

OpenCode caches its agent registry at process start, so static-path changes require a server restart (pkill -f 'opencode serve' then re-launch).

How to swap a model

# Switch the worker fleet from Qwen to Sonnet for the next dispatch
echo "anthropic/claude-sonnet-4-6" > .opencode/models/default.txt
python3 tools/dispatch_implementer.py --once

The dispatcher reads .opencode/models/default.txt fresh on every POST /session, so the next cycle picks up the change immediately. No restart, no /config/reload, no env-var juggling. Interactive sessions spawned through OpenCode directly will keep the previous model until the server is restarted.

Inventory

Role file Agents that resolve to it
default.txt All agents that don't have a name-matched file (27 agents today: pr-review-worker, implementation-worker, auto-agents, supervisor, every git-*-util, every session-health-*-util, work-group-util, async-agent-util, tier-dispatcher, estimator-implementation, conflict-resolver-worker, pr-merge-worker, pr-merge-supervisor)
tier-qwen-small.txt tier-qwen-small
tier-qwen-med.txt tier-qwen-med
tier-qwen-large.txt tier-qwen-large
tier-kimi.txt tier-kimi
tier-haiku.txt tier-haiku
tier-sonnet.txt tier-sonnet
tier-opus.txt tier-opus
tier-codex.txt tier-codex
tier-gpt5-mini.txt tier-gpt5-mini
tier-gpt5-nano.txt tier-gpt5-nano
tier-o4-mini.txt tier-o4-mini
ca-test-infra-improver.txt ca-test-infra-improver

Agents that deliberately inherit from their caller (no model: line, no override file): task-implementor, agent-evolution-pool-supervisor.

File format

  • Exactly one line per file (the model id).
  • Trailing newline is stripped by the resolver and by OpenCode's {file:...} interpolation. Do not put anything else in these files (no comments, no blank lines, no extra whitespace).
  • The model id must be valid providerID/modelID syntax (e.g. CleverThis-15/Qwen3-6-35B-A3B-GGUF-UD-Q3-K-XL, anthropic/claude-sonnet-4-6). The provider id must already be declared in opencode.json's provider block.

See also