From blitz
Framework-API correctness audit for Firestore, VueFire, Vue 3, and Pinia. Detects anti-patterns, misuse, dead exports, and duplication. Read-only by default; --fix applies low-risk fixes. Use when the user says 'code-doctor', 'audit firestore', 'pinia anti-patterns', or sees framework-API warnings in logs.
How this skill is triggered — by the user, by Claude, or both
Slash command
/blitz:code-doctor [scope] [--scan|--fix|--fix-all] [--rules firestore,vuefire,vue,pinia,dead,duplication][scope] [--scan|--fix|--fix-all] [--rules firestore,vuefire,vue,pinia,dead,duplication]opus**/*.vue**/firestore.rules**/firebase.json**/stores/**/*.{ts,js}**/*.firestore.{ts,js}This skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
<!-- import: from _shared/project-context.md §Canonical block — Project Context with stack detection -->
!${CLAUDE_PLUGIN_ROOT}/scripts/detect-stack.sh
OUTPUT STYLE: terse-technical per /_shared/terse-output.md. Drop articles, fillers, pleasantries, hedging. Preserve verbatim: code fences, inline code, URLs, file paths, commands, grep patterns, YAML/JSON, headings, table rows, error codes, dates, version numbers. No preamble. No trailing summary of work already evident in the diff or tool output. Format: fragments OK.
Terse exemptions (LITE intensity): severity:critical message field — full sentences required. Resume terse on other severities.
Detect framework-API anti-patterns, misuse, dead exports, and duplication candidates in the project. Default mode is read-only (--scan). Apply low-risk auto-fixes with --fix. Execute every phase in order.
--scan mode (the default).--fix or --fix-all.--fix applies only rules where auto_fix: true in references/main.md.--fix-all applies all fixable rules; print ⚠ fix-all mode: modifying files before any edit.// code-doctor-ignore comments silently — log each suppression in the report.⚠ RATCHET FAIL and list the increased rule ids.Follow session-lifecycle.md §Session Registration and terse-output.md:
SESSION_ID = "code-doctor-<8-char-hex>"SESSION_TMP_DIR = ".cc-sessions/${SESSION_ID}/tmp/"skill_start to .cc-sessions/activity-feed.jsonlPrint:
[code-doctor] Phase 0: INIT
[code-doctor] ├─ session: <SESSION_ID>
From ARGUMENTS:
src/ if it exists, else .)--scan (default), --fix, --fix-all--rules <comma-list> (default: all applicable sets)--no-confirm skips LLM judge in Phase 2.code-doctor.json if present (see references/main.md §E)# Check package.json for framework dependencies
grep -E '"firebase"|"firestore"' package.json 2>/dev/null && echo "HAS_FIRESTORE"
grep -E '"vuefire"' package.json 2>/dev/null && echo "HAS_VUEFIRE"
grep -E '"vue"' package.json 2>/dev/null && echo "HAS_VUE"
grep -E '"pinia"' package.json 2>/dev/null && echo "HAS_PINIA"
Only load and run rule sets whose dependency is detected. If --rules is specified, further filter to those sets.
Print which rule sets will run:
[code-doctor] ├─ rule sets: firestore, vuefire, vue, pinia (dead, duplication)
[code-doctor] └─ mode: scan (read-only) ✓
Read the Rule Table section of references/main.md. Extract only the rows for active rule sets.
For each rule in the active set:
# Example for rule F5
grep -rn "\.docs\.map(d\s*=>\s*d\.data()" --include="*.ts" --include="*.vue" <scope>
Collect findings: { ruleId, file, line, matchedText, severity }.
For rules that require context checking (e.g., F2: onSnapshot without onUnmounted in same file, F6: getDocs(collection( without query( wrapping):
# Check if onSnapshot exists without onUnmounted in same file
for f in $(grep -rl "onSnapshot(" --include="*.vue" <scope>); do
grep -L "onUnmounted" "$f" && echo "MISSING_CLEANUP: $f"
done
Apply inline suppression: skip findings on lines containing // code-doctor-ignore: <ruleId>.
Print progress per category:
[code-doctor] Phase 1: SCAN
[code-doctor] ├─ firestore rules (10)... 3 findings
[code-doctor] ├─ vuefire rules (5)... 1 finding
[code-doctor] ├─ vue rules (5)... 2 findings
[code-doctor] ├─ pinia rules (5)... 0 findings
[code-doctor] ├─ dead export check... 1 finding
[code-doctor] └─ duplication check... 0 findings
# Find all exported symbols
grep -rn "^export " --include="*.ts" <scope> | grep -v "export \*" | grep -v "export type"
# For each export, check if it's imported anywhere
# Flag exports with 0 import matches across the scope
Use a rolling hash approach via Bash: extract 5-line windows from .ts/.vue files, flag windows that appear verbatim in 2+ files. Limit to max 20 duplication findings to avoid noise.
Skip this phase if --no-confirm flag is set or if there are no critical findings.
For each severity: critical finding, spawn a single Agent (subagent_type: general-purpose, model: sonnet) with a tight prompt:
You are a code reviewer. Confirm if this is a real violation of rule <ruleId>.
Rule: <rule description from references/main.md>
File: <file path>
Relevant code (±10 lines around line <line>):
<code excerpt>
Answer: YES (real violation) or NO (false positive), one line, then a one-sentence reason.
Update finding: if agent says NO, set confirmed: false and exclude from report counts (but still list as "dismissed" in report appendix).
Print:
[code-doctor] Phase 2: JUDGE
[code-doctor] ├─ 2 critical findings sent to LLM judge
[code-doctor] └─ 2 confirmed, 0 dismissed
Group confirmed findings by severity: critical → major → minor.
For each finding, include:
file:line — exact locationmkdir -p docs/_audits
Write to docs/_audits/YYYY-MM-DD_code-doctor.md using the schema from references/main.md §D.
Print a compact findings table:
[code-doctor] Phase 3: REPORT
[code-doctor]
[code-doctor] CRITICAL (2)
[code-doctor] ├─ F2 src/composables/useOrders.vue:14 — onSnapshot without cleanup
[code-doctor] └─ V1 src/pages/Dashboard.vue:8 — useCollection outside setup
[code-doctor]
[code-doctor] MAJOR (3)
[code-doctor] ├─ F5 src/stores/orders.ts:42 — .docs.map(d => d.data()) loses id
[code-doctor] ├─ F6 src/services/db.ts:17 — unbounded getDocs(collection(...))
[code-doctor] └─ G1 src/components/OrderList.vue:23 — v-if + v-for same element
[code-doctor]
[code-doctor] MINOR (1)
[code-doctor] └─ V3 src/plugins/firebase.ts:3 — useFirestore() called 3× in file
[code-doctor]
[code-doctor] Report: docs/_audits/YYYY-MM-DD_code-doctor.md
Read .cc-sessions/code-doctor-ledger.jsonl (last entry). Compare current counts.
If any severity count increased:
[code-doctor] ⚠ RATCHET FAIL — new violations since last run:
[code-doctor] major: 2 → 3 (+1) — new: F6 in src/services/db.ts:17
Append new ledger entry regardless:
{"ts":"<ISO>","session":"<SESSION_ID>","critical":2,"major":3,"minor":1}
Skip entirely if mode is --scan (default).
--fix: apply only rules with auto_fix: true in references/main.md (F5, V3, P2)--fix-all: apply all rules with a fix_recipe — print ⚠ fix-all mode: modifying files firstFor each fixable finding:
file_change to activity feedPrint per fix:
[code-doctor] ├─ FIXED V3 src/plugins/firebase.ts:3 — deduplicated useFirestore() calls
Run a targeted grep for the fixed rule ids to verify the fix removed the violation. If any remain, log as fix_partial and instruct the user to review manually.
Log skill_complete to activity feed:
{"event":"skill_complete","message":"code-doctor scan complete","detail":{"critical":<n>,"major":<n>,"minor":<n>,"fixed":<n>}}
Print:
[code-doctor] Done. <critical> critical · <major> major · <minor> minor
[code-doctor] Next: fix critical issues manually — run /blitz:code-doctor --fix for auto-fixable minors
If there are critical findings, suggest /blitz:refactor for the extraction candidates or direct file editing for Firestore fixes.
npx claudepluginhub lasswellt/blitz-cc --plugin blitzGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.