feat(model-router): wave 3-C — /route forget <name|all|projects>
Clears first-use decisions from the tracked routing.json through the existing writer: a name is forgotten in every table (confirmed, changed with the row restored to its recorded shipped phase under guards, project exceptions pruned) and asked again; all and projects ask a confirmation in the engine dialog (Cancel first) and hold the single-dialog slot; nothing is written when there is nothing to forget; the answer names what was restored and the frontmatter floor to realign when one was aligned; the route tool has no forget path. Docs name the new writer. Kit suite 232 → 284. Contract .claude/tasks/contracts/2026-10-11-model-router-w3c-forget-1457.md, plan r3: 3 lenses + 1 confirmation, feater + 3 rounds (one real defect), GATE 0 MET, verifier at the cap on coverage (user-accepted), security PASS.
This commit is contained in:
@@ -135,9 +135,9 @@ effort, never version. Transcript audit `python3 lib/effort-audit.py`.
|
||||
- Main loop: every request gets the route in force. A typed skill with a row routes the main loop to it; a best-tier row (`plan`, `reflect`, `orchestrate`, `escalate`) holds across turns in a run slot until `/route clear`, `/route off`, a user `/model` or a typed skill on a non-best row. A skill without a row leaves the route as it is.
|
||||
- Sub-agents: a routed agent gets its row's model at spawn, within its tier and only upward from its frontmatter model, and the row's effort on every step. Explicit `model` / `effort` params on the Agent call win; a project-defined agent of the same name keeps its own definition. Built-ins: Explore runs on sonnet/medium, Plan on opus/xhigh.
|
||||
- Levers inside a run: `ultrathink` in a prompt sets the turn's minimum effort; `/route effort=max` holds until `/route clear`. The built-in `/effort` is not a lever inside a run, rows and routes outrank it.
|
||||
- `/route` (user command) shows or sets the route: `show`, `clear`, `off`, `on`, `reload`, `pending` (rows and phases not confirmed yet), `ask on|off` (first-use dialog on or off), a phase name, `model=<alias|id> effort=<level>`, `switch on|off`, `verbose on|off`. `/route show` names the run slot when one holds (`main: run <phase>`). The model sets routes through a `route` tool.
|
||||
- `/route` (user command) shows or sets the route: `show`, `clear`, `off`, `on`, `reload`, `pending` (rows and phases not confirmed yet), `ask on|off` (first-use dialog on or off), `forget <name|all|projects>` (takes decisions back: a changed row returns to its shipped phase; `all` and `projects` ask first), a phase name, `model=<alias|id> effort=<level>`, `switch on|off`, `verbose on|off`. `/route show` names the run slot when one holds (`main: run <phase>`). The model sets routes through a `route` tool.
|
||||
- First use: the first time a rowed skill is typed, a rowed agent is spawned or a phase is declared on the main loop through the `route` tool, the mod asks once whether the route is right. The question gives context: the skill's description (first sentence of its `SKILL.md` frontmatter) or the agent's, the phase with its `about` line, and the model id and effort the next step really runs on; a declared phase also says what uses it (rows, prompt rules). A row offers Later, Keep or Change; a declared phase offers Later or Keep. Change asks the model (fable, opus, sonnet, haiku, each shown with the tier it heads), then the effort among those the phases on that model use (shipped table: fable medium, high, xhigh or max; sonnet low, medium, high or xhigh; opus and haiku have one level each, so no question), then Everywhere or This project only. Rows stay phase names, so the pair maps to an existing phase: the row's current phase wins a tie and the same phase counts as Keep; a pair no phase offers needs a new phase added by hand in routing.json. Everywhere moves the row and records the shipped phase under `changed`; This project only stores an exception under `projects`, keyed by the origin remote reduced to `host/path` (no credentials, no local paths; a remote that cannot be read that way offers no project choice). Keep lands under `confirmed`; Later, a dismissed dialog or a free-text answer asks again next session. After a skill row changes, a toast names the model and effort that skill now runs on, plus the `/route switch on` hint when the main loop holds back a downgrade. One dialog at a time, never in a headless (`-p`) run, never inside a sub-agent.
|
||||
- Only a dialog answer or `/route ask on|off` writes `routing.json`, never the model. Writes are serialized, capped at 64 KiB, and refused when the file is missing (it is never created). Each write leaves the config repo dirty; a toast reminds you to commit it from there.
|
||||
- Only a dialog answer, `/route ask on|off` or `/route forget` writes `routing.json`, never the model. Writes are serialized, capped at 64 KiB, and refused when the file is missing (it is never created). Each write leaves the config repo dirty; a toast reminds you to commit it from there.
|
||||
- The spinner suffix and the status line under the prompt show the route in force.
|
||||
|
||||
Config layers: `mods/model-router/routing.json` (tracked: phases with their tier, effort and `about` line, rows, decisions, `ask`), then the optional per-machine `~/.claude/model-router.json`, which wins. A `.claude/model-router.json` inside a project is never read. Machine keys: `models` (alias → full id), `windows` (context window per full id), `tiers` (ordered alias lists per tier: `best` fable>opus>sonnet, `big` opus>fable>sonnet, `work` sonnet>opus, `cheap` haiku>sonnet; the first alias not down is used), `fallback` (the rank order of the aliases, best first, used by the breaker), `cooldownMinutes` (how long a model stays marked down after an availability error, 15 by default, doubling per episode up to 300), `mainUpgrade` (default `true`: the main loop may move up to a phase's tier), `upgradeMaxTokens` (default 200000: no main-loop upgrade above this context size, since an upgrade re-reads the whole context cold), `phases`, `agents`, `skills`, `prompt` (rules), `mainModelSwitch` (default `false`), `verbose` (default `false`), `spinner` (default `true`), `enabled` (default `true`; `false` turns the mod off on that machine), `ask` (overrides routing.json's `ask` on that machine). A `null` value in `agents` or `skills` drops a row. Edit phases and rows by hand in routing.json (a phase's `about`, 120 characters at most, is read from there only and shown in the dialog; a model and effort pair no phase offers needs a new phase there); without it the mod runs the code's default phases, with no rows and no dialog. `/route reload` re-reads both files.
|
||||
|
||||
Reference in New Issue
Block a user