Skip to main content

Claude Code plugin for automatic review after Claude edits files

Project description

coverage PyPI version

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, or opencode).
  • 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.json without a restart.
  • Dependency-free Python (standard library only).
  • Works inside git worktrees — resolves to the main repo's .claude/claude-auto-review/ state via git 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 TB
    subgraph s1["① Start"]
        STOP["Stop attempt"] --> CTX["Build context"]
    end

    subgraph s2["② Pre-checks"]
        ENABLED{"Enabled?"}
        STATE["Load state"]
        UNREVIEWED{"Unreviewed?"}
        ALLOW_DISABLED["Allow (disabled)"]
        ALLOW_CLEAN["Allow (clean)"]
    end

    subgraph s3["③ Guards"]
        BREAKER{"Breaker?"}
        CLASSIFIER{"Classifier?"}
        ALLOW_BREAKER["Allow (breaker)"]
        ALLOW_INCOMPLETE["Allow (working)"]
    end

    subgraph s4["④ Review"]
        PENDING{"Pending?"}
        PROMPT["Generate prompt"]
        SUCCESS{"Generated?"}
        FINALIZE_OLD["Use cached"]
    end

    subgraph s5["⑤ Verdict"]
        BLOCK2{"Block?"}
        BLOCK["Block stop"]
        ALLOW_REVIEWED["Allow (reviewed)"]
    end

    CTX --> ENABLED
    ENABLED -- "Yes" --> STATE --> UNREVIEWED
    ENABLED -- "No" --> ALLOW_DISABLED
    UNREVIEWED -- "Yes" --> BREAKER
    UNREVIEWED -- "No" --> ALLOW_CLEAN
    BREAKER -- "Yes" --> ALLOW_BREAKER
    BREAKER -- "No" --> CLASSIFIER
    CLASSIFIER -- "incomplete" --> ALLOW_INCOMPLETE
    CLASSIFIER -- "complete / unknown / error / skipped" --> PENDING
    PENDING -- "Yes" --> FINALIZE_OLD --> BLOCK2
    PENDING -- "No" --> PROMPT --> SUCCESS
    SUCCESS -- "Yes" --> BLOCK2
    SUCCESS -- "No" --> BLOCK
    BLOCK2 -- "No" --> ALLOW_REVIEWED
    BLOCK2 -- "Yes" --> BLOCK

    style s1 fill:#fff3e0,stroke:#e65100
    style s2 fill:#e3f2fd,stroke:#1565c0
    style s3 fill:#f3e5f5,stroke:#7b1fa2
    style s4 fill:#e8f5e9,stroke:#2e7d32
    style s5 fill:#ffebee,stroke:#c62828
    style BLOCK fill:#ffebee,stroke:#c62828
    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

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 TB
    subgraph inputs["① Review Inputs"]
        RULES["Review rules"]
        SNAPSHOTS["Session-scoped diff<br/>(captured before first edit)"]
        FILES["Unreviewed files"]
    end

    subgraph assembly["② Prompt Assembly"]
        TIMESTAMP("Gen ID + timestamp")
        BUILD["Build prompt"]
        WRITE_PROMPT["Write prompt file"]
        WRITE_REVIEW["Write review stub"]
    end

    subgraph backend["③ Reviewer Backend"]
        CLAUDE["Claude Code"]
        CODEX["Codex CLI"]
    end

    RULES --> BUILD
    SNAPSHOTS --> BUILD
    FILES --> TIMESTAMP
    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 TB
    subgraph writers["① Event Writers"]
        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"]
        CLI_STATE["Per-client state.jsonl"]
        GLOBAL_LOG["Project lifecycle log"]
    end

    subgraph reader["③ State Reader"]
        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:

Thanks to both projects for the ideas and patterns that influenced this plugin.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

claude_auto_review-1.15.5.tar.gz (95.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

claude_auto_review-1.15.5-py3-none-any.whl (146.8 kB view details)

Uploaded Python 3

File details

Details for the file claude_auto_review-1.15.5.tar.gz.

File metadata

  • Download URL: claude_auto_review-1.15.5.tar.gz
  • Upload date:
  • Size: 95.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for claude_auto_review-1.15.5.tar.gz
Algorithm Hash digest
SHA256 ed2157ea00092ec6b94543d5770a2080e85855f7c6d7444d2586b6c345824bb0
MD5 5de9c50fcdddbf0c056799209f848dac
BLAKE2b-256 5805f25497721f6b5bf89dad8b03e5b55215a5a75cbe7e6e49b316e709be8616

See more details on using hashes here.

File details

Details for the file claude_auto_review-1.15.5-py3-none-any.whl.

File metadata

File hashes

Hashes for claude_auto_review-1.15.5-py3-none-any.whl
Algorithm Hash digest
SHA256 326c12164ac1a2a8d74f25050fb19920172029b499fb48fbd4a98b2cf9e68324
MD5 243a20224c98ecbbf938715003958890
BLAKE2b-256 5f55b414394ee73f244ffe8f313d517c3741a7651e3854d386b07605d7cd48ab

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page