Plain composer prompts with no route in force get a turn-scoped effort from $.model.classify (design/analysis/coding/bookkeeping/chat → phase effort, effort only, never the model). Bounded by a 3 s clock race, a user interrupt neither counts nor writes, three failures in a row pause it for cooldownMinutes (one toast, status marker, cleared by /route reload). No dialog, no routing.json write on a classified route. New Config key `classify` (default on, pickSwitch), `/route classify on|off` session toggle, `/route show` line and argumentHint. An explicit user /effort beats the guess (engineBase check). Docs: README classifier paragraph, USAGE row + sentence, CHANGELOG, effort-shift.md. Kit suite 428 tests.
66 lines
3.2 KiB
Markdown
66 lines
3.2 KiB
Markdown
# Route doctrine — phase-level model and effort on the main loop (BDR-107)
|
|
|
|
Shared include, companion of `lib/model-gate.md`: the gate fixes WHICH model
|
|
reflects, the model-router mod (`mods/model-router`) fixes HOW HARD each
|
|
phase thinks. Rungs: low (fix a line, run a script) · medium (day-to-day) ·
|
|
high (refactor, resisting bug) · xhigh (architecture, audit before
|
|
validation) · max (stuck error, judged need).
|
|
|
|
## The tool
|
|
|
|
`mcp__model-router__route` (params `phase` | `effort` | `clear`). It is a
|
|
deferred tool: when not loaded, run
|
|
`ToolSearch("select:mcp__model-router__route")` once per session. A route
|
|
applies from the next request on, paired with
|
|
another tool call or not (pairing only saves a request). The answer always
|
|
names the id and effort main runs on. A skill with a row routes itself on
|
|
load; a skill without one changes nothing, the last ROWED skill wins.
|
|
|
|
## Wiring points
|
|
|
|
1. Dispatch span starts → `route(phase="orchestrate")`, sent with the
|
|
dispatch.
|
|
2. Reflection resumes (challenge synthesis, verdict, plan revision) →
|
|
`route(phase="reflect")` or `"plan"` per the skill's own level; the line
|
|
before every `lib/challenge-plan.md` call.
|
|
3. Bookkeeping tail (memory commit, doc commit) → `route(phase="apply")`.
|
|
4. Escalation → `route(phase="escalate")`: verify-secure loop caps and
|
|
ship-feature STEP 4b. Not automatic: the challenge fail-safe and "gone
|
|
WRONG → STOP"; their STOP text names the levers below.
|
|
5. Built-in judgment dispatch (`general-purpose` `model="opus"`, `model:
|
|
"fable"` skill-runners) → explicit `effort=` on the Agent call (`xhigh`
|
|
for opus reviewers, `high` for fable runners). A main route never
|
|
reaches a child. Typed agents run on their row, never on a shift.
|
|
6. After a prose gate that ends the turn, the resumed reflection phase
|
|
starts with its own route call.
|
|
|
|
## Run slot and levers
|
|
|
|
A best-tier skill row survives the end of the turn (a run spans prose
|
|
gates); `/route clear`, `/route off` and a user `/model` drop it. Levers for a
|
|
relaunch: `ultrathink` in the prompt (turn floor) or `/route effort=max`
|
|
(sticky, `/route clear` after).
|
|
Builtin `/effort` is NOT a lever inside a run: rows and routes outrank it.
|
|
|
|
## Limits
|
|
|
|
- A skill typed while a background agent is live routes only through the
|
|
typed marker (unverified live 2026-10-10).
|
|
- Headless (`-p`, SDK) runs the hooks, so routing works there too.
|
|
- A plain typed prompt with no route in force gets its turn effort from a
|
|
small-model classifier (effort only; `/route classify off`; never `-p`).
|
|
- Mod off: typed agents fall back to their `model:`/`effort:` frontmatter.
|
|
- First use of a row asks once, with context (Later, Keep or Change: model,
|
|
then effort, then Everywhere or this project only); the answer is kept in
|
|
`mods/model-router/routing.json`. `/route pending` lists what is still
|
|
unconfirmed, `/route ask off|on` toggles the dialog, `/route forget
|
|
<name|all|projects>` takes a decision back.
|
|
|
|
Measure the split any time: `python3 ~/.claude/lib/effort-audit.py`
|
|
(thinking/output/cache tokens per scope, model and effort).
|
|
|
|
## Never
|
|
|
|
- A route inside a dispatched agent: its row rules there.
|
|
- Max is for diagnosis, not for retrying the same fix harder.
|