Claude Code plugin for automatic review after Claude edits files
Project description
Claude Auto Review
Claude Code plugin for automatic review after Claude edits files.
After each file edit (Write/Edit/MultiEdit/Delete), the plugin tracks the file hash. When Claude tries to stop, the plugin blocks until the changes have been reviewed — either manually in-session or automatically via a reviewer CLI backend.
Features
- Tracks file edits through Claude Code hooks and blocks stop until changes are reviewed.
- Supports reviewer CLI backends via
reviewerBackend(claude,codex, oropencode). - Uses a last-message classifier to skip review generation when Claude should keep working.
- Enforces a stop circuit breaker with
maxStopPasses. - Live-reloads
.claude/settings.jsonwithout a restart. - Dependency-free Python (standard library only).
- Works inside git worktrees — resolves to the main repo's
.claude/claude-auto-review/state viagit rev-parse --show-toplevel.
Installation
pip install claude-auto-review # Install from PyPI
claude-auto-review install # One-time init in project root
# or: car install
Creates .claude/claude-auto-review/, copies rules, and updates .claude/settings.json.
Then configure:
claude-auto-review config # Interactive setup wizard
# or: car config
Prompts for the key settings — after that, Claude Code sessions use the plugin automatically.
See INSTALL.md for full details.
Architecture
The implementation is split into small modules instead of one monolith. Below are focused diagrams covering each subsystem.
1. Hook Wiring
Claude Code calls three lifecycle hooks, each mapped to a plugin hook handler via hooks.json:
flowchart LR
subgraph "Hooks.json Registration"
direction TB
PTU["PostToolUse"]
STP["Stop ★"]
SEND["SessionEnd"]
end
subgraph "Plugin Hook Handlers"
direction TB
PTU_H["post_tool_use.py<br/>Tracks file hashes<br/>for review workflow"]
STP_H["stop_hook.py<br/>🚦 Decision engine → review<br/>generation → block / allow"]
SEND_H["session_end.py<br/>Cleans up stale state"]
end
PTU -.-> PTU_H
STP == "★ Reviews happen here ★" ===> STP_H
SEND -.-> SEND_H
style PTU fill:#e3f2fd,stroke:#1565c0,stroke-dasharray: 3 3
style PTU_H fill:#e3f2fd,stroke:#1565c0,stroke-dasharray: 3 3
style STP fill:#fff3e0,stroke:#e65100,stroke-width:4px
style STP_H fill:#fff3e0,stroke:#e65100,stroke-width:4px
style SEND fill:#f3e5f5,stroke:#7b1fa2,stroke-dasharray: 3 3
style SEND_H fill:#f3e5f5,stroke:#7b1fa2,stroke-dasharray: 3 3
2. File Edit Tracking (PostToolUse)
Every time Claude edits a file, the PostToolUse hook captures the file hash and stores an event for later review:
flowchart TD
EDIT["Claude edits file<br/>(Write / Edit / MultiEdit / Delete)"] --> EXTRACT["Extract file paths from hook input"]
EXTRACT --> FILTER{"Should skip?"}
FILTER -- "Runtime path or excluded pattern" --> SKIP["Log skipped file, continue"]
FILTER -- "Tracked path" --> HASH["Get file hash from disk"]
HASH -- "File missing (deleted)" --> DEL["Append EditRecord(deleted=True)"]
HASH -- "Hash obtained" --> REVIEWED{"Already reviewed?"}
REVIEWED -- "Yes" --> APPEND_R["Append EditRecord(reviewed=True)"]
REVIEWED -- "No" --> APPEND_U["Append EditRecord(reviewed=False)"]
APPEND_R --> DONE["Continue Claude session"]
APPEND_U --> DONE
DEL --> DONE
SKIP --> DONE
style EDIT fill:#e3f2fd,stroke:#1565c0
style HASH fill:#e8f5e9,stroke:#2e7d32
style APPEND_U fill:#ffebee,stroke:#c62828
style APPEND_R fill:#e8f5e9,stroke:#2e7d32
style DONE fill:#f5f5f5,stroke:#9e9e9e
3. Stop Flow — Decision Engine
When Claude attempts to stop, the Stop hook runs the stop-flow service through staged checks. Each stage decides whether to allow the stop, continue without review, or block for review:
flowchart TD
STOP["Claude attempts stop"] --> CTX["Build RuntimeContext<br/>(project, client, settings)"]
CTX --> ENABLED{"Plugin enabled?"}
ENABLED -- "No" --> ALLOW_DISABLED["Allow stop (disabled)"]
ENABLED -- "Yes" --> STATE["Load state snapshot"]
STATE --> UNREVIEWED{"Unreviewed files?"}
UNREVIEWED -- "No" --> ALLOW_CLEAN["Allow stop (clean)"]
UNREVIEWED -- "Yes" --> BREAKER{"Circuit breaker hit?"}
BREAKER -- "Yes (≥ maxStopPasses)" --> ALLOW_BREAKER["Allow stop (circuit breaker)"]
BREAKER -- "No" --> CLASSIFIER{"Classifier status?"}
CLASSIFIER -- "incomplete" --> ALLOW_INCOMPLETE["Allow stop —<br/>Claude still working"]
CLASSIFIER -- "complete / unknown / error / skipped" --> PENDING{"Pending review reuse?"}
PENDING -- "Yes (unexpired)" --> FINALIZE_OLD["Finalize with cached review"]
PENDING -- "No" --> PROMPT["Generate review prompt"]
PROMPT --> SUCCESS{"Review generated?"}
SUCCESS -- "No" --> BLOCK["Block stop"]
SUCCESS -- "Yes" --> BLOCK2{"Would stop be blocked?"}
FINALIZE_OLD --> BLOCK2
BLOCK2 -- "No" --> ALLOW_REVIEWED["Allow stop (reviewed)"]
BLOCK2 -- "Yes" --> BLOCK
BLOCK --> RETURN_BLOCKED["Return blocked stop response"]
style STOP fill:#fff3e0,stroke:#e65100
style ALLOW_DISABLED fill:#e8f5e9,stroke:#2e7d32
style ALLOW_CLEAN fill:#e8f5e9,stroke:#2e7d32
style ALLOW_BREAKER fill:#e8f5e9,stroke:#2e7d32
style ALLOW_INCOMPLETE fill:#e8f5e9,stroke:#2e7d32
style ALLOW_REVIEWED fill:#e8f5e9,stroke:#2e7d32
style BLOCK fill:#ffebee,stroke:#c62828
style RETURN_BLOCKED fill:#ffebee,stroke:#c62828
4. Review Prompt Generation
When a new review is needed, the plugin assembles context from rules and session-scoped diffs into a prompt for the reviewer backend:
flowchart LR
subgraph inputs["① Review Inputs"]
direction TB
RULES["Review rules"]
SNAPSHOTS["Session-scoped diff<br/>(captured before first edit)"]
FILES["Unreviewed files"]
end
subgraph assembly["② Prompt Assembly"]
direction TB
TIMESTAMP("Gen ID + timestamp")
BUILD["Build prompt"]
WRITE_PROMPT["Write prompt file"]
WRITE_REVIEW["Write review stub"]
end
subgraph backend["③ Reviewer Backend"]
direction TB
CLAUDE["Claude Code"]
CODEX["Codex CLI"]
end
FILES --> TIMESTAMP
RULES --> BUILD
SNAPSHOTS --> BUILD
TIMESTAMP --> BUILD
BUILD --> WRITE_PROMPT
BUILD --> WRITE_REVIEW
WRITE_PROMPT --> CLAUDE
WRITE_PROMPT --> CODEX
style TIMESTAMP fill:#f3e5f5,stroke:#7b1fa2
style inputs fill:#e3f2fd,stroke:#1565c0
style assembly fill:#f3e5f5,stroke:#7b1fa2
style backend fill:#e8f5e9,stroke:#2e7d32
5. State Management
All session events are recorded as JSONL entries. A snapshot is computed on each stop attempt for consistent queries:
flowchart LR
subgraph writers["① Event Writers"]
direction TB
PTU_W["PostToolUse writes<br/>EditRecord"]
STOP_W["Stop hook writes<br/>ReviewMetadata / StopBlocked"]
SEND_W["SessionEnd writes<br/>cleanup events"]
end
subgraph storage["② State Storage"]
direction TB
CLI_STATE["Per-client state.jsonl"]
GLOBAL_LOG["Project lifecycle log"]
end
subgraph reader["③ State Reader"]
direction TB
SNAPSHOT["StateSnapshot<br/>from events"]
UNREVIEWED["Unreviewed files"]
BLOCKS["Stop blocks count"]
REVIEW_MATCH["Pending review match"]
end
PTU_W --> CLI_STATE
STOP_W --> CLI_STATE
SEND_W --> CLI_STATE
PTU_W -.-> GLOBAL_LOG
STOP_W -.-> GLOBAL_LOG
SEND_W -.-> GLOBAL_LOG
CLI_STATE --> SNAPSHOT
SNAPSHOT --> UNREVIEWED
SNAPSHOT --> BLOCKS
SNAPSHOT --> REVIEW_MATCH
style writers fill:#e3f2fd,stroke:#1565c0
style storage fill:#fff3e0,stroke:#e65100
style reader fill:#e8f5e9,stroke:#2e7d32
The classifier runs before pending-review resolution on unreviewed stop paths: incomplete lets Claude continue working without invoking review generation, while complete, unknown, error, and skipped continue into the normal review/block flow.
The stop flow reads the current client state into a snapshot once per stop attempt so lifecycle queries share one view of the session.
State events are written through a single semantic append path so the per-client state.jsonl log and the project-level lifecycle log stay aligned.
Related Projects
This plugin was inspired by:
- hamelsmu/claude-review-loop — a stop-hook-driven automated review loop that uses Claude Code lifecycle hooks to block stops until diffs are reviewed.
- NTCoding/claude-skillz/automatic-code-review — an automatic code review workflow built around session hooks, review rules, and tracked file changes.
Thanks to both projects for the ideas and patterns that influenced this plugin.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file claude_auto_review-1.15.4.tar.gz.
File metadata
- Download URL: claude_auto_review-1.15.4.tar.gz
- Upload date:
- Size: 95.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
035682463adcec634f926026d46ef2b1c467ccbac1beccf204f8b6b647ac3588
|
|
| MD5 |
0957f91897a46174e5d8ba797b2dbd15
|
|
| BLAKE2b-256 |
6fbbc4d760f8fa455301e04781772c51a842fa0384296ee321ef531f19ac85df
|
File details
Details for the file claude_auto_review-1.15.4-py3-none-any.whl.
File metadata
- Download URL: claude_auto_review-1.15.4-py3-none-any.whl
- Upload date:
- Size: 146.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b669d8cc125327a84f5bd298615602c63fd8df6c389960400daa3257a8330aa1
|
|
| MD5 |
10f2df28eadd8caff894f96c7eb38b4c
|
|
| BLAKE2b-256 |
3ce5215bb07c5ab3c6781fed02f5279f7bb05629bdde8d90dfd2c609024ff7fb
|