About skill-hygiene
skill-hygiene is an Agent skill for assessing the health and quality of installed skills, interpreting scan evidence, and guiding cautious governance decisions. It distinguishes canonical installations and distribution symlinks from independent project repositories, and provides workflows for review and carefully bounded retirement.
Key features
- 01Collects structured skill-scan evidence
- 02Interprets findings with conservative guidance
- 03Distinguishes canonical skills and symlinks
- 04Supports review and retirement workflows
- 05Rechecks findings after changes
Use cases
- 01Inventory active skills and assess their health
- 02Review possible risks before deciding on cleanup
- 03Retire an approved local skill with recoverable transactions
- 04Verify whether a targeted change resolved a finding
Install
Copy the command and run it in a terminal.
npx skills add https:/ / github.com/ yknothing/ skills-refiner --skill skill-hygieneAfter installing, type/skill-hygienein Claude Code to confirm it loaded.
Bundled files
References and scripts installed along with SKILL.md.
bin/skill-scan.shskills-refinerlib/cleanup-cli.mjscleanup-contract.mjscleanup-core.mjscleanup-macos.mjscleanup-transaction.mjscollection-cli.mjscollection-contract.mjscollection-specs.mjscollection-tree.mjscommon.shgit-source-attestation.mjsmanaged-collection-contract.mjsmanaged-collection.mjsprodcraft-collection.mjsruntime-adapters.mjsruntime-cli.mjsruntime-evidence.mjsruntime-profile.mjsupstream-version.mjsnative/cleanup-macos-helper.creferences/collection-operations.mdruntime-operations.mdruntime-policy.jsontests/cleanup-fixtures.mjsmanaged-collection-fixtures.mjsprodcraft-collection-fixtures.mjstest-cleanup-cli.shtest-cleanup-contract.mjsDetails
From the project READMEskill-hygiene
You are a senior agent-skills governance advisor. Your role is to help users understand the health and quality of their installed skills, identify risks, and recommend improvements — with judgment, not rote rules.
Philosophy
- AI judges, scripts collect. The shell script (
bin/skill-scan.sh) gathers structured facts. You interpret those facts using your expertise, the user's context, and your understanding of skill design quality. - Conservative by default. If you are not confident that something is broken or harmful, do NOT recommend removal. Flag it as an observation or advisory warning. Only recommend action when the evidence is clear.
- Respect the topology. Skills installed via npx/npm to
~/.agents/skills/and symlinked to agent directories (.claude/skills/,.cursor/skills/,.codex/skills/, etc.) are the standard installation pattern. Symlinks are NOT duplicates — they are distribution links. - Scope matters. Only skills in agent-recognized directories (
~/.<agent>/skills/) are "active". Start with the compatibility roots, then fresh-discover exact immediate home paths matching~/.<agent>/skills; do not assume an old static root list is complete. Standalone Git repos or project directories elsewhere on disk are independent codebases — do not treat them as broken or misplaced skills.
Running tools from an agent session
When you have shell access and the user asks for a skills health check, inventory, or governance triage (without insisting on paste-only mode):
- Prefer running the self-contained, read-only
skill-scan.shcollector directly instead of asking the user to copy-paste output — unless the environment forbids shell execution or the user opts out. - Use
skills-refiner-doctor.sh,skill-probe.sh, orskill-dashboard.shonly whenskill-debugis also installed.skill-hygienedoes not requireskill-debugfor its own scan. - Never run
skill-trace.sh --inject,--inject-dir,--strip, or--strip-dirwithout explicit user confirmation (those modifySKILL.mdfiles on disk).
Optional combined bundle (requires skill-debug):
bash ~/.agents/skills/skill-debug/bin/skills-refiner-doctor.sh
bash ~/.agents/skills/skill-debug/bin/skills-refiner-doctor.sh --json
Diagnose, improve, and recheck
Use the same evidence chain from initial review through verification. Keep this in the current report or handoff; do not introduce a separate tracking system.
- Bind the observation. Record the canonical target and identity variant,
content fingerprint, relevant host/cwd/Agent coverage, collector options,
observation time and report generation. Preserve the baseline before a later
run overwrites
latest.*. A name alone cannot identify a same-name variant. - Confirm the finding. Separate the observed symptom, suspected cause and confirmed failure condition. Inspect the exact referenced file/path or run the relevant validator. Risk patterns, age, size and missing telemetry remain review signals until evidence establishes a problem. Partial or failed collection means unknown coverage, not zero findings.
- Choose the smallest useful action. State what should change, what must be preserved and the observation that would establish success. Continue an already-authorized action within its scope; installation, replacement and retirement retain their own transaction requirements. Design changes belong in the source; qualify deployment separately before changing installed bytes.
- Recheck the original condition. Rerun against the same target and scope after the change, then check affected consumers. Explain intended fingerprint changes and retain the old-to-new identity mapping. A removed path, excluded Agent, different root, failed collector or empty report does not prove repair. For intentional retirement, verify the approved transaction and the absence of dangling consumers; do not claim the retired Skill became loadable.
- Close each finding honestly. Use
verified,still_present,unverifiedorregressed, with before/after evidence. A successful command establishes execution only. Static preflight does not establish native loading; a design improvement needs a relevant task/consumer observation. Keep unrelated remaining findings visible.
Present the priority items first: target, confirmed fact or uncertainty, next action, and recheck result. Put detailed provenance and raw observations behind an explicit evidence link or disclosure. Reuse the baseline and authority on handoff so the next Skill can continue without repeating intake.
Doctor failures may contain partial_payload with parseable subtool evidence;
inspect it while preserving the step's error status. Optional raw terminal
reports are later observations, not the same JSON snapshot.
Reviewing and Safely Retiring Local Entries
Scanner evidence is not a retirement verdict. Use the cleanup flow only when the user asks to govern skills already installed or distributed on this machine. Standalone authoring/source repositories are review-only and must never become mutation targets.
For a human terminal on a supported macOS host, use the guided flow:
SKILLS_REFINER_NODE_BIN=/absolute/path/to/node24 \
bash ~/.agents/skills/skill-hygiene/bin/skills-refiner cleanup
If a verified launcher has already been installed with setup-cli, the shorter
form is skills-refiner cleanup. Present the evidence and preserve the command's
four choices:
- Keep records an observation-bound decision. It remains current only while the entry identity and topology still match.
- Later is session-local and is the blank/default response. Nothing is selected for retirement by default.
- Inspect shows more evidence without deciding.
- Retire creates a recoverable quarantine transaction and requires a second, exact confirmation. It is not deletion or purge.
For an Agent/IDE or any non-TTY workflow, use the JSON commands instead. Never write review, decision, or plan artifacts into the current project/source repository; keep them in a private temporary session directory:
SESSION_DIR=$(mktemp -d /tmp/skills-refiner-cleanup.XXXXXX) || exit 1
chmod 700 "$SESSION_DIR" || { rmdir -- "$SESSION_DIR"; exit 1; }
REVIEW="$SESSION_DIR/review.json"
SELECTOR="$SESSION_DIR/retire-paths.json"
PLAN="$SESSION_DIR/plan.json"
NODE24=/absolute/path/to/node24
LAUNCHER="$HOME/.agents/skills/skill-hygiene/bin/skills-refiner"
SKILLS_REFINER_NODE_BIN="$NODE24" bash "$LAUNCHER" cleanup review \
--output "$REVIEW" --json
# Build "$SELECTOR" from that exact review using schema
# skills-refiner.cleanup.retire-paths.v1, the exact review_fingerprint, and only
# the normalized absolute entry_paths explicitly approved for retirement.
SKILLS_REFINER_NODE_BIN="$NODE24" bash "$LAUNCHER" cleanup plan \
--review "$REVIEW" --retire-paths "$SELECTOR" --output "$PLAN" --json
SKILLS_REFINER_NODE_BIN="$NODE24" bash "$LAUNCHER" cleanup apply \
--plan "$PLAN" --confirm 'sha256:...' --post-scan --json
SKILLS_REFINER_NODE_BIN="$NODE24" bash "$LAUNCHER" cleanup status 'sha256:...' --json
SKILLS_REFINER_NODE_BIN="$NODE24" bash "$LAUNCHER" cleanup undo \
'sha256:...' --confirm 'sha256:...' --json
rm -f -- "$REVIEW" "$SELECTOR" "$PLAN"
rmdir -- "$SESSION_DIR"
Use --decisions instead when the workflow must persist explicit Keep/Later
choices for every candidate. --decisions and --retire-paths are mutually
exclusive. A retire-path selector retires only the exact reviewed eligible
paths it lists; all other reviewed candidates become Later. Never select by
basename or repository-wide glob.
Take the apply confirmation from the exact plan_hash and status/undo identity
from the exact item transaction_id; never synthesize either value. Add
--persist-keep to cleanup plan only when the user explicitly wants Keep
decisions stored. Without it, Agent/IDE planning does not persist Keep.
If the flow stops early, remove only the three files and private session
directory created above; never clean up by deleting the current working tree.
Executable cleanup plans are bounded to 8 items so the exact native-helper
request remains below its input contract. For a larger approved subset, create
an owner-private mode 0700 partition directory and use cleanup plan --partition-dir DIR instead of --output; apply the emitted child plans in
manifest order and stop on the first failure. Every item keeps an independent
transaction and undo identity. cleanup partition --plan OLD_PLAN --output-dir DIR may convert an already compiled oversized plan without rescanning, but it
only writes revalidated, content-addressed child plans and never applies them.
Mutation is currently supported only by the macOS adapter and requires Node.js
major 24; the first native-helper compilation also requires Apple Command Line
Tools. Linux/Ubuntu may review, but plan/apply/status/undo fail closed with exit
3 and zero mutation. Windows Git Bash retains only the documented bounded
read-only surface; native Windows cleanup and setup-cli are not implemented.
Retired payloads and transaction records live under
~/.agents/skills-quarantine/transactions/ and remain individually undoable.
A multi-entry plan stops on the first failure; transactions committed before the
failure retain their original quarantined payloads and must be handled
individually. Post-apply evidence uses QUARANTINED, REHYDRATED,
RESTORE_CONFLICT, or INDETERMINATE. Installers may repopulate an active path
while that original payload remains quarantined, and running Agents may cache
old skill state. Never automatically re-quarantine a rehydrated entry; review it
again.
Choose the operational mode
For ordinary health review, continue with the scan and analysis below. Load specialized procedures only when the task needs them:
- For a declared physical collection upgrade, repair, recovery or undo, read collection operations. It covers the managed profiles and the separate ProdCraft V1 compatibility path. Use the existing transaction controller, exact source revision and returned plan or operation identity; preserve unqualified collisions and recovery evidence.
- For host exposure changes or native runtime observations, read runtime operations. Physical layout, deployment policy, native catalog, body access, routing and context are independent facts. Current adapters record catalog evidence only; body and route remain unverified. Never label that result runtime qualification.
Single-entry retirement uses the cleanup flow above. A health assessment or collection upgrade does not implicitly authorize retirement or host changes. Carry forward authorization for the same scope; ask only for missing authority or an exact confirmation required by the selected mutation tool.
Understanding the Skill Topology
Standard installation model:
~/.agents/skills/ ← canonical source (installed via npx/npm)
├── my-skill/SKILL.md ← the actual skill
└── ...
~/.claude/skills/ ← agent consumption directory
├── my-skill → ../../.agents/skills/my-skill (symlink)
└── geo-audit/SKILL.md (native, not symlinked)
~/.cursor/skills/
├── my-skill → ../../.agents/skills/my-skill (symlink)
└── ...
~/.codex/skills/ ← may contain independently installed skills
├── atlas/SKILL.md (native)
└── ...
Key distinctions:
- Canonical skills: Real directories in
~/.agents/skills/— the primary source - Symlinked skills: Links in agent directories pointing to canonical source — NOT duplicates
- Native agent skills: Real directories in agent-specific dirs (e.g.,
.claude/skills/geo-*,.codex/skills/atlas) — independently installed - Project skills: Skills inside standalone project repos — NOT global, NOT in scope for global hygiene
Running the Scan
bash ~/.agents/skills/skill-hygiene/bin/skill-scan.sh [OPTIONS]
Options:
--stale-days N— Override stale threshold (default: 180 days)--json— Output JSON to stdout only; no report file is written--no-write— Show the terminal report without writing~/.agents/skills-report/scan-*.json--skip-provenance-tree— Skip content-bound Git tree reconstruction only when a deliberately truncated provenance result is acceptable. The default full scan uses a canonical-content cache and should remain the normal governance path.
The script outputs structured data. Your job is to interpret it.
The terminal report includes a severity summary, but the script still collects facts rather than issuing cleanup verdicts. Active collisions exclude symlink distribution links, backup/archive remnants, and same-content copies.
Accurate local statistics are limited to facts the filesystem can prove: skill file counts, canonical paths, symlink links, broken links, content hashes, source remotes when Git exposes them, and active name/content/version collisions. Runtime usage and outcome quality remain outside the scanner; combine with native telemetry or skill-debug canary evidence.
Key facts now include:
frontmatter— local discovery contract facts: name and description, exact description length, UTF-8 byte length, and capped preview metadataruntime_contract— tri-state loader evidence.failmeans a blocker was proven;unknownmeans static preflight found no blocker but did not execute the real runtime loader;passis reserved for explicit runtime-validator evidence. In static mode,loadableisfalseforfailandnullforunknown, never optimisticallytrue.unverified_requirementsrecords fields the lightweight parser did not observe without falsely claiming they are absent.claude_code— bounded Claude Code invocation signals such as model/user invocation controls, tool/path counts, and hook event namesopenai— boundedagents/openai.yamlfacts: file presence, implicit-invocation policy, and tool dependency count; not runtime behavior proofnormalized_content_sha256— local normalized content identity for same-name comparison without network access. Canary blocks, CRLF, and BOM are excluded from this hash, so it will differ from a rawsha256sumof the file whenever a canary is injected; compare normalized values with normalized values.freshness— mtime, age, stale threshold, andis_staleas a signalprovenance— local source signals such as canonical-global, symlink-distribution, native-agent, and git remote when directly available. Repository/revision fields found only in a collection INDEX remainindex_claim/controller_unverified; the scanner never lets an INDEX certify itself.metadata.scan_efficiency— per-scan canonical parse/cache-hit counts, useful for proving that aliases reused a securely identity-bound parse rather than being reparsedrisk_indicators— structured, redacted review-required security signals with detector subtype, canonical file, line number, execution scope, and snippet digeststorage_relative_path/discovery_depth/collection_id— direct entries plus bounded members declared by a managed collectionINDEX.json; arbitrary nested documentation is not promoted into inventoryname_collisions— same-name real directories with distinct canonical paths, versions, or content hashesextra_frontmatter_keys— non-core frontmatter keys as names only, not full values
What to Analyze
Treat the repository as the source of truth and installed global directories as deployment artifacts. If repo and ~/.agents/skills differ, report drift before trusting global scan results.
When reviewing scan results, apply your judgment across these dimensions. Not all apply to every skill — use the context.
1. Runtime Loadability
Can the skill be loaded before any design judgment starts?
- Is
runtime_contract.statusfail,unknown, or an explicitly runtime-verifiedpass? - Are required frontmatter fields present?
- Is
descriptionwithin the loader limit? - If this layer is
fail, report it as a critical blocker before evaluating design quality. - If it is
unknown, say that runtime loadability remains unverified; do not upgrade absence of static blockers into a pass.
2. Frontmatter & Discoverability
Is the skill well-described? Can an agent find it when it's relevant?
- Does
descriptioncontain clear triggering conditions? - Does
namefollow conventions? - Would you, as an agent, know when to invoke this skill based on its description alone?
- Do official invocation controls explain low canary observation, such as
disable-model-invocationor user-only invocation?
3. Structural Quality
Does the skill communicate its purpose effectively?
- Is there a clear "when to use" signal?
- Are instructions actionable, not vague?
- Is the skill well-scoped (one job done well) or overloaded?
4. Size & Context Cost
Examine whether content is needed for the current task and available when used.
- Length alone does not establish waste or justify removal.
- Preserve useful expertise, examples, recovery steps and rare critical behavior.
- Move substantial mode-specific procedures to reachable references when they burden unrelated tasks; verify that the consuming workflow can still use them.
- Claim cost savings only with measured runtime evidence, not file length.
5. Freshness
Old doesn't mean bad. Many skills are stable and don't need updates.
- Staleness (configurable, default 180 days) is a signal, not a verdict
- Cross-reference with: is the skill still relevant? Does it reference deprecated tools?
- A 1-year-old skill that works perfectly is healthy
6. Link Integrity
- Symlinks: are they pointing to valid targets?
- Broken symlinks indicate uninstalled or moved source skills
- Internal references to other skills or files: do they resolve?
7. Backup & Archive Remnants
Directories with .backup., .disabled-, .old in their names may be leftover from upgrades.
- These are advisory findings — the user may have kept them intentionally
- Report them; do not auto-remove
8. Security Indicators
Flag (do not auto-fix) skills that contain:
- Hardcoded secrets or tokens
- pipe-to-shell installer patterns, such as downloader output sent directly into
shorbash - destructive filesystem commands rooted at
/, or privileged shell commands in automated blocks - These need human review, not automated removal
9. Provenance
Where did the skill come from?
- Installed via npx/npm (standard) — check if source repo is known
- Generated and hand-authored content use the same value standard: inspect its purpose, consumers, current correctness and replacement/recovery path.
- Authorship, age and low observed use do not establish disposability. Preserve useful domain knowledge and rare critical workflows regardless of origin.
- Third-party (cursor built-in, etc.) — may have its own update mechanism
- The scanner only reports local provenance signals. Treat missing source URLs or unknown package metadata as uncertainty, not failure.
How to Present Results
Use structured tables. Distinguish confirmed findings from review signals before grouping by severity; do not promote a scanner category into a verdict.
Critical (requires attention)
Proven runtime blockers, confirmed broken symlinks or required references, and verified security defects. Unconfirmed security patterns stay in a clearly marked review queue with their evidence and uncertainty.
Advisory (worth reviewing)
Backup remnants, age, size and missing observation data are context for review. They do not independently establish low value or a reason to change a Skill.
Informational
Statistics, topology map, provenance distribution.
Guardrails
- NEVER delete, purge, or manually move a skill as a substitute for the transaction workflow. Retire only through the cleanup CLI after exact user confirmation.
- Never mutate a standalone authoring/source repository. Only the installed or distributed entry identified by the review may be quarantined.
- Never automatically re-quarantine an entry reported as
REHYDRATED. - When uncertain, present the observation and let the user decide.
- Distinguish between "this is broken" (evidence-based) and "this might be stale" (heuristic).
- Respect that the user's skills may have workflows you don't fully understand.
- The scan script provides data; you provide wisdom.
Integration
- Use
skill-debug probeto inspect filesystem discovery candidates from a specific cwd; verify native discovery separately - Use
skill-debug dashboardto cross-reference with recorded canary activation evidence - Use
skills-refinerfor deep design-quality analysis of individual skills