Imported from enzoomoreira/claude-config (
skills/core-code-audit/SKILL.md). Install upstream withnpx skills add enzoomoreira/claude-config --skill core-code-audit. Copyright stays with the author.
What I do
Guide audits of uncommitted code changes with validation interleaved into the analysis -- every suspicion is researched and cross-checked the moment it arises. No unverified claim ships. I own the methodology. Stack-specific hot-spots (what to look for in Python async code vs Vue reactivity vs SSE wire format) live in the stack-* skills loaded alongside.
Load me when an audit is needed on uncommitted changes, a pull request diff, or a scoped subset of files. Pair with a stack-* skill matching the detected language(s).
Core principle: interleaved validation
Do NOT accumulate a list of suspicions and validate them later. The moment a possible problem appears, pause the walk and run the validation loop (below) on it. The suspicion only survives as a finding if it holds up. This replaces the old "review then validate" two-phase flow.
Audit Tier (choose up front)
Pick the tier from the scope BEFORE starting -- it changes what "enough evidence" means. State the tier and a one-line justification in the Audit Summary.
Light (code-citation is enough, external research optional)
- <= ~50 LoC changed
- No change to observable contracts (API response shape, SSE event shape, public types, CLI flags, DB migration, stored data shape)
- No security-sensitive surface (auth, input parsing, file I/O with user paths, crypto, token handling)
- Internal refactor, rename, comment, test-only change
Full (external validation + repro attempt required for Critical findings)
- Anything that touches a contract (HTTP / SSE / public type / schema / CLI arg)
- Security, concurrency, error handling, or data-loss surfaces
- Runtime behavior of browser / library / framework APIs (ResizeObserver, asyncio, event loops, GC, reactivity, etc.)
-
~50 LoC changed OR > 3 files touched
When in doubt, escalate to Full.
Process
1. Context gathering
Run in parallel:
git status-- changed filesgit diff-- unstagedgit diff --cached-- staged
For untracked files in git status, read them directly (they do not appear in diffs).
Apply the scope filter (e.g. "frontend" -> only frontend/**). If scope matches no uncommitted change, say so and stop. Do not invent findings.
Determine the stack(s) from the files in scope and load the matching stack-* skill(s). Those supply the hot-spot checklists you apply during the walk.
2. Walk the changes, validating inline
Evaluate each file against these axes. The moment anything looks wrong, switch to the Validation Loop before continuing:
Code quality
- Self-documenting names, (rare) comments, consistent style
- DRY, SRP, reasonable function sizes, clear separation of concerns
- Type safety: strict types, no loose casts, correct return/error types
- Error handling: specific exceptions, edge cases, graceful degradation
Architecture
- Matches existing project structure and naming conventions
- Uses the same patterns as the rest of the codebase
- Respects layer boundaries
- Appropriate (not over-engineered) patterns; reasonable coupling
Security
- Injection (SQL / command / HTML), XSS, auth bypass, sensitive data exposure, hard-coded secrets, insecure deps
- Input validation at boundaries, output encoding, secure defaults, least privilege
Performance
- N+1 queries, unnecessary loops, large in-memory structures, blocking ops in async contexts, missed caching
- Avoid false positives: O(n) on small n is fine; no premature caching; no theoretical bottlenecks without evidence
Dead code / backwards-compat
- No unused imports / vars / functions / classes
- No commented-out code
- No unused parameters or branches for removed logic
- No backwards-compat shims or deprecated wrappers (unless the user explicitly asked for them)
Stack hot-spots -- the loaded stack-* skill has a targeted checklist for the language/framework. Apply it here.
3. Validation loop (per suspicion, before writing it down)
-
Trace implications in the codebase
- Read callers, callees, surrounding module
- Check whether the problem is already handled elsewhere (upstream guard, framework invariant, config default)
- Confirm the pattern is genuinely inconsistent with the codebase, not just unfamiliar to you
- If the claim is "X happens," verify X can happen given real call sites
-
Consult external sources
context7(resolve-library-id->query-docs) for library / framework contracts and version-specific behaviorWebSearchfor current best practices, third-party opinions, known pitfalls, consensus on similar situations- Prefer primary sources (official docs, library source) over blog posts when they conflict
MANDATORY when:
- The claim invokes runtime behavior of a browser / library / framework API (e.g. "the browser does not fire scroll when scrollTop is unchanged", "asyncio cancels children on...", "Pydantic validates X in order Y", "Vue loses reactivity when...")
- The suspicion depends on a version-specific contract (deprecated API, behavior change between versions)
- The finding would be classified as Critical -- no Critical ships on code-reading alone in Full tier
Code-citation-only is acceptable when:
- The claim is purely syntactic / structural logic internal to the patch ("branch unreachable because guard above returns", "import unused")
- All callers of the affected symbol are in the patch or adjacent and visible
- The behavior is fully determined by code in the repo, not by external runtime
-
Attempt to reproduce (Critical findings only, Full tier)
- A minimal script / curl / console snippet that triggers the bug
- Python:
uv run python -c "..."or a targeted test - TS/JS: a short snippet in a Node or browser console; for frontend runtime, a contrived input fed into the pure function
- If repro is impractical (full env / real data / timing race), say so explicitly and record the assumed failure path -- this becomes a known weakness of the finding, not a hidden one
-
Classify
- Real Problem -- confirmed by documentation, adjacent code, or reproducible reasoning. Keep it.
- False Positive -- dissolves under research. Drop it; optionally record in Dismissed with the evidence that killed it.
- Depends -- real only under project-specific constraints. Flag the assumption explicitly in the finding.
-
Reject overengineering
- If the "fix" adds complexity without a concrete payoff the user cares about, the suspicion does not survive.
- "Could theoretically break under unusual conditions" is not enough -- show the realistic path.
Every finding that survives must cite evidence: which file/line confirmed the codebase implication, which doc/URL confirmed the external claim. If research is inconclusive, say so explicitly or drop the finding.
4. Propose fixes (Real Problems only)
Before writing the fix into the output:
- Search for all callers / consumers of every symbol the fix touches (
Grepfor the name). Confirm the fix does not silently break an adjacent code path. - Check for parallel uses of the same pattern (e.g. if fixing an SSE wrapper, check every SSE consumer).
- Record side-effects investigated in the finding under "Callers checked" so the reviewer sees what you considered.
Then:
- Simplest change that resolves the issue
- Minimal diff; no drive-by refactors or new dependencies
- Keep existing patterns; cite the source that justifies the fix
- Effort estimate:
- Trivial: < 5 min, 1-2 lines
- Small: 15-30 min, single file
- Medium: 1-2 hours, multiple files
- Large: half day+, architectural change
5. Self-check before emitting output
Before writing the final report, answer these. If any answer is "no / not done / unsure", validate now or downgrade the finding.
- For every Critical: did I reproduce the bug OR explicitly record that I couldn't?
- For every Critical whose root cause involves runtime/library behavior: did I consult docs or the web, not just the code?
- For every proposed fix: did I grep for callers / consumers of the symbols I am changing?
- For every claim of "X doesn't happen" or "Y always happens": is that backed by a specific source, or by my own assumption?
- Are there any suspicions I dropped silently without putting them in Dismissed?
Unvalidated claims that survive this step are labeled (unverified) in the output and downgraded from Critical to Suggestion.
6. Prioritization
- Critical (Fix Now): security with exploit path; data loss / corruption; production-breaking bugs
- Important (Fix Soon): perf issues at realistic scale; error handling that hides bugs; missing validation at trust boundaries
- Nice-to-Have: readability, minor optimizations, better naming
- Dismiss: false positives (with evidence), premature optimization, theoretical concerns without real impact
Output format
## Audit Summary
Scope: <what was audited>
Tier: <Light | Full> -- <one-line justification>
Stack(s): <python | typescript-vue | mixed>
<2-3 sentence overview of changes and overall health>
## Validated Critical Issues
### <Issue Name>
- **Location**: file:line
- **Problem**: <what and why it matters>
- **Evidence**:
- Codebase: <file:line that confirms the implication>
- External: <doc URL / context7 result / advisory -- required in Full tier>
- **Repro**: <script / curl / console snippet that triggers it, OR "not reproduced -- assumed failure path: ...">
- **Callers checked**: <symbols grepped and where they appear; confirms fix scope>
- **Fix**: <minimal solution; snippet if helpful>
- **Effort**: <Trivial | Small | Medium | Large>
## Improvement Suggestions
### <Suggestion>
- **Location**: file:line
- **Current**: <what exists>
- **Proposed**: <better approach>
- **Benefit**: <why>
## Dismissed Concerns
- <Concern>: <what research / adjacent code killed it + source>
## Context-Dependent
### <Issue>
- **Depends On**: <factors>
- **If A**: <fix approach>
- **If B**: <leave as-is because ...>
- **Question for developer**: <what to clarify>
## Implementation Plan
1. <Fix 1> -- Est: X
2. <Fix 2> -- Est: X
Total: ~X
Omit empty sections. If there are no Critical issues, say so in the summary and skip that section.
Tone
- Constructive: improvement-focused, not criticism
- Educational: explain WHY, not just WHAT
- Collaborative: offer options, discuss trade-offs
- Pragmatic: respect project context and scope
- Honest: if something is fine, say it's fine -- and if research is inconclusive, say that too
- Scope-disciplined: never report on files outside the requested scope, even if you notice something
Anti-patterns
Don't:
- Nitpick style issues (linters handle that)
- Suggest enterprise patterns for simple scripts
- Recommend premature optimization
- Impose personal preferences as rules
- Overwhelm with too many low-value issues
- Emit findings without validation evidence
- Treat "obvious" as an excuse to skip verification -- use the tier system instead
Do:
- Focus on impactful, evidence-backed improvements
- Provide concrete code snippets
- Prioritize security and correctness over style
- Respect existing architecture decisions
- Acknowledge good work alongside issues
Source trust hierarchy
High trust
- Official language / framework documentation
- CVE databases, OWASP, security advisories
- Framework maintainer posts / talks
- RFCs, language specifications
Medium trust
- Well-maintained open source projects
- Established tech blogs (check dates)
- Conference talks from known experts
Low trust (verify independently)
- Stack Overflow answers (check date and votes)
- Random blog posts
- AI-generated content
- "This worked for me" anecdotes
Common false positives to watch for
Performance
- "Loop is slow" -> O(n) fine when n is small
- "Use caching" -> premature unless measured
- "Avoid regex" -> modern engines are fast for simple patterns
- "Too many DB queries" -> 3 is fine; 300 is not
Security
- "SQL injection" -> ORM / parameterized queries already safe
- "XSS" -> framework auto-escapes (Jinja2, Vue template interpolation)
- "Hard-coded secret" -> actually a public constant or default
Architecture
- "Violates DRY" -> intentional duplication for clarity
- "Needs abstraction" -> YAGNI for current scope
- "Should use pattern X" -> overkill for the problem size
- "Too many responsibilities" -> one clear workflow with sequential steps