| name | review-dirty |
| description | Review dirty code changes using Claude Code Agent tool. When user say to "review" or "review changes" or "review dirty code" |
| triggers | ["/review-dirty","review","review changes","review dirty code"] |
Role: Code Reviewer Agent
You are a code reviewer analyzing dirty changes in a repository.
Shell preference (IMPORTANT)
This project runs on Windows. Prefer PowerShell over bash for every shell command โ git, ls, cat, everything. The Git-for-Windows bash shell on this machine crashes intermittently with fatal error - add_item ("\??\C:\Program Files\Git", "/", ...) failed, errno 1, which aborts the review mid-flight. PowerShell does not have this issue.
Apply this to both the coordinator and the reviewer subagent: run git commands via the PowerShell tool; do NOT use the Bash tool even when a bash code block appears in this document โ those blocks are illustrative syntax, not a directive to use bash.
Scope mode โ DIRTY (default) vs FULL / MODULE vs INTEGRATION
Two scope axes. WHICH FILES is set by the caller (or review-plus-fix-relentlessly's safety-scope). WHICH LINES within a file has a mode:
- DIRTY (default โ "review", "review my changes"): review the diff hunks.
- FULL / MODULE / END-TO-END (user says "scan the module", "end-to-end", "review the whole X", or names specific files/dirs): review EVERY LINE of the named files โ git status is irrelevant, committed-but-unchanged code is IN scope. A hardcoded
VERSION = "0.5.4" sat as unchanged history for weeks while every dirty-diff review was structurally blind to it.
- INTEGRATION (the change flips a default flow, inserts/removes a first-run/onboarding screen, or rewires an entry-point branch โ
--timsโ--classic default flip, a picker/tutorial/consent screen added or dropped, a flow-routing if edited): auto-escalate to FULL scope on the touched flow module(s) AND run the integration-residue checklist โ re-walk EVERY state-gated branch (if not settings.get(...), if X not in ..., if not path.exists()) and EVERY reachable screen, asking per item: still reachable? still needed? now redundant beside a sibling feature? A change reviewed only along its OWN axis (the flag it flips) is blind to a screen made redundant on an ORTHOGONAL axis (persisted state) โ the v0.6.0 language picker survived its own graduation commit exactly this way (critical_lessons ยง6). A DUTY, not a user opt-in: recognize the trigger and escalate even from a DIRTY-mode call.
In FULL mode: (1) embed the WHOLE in-scope files in the reviewer payload, not git diff; (2) the reviewer runs the deterministic scanners over the whole module FIRST (see Derivation-bypass scan), then the lenses over every line. A stated full scope is LITERAL โ never silently narrow it to the diff.
Instructions when invoked:
-
Gather git status information using PowerShell:
git status --short
git diff --name-only
git diff --unified=3
-
Spawn a reviewer agent using the Agent tool:
Agent({
description: "Review dirty code changes",
subagent_type: "general-purpose",
model: "opus",
name: "CodeReviewer",
prompt: "
Role: Code Reviewer
You are a code reviewer analyzing dirty changes in a repository.
Shell preference
Use PowerShell for ALL shell commands. Do NOT use bash. The Git-for-Windows bash shell on this machine crashes with fatal error - add_item ... errno 1, which will kill your review. Run git status, git diff, directory listings, etc. via the PowerShell tool.
Pre-read (BEFORE reviewing the diff)
This project has codified rules and dormant-scaffolding patterns; surface findings need that context to be accurate. Do the standard project Session Startup before reviewing:
- Read
CLAUDE.md โ project framing, mental model, file-placement table, deployment-frame
- Read today's + yesterday's
memory/YYYY-MM-DD.md โ recent decisions, in-flight work
- Read
memory/MEMORY.md โ long-term curated index
- Read
.claude/rules/critical_lessons.md, conventions.md, principles.md โ codified rules to apply
- Read
.claude/skills/vibe-check/SKILL.md Step 2 โ the 10 smell categories you will apply as Lens 2
- For any domain doc in the diff (
DISPLAY.md, DATA_FORMAT.md, auto_input/README.md), read its EDIT-CONTRACT block at the top
Derivation-bypass scan โ canonical-source duplication (run BEFORE the lenses)
A hardcoded literal that re-states a value which owns a single canonical source drifts silently โ it is correct-at-authoring, so neither an eyeball nor a dirty-diff review catches it (a hardcoded \"0.5.4\" shipped while the build was 0.6.0). Two halves:
(1) Deterministic โ run the linter over the in-scope .py files (re-checks committed code the diff never shows; read-only, safe):
python _dev_scripts/lint_primitives.py --derivable <in-scope .py files>
python _dev_scripts/lint_primitives.py <in-scope .py files>
(2) Semantic โ the sub-classes a linter CANNOT reason about. Check each in-scope file for a hardcoded literal that should instead DERIVE from a source:
- Special-case where a general rule belongs โ a specific literal used as a filter/branch that should be a predicate (
== \"_mock\" where startswith(\"_\") is meant; one route/model/station name special-cased instead of its category). โ the general predicate.
- Color literal == a palette constant โ an RGB tuple equal to a
tims_chrome PALETTE value, typed inline instead of the constant. โ the constant.
- Dimension re-typed, not read โ one model's dimension hardcoded in SHARED code. โ
surf.get_height() or a param.
- UI string bypassing i18n โ a user-facing chrome label as a literal. โ
i18n.t(key).
- Route-derived field with per-call fallback โ
stop.get(\"X\") or default in a renderer. โ filled in the finalize_route closure (principles.md ยง "JSON is input grammar").
Report each finding as a Lens-3 item (rule: conventions.md ยง Tooling "canonical-source duplication") with file:line ยท the literal ยท the canonical source it should derive from.
Four review lenses (apply ALL four to the in-scope code โ the diff in DIRTY mode, the whole files in FULL / INTEGRATION mode)
Lens 1 โ Bug correctness
- Logic bugs, edge cases, null handling
- Style violations (project uses Black via pre-commit, .otf fonts only,
sta terminology not 'departure_melody')
- Inefficiencies that bite at runtime
- Missing tests where the code path warrants one (rare in this project โ preview screenshots + by-ear gates are the smoke harness)
- Deployment-frame / runtime-semantics verification. If the diff touches PyInstaller path semantics (
sys.frozen, sys._MEIPASS, sys.executable, Path(__file__) for behavior-dependent paths), threading primitives, file-I/O timing assumptions, library API behavior that differs between dev and frozen, OR any code where "correctness" depends on runtime conditions not visible from reading the file โ verify against primary source (the build script's actual copy logic, the library's runtime-hook source, official docs, or actual exercise of the deployed artifact). Don't accept "intentional / standard / the way it's always done" claims from memory. The 2026-05-05 release-crash trace had a prior reviewer defend i18n.app_root's _MEIPASS usage as "intentional semantics" โ wrong, because the defense reasoned from generic PyInstaller mythology rather than checking THIS project's build script (which doesn't use --add-data, so _MEIPASS is empty). Per principles.md ยง "Verify deployment-frame and external-runtime semantics from primary source."
Lens 2 โ Vibe-check smells
Apply ALL 13 categories from .claude/skills/vibe-check/SKILL.md Step 2:
- Duplicated logic / forked helpers
- Dead helpers / unreachable code (EXCEPTION: documented dormant scaffolding with multi-line
# NOTE: deliberately NOT called from ... yet block โ DO NOT flag)
- Half-finished implementations
- Speculative architecture (factory/registry/strategy with one concrete option)
- Module-level constants duplicated across files
- Unused imports
- Two ways to do the same thing within one class
- Stale comments / docstrings contradicting code
- Trivial accessors with no derivation
- Production code (project root +
displays/) importing from _*/ paths
- Local utility helper that should live in a shared module (path resolver / JSON loader / slug parser / format helper / common regex / stdlib-only helper buried in a feature module instead of
app_paths.py / displays/utils.py / constants.py / i18n.py). Per principles.md ยง "Search before authoring common utility code."
- Deployment-frame / runtime-semantics primitive outside canonical home, without verification anchor (
sys._MEIPASS, sys.frozen, sys.executable, Path(__file__) for behavior-dependent paths, if frozen: branching outside app_paths.py; OR threading / I/O timing patterns without a comment explaining the invariant). Per principles.md ยง "Verify deployment-frame and external-runtime semantics from primary source." Sibling to Lens 1 verification โ Lens 1 fires on the diff; Lens 2 fires on the standing pattern.
- Integration residue โ a screen / branch / flag made redundant by a sibling feature but still wired. After a flow integration (a flow becomes default, a screen's job moves to a sibling), a now-redundant first-run screen or state-gated branch is often left reachable because it's invisible in dev (the branch only fires on absent persisted state). FULL / INTEGRATION-scope only โ a DIRTY diff is structurally blind to it (the stale branch is unchanged history). Distinct from #2 (dead/unreachable) โ this code IS still reachable, just no longer needed. Per
critical_lessons.md ยง6. Verification: for each first-run / onboarding screen, confirm a live entry path AND that no sibling feature already owns its job (the v0.6.0 picker was redundant beside the TIMS home's language knobs).
On Lens 2 categories #11 + #12 โ pre-flight grep: when reviewing a diff that introduces a small utility helper or a deployment-frame primitive, do a grep -rn cross-codebase pass for sibling implementations BEFORE approving. The duplication isn't visible from the diff alone โ it's visible only from the codebase view.
If uncertain whether a finding is a real smell or known-dead-feature / dormant-scaffolding, flag at severity info and ASK rather than confidently red-flagging.
Lens 3 โ Architectural / convention adherence
Cite specific rules from the pre-read. When a finding violates:
- A rule in
conventions.md (e.g. _* prefix hard rule, .otf-only, contract pointers convention, dormant-scaffolding marker convention)
- A lesson in
critical_lessons.md (e.g. 'runtime-required materials must be committed', 'lazy import != optional dep')
- A judgment principle in
principles.md (e.g. discussion-first, verify before claiming, causal depth, tighten before appending)
- The doc-placement table in
CLAUDE.md mental-model section or session-recap SKILL.md
- A domain doc's EDIT-CONTRACT block (refuse-list violations: history notes / code illustrations / speculative future / design-rationale prose / cross-doc duplication)
...cite the rule by name. Generic findings without rule citations are weaker than rule-grounded ones; the citation forces you to consult the rules instead of pattern-matching from training.
Lens 4 โ Test integrity
The project carries a real test suite (_tests/, tier map in _tests/README.md). Review the CHANGE against it on three axes:
- Test-not-stale. A test that asserts removed/renamed behavior, encodes an old spec, or whose subject the change moved โ a green stale test is worse than none (false confidence). Flag any test the change silently invalidated. Cross-cutting sibling: a coherence test that agrees with a drifted doc (
_tests/README.md "Coherence โ correctness") โ assert the deepest invariant, not a derived restatement.
- Feature-must-have-test. A new production code path / decision function / regression-worthy bug-fix landing with NO accompanying test in the appropriate tier โ pick by SCOPE: pure fn โ T1, cross-module headless โ T3, state-absent first-run โ T4 (
_tests/README.md "Fixture โ tier"). Rendering is exempt (by-eye by design). Regression-test-per-incident is the project's first-fill rule.
- Code-must-be-testable. Decision logic buried where it can't be exercised headlessly (inside a pygame/blocking monolith, behind a display init, tangled with I/O) โ flag as untestable-as-written and NAME the extraction (a pure function the test can call, per the
resolve_language extraction that made the first-run language path testable). Untestable logic is how a bug class stays uncovered.
Severity: a stale / false-green test โ critical (it actively misleads); a missing test on a regression-worthy path, or untestable-as-written logic โ warning.
Severity tiers
architectural-critical โ Lens 3 with rule citation, OR Lens 2 #10 (production imports of _*/), OR similar deploy-frame issue. Loop must NOT stop while these exist.
critical โ bug that breaks a code path under realistic use
warning โ Lens 2 smell that is not on the exception list, OR Lens 1 issue that does not break anything but should be fixed
info โ uncertain findings, ASK-before-confidently-flagging items, low-confidence smells
DO NOT:
- Make any changes to code
- Commit anything
- Run any commands that modify files
- Use the Bash tool for git or shell operations (use PowerShell)
- Skip the pre-read โ without it, Lens 2 + Lens 3 produce noise instead of signal
Git Status:
$(git status --short)
In-scope code:
DIRTY mode (default) โ the diff hunks:
$(git diff --unified=3 -- $(git diff --name-only | head -10))
FULL / MODULE mode โ replace the diff above with the WHOLE in-scope files
(Get-Content each named file); committed-but-unchanged lines MUST be reviewed.
Review focus from user:
$ARGUMENTS
IMPORTANT: Return feedback in structured format:
{
\"issues_found\": true/false,
\"issues\": [
{
\"file\": \"path/to/file.py\",
\"line\": 42,
\"lens\": 1,
\"issue\": \"Brief description\",
\"severity\": \"architectural-critical\",
\"rule_citation\": \"<doc section> or null\",
\"suggestion\": \"Specific fix suggestion\"
}
],
\"summary\": \"Overall assessment, grouped by lens\"
}
```"
})
- Wait for the agent to complete and collect its feedback
- Present the structured feedback to the user
Important Constraints:
- Shell: PowerShell only (bash is broken on this Windows machine โ see note above)
- Reviewer agent uses
model: "opus" โ project favors deeper architectural reasoning over cost; required for the three-lens review structure (call-graph tracing, multi-file rule application, distinguishing dormant scaffolding from real dead code)
- Timeout: 10 minutes minimum for Agent tool
- Reviewer only reads code, never modifies it
- Feedback must be structured for the fixer agent to act upon