05f96631295d442e14e02be25b404465b37feaf8
The verdict reader matched from the first { to the last } in the whole
reply, so a fenced JSON verdict followed by prose containing a } failed
to parse, counted as FAIL and triggered a rewrite (SAFETY-129, T192).
- Read a ```json fenced block first, then the first balanced {...} that
parses and has a PASS or FAIL verdict. Braces inside strings are
ignored.
- An unreadable reply is re-asked once for the JSON only. Still
unreadable: NOT VERIFIED, "verdict unreadable", handed back to the
manager with the start of the first reply. No fail counted, no
resume, no rewrite.
- 10 new tests; each new rule was also broken on purpose and caught.
Version 0.4.5.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MdqPWvuDpbpRvDEdURoAwo
model-router
A Claude Code plugin that picks a model for every subagent, checks dev work on a second model before it reaches a PR, and estimates what that saved compared with running everything on Opus.
What it does
| Step | Behaviour |
|---|---|
| Route | Dev agents run on Sonnet when the brief decides the approach (Expected / acceptance criteria), on Opus when the design is still open. Review and test agents keep the model they are given (Opus when none). |
| Verify | When a dev agent below Opus finishes a round, the router diffs its clone against the merge base, runs the test command in that clone, and has Opus judge the change. |
| On FAIL | 1st: resume the same agent with the issues. 2nd: a new agent one model up, in the same clone. After that: handed back to the manager. |
| Not verified | A test timeout, a test command that cannot run, a missing clone or merge base, or a verdict that cannot be read even after asking once more: reported as NOT VERIFIED, never as a FAIL. |
| Savings | /router savings prices every run on the model it ran on and compares it with the same tokens on Opus 5.5. |
Briefs
Every dev, review and test brief carries one line:
Clone: /home/homelab/projects/goodwe/clones/<TICKET>-dev/
Add (Role: dev|review|test) when the path does not end in the role. Tickets with extra parts (OPT-11-P4) are fine. Name the base branch (Base branch: release/1.0).
Install
/plugin marketplace add <this repo's git URL>
/plugin install model-router@model-router
Or for development: claude --plugin-dir /path/to/model-router.
Settings (/config)
| Setting | Default | Notes |
|---|---|---|
testCommand |
empty | Run in the agent's clone; output goes to the verifier |
testTimeoutSec |
1800 | Wrapped in GNU timeout --verbose; a timeout is NOT VERIFIED |
defaultBaseBranch |
release/1.0 |
After the PR lookup and the brief's own base branch |
prBaseCommand |
empty | Optional command that prints the PR's base branch |
maxRewrites |
2 | Failed verdicts before handing back |
safetyPatterns |
control loop, rs485, ... | Marks tasks as critical in the log |
respectExplicitModel |
false | Keep a named model on agents without a role |
allowFable |
false | Rewrite on Fable after Opus fails |
prices |
empty | JSON price overrides, USD per MTok |
Commands
/router: recent decisions, verdicts and savings/router savings [Tn]: the full savings table, or one task/router clear: reset log, records and costs
Tests
claude plugin validate .
claude plugin test .
54 tests. Every routing, verification, cost and timeout rule was also checked by breaking it on purpose (66 mutations in v0.4.4, plus 13 for the verdict reader in v0.4.5; all caught by a test).
Known limits
- Savings are an upper bound: Opus may need fewer tokens than the cheaper model did.
timeoutstops thedockerclient, not the container: name the container and remove it in atrapin the test command.- An Opus rewrite is not verified; the PR review covers it.
Languages
TypeScript
100%