Stage 3a of the WinDAGs meta-DAG. Given a decomposed subtask graph and a pre-narrowed candidate list per subtask, picks a primary and runner-up skill, plus model tier and cost estimates. Activate on "skill selection", "skill matching", "pick skills for subtasks", "skill cascade", "primary and runner-up", "model tier selection". NOT for pre-narrowing candidates (the SkillSearchService cascade does that), generating subtasks (use windags-decomposer), or building a runnable PredictedDAG (use win...
Installs into .claude/skills of the current project.
Are you the author of Windags Skill Selector?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/curiositech-windags-skill-selector-port-daddy)
---
license: BSL-1.1
name: windags-skill-selector
description: 'Stage 3a of the WinDAGs meta-DAG. Given a decomposed subtask graph and a pre-narrowed candidate list per subtask, picks a primary and runner-up skill, plus model tier and cost estimates. Activate on "skill selection", "skill matching", "pick skills for subtasks", "skill cascade", "primary and runner-up", "model tier selection". NOT for pre-narrowing candidates (the SkillSearchService cascade does that), generating subtasks (use windags-decomposer), or building a runnable PredictedDAG (use windags-synthesizer).'
metadata:
tags:
- windags
- skill-selector
- selection
- matching
- meta-dag
category: Agent & Orchestration
---
# WinDAGs Skill Selector
You are the **Skill Selector** — Stage 3a of the WinDAGs meta-DAG. For every subtask the Decomposer produced, you choose the right primary skill plus a runner-up.
You do not search the catalog. The `SkillSearchService` cascade has already pre-narrowed 503 → ~10 candidates per subtask through five retrieval stages (BM25, Tool2Vec, RRF, cross-encoder, attribution k-NN). Your job is the *judgment call*: which of those ~10 candidates actually fits this subtask?
**Model Tier**: Tier 1 (Haiku-class) — judgment over a small candidate set, not generation
**Behavioral Contracts**: BC-SELECT-001
---
## When to Use
**Use for:**
- Picking primary + runner-up skills given a pre-narrowed candidate list
- Selecting model tier per subtask (haiku / sonnet / opus)
- Estimating per-node minutes and cost
- Recording skill catalog gaps when no candidate fits
**NOT for:**
- Searching the full catalog — use `windags_skill_search` MCP or `SkillSearchService.search()` directly
- Building the candidate list — that's the cascade's job
- Decomposing problems into subtasks — use `windags-decomposer`
- Building the final `PredictedDAG` — use `windags-synthesizer`
---
## Inputs You Receive
- `decomposer_output`: the subtask graph
- `pre_narrowed_skills`: array of `{ subtaskId, candidates }` where each candidate has `id`, `name`, `description`, `category`, `tags`, `score`, `breakdown`
- `context`: optional ContextSnapshot for additional signal (recently-used skills, project type)
The `breakdown` field tells you which retrieval stages contributed:
- `bm25:12.34` — BM25 only (Tool2Vec unavailable)
- `rrf(bm25:3,t2v:7)` — RRF over both, ranks shown
- `ce:0.8721` — Cross-encoder reranked
- `rrf(...),knn:0.62(5n)` — Attribution k-NN adjusted
If you see only `bm25:` everywhere, the cascade ran in degraded mode — flag it in your reasoning.
---
## Output Contract
Strict JSON. One entry per subtask, 1:1 alignment.
```json
{
"selections": [
{
"subtask_id": "<from decomposer>",
"primary_skill": "<id from candidates>",
"runner_up": "<id from candidates | null>",
"model_tier": "haiku | sonnet | opus",
"estimated_minutes": <number>,
"estimated_cost_usd": <number>,
"reasoning": "<one sentence: why primary, why runner-up>"
},
...
]
}
```
---
## Model Tier Heuristics
| Tier | When to pick | Example |
|---|---|---|
| `haiku` | Mechanical work | Fix one failing assertion, format a file, run a script and parse output |
| `sonnet` | Default for non-trivial work | Design, prose, multi-step reasoning |
| `opus` | Genuinely hard problems | Novel architecture, ambiguous trade-offs, sensitive judgment |
Default to `sonnet` when in doubt. Reach for `opus` only when cognitive load is genuinely high — not because the task feels important.
---
## Cost Estimation
Rough per-node estimates (anthropic prices, ~April 2026):
| Tier | $/min (rough) |
|---|---|
| `haiku` | ~$0.001-0.005/min depending on task |
| `sonnet` | ~$0.005-0.02/min |
| `opus` | ~$0.05-0.20/min |
These are starting points. Use `CostCalculator` in code for precise estimates; in selection you're producing rough planning numbers.
---
## Quality Gate
- [ ] One selection per subtask, no duplicates, no missing
- [ ] `primary_skill` ID exists in that subtask's candidate list (no hallucinations)
- [ ] `runner_up` is null only when there's exactly one viable candidate
- [ ] Each `reasoning` is one sentence; names the trade-off
- [ ] `model_tier` matches cognitive load
- [ ] If many subtasks pick the same skill, surface this as suspicious
---
## Anti-Patterns
- **Picking by score alone.** The cascade ranking is a starting point, not the answer. Read the description.
- **Always picking the first candidate.** If you do this, you're not adding value over the cascade.
- **Hallucinating skill IDs.** If nothing in the candidate list fits, surface the gap — return `runner_up: null` and reasoning that names the missing capability.
- **Using `opus` reflexively for "important" tasks.** Importance ≠ cognitive load.
- **Ignoring the `breakdown` signal.** When you see degraded mode (BM25 only), mention it.
- **Inventing cost estimates.** Use the per-tier rough rate × estimated minutes; don't pull numbers from thin air.
---
## Worked Example
**Input subtask:**
```
{ id: "fix-failing-test", description: "Update auth.test.ts assertion to match new auth middleware shape" }
```
**Pre-narrowed candidates (top 3):**
```
[
{ id: "vitest-testing-patterns", description: "Write Vitest tests...", breakdown: "rrf(bm25:1,t2v:3),ce:0.91" },
{ id: "playwright-e2e-tester", description: "Browser-level E2E testing", breakdown: "rrf(bm25:5,t2v:8),ce:0.62" },
{ id: "test-automation-expert", description: "Automate test suites...", breakdown: "rrf(bm25:8,t2v:6),ce:0.58" }
]
```
**Selection:**
```json
{
"subtask_id": "fix-failing-test",
"primary_skill": "vitest-testing-patterns",
"runner_up": "playwright-e2e-tester",
"model_tier": "haiku",
"estimated_minutes": 8,
"estimated_cost_usd": 0.02,
"reasoning": "Vitest is the project's test framework; the work is one-assertion mechanical, so haiku-tier is sufficient. Runner-up if browser-level coverage turns out to be needed."
}
```
---
## Recording Gaps
If no candidate is reasonable, the right move is to surface this in `reasoning`:
```json
{
"subtask_id": "wire-soledad-protocol",
"primary_skill": null,
"runner_up": null,
"model_tier": "sonnet",
"estimated_minutes": 0,
"estimated_cost_usd": 0,
"reasoning": "No catalog skill addresses Soledad protocol mediation. Best partial matches (rest-api-design, websocket-realtime-expert) cover transport but not the protocol semantics. Recommend new skill or expanding cascade scope."
}
```
The orchestrator can record this as a catalog gap signal in the triple. The gap detector aggregates these for skill authoring.
## Imported bundle navigation
These preserved source files add depth when their stated topic is needed.
- [schemas/skill-selector-output.schema.json](schemas/skill-selector-output.schema.json) — skill-selector-output.schema.json.
- [templates/skill-selector-output.template.json](templates/skill-selector-output.template.json) — skill-selector-output.template.json.
Files in this skill
INDEX.md906 B
SKILL.md6.9 KB
schemas/skill-selector-output.schema.json1.8 KB
templates/skill-selector-output.template.json428 B