Files
cleveragents-core/.opencode/models/README.md
T
drew 6178be3aa7 feat(models): single-source model registry via models.yaml + sync_models.py
.opencode/models/models.yaml is now the ONE file humans edit to assign a
model to an agent. tools/sync_models.py regenerates every derived surface
— the .opencode/models/*.txt files, opencode.json's `agent` block, and
each non-tier agent's .md `model:` frontmatter — so an assignment cannot
drift across surfaces. `--check` verifies with no writes and is enforced
in CI by test_model_registry_in_sync_with_manifest.

Hardened after adversarial review:
- Deletes orphan <agent>.txt files left behind when an override is
  dropped from the manifest. The dispatcher's resolver reads
  <agent>.txt before default.txt, so a stale file would silently pin
  the old model. Tier .txt files are left to sync_tier_models.py.
- Rejects a manifest key that does not name a real agent (no matching
  .opencode/agents/<name>.md) instead of silently appending a bogus
  opencode.json entry and leaving the real agent on the default model.
- Validates the regenerated opencode.json BEFORE writing it, so a bad
  render aborts cleanly instead of corrupting the file on disk.

Tier-ladder agents (task-implementor-tier-*) remain governed separately
by tiers.yaml + sync_tier_models.py and are passed through untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 07:33:18 -04:00

3.2 KiB

.opencode/models/ — Model registry

Single source of truth: models.yaml

models.yaml is the ONE file you edit to assign an LLM model to an agent. Every other model-bearing surface is generated from it by tools/sync_models.py — do not hand-edit the generated artifacts; the next sync overwrites them.

# models.yaml
default: local-claude/claude-haiku-4-5
agents:
  conflict-resolver-worker: local-claude/claude-opus-4-6
  estimator-implementation: local-claude/claude-sonnet-4-6
  # ... only agents needing a NON-default model appear here

tools/sync_models.py regenerates, from models.yaml:

Generated artifact Consumed by
.opencode/models/<agent>.txt, default.txt the dispatcher's _opencode_worker._resolve_role_model
opencode.jsonagent.<name>.model OpenCode's static agent registry
model: frontmatter in .opencode/agents/<agent>.md OpenCode's per-agent config

Both OpenCode-facing surfaces (the opencode.json block and the .md frontmatter) are written, because which one OpenCode honours has varied across versions — writing both makes the assignment correct regardless. Since all of them derive from the one manifest, they cannot disagree.

Swapping a model

  1. Edit models.yaml.
  2. Apply it — either:
    • relaunch the controller pipeline — tools/run-controller-state-machine-pipeline.sh runs sync_models.py automatically at startup (before OpenCode boots); or
    • run python3 tools/sync_models.py by hand.
  3. Restart OpenCode — it caches its config at process start, so a running server keeps the old model until restarted. (The pipeline launcher restarts OpenCode for you.)

Verify with no writes — python3 tools/sync_models.py --check exits 1 on any drift between models.yaml and the generated artifacts (suitable for CI or a pre-launch gate).

Tier-ladder agents — tiers.yaml

The task-implementor-tier-* agents are governed separately by tiers.yaml + tools/sync_tier_models.py (the escalation ladder has its own manifest, generator, and drift test). sync_models.py passes their opencode.json entries through untouched and never edits their .md files. To change a tier model, edit tiers.yaml and run tools/sync_tier_models.py.

Inheriting agents

task-implementor and agent-evolution-pool-supervisor have no opencode.json agent entry and no model: line — they deliberately inherit their caller's model. sync_models.py does not touch them.

File reference

File Role
models.yaml Source of truth — per-agent model assignment (hand-edited)
tiers.yaml Source of truth for the tier ladder (hand-edited)
<agent>.txt, default.txt Generated by sync_models.py
README.md This file

Every model id is providerID/modelID; the provider must be declared in opencode.json's provider block — sync_models.py validates this and aborts on an unknown provider.

See also