plugins/workflow/skills/repo-health/SKILL.md
Analyze a repository's configuration against CC and workflow best practices. Use when auditing a repo, after repo-init, or when troubleshooting token usage or workflow gaps. Reports issues by severity with auto-fix offers.
npx skillsauth add rbergman/dark-matter-marketplace repo-healthInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Scan the current repository against CC optimization and workflow best practices. Reports gaps with severity ratings and offers to fix what it can.
Canonical reference: The checks below derive from cc-optimization-playbook.md. When in doubt, the playbook is the source of truth.
Related skills:
Run all checks in order. Collect findings into a report table, then present to user.
Default: Report only. Offer fixes inline — apply only with user confirmation.
Auto-detect from repo contents:
# Language detection
[ -f go.mod ] && echo "go"
[ -f Cargo.toml ] && echo "rust"
[ -f package.json ] && echo "node"
[ -f pyproject.toml ] || [ -f setup.py ] && echo "python"
[ -f mix.exs ] && echo "elixir"
Also detect: monorepo (multiple language markers or packages//apps/ dirs), web framework (.next/, vite.config.*), AI/ML (*.safetensors, models/).
Record detected types for use in subsequent checks.
.claudeignore exists (CRITICAL)Check: file exists at repo root.
If missing → offer to create from universal base + detected language patterns. Use templates from repo-init skill.
If exists → verify it covers:
| Category | Patterns to check | Severity |
|----------|--------------------|----------|
| Secrets | .env, .env.*, .envrc, *.pem, *.key | CRITICAL |
| Lock files | package-lock.json, yarn.lock, pnpm-lock.yaml, Cargo.lock, go.sum, poetry.lock, uv.lock | IMPORTANT |
| Source maps | *.map | IMPORTANT |
| Binary assets | *.png, *.jpg, *.jpeg, *.gif, *.ico, *.svg, *.woff, *.woff2, *.ttf, *.eot | IMPORTANT |
| Build output | Language-specific (node_modules/, target/, dist/, etc.) | IMPORTANT |
| Agent dirs | .worktrees/, .beads/, .timbers/, history/ | IMPORTANT |
Report each missing category separately.
wc -l CLAUDE.md AGENTS.md 2>/dev/null
bytes / 4If both files exist:
readlink CLAUDE.md and readlink AGENTS.mdtest -e <symlink> to verify the target exists. If it does → PASSED ("unified via symlink — zero-maintenance dedup"). If the symlink is dangling → flag as IMPORTANT (broken link masquerading as a passing check).mv CLAUDE.md CLAUDE.md.bak && ln -s AGENTS.md CLAUDE.md after confirming AGENTS.md is canonical) as the preferred fix, with the stub pattern (echo "See @AGENTS.md" > CLAUDE.md) as the fallback for filesystems without symlink support.If ~/.claude/CLAUDE.md exists, check for sections duplicated into the repo's AGENTS.md/CLAUDE.md:
Flag matches as NICE — suggest removing from per-repo file.
.gitignore exists (CRITICAL)Check: file exists. If missing → offer to create from repo-init templates.
.gitignore coverage (IMPORTANT)Verify language-specific patterns are present for detected project type:
| Language | Must include |
|----------|-------------|
| Node/TS | node_modules/, dist/, .next/ (if Next.js) |
| Python | __pycache__/, .venv/, *.pyc |
| Go | vendor/ (if vendoring), bin/ |
| Rust | target/ |
core.hooksPath check (IMPORTANT)git config core.hooksPath 2>/dev/null
Expected: .beads/hooks (relative). Beads 1.0+ owns core.hooksPath and writes shim scripts to .beads/hooks/. Timbers detects this and appends into the same hook files. Quality gates go between the BEADS and TIMBERS marker sections.
Problem values:
.husky/ — husky redirect, migrate away.githooks — old "shared hooks umbrella" pattern (pre-1.0); migrate to .beads/hooks/.beads-hooks/ — old bd hooks install --shared location (pre-1.0); migrate to .beads/hooks//Users/.../.beads/hooks) — breaks worktrees that share repo config; force relative.git/hooks/ (local-only, not shared). Run bd hooks install --force --beads for any beads-using repo.Fix:
# Migrate from husky:
npm uninstall husky && rm -rf .husky && npm pkg delete scripts.prepare
# Migrate from .githooks/ or .beads-hooks/:
git rm -r --cached .githooks/ 2>/dev/null
rm -rf .beads-hooks/ .githooks/
bd hooks install --force --beads
git config core.hooksPath .beads/hooks # force relative
# If timbers is also installed, append its section:
command -v timbers >/dev/null 2>&1 && timbers hooks install
After migration, manually port quality gates (lint-staged, just check, etc.) into .beads/hooks/pre-commit BETWEEN the --- END BEADS INTEGRATION --- line and the --- timbers section --- block. They'll be preserved across reinstalls.
git ls-files | grep -iE '\.env$|\.env\.|\.pem$|\.key$|credentials|secret' 2>/dev/null
If matches found → CRITICAL. Do NOT auto-fix (destructive). Warn user.
command -v bd >/dev/null 2>&1 && echo "installed" || echo "not installed"
[ -d .beads ] && echo "initialized" || echo "not initialized"
bd --version 2>/dev/null
Beads 1.0+ uses embedded Dolt by default — no external dolt binary required, no server daemon to manage. Check:
brew upgrade beads). 1.0 brought auto-export defaults, blessed embedded mode on macOS, hook auto-install, and worktree-aware path resolution. 1.0.4 additionally removes the embedded-mode flock (concurrent bd safe), adds bd -C <path>, and hardens hook auto-import after pull/checkout. bd init --force is deprecated in 1.0.4 → use --reinit-local (with --discard-remote if you mean it).bd hooks list reports shim version older than the installed bd --version: flag as IMPORTANT — run bd hooks install --force --beads to refresh shims.External dolt binary is only needed for repos still in server mode. Server mode is OPTIONAL in 1.0+ — embedded is the default. Migration recipe (server → embedded): bd export -o .beads/issues.jsonl && bd dolt stop && mv .beads/dolt .beads/dolt.server-backup && bd init --reinit-local --discard-remote --from-jsonl --prefix <p> --non-interactive --destroy-token=DESTROY-<p>.
Suggest bd init for project repos. Skip for config/docs-only repos.
When a repo has .beads/issues.jsonl committed but no embedded database (.beads/embeddeddolt/) or server database — the typical fresh-clone state — bd ready and friends will fail with "no beads database found". The fix is not bd init (which mints a new identity and can clobber prefix/metadata) and not bd import (which requires the DB to already exist). The right command is:
bd bootstrap # auto-detects .beads/issues.jsonl, recreates the embedded DB
bd config set beads.role maintainer # or "contributor" for OSS contributors who shouldn't commit beads changes
Detection:
[ -f .beads/issues.jsonl ] && [ ! -d .beads/embeddeddolt ] && [ ! -d .beads/dolt ] && echo "fresh clone — needs bd bootstrap"
If detected → flag as IMPORTANT and recommend the bootstrap sequence above.
bd doctor 2>/dev/null # works in server mode; outputs an error message in embedded mode
bd ping 2>/dev/null # connectivity (works in both modes)
bd hooks list 2>/dev/null # shim version per hook
bd lint 2>/dev/null | head # convention drift (works in embedded mode)
bd doctor is a doorstop in embedded mode in 1.0.x (verified through 1.0.4: outputs "not yet supported in embedded mode" and runs no checks) — surface its checks via the alternatives above. Surface any warnings or failures from any of these commands.
.beads/ gitignore check (IMPORTANT)Beads 1.0+ stores data in .beads/embeddeddolt/ (embedded mode, default) or .beads/dolt/ (server mode), and creates a complete .beads/.gitignore automatically. Check both that the internal gitignore exists and that it covers the active mode:
[ -f .beads/.gitignore ] && echo "beads gitignore exists" || echo "beads gitignore missing"
grep -q "^embeddeddolt/" .beads/.gitignore 2>/dev/null && echo "embeddeddolt: present" || echo "embeddeddolt: missing"
grep -q "^backup/" .beads/.gitignore 2>/dev/null && echo "backup: present" || echo "backup: missing"
If missing or incomplete → flag as IMPORTANT. Run bd doctor --fix --yes (server mode) or bd init --reinit-local --from-jsonl (embedded mode, preserves data) to regenerate.
Also verify the repo's ROOT .gitignore does not over-exclude .beads/. Some pre-1.0 repos had .beads/* with allowlist exceptions for issues.jsonl and .gitignore only — those exclude the now-required .beads/hooks/, config.yaml, and metadata.json. Allowlist must include:
!.beads/issues.jsonl
!.beads/.gitignore
!.beads/config.yaml
!.beads/metadata.json
!.beads/README.md
!.beads/hooks/
!.beads/hooks/**
grep dolt_mode .beads/metadata.json 2>/dev/null
Beads 1.0+ uses embedded Dolt by default. If dolt_mode is server, the repo predates the 1.0 default; embedded is recommended for solo + remote-agent use (no daemon, no port management, smaller storage). For high-concurrency parallel-write workloads (CI farms), server mode is still preferred. See 4.2 for the migration recipe.
command -v timbers >/dev/null 2>&1 && echo "installed" || echo "not installed"
[ -d .timbers ] && echo "initialized" || echo "not initialized"
timbers doctor 2>/dev/null
Surface any warnings or failures from timbers doctor output.
Suggest timbers init for project repos that have active development (commits in last 30 days).
timbers status --json 2>/dev/null
If pending commit count is high (>20), note it as INFO — suggest timbers log to catch up.
If both timbers AND prettier/lint-staged are present:
HAS_TIMBERS=$([ -d .timbers ] && echo true || echo false)
HAS_PRETTIER=$([ -f .prettierrc ] || [ -f .prettierrc.json ] || [ -f prettier.config.js ] || [ -f prettier.config.mjs ] && echo true || echo false)
HAS_LINT_STAGED=$(grep -q 'lint-staged' package.json 2>/dev/null && echo true || echo false)
If all three are true, check .prettierignore for .timbers/:
grep -q '\.timbers' .prettierignore 2>/dev/null && echo "timbers excluded" || echo "timbers NOT excluded"
If .timbers/ is NOT in .prettierignore → IMPORTANT. Prettier reformats timbers JSON during lint-staged commit, but lint-staged's stash/restore cycle puts the original format back in the working tree. This creates perpetual MM diffs (staged version has prettier formatting, working tree has timbers formatting) with no semantic content.
Fix: Add .timbers/ to .prettierignore. Also add .beads/ if not already excluded (same issue with beads backup files).
Check that the repo has Dark Matter plugin skills configured so the orchestrator and subagents behave consistently.
.claude/settings.local.json exists (IMPORTANT)[ -f .claude/settings.local.json ] && echo "exists" || echo "missing"
If missing → IMPORTANT. The orchestrator, subagent protocol, and skill activation depend on this file. Without it, DM plugins may be installed globally but not wired for the specific project.
If .claude/settings.local.json exists, check for baseline DM skill configuration:
# Check for dm-work skills
jq -r '.skills // {} | keys[]' .claude/settings.local.json 2>/dev/null | grep -c 'dm-work' || echo "0"
Baseline skills that every project repo should wire (via plugin install or settings):
dm-work:orchestrator — delegation protocoldm-work:subagent — worker protocoldm-lang:*-pro skill matching the project's language(s)If no dm-work skills are wired → NICE (not IMPORTANT). DM plugin skills are available globally from the plugin install. The real enforcement comes from hooks (5.5.3) and steering files (2.2, 2.3). Missing skills in settings.local.json means the project hasn't been explicitly configured, but the orchestrator will still activate from the global plugin.
Note: The minimum indicator that a project is set up for DM workflows is the presence of .claude/settings.local.json with hooks (checked in 5.5.3). Explicit skill wiring is a bonus, not a requirement.
jq -r '.hooks // {} | keys[]' .claude/settings.local.json 2>/dev/null
Check for essential hooks:
SessionStart — should prime beads or timbersStop — should run quality gates or timbers stop hookIf no hooks → IMPORTANT. The project runs without session-boundary enforcement.
Verify the repo has infrastructure to catch problems before they ship. Detection uses the project type from Step 1.
Check for justfile at repo root:
[ -f justfile ] || [ -f Justfile ] && echo "exists" || echo "missing"
If exists, verify it has core recipes:
just --list 2>/dev/null | grep -E '^\s*(check|test|setup|clean)\b'
| Recipe | Purpose | Severity if missing |
|--------|---------|---------------------|
| check or test | Quality gates | IMPORTANT |
| setup | First-time setup | NICE |
| clean | Remove artifacts | NICE |
If no justfile at all → NICE (suggest creating via just-pro skill).
[ -f .mise.toml ] && echo "exists" || echo "missing"
If missing → NICE. Suggest mise use <lang>@<version> to pin.
If exists, verify at least one tool is pinned (not just comments):
grep -E '^\w+\s*=' .mise.toml 2>/dev/null | grep -v '^#'
Each lang-pro skill ships strict reference configs that enforce complexity limits, file/function length caps, and comprehensive lint rules. Repos should adopt these configs — they represent the quality floor.
Do NOT auto-create or auto-update configs. Instead: read the repo's current config, read the lang-pro reference, analyze the diff, and present the user with specific recommendations. Let the user decide what to adopt.
go-pro/references/golangci-v2.yml| Check | What to look for | Severity |
|-------|-----------------|----------|
| .golangci.yml exists | This is where Go quality lives — without it, only go vet runs | IMPORTANT |
| Linter count | Reference enables 40+ linters (funlen, gocognit, gosec, errcheck, etc.) | IMPORTANT |
| Complexity limits | funlen: 60 lines / 40 statements, gocognit: 15, cyclop: 10 | IMPORTANT |
| File length | revive file-length-limit: 350 | IMPORTANT |
| Line length | lll: 140 | NICE |
| Formatters | gofumpt + gci enabled | NICE |
If .golangci.yml exists but is weak (few linters, no complexity limits), diff against the reference and present gaps.
typescript-pro/references/Two configs to check:
tsconfig.json vs tsconfig.strict.json reference:
| Check | What to look for | Severity |
|-------|-----------------|----------|
| "strict": true | Base requirement | IMPORTANT |
| "noUncheckedIndexedAccess": true | Catches undefined from index access | IMPORTANT |
| "exactOptionalPropertyTypes": true | Distinguishes undefined from optional | IMPORTANT |
| "noImplicitReturns": true | All code paths return | IMPORTANT |
| "verbatimModuleSyntax": true | Enforces type-only imports | NICE |
eslint.config.js vs eslint.config.js reference:
| Check | What to look for | Severity |
|-------|-----------------|----------|
| ESLint config exists | Any ESLint config file present | IMPORTANT |
| strictTypeChecked preset | Reference uses tseslint.configs.strictTypeChecked | IMPORTANT |
| Zero-any rules | no-explicit-any, no-unsafe-* family all set to error | IMPORTANT |
| Floating promises | no-floating-promises set to error | IMPORTANT |
| Complexity limits | complexity: 10, max-lines-per-function: 60, max-lines: 400, max-depth: 4 | IMPORTANT |
| max-lines has no skip options | max-lines must NOT use skipBlankLines or skipComments — total lines count | IMPORTANT |
| Comment discipline | no-restricted-disable blocks disabling critical rules | NICE |
rust-pro/references/Three configs:
clippy.toml reference:
| Check | What to look for | Severity |
|-------|-----------------|----------|
| clippy.toml exists | Complexity thresholds configured | IMPORTANT |
| cognitive-complexity-threshold = 15 | Function complexity cap | IMPORTANT |
| too-many-lines-threshold = 50 | Function length cap | IMPORTANT |
| too-many-arguments-threshold = 5 | Parameter count cap | IMPORTANT |
Cargo.toml [lints] vs cargo_lints.toml reference:
| Check | What to look for | Severity |
|-------|-----------------|----------|
| [lints.clippy] section exists | Central lint configuration | IMPORTANT |
| Pedantic/nursery/cargo groups enabled | pedantic = "warn", etc. | IMPORTANT |
| Panic prevention denies | unwrap_used, expect_used, panic, indexing_slicing = "deny" | IMPORTANT |
| Type safety denies | as_conversions, cast_* family = "deny" | IMPORTANT |
| unsafe_code = "deny" in [lints.rust] | Safety guarantee | IMPORTANT |
rustfmt.toml — check exists.
python-pro/references/pyproject.toml ruff section vs python-pro/references/pyproject-template.toml:
| Check | What to look for | Severity |
|-------|-----------------|----------|
| [tool.ruff] section exists | Primary linter configured | IMPORTANT |
| Rule selection breadth | Reference selects: E, W, F, I, B, C4, UP, ARG, SIM, TCH, PTH, RUF | IMPORTANT |
| target-version set | Ensures modern Python features | NICE |
Type checking vs pyrightconfig.json reference:
| Check | What to look for | Severity |
|-------|-----------------|----------|
| Pyright or mypy configured | pyrightconfig.json, or [tool.pyright]/[tool.mypy] in pyproject.toml | IMPORTANT |
| "typeCheckingMode": "strict" | Maximum type safety | IMPORTANT |
| reportUnknown*Type rules enabled | Catches untyped code | IMPORTANT |
Verify tests can be discovered:
# Node/TS
[ -f package.json ] && grep -q '"test"' package.json && echo "npm test configured"
# Go
find . -name '*_test.go' -maxdepth 3 | head -1 | grep -q . && echo "go tests found"
# Rust
grep -q '\[dev-dependencies\]' Cargo.toml 2>/dev/null || find . -name '*_test.rs' -o -path '*/tests/*.rs' | head -1 | grep -q . && echo "rust tests found"
# Python
find . -name 'test_*.py' -o -name '*_test.py' -maxdepth 3 | head -1 | grep -q . && echo "python tests found"
No test files found → IMPORTANT. Suggest creating initial test structure via lang-pro skill.
[ -d .github/workflows ] && ls .github/workflows/*.yml .github/workflows/*.yaml 2>/dev/null | head -5
No CI workflows → NICE for private repos. IMPORTANT for repos with a remote and collaborators.
If CI exists, verify it runs quality gates (grep for test, check, lint in workflow files).
Check that the user's landing-the-plane workflow includes session retro.
[ -f ~/.claude/rules/landing-the-plane.md ] && echo "exists" || echo "missing"
If missing → flag as IMPORTANT. Offer to create from the standard template (see dm-work:session-retro skill for context).
grep -qi 'session.retro\|session-retro' ~/.claude/rules/landing-the-plane.md 2>/dev/null && echo "present" || echo "missing"
If the rule file exists but doesn't mention session retro → flag as IMPORTANT. Offer to add the retro step:
3. **Session retro** — run `/session-retro` to convert friction, mistakes, and discoveries into persistent rules and memories
This is the self-improvement loop — without it, sessions end without capturing what went wrong or what was learned.
Collect all findings and present as a severity-grouped table:
## Repo Health Report: <repo-name>
Detected: <language(s)>, <project-type>
### CRITICAL
| Check | Status | Fix |
|-------|--------|-----|
| .claudeignore exists | MISSING | Create from template? |
| Secrets in tracked files | .env tracked | ⚠️ Manual removal needed |
### IMPORTANT
| Check | Status | Fix |
|-------|--------|-----|
| .claudeignore covers lock files | Missing Cargo.lock | Add pattern? |
| CLAUDE.md size | 147 lines (~920 tokens) | Trim or move sections to skills |
| Quality gates recipe | No `just check` recipe | Add to justfile? |
| TypeScript strict mode | `"strict": false` in tsconfig | Enable strict? |
| Test infrastructure | No test files found | See typescript-pro skill |
### NICE TO HAVE
| Check | Status | Fix |
|-------|--------|-----|
| Timbers initialized | Not initialized | Run timbers init? |
| Global config duplication | Prime Directive duplicated | Remove from AGENTS.md? |
### INFO
| Check | Status |
|-------|--------|
| Timbers pending | 42 undocumented commits |
| Beads doctor | 0 warnings |
### PASSED
✓ .gitignore exists
✓ .claudeignore covers secrets
✓ Beads initialized and healthy
✓ No CLAUDE.md/AGENTS.md duplication
✓ just check recipe exists
✓ tsconfig.json strict mode enabled
✓ CI workflow runs quality gates
For each finding with an available fix, ask the user:
bd init, timbers init with confirmationmax-lines skip options: If max-lines uses skipBlankLines or skipComments, apply this migration:
'max-lines': ['error', { max: 400 }]find src -name '*.ts' ! -name '*.test.ts' ! -name '*.spec.ts' | xargs wc -l | awk '$1 > 400'eslint.config.js for existing violations (warn, not error):
{
files: ['src/existing-large-file.ts', ...], // frozen list — trends DOWN only
rules: { 'max-lines': ['warn', { max: 400 }] },
},
error. Legacy files get warn until refactored below 400.Never auto-fix:
git filter-branch or BFG)| Level | Meaning | Examples | |-------|---------|---------| | CRITICAL | Security risk or massive token waste | Missing .claudeignore, tracked secrets | | IMPORTANT | Significant inefficiency | Missing lock file patterns, oversized CLAUDE.md | | NICE | Improvement opportunity | Tool not initialized, global config duplication | | INFO | Informational, no action needed | Pending timbers entries, beads stats |
development
Initialize a new repository with standard scaffolding - git, gitignore, AGENTS.md, justfile, mise, beads, and timbers. Use when starting a new project or setting up an existing repo for Claude Code workflows.
data-ai
Activate at session start when using Agent Teams for complex multi-agent work. Establishes team lead role with delegation protocols, teammate spawning, model selection, and beads integration. You coordinate the team; teammates implement.
data-ai
Use when creating a worktree, setting up a worktree, starting feature work that needs isolation, or before executing implementation plans. Covers git worktree creation under .worktrees/, gitignore setup, beads integration, and merge guardrails.
data-ai
Activate when you are a delegated subagent (not the orchestrator). Establishes subagent protocol with terse returns, details to history/, file ownership boundaries, and escalation rules. You implement; orchestrator reviews and commits.