name: jr-audit
description: Full codebase audit using specialized expert agents. Scales dynamically with preflight estimation, validation baselines, and audit history. Supports scoping, filtering, and auto-fix. Prioritizes thoroughness over speed; use quick or nofix for fast paths.
argument-hint: "[path] [nofix|full|quick|--refresh-stack|--refresh-baseline|--converge[=N]|--no-verify-claims] [--only=dims] [--exclude=glob]"
effort: high
model: opus
disable-model-invocation: true
user-invocable: true
allowed-tools: Read Write(.claude/) Edit(.claude/) Write(.gitignore) Edit(.gitignore) Glob Grep Bash(git diff *) Bash(git status *) Bash(git log *) Bash(git ls-files *) Bash(git rev-parse *) Bash(git diff-tree *) Bash(git show *) Bash(git config --get *) Bash(git clean -fd *) Bash(git -c core.symlinks=false checkout *) Bash(git reset *) Bash(gh repo view *) Bash(gh pr list *) Bash(gh pr view *) Bash(gh api *) Bash(gh auth status *) Bash(gh issue list *) Bash(gh issue create *) Bash(glab repo view *) Bash(glab mr list *) Bash(glab mr view *) Bash(glab api *) Bash(glab auth status *) Bash(glab issue list *) Bash(glab issue create *) Bash(jq *) Bash(wc *) Bash(grep *) Bash(stat *) Bash(test *) Bash(mkdir -p ) Bash(rm -f .claude/) Bash(rm -f -- ) Bash(mv .claude/) Bash(find . *) Bash(cat *) Bash(head *) Bash(tail *) Bash(comm *) Bash(sort *) Bash(printf *) Bash(date *) Bash(mktemp *) Bash(flock *) Bash(shasum *) Bash(sed *) Bash(tr *) Bash(awk *) Bash(xargs *) Bash(base64 *) Bash([ *) Bash(echo *) WebFetch AskUserQuestion Agent advisor TaskCreate TaskList TeamCreate TeamDelete SendMessage
Perform a comprehensive audit of the codebase using a swarm of specialized expert agents.
Arguments: $ARGUMENTS
Parse arguments as space-separated tokens. Recognized flags:
nofix— Findings-only mode. Skip Phase 5 (implementation) and Phase 6 (validation). Just report findings and stop. Alias:--dry-run.full— Force the full swarm even for small scopes.quick— Force lightweight mode (max 3 reviewers) even for large scopes.--refresh-stack— Force re-detection of package manager, validation commands, and stack info. Use after changing package.json scripts or switching package managers.--refresh-baseline— Force re-run of validation baseline even if a cached baseline exists within TTL.--converge[=N]— Re-audit modified files after Phase 6 (validate-fix loop) until no new findings emerge ORNiterations are reached. Default N depends onCLAUDE_EFFORT(read at runtime via Bash:effort="$CLAUDE_EFFORT"; [ -z "$effort" ] && effort=high):low/medium→ 2,high→ 3,xhigh/max→ 5 (mirrors/jr-review's effort-adaptive default, bounded by this skill's cap below). An explicit--converge=Noverrides the effort-adaptive default. Capped at[2, 5]— values outside the range warn and are clamped (N=1is upgraded to 2 with a warning since one iteration provides no re-audit;N>5is clamped to 5 to limit runtime). Mutually exclusive withnofix(no fixes means nothing to re-audit). When set, a wall-clock timeout of 15 minutes applies across the entire convergence loop.--no-verify-claims— Opt OUT of claim verification (anti-hallucination), which is on by default. By default, for findings the lead classifies in Phase 3 as external-authority claims (API deprecation, version-specific behavior, framework rules, CVEs, WCAG/OWASP — anything not provable from the cited code), the lead fetches an authoritative source to confirm or refute the claim before it reaches the report (confirmed→ tagged[verified: …];refuted→ rejected). Passing--no-verify-claimsskips the fetch (offline / speed); unverifiable external-authority claims are then capped tospeculativeand routed to the user (Tier 1 fallback). See Phase 3 step 0.5 and../shared/claim-verification.md.--only=<dimensions>— Run only the specified reviewer dimensions (comma-separated). All others are skipped. Example:--only=security,typescript,--only=testing,--only=simplicity.--model=<tier>— Override the model for every subagent spawned this run (sonnet|opus|haiku|fable); nested spawns inherit it. Does NOT change the lead (frontmatter applies before argument parsing — run/model <tier>first for a uniform run). Compatible with all other flags. Canonical semantics:../shared/model-override.md.--exclude=<glob>— (Repeatable) Remove files matching the glob from audit scope. Example:--exclude=src/generated/**,--exclude=**/*.stories.tsx.- Any bare path prefix — Limits audit to files under that path. Example:
src/hooks/. - Any bare number — Max validation retries (default: 3). Example:
5.
Examples: /jr-audit, /jr-audit nofix, /jr-audit src/api/, /jr-audit --only=security,node-api, /jr-audit quick --exclude=e2e/**, /jr-audit src/ nofix --only=typescript,testing 5, /jr-audit --refresh-baseline
If both a scope path and --exclude are provided, first filter to the path prefix, then remove excluded patterns.
Flag conflicts
full+quick—quickwins (explicit override for speed). Ignorefull.--refresh-baseline+nofix— baseline is skipped in nofix mode, so--refresh-baselineis silently ignored.--refresh-baseline+quick— baseline still runs in quick mode (unlike /jr-review where quick skips baseline), so--refresh-baselineapplies normally.--converge+nofix—nofixwins (no fixes means no re-audit needed). Warn:--converge ignored: nofix mode produces no fixes to re-audit.and proceed without convergence.--converge+quick— both apply: convergence runs but each iteration usesquickreviewer caps. Useful for tight cycles when you only need top-3 dimensions per pass.--no-verify-claims+ any mode — compatible with all modes. Classification + local grounding always run in Phase 3; verification (the Tier 2 fetch) runs by default and--no-verify-claimsskips it (falling back to the Tier 1 cap). Verification runs even undernofix(refuting a hallucinated finding is valuable even when no fix is applied) and underquick(limited to the reduced finding set).
Parameter sanitization
--exclude=<glob>: Reject values containing control characters (null bytes, newlines, carriage returns). Validate against allowlist regex^[a-zA-Z0-9_*?][a-zA-Z0-9/_.*?{},-]*$(must start with an alphanumeric character, underscore, or glob wildcard; remainder allows forward slashes, dots, hyphens, underscores, and glob characters —!is intentionally excluded to prevent glob negation patterns that could invert exclusion scope). Reject absolute paths (beginning with/). Reject paths containing../traversal sequences. Reject paths where any segment starts with a dot (matches(^|/)\.) to block hidden directories. Reject paths where any segment starts with a hyphen (matches(^|/)-) to prevent argument injection. Double-quote the value in any shell or Glob context.- Path prefix (first positional argument): Apply the same validation as
/jr-review's--scopeparameter — allowlist regex^[a-zA-Z0-9_][a-zA-Z0-9/_.-]*$, reject absolute paths, reject../traversal, reject dot-prefixed segments, reject hyphen-prefixed segments. Double-quote in Bash commands. - Max retries (positional number argument): Validate as a positive integer. If the value exceeds 10, warn: 'Max retries capped at 10 to limit automated modification cycles.' and use 10. If 0, negative, or non-numeric, warn and use default (3).
--only=<dimensions>: Trim leading and trailing whitespace from each comma-separated value before validation. Ignore empty entries resulting from consecutive commas. Validate that each remaining value matches one of the recognized built-in dimension names:security,typescript,react,node,database,performance,testing,accessibility,infra,error-handling,css,dependency,architecture,comment,simplicityOR is defined as a custom reviewer dimension in.claude/review-config.md(if loaded in Track A). Reject values that match neither a built-in nor a custom dimension with: 'Unrecognized dimension: "". Valid built-in dimensions: security, typescript, react, node, database, performance, testing, accessibility, infra, error-handling, css, dependency, architecture, comment, simplicity. Custom dimensions can be defined in .claude/review-config.md.' Note: /jr-auditsupports additional dimensions (css,dependency,architecture,comment) beyond those available in/jr-review. These dimensions are specific to audit's broader scope.--model=<tier>: Allowlist regex^(sonnet|opus|haiku|fable)$. Reject any other value with:Invalid --model value '<value>'. Valid values: sonnet, opus, haiku, fable.(per../shared/model-override.md).
Model requirements
- Reviewer agents (Phase 2) and implementer agents (Phase 5): Spawn with
model: "opus"(or the--modeloverride when set —../shared/model-override.md). Include in each agent's prompt: "Before reporting each finding: (1) re-read the cited code and confirm the issue is real, not speculative; (2) check whether another dimension owns it per the boundary rules and defer if so; (3) calibrate confidence honestly — usespeculativewhen you cannot verify without context you don't have. Do not report findings you would not defend in a PR review." - All other phases (context gathering, dedup, validation, cleanup): Default model is fine — these are mechanical steps. Any agent spawned in these phases also honors a
--modeloverride (the override is total, not premium-sites-only).
Display protocol
Common rules — phase headers, running progress timeline, silent-reviewers/noisy-lead, compact reviewer progress table (Phase 2), Phase 5/6 compact display, console-output redaction (interactive + headless variants) — are in ../shared/display-protocol.md (read into lead context at Phase 1 Track A; hard-fail guard ensures it was non-empty and structurally valid). Apply those verbatim. The two subsections below are /jr-audit-specific and stay inline.
Findings-first approval display (Phase 4)
Present the tier summary first before listing individual findings:
Tier 1 — Critical & High (14 findings)
3 critical | 11 high
Dimensions: typescript (5), security (3), node-api (2), react (2), error-handling (1), database (1)
Tier 2 — Medium (12 findings)
Dimensions: testing (4), performance (3), react (2), typescript (2), accessibility (1)
Tier 3 — Speculative (3 findings)
Dimensions: performance (2), architecture (1)
Then present AskUserQuestion per tier with:
- Approve all — approve everything in this tier without seeing details
- Review individually — expand the full finding list for cherry-picking
- Skip tier — skip this tier entirely
- Abort — cancel the audit
Phase 0 — Preflight (with parallel config pre-read)
Run three tracks in parallel:
Track 1 — Cost estimation
- Count the files in scope (fast Glob). Apply scope filter and
--excludepatterns. - Determine how many reviewers will be spawned (based on Phase 2 logic and
--onlyfilter).
Track 2 — Config pre-read (head start on Phase 1 Track A)
Start reading configuration files in parallel with Track 1 — these have no dependency on the user's Phase 0 decision:
- Read
CLAUDE.md,AGENTS.md,.claude/CLAUDE.md,.claude/review-config.md,.claude/audit-history.json— all in parallel using multiple Read tool calls in a single message. - Also pre-read project memory:
~/.claude/projects/"${PWD//[.\/]/-}"/memory/MEMORY.mdand every file it references (see Phase 1 Track A for the full rule). Silent no-op if the directory is absent. - If the user aborts, discard the results. If they proceed, Phase 1 Track A is already complete.
Track 3 — Codebase-memory graph probe
Detect whether the codebase-memory-mcp graph is available and indexed for this repo. This track exists because the architecture, dependency, error-handling, and cross-file-consistency dimensions are materially more accurate when backed by a graph than by Grep heuristics.
- Check tool availability: call
mcp__codebase-memory-mcp__list_projects(via ToolSearch if the schema isn't already loaded). If the tool cannot be loaded or errors out, setGRAPH_AVAILABLE=falseand skip this track — do NOT block the audit on graph absence. - If the tool loads, scan its result for an entry whose root path matches the current repo (compare
git rev-parse --show-toplevelagainst each project's root). If found, setGRAPH_AVAILABLE=trueandGRAPH_INDEXED=true; proceed silently. - If the tool loads but the current repo is NOT indexed, set
GRAPH_AVAILABLE=trueandGRAPH_INDEXED=false. After Track 1 completes and the file count is known, if the scope exceeds 30 files AND thequickflag is NOT set, offer via AskUserQuestion (fold into the existing Phase 0 Proceed prompt as an extra option):Codebase graph is available but not indexed. Indexing improves architecture, dependency, and cross-file findings. Options: [Index now, then proceed (Recommended)] / [Proceed without indexing] / [Narrow scope] / [Abort]. On Index now, callmcp__codebase-memory-mcp__index_repositoryfor the current repo and wait for completion before entering Phase 1; updateGRAPH_INDEXED=true. On Proceed without indexing, continue withGRAPH_INDEXED=false. For scopes of 30 files or fewer, silently skip the offer (graph overhead isn't worth it on small audits). - Pass
GRAPH_AVAILABLEandGRAPH_INDEXEDto Phase 2 so reviewers know whether to call graph tools or fall back to Grep.
After Track 1 completes
- Large scope warning: If the file count exceeds 300 and no scope filter or
--onlyis set, recommend narrowing. - Present via AskUserQuestion: "This audit will scope N files across M reviewers. Proceed?"
- Proceed — continue
- Narrow scope — let the user provide a scope filter
- Abort — cancel
Skip this prompt if quick flag is set (just proceed).
Phase 1 — Gather context and detect stack
Run the following in parallel where possible:
Track A — Read configuration
If Phase 0 Track 2 already completed these reads, reuse the results. Otherwise:
Read all of the following in parallel using multiple Read tool calls in a single message:
CLAUDE.md,AGENTS.md,.claude/CLAUDE.md(project standards — override generic best practices).claude/review-config.md(suppressions, severity overrides, custom reviewers, validation commands, finding budgets, auto-learned suppressions).claude/audit-history.json(cross-run shared state — schema defined in Phase 4.5 "Cross-run shared state"). At Phase 1 Track A, before reading any derivations, apply the canonical Read-side integrity check (mandatory) from../shared/audit-history-schema.md(all three steps: quarantine sentinel, cross-arrayrunIdreachability, timestamp sanity, plus the quarantine protocol). On quarantine, treat audit-history as absent for this run — skip all three derivations below AND the Phase 4.5 cross-run promotion check; the Phase 7 audit-history append still recreates the file with this run's entries. Then read three derivations from this file (skip silently if absent — fresh repo, OR quarantined this run):- Hot spots: from
runs[], files implicated as the source of ≥ 2 findings across the last 3 audit runs. Pass as priority targets to relevant reviewers in Phase 2. - Reviewer false-positive rates: take the last 5
reviewerStatsentries per dimension (anyskill, both/jr-auditand/jr-reviewcount) and compute the per-dimension running average ofrejectionRate. If a dimension's running average ≥ 0.25, mark it for a calibration note prepended to that reviewer's Phase 2 prompt:Calibration: Your last 5 runs in this project rejected an average of N% of findings — be more conservative on borderline cases. Prefer "speculative" confidence and skip findings you can't cite with a verbatim 3-line excerpt.The calibration note is operational, not informational — reviewers must apply it. lastPromptedAtmap for the global-preference promotion suppression check (see Phase 4.5).
- Hot spots: from
- Shared protocol files — single source of truth (resolve paths relative to this SKILL.md — one directory up then into
shared/):../shared/reviewer-boundaries.md,../shared/untrusted-input-defense.md,../shared/gitignore-enforcement.md,../shared/display-protocol.md,../shared/audit-history-schema.md,../shared/secret-scan-protocols.md,../shared/secret-warnings-schema.md,../shared/secret-patterns.md,../shared/cache-schema-validation.md,../shared/abort-markers.md,../shared/phase1-track-a-protocol.md,../shared/code-edit-discipline.md,../shared/claim-verification.md,../shared/forge-detection.md,../shared/model-override.md. These files are load-bearing — their content is referenced by later phases via call-sites (apply … per ../shared/<file>) rather than duplicated inline; the per-file usage map lives in the repoCLAUDE.md"shared/ — single source of truth" section. Passreviewer-boundaries.mdcontent verbatim to every reviewer prompt; passuntrusted-input-defense.mdcontent verbatim into every reviewer and implementer prompt; passclaim-verification.mdcontent verbatim to every reviewer prompt (the lead performs the authoritative claim classification at Phase 3 step 0.5). (/jr-auditis interactive-only as of writing — it consumes only the Advisory-tier classification section ofsecret-scan-protocols.md, not the headless/CI halt or User-continue path sections.) Hard-fail guard: if any shared file fails to Read, or returns empty content (zero bytes or whitespace-only), abort Phase 1 immediately with: "Phase 1 aborted:<path>is missing or empty. /jr-audit requires shared protocol files to enforce reviewer boundaries, untrusted-input safety, cache-write .gitignore checks, display-protocol consistency, audit-history schema, secret-scan protocols, secret-warnings schema, secret-pattern catalog, cache-schema validation, abort-marker rendering, Phase 1 Track A smoke-parse, code-edit discipline, claim verification, forge detection, and model-override semantics. Restore the file from git or the repo's canonical copy before re-running." Do NOT fall back to inline text — the inline duplicates were intentionally removed to eliminate drift; a missing shared file means the skill's guarantees cannot be enforced. Record the file byte-size and first-line hash in memory at Phase 1 so later call-sites can re-verify if they suspect tampering between Read and use. Structural smoke-parse (mandatory): After the read succeeds and content is non-empty, apply the smoke-parse algorithm and Canonical Anchor Table from../shared/phase1-track-a-protocol.md— each row of the canonical's table lists the required substrings for one shared file (case-sensitive, fixed-string match viagrep -F, AND-joined within a row). Self-reference escape hatch (hardcoded): before parsing the canonical's table, verify../shared/phase1-track-a-protocol.mditself contains the literal stringCanonical Anchor Table— a stub corruption of the canonical that preserves only its self-row anchor would otherwise pass the table-driven check. If any file fails the smoke-parse (self check OR any row check), abort Phase 1 with: "Phase 1 aborted:<path>is structurally invalid (smoke-parse:<missing-substring>). Restore the file from git or the repo's canonical copy before re-running." - Skill-local protocol files (mandatory): Read
${CLAUDE_SKILL_DIR}/protocols/phase2-reviewers.mdand${CLAUDE_SKILL_DIR}/protocols/phase7-report.mdinto lead context (parallel Reads with the shared/* files above). Apply the same hard-fail + non-empty + smoke-parse discipline: abort Phase 1 with[ABORT — SHARED FILE MISSING]per../shared/abort-markers.mdif either file is absent, empty, or fails its smoke-parse anchors (case-sensitivegrep -F) —phase2-reviewers.md:### Classify scope sizeAND### Finding format;phase7-report.md:False positive rates. - Project memory (auto-memory system, silent no-op if absent — new project): compute the memory dir via
memoryDir=~/.claude/projects/"${PWD//[.\/]/-}"/memory(the encoding replaces/and.in$PWDwith-). Read"$memoryDir/MEMORY.md"first; the file is an index of- [Title](file.md)pointers. Then fan out in parallel to read every referencedfeedback_*.md,project_*.md,reference_*.md, anduser_*.mdfile in$memoryDir. These entries are explicit user decisions from prior sessions in this project — treat them with the same precedence asCLAUDE.md. Pass the concatenated content to reviewers in Phase 2 as an additional Project memory block alongside the existing project-standards context. - User-global memory —
user-type entries only (silent no-op if absent): also read~/.claude/projects/-Users-jroussel--claude-skills/memory/MEMORY.md(the user's auto-memory dir; the path is fixed and independent of$PWD). From the index, fan out in parallel touser_*.mdfiles only — skipfeedback_*.md,project_*.md, andreference_*.mdhere because those are project-specific and must NOT leak across repos (e.g., a React/Tailwind-flavored feedback entry must not apply when auditing a Python service).user_*.mdentries describe the user's role, expertise, and communication preferences — those apply globally. If the current CWD is itself the skills repo, this file is the same as the project-memory read above; read it once and de-duplicate. Pass the user-global block to reviewers in Phase 2 under a User-global context header, separate from Project memory.
Track B — Collect file inventory
Run steps 4 and 5 in parallel (Glob and git churn are independent):
4. Collect source files: Use Glob to collect all source files. Include application code, configuration, and test files. Exclude node_modules/, dist/, build/, .git/, coverage reports, lock files, and generated artifacts. Apply scope filter and --exclude patterns.
5. Git churn analysis: Run git log --since="3 months ago" --format=format: --name-only | sort | uniq -c | sort -rn | head -20 to identify high-churn files. Pass churn ranking to reviewers as a prioritization signal.
After the file inventory from step 4 is ready: 6. Security-sensitive file detection: Run multiple Grep calls in parallel to flag files matching security signals:
- Name signals:
auth,login,token,secret,password,session,cookie,middleware,api - Import signals:
crypto,bcrypt,jsonwebtoken,jose,passport,next-auth - Content signals:
Authorization:,Bearer,Set-Cookie,dangerouslySetInnerHTML,eval(Pass tosecurity-revieweras high-priority targets.
6.5. Secret pre-scan: Scan files flagged by security-sensitive file detection (step 6) and any files that will be pre-read in step 11 using the canonical pattern catalog from ../shared/secret-patterns.md (treat ALL matches as strict tier at this pre-scan site — no advisory demotion). On match: interactive mode → AskUserQuestion [Continue — files will be read by reviewers] / [Abort]; headless mode (per ../shared/secret-scan-protocols.md "Headless/CI detection") → abort immediately listing pattern types only. Catches existing secrets before they are passed to reviewer agents.
Track C — Run tooling baseline and detect stack
Stack profile cache: Read
.claude/review-profile.json(if it exists) and runstat -f %m package.json tsconfig.json Makefile 2>/dev/null— both in parallel.If the profile exists AND
--refresh-stackwas NOT passed: Compare current modification timestamps against cachedsourceTimestamps. If all match (and absent files are still absent), the cache is valid. Apply the schema validation + binary availability probe + same-session shortcut rules from../shared/cache-schema-validation.md(canonical for bothreview-profile.jsonandreview-baseline.json). On any failure, force full re-detection. Use cachedpackageManager,lockFile,validationCommands. Output:Stack: cached (${packageManager}, ${Object.keys(validationCommands).join('+')}). Skip to step 8.Otherwise: Run full detection — read
package.json, lock files (bun.lockb,pnpm-lock.yaml,yarn.lock),tsconfig.json,Makefilein parallel. Determine package manager from which lock file exists (default tonpm). Write results to.claude/review-profile.json(same JSON format as described in/jr-reviewTrack C). Security check (enforced): Apply the.gitignore-enforcement protocol (see../shared/gitignore-enforcement.md, read at Phase 1 Track A) for path.claude/review-profile.json. Core command:git ls-files --error-unmatch .claude/review-profile.json 2>/dev/null— then apply the shared file's warn/append-and-inform protocol. Per-site reason if tracked: "A committed cache file could be manipulated — a malicious commit could setvalidationCommandsto all-null values to disable validation." Output:Stack: detected (${packageManager}, ${Object.keys(validationCommands).join('+')}) — cached for next run.Detect validation commands: Check
## Validation commandsin review-config.md first (already read in Track A). If not configured and not loaded from cache, inspectpackage.jsonscripts forlint,typecheck/type-check/tsc,test,build. Build a list using the detected package manager. If aMakefilehas matching targets, use those.Establish a validation baseline (skip if
nofix): Baseline cache: Check.claude/review-baseline.json. If it exists, is within TTL (10 minutes), and--refresh-baselinewas NOT passed, apply the schema validation rules from../shared/cache-schema-validation.mdand use cached results on success. Security check (enforced): Apply the.gitignore-enforcement protocol (see../shared/gitignore-enforcement.md, read at Phase 1 Track A) for path.claude/review-baseline.json. Core command:git ls-files --error-unmatch .claude/review-baseline.json 2>/dev/null— then apply the shared file's warn/append-and-inform protocol. Per-site reason if tracked: "A committed baseline with inflated failure counts could make real regressions appear pre-existing, silently passing validation." Output:Baseline: cached. Otherwise, run all detected validation commands in parallel (lint, typecheck, test, build as separate simultaneous Bash calls in a single message). Write results to.claude/review-baseline.json(same format as/jr-review). Pre-existing failures are NOT the audit's responsibility.Collect test coverage and dependency audit in parallel: Run both simultaneously using parallel Bash calls:
- Test coverage command (if available). Pass output to
testing-reviewer. <pkg-manager> audit(if available). Pass output tosecurity-reviewer.
- Test coverage command (if available). Pass output to
Lazy-load source files (default): Do NOT pre-read source files into the lead-agent context. Instead, pass each reviewer the file inventory (paths only) and grant Read access; reviewers fetch only the files relevant to their dimension on demand. Rationale: pre-reading 100 files at ~5–10KB each costs ~500KB–1MB in lead context that then multiplies across every reviewer prompt — verified token-cost hot spot. Lazy-load also means reviewers skip files irrelevant to their dimension entirely (e.g.,
accessibility-reviewerignores migration scripts). Opt-in pre-read fallback: If the user passes--prefetch(new flag, undocumented in primary help — internal escape hatch) AND scope ≤ 50 files, restore the original behavior of pre-reading all source files in batches of 10–15 per parallel Read call message and including content blocks in each reviewer prompt. Use only when reviewers report missing context — the default lazy path is correct for nearly all cases.
After all tracks complete
- Baseline health gate: If the build is completely broken (TypeScript compilation fails) or >50% of tests fail, warn the user and offer to abort.
- Store everything collected — file inventory, standards, suppressions, churn data, security-sensitive files, baseline metrics, coverage, dependency scan, pre-read contents.
Phase 2 — Spawn reviewer swarm (dynamically scaled)
The full Phase 2 procedure — scope classification, the effort-adaptive overlay, dynamic reviewer selection, swarm scaling, reviewer instructions (finding budget, per-reviewer calibration note, untrusted-input + claim-verification context, graph-backed queries), dimension boundaries, cross-file consistency analysis, and finding format — lives in ${CLAUDE_SKILL_DIR}/protocols/phase2-reviewers.md (read into lead context at Phase 1 Track A under the hard-fail + smoke-parse guard). Apply it here.
Phase 3 — Deduplicate and prioritize
After all reviewers complete (or time out), read the full task list (TaskList). As the lead:
- Sanity-check findings (reject hallucinations): Before dedup, iterate every finding and verify its citation is real. Each reviewer was required to submit — per finding — a
file, aline, and acodeExcerpt(3 consecutive lines from the cited file starting atline, verbatim with original whitespace; mandated in the reviewer prompt assembled in Phase 2). Run all checks in parallel via Bash — batch all file existence tests and line-count queries into a single multi-call message:test -f "$file" && wc -l < "$file"per finding. Reject a finding (delete the task) when (a) thefiledoes not exist relative to the scope root, (b)lineis not a positive integer, (c)lineexceeds the file's line count, or (d) content-excerpt mismatch — readfilelines[line, line+2]via the Read tool. Dedupe by file before reading: many findings cluster in the same file, so build a set of unique(file, min-line, max-line)tuples first, fetch each unique file once (batching all unique reads into a single message in parallel with the Bash checks), cache the content, then derive each finding's excerpt range from the cached content. Compare against the reviewer'scodeExcerptafter normalizing both sides (strip trailing whitespace per line; collapse any run of blank lines to a single blank; treat tabs and spaces as equivalent when the only difference is indentation). If no line in[line, line+2]matches any line in the excerpt after normalization, reject the finding. If the excerpt is missing or empty on a finding, treat it as hallucination evidence and reject. Log each rejection under[REJECTED — INVALID CITATION]with the reviewer's dimension name, the citedfile:line, the reason (one of: missing-file / bad-line / line-out-of-range / excerpt-missing / excerpt-mismatch), and — for excerpt-mismatch rejections — a 2-line diff showing what the reviewer claimed vs. what the file actually contains. Include all rejections in the Phase 7 report. Track the rejection rate per reviewer dimension; if a single reviewer exceeds 25% rejection, emit a Phase 7ACTION REQUIREDnote so the user can investigate whether that reviewer hit its turn limit or was confused by the file set. The content-excerpt check catches a subtler hallucination than the line-range check alone: real line number + fabricated problem description. If the reviewer couldn't quote the line, they probably couldn't read the line. 0.5. Verify claims (reject + cap hallucinated external facts): Apply../shared/claim-verification.md. For every finding that survived step 0, the lead (not the reviewer) classifies it by scanning its title/description for external-authority language (deprecated,removed in,as of version,violates the rules of,OWASP,CVE-,WCAG,best practice, version numbers tied to a behavior claim), defaulting to external-authority when in doubt; a finding is code-internal only when its correctness is provable from the cited excerpt plus other local files (already covered by step 0). For each external-authority claim, first try to ground it in the project's own internal official documentation (pinned dependency version inpackage.json/lockfile, local.d.ts/type defs, config) — if grounded, keep it and tag the grounding source. Otherwise, by default fetch an authoritative source (skip only under--no-verify-claims) per the doctrine's source-fetch discipline (gh api …/contents/<path>raw markdown, or the doc's raw.md; never rest a load-bearing claim on a singleWebFetchsummary — cross-check it). Thisgh apifetches an external authority (docs), so it staysgheven when the user's repo is on GitLab — external-authority carve-out,../shared/forge-detection.md§e; only user-repo forge ops switch with the detected forge.confirmed→ keep and tag[verified: <source> <date>];refuted→ delete the task, logged under[REJECTED — CLAIM REFUTED BY SOURCE]with the citedfile:line, the claim, and the contradicting source;unreachable/ambiguous/--no-verify-claims→ fall through to the cap. In the fall-through (verification skipped, unreachable, or uncorroborable), cap the finding's confidence tospeculativeand tag it[unverified external claim](its original severity is preserved for display — see step 3). Verify each unique claim-source at most once per run (in-memory dedup; no persisted cache in v1). Track a per-reviewerrefutedrate; if a single dimension exceeds 25% refuted, emit a Phase 7ACTION REQUIREDnote (mirrors step 0's escalation). - Deduplicate: Merge findings at the same code location. Keep the most actionable description. Use the highest confidence among merged findings. Exception: if merged findings have contradictory fixes, keep both and flag the conflict for the user in Phase 4.
- Root-cause clustering: Group findings with a shared root cause. Annotate blast radius (how many files/consumers affected).
- Drop low-value items: Delete
lowseverity tasks unless trivially fixable. Exception: never drop a finding whose lowered confidence is solely a step-0.5 unverified-external cap — its original severity governs visibility, so ahigh-severity unverified deprecation stays in its tier tagged[unverified — needs confirmation]. - Prioritize: Sort by severity → confidence → security-sensitive file → churn rank.
- Assign file ownership: Group tasks by file for implementer dispatch.
Display: Compact summary: 28 raw → 18 deduplicated (5 merged, 5 dropped), 3 root-cause clusters. Update timeline.
Zero findings: If no findings remain after dedup, skip Phases 4-6. Output: "Clean audit — no findings." Proceed directly to Phase 7 for cleanup and report.
Phase 4 — User approval gate (progressive disclosure)
Pre-approval advisor check (conditional): Before opening the tier display, evaluate two signals over the deduplicated findings:
- High volume:
totalFindings >= 20. - Dimension skew: any single reviewer dimension contributes
>= 60%oftotalFindings. (Skip the check iftotalFindings < 5— too few to compute a meaningful skew.)
If EITHER signal trips, call advisor() (no parameters — the full transcript is auto-forwarded) for a second opinion on the finding set BEFORE presenting tiers to the user. The advisor sees the run's evidence (reviewer outputs, rejection rates from Phase 3 step 0, citation excerpts) and can spot reviewer drift that the lead missed. If the advisor concurs, proceed silently to the tier display. If the advisor raises a concrete concern (e.g., "12 of 18 findings are from react-reviewer flagging the same component shape — likely a calibration issue, not 12 separate problems"), surface it via AskUserQuestion BEFORE the tier display: Advisor flagged a concern about the finding set: <one-line summary>. Options: [Continue to tier display] / [Drop the flagged dimension's findings and proceed] / [Abort the audit and re-run with --only=...]. On Drop the flagged dimension, treat all findings from that dimension as Phase 3 step 0 hallucination rejections (record them in audit-history.json under runs[] with rejected: true for FP-rate persistence). The advisor runs at most once per audit run — do NOT re-call between tiers. Skip the pre-approval check entirely if nofix is set with no tiers to display, AND skip if --quick is set (advisor latency outweighs benefit on focused audits).
Present findings in tiers. Follow the findings-first display from the Display protocol.
Tier 1 — Critical and high severity
Show tier summary first, then AskUserQuestion:
- Approve all — approve everything in this tier
- Review individually — expand for cherry-picking (show severity, confidence, file, one-line summary, doc reference). When rejecting, optionally provide a one-line reason.
- Abort — cancel audit
Tier 2 — Medium severity
Same pattern: summary → approve all / review individually / skip tier / abort.
Tier 3 — Speculative
Same pattern: summary → approve all / review individually / skip tier / abort. Unverified external-authority claims capped at Phase 3 step 0.5 surface here tagged [unverified external claim] — the ones verification couldn't confirm (source unreachable/uncorroborable, or --no-verify-claims was set); approving one accepts an unconfirmed external fact — prefer re-running online (without --no-verify-claims) to confirm or refute it first.
If the user aborts at any tier, skip to Phase 7 (cleanup). Delete rejected tasks and proceed.
If nofix is set: After tier review, skip directly to Phase 7. The approved findings serve as the audit output.
Phase 4.5 — Auto-learn from rejections
If the user rejected any tasks, analyze for patterns and append learned suppressions to .claude/review-config.md. Create the file if it doesn't exist.
Rules:
Only add a suppression if 2+ rejected findings share the same pattern (same dimension + same issue type) within this audit OR across recent audits. Check existing entries in
## Auto-learned suppressions— if a pattern was rejected once before and once now, that counts as 2. Single rejections are situational. Findings auto-capped tospeculativeby Phase 3 step 0.5 (unverified external claims) that the user did NOT explicitly reject do NOT count toward this threshold — a cap is not a rejection.Include the user's rejection reason in the suppression if provided.
Append under
## Auto-learned suppressionswith a date stamp.Never overwrite existing rules.
Never auto-learn suppressions for the
security-reviewerdimension. Security rejections should always be treated as situational rather than patterns to learn from. If a user wants to suppress specific security patterns, they must add them manually to.claude/review-config.md(requiring explicit intent). This prevents progressive disabling of security checks through accumulated auto-learned suppressions.Cross-run memory promotion (global preference check): After appending repo-local suppressions, scan
.claude/audit-history.json(canonical, shared with/jr-review— see "Cross-run shared state" below) for thisdimension+categorypair across the most recent 10 runs (including this one, both skills counted). If the samedimension+categoryhas been rejected in 2 or more separate runs AND the dimension is NOTsecurityAND nolastPromptedAtentry blocks re-prompting (see below), offer in interactive mode (skip silently in headless/CI mode):You've rejected findings in this dimension/category across N separate runs. Save as a global preference in your user memory? [Yes — save globally] / [No — keep repo-scoped]. On Yes, write a newfeedback-type memory file to the user-global auto-memory path~/.claude/projects/-Users-jroussel--claude-skills/memory/feedback_<dimension>_<category>.md(this path is fixed — it does NOT depend on the current CWD, because the intent is a preference that applies across every project, not just the one running this audit). Sanitize<dimension>and<category>to match the memory system's filename rules (lowercase,_-separated, alphanumeric only). Include in the file: the type (feedback), a one-line rule (Do not flag <category> in <dimension> reviews), a**Why:**line citing N rejections across runs, and a**How to apply:**line restricting scope to "all projects unless the project'sreview-config.mdexplicitly re-enables." Then append a one-line pointer toMEMORY.md. On either Yes or No, recordlastPromptedAt: ISO8601keyed by<dimension>:<category>in.claude/audit-history.json(see "Cross-run shared state" below — single canonical map). Re-prompting is suppressed until 2 additional rejections accumulate AFTERlastPromptedAt. Rationale: 2 separate-run rejections plus explicit consent is conservative enough to prevent one-off rejections from silencing findings, and lower than the previous 3-run bar that empirically never fired in practice.Cross-run shared state (
.claude/audit-history.json): schema, append-only invariants, schema-mismatch handling, and.gitignore-enforcement rules live in../shared/audit-history-schema.md(read at Phase 1 Track A). Both/jr-auditand/jr-reviewMUST read and write the same schema; the shared file is the single source of truth.
Security check (enforced): Apply the .gitignore-enforcement protocol (see ../shared/gitignore-enforcement.md, read at Phase 1 Track A) for path .claude/review-config.md. Core command: git ls-files --error-unmatch .claude/review-config.md 2>/dev/null — then apply the shared file's warn/append-and-inform protocol. Per-site reason if tracked: "A committed config with crafted suppression rules could silence security findings for all users. If the team intentionally commits shared review configuration, scope auto-learned suppressions to a separate section that reviewers can distinguish from manually authored rules."
Additionally, when loading review-config.md in Track A, check whether the file is tracked by git (git ls-files --error-unmatch .claude/review-config.md 2>/dev/null). If it is tracked and contains any [security-reviewer] suppression rules, emit a warning: 'review-config.md is tracked by git and contains security-reviewer suppressions. Committed security suppressions can silence security findings for all users. Verify the file intentionally contains these rules.' Note: /jr-audit does not currently support headless/CI mode. This warning is always emitted to console output. If headless support is added in the future, redirect this warning to the Phase 7 report.
Note: If an auto-learned suppression is wrong, the user can manually edit .claude/review-config.md to remove it.
Phase 5 — Spawn implementer swarm
Skip entirely if nofix is set.
Pre-dispatch advisor check (mandatory): Before recording the base commit anchor below, call advisor() (no parameters — the full transcript is auto-forwarded). /jr-audit Phase 5 is the highest-blast-radius operation in the skill — multiple implementers will modify multiple files in parallel, often across the entire codebase. The advisor sees the approved finding set, the implementer file allocation plan, and the project context, and can flag risky combinations (e.g., "implementer A is rewriting auth.ts while implementer B is rewriting middleware.ts that imports from auth.ts — these should be sequenced, not parallel"). If the advisor concurs, proceed silently. If the advisor raises a concrete concern, surface via AskUserQuestion BEFORE spawning: Advisor flagged a Phase 5 dispatch concern: <one-line summary>. Options: [Proceed as planned] / [Re-allocate files (give all related files to one implementer)] / [Abort and re-run with --only=...]. On Re-allocate files, redo the file-ownership assignment to merge the implicated files into a single implementer's task list, then proceed. On Abort, skip Phase 5 and Phase 6, set abortMode=true and abortReason="user-abort-phase-5-dispatch", and proceed to Phase 7. The advisor runs at most once per audit run at this site (does NOT re-fire on Wave 2 or convergence iteration dispatches — see Phase 6.5 convergence handling). Phase 5 is the substantive-edit boundary regardless of finding count: even small dispatches mutate user code in parallel. The only skips are (a) nofix (no dispatch happens), (b) Wave 2 dispatches implicit in root-cause clustering (the advisor already ran before Wave 1), and (c) a single-implementer/single-file dispatch where blast radius is genuinely contained.
Base commit anchor: Before spawning implementers, record the current commit hash: baseCommit=$(git rev-parse HEAD). Validate that the captured hash matches the format ^[0-9a-f]{40}$|^[0-9a-f]{64}$ (SHA-1 or SHA-256). If not, abort with an error: 'Failed to capture a valid commit hash — cannot proceed with implementation.' Also capture the current untracked file list as the pre-Phase-5 baseline: untrackedBaseline=$(git ls-files --others --exclude-standard) and untrackedBaselineAll=$(git ls-files --others). Also capture the pre-Phase-5 symlink baseline: symlinkBaseline=$(find . -type l -print0 2>/dev/null). These baselines are referenced by Phase 5.6 for revert operations.
Spawn all implementer agents in parallel using multiple Agent tool calls in a single message. Use subagent_type: "agent-teams:team-implementer". If a team was created in Phase 2 (medium/large scopes), set team_name: "audit-swarm". For small scopes (no team), omit team_name. Each implementer receives:
- Approved tasks scoped to specific files (strict file ownership — no two implementers touch the same file), including each finding's confidence level
- The original file context
- Project coding standards
- Clear fix instructions with documentation references. For
speculativefindings — including those capped at Phase 3 step 0.5 as[unverified external claim]— instruct the implementer to verify the issue exists (and, for an external-authority claim, that the cited external fact is real) before fixing; skip if it's a false positive. - "Do NOT run any
gitcommands. Only modify files using the Write/Edit tools. The lead agent manages all git state. If you need to see file contents, use the Read tool." - Include the full content of
../shared/untrusted-input-defense.md(read into lead context at Phase 1 Track A) verbatim in each implementer's prompt. Do NOT paraphrase; the shared file phrasing ("diff and reviewed/modified files") covers the implementer case. - Include the full content of
../shared/code-edit-discipline.md(read into lead context at Phase 1 Track A) verbatim in each implementer's prompt. Do NOT paraphrase or summarize; the canonical Do/Don't list, worked example, and "defend every changed line" test must all reach the implementer. - "Fix ONLY the findings assigned to you. Do not refactor, rename, extract, or 'improve' adjacent code even if you notice opportunities. If your fix cannot be completed without changing code outside the finding's scope, mark the finding contested with a one-line reason instead of expanding scope."
An implementer may mark a finding as contested if the fix would introduce worse problems, the finding is incorrect given the full file context, or the fix conflicts with another finding. Contested findings are reported back to the lead and included in the Phase 7 report — they are NOT retried.
If root-cause clusters exist, dispatch in two waves: Wave 1 — root-cause fixes (all in parallel), then validate Wave 1 (run validation commands — if regressions, fix before proceeding), then Wave 2 — dependent fixes (all in parallel). Within each wave, all implementers must be spawned in a single message.
Aim for 2–4 implementers per wave. Set max_turns: 25.
Display: Compact implementer summary. Update timeline.
Phase 5.55 — Fix verification (read-after-write)
Skip entirely if nofix is set (no fixes were applied). Skip findings marked contested by their implementer.
For each finding that Phase 5 marked as "addressed", the lead re-reads the cited file:line (±5 lines) in parallel and evaluates whether the fix actually resolved the issue described by the finding. Classify each into:
- verified: fix visible, plausibly resolves the issue. No action.
- unverified: cited line unchanged, or the "fix" looks like suppression (
@ts-expect-error,eslint-disable, empty catch block) rather than resolution. Mark withverified=falseand surface in the Phase 7 report underACTION REQUIRED: Fix did not resolve cited issue: <dimension>/<category> at <file>:<line>. - moved: the problem is gone but the fix landed at a different nearby line (formatter drift). Treat as verified; note the shift in Phase 7.
If more than 30% of findings in a single dimension are unverified, emit a Phase 7 ACTION REQUIRED note flagging that dimension for manual review. If any critical-severity finding is unverified, surface it explicitly — do NOT auto-revert (soft flag, not halt). Rationale: Phase 6 validation catches regressions, but lint/typecheck passing doesn't prove a finding was actually resolved. This check reads the cited lines and confirms the described issue is no longer present.
Display: Phase 5.55 — Verification: M/N fixes verified (K unverified, L moved) (or skip if zero fixes).
Phase 5.6 — Secret re-scan
Skip if nofix flag is set.
Before scanning, verify the base commit anchor is still valid: if [ "$(git rev-parse HEAD)" != "$baseCommit" ]; then warn: 'HEAD has moved unexpectedly — an implementer may have run git commands. Aborting for safety.' First reset HEAD to the base commit (git reset "$baseCommit"), then apply the Combined revert sequence from ../shared/secret-scan-protocols.md (uses git -c core.symlinks=false checkout + NUL-delimited symlink comparison; the canonical sequence is the only sanctioned form), set abortMode=true/abortReason="head-moved-phase-5.6", and proceed to Phase 7.
Re-run the secret pre-scan patterns against all files modified by implementers. Additionally, check for new untracked files created by implementers (git ls-files --others --exclude-standard) and include them in the scan. Also check for new gitignored files (git ls-files --others compared against $untrackedBaselineAll). Apply the advisory-tier classification per ../shared/secret-scan-protocols.md ("Advisory-tier classification for re-scans"): only strict-tier matches trigger the halt; advisory-tier matches (SK, dapi, sk- meeting demotion criteria) are logged to the report.
If strict-tier secrets are detected, halt immediately. Security check (enforced): Apply the .gitignore-enforcement protocol (see ../shared/gitignore-enforcement.md) for path .claude/secret-warnings.json (its warn/append-and-inform behavior). Per-site reason if tracked: "A committed secret-warnings file would conflate one user's accepted-secret entries with another's, silently suppressing legitimate halts." Then write detected secret locations to .claude/secret-warnings.json per ../shared/secret-warnings-schema.md (preserve any pre-existing consumerEnforcement value).
In headless mode (per ../shared/secret-scan-protocols.md "Headless/CI detection"), apply the CI/headless secret-halt protocol from the shared file (sets abortMode=true; the caller MUST also set abortReason="secret-halt-phase-5.6" before invoking).
In interactive mode, present via AskUserQuestion: [Abort | Continue].
- On Continue: apply the User-continue path protocol from
../shared/secret-scan-protocols.md("User-continue path after post-implementation secret detection") — execute ALL SIX behaviors verbatim (ACTION REQUIRED logging, audit-trail write, pre-commit hook offer, final⚠ SECRET STILL PRESENTwarning,userContinueWithSecret=truelatch for non-zero Phase 7 exit, and suppression-list snapshot to$postImplAcceptedTuples). No subset is permitted. Then proceed to Phase 6. - On Abort: apply the Combined revert sequence from
../shared/secret-scan-protocols.md, setabortMode=true/abortReason="secret-halt-phase-5.6-user-abort", proceed to Phase 7.
Phase 6 — Validate-fix loop
Skip entirely if nofix is set.
Post-implementation formatting
If the project has a formatter configured (detected from package.json scripts: format, prettier, etc.), run it on modified files first (before validation).
Validation
Run all detected validation commands in parallel (lint, typecheck, test as separate simultaneous Bash calls in a single message). Compare against the Phase 1 baseline — only new failures count as regressions.
- No new failures: Move to Phase 7.
- New failures: Fix regressions (dispatch multiple implementer agents in parallel — pass them coding standards so fixes don't introduce new violations; include all implementer safety instructions: git restriction, the full content of
../shared/untrusted-input-defense.mdverbatim — do NOT paraphrase, the full content of../shared/code-edit-discipline.mdverbatim — do NOT paraphrase, and strict file ownership), then re-validate. Repeat up to max retries (default 3).- Secret re-scan after regression fixes: Run the secret pre-scan against files modified by regression-fix implementers after each fix attempt. Apply the advisory-tier classification per
../shared/secret-scan-protocols.md("Advisory-tier classification for re-scans"): only strict-tier matches trigger the halt; advisory-tier matches (SK, dapi, sk- meeting demotion criteria) are logged to the report. If strict-tier secrets are detected, halt and present to user via AskUserQuestion. IfisHeadlessis true (per../shared/secret-scan-protocols.md"Headless/CI detection"), do NOT call AskUserQuestion — instead apply the automatic revert and failure exit from../shared/secret-scan-protocols.md("CI/headless secret-halt protocol"); the caller MUST also setabortReason="secret-halt-phase-6-regression"before invoking the protocol. If the user aborts, apply the Combined revert sequence from../shared/secret-scan-protocols.md(clean → rm-f → symlink-removal → checkout → reset), setabortMode=trueandabortReason="user-abort", and proceed to Phase 7 in abort mode. If the user continues, apply the User-continue path protocol from../shared/secret-scan-protocols.md(User-continue path after post-implementation secret detection) — execute ALL SIX behaviors verbatim. No subset is permitted (ACTION REQUIRED logging, audit-trail write to.claude/secret-warnings.jsonwithconsumerEnforcementpreserved and gitignore-enforcement applied, pre-commit hook offer, final⚠ SECRET STILL PRESENTwarning,userContinueWithSecret=truenon-zero-exit latch, suppression-list snapshot). Proceed with next retry.
- Secret re-scan after regression fixes: Run the secret pre-scan against files modified by regression-fix implementers after each fix attempt. Apply the advisory-tier classification per
- Max retries exhausted: Before moving to Phase 7, run the stuck-loop advisor check (single-fire). Initialize
phase6AdvisorFired=falseat Phase 6 entry; on the first time this branch is reached ANDphase6AdvisorFired=false, setphase6AdvisorFired=trueand calladvisor()(no parameters — full transcript auto-forwarded). Per../shared/advisor-criteria.md's "When stuck" criterion, validation regressions survivingmaxRetriesrounds are the canonical stuck signal. If the advisor concurs (no actionable insight), proceed silently to Phase 7 and report remaining failures. If the advisor offers a concrete actionable insight, surface via AskUserQuestion:[Apply suggested fix and retry once more] / [Stop here — proceed to Phase 7] / [Abort and revert all changes since $baseCommit]. On Apply, dispatch ONE additional implementer with the advisor's suggestion (include all implementer safety instructions: git restriction, the full content of../shared/untrusted-input-defense.mdverbatim — do NOT paraphrase, the full content of../shared/code-edit-discipline.mdverbatim — do NOT paraphrase, and strict file ownership); if that retry also fails, do NOT re-fire — proceed to Phase 7. On Abort, apply the Combined revert sequence (see../shared/secret-scan-protocols.md), setabortMode=true/abortReason="user-abort", proceed to Phase 7. The single-fire guard prevents budget burn — the advisor sees the full retry history once.
After a successful validation (no new regressions), update .claude/review-baseline.json with the post-fix results.
Display: Compact validation summary per command. Update timeline.
Phase 6.5 — Convergence loop (opt-in via --converge)
Skip entirely if --converge is not set, OR nofix is set, OR abortMode=true, OR Phase 6 ended with Max retries exhausted.
The full convergence-loop protocol — initialization, NUL-safe file tracking, termination conditions, pre-iteration advisor check (iter ≥ 2), per-pass constraints, iteration log — lives in convergence-protocol.md (read into lead context at Phase 1 Track A when --converge is set). Hard-fail guard: abort Phase 1 with [ABORT — SHARED FILE MISSING] if the file fails to Read, returns empty, or fails the smoke-parse anchor pre-iteration advisor check (case-sensitive grep -F). Apply that protocol verbatim. /jr-audit's maxIterations defaults effort-adaptively per the --converge[=N] flag doc (low/medium → 2, high → 3, xhigh/max → 5; clamped 2–5).
Phase 7 — Cleanup and report
Declare-done advisor check (gated): Before rendering the report, call advisor() once (no parameters — the full transcript is auto-forwarded) if the run is non-trivial: findingCount >= 5 OR dimensionCount >= 3 OR rejectionCount >= 1 OR any fix was applied in Phase 5/6 OR abortMode=true. Per ../shared/advisor-criteria.md, declaring done on multi-phase work warrants a second opinion; the gate skips trivially-clean small runs (the "Unconditional advisor on every run" anti-pattern). The deliverable is durable by this point — fixes are committed to the working tree and the report is about to render — so an interruption mid-call loses nothing. If the advisor concurs, proceed silently. If it raises a concrete concern (e.g., a fix that doesn't match its finding, a missed regression, a contested finding that should have blocked), surface it in the report under an ADVISOR NOTES line. The Phase 5 pre-dispatch advisor covers the substantive-edit boundary; this one covers the run as a whole.
- If a team was created, send all shutdown requests in parallel (multiple SendMessage calls with
type: "shutdown_request"in a single message). Wait up to 30 seconds for confirmations — proceed with TeamDelete even if some agents don't respond. Skip if no team was created. - Run the following in parallel:
git diff --stat(if fixes were applied), write the audit report file, and update audit history.
Abort-mode reporting (mandatory, runs before report contents)
When abortMode=true, render the marker corresponding to the run's abortReason per ../shared/abort-markers.md (read at Phase 1 Track A). Implement via case "$abortReason" in ... ;; esac with NO glob arms — every reason value must match an explicit pattern so a typo (e.g., serect-halt-convergence) falls through to *) → [ABORT — UNLABELED] and surfaces the contract violation as ACTION REQUIRED. Reasons /jr-audit currently emits: head-moved-convergence-start, user-abort-phase-5-dispatch, user-abort-convergence, secret-halt-convergence. The canonical mapping covers each value (and any future ones added at /jr-audit abort sites — keep abort-markers.md in sync first if introducing a new reason).
The rendered marker appears at the top of the Phase 7 report on its own line so the run outcome is unmistakable. Exit-code rules and the full set of exit-forcing markers are defined in ../shared/abort-markers.md ("Exit-code contribution") — consult that file as the single source of truth (the marker set includes [AUDIT-HISTORY BACKUP FAILED] in addition to the abort/revert/secret/fresh-eyes/audit-trail/secret-warnings markers).
Anti-patterns to avoid (mirrors abort-markers.md's "Anti-patterns" section): do NOT emit two markers for the same event (a secret-halt-* reason that already produced [SECRET DETECTED — ...] MUST NOT additionally emit [ABORT — *]); do NOT render markers when abortMode=false; do NOT add a glob arm in the case statement.
Report redaction
Apply the canonical line-by-line console-output redaction rule from ../shared/display-protocol.md ("Console output redaction" section) using the canonical pattern catalog in ../shared/secret-patterns.md. Both files are already loaded at Phase 1 Track A; do NOT re-fetch them here.
Save report
Security check (enforced): Apply the .gitignore-enforcement protocol (see ../shared/gitignore-enforcement.md, read at Phase 1 Track A) for path .claude/audit-report-YYYY-MM-DD.md (with the concrete date). Core command: git ls-files --error-unmatch ".claude/audit-report-YYYY-MM-DD.md" 2>/dev/null — warn if tracked; if the glob .claude/audit-report-*.md is not in .gitignore (git check-ignore -q returns non-zero), append the glob and inform the user. Per-site reason if tracked: "Audit reports contain finding descriptions, code excerpts, and potentially redacted secret locations — these should not be committed to the repository."
Write audit report to .claude/audit-report-YYYY-MM-DD.md.
Save audit history
Update .claude/audit-history.json per the canonical schema in ../shared/audit-history-schema.md. Create the file with the empty four-key shape if it doesn't exist; tolerate older array-only formats by upgrading them in place per the shared file's "Schema upgrade" rules.
Per-run appends with skill: "audit":
- One entry to
runs[]per (dimension, category) rejection from Phase 4 OR Phase 3 step 0 hallucination rejection. Only rejection records are appended. - One entry to
runSummaries[]keyed by a fresh UUIDv4runId. - One entry per producing dimension to
reviewerStats[](skip dimensions withtotalFindings == 0).rejectedFindingscounts Phase 3 step 0 + Phase 4 rejections together. lastPromptedAtis owned by Phase 4.5 only.
Atomic-write + per-session-filename fallback rules apply per ../shared/secret-warnings-schema.md "Atomic write" section (the flock(1) probe and post-flock fallback are shared between secret-warnings.json and audit-history.json).
Security check (enforced): Apply the .gitignore-enforcement protocol (see ../shared/gitignore-enforcement.md, read at Phase 1 Track A) for path .claude/audit-history.json. Core command: git ls-files --error-unmatch .claude/audit-history.json 2>/dev/null — then apply the shared file's warn/append-and-inform protocol. Per-site reason if tracked: "A committed history with manipulated false-positive rates could bias reviewer calibration in future audits."
Report contents
The Phase 7 final-report shape — the timeline display, the 18-item Summarize enumeration, and the "only non-empty sections" rule — lives in ${CLAUDE_SKILL_DIR}/protocols/phase7-report.md (read into lead context at Phase 1 Track A under the hard-fail + smoke-parse guard). Apply that protocol verbatim.