APP

skill-pilot

Lints SKILL.md files for description quality (1,536-char cap, front-loaded triggers, valid frontmatter), and ships a UserPromptSubmit hook that injects a system reminder naming the skills that match each prompt — so Claude stops missing the right skill among 100+. Three layered off-switches; fails closed.

skill-pilot
Install this app

Paste this into Claude Code (VS Code panel, Adom editor, or terminal) to install:

I want to install the "skill-pilot" app from the Adom Wiki (https://wiki-ufypy5dpx93o.adom.cloud/wiki/apps/skill-pilot). For the Docker CLI: curl -fsSL https://wiki-ufypy5dpx93o.adom.cloud/static/apps/skill-pilot/skill-pilot -o /tmp/skill-pilot && chmod +x /tmp/skill-pilot && sudo install -m 0755 /tmp/skill-pilot /usr/local/bin/skill-pilot && skill-pilot install Then verify the install works.

Download latest

Windows coming soon
macOS coming soon
🐧 Linux coming soon
🐳 Adom Docker CLI skill-pilot ·

See all releases on GitHub (private repo — access required)

skill-pilot

Stops Claude Code from missing skills. Two halves working together: a lint that audits every SKILL.md for description quality, and a router hook that nudges Claude on every prompt by name-matching the prompt against your skill index.

The problem this solves

Claude Code surfaces every installed skill to the model via its description frontmatter — capped at 1,536 characters per skill, with a global ~8,000-char budget across all skills. With 100+ skills, two things go wrong:

  1. Buried trigger phrases. A description that puts keywords past the first 200 characters effectively hides them. Claude never sees "use this for Mouser searches" if the prose only mentions Mouser at the end.
  2. Soft signal. Even when Claude does see a relevant description, picking it from 100+ candidates is fuzzy. A skill that should fire ~always (like tool-publisher for any "publish" prompt) often gets passed over.

skill-pilot fixes both.

How the router works

skill-pilot on registers a UserPromptSubmit hook in ~/.claude/settings.json. Every time you hit Enter, the hook runs skill-pilot match with your prompt as stdin. The matcher:

  1. Loads (or builds + caches for 5 min) an in-memory keyword index from every SKILL.md in ~/.claude/skills/ and ~/project/gallia/skills/. Triggers come from Trigger words: blocks, comma-separated noun phrases in the description, and proper-noun-ish words like Mouser / KiCad / JLCPCB.

  2. Word-boundary matches the prompt against the index. Single-word triggers require word boundaries (so mouser matches mouser, never mouserate); multi-word phrases use substring match.

  3. Emits one short <system-reminder> listing the top-5 matching skill names, e.g.:

    <system-reminder>skill-pilot: matching skills for this prompt — adom-mouser, adom-parts-search, electrical-engineering. Invoke if relevant; ignore if not.</system-reminder>

  4. Logs to ~/.adom/skill-pilot/matches.log (timestamp, skills, prompt prefix) so you can audit precision/recall.

Claude sees the reminder by name — much louder signal than ambient description matching against 100+ skills.

How the lint works

skill-pilot lint scans every SKILL.md and scores 0–100 with deductions for:

IssuePenalty
Missing name / description−30 / −50
description + when_to_use over 1,536 chars (gets truncated)−20
No detectable trigger phrases−30
Triggers exist but none in first 200 chars−25
Description shorter than 60 chars−15

Output is human-readable by default, --json for machine consumption. Use it before skill-pilot on to find skills the matcher won't be able to see, then front-load their trigger words.

Install (Tier A — auto-installed)

skill-pilot is Tier A: every Adom container gets it automatically when gallia/install.mjs runs (which happens on every gallia auto-update, ~30 min cadence). The router hook is enabled by default during install. New containers will see a one-time notice in the install output explaining what was just turned on.

If you need to (re)install manually:

curl -fsSL https://wiki-ufypy5dpx93o.adom.cloud/static/apps/skill-pilot/skill-pilot \
  -o /tmp/skill-pilot && chmod +x /tmp/skill-pilot \
  && sudo install -m 0755 /tmp/skill-pilot /usr/local/bin/skill-pilot \
  && skill-pilot install \
  && skill-pilot on

Gallia's 30-min wiki-refresh hook keeps the installed binary in sync with the wiki's pub_version.

Don't want it?

skill-pilot off                   # remove hook from settings.json
export ADOM_SKILL_PILOT=0         # or pause per-shell, no settings change

Both off-switches survive future gallia updates — install.mjs runs skill-pilot on only on the initial install (on is idempotent and won't re-enable a hook you've explicitly removed).

CLI

# Lint (do this BEFORE turning the router on)
skill-pilot lint                    # human-readable report
skill-pilot lint --json             # machine output
skill-pilot lint --dir <path>       # custom skill dirs

# Router hook
skill-pilot on                      # register UserPromptSubmit hook
skill-pilot off                     # remove hook
skill-pilot status                  # wired? env-var state? last 10 matches

# Dry-run / debug
skill-pilot match --prompt "find a 10k resistor on mouser"
skill-pilot match --prompt "..." --no-log

# Historical analysis
skill-pilot analyze                 # top-firing skills, false-positive
                                    #   candidates, co-occurrence, zero-matches
skill-pilot analyze --json          # machine output
skill-pilot analyze --log <path>    # custom log path

Auditing the router with skill-pilot analyze

Every prompt that flows through the hook is appended to ~/.adom/skill-pilot/matches.log — including prompts that matched zero skills (so you can see what the router is missing, not just what it found). Format is one line per prompt:

<unix_timestamp>\t<comma_separated_skills>\t<first_120_chars_of_prompt>

skill-pilot analyze reads this log and surfaces:

SectionWhat it tells you
ActivityTotal prompts logged, time buckets (1h / 24h / 7d), zero-match %, avg matches per matched prompt
Top firing skillsTop-25 skills by count + percent of all prompts. flags skills firing on ≥30% (false-positive candidates). · flags skills firing on <2% (rare or niche)
False-positive candidatesSkills that fire on ≥30% of prompts — almost certainly matching too aggressively. Narrow their triggers
Top co-occurring pairsSkills that always fire together. Often a sign that one matcher is dragging others along (shared trigger or noise like <task-notification> blobs)
Recent zero-match promptsRecent prompts the router didn't route at all — gaps where you might want to widen a skill's triggers, or accept that no skill should fire there

How to read the output:

  • Avg matches per matched prompt > 3.5 — too liberal. Either narrow triggers, or lower the per-prompt cap (currently 5).
  • Any skill firing on >30% of prompts — almost always a false positive on a common word. Edit its description's trigger phrases to be more specific.
  • A pair of skills with co-occurrence equal to each individual count — they're firing as a block (either correctly because they're always relevant together, or incorrectly because they share a common trigger). Investigate the prompts that fired both.
  • Zero-match prompts that look obviously routable — an opportunity to add a missing trigger phrase to a skill, or write a new skill.

Privacy: the log only stores the first 120 characters of each prompt. Tabs and newlines are flattened. The log lives at ~/.adom/skill-pilot/matches.log — local to your container, never uploaded.

Recommended cadence: run skill-pilot analyze after a week of real use. The first few hours of a fresh log are dominated by whatever conversational topic happens to be active and won't reflect steady-state behavior.

Recommended rollout

  1. Lint first. skill-pilot lint on a fresh box almost always surfaces 5–15 skills with buried triggers. Front-load them. (Score-100 skills tend to have a Trigger words: a, b, c, ... line in the first 200 chars of the description.)
  2. Then enable. Run skill-pilot on. Active from the very next prompt — no Claude Code restart needed. Every session on the same container picks it up on its next message.
  3. Verify in the log, not the UI. The Claude Code VS Code extension renders hook output inconsistently — sometimes as a collapsible ▶ UserPromptSubmit hook success disclosure above your message, sometimes not visible at all. The hook itself fires reliably regardless. Trust these instead:
    • skill-pilot status — last 10 matches inline
    • tail -f ~/.adom/skill-pilot/matches.log — streams every match in real time
  4. Audit weekly. Watch the log for skills firing on >30% of prompts — those are false-positive candidates whose triggers need narrowing.

Three off-switches

The router is opt-in and easy to kill. In order of scope:

LayerCommandEffect
Per-shellexport ADOM_SKILL_PILOT=0matcher exits silently for that shell
Per-machineskill-pilot offremoves hook entry from ~/.claude/settings.json (backup at .skill-pilot.bak)
Manualedit ~/.claude/settings.jsonrestore from .skill-pilot.bak if anything went sideways

Plus the hook fails closed: if the binary errors or panics, it emits nothing and exits 0. Claude Code is never blocked by skill-pilot.

Performance

  • Hook overhead: ~5–15 ms per prompt (read cached index, word-boundary scan, write log line).
  • Injection: capped at 5 skills, ~200 chars total — invisible against the prompt itself.
  • Index cache: ~/.adom/skill-pilot/index.json, rebuilt every 5 minutes.

Source

Source lives in the gallia monorepo at gallia/skill-pilot/ (adom-inc/gallia, private). Build with cargo build --release from that directory. The compiled binary is published to this wiki page as a docker_binary asset; users install via the install_hint above (Tier B — on-demand fetch from the wiki, no GitHub credentials needed).

Related

  • skill-creator — Anthropic's official skill-authoring skill; use it to write new skills, then run skill-pilot lint to verify discoverability before shipping.
  • tool-publisher — for publishing CLIs and skills to the wiki (this very page).
  • adom-wiki — wiki search / publish CLI.
  • skill-pilot-build — sibling skill for cutting new releases.
SKIL
skill-pilot 1 month ago
v0.1.2 build for adom docker
1.2 MB

Install notes

Adom Docker CLI install steps
curl -fsSL https://wiki-ufypy5dpx93o.adom.cloud/static/apps/skill-pilot/skill-pilot -o /tmp/skill-pilot && chmod +x /tmp/skill-pilot && sudo install -m 0755 /tmp/skill-pilot /usr/local/bin/skill-pilot && skill-pilot install

Screenshots

AI Skill — how Claude uses this app

Edit AI Skill

name: skill-pilot description: > Audit Claude Code SKILL.md files and route user prompts to matching skills via a UserPromptSubmit hook so Claude actually invokes the right skill. Trigger words: skill-pilot, lint skills, audit skills, skill description quality, skill front-load, skill triggers, why isn't claude using my skill, skill not triggering, skill routing, prompt routing, route to skill, skill matcher, skill router, enable skill hook, disable skill hook, skill-pilot on, skill-pilot off, skill-pilot status, skill-pilot lint, skill-pilot analyze, analyze skill matches, false positive skills, noisy skills, skill match log, skill router stats, audit my skills, check skill descriptions, are my skills formatted right, claude doesn't use my skills, claude misses skills, skill triggering, 1536 cap, skill cap, system reminder skills, claude code hook skills. Use when the user wants to audit their SKILL.md corpus for description quality (front-loaded triggers, length under the 1,536 cap, valid frontmatter), enable or disable the prompt-router hook that nudges Claude toward matching skills, see what skills matched recent prompts, or troubleshoot why Claude is ignoring a skill it should be using.

skill-pilot

Two halves: lint (audit your skill corpus) + router hook (inject a system reminder listing matching skills on every prompt so Claude actually invokes them).

When to use

  • The user says "claude isn't triggering my skill", "audit my skills", "lint skills", "skill-pilot lint/on/off/status", or "why isn't claude using <skill>?"
  • The user has > 50 skills and wants Claude to actually find the right one
  • Before publishing a new skill, to check description quality

CLI

skill-pilot lint                 # audit ~/.claude/skills + gallia/skills
skill-pilot lint --json          # machine-readable output
skill-pilot lint --dir <path>    # custom dir(s)

skill-pilot match --prompt "<text>"   # dry-run the matcher

skill-pilot on                   # wire UserPromptSubmit hook in ~/.claude/settings.json
skill-pilot off                  # remove hook
skill-pilot status               # wired? env-var state? last 10 matches

skill-pilot analyze              # historical log analysis: top firing,
                                 #   false-positive candidates, co-occurrence,
                                 #   zero-match prompts
skill-pilot analyze --json       # machine-readable

How the router works

Hook reads each user prompt → matches against an in-memory keyword index built from every skill's description+name → emits at most one <system-reminder> listing up to 5 matching skill names. Claude sees the reminder and invokes the relevant skill.

Index is cached in ~/.adom/skill-pilot/index.json for 5 minutes. Matches are logged to ~/.adom/skill-pilot/matches.log (timestamp, skills, prompt prefix).

Disabling

Three off-switches, increasing in scope:

  1. ADOM_SKILL_PILOT=0 — env var, skips matching for that shell
  2. skill-pilot off — removes the hook entry from settings.json
  3. Edit ~/.claude/settings.json by hand — settings.json.skill-pilot.bak is kept

The hook also fails closed: if the binary errors or panics, it emits nothing and exits 0. Claude Code is never blocked by skill-pilot.

Lint scoring

Each skill scored 0–100. Deductions:

  • missing name / description: −30 / −50
  • description+when_to_use over 1,536 chars (the cap): −20
  • no detectable trigger phrases: −30
  • triggers exist but none in first 200 chars: −25
  • description shorter than 60 chars: −15

Trigger phrases are pulled from Trigger words: / Triggers: / Examples: blocks first, with a fallback to comma-separated noun phrases.

Storage

  • Binary: wherever you put skill-pilot on PATH
  • Settings: ~/.claude/settings.json
  • Cache: ~/.adom/skill-pilot/index.json
  • Match log: ~/.adom/skill-pilot/matches.log
  • Settings backup: ~/.claude/settings.json.skill-pilot.bak

Sub-Skills
?
What are Sub-Skills?

Sub-skills are community-contributed AI skill extensions for this component. They teach AI assistants about specific tools, configurators, or workflows.

Examples:

  • A manufacturer’s configuration tool for a motor controller
  • A community-written design guide for an amplifier circuit
  • An automated test/validation script for a sensor module

How to add one: Click Add Sub-Skill, provide the URL to your skill and a brief description. Submissions are reviewed by the Adom team before going live.

No sub-skills yet. Be the first to contribute one!

🔎 How Claude finds this page (discovery snippet)

This page opts into Adom Wiki auto-discovery. When a user working in Claude Code mentions any of the trigger phrases below, Claude can proactively suggest this page. The pitch is exactly what Claude will say.

Pitch
"Stops Claude Code from missing skills. Lints every SKILL.md for description quality (front-loaded triggers, the 1,536-char cap, valid frontmatter), and a UserPromptSubmit hook injects a system reminder listing matching skills on every prompt so Claude is nudged by name instead of fuzzy-matching against 100+ descriptions."
Triggers
"skill-pilot", "lint skills", "audit skills", "audit my skills", "check skill descriptions", "skill description quality", "skill front-load", "skill triggers", "why isn't claude using my skill", "skill not triggering", "claude doesn't use my skills", "claude misses skills", "skill triggering", "skill router", "skill matcher", "prompt routing", "route to skill", "enable skill hook", "disable skill hook", "skill-pilot on", "skill-pilot off", "skill-pilot status", "skill-pilot lint", "skill-pilot match", "1536 cap", "skill cap", "system reminder skills", "claude code hook skills", "are my skills formatted right"