PD005 · neutron design brief · stage: proposal
Autonomous Model Routing — Right Model, Right Effort, per Task
Today a human picks the backend and effort. Headless work — workflows, schedules, intake jobs — needs Neutron to decide: classify the task, apply an operator-owned routing policy, respect budgets and account health, and record why. Routing is deterministic policy over data; the model is consulted only when the policy says so.
1 · What exists to build on
| Piece | Where | Gives the router |
|---|---|---|
| backend registry | config.ts + custom backends | the menu: models, lanes, VPN needs |
| effort ladder | engine claude.ts | thinking-budget dial per turn |
| cost tracking | providers/cost.ts + model_pricing | per-model price signals, per-agent spend |
| account pools | claude-accounts.ts · codex-accounts.ts | live availability: benched, limited, pinned |
| runtime evaluation | engine/runtime-evaluation* | evidence of which lane handles which work |
2 · Routing flow
flowchart LR T[task arrives
chat · workflow step ·
schedule · intake job] --> C[classify
deterministic signals first:
source · connector · repo touch ·
prompt shape · attachments] C -->|ambiguous only| L[small-model classify
cheap lane · cached] C --> P[policy table
class × constraints → backend + effort] L --> P P --> H{account health
benched? limited? VPN up?} H -->|primary| R[run] H -->|failover| P R --> E[record: route + reason
cost attributed · outcome fed back]
- Classify deterministically first. A workflow step declares its class in
the graph; an intake job is
codingby construction; a schedule names its class. Only free-form chat with no signals falls through to a cheap cached small-model call. - Policy is an admin-editable table, not code: task class × constraints (max cost, latency, privacy/VPN lane, instance defaults) → backend + effort. Shipped with sensible defaults; per-agent overrides win; an explicit human choice always wins.
- Health-aware. The router consults pool state (benched accounts, reset timers, pinning) before committing, and fails over inside the policy's allowed lanes — never silently to a lane the operator excluded.
- Recorded. Every routed turn stores route + reason next to cost, so "why did this run on GLM at low effort" is a lookup, not archaeology.
3 · Example policy (default ship)
| Task class | Backend lane | Effort |
|---|---|---|
| chat · attended | instance default (Claude) | medium |
| coding · intake job | promoted coding lane (runtime-eval gated) | high |
| review / verify | strongest available lane | high |
| workflow glue · extraction · digests | cheap lane (GLM / Haiku-class) | low |
| bulk / scheduled sweeps | cheap lane, subscription pool preferred | low |
4 · Guardrails
- Per-agent and per-workflow budget caps (daily tokens / currency); breach parks the run and raises an inbox card — never silent overrun.
- Routing can change cost and quality, so policy edits are a gated admin action with audit, like pricing edits today.
- The feedback loop is offline: runtime-evaluation and outcome data propose policy changes; a human (or gated admin agent) applies them. No self-tuning in the hot path.
5 · Phases
- Policy table + deterministic router (~4–6 sessions). Class from declared context, admin-editable table, health-aware failover, route recording. Covers all headless work.
- Budgets + reporting (~3–4 sessions). Caps, park-on-breach, route/reason surfaced in usage UI.
- Classifier + feedback (~4–6 sessions). Small-model fallback for unclassified chat, eval-driven policy proposals to the owner inbox.
6 · Acceptance
- A workflow step with no explicit model runs on the policy's lane and records why.
- Benching the primary account mid-run fails over within policy lanes only.
- A budget breach parks the workflow and notifies; nothing runs past the cap.
- An explicit per-agent model override always beats the router.
- Deterministic classes never invoke the classifier model (counted, not assumed).