config-audit/commands/config-audit.md
Kjell Tore Guttormsen acd1cf1248 fix(commands): stop writing files no later step can read, and payloads nobody asked for
Dogfooding the four read commands (posture, tokens, manifest, whats-active)
surfaced four defect classes, all in the seam between what a command template
promises and what the scanner behind it actually does.

M-BUG-40, fifth arm: posture wrote four temp files it could never read back.
#49 closed the $$/cross-block class in four commands, but posture survived it —
and so did the guard written to prevent exactly this. The guard compared each
$$ path to the block that created it, so a path written once and then read via
prose had no second occurrence to flag. Measured live: written from PID 21614,
read attempted from PID 23772. The invariant is now blanket (no $$ in any temp
path), which also caught fix.md and feature-gap.md.

M-BUG-43: 6 of 7 scanners write their payload to stdout when --raw/--json is
set even when --output-file was given, and the templates redirected only
stderr. Measured: posture 255 182 B, whats-active 35 922 B, drift 28 316 B,
manifest 23 825 B, tokens 8 768 B. fix and feature-gap never read the file they
wrote, so both recovered one letter grade from a quarter-megabyte dump.

tokens swallowed --json and --with-telemetry-recipe: documented, never
threaded, so --json returned the humanized payload where the docs promise
byte-stable v5.0.0 output.

M-BUG-42: manifest's render contract asked for {load}; the payload carries
loadPattern, so the Load column rendered blank for all 96 rows.

Four new tests (1449 -> 1453), each verified red before the fix. The
render-contract test checks {field} names against a live payload from a
fixture, since a hardcoded key list would drift. Frozen v5.0.0 snapshots
untouched.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VGCk9o27eWo9uXLjkZTXEq
2026-08-01 20:40:07 +02:00

10 KiB

name description argument-hint allowed-tools model
config-audit Claude Code Configuration Intelligence - audit, analyze, and optimize your configuration [posture|tokens|manifest|feature-gap|optimize|fix|rollback|plan|implement|help|discover|analyze|interview|drift|plugin-health|whats-active|campaign|knowledge-refresh|status|cleanup] Read, Write, Glob, Grep, Bash, Agent, AskUserQuestion opus

Config-Audit: Claude Code Configuration Intelligence

Analyze, report on, and optimize your Claude Code configuration.

Router Logic

If a subcommand is provided, route to it:

  • posture/config-audit:posture
  • tokens/config-audit:tokens
  • manifest/config-audit:manifest
  • feature-gap/config-audit:feature-gap
  • optimize/config-audit:optimize
  • fix/config-audit:fix
  • rollback/config-audit:rollback
  • plan/config-audit:plan
  • implement/config-audit:implement
  • help/config-audit:help
  • discover/config-audit:discover
  • analyze/config-audit:analyze
  • interview/config-audit:interview
  • drift/config-audit:drift
  • plugin-health/config-audit:plugin-health
  • whats-active/config-audit:whats-active
  • campaign/config-audit:campaign
  • knowledge-refresh/config-audit:knowledge-refresh
  • status/config-audit:status
  • cleanup/config-audit:cleanup

If a scope override is provided (current, repo, home, full), use it as the scope type (see Scope Resolution below).

If no subcommand and no scope override: run the default audit (see below).

UX Rules (MANDATORY — apply to every step)

  1. Narrate before acting. Before each step, tell the user what you're about to do and why, in plain language.
  2. Never show raw output. All scanner Bash commands MUST use --output-file <path> AND 2>/dev/null. The user should NEVER see JSON, stderr progress lines, or exit codes.
  3. Handle exit codes silently. Append ; echo $? to scanner commands. Exit codes 0/1/2 are all expected (PASS/WARNING/FAIL). Only exit code 3 is a real error — tell user: "Scanner encountered an unexpected error. Try /config-audit posture for a quick check instead."
  4. Explain, don't dump. When presenting findings, add plain-language context. "Grade B" alone means nothing — say "Grade B — your CLAUDE.md files are well-structured with minor improvements possible."
  5. Separate signal from noise. If findings exist in tests/fixtures/ or examples/ directories, count them separately and exclude from the main count: "Found 37 findings (66 additional in test fixtures, excluded)."
  6. Context-sensitive next steps. Don't just list commands — explain what each does and why the user might want it based on their specific results.

Default Audit (no arguments)

Step 1: Auto-detect scope and greet the user

If the user provided a scope override (/config-audit full, /config-audit repo, etc.), use that.

Otherwise, auto-detect:

  1. Run git rev-parse --show-toplevel 2>/dev/null via Bash
  2. If it succeeds and pwd is inside the repo → repo scope (use the git root path)
  3. If pwd is $HOMEhome scope
  4. Otherwise → current directory scope

Show the user what's happening:

## Config-Audit

Analyzing your Claude Code configuration...

**Scope:** {Repository|Home directory|Current directory} — `{path}`
**What this checks:** CLAUDE.md quality, settings validation, hook safety, rules correctness, MCP server config, import chains, conflicts, and feature coverage.

Step 2: Initialize session

  1. Generate session ID: YYYYMMDD_HHmmss format
  2. Create session directory and findings subdirectory:
mkdir -p ~/.claude/config-audit/sessions/{session-id}/findings

This is a silent infrastructure step — do NOT show output to the user.

Step 3: Run scanners and posture assessment

Tell the user: "Running 12 configuration scanners..."

Run both scanners and posture in a single Bash command. Default mode runs the humanizer, so each finding in scan-results.json carries userImpactCategory, userActionLanguage, and relevanceContext alongside the v5.0.0 fields. If the user passed --raw, thread it through to both CLIs to get v5.0.0 verbatim output.

RAW_FLAG=""
if echo "$ARGUMENTS" | grep -q -- "--raw"; then RAW_FLAG="--raw"; fi
# Set to the scope flags the detected scope calls for, otherwise leave empty.
# A placeholder in square brackets does not start with a dash, so both CLIs'
# arg loops would take it as the TARGET PATH instead of a flag.
SCOPE_FLAGS=""   # e.g. SCOPE_FLAGS="--full-machine" or SCOPE_FLAGS="--global"
node ${CLAUDE_PLUGIN_ROOT}/scanners/scan-orchestrator.mjs <target-path> --output-file ~/.claude/config-audit/sessions/{session-id}/findings/scan-results.json $SCOPE_FLAGS $RAW_FLAG >/dev/null 2>/dev/null; node ${CLAUDE_PLUGIN_ROOT}/scanners/posture.mjs <target-path> --output-file ~/.claude/config-audit/sessions/{session-id}/posture.json $SCOPE_FLAGS $RAW_FLAG 2>/dev/null; echo $?

Use --full-machine for full scope, --global for home scope. For repo and current, pass the resolved path directly.

Check the echoed exit code:

  • 0, 1, or 2 → continue normally
  • 3 → tell user: "Scanner encountered an unexpected error. Try /config-audit posture for a quick check instead." and stop.

Step 4: Analyze results

Tell the user: "Scanners complete. Preparing your results..."

Read BOTH output files using the Read tool:

  • ~/.claude/config-audit/sessions/{session-id}/findings/scan-results.json
  • ~/.claude/config-audit/sessions/{session-id}/posture.json

Extract these metrics from the JSON:

From posture.json:

  • overallGrade — the health grade (A-F)
  • opportunityCount — number of unused features detected
  • areas[] — per-area grades and finding counts (use only quality areas, exclude Feature Coverage)

From scan-results.json:

  • aggregate.total_findings — total findings (test fixture findings are already excluded automatically)
  • fixture_findings array (if present) — count of findings excluded from test/example directories
  • Count findings by severity from aggregate.counts (critical, high, medium, low, info)
  • Count findings where autoFixable: true
  • Note total files_scanned across scanners

Step 5: Update state

Write session state (silent — no user output):

session_id: "{session-id}"
current_phase: "analyze"
completed_phases: ["discover", "analyze"]
next_phase: "plan"
updated_at: "{ISO timestamp}"
scope_type: "{repo|home|current|full}"
target_path: "{resolved path}"

Write to: ~/.claude/config-audit/sessions/{session-id}/state.yaml

Step 6: Display results

Present results using this template. The humanizer has already replaced jargon-heavy title/description/recommendation strings on every finding with plain-language equivalents — render them verbatim. Lead urgency phrasing with userActionLanguage ("Fix this now", "Fix soon", "Fix when convenient", "Optional cleanup", "FYI") and group "What you can do next" suggestions by that field. Do not re-derive an A/B/C/D/F-to-prose ladder here; the humanized stderr scorecard headline already supplies the grade context, and userActionLanguage supplies finding-level urgency.

### Results

**Health: {overallGrade}** | {qualityAreaCount} areas scanned

{Use the headline line from the humanized stderr scorecard — it carries grade-context prose already. Avoid hardcoding a separate per-grade prose ladder.}

Scanned {files_scanned} files | {real_finding_count} findings ({severity_breakdown})
{If test_fixture_count > 0: "({test_fixture_count} additional findings in test fixtures were excluded.)"}
{If fixable_count > 0: "{fixable_count} of these can be auto-fixed."}

### Area Breakdown

| Area | Grade | Findings | |
|------|-------|----------|-|
| CLAUDE.md | {grade} | {count} | {one-phrase status} |
| Settings | {grade} | {count} | {status} |
| Hooks | {grade} | {count} | {status} |
| Rules | {grade} | {count} | {status} |
| MCP Servers | {grade} | {count} | {status} |
| Imports | {grade} | {count} | {status} |
| Conflicts | {grade} | {count} | {status} |

{For the status column, use the humanized title from the most-severe finding in that area, or a one-phrase plain-language summary. Findings carry userImpactCategory which already groups by impact bucket — use that vocabulary, not raw scanner names.}

{If opportunityCount > 0:}
{opportunityCount} feature opportunities available — run `/config-audit feature-gap` for context-aware recommendations.

### What you can do next

Group suggestions by `userActionLanguage` from the humanized findings:

{If any finding has userActionLanguage "Fix this now" or "Fix soon":}
- **`/config-audit fix`** — auto-fix what's possible (backup created first, one-command rollback). The remaining items go into a prioritized plan.
- **`/config-audit plan`** — produce a prioritized action plan for the items that need manual attention.

{If most findings are "Fix when convenient" or "Optional cleanup":}
- **`/config-audit feature-gap`** — see which features could enhance your setup; pick what you want and implement on the spot.
- **`/config-audit fix`** — auto-fix anything deterministic; the rest is genuinely optional.

{If only "FYI" findings:}
- **`/config-audit feature-gap`** — explore opportunities; nothing is urgent.

Session saved to: `~/.claude/config-audit/sessions/{session-id}/`

Scope Resolution

Scope What gets scanned
current Current directory + parent CLAUDE.md files up to root + ~/.claude/
repo Git repository root + ~/.claude/
home ~/.claude/ global configuration only
full Everything: ~/.claude/, managed paths, all dev dirs under $HOME

Error Handling

  • If scanner fails (exit 3), tell the user in plain language and suggest /config-audit posture as fallback
  • If path doesn't exist, tell the user: "That path doesn't exist. Run /config-audit without arguments to auto-detect."
  • If git command fails for auto-detect, silently fall back to current scope
  • If no CLAUDE.md found anywhere, explain: "No CLAUDE.md found. This is the main configuration file for Claude Code — creating one is the single highest-impact thing you can do. Run /config-audit feature-gap to see what's recommended."