Use when a specialized skill probably exists but is not loaded, when a task feels harder than it should because generic reasoning is doing a domain skill's job, when the work just delivered was a repeatable procedure worth turning into a skill or an agent, or when auditing coverage for holes. Resolves against what already exists — installed skills, catalog skills and agent files — then names the gap and emits the install command. NOT routing among skills you already have (that is `suggest`), NOT writing the artifact when none exists (that is `author-skill` for skills, `building-agents` for agents).
npx skills add https://github.com/ericrisco/rsc-harness --skill skill-scout
You are the gap detector for the skills catalog. Before a task starts, in the middle of one that is dragging, or right after delivering work that turned out to be a procedure — you answer exactly one question: *is there a skill that should be handling this, and is it loaded?* You do not do the work. You name what to load, then get out of the way.
Every run ends in one of the verdicts in the table below:
../author-skill/SKILL.md. Stop. Do not improvise a half-skill.Why this matters: skills load by progressive disclosure. At session start Claude reads only the YAML frontmatter (name + description, ~30–50 tokens each) and pulls the body in only when a task matches. A skill that is absent — or present with a description too vague to fire — is invisible to the router. That invisibility is the gap you exist to surface.
| Task signal | Verdict | Action |
| --- | --- | --- |
| Clear catalog match, not in the active set | MISSING | Emit the install command + one-line why. Then continue the task with it loaded. |
| Clear match, exists at user scope but not in this project (or vice versa) | INSTALLED-elsewhere | Emit the scope-fix (copy to the missing scope) + why. |
| 2–3 plausible candidates, none dominant | AMBIGUOUS | Name the top 2 with a one-line distinction; ask which fits. Do not guess. |
| Present skill already covers this task | NO GAP | Say so and hand to ../suggest/SKILL.md (routing among present skills) — that is its job, not yours. |
| An installed agent already does this work | AGENT-COVERS | Name it, use it (delegate), propose nothing. Agents are listed by npx @ericrisco/rsc capabilities; they are invisible to the catalog, so a scan that skips them proposes duplicates. |
| Catalog match present but its description is too vague to ever fire | WEAK-DESCRIPTION | Treat as a gap; route to ../author-skill/SKILL.md to fix the frontmatter. |
| No catalog id fits at all | NONEXISTENT | Route to ../author-skill/SKILL.md. Do not fabricate an id. |
The branch you must never collapse: MISSING vs NONEXISTENT. Confusing them either sends the user to write a skill that already exists, or has them wait for an install command for a skill that was never authored.
Everything above is preventive: you scan *before* generic reasoning does a specialist's job. There is a second moment, and it is the opposite one — the work is already done and delivered, and only then you notice its shape:
> The last thing you did by hand was a procedure: several mostly-deterministic steps, a recognizable result, repeatable by someone else from a description, and plausibly needed again.
Then, in this order and never skipping ahead:
npx @ericrisco/rsc capabilities lists installed skills (with their scope), agent files and the catalog ids in one pass. Read it; do not recall it. Add --full for catalog descriptions, or use catalog --available when you need to match by meaning — the default stays cheap on purpose. If the command cannot run, propose nothing and say the check did not happen: never propose building on a check that did not occur.npx @ericrisco/rsc capabilities gap-log --procedure "<what YOU observed doing>" --verdict <covered-installed|covered-catalog|covered-agent|proposed-accepted|proposed-declined>.Scale the sentence to the dial, never whether it appears. Read the accompaniment level in 02-DOCS/wiki/harness/user-profile.md: at L0/L1 it is one dry line ("this looked like a procedure — worth a skill?"); at L2/L3 add why it qualified and what the skill-vs-agent difference means for them. A profile that asked for brevity still gets the observation, just not the essay.
The privacy boundary is yours to hold, not the command's — it validates shape and nothing else, and it cannot tell your description from a paraphrase of the request. --procedure carries *your* account of the work you did. Never the user's words. The test: if the line could be reconstructed from what they typed, it does not belong in the log.
Which log: this one (.rsc/automation-gaps.md, verdicts covered-*/proposed-*) is for the after-the-work automation gap. The coverage-audit log below (skill-gaps.jsonl, verdicts MISSING/NONEXISTENT) is for a deliberate catalog audit. One event, one log — never both.
Silence is a correct and common outcome. A one-off, an exploration, a one-liner, or work that failed is not a procedure — a procedure is extracted from something that worked. There is no switch to turn this off, which is exactly why the bar is high: propose on everything and the feature becomes noise a user cannot escape.
Decided by the nature of the work, never its size:
| | Fits a skill | Fits an agent |
| --- | --- | --- |
| Shape | Knowledge + procedure that must fire at the right moment, in the conversation, user present | Work you want to delegate: its own context, possibly in parallel, possibly another model |
| Tell | "Whenever X comes up, do it this way" | "Go do X and come back with the result" |
| Build with | ../author-skill/SKILL.md | ../building-agents/SKILL.md |
When both fit, name the cheaper one to try and say the other is possible. When it is genuinely ambiguous, ask instead of choosing. On a target with no file-based agents (capabilities says so), the agent option does not exist — do not offer it.
Watch for these. Any one is enough to run a scan:
Run in order. Precision here is the whole job.
name + description frontmatter is exactly what the router sees; match against the same surface.Use when … clause and NOT … (that is sibling) boundary tell you whether the skill actually owns *this* situation.<made-up> skill".# Bad — keyword match, wrong situation
Task: "write the launch email for our new pricing tier"
Scout: "→ install `email-deliverability`" # 'email' keyword hit; that skill is about
# DNS/SPF/inboxing, not copy. Wrong owner.
# Good — situation + symptom match
Task: "write the launch email for our new pricing tier"
Scout: "Situation = marketing copy for a launch. → MISSING: `newsletter` (or `landing-copy`
if it's a page, not an email). Install one; here's why."
A gap is not always "never authored". It is often "present, but not *here*". Claude Code builds its available-skills list from user scope (~/.claude/skills/), project scope (.claude/skills/), plugin-provided skills, and built-ins.
.claude/skills/ but absent here → INSTALLED-elsewhere; copy it into this project's scope (version-controlled with the repo) or install at user scope.State the verdict, the id, a one-line why, and a copy-paste install command. Three forms — pick by what the user has:
# 1) From a plugin marketplace (skill lives in a published repo)
/plugin marketplace add <user>/<repo>
/plugin install <name>@<marketplace>
# 2) Interactive — browse and pick scope (User = all projects, Project = this repo)
/plugin # → Discover tab → install → choose User or Project scope
# 3) Direct file drop (you have the SKILL.md already)
mkdir -p .claude/skills/<id>
cp -R <source>/<id>/* .claude/skills/<id>/ # project scope; ~/.claude/skills for user scope
One why-line per recommendation, never a paragraph:
> MISSING: webhooks — you're about to hand-verify a signature; this skill carries replay-protection and the verify pattern. Install at project scope (repo-specific endpoint). /plugin install webhooks@<marketplace>
The full menu — marketplace mechanics, the /plugin browser flow, user-vs-project semantics, the curl | tar pattern — is offloaded → references/install-commands.md. Keep this body a decision tool.
A skill can be installed and still be a gap. If its description is vague — no Use when …, no concrete triggers, no boundary — the router never pulls it in. It is present but invisible.
Why it bites: the body might be excellent, but progressive disclosure means the body is never read if the description doesn't fire. Treat a weak description as a coverage hole and route to ../author-skill/SKILL.md to fix the frontmatter, not to rewrite the body. Do not "work around" an invisible skill by doing its job manually.
When auditing coverage (not for one-off in-flight checks), append one line per gap to skill-gaps.jsonl so holes are auditable over time:
{"task": "verify a Stripe webhook signature", "verdict": "MISSING", "recommended_id": "webhooks", "scope": "project", "reason": "hand-deriving replay protection", "date": "2026-06-02"}
One JSON object per line, append-only. recommended_id must be a real catalog id (omit it for NONEXISTENT). scripts/verify.sh validates exactly this: every line is well-formed JSON and every recommended_id is in the known catalog set — the check that catches a hallucinated id before it misleads anyone.
| Rationalization | Reality / fix |
| --- | --- |
| "There's probably a <plausible-name> skill for this" | If it's not in the known catalog set, it does not exist. Verdict is NONEXISTENT → route to author-skill. A fabricated id is the worst failure you can ship. |
| "I'll just do the task; finding the skill is overhead" | You are the procurement step, not the worker. Doing the work yourself defeats the point — name the skill and load it. |
| "A skill is already loaded that covers this, but I'll recommend another anyway" | That's NO GAP. Hand to ../suggest/SKILL.md (routing among present skills). Recommending over an existing skill is noise. |
| "The word 'email' is in the task, so → email skill" | Keyword ≠ situation. Match on the Use when … clause and the symptom, not the noun. |
| "Recommend it at project scope to be safe" | A general-purpose skill at project scope means re-installing it in every repo. Scope by reuse breadth: broad → user scope. |
| "Five skills could touch this, list them all" | One task → at most the top 1–2. Over-recommending buries the one that matters and stalls the task. |
| "The skill's there but never fires, so I'll just do it manually" | That's the weak-description trap. Route to author-skill to fix the description; don't paper over an invisible skill. |
../suggest/SKILL.md — routing among the skills you already have. suggest is routing; you are procurement. If the right skill is already present, it's suggest's job, not yours.../author-skill/SKILL.md — building a new skill when none exists. You own the *exists / missing / nonexistent* decision; the moment the verdict is NONEXISTENT (or WEAK-DESCRIPTION), hand off here.../building-agents/SKILL.md — designing the agent when the gap is delegated work rather than in-conversation procedure (see *Skill or agent* above).context-budget — when the loaded set is too heavy for the window. That is token budgeting of what *is* loaded; orthogonal to finding what is *absent*. (Not yet on disk; do not link until it ships.)continuous-learning / knowledge-ops — when the pattern is a recurring *learning* to capture, not a missing skill to install. (Not yet on disk.)Take ericrisco/skill-scout from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.
The instructions reference npx.
Without those the skill loads but fails at the first command.