10 KiB
10 KiB
name, description, metadata
| name | description | metadata | ||
|---|---|---|---|---|
| boo-router | Resolves the single best provider string for a Paseo dispatch from the active orchestration preset's candidate pool, using the deterministic model-router script (grade and role fit, effective cost, quota, locality, plus the never-subagent guardrail). Use when a role maps to an array of candidates and you must pick ONE provider before create_agent, when the operator says "route this", "which model for <role>", "pick the model", or just before fanning out subagents. Do NOT use to dispatch a skill to a subagent; that is paseo-boo. Do NOT use to decompose a goal into a skill pipeline; that is boo-meta. |
|
Boo-Router
Resolves one provider for one dispatch. This skill is a thin protocol around the deterministic router script; it holds no model knowledge of its own. The registry (~/.paseo/model-tiers.json) and the active preset (~/.paseo/orchestration-preferences.json) are the only sources of truth; the script reads both.
Size
Not sized. One deterministic call per resolution, no fan-out, no agents dispatched.
Process
- Gather the request. Required:
role(one ofimpl,ui,audit,research,planning) and a shorttaskdescription. Optional:difficulty(simple,standard,hard),priority(cost-efficiency,speed,quality,balanced- defaultbalanced),context-tokens(approx input size),requires(comma-separated hard modality needs, e.g.vision,computer-use),fanout(parallel agent count),resident-local(the local model currently loaded in llama-swap).- Invocation shorthand:
boo-router <preset> <priority>(e.g.boo-router workhorse cost-efficiency) means--preset ~/.paseo/presets/<preset>.json --priority <priority>; role and task still come from the operator's request. - Priority profiles tune the deterministic scorer (they nudge, they do not override role fit):
cost-efficiencyweights effective cost + quota heavily and leans reasoning lower;speedrewards the per-model speed signal (TTFT-oriented) and leans reasoning lower;qualityrewards higher grade and leans reasoning higher;balancedis neutral. Legacy--budget(cost_sensitive/balanced/quality) still maps onto these.
- Invocation shorthand:
- Run the router (deterministic, no LLM):
It defaults to the active preset and registry; pass
node ~/.agents/skills/boo-router/scripts/router.mjs --role <role> --task "<task>" \ [--priority <p>] [--difficulty <d>] [--context-tokens <n>] [--requires <list>] \ [--fanout <n>] [--resident-local <id>] [--reserve <id>] [--no-ledger] [--preset <path>] --json--preset/--model-tiersonly to override.- Load awareness: the router reconciles a shared cross-process ledger (
~/.paseo/router-load.jsonl) so concurrent fan-out dispatches spread across providers instead of all picking the same top score. Pass--reserve <id>on a real dispatch to record the pick as in-flight (the dispatcher, paseo-boo, then calls--release <id>at closure); omit it for a preview.--no-ledgerroutes statelessly. The penalties are soft: in-flight crowding vs a per-sourceconcurrency_softcap, remaining 5h quota, and host saturation for local models. They nudge, they never eliminate a candidate.
- Load awareness: the router reconciles a shared cross-process ledger (
- Read
result.providerfrom the JSON. Pass EXACTLY that string tocreate_agent'sproviderfield. - Apply
result.reasoning{ effort, apply }to the dispatched model. OpenCode uses one unified option,reasoningEffort(verified in the opencode binary: it emitsreasoning_effortfor OpenAI/DeepSeek/MiniMax and maps to an Anthropic thinking budget):effortis a concrete value (high,max,medium,none, etc.) -> setoptions.reasoningEffort = <effort>on the model (OpenCode per-model config options, or the model option at create_agent).effort: "auto"-> set nothing; leave the model default. OpenCode rejectsreasoningEfforton non-reasoning models, so never force it.- DeepSeek
effort: "max"needs a large context window (>=384K) and a generous output cap, and thinking mode ignorestemperature. - Via Paseo, the cleanest path is
create_agent settings.thinkingOptionId = <effort>(Paseo maps it per backend); theoptions.reasoningEffortform is the standalone path.
- Apply
result.permissions{ backend, mode, settings }. The defaultmodeisbypass(fully unattended, per operator policy). Passsettingstocreate_agent: opencode ->{ modeId: "build", features: { auto_accept: true } }; claude/claude-ib ->{ modeId: "bypassPermissions" }; codex ->{ modeId: "full-access" }; reasonix ->{ modeId: "yolo" }. For the standalone CLI path usecliBypass(e.g. claude--dangerously-skip-permissions, codex--dangerously-bypass-approvals-and-sandbox). To downgrade from yolo, read the backend'ssafe/readonlyentry from the registrypermissionsblock instead. - Keep
result.fallbacks(the remaining survivors, in score order) for failover. If the dispatched model fails, retry the next provider in the chain ONLY for a transient error (registryfallback.transient: 408/409/425/429/5xx, RateLimit/Timeout/Connection/Overloaded/ContextOverflow); fail fast on permanent errors (registryfallback.permanent: 400/401/403/404/422, auth/validation/not-found). Re-resolve reasoning + permissions for the fallback model (its backend and supported levels differ). The router has already clampedeffortto the model's supported levels and stepped it down under context pressure, so use the value as given. - Relay
result.rationaleas the why. For the full per-candidate trace plus the reasoning and permission notes, re-run with--explaininstead of--json. - If the script cannot run (no
node, file missing), use the manual fallback: read the active preset and registry yourself and apply the same order: eliminateneverSubagentand non-routablecandidates, then any whosemodalitiesmiss arequiresneed or whosectx_maxis belowcontext-tokens; rank survivors byattributes.roles[role], then effective cost (output-weighted,_over_256kband when context crosses 256K), then quota, then locality; default to the first array element when nothing distinguishes them. For reasoning, readreasoning[<model>].by_difficulty[difficulty](or.default) from the registry and setoptions.reasoningEffortthe same way as step 4; skip it when the entry is{ "effort": "auto" }.
What NOT to do
- Do not pass an array, the
scoreslist, or any object tocreate_agent; pass the singleproviderstring only. - Do not route a subscription-high model (
gpt-5,gpt-5.5,opus,fable) as a subagent; the router eliminates them by theneverSubagentguardrail, never re-add one by hand. - Do not invent or remember provider strings; the active preset and registry are the only sources.
- Do not call an LLM to judge task fit; routing is deterministic by design.
- Do not dispatch the agent yourself (that is paseo-boo) or decompose a multi-skill goal (that is boo-meta).
Gotchas
- The active preset is
~/.paseo/orchestration-preferences.json(the filepaseo-presetcopies a named preset onto), not a file underpresets/. Switch grade pools withpaseo-preset grade-L|grade-C|grade-B|grade-A|grade-S. - Provider strings carry the provider prefix:
opencode/opencode-go/<model>(cloud gateway),opencode/deepseek/<model>(DeepSeek direct API, used fordeepseek-v4-flashanddeepseek-v4-pro),opencode/==qwen==/<model>(local, llama-swap),claude/<model>,codex/<model>. Theagentsmap values omit theopencode/prefix; the router handles both. The router keys attributes/pricing/quota by the last path segment, so the provider namespace can change without touching the registry. - Local models are served through the OpenCode provider's
==qwen==namespace; only one is resident in llama-swap at a time, so pass--resident-local <id>to earn the no-swap bonus and avoid thrashing. - A role may be a pinned string (not an array) in the preset; the router returns it as-is with no scoring. That is expected, not a failure.
- The MiniMax M3 promo is priced via the registry
effective_*fields, not router code; if a pick looks too M3-favorable, check whether the promo ended and the fields were removed. - Provider priority: the registry
provider_priorityblock adds a per-SOURCE bonus so equivalent models route to the preferred provider. Current order (2026-06): digitalocean (free GitHub Student credits, spend first) > reasonix > openrouter > opencode-zen (free) > local (sam-desktop) > local-edge > opencode-go (DEPRIORITIZED, usage low, last-resort fallback) > subscription. Source is classified from the provider string. Thecredits-firstpreset is the cross-provider default that exploits this; switch withpaseo-preset credits-first. - Cross-provider pools: a role pool may list the same logical model via several providers (e.g. deepseek-v4-pro via oc-digitalocean, reasonix, oc-openrouter, opencode-go). The router picks the highest-priority source and returns the rest as the
fallbackschain, so a dead provider fails over to the next. - New providers all extend opencode in Paseo, so
oc-digitalocean/oc-openrouter/oc-sam-desktop/oc-embeddingresolve to the opencode permission posture (build + auto_accept); reasonix stays yolo. DigitalOcean's flash id is literallydeepseek-4-flash(missing the v).
- No commit: never commit, push, or stage changes; never
git add -A. Prove any edits withgit diff --stat. - No em dashes: never use em dashes (U+2014) in output or files you write.
Output format
Routed: <role> -> <provider>
reasoningEffort: <effort> (or "auto" = left at model default)
Permissions: <backend> <mode> -> <settings to pass to create_agent> (default mode = bypass/yolo)
Fallbacks: <provider2> -> <provider3> (ordered failover chain, transient errors only)
Preset: <active preset name>
Why: <rationale line from result.rationale>
Every report ends with:
Claims I did not verify
- <anything taken on the script's word without re-running --explain>
Failure modes
- Role has no entry in the active preset: the router errors
Preset has no provider entry for role; report it and stop. - All candidates eliminated: the router errors with each candidate's disqualifying reason; relay them and stop. The usual cause is a pool with no model meeting a hard modality or context need; suggest a different preset.
nodemissing or script absent: use the manual fallback in Process step 5; say you used it.- Registry or preset unparseable: report the failing path and the parse error; never guess a provider.