Skip to content

j0yen/skill-doctor

Repository files navigation

skill-doctor

Finds the places where a Claude skill's prose has drifted from the tools it tells you to run — a skill that still says pevent gc --dry-run after the binary dropped that flag — and parks each one as a proposal you review by hand.

Why it exists

Skill files are documentation, and documentation rots. A skill cites a command; months later the binary's flags have moved; the skill still says the old thing, and nothing notices until a run fails on a flag that no longer exists. This has happened on this machine more than once.

The fix has two halves. tool-manifest records the ground truth — which subcommands and flags each binary actually accepts. skill-doctor is the consumer: it reads that manifest, walks the skill set, and reports where the prose and the truth disagree.

It proposes; it never edits. Parsing shell out of Markdown produces false positives no matter how careful the extractor is, and skill prose is the kind of thing a human should sign off on before it changes. So detection writes a queue and application stays a separate, deliberate step. Same review-gated shape as recall observe.

Install

Requires cargo / rustc 1.85+ (edition 2024).

git clone https://github.com/j0yen/skill-doctor
cd skill-doctor
cargo build --release
install -Dm755 target/release/skill-doctor ~/.local/bin/skill-doctor

Also installable via the wintermute bootstrap/install.sh.

Quickstart

# Walk the live skill set against the tool-manifest, write new proposals.
skill-doctor check
# → "7 drift findings, 3 new proposals"

# Work the queue.
skill-doctor proposals list
skill-doctor proposals show <ULID>
skill-doctor proposals reject <ULID>
skill-doctor proposals promote <ULID>

check reads ~/.claude/tool-manifest/manifest.json directly — it does not shell out to other binaries in its hot path. If the manifest is absent it prints a pointer to tool-manifest sync and exits 2. Override any of the three paths:

skill-doctor check --skills-root ~/.claude/skills \
                   --manifest ~/.claude/tool-manifest/manifest.json \
                   --proposals ~/.claude/skill-doctor/proposals

promote does not touch the skill file. It marks the proposal promoted and prints the recommended manual edit ($EDITOR +<line> <skill>) for you to apply, then re-run check to confirm the drift is gone.

What counts as drift

check extracts invocations from fenced shell blocks (bash/sh/shell/zsh) and inline backtick code, then classifies each against the manifest:

Drift kind Fires when
BinaryMissing the invoked binary is neither in the manifest nor a stock system tool (git, sed, cargo, …)
SubcommandUnknown the binary exists but the named subcommand is not in its surface
FlagUnknown the subcommand exists but a --flag is not in its accepted set
SkippedVersionOnly a --version/-V-only invocation — informational, never written as a proposal

Stock system tools are excluded from BinaryMissing so the queue fires only for genuinely absent local tools — the false-positive control that keeps the queue worth reading.

The proposal queue

Each proposal is a Markdown file at ~/.claude/skill-doctor/proposals/<ULID>.md with YAML frontmatter — status: pending|rejected|promoted, a content hash, and the source location. The directory is created mode 0700. Re-running check is idempotent: pending proposals are deduped by a hash over (skill_path, line, binary, drift_kind, detail), so the queue does not grow on repeated runs.

Where it fits

Half of a pair. tool-manifest produces the ground truth; skill-doctor consumes it to find skill drift. Decoupling the two lets the same manifest feed other checkers later.

License

Dual-licensed under Apache-2.0 or MIT, at your option.

About

Rust CLI that finds drift between Claude skill prose and installed tool surfaces, and parks review-gated fix proposals.

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors