Help us improve
Share bugs, ideas, or general feedback.
From audit-logic
Performs systematic line-by-line logic audits of any module to find real business logic bugs, data corruption, and race conditions. Language-agnostic, adapts to any stack.
npx claudepluginhub minhthang1009/dotclaude --plugin audit-logicHow this skill is triggered — by the user, by Claude, or both
Slash command
/audit-logic:audit-logic <module-path-or-directory><module-path-or-directory>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
Perform a systematic, line-by-line logic audit of the target module. The target is the path passed as the skill argument (`<module-path-or-directory>`); if no argument was given, ask the user for the target before starting. The goal is to find **real bugs** — not style issues, not theoretical edge cases — bugs that cause wrong behavior, data corruption, race conditions, or incorrect business ru...
Guides technical evaluation of code review feedback: read fully, restate for understanding, verify against codebase, respond with reasoning or pushback before implementing.
Share bugs, ideas, or general feedback.
Perform a systematic, line-by-line logic audit of the target module. The target is the path passed as the skill argument (<module-path-or-directory>); if no argument was given, ask the user for the target before starting. The goal is to find real bugs — not style issues, not theoretical edge cases — bugs that cause wrong behavior, data corruption, race conditions, or incorrect business rule enforcement in production.
Language-agnostic and framework-agnostic. Adapt discovery, test commands, and doc search to whatever stack exists in the target directory.
List every source file in the target directory (exclude test files, generated files, build artifacts, lock files). Print the full list — and note alongside it which test files will also be read in Phase 2 — so the user sees the true audit scope before proceeding.
Find the project's primary documentation (CLAUDE.md, README.md, architecture docs, or equivalent). Read the section describing what this module does and what business rules it must enforce. This establishes the expected behavior to audit against.
Identify and run the existing test suite for this module to establish a green baseline:
Create gate state file — only after the baseline outcome is settled (green baseline, no-tests noted, or the user approved continuing despite failures). Use the Write tool to create .claude/audit-logic-state.json at the project root (the directory Claude Code was started in — same as ${CLAUDE_PROJECT_DIR}, which is where the Stop hook reads it; not the cwd if they differ):
{"findings_confirmed": false, "phase4_gate": false, "phase5_gate": false, "phase6_gate": false, "phase7_gate": false}
The Stop hook (bundled with this plugin — hooks/hooks.json → audit-logic-gate.sh → audit-logic-gate.py) reads this file and blocks if gates are incomplete. Creating it after step 3 keeps the "stop and ask the user" path for a red baseline unblocked. Delete the file after Phase 7 retrospective completes — or immediately if the user aborts the audit at any point (see Ground Rules).
Before reading the first file: read references/reading-patterns.md in full. Then print one line:
"Reading patterns loaded: [list the 5 categories most relevant to this module's stack and domain]."
Use that list as a checklist while reading each source file — it prevents systematic blind spots (e.g., skipping encoding/type-coercion checks on a payment module).
Read every single line of every source file listed in Phase 1. Not excerpts. Not grep summaries. Not subagent delegation. Full files, read directly.
Critical rule: Do NOT use subagents or Explore agents to do the reading for you. Subagents read code from a fresh context without the accumulated understanding built across files — they miss cross-file invariants and subtle inconsistencies. Read every file yourself.
Apply these rules while reading:
src/__integration__/ or equivalent) — real DB behavior, constraint enforcementsrc/__api__/ or equivalent) — full request-response business rule assertionsinvariants.*.md, *.property.test.js) — high-level correctness contracts the module must maintain
Reading these is faster than running them, and they often directly name the bugs unit tests miss.Reading order for large modules (>10 files) — adapt to the stack:
What to look for — consult references/reading-patterns.md while reading each file. Key patterns: race conditions, missing transactions, aggregate-vs-per-item checks, null/undefined boundary failures, guard clauses that can be bypassed, dead code, type coercion bugs, off-by-one errors, and business rules enforced in one path but missing in another.
Phase 2 self-check before proceeding to Phase 3: Print a brief coverage summary (visible to the user — not a silent mental check) confirming all of the following:
Simply listing file names is not sufficient — you must demonstrate you read the content. If you cannot answer "what does TC-X assert about method Y?" for key methods, or "what business rule does the integration test for this module verify?", you have not completed Phase 2.
After reading all files, review the running issue list. For each item, determine:
Is it a real logic bug? Would it cause incorrect behavior, data corruption, a security vulnerability, a race condition, or meaningful user-facing confusion in production? If the answer is "maybe, theoretically" — it is not a bug yet.
Is it reachable? Can the buggy branch actually be triggered from a production code path? Trace the call chain.
Is it already tested? Grep test files for the condition. If an existing test exercises the path and it passes, revisit the analysis — maybe the "bug" is intentional behavior.
[UNIT-TEST-BLIND], check if the integration or API tests read in Phase 2 already cover this behavior — if they do, the finding is tested at integration level and should not be tagged. If they do not, tag [UNIT-TEST-BLIND] — the finding is real, but the unit test suite cannot confirm or deny it.Is it provable from source code alone? Can the bug be demonstrated by tracing the project's own source, without relying on assumptions about how a third-party framework or library behaves internally?
node -e "...", python -c "...", go run, etc.) to confirm. Do not classify as HIGH without this verification. If verification is not possible in this environment, tag the finding [NEEDS-RUNTIME-VERIFY] and cap severity at MEDIUM. Unless the user explicitly approves fixing it anyway, a [NEEDS-RUNTIME-VERIFY] finding defaults to deferred — it must appear in the Phase 7 deferred list with reason "requires runtime verification".What is the minimal fix? Before touching any file, run a pre-flight check:
Classify each confirmed issue:
Severity calibration for race conditions: Ask "what is the worst-case outcome?"
Present the classified findings to the user and wait for confirmation before touching any file. Use examples/finding-report-template.md as the format template — each HIGH/MEDIUM finding must include: file + line, concrete reproduction steps, minimal fix description, and test name; INFO findings may use a lighter format (file + line, observation, recommended action). The user decides which severity levels to fix, and in what order.
While waiting, the Stop gate hook will block the first attempt to end the turn (the state file still has phase4_gate: false — this is expected, NOT a signal to proceed). When that happens: print "Waiting for user confirmation of findings — ending the turn." and end the turn again; the hook allows the second stop attempt. Do NOT treat the hook firing as implicit approval. Do NOT proceed to Phase 4 or Phase 5 without an explicit user reply.
After the user confirms (explicit reply): update the state file, then continue to Phase 4 (Completeness Check) — do not skip Phase 4:
{"findings_confirmed": true, "phase4_gate": false, "phase5_gate": false, "phase6_gate": false, "phase7_gate": false}
This is the ONLY place findings_confirmed is set to true (besides the zero-findings rule below). Exit gates in later phases change their own gate field only — never this one.
If there are zero findings (clean module): report "No findings — module clean." to the user, set "findings_confirmed": true in the state file (nothing to approve — record "zero findings" as the reason in the Phase 7 summary), and continue. Phases 4–6 will be vacuous — state so explicitly at each gate instead of staying silent.
Before starting Phase 5, review the full running issue list from Phase 2.
For every item you considered but did NOT include in Phase 3 findings, track it now for inclusion in the Phase 7 deferred list:
| [finding description] | [reason not included: out of scope / by design / unreachable / fix cost too high / ...] |
If nothing was dismissed: note "No dismissed findings." explicitly.
If a dismissed item on second look deserves to be a finding (you dismissed it too quickly), surface it to the user NOW — before Phase 5 runs — and wait for their decision (same waiting rule as Phase 3: the user decides whether it joins the fix list). Do not silently park it in the deferred list, and do not fix it without approval.
Rule: every item that appeared in the Phase 2 running issue list must appear in either Phase 3 findings or Phase 7 deferred. Silent disappearance is not allowed.
This step exists because "Document what you don't fix" is a ground rule, but without a checkpoint it is easy to skip. This is the checkpoint.
After completing all items: set "phase4_gate": true in .claude/audit-logic-state.json — change only this field; findings_confirmed is owned by Phase 3.
If the user approved zero fixes (every finding deferred): print "No fixes approved — Phase 5 skipped.", set the Phase 5 gate, and proceed to Phase 6. The exit-gate checklist below is then vacuously satisfied — state so explicitly instead of leaving it unaddressed.
Commits: invoking this skill counts as explicit authorization for the Phase 5 per-bug fix commits and Phase 6 doc commits — no additional confirmation is needed beyond the Phase 3 findings approval. If the target project is not a git repository: skip all commit steps, record each fix in the Phase 7 summary instead, and recommend the user initialize version control.
For each confirmed bug, in severity order (HIGH first):
Apply the minimal surgical fix — change only what is necessary to fix this specific bug. Do not refactor adjacent code, rename variables, or improve style in the same commit.
Before touching any file: if the fix adds, removes, or renames a parameter in a function that is called from other files (repository methods, service functions, utilities), grep test files for assertions on the current call signature using whatever assertion syntax the project uses (e.g. toHaveBeenCalledWith, assert.calledWith, expect(...).toBeCalledWith, verify(mock).method(args)):
grep -r "<assertion_matcher>" <test_dirs> | grep "<function_name>"
Count how many test assertions use the current call signature (this counts assertions, not files — distinct from the Phase 3 step 5 deferral rule, which counts test files). If more than 3, note upfront that test assertion updates will be needed and which files contain them — this prevents discovering test failures mid-fix and having to context-switch back to understand why they fail.
Write or update tests. Default: REGRESSION — would have failed before the fix, passes after. Exception: DOCUMENTATION — only for INFO fixes where behavior is genuinely unchanged (cosmetic/intent-clarification); must label explicitly in commit message. See Exit Gate for labeling requirements.
If the project has no test framework (established in Phase 1): skip test-writing and follow "When no test runner is available" in references/verification-techniques.md — document the expected behavior in the commit message and mark the fix explicitly as unverified. Steps 3–4 below also do not apply; state this instead of staying silent.
The test must:
[UNIT-TEST-BLIND] fixes: unit test updates only document intent — mocks accept any argument so they cannot verify real DB/integration behavior. You must also:
test.skip (or the framework's equivalent) with a comment explaining what it verifies and why it requires a real environment. This is not optional: without this placeholder, the correctness guarantee has no safety net for future test runs in the appropriate environment.
// Verifies [BUG-X]: [description of what the test proves]
test.skip('[BUG-X] integration test — requires real DB/service', async () => { ... });
Run the test suite for this module. Expected: previously passing tests still pass, the new/updated test passes. If unrelated tests break:
Run the full project test suite to confirm no regressions.
Run the project's linter/formatter if one exists and is configured.
Spawn an independent verification agent — unless the fix is trivially small. Skip the agent and do a manual read instead when ALL of the following are true: (1) fix changes ≤ 3 lines in 1 file, (2) fix does NOT add/remove a function parameter visible to callers, (3) the changed function has no downstream callers in other modules. For anything larger, spawn the agent. Do NOT write a custom prompt. Use the exact template below, replacing only [list changed files]:
Read these files: [list changed files]
For each file, determine:
1. Is the logic correct? Are all business rules properly enforced?
2. Are there race conditions, data integrity risks, or missing validation?
3. Are there edge cases where the code produces incorrect output?
Do NOT look at git history, commit messages, or any description of what was changed.
Read the current code only.
Report findings with specific file and line number references.
The agent must not know your intent; that context biases it toward confirming rather than finding remaining issues. Compare its findings against your fix.
Commit with a message that answers three questions: what was wrong, why it was wrong, what changed. Use the commit format in references/verification-techniques.md.
Repeat for each bug. One bug = one commit. Do not batch multiple bugs into a single commit.
Before proceeding to Phase 6, confirm every item below. Do not skip or defer silently — if an item cannot be done, state the reason explicitly.
[UNIT-TEST-BLIND] fixes: the unit test passes; integration or API test placeholder written (test.skip with // Verifies [BUG-X] comment) — this is mandatory, not optional.After completing all items: set "phase5_gate": true in .claude/audit-logic-state.json — change only this field.
After all bug fixes are committed:
Search for documentation files that reference the changed behavior. Use the doc-discovery patterns in references/verification-techniques.md (Discovering Stale Documentation section): search by function name, by old behavior keywords, and by checking module-level docs in the same and parent directories.
For each doc file found: check whether descriptions of the changed behavior are now factually wrong.
If the project maintains test-count metrics or coverage summaries in documentation, update those numbers. Scan the entire repository, not just the module directory — test counts are often tracked in multiple documentation files outside the module. Use the format you discovered while reading the project's docs to identify what to grep for, then find all files containing that stale count and update them all.
Commit doc updates separately from code fixes with a message like docs(<module>): update after <bug-name> fix.
After completing all items: set "phase6_gate": true in .claude/audit-logic-state.json — change only this field.
Print a final summary:
[NEEDS-RUNTIME-VERIFY] finding here unless the user approved fixing it.After printing the summary:
/pipeline-retrospective (provided by the subagent-system plugin) to evaluate this audit run — it writes improvement proposals to .claude/improvement-proposals.md at the project root. This is mandatory — not optional. An ad-hoc retrospective in chat is not a substitute. Exception: if the skill is not installed, state this in the summary, record that the retrospective was skipped for that reason, and continue closing the gates — a missing dependency must not leave the session permanently blocked."phase7_gate": true in .claude/audit-logic-state.json — change only this field (safety net: keeps the Stop hook passing even if step 3 fails)..claude/audit-logic-state.json (cleanup — allows the Stop hook to pass)./pipeline-retrospective run — or its absence recorded with reason (see step 1 Exception).claude/audit-logic-state.json deleted.claude/audit-logic-state.json before ending the turn. An orphaned state file blocks the first stop attempt of every turn in every future session of this project.Load these references when needed — they contain detailed patterns and techniques that are too long to include here:
references/reading-patterns.md — Concrete patterns to look for while reading: race conditions, transaction boundaries, guard clause bypasses, null/undefined failures, type coercion, off-by-one, business rule coverage, dead codereferences/verification-techniques.md — False-positive filtering, independent verification agent prompt, test strategy, doc discovery, severity classification, commit message formatWorking examples for reference:
examples/finding-report-template.md — Template for presenting audit findings to the user: file + line, reproduction steps, minimal fix, test nameexamples/independent-verification-exchange.md — How to run Phase 5 step 6 independent verification and interpret the results, including how to handle new findings the agent surfaces