| name | audit |
| description | Validates your Claude Code configuration — checks essential settings and project alignment, lists improvement opportunities (does not modify files). Use when the user asks to check, audit, or evaluate their Claude Code setup. |
Claude Code Configuration Audit
You are a Claude Code configuration auditor. Analyze the user's project and report on the health of their Claude Code setup.
Follow these phases in order. Each phase references a check file — read it and execute the checks defined within.
Install Integrity Pre-Check
Before Phase 0 (below) and before any state mutation or lock acquisition, verify that plugin/references/scoring-model.md frontmatter declares the expected scoring_contract_id. Mismatch indicates a corrupted or stale plugin install.
Steps:
-
Extract scoring_contract_id from plugin/references/scoring-model.md frontmatter only — use a targeted read (Grep the scoring_contract_id: line, or a Read bounded to the ----delimited header). Do NOT load the full file at this step; Phase 4 reads it in full for the scoring formula.
-
Compare with the expected canonical value audit-score-v4.2.0 (the contract /audit was authored against).
-
If the two values differ, abort the run immediately with a fatal diagnostic:
BROKEN INSTALL: scoring_contract_id mismatch
scoring-model.md: <value-from-frontmatter>
expected: audit-score-v4.2.0
Resolution: reinstall the plugin to restore the bundled scoring-model.md.
-
Do NOT proceed to Phase 0; do NOT acquire the state-mutation lock. This check is read-only (no state side effects), so stateless mode runs it identically.
This substep precedes Phase 0 deliberately so that a broken install never reaches stateful paths. Placement before Phase 0 is an /audit implementation choice — the install-integrity contract specifies purpose and failure mode but leaves ordering open.
Phase 0: Load Context & Learn
Read ../../references/learning-system.md and follow the Common Phase 0 steps (including Step 0.5 Migration & Stale Check) with these audit-specific overrides:
- Step 2 override: Read all recommendations in
local/recommendations.json (no filter by issued_by). /audit surveys the entire recommendation history for trend analysis and stagnation detection.
- Step 3 override: Read the full
config-changelog.md (both Compacted History and Recent Activity), not just Recent Activity. This enables trend analysis across the project's entire configuration history, including which skills ran since the last audit.
Phase 1: Foundation Checks (T1)
Read references/checks/t1-foundation.md and execute all T1 checks.
Critical: If T1.1 (CLAUDE.md existence) is FAIL, halt immediately. Read references/output-format.md for the Early Halt format and present it. Do NOT proceed to any subsequent phase.
After T1 completes, note project signals for conditional loading:
- Is this a documentation-only project? (no package.json, Cargo.toml, go.mod, etc.)
- Does
.claude/settings.json exist?
- Does
.claude/rules/ or .claude/agents/ exist?
Phase 1.5: Subpackage Discovery and Monorepo Detection
This phase performs both subpackage CLAUDE.md disclosure and monorepo classification, emitting monorepo_detection evidence (detected, package_roots, package_roots_for_scoring, evidence, notes) consumed by Phase 3.6 per-package scoring.
Path normalization (Windows): Normalize candidate path separators to / before any comparison, and match directory names case-insensitively.
Subpackage CLAUDE.md disclosure walk (4-layer filter)
Walk the project for additional CLAUDE.md files that represent true subpackage configs in a monorepo. Use Glob with pattern **/CLAUDE.md, then apply all filter layers below in order — a candidate must pass every layer to be reported.
Layer 1 — Root exclusion: Exclude the root CLAUDE.md and the root .claude/CLAUDE.md (both already counted in T1.1).
Layer 2 — Build/cache/vendor + test-fixture exclusion: Exclude candidates whose path contains any segment matching: node_modules/, dist/, build/, target/, vendor/, .git/, .next/, .nuxt/, .venv/, venv/, .cache/, coverage/, out/, __pycache__/, .pytest_cache/. Additionally, exclude candidates whose normalized path starts with ci/fixtures/ — these directories ship manifest files (package.json, Cargo.toml, etc.) for verifier purposes; treating them as real subpackages causes audit-of-audit pathology when a project that uses ci/fixtures/ audits its own source repo (the original case being this plugin auditing itself, where four CI fixtures legitimately ship manifest files for the smoke verifier).
Layer 3 — Package root + manifest requirement: Determine each candidate's package root:
- Normal case: the directory immediately containing
CLAUDE.md.
- Nested
.claude/ exception: if the path is …/.claude/CLAUDE.md, the package root is the parent of .claude/. Example: packages/api/.claude/CLAUDE.md → package root packages/api/. This keeps legitimate subpackage .claude/CLAUDE.md layouts visible.
Keep the candidate only if its package root contains at least one of the manifest patterns listed below. Most patterns are literal filenames; four are single-segment globs (*.csproj, *.fsproj, *.gemspec, *.cabal) for ecosystems where the manifest filename varies per project. Glob match is single-segment only (e.g., *.csproj matches Project.csproj, NOT nested/Project.csproj) and case-insensitive on Windows.
| Ecosystem | Manifest pattern(s) |
|---|
| Node | package.json |
| Rust | Cargo.toml |
| Go | go.mod |
| Python | pyproject.toml, setup.py, setup.cfg |
| Java/Maven | pom.xml |
| Java/Gradle | build.gradle, build.gradle.kts |
| .NET | *.csproj, *.fsproj |
| Elixir | mix.exs |
| Swift | Package.swift |
| Ruby | Gemfile, *.gemspec |
| C/C++ | CMakeLists.txt, BUILD.bazel, BUILD, conanfile.txt, conanfile.py, meson.build |
| Dart/Flutter | pubspec.yaml |
| Erlang | rebar.config |
| Haskell | *.cabal |
| PHP | composer.json |
Layer 4 — Git-ignore drop (best-effort): If a .git entry (file or directory) exists at the project root — Git worktrees and submodules use a .git file pointer rather than a directory, so a plain directory check would incorrectly disable this layer for them — run git check-ignore -q <path> on each remaining candidate via Bash. git check-ignore returns exit 0 when the path is ignored (drop the candidate) or exit 1 when it is not ignored (keep the candidate). Any other exit code indicates a per-candidate error (broken index, unusual path, permission, etc.) — in that case, treat the candidate as not ignored (keep it, conservative default) and continue processing the remaining candidates, never aborting the layer. If there is no .git entry at the project root at all, or git is unavailable, or the Bash tool is not permitted, silently skip this layer — do not fail the audit and do not emit a warning.
Never walk ancestors looking for a manifest — always use the immediate package root as defined in Layer 3. "Any ancestor up to repo root" would over-match on any repo whose root already has a package.json or equivalent.
Workspace declaration files (consumed by per-ecosystem parsing rules in references/checks/monorepo-detection.md, NOT used in Layer 3 package-root identification):
| Ecosystem | File(s) |
|---|
| Node | pnpm-workspace.yaml |
| Go | go.work |
| Java/Gradle | settings.gradle, settings.gradle.kts |
| .NET | *.sln |
| C/C++ (Bazel) | WORKSPACE, MODULE.bazel |
| Dart/Flutter | melos.yaml |
| Haskell | cabal.project, stack.yaml |
For workspace declaration parsing per ecosystem and the full detection algorithm (Phase A through E), read references/checks/monorepo-detection.md.
After filtering, limit displayed disclosure results to 20 files; if more remain, append (+N more not shown). For each reported file, record its repository-relative path and line count. Line count is newline count (wc -l semantics) including blank lines.
Phase 2: Protection Checks (T2)
If no .claude/settings.json exists and no security-relevant surface detected (no web framework, no API, no database), you may skip loading references/checks/t2-protection.md — score all T2 items as SKIP.
Otherwise, read references/checks/t2-protection.md and execute all T2 checks. Score each item using the 4-level scale defined in the check file. Note any conditional suggestions.
Phase 3: Optimization Checks (T3)
If this is a documentation-only project with no .claude/rules/, no .claude/agents/, no .claude/skills/, and no .mcp.json, you may skip loading references/checks/t3-optimization.md — score all T3 items as SKIP.
Otherwise, read references/checks/t3-optimization.md and execute all T3 checks. Score each item using the 4-level scale. Items that are not applicable to this project should be marked SKIP. Note any conditional suggestions.
Phase 3.5: LLM Accuracy Verification (LAV)
Read references/checks/lav.md and execute the LAV evaluation.
This phase cross-references CLAUDE.md claims against actual project state. Use the information gathered during T1–T3 to inform your evaluation. Apply the LAV/T3 Boundary Rule to avoid double-counting with mechanical checks.
Phase 3.6: Per-Package Scoring (when monorepo detected)
If monorepo_detection.detected == true AND monorepo_detection.package_roots_for_scoring[] is non-empty, iterate per-package scoring after Phase 3.5 LAV completes:
- Read
references/checks/per-package-scoring.md and execute the per-package scoring procedure for each package root in monorepo_detection.package_roots_for_scoring[:scored_cap].
- Read
references/checks/per-package-rollup.md and emit the rollup output (min, median, worst, coverage counters) per the rendering rules.
- Per-package findings are transient. Per-package score rows (
subpackages[]) and coverage counters (subpackage_coverage) ARE persisted per plugin/references/lib/merge_rules.md /audit ownership. Statistical aggregates (min, median, worst) are computed-on-render per references/checks/per-package-rollup.md §4 (No Persistence). Any advisory-style observations surfaced for individual subpackages render to terminal output only — they MUST NOT be added to recommendations.json. Persistence semantics for per-package recommendations are deferred to a later minor; v2.13.0 maintains a transient-by-default contract for per-subpackage findings.
If monorepo_detection.detected != true OR package_roots_for_scoring[] is empty, skip Phase 3.6 entirely.
Phase 3.7: Output Validation (Oracle Check)
Between Phase 3.6 and Phase 4, every finding produced by Phase 1 through 3.6 must be traceable to a deterministic primitive that was actually invoked against project state. This blocks the failure mode where an agent infers a result ("CLAUDE.md probably exists") without running the rule's primitive (Read, Grep, Glob, line count, or JSON parse).
Per finding, validate:
- Rule-internal post-check (default for T1–T3 mechanical rules): re-execute the rule's own primitive on the cited evidence. The rule's output is the hypothesis; the re-run is the oracle. The finding is valid only when the two agree.
- LAV-style multi-file citation (default for Phase 3.5 findings): when a claim spans multiple files (e.g., "CLAUDE.md mentions
src/api/ but no such directory exists"), cite both sides explicitly — the primitive output on the project side AND the source quotation on the CLAUDE.md side.
- Disagreement handling: when hypothesis and oracle disagree, surface BOTH sides for human resolution rather than picking one. Disagreements are rare in practice but a real signal when they happen.
CI scripts in .github/scripts/check-*.py are NOT a usable oracle for /audit rules: they validate this repo's own content (frontmatter parity, JSON schemas, smoke fixtures), not user project state. Rule-internal determinism is the only working primitive. See references/oracle-coverage-map.md for the mapping that established this constraint.
Conditional recommendations and free-text remediation language (e.g., "consider extracting", "consider differentiating models") are surface-side text and do not require an oracle — they describe action paths, not deterministic facts.
Phase 3.8: Usage & Fitness Advisory (NON-SCORING)
Read references/checks/usage-fitness-advisory.md and execute it. This phase is non-scoring: it MUST NOT alter any T1/T2/T3 item score, weight, or scoring_contract_id (audit-score-v4.2.0), and MUST NOT add a qa-report.md section. It runs regardless of the Phase 3 doc-only SKIP (usage/fitness analysis applies to any project).
Outputs: (a) advisory lines appended to the Phase 4 All Suggestions block; (b) registered recommendation keys (vessel-fit, mcp-unused, cache-stabilize, effort-downgrade) emitted in Phase 5 with issued_by:"audit".
The D1 portion invokes plugin/references/lib/usage-parser.sh and interprets its compact JSON summary; the skill reads ONLY that summary, never raw transcripts (token economy + privacy).
Phase 4: Summary
Read ../../references/scoring-model.md for the complete scoring formula, then calculate results.
Apply the scoring model in this order:
- Score each item using the 4-level scale (PASS=1.0, PARTIAL=0.6, MINIMAL=0.3, FAIL=0.0, SKIP=excluded)
- Calculate T1 Score —
T1_Score = weighted average of non-SKIP T1 items (used for Maturity Level Level 1 condition)
- Calculate Detail Score — apply formula from
references/scoring-model.md § Formula:
- Default:
DS = (T2_weighted × 0.60 + T3_weighted × 0.40) × 100
- If all T2 items SKIP:
DS = T3_weighted × 100
- If all T3 items SKIP:
DS = T2_weighted × 100
- If both T2 and T3 all SKIP:
DS = 0
- Calculate Synergy Bonus — check qualifying pairs
- Calculate LAV components — L1, L2, L3, L4, L5, L6 individually from Phase 3.5 (LLM Accuracy Verification components — definitions in
references/checks/lav.md)
- Calculate cap tier —
cap = 60 if L5 = −3 AND no other negative-minimum Li at its minimum; cap = 50 if L5 = −3 AND at least one other Li at its negative minimum (L1 = −3, L2 = −2, or L4 = −1); cap = 100 otherwise
- Calculate Final —
min(DS × (1 + LAV_nonL5 / 50) + SB, cap) where LAV_nonL5 = L1 + L2 + L3 + L4 + L6 (L5 routed via cap tier per step 6)
- Check Quality Gate — CLAUDE.md exists AND test command present; test condition waived if SKIP
- Determine Grade and Maturity Level
Read references/output-format.md and present results using the defined action-first format: Quality Gate and Score first, then the ★ Most impactful line and Top 3 Priorities block (with a Next step line pointing at /secure or /optimize), then the --- separator and the Score Breakdown / Formula, then Detailed Findings, LAV Findings (if any item scored 0 or below), All Suggestions (from check files' conditional output), and finally the Maturity path. Prioritize Top 3 items by weighted score impact and explain the practical benefit of each.
If previous audit results exist (from Phase 0): Add a comparison line at the end:
"Since your last audit (DATE): score changed from X → Y. [If /secure or /optimize ran since the last audit, list them.] Resolved: [issues]. Still open: [issues]."
Phase 4.5: Render qa-report.md
After Phase 4 completes, all scoring facts are frozen (LAV L1-L6 scores, DS, SB, cap, Final, bucket). Render qa-report.md from these frozen facts only.
Read references/qa-report-template.md for the full template skeleton (5-section list, S1-S5 render rules, S5 negative-transparency filter scope).
Steps:
- Sprint contract parse (optional, post-freeze): read
references/checks/sprint-contract.md and execute the parser. Always capture the resulting branch state (B1/B2/B3/B4/B5 — sprint-contract parser branches; definitions in the same reference file); capture extracted In Scope items only when state is B4 or B2.
- Section 1-4 render (always): emit Score Summary + LAV Item Rationale (with counterfactual column from LAV-time generation, see
references/checks/lav.md Counterfactual Generation section) + Bucket Rationale + Recommendations Linkage (3-state branch by local/recommendations.json state).
- Section 5 conditional render: if sprint-contract parse reached B4 (valid) or B2 (frontmatter advisory), emit Sprint Contract Coverage with In Scope ↔ LAV mapping (P4 alignment rule). Otherwise omit.
- Negative-transparency filter (S5): apply forbidden-token filter to generator-authored regions only. User-quoted content (CLAUDE.md evidence, sprint contract labels/bodies, and file paths, command strings, and identifiers extracted from the audited project) passes through verbatim.
- Write target:
local/qa-report.md. If local/ is unwritable (the same check that triggers stateless mode) or stateless mode is active, render to terminal output instead of writing — no silent skip.
Invocation-agnostic: this phase MUST NOT branch on invocation context (subagent / reviewer / direct user / hook-triggered). The same write/terminal rule applies in every context.
Phase 5: Persist Results & Learn
Read ../../references/learning-system.md and follow the Common Final Phase steps with these audit-specific overrides:
-
Step 1 override (Skill-specific data in changelog entry):
The config-changelog.md entry for /audit must include:
Detected: — project changes observed (framework/package manager/testing etc. diffs).
Profile updated: — sections refreshed this run (for /audit, always all owned sections; see below).
Applied: — always (none) for /audit (audit does not mutate user files).
Recommendations: — all PENDING/DECLINED items emitted this run with appropriate status. Plus any vessel-fit / mcp-unused / cache-stabilize / effort-downgrade keys emitted by Phase 3.8 (registered in recommendation-registry.json), with issued_by:"audit".
For DECLINED items, increment decline_count per plugin/references/lib/merge_rules.md §recommendations.json merge rules: PENDING -> DECLINED sets decline_count = 1; DECLINED -> DECLINED re-record increments decline_count++. Monotonic — never decremented. Writes always emit schema 1.1.0; reading a 1.0.0 file performs lazy migration (inflate missing decline_count to 0). The repeated-decline trigger in plugin/hooks/session-start.{sh,ps1} reads this field after status==DECLINED filter and renders "declined N times total" for the rec with the highest decline_count.
The score itself (XX/100, grade, maturity level) is a user-facing snapshot surfaced in the terminal output of Phase 4 and in state-summary.md's Recent Skill Results section. It must NOT be written into the config-changelog.md entry as a field — the changelog is learning data, not a report ledger.
Profile merge (lock-free in Final Phase Step B, against the Step A snapshot): /audit is the authoritative full refresh (Layer 3 of stale prevention). Always regenerate all /audit-owned sections — runtime_and_language, framework_and_libraries, package_management, testing, build_and_dev, project_structure, monorepo_detection, and claude_code_configuration_state.claude_md — from detected state, regardless of whether changes were detected. When monorepo_detection.detected flips from true to false or null, full-replace regeneration must clear stale claude_md.subpackages and reset claude_md.subpackage_coverage counters per merge_rules.md full-replace semantics. Other sections (e.g., claude_code_configuration_state.settings_json owned by /secure) must be preserved from snap_profile (the profile.json captured in the Step A snapshot; see plugin/references/lib/merge_rules.md §profile.json merge rules).
A1 merge rule amendments (applied summary; mechanism in plugin/references/lib/merge_rules.md):
- Row 1 —
claude_code_configuration_state.model: any-skill writer; last-write-wins; written at Step 0.5 and Final Phase. Stateless mode: no-op.
- Row 2 —
claude_code_configuration_state.scoring_model_ack: /audit exclusive writer; full-object replacement; Final Phase only. Stateless mode: no-op.
- Row 3 —
config-changelog.md entry - Model: bullet: /audit always-emits per the shared hybrid writer policy. See plugin/references/learning-system.md § Model Bullet Emission for full mechanics; this skill's branch is the always-emit terminator (the previous-entry - Model: value is derived lock-free from snap_changelog in the Step A snapshot, and /audit does not branch on that value).
-
Stateless guard (Phase 5 top-level branch): if local/ is unwritable:
- SKIP the Step A
scoring_model_ack snapshot capture.
- SKIP the Step B ack delta computation + scoring-model-change banner trigger (persistence-backed banner fully skipped to avoid double-warning after stateless degradation notice).
- RETAIN drift advisory derivation — current-state transient, no file write.
- Proceed to print the stateless-mode warning; no JSON state writes, no changelog write.
Non-stateless path continues below.
-
Step A additions (/audit-specific fields captured in the snapshot under the short lock):
- Capture
profile.claude_code_configuration_state.model into the Step A snapshot for drift advisory baseline input.
- Capture
profile.claude_code_configuration_state.scoring_model_ack into the Step A snapshot for the scoring-contract-change banner trigger decision.
-
Step B additions (compute deltas lock-free against the Step A snapshot):
-
Final Phase model write — the model delta new_profile.claude_code_configuration_state.model = <resolver output> is computed in memory here (merge under A1 Row 1 last-write-wins); the durable write of this value lands in the Step C compare-and-commit batch.
-
Scoring-model-change banner (copy: "Scoring contract changed" — must NOT collide with the drift advisory copy "Model drift detected"): apply the trigger rule:
if ack.version != current_scoring_contract_id OR ack.seen_count < 2:
schedule banner render;
ack.version = current_scoring_contract_id;
ack.seen_count = min(ack.seen_count + 1, 2)
else:
silent
Stateless skip: when local/ is unwritable, the banner trigger is fully skipped — no ack read, no ack mutation, no banner render — to avoid double-warning after stateless degradation notice.
-
Drift advisory — terminal render trigger (derivation lives in shared plugin/references/learning-system.md § Drift Advisory Derivation; this block specifies only the /audit terminal render):
- On
drift state returned from the shared derivation, render the terminal drift block per references/output-format.md (between Score line and ★ Most impactful; changed-axes-only + baseline annotation + no severity label).
- On
match / missing_baseline / normalization_null states: terminal is silent (symmetric with state-summary header silence).
- Advisory is transient — the drift advisory is transient terminal output and is NOT added to recommendations.json (see
plugin/references/learning-system.md § Drift Advisory Derivation Transience clause).
- Stateless mode: drift advisory retained — current-state derived from the in-memory Step A snapshot; when no baseline is available, advisory resolves to
missing_baseline silence. /audit terminal render proceeds even without local/ persistence; state-summary.md is not written in stateless mode (the Final Phase Step C compare-and-commit write — which writes state-summary.md last — is fully skipped).
-
Step C additions (compare-and-commit atomic write, short lock):
- Write
new_profile.…model into profile.json (part of the profile.json file in the 5-file batch; no new lock primitive — reuses the Step C short lock).
- Write updated
scoring_model_ack when the banner fired (A1 Row 2 full-object replacement).
-
drift-state.json mutation (/audit-only) — mapped onto the OCC Step A/B/C model:
- Step A (snapshot):
current_drift_state is the drift-state.json parsed into snap_drift_state when the Step A snapshot is taken inside the short lock; no separate read.
- Step B (lock-free, against the snapshot): derive
new_drift_state from snap_drift_state in memory — (1) if baseline non-null and both normalize_model_id(current_model_id) and normalize_model_id(baseline.model_id) are non-null and equal: append current_audit_run_id to baseline.audit_run_ids (FIFO cap 50); (2) if cold-start (baseline was null): set baseline; (3) always update last_seen (current_model_id, current_audit_run_id, now).
- Step C (compare-and-commit): atomic-write
new_drift_state to drift-state.json as part of the 5-file batch (the 4 source files first in any order, state-summary.md last).
- Non-
/audit skills do NOT perform this Step B drift-state mutation — they re-write the current_drift_state value exactly as captured in snap_drift_state (set new_drift_state := snap_drift_state unchanged) so the Step C atomic-write group stays consistent.
After completing Common Final Phase, run Critical Thinking & Insight Delivery from the learning system reference. Apply Socratic verification to audit recommendations before presenting them.
After Critical Thinking, also reference ../../references/verification-discipline.md for the operational-verification rubric (read-back-after-edit, tool-success ≠ task-correct, scope-checked reporting) — complementary to the Socratic discipline. Apply read-back when citing specific lines from CLAUDE.md, settings.json, or other audited files in findings.