Commit Graph
10 Commits
Author SHA1 Message Date
bchanot 32b71d25b5 chore(model-router): routing.json decision — security-auditor on judge (opus/xhigh), user's answer to the new first-use dialog; changed.from restored 2026-10-11 14:11:08 +02:00
bchanot 604a6c4411 feat(model-router): wave 3-B — first-use dialog with context, model then effort on change
The dialog now explains what it asks about: the skill's description (from
its SKILL.md frontmatter, five YAML forms, first sentence, cleaned), the
agent's description (from agent.offer), the phase's new 'about' line in
routing.json, and the real model id and effort the next step runs on.
Options Later / Keep / Change; Change asks the model (fable, opus, sonnet,
haiku with their tier role), then the effort among those the phases of
that model offer, then the scope; the pair maps to an existing phase (rows
stay phase names; the row's current phase wins a tie; same phase = Keep).
A main-loop phase (T3) is Later / Keep only. A main-row change toasts the
real decision and the /route switch hint when the pick is a downgrade.
Descriptions pass a hardened read (name allowlist, stat kind, size cap)
and clean(). Kit suite 190 → 232; W3-A dialog tests migrated.

Contract .claude/tasks/contracts/2026-10-11-model-router-w3b-dialog-1240.md,
plan r3: 3 lenses (2 BLOCKERs: inline rows, phase edits) + 1 confirmation,
feater + 2 rounds, GATE 0 MET, verifier CONFORME (3rd pass), security PASS.
2026-10-11 14:10:24 +02:00
bchanot 5bab61e13a chore(model-router): routing.json decision — doc-syncer kept on write (live first-use dialog, user Keep) 2026-10-11 11:57:56 +02:00
bchanot 22455c051f feat(model-router): wave 3-A — first-use route confirmation, decision memory, project exceptions
routing.json (tracked, reached through the plugin directory) is now the
single source of the phase table and of every skill/agent row, plus the
decisions: confirmed rows/phases, changed rows (from/to) and projects
exceptions keyed by a normalized git remote (credentials never stored, no
machine paths). First use of a rowed typed skill, a rowed agent spawn or a
main-loop phase opens the engine's dialog (Later / Keep / two alternative
phases; Other = a phase name); a change asks Everywhere or This project
only. One dialog at a time, never in headless, never inside an agent,
never written by the model: only a dialog answer or /route ask writes,
serialized, size-capped, never creating the file. Layers: routing.json <
~/.claude/model-router.json; the project tree is never read. /route
pending, /route ask on|off. Census reads rows and phases from the file and
tolerates a user-changed row (WARN). Kit suite 86 → 190 tests.

Contract .claude/tasks/contracts/2026-10-10-model-router-w3a-confirm-1201.md,
plan r4: 3 lenses + 1 confirmation, feater + 4 rounds, GATE 0 MET,
verifier CONFORME then re-verify after security, security BLOCK(1) fixed
then PASS. Live: T2 dialogs answered by the user from the hot-loaded mod.
2026-10-11 11:48:25 +02:00
bchanot 1f2d33b7a6 feat(model-router): wave 2-B — orchestrators declare phases, shifters and pins removed, frontmatter = off-state floor
The 15 Skill(effort-*) citers now call mcp__model-router__route per phase
(orchestrate at a dispatch span, reflect/plan for the skill's own level,
apply at the bookkeeping tail, escalate at the verify-secure caps); built-in
judgment dispatches carry an explicit effort= param. lib/effort-shift.md is
the route doctrine, lib/model-gate.md the mod rule (route answer = witness,
/route on as remedy). Deleted: skills/effort-*, lib/effort-pins.txt/.sh,
lib/model-check.sh, their tests, the installers' re-apply blocks. The mod
drops its Skill(effort-*) bridge. The tracked model:/effort: frontmatter
stays as the off-state floor, census-locked equal to the rows
(lib/tests/effort-routing.test.sh rewritten, 140 checks; analyzer → xhigh).

Contract .claude/tasks/contracts/2026-10-10-model-router-w2b-1045.md, plan
r4 § W2-B: GATE 0 MET, verifier ECARTS(7) then CONFORME 10/10, security
PASS, full make test green (design-tool-gate env red only).
2026-10-10 11:24:54 +02:00
bchanot bb56f3e41e feat(model-router): wave 2-A — phase rows for every repo skill and agent, run slot, typed-slash routing
Rows by role replace the pins as the live source (frontmatter stays as the
off-state floor): phases write=work/high and apply=work/low, 56 skill rows,
21 agent rows + Explore/Plan. Agents get the row's model at spawn (within
the tier, upward only, explicit params win, project-defined agents skipped
via agent.offer) and its effort per step. A typed slash of a rowed skill
routes main through a name-bound marker (composer|sdk|bridge, pending slot
mid-turn) or the idle fallback; a best-tier row lives in a runMain slot
that survives turn end and route calls. An unrowed skill leaves the route.
Typed /effort-* floor code removed (bridge kept until W2-B). The route
answer always names the id. Override rows accept null. Kit suite 58 → 88.

Contract .claude/tasks/contracts/2026-10-09-model-router-w2a-1546.md, plan
r4 .claude/tasks/plans/2026-10-09-model-router-w2-1546.md: 3 lenses + 2
confirmations, feater + 4 rounds, GATE 0 MET, verifier 3x ECARTS on test
coverage only (user-accepted at the cap), security PASS.
2026-10-09 17:22:07 +02:00
bchanot d0fa1001bb feat(mods): model-router adaptive tiers — absolute tiers, availability breaker, derived phases
Phases name absolute tiers (best fable>opus>sonnet, big opus>fable>sonnet,
work sonnet>opus, cheap haiku>sonnet) resolved to the first available full
id; per-model circuit breaker fed by StopFailure kinds (rate_limit,
overloaded, billing_error, model_not_found) and PostModelSwitch auto, with
episode backoff 15→300 min, cleared by a user /model or /route reload and
kept across /clear; fallback chain fable→opus→sonnet→haiku with the effort
unchanged; main loop upgrades to a phase's tier by itself under a context
cap (fails closed on unknown usage), downgrades only with the switch on,
sticky within a turn; derived orchestrate on background dispatches;
prompt default rules (plan/reflect, Unicode guards, skipped on slash
commands, floor matches and mid-turn). 58 plugin tests.
2026-10-09 15:08:49 +02:00
bchanot 1ff608a68c feat(mods): model-router user effort floor — ultrathink and typed /effort-<l> set the main turn's default and minimum
One decision helper (mainEffort) feeds the plan and every answer text;
per-axis precedence (sticky > turn route > floor > engine); a mid-turn
prompt floors the running turn and the next; per-machine kill switch
"enabled": false in ~/.claude/model-router.json, kept across /clear and
across a failed reload; typed /effort-<l> attested at prompt.submit so a
sub-agent preload cannot floor the main loop. 30 plugin tests.
2026-10-09 10:12:28 +02:00
bchanot 346d6aeab2 feat(mods): model-router hardening — user-only /route, effort-only agent routes, config caps, visible fail-open
Security-gate round on the wave 1-A mod: /route answers only a composer
origin; an in-agent route call can no longer change the agent's model
(effort only, model fixed at spawn); config patterns capped (200 chars,
4096-char scan), phase keys restricted, override file refused above 64 KB,
additionalProperties false on the tool schema; every .catch logs once per
session; post-next bookkeeping isolated. 14 plugin tests, verifier 11/11.
2026-10-08 16:53:43 +02:00
bchanot b721c94dcb feat(mods): model-router mod, wave 1-A — per-request model/effort routing
Function-hooks plugin under mods/model-router: routes effort (and, behind a
flag, the model) of every main-loop request, sets built-in sub-agents' model
at spawn with full ids, answers Skill(effort-*) itself (single writer, no
pairing rule), exposes the route tool and /route, validates the optional
~/.claude/model-router.json. 11 plugin tests, validate + tsc clean.
Contract .claude/tasks/contracts/2026-10-08-model-router-w1a-1533.md.
2026-10-08 16:26:57 +02:00