Raw capture โ raw/drskill.md
url: https://github.com/dbreunig/drskill title: drskill author: dbreunig (David Breunig) date_fetched: 2026-07-25 date_published: 2026-07-25 version: 0.6.2
drskill is brew doctor for your AI coding agent's skill loadout. It is a Python CLI that scans all coding agents detected on a machine or in a repo, resolves each agent's effective skill set and MCP server configurations, and checks the whole set for problems: shadowing, duplicates, description collisions, injection surfaces, broken links, token budget violations, MCP misconfigurations, and tool poisoning. Every problem it reports ends in a fix command or an ack command. It reads files only โ it never installs, edits, or deletes a skill. It makes zero LLM calls unless you opt in, and it never connects to MCP servers unless you opt in.
src/drskill/
__init__.py โ empty
cli.py โ Typer-based CLI (~715 lines): scan, ack, show, review, list, audit, cache, init
models.py โ Pydantic data models: RawInstance, Contributor, Finding, Deployment, etc.
pipeline.py โ Orchestration: run_scan() ties discovery โ resolution โ checks โ deep โ verdicts
discovery.py โ Walks harness search paths to find SKILL.md files and broken symlinks
resolution.py โ build_world(): deduplicates instances, parses frontmatter, marks shadows
harnesses.py โ HarnessDef model + detection: 70+ coding agents defined in data/harnesses.toml
ledger.py โ drskill.toml parsing, ack append (text-preserving), config merging
deep.py โ Deep tier logic: pair keys, verdict cache CRUD, flagged_pairs, apply_verdicts
deep_llm.py โ dspy/LiteLLM integration: judge and rewriter programs, lazy-imported
report.py โ Rich-based terminal rendering of findings and harness tables
tokens.py โ Token counting: tiktoken o200k_base with fallback to len//4
mcp.py โ Static MCP config discovery: 5 config formats, secret detection
mcp_connect.py โ Live MCP handshake: spawns servers, enumerates tools, snapshots
interactive.py โ Terminal keypress reading for `drskill review`
suites.py โ Suite assignment: matches skills to plugin caches on disk
state.py โ Seen-state tracking: which findings the user has already seen
text.py โ Text utilities
checks/
__init__.py โ Check registry, fingerprint(), make_finding(), run_all()
shadowing.py โ name-shadow, double-load
duplicates.py โ exact-duplicate, near-duplicate (MinHash + Jaccard)
spec.py โ SKILL.md spec violations (name mismatch, missing description, etc.)
filesystem.py โ broken-symlink
lockfile.py โ lockfile-drift
budget.py โ budget-catalog-tokens, budget-body-tokens
heuristics.py โ description-overlap, missing-activation, generic-description, opposing-imperatives
injection.py โ 7 injection checks (unicode, encoded-blob, override, remote-fetch, egress, credential-read, mandatory-script)
mcp.py โ Static MCP checks (config, shadowing, divergence, secrets, unpinned, insecure, dead-server)
mcp_tools.py โ mcp-tool-collision, mcp-tools-unreviewed
mcp_injection.py โ mcp-tool-poisoning (scans tool descriptions from committed snapshots)
traces/
__init__.py
model.py โ Invocation data model
common.py โ Shared trace utilities
pipeline.py โ Orchestration for `drskill audit`: discover, extract, filter
cache.py โ Trace extraction cache at ~/.drskill/cache/audit/
claude_code.py โ Claude Code trace parser
codex.py โ Codex trace parser
pi.py โ Pi trace parser
copilot.py โ Copilot trace parser
report.py โ Audit report rendering
data/
harnesses.toml โ Definition table for 70+ coding agents
tests/ โ ~30 test files covering checks, CLI, traces, discovery, MCP, models, etc.
docs/superpowers/ โ Design specs and plans from development
Total project size: approximately 5,000โ6,000 lines of Python (core src), plus ~30 test files.
--mcp-connect): Connects to configured MCP servers, runs the handshake, enumerates tools, writes snapshots. Opt-in.--deep): Sends skill pairs flagged as overlapping to an LLM for judgment. Opt-in, budgeted (default 25 calls).HarnessDef[] โ discover() โ [RawInstance]
โ
harnesses.toml build_world() โ World
โ
run_all() โ [Finding]
โ
ledger.filter_findings() โ active, acked
โ
deep.apply_verdicts() โ reshaped findings
โ
report.render()
Checks are registered via a @check("check-id") decorator. Each check is a pure function (World, Config) -> list[Finding]. The run_all() function imports all check modules (triggering registration), then calls every registered check and merges findings with identical fingerprints.
Every finding carries a fingerprint โ a SHA-256 hash of check_id | sorted(contributor content hashes) | extra_key. An ack silences a finding only while that fingerprint still matches. If a skill's content changes, its hash changes, the fingerprint no longer matches, and the finding resurfaces. This makes acks mean "I've reviewed this exact situation" rather than "never check this pair again."
Deep judgments are stored as JSON files in .drskill/cache/ under the project root (or ~/.drskill/cache/ in global mode). This directory is committed to version control. Every scan reads it, so one person runs the LLM judgments and every teammate and CI run gets the verdicts for free. A verdict lasts until either skill's description changes.
The file data/harnesses.toml defines 70+ coding agents (Claude Code, Codex, Pi, Cursor, Gemini CLI, Cline, Copilot, and ~65 more vendored from vercel-labs/skills). Each entry specifies:
- id, display_name
- project_paths, global_paths โ where skills live
- search_order โ project-first, global-first, or "none" (Codex keeps both copies visible)
- recursive โ whether the harness walks subdirectories
- paths_verified, precedence_verified โ which behavior claims were confirmed against docs/source
- mcp_* โ MCP config file locations and format
A finding's harness list carries ? suffixes for unverified facets that the finding actually depends on. Shadowing depends on precedence; broken symlinks depends only on paths. The uncertainty annotation is precise, not blanket.
Hand-rolled MinHash using zlib.crc32 (not Python's salted hash()). Word shingles of 5 words, 128 hash functions, Jaccard similarity estimate by comparing signature arrays. Default threshold 0.85.
mcp.py:looks_secret() detects credential-shaped values in MCP env blocks using prefix matching (sk-, ghp_, AKIA, etc.), entropy heuristics, and public-material exclusion. The detected value is immediately discarded โ only the variable name appears in models and fingerprints.
Acks are routed based on contributor scope. Machine-level skills (all contributors have scope="user") โ ~/.drskill.toml. Any project-level contributor โ project drskill.toml. Every project scan honors acks from both ledgers, so you decide once per machine. MCP configs use file location to route: home-side files โ machine ledger.
Upstream npx skills computes hashes differently. If none of the hashes in a lockfile match what drskill computes, it won't accuse every skill of drift โ instead it prints one warning saying hashes could not be verified. Per-skill drift warnings only appear once drskill confirms its algorithm agrees with the lockfile producer by matching at least one hash.
All 7 injection checks are static pattern matchers. Each one quotes exact lines from the skill file. Every finding ends with "(static flag: drskill shows the evidence; it cannot verify intent)." The ack ledger is the user's escape hatch. No LLM call is involved.
Specific patterns:
- injection-unicode: Detects bidirectional control characters and zero-width characters (U+200B, U+202A-U+202E, U+2066-U+2069), excluding ZWJ/ZWNJ (used in emoji and writing systems)
- injection-override: 12 regex patterns for instruction-override phrasing like "ignore all previous instructions" or "do not tell the user"
- injection-mandatory-script: Skill text + bundled file name on the same line with mandatory framing ("must first run scripts/x")
- injection-egress: 17 patterns for network calls in script files (not prose): curl, requests.post, fetch(), axios, etc.
- injection-credential-read: References to credential paths (~/.ssh, ~/.aws, .pem) in scripts; .env reads are only a warning
- injection-remote-fetch: Detects curl | sh patterns and "download and follow" directives in skill prose
- injection-encoded-blob: Base64 runs โฅ120 chars or hex runs โฅ129 chars (URLs are stripped first)
The deep tier uses dspy (Stanford's DSPy framework) with LiteLLM for provider-agnostic model access. Two dspy programs: - ConflictJudge: Classifies skill pairs as distinct, description_collision, or scope_overlap - DescriptionRewrite: For collision pairs, rewrites one description to add a distinguishing "use when" condition
The model is configured in the ledger and defaults to anthropic/claude-haiku-4-5. Any LiteLLM-supported provider works.
drskill audit reads local session traces from Claude Code, Codex, Pi, and Copilot to report which skills and MCP tools actually got invoked. It caches extracted data at ~/.drskill/cache/audit/ and provides drill-down showing the user query that triggered each invocation, with exact trace file and line numbers.
--ci flagscan never prompts โ safe for scripts and agentsThe description and instruction checks are heuristic. The thresholds are tuned against real public skill corpora but will miss paraphrased conflicts and flag some judgment calls. The escape hatch is the ack ledger, not more sophisticated detection.
Uses tiktoken's o200k_base encoding โ a reasonable estimate but won't match every harness's actual tokenizer.
Each harness has paths_verified and precedence_verified boolean facets. A finding only inherits the uncertainty it actually depends on. Shadowing depends on precedence โ only precedence-unverified harnesses get ?. Broken symlinks depend only on paths โ only paths-unverified harnesses get ?. This is surgical but vulnerable to harnesses where both facets differ from the default โ the ? tells you "something might be wrong" but not what.
The verdict cache and ack ledger share the same trust model: both are unsigned, so anyone who can commit to the repo can silence a warning through either one. This is acknowledged in the README.
brew doctor which is Mac-specific, drskill is cross-platform and works with any coding agentnpx skills (which installs skills), drskill only reads and reports โ it's the doctor, not the surgeonMalicious Agent Skills in the Wild (which is research measurement), drskill is an operational tool you run in your own repos~30 test files covering: check output validation, CLI behavior, discovery, MCP config parsing, MCP connect, deep mode, trace parsing, interactive mode, smoke tests, conformance tests with fixture skill trees.