Skill Infrastructure
Coverage
- The library-as-database mental model: skill-infrastructure as the linter, integrity checker, and query planner for a SKILL.md library
- Why deterministic, zero-LLM tooling is mandatory for skill libraries (trustworthy enough for CI gates; LLM-based health checks are circular)
- The five categories of skill-health tooling: (1) inventory and frontmatter validation, (2) protocol consistency, (3) conflict detection (overlap, imperative, code duplication, heading overlap), (4) routing health (gap analysis, miss tracking), (5) drift detection (truth-source hashing, mirror parity)
- Eval quality patterns: minimum eval threshold per skill, the contradiction-check eval type, the negative-expectation requirement, valid eval-type taxonomy
- Imperative conflict detection: the same-target-opposite-polarity rule, three-check false-positive suppression, when conflicts indicate scope-tightening vs merging
- Routing gap analysis: how to read a "routing-misses" log, how to distinguish keyword gaps from skill content gaps, signal-hygiene rules to suppress noise
- Maintenance workflows: when to run a full health check, the order in which to run the categories, what to fix before what
- Anti-patterns that cause invisible decay: dirty-tree manifest writes, deletion-as-conflict-resolution, eval-renumbering during cleanup, scope misuse to mask threshold violations
- The verification gate before any batch skill commit: every category clean, every new skill meets eval minimums, every routing change is reflected in the manifest
- Package and workspace-root integrity: the npm CLI entrypoint must dispatch to the same scripts as local development while resolving schemas from the package and skills/manifests from the caller workspace
Philosophy
A skill library is only as useful as its worst skill. When agents load stale, conflicting, poorly-routed, or mirror-drifted skills, they get worse at tasks — not better. A skill library at scale (50+, certainly 200+) decays invisibly: eval counts drift below minimums, keyword maps miss whole product areas, mirror copies fall out of sync, and two skills start giving opposite instructions for the same function.
The infrastructure exists to catch that decay deterministically, with zero LLM calls. Every health check reads files, parses structure, and computes — it does not reason, infer, or hallucinate. That makes the output trustworthy enough to use in CI-style gates. An LLM-based health check is circular: the same probabilistic component that produces the skill library cannot reliably grade its own output.
If the skill library is a codebase, skill-infrastructure is its combined linter, type-checker, and dead-code detector — always-on, zero-model, CI-safe.
The maintenance commitment is: run a full health check after any batch skill work, fix threshold violations before they reach the gate, and document conflicts before the agents loading those skills are affected.
The Library-as-Database Mental Model
Treat the skill library as a database and skill-infrastructure as its query planner, integrity checker, and migration-safety net combined.
| Database concept |
Skill-library equivalent |
| Schema |
SKILL.md frontmatter schema (JSON Schema or equivalent) |
| Constraints |
Required fields, eval thresholds, valid enum values |
| Foreign keys |
relations.boundary[], relations.related[] targets — must point at real skills |
| Indexes |
Manifest, routing-keyword map, path-glob inverse index |
| Integrity check |
Protocol-consistency tooling (cross-schema parity, sample correctness, generated-field parity) |
| Query planner |
Skill router (matches user prompt → skill activation) |
| Replication lag |
Mirror parity (.claude/skills, .agents/skills, harness-specific copies) |
| Dead code |
Skills with broken relation targets, phantom routing entries |
Every script in this domain reads files and computes — it does not reason. Output is deterministic, reproducible, and safe to embed in CI gates.
The Five Categories of Skill-Health Tooling
A production skill library needs all five. Missing any one allows a class of decay through.
1. Inventory and Frontmatter Validation
Walks the skill tree, parses every SKILL.md's frontmatter, and validates against the schema.
| Check |
Why it matters |
Required fields present (name, description, version, type, scope, owner, freshness) |
Missing fields break the manifest generator and the router |
Field-value enums valid (type, scope, eval_state) |
Drift in valid values leaks invalid skills into routing |
| Description-length and quality (≥ 100 chars, contains "Use when X / Do NOT use for Y") |
Short or vague descriptions degrade router precision |
| Eval-count per skill (warn at < 7, error at < 3 for non-reference skills) |
Under-evaluated skills regress quality undetected |
Reference-path resolution (every references/X.md cited in frontmatter actually exists) |
Dangling references mislead the agent at activation time |
Scope-grounding consistency (scope: codebase requires populated grounding block) |
Codebase claims without grounding can hallucinate file paths |
Reference implementation: scripts/skill-lint.js in this repo runs T5 per-skill lint covering most of these.
2. Protocol Consistency
Cross-checks that the schema, generator, sample manifest, and field-reference docs all agree.
| Check |
Failure mode if missing |
| Cross-schema parity (versioned schemas describe the same fields) |
Schema bumps silently drop fields |
| Authored-to-generated parity (frontmatter fields match what the generator emits) |
Generator drift breaks downstream consumers |
| Sample manifest matches generator output |
Sample stales as skills are added |
| Generated field-reference matches authored field-reference |
Documentation drift hides field changes |
| Truth invariants on example evals (e.g. truth-source line ranges still resolve) |
Eval expectations point at non-existent code |
Reference implementation: scripts/check-protocol-consistency.js runs C1–C7 protocol checks.
3. Conflict Detection
Pairwise comparison across all active skills to surface duplication, contradiction, and structural overlap.
| Dimension |
Method |
Signal |
| Description similarity |
Jaccard on word bigrams |
> 0.4 = potential duplicate |
| Heading overlap |
Shared H2/H3 headings excluding boilerplate |
High overlap = structural duplication |
| Code duplication |
Identical fenced code blocks > 30 chars |
Copy-paste anti-pattern |
| Imperative conflicts |
Same target, opposite polarity (ALWAYS vs NEVER) |
Agents get contradictory instructions |
Imperative extraction patterns:
- Positive:
\b(?:always|must|required|mandatory)\b\s+(.{10,80})/gi, \buse\s+(.{5,60})\s+(?:for|when|instead)/gi
- Negative:
\b(?:never|do\s+not|don't|must\s+not|prohibited)\b\s+(.{10,80})/gi, \bdo\s+NOT\s+use\s+(.{5,60})/gi
Three-check false-positive suppression for the most common phantom-conflict sources (e.g. Do NOT use X matching as positive use X):
- Lookbehind check — if
not, never, don't, or cannot appears in the 20 characters before a positive match, suppress it
- Within-match check — if
not appears between the start of the match and the target identifier (extracted via backticks), suppress it
- Same-line dedup — if the target was already extracted as a negative on the current line, suppress any positive extraction for that target
When a conflict is real vs spurious:
| Conflict type |
Resolution |
| Phantom ref |
Routing config maps to a non-existent skill — delete the stale entry |
| Code duplication |
One skill owns the example; the other links to it |
| Heading overlap |
Acceptable for structural templates; review only the differentiating content |
| Imperative conflict (real) |
Scope the instructions more precisely (always use X → always use X in app code); rarely merge skills |
| Imperative conflict (spurious) |
Un-backticking an identifier hides a real boundary ambiguity — fix the skill wording instead |
4. Routing Health
Reads the routing-miss log and the routing config to identify where the keyword map fails.
| Input |
Purpose |
| Routing-misses log (queries that matched zero skills) |
Surface keyword gaps — words users typed that never reached a skill |
Eval-history log with failure_category |
Surface skills failing for reasons routing can fix (skill_not_activated, wrong_answer) |
Active routing config (keywordMap, labelMap) |
Authoritative truth for what currently routes |
Output sections:
- Keyword gaps — words appearing in routing-misses but absent from the active keyword map, sorted by frequency
- Eval failure breakdown — skills with 2+ failures, grouped by failure category
- Suggested actions —
add_keyword for frequent gaps; improve_skill for skills failing for content reasons
Signal hygiene rules (suppress these from the suggestion list):
- Low-signal tokens (
v, v4, skill, start, events, daily, log, status, health)
- Single-word misses already covered by an existing multi-word phrase (e.g.
error should not surface if error recovery is already mapped)
- Stale historical misses where the full query already routes under the current config
- Synthetic no-match probes used to verify the router's miss path
- Bundle entries (only direct
keywordMap entries participate in free-text matching)
Reference implementation: the routing harness (scripts/skill-graph-routing-eval.js in this repo) provides the negative case — verifying that a skill's authored examples actually route to it. A real routing-gap report is the symmetric positive case (verifying that real user prompts reach a skill).
5. Drift Detection
Detects when the world the skill claims has changed without the skill being updated.
| Drift type |
Detection |
| Truth-source drift |
drift_check.truth_source_hashes records SHA-256 of cited files; rerun hashes; mismatch = drift |
| Mirror parity |
Hash every <library>/skills/<name>/SKILL.md and every <harness-mirror>/skills/<name>/SKILL.md; mismatch = drift |
Stale freshness date |
Skill has not been touched in > lifecycle.stale_after_days; surface for review |
| Tracker → skill drift |
Issue tracker references a skill that no longer exists; or skill references a closed issue |
Reference implementation: scripts/skill-graph-drift.js in this repo records and verifies truth-source hashes against the live files.
Eval Quality Patterns
The minimum-threshold rule
Every active skill should have at least 7 evals. Most healthy skills carry 9–15 covering happy paths, edge cases, anti-patterns, and contradiction checks. The threshold is a floor, not a goal.
Recommended enforcement:
- Error if
eval_count < 3 (or warn for scope: reference skills, where the file is documentation more than testable behaviour)
- Warn if
eval_count < 7
Below 7, the skill is statistically under-tested. Below 3, it is effectively un-evaluated.
The contradiction-check eval type
A contradiction-check eval tests that the agent correctly handles a documented exception or boundary condition that a simpler reading of the skill would mishandle. Format:
{
"id": 5,
"type": "contradiction-check",
"grounding": "repo-specific",
"difficulty": "adversarial",
"prompt": "Skill A says always use the scoped fetcher. One service uses the unscoped fetcher with an inline comment. Is this wrong?",
"expected_output": "Not wrong — the unscoped fetcher with an inline justification comment is the documented exception for system-level reads.",
"expectations": [
"Correctly identifies the documented exception from the skill's anti-patterns table",
"Does NOT flag the usage as a bug without reading the inline comment",
"Distinguishes a system-level exception from a regular violation in application code"
]
}
Use a contradiction-check when:
- A skill has a documented exception that overrides the general rule
- Two adjacent skills appear to contradict each other but actually operate in different scopes
- A historical false positive or conflict was resolved and the resolution is non-obvious
The negative-expectation requirement
Every eval case with an expectations array must include at least one expectation containing does not, never, must not, should not, or do not. Without this, evals become pure happy-path tests and miss the failure modes that motivated the skill.
Recommended enforcement: the inventory tool flags any eval missing this pattern in a missingNegativeEvalIds field of its report.
Valid eval types
| Type |
When to use |
knowledge |
Tests a factual claim or pattern from the skill |
contradiction-check |
Tests documented exceptions and boundary conditions |
browser |
Tests a browser-executable interaction (requires running server) |
edge-case |
Tests unusual inputs or rare conditions |
business-model |
Tests domain-specific logic (e.g. SaaS billing rules, e-commerce fulfilment) |
negative |
Tests refusal or correct non-action |
Maintenance Workflows
The full health check sequence
Run after any batch skill work — creating ≥ 3 skills, changing routing config, or modifying skill content across multiple files. Order matters:
# 1. Inventory snapshot — discover invalid frontmatter, missing fields, broken refs
<inventory tool>
# 2. Protocol consistency — cross-schema, manifest, generated-doc parity
<protocol-consistency tool>
# 3. Conflict detection — overlap, imperatives, code duplication
<conflict tool> --conflicts
# 4. Routing gaps (last 7 days)
<routing-gap tool> --since 7d
# 5. Drift sentinel — truth-source hashes, mirror parity
<drift tool>
# 6. Regenerate manifest + index from the now-clean tree
<manifest generator> --write
Review the output of steps 1–5 before running step 6. The manifest and index should reflect a clean state — never write a manifest from a dirty tree.
Adding evals to an existing skill
- Read the skill's existing eval set
- Identify gaps: are all eval types represented? Are there contradiction-checks for documented exceptions?
- Draft new cases with
id, prompt, expected_output, expectations, type, grounding, difficulty
- Ensure every new case has at least one
does not / never / must not expectation
- Append to the eval array — never renumber existing IDs (eval-history logs reference numeric IDs)
- Re-run the inventory tool and verify the skill no longer appears in
belowMinimum or missingNegativeEvalIds
Triaging imperative conflicts
- Run the conflict tool with
--conflicts --json to get the structured list
- For each conflict, identify which skill's instruction is more precise or more scoped
- Resolve by narrowing scope, not by deleting the instruction:
- "Use X" → "Use X in app code" (narrower)
- "Always use X" → "Always use X for tenant-scoped data" (specific)
- Move the negative instruction to an anti-patterns table row that does not start with "Use"
- Add an inline qualifier (e.g.
// system: <reason>) that the detector can distinguish
- Re-run
--conflicts to confirm the conflict is gone
- Document the resolution in a conflict log so future audits know it was deliberate
Fixing invalid frontmatter
| Problem |
Fix |
scope field absent |
Add the correct value (portable / reference / codebase) |
drift_check.last_verified absent or stale |
Add or update to today's ISO date |
eval_artifacts absent |
Set to present if eval files exist, planned if intended, none otherwise |
keywords empty or short |
Add 5–15 natural-language phrases users would actually type |
description too short |
Quote it; require ≥ 100 chars; include trigger phrases and a "Do NOT use for X (use Y)" exclusion |
version absent |
Set to 1.0.0 for new skills; bump per semver on substantive change |
After editing, re-run the inventory tool and confirm the skill no longer appears in the invalid-frontmatter list.
Anti-Patterns
| Anti-pattern |
Why it fails |
What to do instead |
| Running manifest-write on a dirty skill tree |
Writes a broken index that downstream consumers trust |
Fix all inventory errors first, then regenerate |
| Resolving conflicts by deleting one instruction |
Removes useful guidance the agent needs in the right scope |
Narrow the scope of the instruction instead |
| Adding evals without negative expectations |
Census flags them; they test only happy paths |
Every eval must have at least one does not / never / must not expectation |
| Renumbering eval IDs during cleanup |
Breaks eval-history references that use numeric IDs |
Always append; never renumber |
| Un-backticking an identifier to suppress a false positive when the conflict is real |
Hides a real boundary ambiguity |
Fix the skill wording to accurately reflect the scope |
| Adding routing keywords without a real skill to route to |
Creates more broken mappings |
Only add keywords that map to an existing skill |
| Treating heading overlap as always wrong |
Structural-template skills (model profiles, integration patterns) legitimately share structure |
Review the differentiating content instead of restructuring |
Using scope: reference to mask threshold violations |
Reference scope downgrades eval-error to warning, hiding real gaps |
Use reference only for genuine reference docs (contracts, schemas), never to dodge threshold enforcement |
| Producing a thin audit summary after a multi-hour session |
A two-hour audit that outputs "5 entities missing evals" has performed a census, not an audit — 95% of the invested tokens are wasted |
Census counts things; audits verify claims against evidence. Every audited skill needs per-claim verdicts (verified / drift) referencing specific file:line evidence |
| Running a "skill loop" without a minimum-output specification |
Agents read methodology sections but skip output-format sections, then produce free-form summaries |
Before any audit/eval/improvement session, define the output format up front. Templates exist — use them |
| LLM-based health checks instead of deterministic ones |
Probabilistic grading of probabilistic content is circular and unreliable |
Health-tooling layer is zero-LLM by design. LLMs grade task output, not skill metadata |
Verification
Before any batch skill commit, verify:
Do NOT Use When
| Use instead |
When |
skill-scaffold |
Authoring or restructuring a single new SKILL.md (the contract for one file, not the system around the library) |
graph-audit |
Running the conformance audit on this Skill Graph repo specifically (operational), not designing the discipline |
lint-overlay |
General-purpose lint-rule selection and gate placement for any codebase, not skill-system-specific tooling |
documentation |
Writing prose for a human reader explaining how the skill system works |
code-review |
Reviewing a code change to the health-tooling scripts themselves |
testing-strategy |
Designing the test pyramid / trophy / honeycomb shape for a non-skill-library codebase |
prompt-craft |
Improving the wording of a single skill's prompt or eval prompt |
1---2name: skill-infrastructure3description: Use when designing the deterministic health-tooling layer for a skill library, diagnosing why an existing library is decaying invisibly, deciding which categories of automated check to add (inventory, protocol consistency, conflict detection, routing health, drift sentinel), debugging eval-threshold violations across many skills at once, or auditing whether a skill-system has the safety nets a production library needs. Covers the five categories of skill-health tooling, the library-as-database mental model, eval quality patterns (minimum thresholds, contradiction-check pattern, negative-expectation requirement), maintenance workflows triggered by batch skill changes, and the anti-patterns that cause skill libraries to decay until agents loading them get worse over time. Do NOT use for authoring an individual SKILL.md (use `skill-scaffold`), for running the conformance audit on the Skill Graph repo itself (use `graph-audit`), or for general lint rule selection across a codebase (use `lint-overlay`).4license: MIT5---6
7# Skill Infrastructure
8
9## Coverage
10
11- The library-as-database mental model: skill-infrastructure as the linter, integrity checker, and query planner for a SKILL.md library
12- Why deterministic, zero-LLM tooling is mandatory for skill libraries (trustworthy enough for CI gates; LLM-based health checks are circular)
13- The five categories of skill-health tooling: (1) inventory and frontmatter validation, (2) protocol consistency, (3) conflict detection (overlap, imperative, code duplication, heading overlap), (4) routing health (gap analysis, miss tracking), (5) drift detection (truth-source hashing, mirror parity)
14- Eval quality patterns: minimum eval threshold per skill, the contradiction-check eval type, the negative-expectation requirement, valid eval-type taxonomy
15- Imperative conflict detection: the same-target-opposite-polarity rule, three-check false-positive suppression, when conflicts indicate scope-tightening vs merging
16- Routing gap analysis: how to read a "routing-misses" log, how to distinguish keyword gaps from skill content gaps, signal-hygiene rules to suppress noise
17- Maintenance workflows: when to run a full health check, the order in which to run the categories, what to fix before what
18- Anti-patterns that cause invisible decay: dirty-tree manifest writes, deletion-as-conflict-resolution, eval-renumbering during cleanup, scope misuse to mask threshold violations
19- The verification gate before any batch skill commit: every category clean, every new skill meets eval minimums, every routing change is reflected in the manifest
20- Package and workspace-root integrity: the npm CLI entrypoint must dispatch to the same scripts as local development while resolving schemas from the package and skills/manifests from the caller workspace
21
22## Philosophy
23
24A skill library is only as useful as its worst skill. When agents load stale, conflicting, poorly-routed, or mirror-drifted skills, they get *worse* at tasks — not better. A skill library at scale (50+, certainly 200+) decays invisibly: eval counts drift below minimums, keyword maps miss whole product areas, mirror copies fall out of sync, and two skills start giving opposite instructions for the same function.
25
26The infrastructure exists to catch that decay deterministically, with **zero LLM calls**. Every health check reads files, parses structure, and computes — it does not reason, infer, or hallucinate. That makes the output trustworthy enough to use in CI-style gates. An LLM-based health check is circular: the same probabilistic component that produces the skill library cannot reliably grade its own output.
27
28> If the skill library is a codebase, skill-infrastructure is its combined linter, type-checker, and dead-code detector — always-on, zero-model, CI-safe.
29
30The maintenance commitment is: run a full health check after any batch skill work, fix threshold violations before they reach the gate, and document conflicts before the agents loading those skills are affected.
31
32## The Library-as-Database Mental Model
33
34Treat the skill library as a database and skill-infrastructure as its query planner, integrity checker, and migration-safety net combined.
35
36| Database concept | Skill-library equivalent |
37|---|---|
38| Schema | SKILL.md frontmatter schema (JSON Schema or equivalent) |
39| Constraints | Required fields, eval thresholds, valid enum values |
40| Foreign keys | `relations.boundary[]`, `relations.related[]` targets — must point at real skills |
41| Indexes | Manifest, routing-keyword map, path-glob inverse index |
42| Integrity check | Protocol-consistency tooling (cross-schema parity, sample correctness, generated-field parity) |
43| Query planner | Skill router (matches user prompt → skill activation) |
44| Replication lag | Mirror parity (`.claude/skills`, `.agents/skills`, harness-specific copies) |
45| Dead code | Skills with broken relation targets, phantom routing entries |
46
47Every script in this domain reads files and computes — it does not reason. Output is deterministic, reproducible, and safe to embed in CI gates.
48
49## The Five Categories of Skill-Health Tooling
50
51A production skill library needs all five. Missing any one allows a class of decay through.
52
53### 1. Inventory and Frontmatter Validation
54
55Walks the skill tree, parses every SKILL.md's frontmatter, and validates against the schema.
56
57| Check | Why it matters |
58|---|---|
59| Required fields present (`name`, `description`, `version`, `type`, `scope`, `owner`, `freshness`) | Missing fields break the manifest generator and the router |
60| Field-value enums valid (`type`, `scope`, `eval_state`) | Drift in valid values leaks invalid skills into routing |
61| Description-length and quality (≥ 100 chars, contains "Use when X / Do NOT use for Y") | Short or vague descriptions degrade router precision |
62| Eval-count per skill (warn at < 7, error at < 3 for non-reference skills) | Under-evaluated skills regress quality undetected |
63| Reference-path resolution (every `references/X.md` cited in frontmatter actually exists) | Dangling references mislead the agent at activation time |
64| Scope-grounding consistency (`scope: codebase` requires populated `grounding` block) | Codebase claims without grounding can hallucinate file paths |
65
66**Reference implementation:** `scripts/skill-lint.js` in this repo runs T5 per-skill lint covering most of these.
67
68### 2. Protocol Consistency
69
70Cross-checks that the schema, generator, sample manifest, and field-reference docs all agree.
71
72| Check | Failure mode if missing |
73|---|---|
74| Cross-schema parity (versioned schemas describe the same fields) | Schema bumps silently drop fields |
75| Authored-to-generated parity (frontmatter fields match what the generator emits) | Generator drift breaks downstream consumers |
76| Sample manifest matches generator output | Sample stales as skills are added |
77| Generated field-reference matches authored field-reference | Documentation drift hides field changes |
78| Truth invariants on example evals (e.g. truth-source line ranges still resolve) | Eval expectations point at non-existent code |
79
80**Reference implementation:** `scripts/check-protocol-consistency.js` runs C1–C7 protocol checks.
81
82### 3. Conflict Detection
83
84Pairwise comparison across all active skills to surface duplication, contradiction, and structural overlap.
85
86| Dimension | Method | Signal |
87|---|---|---|
88| Description similarity | Jaccard on word bigrams | > 0.4 = potential duplicate |
89| Heading overlap | Shared H2/H3 headings excluding boilerplate | High overlap = structural duplication |
90| Code duplication | Identical fenced code blocks > 30 chars | Copy-paste anti-pattern |
91| Imperative conflicts | Same target, opposite polarity (ALWAYS vs NEVER) | Agents get contradictory instructions |
92
93**Imperative extraction patterns:**
94
95- Positive: `\b(?:always|must|required|mandatory)\b\s+(.{10,80})/gi`, `\buse\s+(.{5,60})\s+(?:for|when|instead)/gi`
96- Negative: `\b(?:never|do\s+not|don't|must\s+not|prohibited)\b\s+(.{10,80})/gi`, `\bdo\s+NOT\s+use\s+(.{5,60})/gi`
97
98**Three-check false-positive suppression** for the most common phantom-conflict sources (e.g. `Do NOT use X` matching as positive `use X`):
99
1001. **Lookbehind check** — if `not`, `never`, `don't`, or `cannot` appears in the 20 characters before a positive match, suppress it
1012. **Within-match check** — if `not` appears between the start of the match and the target identifier (extracted via backticks), suppress it
1023. **Same-line dedup** — if the target was already extracted as a negative on the current line, suppress any positive extraction for that target
103
104**When a conflict is real vs spurious:**
105
106| Conflict type | Resolution |
107|---|---|
108| Phantom ref | Routing config maps to a non-existent skill — delete the stale entry |
109| Code duplication | One skill owns the example; the other links to it |
110| Heading overlap | Acceptable for structural templates; review only the differentiating content |
111| Imperative conflict (real) | Scope the instructions more precisely (`always use X` → `always use X in app code`); rarely merge skills |
112| Imperative conflict (spurious) | Un-backticking an identifier hides a real boundary ambiguity — fix the skill wording instead |
113
114### 4. Routing Health
115
116Reads the routing-miss log and the routing config to identify where the keyword map fails.
117
118| Input | Purpose |
119|---|---|
120| Routing-misses log (queries that matched zero skills) | Surface keyword gaps — words users typed that never reached a skill |
121| Eval-history log with `failure_category` | Surface skills failing for reasons routing can fix (`skill_not_activated`, `wrong_answer`) |
122| Active routing config (`keywordMap`, `labelMap`) | Authoritative truth for what currently routes |
123
124**Output sections:**
125
1261. **Keyword gaps** — words appearing in routing-misses but absent from the active keyword map, sorted by frequency
1272. **Eval failure breakdown** — skills with 2+ failures, grouped by failure category
1283. **Suggested actions** — `add_keyword` for frequent gaps; `improve_skill` for skills failing for content reasons
129
130**Signal hygiene rules** (suppress these from the suggestion list):
131
132- Low-signal tokens (`v`, `v4`, `skill`, `start`, `events`, `daily`, `log`, `status`, `health`)
133- Single-word misses already covered by an existing multi-word phrase (e.g. `error` should not surface if `error recovery` is already mapped)
134- Stale historical misses where the full query already routes under the current config
135- Synthetic no-match probes used to verify the router's miss path
136- Bundle entries (only direct `keywordMap` entries participate in free-text matching)
137
138**Reference implementation:** the routing harness (`scripts/skill-graph-routing-eval.js` in this repo) provides the negative case — verifying that a skill's authored `examples` actually route to it. A real routing-gap report is the symmetric positive case (verifying that real user prompts reach a skill).
139
140### 5. Drift Detection
141
142Detects when the *world the skill claims* has changed without the skill being updated.
143
144| Drift type | Detection |
145|---|---|
146| Truth-source drift | `drift_check.truth_source_hashes` records SHA-256 of cited files; rerun hashes; mismatch = drift |
147| Mirror parity | Hash every `<library>/skills/<name>/SKILL.md` and every `<harness-mirror>/skills/<name>/SKILL.md`; mismatch = drift |
148| Stale `freshness` date | Skill has not been touched in > `lifecycle.stale_after_days`; surface for review |
149| Tracker → skill drift | Issue tracker references a skill that no longer exists; or skill references a closed issue |
150
151**Reference implementation:** `scripts/skill-graph-drift.js` in this repo records and verifies truth-source hashes against the live files.
152
153## Eval Quality Patterns
154
155### The minimum-threshold rule
156
157Every active skill should have at least 7 evals. Most healthy skills carry 9–15 covering happy paths, edge cases, anti-patterns, and contradiction checks. The threshold is a *floor*, not a goal.
158
159**Recommended enforcement:**
160
161- **Error** if `eval_count < 3` (or **warn** for `scope: reference` skills, where the file is documentation more than testable behaviour)
162- **Warn** if `eval_count < 7`
163
164Below 7, the skill is statistically under-tested. Below 3, it is effectively un-evaluated.
165
166### The contradiction-check eval type
167
168A `contradiction-check` eval tests that the agent correctly handles a documented exception or boundary condition that a simpler reading of the skill would mishandle. Format:
169
170```json
171{
172 "id": 5,
173 "type": "contradiction-check",
174 "grounding": "repo-specific",
175 "difficulty": "adversarial",
176 "prompt": "Skill A says always use the scoped fetcher. One service uses the unscoped fetcher with an inline comment. Is this wrong?",
177 "expected_output": "Not wrong — the unscoped fetcher with an inline justification comment is the documented exception for system-level reads.",
178 "expectations": [
179 "Correctly identifies the documented exception from the skill's anti-patterns table",
180 "Does NOT flag the usage as a bug without reading the inline comment",
181 "Distinguishes a system-level exception from a regular violation in application code"
182 ]
183}
184```
185
186Use a contradiction-check when:
187
188- A skill has a documented exception that overrides the general rule
189- Two adjacent skills appear to contradict each other but actually operate in different scopes
190- A historical false positive or conflict was resolved and the resolution is non-obvious
191
192### The negative-expectation requirement
193
194Every eval case with an `expectations` array must include at least one expectation containing `does not`, `never`, `must not`, `should not`, or `do not`. Without this, evals become pure happy-path tests and miss the failure modes that motivated the skill.
195
196**Recommended enforcement:** the inventory tool flags any eval missing this pattern in a `missingNegativeEvalIds` field of its report.
197
198### Valid eval types
199
200| Type | When to use |
201|---|---|
202| `knowledge` | Tests a factual claim or pattern from the skill |
203| `contradiction-check` | Tests documented exceptions and boundary conditions |
204| `browser` | Tests a browser-executable interaction (requires running server) |
205| `edge-case` | Tests unusual inputs or rare conditions |
206| `business-model` | Tests domain-specific logic (e.g. SaaS billing rules, e-commerce fulfilment) |
207| `negative` | Tests refusal or correct non-action |
208
209## Maintenance Workflows
210
211### The full health check sequence
212
213Run after any batch skill work — creating ≥ 3 skills, changing routing config, or modifying skill content across multiple files. Order matters:
214
215```bash
216# 1. Inventory snapshot — discover invalid frontmatter, missing fields, broken refs
217<inventory tool>
218
219# 2. Protocol consistency — cross-schema, manifest, generated-doc parity
220<protocol-consistency tool>
221
222# 3. Conflict detection — overlap, imperatives, code duplication
223<conflict tool> --conflicts
224
225# 4. Routing gaps (last 7 days)
226<routing-gap tool> --since 7d
227
228# 5. Drift sentinel — truth-source hashes, mirror parity
229<drift tool>
230
231# 6. Regenerate manifest + index from the now-clean tree
232<manifest generator> --write
233```
234
235Review the output of steps 1–5 before running step 6. The manifest and index should reflect a clean state — never write a manifest from a dirty tree.
236
237### Adding evals to an existing skill
238
2391. Read the skill's existing eval set
2402. Identify gaps: are all eval types represented? Are there contradiction-checks for documented exceptions?
2413. Draft new cases with `id`, `prompt`, `expected_output`, `expectations`, `type`, `grounding`, `difficulty`
2424. Ensure every new case has at least one `does not / never / must not` expectation
2435. **Append** to the eval array — never renumber existing IDs (eval-history logs reference numeric IDs)
2446. Re-run the inventory tool and verify the skill no longer appears in `belowMinimum` or `missingNegativeEvalIds`
245
246### Triaging imperative conflicts
247
2481. Run the conflict tool with `--conflicts --json` to get the structured list
2492. For each conflict, identify which skill's instruction is more precise or more scoped
2503. Resolve by *narrowing scope*, not by deleting the instruction:
251 - "Use X" → "Use X in app code" (narrower)
252 - "Always use X" → "Always use X for tenant-scoped data" (specific)
253 - Move the negative instruction to an anti-patterns table row that does not start with "Use"
254 - Add an inline qualifier (e.g. `// system: <reason>`) that the detector can distinguish
2554. Re-run `--conflicts` to confirm the conflict is gone
2565. Document the resolution in a conflict log so future audits know it was deliberate
257
258### Fixing invalid frontmatter
259
260| Problem | Fix |
261|---|---|
262| `scope` field absent | Add the correct value (`portable` / `reference` / `codebase`) |
263| `drift_check.last_verified` absent or stale | Add or update to today's ISO date |
264| `eval_artifacts` absent | Set to `present` if eval files exist, `planned` if intended, `none` otherwise |
265| `keywords` empty or short | Add 5–15 natural-language phrases users would actually type |
266| `description` too short | Quote it; require ≥ 100 chars; include trigger phrases and a "Do NOT use for X (use Y)" exclusion |
267| `version` absent | Set to `1.0.0` for new skills; bump per semver on substantive change |
268
269After editing, re-run the inventory tool and confirm the skill no longer appears in the invalid-frontmatter list.
270
271## Anti-Patterns
272
273| Anti-pattern | Why it fails | What to do instead |
274|---|---|---|
275| Running manifest-write on a dirty skill tree | Writes a broken index that downstream consumers trust | Fix all inventory errors first, then regenerate |
276| Resolving conflicts by deleting one instruction | Removes useful guidance the agent needs in the right scope | Narrow the scope of the instruction instead |
277| Adding evals without negative expectations | Census flags them; they test only happy paths | Every eval must have at least one `does not / never / must not` expectation |
278| Renumbering eval IDs during cleanup | Breaks eval-history references that use numeric IDs | Always append; never renumber |
279| Un-backticking an identifier to suppress a false positive when the conflict is real | Hides a real boundary ambiguity | Fix the skill wording to accurately reflect the scope |
280| Adding routing keywords without a real skill to route to | Creates more broken mappings | Only add keywords that map to an existing skill |
281| Treating heading overlap as always wrong | Structural-template skills (model profiles, integration patterns) legitimately share structure | Review the differentiating content instead of restructuring |
282| Using `scope: reference` to mask threshold violations | Reference scope downgrades eval-error to warning, hiding real gaps | Use `reference` only for genuine reference docs (contracts, schemas), never to dodge threshold enforcement |
283| Producing a thin audit summary after a multi-hour session | A two-hour audit that outputs "5 entities missing evals" has performed a *census*, not an *audit* — 95% of the invested tokens are wasted | Census counts things; audits verify claims against evidence. Every audited skill needs per-claim verdicts (verified / drift) referencing specific file:line evidence |
284| Running a "skill loop" without a minimum-output specification | Agents read methodology sections but skip output-format sections, then produce free-form summaries | Before any audit/eval/improvement session, define the output format up front. Templates exist — use them |
285| LLM-based health checks instead of deterministic ones | Probabilistic grading of probabilistic content is circular and unreliable | Health-tooling layer is zero-LLM by design. LLMs grade *task output*, not *skill metadata* |
286
287## Verification
288
289Before any batch skill commit, verify:
290
291- [ ] Inventory tool exits with zero critical errors
292- [ ] Zero invalid-frontmatter entries
293- [ ] Zero broken mappings in routing config
294- [ ] All new skills meet the eval minimum (≥ 7, or ≥ 3 with explicit warning acceptance)
295- [ ] All new evals include at least one negative expectation
296- [ ] Conflict tool shows no NEW conflicts vs baseline
297- [ ] Routing-gap report shows no new keyword gaps caused by your changes
298- [ ] Manifest generator completed without errors
299- [ ] Mirror parity verified if the library replicates to multiple harness directories
300- [ ] Skill index header count matches actual skill count
301
302## Do NOT Use When
303
304| Use instead | When |
305|---|---|
306| `skill-scaffold` | Authoring or restructuring a single new SKILL.md (the contract for one file, not the system around the library) |
307| `graph-audit` | Running the conformance audit on this Skill Graph repo specifically (operational), not designing the discipline |
308| `lint-overlay` | General-purpose lint-rule selection and gate placement for any codebase, not skill-system-specific tooling |
309| `documentation` | Writing prose for a human reader explaining how the skill system works |
310| `code-review` | Reviewing a code change to the health-tooling scripts themselves |
311| `testing-strategy` | Designing the test pyramid / trophy / honeycomb shape for a non-skill-library codebase |
312| `prompt-craft` | Improving the wording of a single skill's prompt or eval prompt |