routing: make per-role tier and effort user-configurable (config layer), persistent across plugin updates #54
Labels
No labels
already-shipped
bug
documentation
duplicate
enhancement
good first issue
help wanted
in progress
invalid
needs-decision
proposal
question
wontfix
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: crenshawdev/cadence#54
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
Model routing is defined in two plugin-internal places:
cadence-core/route-table.json(per-roletierandbase_effort, plus the profile matrix) and each agent's frontmatter (effort:). Both ship inside the plugin, so a plugin update replaces them and any user edit to routing is silently overwritten.The only update-safe customization surface is the config layers that live outside the plugin (
~/.claude/cadence/config.jsonglobal,.planning/config.jsonper repo). Today those expose model selection only:model.profile(fast / balanced / quality / auto)model.auto.*(ceiling, escalation)model.overrides.<role>(pin a role to a model alias)There is no config key for per-role
tieroreffort. A user cannot durably change either: editingroute-table.jsonor agent frontmatter works until the next plugin update, then reverts.Impact
A user who wants (for example)
cad-verifierrouted lighter, orcad-assumptions-analyzerat a lower effort, has no persistent path. The model can be pinned; tier and effort cannot.model.overridescan only assert a model alias, and per the resolver it explicitly does not touch effort (route.mjsoverride block; effort stays fixed fromroute-tablebase_effort+ agent frontmatter).Desired behavior
route.mjs resolveshould read per-roletierandeffortfrom the config layer, falling back toroute-table.jsonwhen unset, matching the precedencemodel.overridesalready follows (config over shipped default). Thenroute-table.jsonstays purely our defaults, and a user's config carries their routing, surviving every update.Sketch
model.overrides.<role>from a bare alias string into an object{ model?, tier?, effort? }, or add a siblingmodel.roles.<role>: { tier?, effort? }. Keep the bare-string form working for back-compat.route.mjs: after resolving from the profile/tier matrix, apply configtier/effortover the route-table defaults (alongside the existing model-pin step).route-tablebase_effort. Decide the single source of truth and reconcile so the two cannot silently disagree (nothing checks they match today).config.schema.json+ validation, add aself-verifyCONTRACTS entry, and cover with tests: config tier/effort applied, absent falls back to route-table, back-compat string pin still works.Acceptance
tierandeffortin~/.claude/cadence/config.json(or.planning/config.json) and it persists across a plugin update.route-table.jsonand agent frontmatter carry defaults only; nothing a user must edit to customize routing lives inside the plugin.Collision to settle before either is scheduled: #63 proposes deleting the tier ladder entirely and replacing model-as-lever with effort-as-lever. This issue asks to make that same tier ladder user-configurable so it survives a plugin update. Both cannot land. Whichever wins, the other closes.