SuperAPI AI Directory

claude-health

Agents & models

View repository

Updated 10-16 03:40

About this skill

Claude Health Check

Trigger

  • Keywords: health check, .claude check, config audit, lint .claude, claude health, plugin sync, version drift, upgrade check, doctor

When NOT to Use

  • Code review (use /codex-review-fast)
  • Doc review (use /codex-review-doc)
  • Security review (use /codex-security)

Scope

Argument Description
--scope hygiene Only run C1-C7 hygiene checks
--scope sync Only run S1-S3 sync checks and the S4 plugin-copies inventory
--scope budget Only run the Instruction Budget Module (B1-B3)
--scope all Run every module — hygiene, sync and budget (default)

Workflow

[--scope] → Select modules → Scan → Classify → Report → Fix suggestions
               │                                  │
       ┌───────┴───────┐                     P0/P1/P2
       ▼               ▼                    + fix commands
  Hygiene (C1-C7)  Sync (S1-S3)

Hygiene Module — Checks (7 items)

# Check Method Criteria
1 Junk files find .claude/ -name ".DS_Store" -o -name "*.zip" -o -name ".tmp*" Any exists → P1
2 .gitignore exists ls .claude/.gitignore Missing → P1
3 .gitignore completeness Read .claude/.gitignore, compare required items Missing required → P2
4 Naming consistency Scan all skills/*/ for reference vs references Inconsistent → P2
5 README count sync Count actual vs README description Mismatch → P2
6 Command-Skill pairing Each core skill should have corresponding command Missing → P1
7 Cache size du -sh .claude/cache/ > 50M → P2

Check 1: Junk Files

find .claude/ -name ".DS_Store" -o -name "*.zip" -o -name ".tmp*" 2>/dev/null
  • Has results → P1: List files, suggest deletion
  • No results → ✅

Check 2-3: .gitignore

ls .claude/.gitignore 2>/dev/null || echo "MISSING"

Missing → P1. If exists, read content and compare required items:

Required Item Reason
.DS_Store macOS generates continuously
settings.local.json Personal config
cache/ Runtime cache
.tmp* Temp files
*.tmp Temp files (suffix variant)
*.zip Backup archives

Missing any → P2

Check 4: Naming Consistency

# Scan all skill subdirectories
for dir in .claude/skills/*/; do
  if [ -d "${dir}reference" ]; then echo "INCONSISTENT: ${dir}reference"; fi
done

Has reference/ (singular) → P2, suggest renaming to references/

Check 5: README Count Sync

# Count actual items
ls .claude/commands/ 2>/dev/null | wc -l
ls .claude/skills/ 2>/dev/null | wc -l
ls .claude/agents/ 2>/dev/null | wc -l
ls .claude/rules/ 2>/dev/null | wc -l
ls .claude/hooks/*.sh 2>/dev/null | wc -l

Extract counts from README.md, compare. Mismatch → P2

Check 6: Command-Skill Pairing

Scan all skills/*/SKILL.md, exclude these types, then check for corresponding command:

Exclude Type Examples Reason
Domain KB portfolio, aum Referenced by other skills, no standalone entry
External agent-browser Not maintained by this project

Remaining skills without command → P1

Check 7: Cache Size

du -sh .claude/cache/ 2>/dev/null
  • > 50M → P2, suggest cleanup
  • ≤ 50M → ✅

Sync Module — Checks (S1-S3)

Only runs when --scope sync or --scope all (default).

S1: Version Check

# Check Method Criteria
S1.1 Manifest exists Read .sd0x/install-state.json Missing → P1
S1.2 Manifest parseable JSON.parse Parse error → P1
S1.3 schema_version current == 1 Mismatch → P2
S1.4 plugin_version matches manifest vs .claude-plugin/plugin.json or package.json Mismatch → P1
S1.5 Manifest completeness Has rules + hook_scripts + scripts keys Missing key → P2 (MANIFEST_GAP)

Plugin version resolution (priority order):

.claude-plugin/plugin.json → package.json → "unknown"

Plugin source location (same as /install-rules Phase 1):

Glob: ~/.claude/plugins/**/sd0x-dev-flow/rules/auto-loop.md
Glob: ${REPO_ROOT}/node_modules/sd0x-dev-flow/rules/auto-loop.md
Fallback: @rules/auto-loop.md (plugin-relative)

S2: Component Classification

For each managed component (rules, hooks, scripts), compute 3 hashes and classify:

manifest_hash  = manifest[category][filename].hash    # null if missing
local_hash     = git hash-object --no-filters <local-path>  # null if file missing
plugin_hash    = git hash-object --no-filters <plugin-path>  # source of truth

Classification table (read-only diagnostic; maps to install-rules states for delegation):

Doctor State Condition Severity install-rules Equivalent
OK local == manifest == plugin ✅ SKIP
MISSING local_hash is null, plugin exists P1 FRESH_INSTALL
OUTDATED local == manifest, plugin != manifest P1 AUTO_UPDATE
LOCAL_MODIFIED local != manifest, plugin == manifest ✅ KEEP_LOCAL
CONFLICT local != manifest, plugin != manifest P2 CONFLICT
LEGACY manifest_hash is null, local exists P2 LEGACY
MANIFEST_GAP manifest category key missing P2 N/A
TOMBSTONED manifest deleted: true, local missing ✅ SKIP_DELETED
RETIRED name on /install-rules' retired list, plugin file absent, local exists P2 Retired (remove when unmodified, keep when modified)

Managed inventory (hardcoded):

Category Local Path Plugin Source Files
Rules .claude/rules/*.md rules/*.md auto-loop.md, codex-invocation.md, testing.md, security.md, git-workflow.md, logging.md, docs-writing.md, docs-numbering.md, self-improvement.md, context-management.md, discretion.md, scope-discipline.md, override-contract.md
Hooks .claude/hooks/*.sh hooks/*.sh pre-edit-guard.sh, pre-bash-codex-launch-guard.sh, post-edit-format.sh, post-skill-auto-loop.sh, post-compact-auto-loop.sh, stop-guard.sh, user-prompt-review-guard.sh
Retired rules .claude/rules/*.md — (no longer shipped) Every name on /install-rules' Retired table — today fix-all-issues.md, framework.md. Classified RETIRED when the local file exists, TOMBSTONED when the manifest marks it deleted, and nothing when neither
Scripts .claude/scripts/ scripts/ precommit-runner.js, verify-runner.js, review-state.js, dep-audit.sh, commit-msg-guard.sh, pre-push-gate.sh, protected-branches.sh, lib/utils.js, lib/tree-digest.js

S2.5: Override Safeguard Checks

7 checks for project override files (e.g., auto-loop-project.md):

# Check Severity Detection Recommendation
1 Override drift P2 based_on hash comment in project file vs the hash of the base file that comment names (derived, never hard-coded — auto-loop-project.md, testing-project.md and git-workflow-project.md all ship) — only when the override file has active content; a scaffold with every section still commented out has no overrides to review, so drift is not reported "Base <rule> updated since override authored; review your overrides"
2 Policy contradiction P1 An overridden section omits a required check command that the same section of the base rule contains "Override drops a required check command its base section carries"
3 Missing reference or base P1 For each shipped override file (auto-loop-project.md, testing-project.md, git-workflow-project.md): .claude/CLAUDE.md has @rules/<file> but the file is missing, OR the file exists but is not referenced (by @rules/<file>, or — for a template carrying paths: frontmatter — by a plain rules/<file> mention; an @ import of a path-scoped template is reported P2 instead, because it loads the file at launch and defeats the scoping), OR the file exists but the base rule its Based on: comment names is missing from .claude/rules/ /install-rules to recreate the missing file or base, or add the reference
4 Wrong-layer edit P2 Base auto-loop.md has LOCAL_MODIFIED, CONFLICT, or LEGACY state while project override exists "Move customization to auto-loop-project.md"
5 Duplicate heading P2 Override file has multiple active ## <heading> with same text "Keep one, remove duplicates. Last occurrence takes effect."
6 Legacy precedence header P2 Precedence declaration exists only inside an HTML comment (<!-- Precedence: present, no live Precedence: line before the first ##) — HTML comments are stripped from model context (R8), so the declaration never reaches its only reader "Header predates the live-precedence contract; migrate the precedence line to live text by hand or regenerate via /install-rules --customize <rule> --reset. This check is read-only — it never edits the user-owned file"
7 Git override conflict P1 / P2 git-workflow-project.md only. P1 whenever the file exists, active content or not — two empty duplicate ## Protected Branches headings are already a parse error: when /bin/bash -p -- <resolver> --root <repo> --list exits 2, where <resolver> is the plugin install's copy — ${CLAUDE_PLUGIN_ROOT}/scripts/protected-branches.sh when that variable is set and its real path lies outside the audited repository, else ~/.claude/plugins/**/sd0x-dev-flow/scripts/protected-branches.sh (one match) — never a copy inside the audited repository (.claude/scripts/, scripts/, node_modules/), because this check is read-only and the repository controls those files; no plugin install found → execute nothing and report check #7 as not run (P2), while S2 still classifies the local copy by hash — a removal attempt (- !main), a malformed bullet or a duplicate heading in ## Protected Branches, which makes every branch read as protected; an omitted default is never reported, since the set only widens. P2, active content only, when a ## Deploy Workflow line matches neither merge <source> -> <target> [--no-ff|--ff-only] nor run <path> [args…] with every token in ^[A-Za-z0-9._/@:=+,-]+$, or when ## Offer Mode / ## Run Steps carries a value outside on|commit-only|off / print|execute "Fix the named line; until then the protected set reads every branch as protected / the deploy block is ignored / the setting keeps its default"

Policy contradiction detection: For each ## <heading> section the override restates, extract the backticked check commands (/codex-review-fast, /codex-review-doc, /precommit) from the same-heading section of the base auto-loop.md and require the restated section to keep every one of them. A verbatim copy therefore never flags; only a restatement that drops a command its base section carries is P1. (The base's Auto-Trigger table was retired by R3 — code/doc routing now lives in the unheaded terminal-invariant paragraph, which the exact-##-heading override mechanism cannot restate, so routing itself is not overridable and is out of this check's scope.) No restated section → check passes vacuously.

Override drift detection: First check whether the project file has active content. Two forms count, and the distinction matters because the scaffold ships its ## headings live: a non-empty, non-comment body line under any heading, or a heading that carries its own value (## Plan Review: enabled, ## Git Memory: enabled — for these settings the heading is the value, so there is no body to look for). A bare scaffold heading with nothing but comments beneath it is an empty slot, not an override. The live Precedence: header is preamble material and never activation. A scaffold whose sections are all still commented out is skipped: drift means "the base changed since you wrote your overrides", and there are none, so reporting it on a fresh install is a false positive rather than a finding. Otherwise read the <!-- Based on: <base>.md @ <hash> --> comment and derive the base file from the comment's own filename — git hash-object --no-filters .claude/rules/<base>.md | cut -c1-7. The base must not be hard-coded: R8 distributes testing-project.md alongside auto-loop-project.md, so a fixed auto-loop.md comparand would check a testing override's hash against the wrong rule and report drift that does not exist. If the derived base file is missing, drift is undefined rather than zero — report it through check #3's missing base branch (P1) and do not emit a drift finding. Both checks must cover every shipped override file, not just auto-loop-project.md: an active testing-project.md whose testing.md has been deleted would otherwise fall through both. If the hashes differ, the base has been updated since the override was authored. Uses blob hash for content-level comparison; accepts legacy commit-style hashes (any 7+ hex chars) during backward-compat transition.

S3: Settings Compatibility

Check both settings.json and settings.local.json (precedence: settings.local.json > settings.json). A hook entry in either file satisfies the integrity check.

# Check Method Criteria
S3.1 Legacy hook paths Grep both settings files for bare .claude/hooks/ without $CLAUDE_PROJECT_DIR Found → P2
S3.2 Retired guard-mode setting Read env.STOP_GUARD_MODE (and legacy hooks_config.stop_guard_mode) from either settings file Found in either → P2 (retired: the Stop hook is reminder-only since hook-lightweighting — the setting is dead config, recommend removing it). Absent → ✅
S3.3 Hook entry integrity Each installed hook script has matching entry in either settings file Missing from both → P1
S3.4 Orphan hook entries Either settings file references script that doesn't exist on disk Orphan → P2

Settings file precedence: settings.local.json overrides settings.json at runtime. When delegating S3 fixes, use /install-hooks --local if the issue is in settings.local.json.

Legacy path detection:

Grep for: "\.claude/hooks/[^"]+\.sh"  (without leading "$CLAUDE_PROJECT_DIR")
Applied to both: settings.json and settings.local.json

Fix Tiers

Only applies when --fix-safe or --fix is specified alongside sync scope.

Tier Flag Description
Report (default) Diagnosis only — output actionable recommendations
Safe --fix-safe Auto-fix P1 hygiene + safe sync fixes
Guided --fix Auto-fix P1 hygiene + guided sync remediation (interactive)

Category-specific safe fix delegation:

Category MISSING OUTDATED CONFLICT/LEGACY
Rules /install-rules <names> /install-rules <names> (smart merge AUTO_UPDATE) Skip (report only)
Hooks /install-hooks <names> Report only + suggest /install-hooks <names> --force Skip (report only)
Scripts /install-scripts <names> Report only + suggest /install-scripts <names> --force Skip (report only)

Why hooks/scripts OUTDATED is report-only in safe tier: /install-hooks and /install-scripts use skip/force semantics (no manifest-aware smart merge). Only /install-rules has 7-state classification for safe auto-update.

S3 settings fix delegation: All settings mutations delegate to /install-hooks (sync module never writes JSON directly).

--fix tier: Delegates all actionable states (including CONFLICT, LEGACY) to /install-* commands which handle interactive resolution.

Argument conflict: --fix and --fix-safe are mutually exclusive. If both specified, error.

Instruction Budget Module

Claude Code adds up every always-loaded instruction file at launch and warns when the sum passes a total limit. The check reproduces that accounting (2.1.281) so the user learns it here first, with the plugin's share separated out. Runs under --scope budget and --scope all (the default), never under --scope hygiene or --scope sync. The script is the plugin install's copy — $CLAUDE_PLUGIN_ROOT when its real path lies outside the audited repository — never a copy inside the audited repository (.claude/scripts/, scripts/), because this check is read-only and the repository controls those files. No plugin install found → skip the module with a note:

REPO_ROOT=$(git rev-parse --show-toplevel) || { echo "instruction budget: skipped — not in a git repository"; exit 0; }
PR="${CLAUDE_PLUGIN_ROOT:-}"
case "$(cd "$PR" 2>/dev/null && pwd -P)/" in "$(cd "$REPO_ROOT" && pwd -P)/"*|/) PR="" ;; esac
[ -n "$PR" ] && [ -r "$PR/scripts/instruction-budget.js" ] \
  && node "$PR/scripts/instruction-budget.js" --root "$REPO_ROOT" --plugin-root "$PR" \
  || echo "instruction budget: skipped — no plugin install outside this repository"
# Check Severity Recommendation
B1 Always-loaded total over the limit (total = max(120000, per-file); pass --per-file for the model in use — the default is the 150,000 observed on 2.1.281) P2 Move a rule on demand (paths: frontmatter) or trim it; the three largest files are listed
B2 A file over the per-file limit P2 Claude Code warns on it alone and leaves it out of the total; split or trim it
B3 A lessons, archive, log or history file in .claude/rules/ P2 Move it out of rules/ — the lessons log lives at .claude/sd0x-dev-flow-lessons.md — or give it paths: frontmatter

The script is read-only; it never edits or moves a file. A missing script skips the module with a note rather than guessing a total.

Plugin Copies (S4)

Runs with the Sync module (--scope sync and --scope all). Report-only: it lists where copies of this plugin's content come from, so a stale or second copy is seen before it is mistaken for the plugin's current text. It never deletes, moves or edits a copy.

Origin Where Version read from
Local install .claude/rules/, .claude/hooks/, .claude/scripts/ .sd0x/install-state.json plugin_version (S1)
Marketplace plugin Every ~/.claude/plugins/**/sd0x-dev-flow/**/.claude-plugin/plugin.json whose name is sd0x-dev-flow — the versioned cache (cache/<marketplace>/sd0x-dev-flow/<version>/) and the marketplace checkout both match Each match's version; several matches are listed as found, never collapsed to one
claude.ai synced skills ~/.claude/skills/synced/ (Claude Code 2.1.273 and later) None — a synced skill carries no plugin version; list each directory named like a skill this plugin ships
# Check Severity
S4.1 Marketplace copies carry different versions P2 — the stale copies are the host's cache, cleared through /plugin; local-install drift is S1.4's finding, reported there once and never re-graded here
S4.2 A synced skill has the same name as a plugin skill P2 — two skills of one name are offered; the plugin's runs as /sd0x-dev-flow:<name>. Rename or turn off the copy on claude.ai: sync overwrites a local edit
S4.3 An origin cannot be read Reported as not checked, never as absent

Prompt Audit (manual step)

Claude Code 2.1.283 and later audit instruction files for outdated or conflicting content with /doctor prompt-audit [path] (alias /checkup prompt-audit). It covers CLAUDE.md, CLAUDE.local.md and AGENTS.md plus the rules and skills under .claude/ and ~/.claude/, reports findings with proposed edits, and changes nothing until asked. This skill does not run it: it is the host's command, and the report names it as the manual next step. Its findings on this plugin's content are handled by owner:

Finding on Handling
.claude/rules/*.md, .claude/hooks/ or .claude/scripts/ installed by this plugin Report only. Fix it upstream, or customize through a *-project.md override; S2 detects a local edit on every later run and classifies it by its hash table (LOCAL_MODIFIED, CONFLICT or LEGACY)
Anchor text — the Anchor Register in rules/discretion.md, or the Anchors section of the generated AGENTS.md Rejected. The plugin pins that text byte-for-byte and /codex-setup sync regenerates the AGENTS.md Anchors from rules/, so an edit there is a spec change for the maintainer, never an audit fix
*-project.md overrides and the project's own CLAUDE.md The user's call — these files are user-owned

Output

# .claude/ Health Check Report

## Hygiene Summary (C1-C7)

| Item | Status | Notes |
|------|--------|-------|
| Junk files | ✅/⛔ | ... |
| .gitignore | ✅/⛔ | ... |
| Naming consistency | ✅/⛔ | ... |
| README count | ✅/⛔ | ... |
| Command-Skill | ✅/⛔ | ... |
| Cache size | ✅/⛔ | ... |

## Sync Summary (S1-S3)

### S1: Version
| Check | Status | Detail |
|-------|--------|--------|
| Manifest | ✅/⛔ | Found / Missing |
| Plugin version | ✅/⛔ | 2.0.3 == 2.0.3 / 1.8.12 → 2.0.3 |
| Manifest keys | ✅/⛔ | Complete / Missing: hook_scripts, scripts |

### S2: Component Status
| File | Category | Status | Action |
|------|----------|--------|--------|
| auto-loop.md | Rules | OUTDATED | `/install-rules auto-loop` |
| security.md | Rules | OK | — |
| stop-guard.sh | Hooks | MISSING | `/install-hooks stop-guard` |
| ... | ... | ... | ... |

### S3: Settings Compatibility
| Check | Status | Detail |
|-------|--------|--------|
| Hook paths | ✅/⛔ | Modern / Legacy found |
| Retired guard mode | ✅/⚠️ | absent / STOP_GUARD_MODE found (dead config) |
| Entry integrity | ✅/⛔ | All matched / N missing |
| Orphan entries | ✅/⛔ | None / N orphans |

## Budget Summary (B1-B3)
| Check | Status | Detail |
|-------|--------|--------|
| B1 Total | ✅/⚠️ | 89,472 / 150,000 chars; plugin share 89,472 |
| B2 Per-file | ✅/⚠️ | None over / .claude/rules/big.md (152,000) |
| B3 Lessons in rules/ | ✅/⚠️ | None / .claude/rules/lessons.md → move to .claude/sd0x-dev-flow-lessons.md |

## Plugin Copies (S4)

| Origin | Version | Note |
|--------|---------|------|
| Local install | 5.0.0 | from `.sd0x/install-state.json` |
| Marketplace plugin | 5.0.0 / not checked | |
| claude.ai synced skills | — | names shared with plugin skills, or none |

Next step (manual): `/doctor prompt-audit` — findings on plugin-shipped content are report-only.

## Statistics

| Category | Count |
|----------|-------|
| Commands | N |
| Skills | N |
| Rules | N (installed) / N (managed) |
| Hooks | N |

## Issues

### P1
- [Issue] → [Fix recommendation / command]

### P2
- [Issue] → [Fix recommendation]

## Gate
✅ All Pass / ⛔ N issues need fixing

Verification

  • Hygiene: All 7 checks executed (when scope includes hygiene)
  • Sync: S1-S3 checks executed (when scope includes sync)
  • Budget: B1-B3 reported, or the skip note printed (when scope is budget or all)
  • Each check has clear ✅/⛔ status
  • P1 issues have specific fix commands
  • S2 classification covers every file in the managed inventory above (29 today: 13 rules, 7 hooks, 9 scripts)
  • Fix delegation uses targeted file names (not --all)

References

  • references/best-practices.md — Best practices for .claude/ directory structure

Examples

Input: /claude-health
Action: Scan hygiene (7 items) + sync (S1-S3) → Generate consolidated report

Input: /claude-health --scope sync
Action: Scan S1-S3 only → Report version drift + component status

Input: /claude-health --fix-safe
Action: Scan all → Auto-fix safe items → Delegate to /install-* → Report

Input: Is my plugin up to date?
Action: Trigger sync check → Report version + component drift