skill-router · diff
git:20260430.ff1408b to git:20260906.f2c7c6b
216 added, 171 removed. Audit A to A.
---
name: skill-router
- description: INVOKE BEFORE EVERY NON-TRIVIAL TASK — before writing code, before using any tool, before answering. Do not skip. Produces the required Skill + Agent + Model for the task. Routing engine for 2,700+ skills.
+ description: INVOKE BEFORE EVERY NON-TRIVIAL TASK — before writing code, before using any tool, before answering. Do not skip. Produces the required Skill + Agent + Model for the task. Routing engine for 400+ installed skills.
---
- # Skill Router — Universal Router
+ # Skill Router
**Output always:** `Skill + Agent + Model`
+ Routing runs automatically. A `UserPromptSubmit` hook classifies every prompt
+ and injects a `[skill-router]` announcement before your first action, so most
+ of the time your job is to *follow* an announcement, not compute one. This file
+ is the contract that announcement is written against, and what you fall back on
+ when the hook is silent.
+
+ **First, is it healthy?** If you have not seen a `[skill-router]` line in a
+ while, routing may be dead rather than quiet:
+
+ ```bash
+ python3 ~/.claude/skills/skill-router/scripts/doctor.py
+ ```
+
---
## THE 3-QUESTION TRIAGE (run now, takes 5 seconds)
```
Q1: Is something BROKEN / WRONG / FAILING?
Error, crash, test fail, unexpected output, user correction
YES → BROKEN PATH
Q2: Is this CREATE / BUILD / ADD something new?
New feature, file, component, integration, page, script
YES → BUILD PATH
Q3: Everything else (improve, ship, configure, automate, research)
→ OPERATE PATH
AMBIGUOUS? → Default to HIGHER-COMPLEXITY path
```
+ Before the table, two layers get first refusal:
+
+ 1. **Project routes** — `SKILL.personal.md` maps names that mean exactly one
+ project (`@economicalai`, `testflight`, `jobhunt`) straight to that
+ project's skill. Generic triage cannot tell one project from another; this
+ is the only layer that can.
+ 2. **The routing table** below.
+
---
## BROKEN PATH
- | Signal | Skill | Agent | Model | Thinking |
- |--------|-------|-------|-------|----------|
- | Error / crash / exception | `superpowers:systematic-debugging` | general-purpose | sonnet | think |
- | Test failing | `test-runner` → `superpowers:systematic-debugging` | test-runner | sonnet | none |
- | TypeScript errors | `typescript-expert` | general-purpose | sonnet | none |
- | Performance regression | `perf` → `superpowers:systematic-debugging` | optimizer | sonnet | think |
- | Security issue found | `security` | security-auditor | sonnet | think-hard |
- | Deploy / build failed | `superpowers:systematic-debugging` | general-purpose | sonnet | think |
- | User says "no" / "wrong" | STOP → `superpowers:systematic-debugging` | general-purpose | sonnet | think |
- | Production incident | `superpowers:systematic-debugging` | general-purpose | **opus** | **ultrathink** |
+ | Signal | Skill | Agent | Thinking |
+ |--------|-------|-------|----------|
+ | Error / crash / exception | `superpowers:systematic-debugging` | general-purpose | think |
+ | Test failing | `superpowers:systematic-debugging` | test-runner | think |
+ | Performance regression | `perf` | optimizer | think |
+ | Security issue found | `security` | security-auditor | think-hard |
+ | Deploy / build failed | `superpowers:systematic-debugging` | general-purpose | think |
+ | User says "no" / "wrong" | STOP → `superpowers:systematic-debugging` | general-purpose | think |
+ | Production incident | `superpowers:systematic-debugging` | general-purpose | **ultrathink** |
---
## BUILD PATH
- **Multi-file / new feature:** `brainstorming` → `writing-plans` → domain skill
- **Single file / trivial add:** go directly to domain skill
+ **Multi-file / new feature:** `writing-plans` → domain skill
+ **Single file / trivial add:** go directly to the domain skill
- | What | Skill | Agent | Model | Thinking |
- |------|-------|-------|-------|----------|
- | UI component / page | `frontend-design:frontend-design` | feature-dev:code-architect | sonnet | none |
- | API endpoint | `feature-dev:feature-dev` | feature-dev:code-architect | sonnet | think |
- | Database schema | `db-expert` | db-expert | sonnet | think |
- | Auth / permissions | `brainstorming` → `security` | security-auditor | opus | **ultrathink** |
- | AI feature / agent | `superpowers:brainstorming` | feature-dev:code-architect | sonnet | think-hard |
- | 3rd-party integration | `connect-apps` | integration-specialist | sonnet | none |
- | Mobile screen | `frontend-design:frontend-design` | feature-dev:code-architect | sonnet | none |
- | CLI / automation script | `superpowers:writing-plans` | general-purpose | sonnet | think |
- | Skill / Claude skill file | `superpowers:writing-skills` | general-purpose | sonnet | think |
+ | What | Skill | Agent | Thinking |
+ |------|-------|-------|----------|
+ | UI component / page | `frontend-design:frontend-design` | feature-dev:code-architect | none |
+ | API endpoint | `feature-dev:feature-dev` | feature-dev:code-architect | think |
+ | Database schema | `supabase:supabase` | db-expert | think |
+ | Auth / permissions | `security` | security-auditor | **ultrathink** |
+ | AI / RAG / agent feature | `superpowers:writing-plans` | feature-dev:code-architect | think-hard |
+ | 3rd-party integration | `connect-apps` | integration-specialist | none |
+ | Mobile screen | `frontend-design:frontend-design` | feature-dev:code-architect | none |
+ | CLI / automation script | `superpowers:writing-plans` | general-purpose | think |
+ | Skill / Claude skill file | `superpowers:writing-skills` | general-purpose | think |
---
## OPERATE PATH
- | Signal | Skill | Agent | Model | Thinking |
- |--------|-------|-------|-------|----------|
- | Refactor / clean up | `refactor` | code-simplifier:code-simplifier | sonnet | none |
- | Add tests / coverage | `superpowers:test-driven-development` | test-runner | sonnet | none |
- | Performance optimize | `perf` | optimizer | sonnet | think |
- | Write docs | `docs` | general-purpose | sonnet | none |
- | Code review | `superpowers:requesting-code-review` | superpowers:code-reviewer | sonnet | think-hard |
- | Got review feedback | `superpowers:receiving-code-review` | general-purpose | sonnet | think |
- | Deploy | `superpowers:verification-before-completion` → `vercel:deploy` | general-purpose | sonnet | none |
- | Merge / PR / push | `superpowers:finishing-a-development-branch` | general-purpose | sonnet | none |
- | DB migration | `db-expert` | db-expert | sonnet | think |
- | 2+ independent tasks | `superpowers:dispatching-parallel-agents` | general-purpose | sonnet | none |
- | Resume previous work | `superpowers:executing-plans` | general-purpose | sonnet | none |
- | Research / docs lookup | context7 → `brainstorming` | general-purpose | sonnet | none |
- | Architecture / scope decision | `superpowers:brainstorming` → `superpowers:writing-plans` | general-purpose | opus | **ultrathink** |
+ | Signal | Skill | Agent | Thinking |
+ |--------|-------|-------|----------|
+ | Refactor / clean up | `refactor` | code-simplifier:code-simplifier | none |
+ | Add tests / coverage | `superpowers:test-driven-development` | test-runner | none |
+ | Code review | `superpowers:requesting-code-review` | code-reviewer | think-hard |
+ | Got review feedback | `superpowers:receiving-code-review` | general-purpose | think |
+ | Deploy | `superpowers:verification-before-completion` → `vercel:deploy` | general-purpose | none |
+ | Merge / PR / push | `superpowers:finishing-a-development-branch` | general-purpose | none |
+ | 2+ independent tasks | `superpowers:dispatching-parallel-agents` | general-purpose | none |
+ | Resume previous work | `superpowers:executing-plans` | general-purpose | none |
+ | Architecture / scope call | `superpowers:writing-plans` | general-purpose | **ultrathink** |
---
- ## WHEN NO SKILL IS NEEDED
-
- Single-line fix · reading code · one factual question · one command · under 3 trivial steps
-
- **Router precision contract:** when no triage signal matches (BROKEN/BUILD/OPERATE), the
- router emits **nothing** — silence is the correct output. A missing `[skill-router]` line
- means the prompt was conversational, exploratory, or trivial. Do not interpret silence as
- "OPERATE → refactor" by default; the router only suggests when it is confident.
+ ## THE MODEL COLUMN IS `inherit`
- **Iron rule enforcement:** when the router *does* announce a chain, the announcement
- includes an `IRON RULE` block naming the next required `Skill(skill="<X>")` call. A
- `PreToolUse` hook denies state-changing tools (`Bash`, `Edit`, `Write`, `Task`) until that
- skill is invoked, and a `Stop` hook blocks turn end if it never was. Read/Glob/Grep/
- TodoWrite remain allowed so context-gathering still works.
+ Steps run **in this session, at this session's model**, unless there is a
+ reason to do otherwise. There are two:
- **Escape hatch:** the **USER** must include `[no-router]` in their next message to disable
- enforcement for that turn. The router stays silent and clears pending state on UserPromptSubmit,
- so all hooks pass through. **Writing `[no-router]` in your own response text does NOT clear
- pending state** — only the user's prompt triggers the clear. If the Stop hook is blocking you
- on a ghost skill, it will self-clear on the next user message regardless (ghost-skill guard).
+ | Value | Meaning | When |
+ |---|---|---|
+ | `inherit` | run in-session at the parent's model | the default, nearly always |
+ | `haiku` | dispatch to a sub-agent on the cheap model | bulk read-only scans whose output is a list of paths, not a judgment |
- **Calibration:** `tests/calibration.py` runs ~100 curated prompts through the router and
- reports precision/recall/F1 by triage path. Run with `--min-accuracy N` for a CI gate.
- Current baseline: **100% path accuracy, 95.2% skill accuracy**.
+ The table used to name `sonnet` on most rows and `opus` on hard ones. That was
+ written when the parent was always Sonnet, so `sonnet` silently meant
+ `inherit`. It stopped meaning that — and because the dispatch protocol reads
+ "step model ≠ parent model" as "fan out to a sub-agent", every routed step on a
+ Fable or Opus session was being shipped to a *weaker* model than the user chose.
- **Learning loop:** `scripts/learn-from-history.py` joins announcement events
- (`~/.claude/skill_router_log.jsonl`) with actual Skill invocations (`~/.claude/
- skill_usage.log`) and surfaces tuning suggestions — which announced skills are ignored
- most often, and which Skill invocations the router missed. Run periodically to keep
- patterns calibrated to real usage.
+ Depth now comes from `Thinking`, which composes with any model. Never
+ reintroduce a frontier model name into the table.
---
- ## COMPLETION GATE
+ ## SPECIALIST LAYER — 400 skills, not 20
- Before any "done" claim → `superpowers:verification-before-completion`
+ The tables above name ~20 process skills. This machine has ~395 invokable ones,
+ and the rest are the domain specialists that make a task go faster. They cannot
+ be enumerated in a table — new skills land weekly — so the router ranks them at
+ query time and appends one advisory line:
```
- □ Code actually runs correctly
- □ TypeScript passes (tsc --noEmit)
- □ Tests pass
- □ Original request fully met (re-read it)
+ [skill-router] Specialist available: seo-technical — Technical SEO audit across 9 categories…
```
+ Advisory, never enforced. Load it alongside the announced step when it fits;
+ ignore it when it doesn't. When no specialist clears the confidence bar, the
+ line is absent — which is the common case and the correct one.
+
+ ```bash
+ # what would match, and why
+ python3 ~/.claude/skills/skill-router/scripts/catalog_match.py "your prompt"
+ ```
+
+ The catalog rebuilds at every `SessionStart`, so a skill you install today is
+ routable today. Non-invokable skills (`~/.agent/skills`, `~/.composio-skills`)
+ are catalogued but never announced — they can only be suggested for install.
+
---
- ## COMPLEXITY RULE
+ ## SUB-AGENTS GET ROUTED TOO
+ A `SubagentStart` hook injects the same kind of brief into every dispatched
+ sub-agent, naming the skills that fit that agent's job:
+
```
- 1 domain → 1 skill → single-domain announcement
- 2+ domains → announce chain → multi-domain announcement
+ [skill-router] Skills for seo-technical: Skill(skill="seo-technical"), Skill(skill="seo")
```
- Operators in the chain:
- - `→` sequential (B depends on A)
- - `+` parallel (steps don't share state)
+ Pairings come from `agent_skills.json` when hand-set, and are otherwise derived
+ by ranking the agent's own description against the catalog — so a new agent
+ gets sensible skills with no registration step. Generic agents
+ (`general-purpose`, `Explore`, `researcher`) get nothing, because they have no
+ domain and any suggestion would be noise.
- Full chain syntax + standard shapes: see [`references/multi-domain-chaining.md`](./references/multi-domain-chaining.md).
+ The hook is the mechanism, deliberately. Agent frontmatter also documents a
+ `skills:` field that preloads full skill text at startup; on Claude Code
+ 2.1.263 it was tested here and the content did not arrive in the sub-agent's
+ context, while the hook brief did — verified by asking a dispatched agent what
+ it could see. Revisit `skills:` when a release notes a fix; until then the hook
+ is the only path that demonstrably works.
+ **The IRON RULE does not apply inside sub-agents.** The parent's pending skill
+ belongs to the parent's turn and a sub-agent cannot satisfy it, so enforcement
+ stands down at the boundary. Sub-agents are told what to use; they are never
+ blocked.
+
+ When you dispatch an agent yourself, name the skill in the prompt:
+
+ ```
+ Agent(subagent_type="db-expert",
+ prompt="think. Use Skill: supabase:supabase. Task: … Context: …")
+ ```
+
---
- ## ANNOUNCEMENT FORMAT — Output VERBATIM (substitute only `<vars>`)
+ ## WHEN NO SKILL IS NEEDED
- The announcement is the testable contract. Users will `grep '\[skill-router\]'`
- their transcript to verify what fired matches what was announced. Format is
- non-negotiable. Output it BEFORE any other tool call (Read, Edit, Bash, Agent).
+ Single-line fix · reading code · one factual question · one command · under 3
+ trivial steps.
- **Single-domain (one skill, no chain):**
- ```
- [skill-router] This is a <BROKEN|BUILD|OPERATE> task → <skill> → <agent>.
- [skill-router] Model: <model> · Thinking: <thinking>
- [skill-router] Invoke now:
+ **Silence is an answer.** When no triage signal matches, the router emits
+ nothing. A missing `[skill-router]` line means the prompt was conversational,
+ exploratory, or trivial — not that you should invent a route.
- ▶ <skill> (<model>, <in-session | via Agent>)
- ```
+ **Explicit slash-commands stand down.** If the prompt is itself an invocation
+ (`/gstack`, `/ship prod`), the user already chose. Never reclassify it.
- **Multi-domain (computed chain):**
- ```
- [skill-router] This touches <N> domains: <d1>, <d2>, <d3>.
- [skill-router] Chain: <s1> → <s2> + <s3> → <s4>
- [skill-router] Models: <m1> · <m2>+<m3> · <m4> · Thinking: <max-thinking>
- [skill-router] Invoke step 1/<N> now:
+ ---
- ▶ <s1> (<m1>, <in-session | via Agent>)
- ▶ <s2> + <s3> (<m2>, parallel via Agent)
- ▶ <s4> (<m4>, <in-session | via Agent>)
- ```
+ ## IRON RULE
- **Multi-domain (saved chain wins):**
- ```
- [skill-router] Using your saved chain `<name>`: <s1> → <s2> + <s3>
- [skill-router] Models: <m1> · <m2>+<m3> · Thinking: <max-thinking>
- [skill-router] Invoke step 1/<N> now:
+ When the router announces, a `PreToolUse` hook denies `Edit`/`Write`/`Task`/
+ `NotebookEdit`/`MultiEdit` until that skill is invoked, and a `Stop` hook blocks
+ turn end if it never was. `Read`/`Glob`/`Grep`/`Bash`/`TodoWrite`/`Skill` stay
+ allowed, so context-gathering, shell work, and the override below keep working.
- ▶ <s1> (<m1>, <in-session | via Agent>)
- ▶ <s2> + <s3> (<m2>, parallel via Agent)
- ```
+ **Two escape hatches:**
- Rules:
- - `Models:` line uses `·` between sequential steps and `+` inside one parallel step.
- - `Thinking:` is the highest depth of any step (`none` / `think` / `think-hard` / `ultrathink`). Omit the field when every step is `none`.
- - Each `▶` line ends with one of: `in-session`, `via Agent`, or `parallel via Agent` — matching the dispatch protocol decision below.
- - After each step completes, output `[skill-router] Step <n>/<N> done.` before dispatching the next.
- - On chain end, output `[skill-router] Chain done.`
+ 1. **User opt-out** — the *user* includes `[no-router]` in their next message.
+ Writing it in your own response does nothing.
+ 2. **Reasoned override** — if you judge the route wrong, don't fight the rule:
- Two layers of testability — keep them aligned:
- - **`[skill-router]` lines + `▶` markers** are the *human-readable* proof in the transcript. `grep '\[skill-router\]'` shows what was announced; the `▶` line shows the dispatch decision the parent made.
- - **`~/.claude/skill_router_log.jsonl`** events (`chain-start`, `chain-step`, `thinking-active`, `chain-end`) are the *machine-readable* proof read by `scripts/audit-dispatch.py` and the statusline. The `▶` line does NOT replace the JSONL `chain-step` event — write both. See [`references/dispatch-protocol.md`](./references/dispatch-protocol.md).
+ ```bash
+ python3 ~/.claude/skills/skill-router/scripts/router_override.py "<reason>"
+ ```
- Skipping the announcement format = silently breaking the testability claim.
+ This clears the rule for the turn, logs your reason, and counts against that
+ skill. Past `OVERRIDE_THRESHOLD` the router defers it — **for
+ `DEFER_TTL_DAYS`, then it comes back**. Demotions expire on purpose:
+ permanent ones once killed five core skills here and left the router
+ answering SKIP to everything while looking perfectly healthy.
---
- ## NAMED CHAIN LOOKUP — Run Before Computing Fresh
+ ## COMPLETION GATE
- After triage, BEFORE computing fresh, check `SKILL.personal.md` for a
- `chains:` block. If any `when:` substring matches the user's prompt
- (case-insensitive, first match wins), use the saved chain instead.
+ Before any "done" claim → `superpowers:verification-before-completion`
- When a saved chain wins, announce it with provenance:
```
- Using your saved chain `<name>`: <step1> → <step2> + <step3>
+ □ Code actually runs correctly
+ □ TypeScript passes (tsc --noEmit)
+ □ Tests pass
+ □ Original request fully met (re-read it)
```
- Schema, match algorithm, per-step model resolution: [`references/named-chains.md`](./references/named-chains.md).
-
---
- ## CATALOG CHECK — Run After Routing-Table Lookup (Key Differentiator)
+ ## ANNOUNCEMENT FORMAT — output VERBATIM (substitute only `<vars>`)
- If the table returned a generic skill (e.g. `integration-specialist`),
- search local + remote catalogs for a more specific match. If found, use
- the specialist instead.
+ The announcement is the testable contract: `grep '\[skill-router\]'` shows what
+ fired. When the hook already produced one, follow it — do not reprint it.
+ **Single-domain:**
```
- 1. Local: ls ~/.agent/skills/, ~/.claude/skills/, ~/.composio-skills/ | grep -iE '<keyword>'
- 2. Remote: site:github.com "SKILL.md" claude <keyword> (4 curated repos in ref doc)
- 3. Generate: superpowers:writing-skills (last resort)
+ [skill-router] This is a <BROKEN|BUILD|OPERATE> task → <skill> → <agent>.
+ [skill-router] Model: <in-session|haiku> · Thinking: <thinking>
+ [skill-router] Invoke now:
+
+ ▶ <skill> (<inherit|model>, <in-session | via Agent>)
```
- Skip when: routing-table answer is already specialist · single-line fix ·
- keyword is too generic ("code", "file", "text").
+ **Multi-domain:**
+ ```
+ [skill-router] This touches <N> domains: <d1>, <d2>.
+ [skill-router] Chain: <s1> → <s2> + <s3>
+ [skill-router] Models: inherit (this session) · Thinking: <max-thinking>
+ [skill-router] Invoke step 1/<N> now:
- Full validation gates + curated repos: [`references/catalog-check.md`](./references/catalog-check.md), [`references/known-skill-repos.md`](./references/known-skill-repos.md).
+ ▶ <s1> (inherit, in-session)
+ ▶ <s2> + <s3> (inherit, parallel via Agent)
+ ```
- ---
+ Rules:
+ - `Thinking:` is the deepest of any step. Omit when every step is `none`.
+ - Each `▶` line ends with `in-session`, `via Agent`, or `parallel via Agent`.
+ - After each step: `[skill-router] Step <n>/<N> done.` On completion:
+ `[skill-router] Chain done.`
- ## PERSONAL OVERRIDES
+ ---
- Add project-specific routing on top of this file:
+ ## DISPATCH PROTOCOL
- ```bash
- curl -sL https://raw.githubusercontent.com/hussi9/skill-router/main/SKILL.personal.md \
- > ~/.claude/skills/skill-router/SKILL.personal.md
```
+ For each step:
+ IF step.model == "inherit" AND not a parallel fan-out:
+ → Skill(<skill>) in-session (same context, no dispatch cost)
+ ELSE:
+ → Agent(subagent_type=<agent>, model=<model>,
+ prompt="<thinking-keyword>. Use Skill: <skill>. Task: <slice>. Context: <files>")
+ Sequential `→`: wait. Parallel `+`: one message, multiple Agent calls.
+ ```
- Edit `SKILL.personal.md` with your project signals. Your rules win over the core (CSS cascade model).
+ Parallel steps go through `Agent` even at `inherit` — not for the model, but
+ because they need independent contexts to run at once.
+ Full event schema and verification: [`references/dispatch-protocol.md`](./references/dispatch-protocol.md).
+
---
- ## THINKING DEPTH — Pre-pend the Right Keyword
+ ## THINKING DEPTH
- Pre-pend the routing row's `Thinking` value as the literal first word of the
- dispatch prompt:
+ Pre-pend the row's `Thinking` value as the literal first word of the dispatch
+ prompt. Do not paraphrase.
| Value | Pre-pend |
|-------|----------|
| `none` | (nothing) |
| `think` | `think.` |
| `think-hard` | `think hard.` |
| `ultrathink` | `ultrathink.` |
- Do not paraphrase. If a community `ultrathink` / `think-hard` skill is
- installed, invoke that skill INSTEAD of the bare keyword.
-
- Full rules + community alternatives: [`references/thinking-depth.md`](./references/thinking-depth.md).
+ Full rules: [`references/thinking-depth.md`](./references/thinking-depth.md).
---
- ## DISPATCH PROTOCOL — How Each Step Actually Runs
-
- This is what makes the **Model** column enforced, not advisory.
+ ## COMPLEXITY RULE
```
- For each step in the announced chain:
- IF step.model == parent_model AND not parallel-fan-out:
- → Skill(<skill>) in-session (cheaper, same context)
- ELSE:
- → Agent(subagent_type=<agent>, model=<model>,
- prompt="<thinking-keyword>. Use Skill: <skill>. Task: <slice>. Context: <files>")
- Sequential `→`: wait. Parallel `+`: one message, multiple Agent calls.
+ 1 domain → 1 skill → single-domain announcement
+ 2+ domains → announce chain → multi-domain announcement
```
- After dispatching, write log lines to `~/.claude/skill_router_log.jsonl`
- (`chain-start`, `chain-step`, `thinking-active`, `chain-end`) for the
- statusline + the `scripts/audit-dispatch.py` compliance auditor.
+ `→` sequential (B depends on A) · `+` parallel (no shared state).
+ Chain shapes: [`references/multi-domain-chaining.md`](./references/multi-domain-chaining.md).
- Full event schema, common skip patterns, and verification: [`references/dispatch-protocol.md`](./references/dispatch-protocol.md).
+ ---
+ ## MAINTENANCE
+
+ | Command | When |
+ |---|---|
+ | `scripts/doctor.py` | routing feels dead, or after any Claude Code upgrade |
+ | `scripts/install_hooks.py` | doctor reports missing hooks |
+ | `scripts/build_catalog.py` | you installed a skill and want it routable now |
+ | `scripts/catalog_match.py "<prompt>"` | a specialist suggestion looked wrong |
+ | `scripts/learn-from-history.py` | monthly: which announcements get ignored |
+ | `python3 -m pytest tests/ -q` | after editing any routing logic |
+ | `tests/calibration.py --min-accuracy 95` | accuracy gate over 109 curated prompts |
+
+ Personal routes and project guardrails: [`SKILL.personal.md`](./SKILL.personal.md).
+
---
- ## RED FLAGS — Signs You're About to Skip This
+ ## RED FLAGS — signs you're about to skip this
```
- "This is simple" → Simple things take 5s to route. Skip routing = hours wasted.
+ "This is simple" → Simple things take 5s to route.
"I know what to do" → Then routing confirms it. 5s cost, 0 downside.
- "No match in table" → Run Catalog Check above before giving up.
- "Ambiguous task" → Default to higher-complexity path (BUILD).
- "I already know the skill" → Still run catalog check — a better one may exist.
- "I'll just paraphrase" → No. Output the [skill-router] format VERBATIM. Greppability is the contract.
- "I can skip the ▶ lines" → No. Per-step ▶ lines are the dispatch-mode proof. Without them the audit script can't score the chain.
+ "No match in table" → Check the specialist line before giving up.
+ "Ambiguous task" → Default to the higher-complexity path.
+ "I'll just paraphrase" → No. The [skill-router] format is the contract.
+ "The announcement is wrong" → Overrule it with a reason. Don't ignore it.
```