跳到正文
GitHub·· 6 天前AI 评分38

Inkvi/code-reviewer:基于 Claude、Codex 等模型的 AI 代码审查工具

Inkvi/code-reviewer

AI 导读

Inkvi/code-reviewer 是一款由 Claude、Codex、Antigravity、OpenCode 和 pi 驱动的 AI 代码审查工具,可作为 GitHub PR 守护进程或本地 git 仓库审查工具运行。它支持多审查器并行、PR 评论 /review 触发、按风险分级自动批准,并可通过 TOML 配置模型与推理强度。

正文

AI code review tool powered by Claude, Codex, Antigravity, OpenCode, and pi. Works as a GitHub PR daemon or as a local review tool for git repositories.

Requirements

  • Python 3.12+
  • uv
  • gh authenticated (gh auth login)
  • codex authenticated
  • claude authenticated (Agent SDK depends on Claude Code runtime)
  • if using antigravity reviewer: agy (Antigravity CLI) installed and authenticated
  • if using opencode reviewer: opencode installed and configured with a provider
  • if using pi reviewer: pi (@mariozechner/pi-coding-agent) installed, with a provider API key in the environment (e.g. OPENROUTER_API_KEY)
  • for codex_backend = "agents_sdk": OpenAI Agents SDK package + OPENAI_API_KEY

Setup

uv sync --extra dev
cp config.example.toml config.toml   # optional for run-once/review; required for check/start

Commands

uv run code-reviewer check                  # preflight checks + runtime summary (requires config)
uv run code-reviewer run-once               # one polling cycle (requires config with github_orgs)
uv run code-reviewer start                  # daemon mode (requires config with github_orgs)
uv run code-reviewer review --uncommitted   # review local uncommitted changes (config optional)
uv run code-reviewer webhook                # GitHub App webhook server (env: WEBHOOK_SECRET)

Note: run-once --pr-url and review work without a config file — sensible defaults are used. If ./config.toml exists it is loaded automatically; pass --config path.toml to use a different file.

Local Review

Review changes in any local git repository without GitHub:

# Review uncommitted changes (staged + unstaged) against HEAD
uv run code-reviewer review --uncommitted

# Compare branches
uv run code-reviewer review --base main
uv run code-reviewer review --base main --branch feature-x

# Review a specific commit
uv run code-reviewer review --commit abc1234

# Review a different repo
uv run code-reviewer review --repo /path/to/repo --uncommitted

# JSON output
uv run code-reviewer review --uncommitted --output-format json

All reviewer/model override flags work with review too:

uv run code-reviewer review --uncommitted --enabled-reviewer codex
uv run code-reviewer review --base main --reconciler-backend antigravity

PR Daemon

Target specific PRs

uv run code-reviewer run-once --pr-url https://github.com/<org>/<repo>/pull/<number>
uv run code-reviewer run-once --pr-url https://github.com/<org>/<repo>/pull/<number> --auto-post-review
uv run code-reviewer run-once --pr-url https://github.com/<org>/<repo>/pull/<number> --use-saved-review --auto-post-review
uv run code-reviewer run-once --no-auto-post-review

JSON output (requires --pr-url)

uv run code-reviewer run-once --pr-url https://github.com/<org>/<repo>/pull/<number> --output-format json

Slash command trigger

The daemon monitors PR comments for /review commands:

  • /review — request a review on the current PR
  • /review force — force a re-review even if the current HEAD was already reviewed

Who can trigger: PR author and org members in monitored orgs.

Behavior:

  • Reacts with 👀 to the triggering comment
  • If already reviewed at the current commit: replies with a skip message (unless force is used)
  • Runs the full review pipeline and posts results

Configuration

GitHub scope

github_orgs = ["Inkvi"]
# github_orgs = ["polymerdao", "another-org", "Inkvi"]
excluded_repos = ["polymerdao/infra", "sandbox-repo"]

Reviewers

# Run both in parallel (default)
enabled_reviewers = ["claude", "codex"]

# Single reviewer
# enabled_reviewers = ["codex"]
# enabled_reviewers = ["claude"]
# enabled_reviewers = ["antigravity"]
# enabled_reviewers = ["opencode"]
# enabled_reviewers = ["pi"]

Codex backend

# Stable default:
codex_backend = "cli"

# Experimental OpenAI Agents SDK backend:
# codex_backend = "agents_sdk"

Both backends use the same configurable full-review prompt.

Model and reasoning tuning

# Claude
# claude_model = "claude-sonnet-4-5"
# claude_reasoning_effort = "low"    # low|medium|high|max

# Codex
codex_model = "gpt-5.3-codex"
codex_reasoning_effort = "low"       # low|medium|high

# Antigravity
# antigravity_model = ""  # leave unset to use agy default

# OpenCode (access models via OpenRouter, OpenAI, Google, etc.)
# opencode_model = "openrouter/zhiyu/glm-5"

# pi (provider/model, optional :<thinking> suffix; key from env, e.g. OPENROUTER_API_KEY)
# pi_model = "openrouter/deepseek/deepseek-v4-flash:high"

# Reconciler (claude|codex|antigravity|opencode|pi)
reconciler_backend = "claude"
# reconciler_model = "claude-opus-4-1"
# reconciler_reasoning_effort = "high"    # claude: low|medium|high|max, codex: low|medium|high

Triage and lightweight review

Every PR goes through triage first. Simple changes (config, version bumps, image tags) get a lightweight single-model checklist review. Complex changes go through the full multi-reviewer pipeline.

Triage also rates how risky the PR would be to merge without a careful human review: low, medium, or high, with a one-sentence reason. By default only low-risk PRs can be auto-approved; auto_approve_max_risk changes that (see Auto submission). A custom triage_prompt_path must ask for "risk" and "risk_reason" in its JSON reply, or PRs will never be auto-approved unless auto_approve_max_risk = "high".

triage_backend = "claude"              # claude|codex|antigravity|opencode|pi
# triage_model = ""                    # leave unset to use backend default
triage_timeout_seconds = 60

lightweight_review_backend = "claude"  # claude|codex|antigravity|opencode|pi
# lightweight_review_model = ""        # leave unset to use backend default
# lightweight_review_reasoning_effort = "low"   # low|medium|high|max
lightweight_review_timeout_seconds = 300

Prompt overrides

Every model-backed step can load an optional TOML prompt spec from config:

triage_prompt_path = "./prompts/triage.toml"
lightweight_review_prompt_path = "./prompts/lightweight_review.toml"
full_review_prompt_path = "./prompts/full_review.toml"
reconcile_prompt_path = "./prompts/reconcile.toml"

Prompt paths are resolved relative to the config.toml file that declares them. Each spec fully replaces that step's built-in instruction package:

prompt = """Review {url}"""
system_prompt = """Optional system prompt"""

Built-in prompt specs now live in src/code_reviewer/prompt_specs/triage.toml, src/code_reviewer/prompt_specs/lightweight_review.toml, src/code_reviewer/prompt_specs/full_review.toml, and src/code_reviewer/prompt_specs/reconcile.toml. Use them as the visible source of truth for the default templates.

Rules:

  • prompt is required
  • system_prompt is optional
  • unknown keys or unknown placeholders fail config load
  • prompt override paths are config-only in this release; there are no CLI flags for them

Supported placeholders:

  • Common: {url_label}, {url}, {title}, {base_ref}, {head_sha}, {changed_files}, {additions}, {deletions}, {workspace}
  • triage: {diff_section}
  • full_review: {diff_command}, {extra_context}
  • reconcile: {pr_comments}, {reviewer_sources}, {max_findings}, {max_test_gaps}

Notes:

  • full_review_prompt_path applies to Claude, Codex CLI, Codex Agents SDK, Antigravity, OpenCode, and pi
  • Antigravity only supports prompt execution and requires full_review_prompt_path to be set
  • for Codex Agents SDK, system_prompt is used as the agent instruction layer
  • code-reviewer check shows whether each step is using the default prompt or an override path

Examples:

# triage.toml
prompt = """Classify this PR using the diff:
{diff_section}
Respond with JSON only."""
system_prompt = "You are a PR triage classifier."
# lightweight_review.toml
prompt = """Review this simple change:
- URL: {url}
- Files: {changed_files}
Return only ### Findings and ### Test Gaps."""
system_prompt = "You are a lightweight config reviewer."
# full_review.toml
prompt = """Review this change set:
- URL: {url}
- Base: {base_ref}
Run `{diff_command}` and inspect the workspace at {workspace}.
Return only ### Findings and ### Test Gaps."""
system_prompt = "You are a code reviewer. Use the diff command and repository context. Do not invent evidence."
# reconcile.toml
prompt = """Reconcile these reviewer outputs:
{reviewer_sources}
PR comments:
{pr_comments}
Keep at most {max_findings} findings and {max_test_gaps} test gaps."""
system_prompt = "You are a review reconciler."

Auto submission

# Post concise review as a normal PR comment
auto_post_review = false

# Submit formal review decision automatically:
# - approve when no P0/P1 findings, triage risk is at or below auto_approve_max_risk,
#   CI checks have all passed, and there are no merge conflicts
# - otherwise, a clean review is posted as a comment explaining why it was not approved
# - request changes when any P0/P1 finding exists
auto_submit_review_decision = false

# Highest triage risk that can be auto-approved: low|medium|high
# "high" turns the risk check off, so PRs triage could not rate are approved too
auto_approve_max_risk = "low"

# Changed files matching these patterns make a PR high risk, whatever triage says.
# fnmatch rules: * also matches across folders, so "*auth*" matches src/auth/login.py.
# Checked against the reviewed commit; a renamed file counts under both names, and if
# the changed files cannot be listed the PR is treated as high risk.
# Has no effect when auto_approve_max_risk = "high". Default: no patterns.
# high_risk_paths = ["*auth*", "*billing*", "migrations/*", ".github/workflows/*"]

# Extra patterns for specific repos. A PR is checked against high_risk_paths plus the
# list for its repo. Keys are "owner/repo" (case-insensitive). Default: none.
# high_risk_paths_by_repo = { "polymerdao/obul" = ["contracts/*", "deploy/*"] }

Trigger mode

trigger_mode = "rerequest_only"  # rerequest_only|rerequest_or_commit

Output limits

max_findings = 10       # 1-20
max_test_gaps = 3       # 1-10

Slash command

slash_command_enabled = true

Other settings

poll_interval_seconds = 60
skip_own_prs = true
include_reviewer_stderr = true
max_parallel_prs = 1
max_mid_review_restarts = 2    # 0-5, restart review when new commits land mid-flight
claude_timeout_seconds = 900
codex_timeout_seconds = 900
antigravity_timeout_seconds = 900
opencode_timeout_seconds = 900
pi_timeout_seconds = 900
output_dir = "./reviews"
state_file = "./.state/pr-reviewer-state.json"
clone_root = "./.tmp/workspaces"

CLI overrides

Most config fields can be overridden from the CLI:

uv run code-reviewer run-once --enabled-reviewer codex
uv run code-reviewer start --enabled-reviewer claude --enabled-reviewer codex
uv run code-reviewer run-once --codex-backend cli
uv run code-reviewer run-once --codex-model gpt-5.3-codex --codex-reasoning-effort high
uv run code-reviewer run-once --claude-model claude-sonnet-4-5 --claude-reasoning-effort medium
uv run code-reviewer run-once --reconciler-backend codex --reconciler-model gpt-5.3-codex
uv run code-reviewer run-once --reconciler-backend antigravity
uv run code-reviewer run-once --enabled-reviewer opencode --opencode-model openrouter/zhipu/glm-5
uv run code-reviewer run-once --enabled-reviewer pi --pi-model openrouter/deepseek/deepseek-v4-flash:high
uv run code-reviewer start --slash-command-enabled
uv run code-reviewer start --no-slash-command-enabled
uv run code-reviewer run-once --triage-backend claude --triage-model claude-sonnet-4-5
uv run code-reviewer run-once --lightweight-review-backend claude

Review Pipeline

flowchart TD
    Start([PR or local changes]) --> Triage

    subgraph Triage
        T[Run triage classifier<br><i>claude / codex / antigravity / opencode / pi</i>]
        T --> Simple{simple?}
    end

    Simple -->|yes| LW[Lightweight review<br><i>single-model checklist</i>]
    LW --> LWValid{success?}
    LWValid -->|yes| Validate1[Validate output format]
    LWValid -->|no| Fallback[Fall back to full review]
    Validate1 --> Output

    Simple -->|no| FullReview
    Fallback --> FullReview

    subgraph FullReview [Full Review]
        direction TB
        Launch[Launch enabled reviewers<br>in parallel]
        Launch --> Claude[Claude<br><i>Agent SDK</i>]
        Launch --> Codex[Codex<br><i>CLI exec or Agents SDK</i>]
        Launch --> Antigravity[Antigravity<br><i>prompt only</i>]
        Launch --> OpenCode[OpenCode<br><i>any model via providers</i>]
        Launch --> Pi[pi<br><i>any model via providers</i>]

        Claude --> Collect[Collect outputs]
        Codex --> Collect
        Antigravity --> Collect
        OpenCode --> Collect
        Pi --> Collect

        Collect --> Multi{multiple<br>reviewers?}
        Multi -->|yes| Reconcile[Reconciler<br><i>claude / codex / antigravity / opencode / pi</i><br>merges + deduplicates findings]
        Multi -->|no| Single[Use single reviewer output]
    end

    Reconcile --> Validate2[Validate output format]
    Single --> Validate2
    Validate2 --> Output

    subgraph Output [Output]
        direction TB
        Write[Write review markdown<br>+ raw sidecar + versioned history]
        Write --> Mode{PR or local?}
        Mode -->|PR| Publish{auto post<br>enabled?}
        Publish -->|yes| Post[Post comment /<br>submit review decision]
        Publish -->|no| Done1([Done — file only])
        Post --> Done2([Done])
        Mode -->|local| Print[Print review to terminal]
        Print --> Done3([Done])
    end

    style Triage fill:#f0f4ff,stroke:#4a6fa5
    style FullReview fill:#fff5f0,stroke:#c56a3a
    style Output fill:#f0fff4,stroke:#3aaa5b

Loading

Webhook Server (GitHub App)

Run as a GitHub App webhook receiver instead of polling. The webhook server listens for PR events and spawns run-once --pr-url for each actionable event.

Setup

  1. Create a GitHub App with permissions: pull_requests: write, issues: read, contents: read
  2. Subscribe to events: pull_request, issue_comment
  3. Set the webhook URL to https://<your-host>/webhook
  4. Note the webhook secret

Run locally

WEBHOOK_SECRET=your-secret code-reviewer webhook
WEBHOOK_SECRET=your-secret code-reviewer webhook --host 127.0.0.1 --port 9090

Environment variables

Variable Description Default
WEBHOOK_SECRET GitHub App webhook secret (recommended) (none, signature validation disabled)
WEBHOOK_HOST Bind address 0.0.0.0
WEBHOOK_PORT Bind port 8000

Endpoints

  • POST /webhook — GitHub App webhook receiver
  • GET /healthz — liveness probe

Handled events

Event Action Behavior
pull_request opened, synchronize, review_requested Spawns review (skips drafts)
issue_comment created with /review or /review force Spawns review
ping — Returns pong

Docker

docker build -t code-reviewer .
docker run -e WEBHOOK_SECRET=your-secret -p 8000:8000 code-reviewer

The default entrypoint runs code-reviewer webhook. Override the command for other modes:

docker run code-reviewer run-once --pr-url https://github.com/org/repo/pull/123
docker run code-reviewer start

Behavior

  • Polls open PRs in all configured owners (github_orgs) where review-requested:@me
  • Excludes repos listed in excluded_repos
  • Runs only reviewers listed in enabled_reviewers
  • Skips draft PRs and (by default) PRs authored by you
  • Triages every PR as "simple" or "full_review" and rates its risk as low, medium, or high
  • Simple PRs get a lightweight single-model checklist review
  • Complex PRs go through the full multi-reviewer + reconciler pipeline
  • If triage or lightweight review fails, falls back to full review
  • Bootstraps all discovered candidate PRs when no prior state exists
  • After bootstrap, processes PRs when a newer direct re-request is observed
  • Runs all enabled reviewers in parallel
  • Injects PR issue-thread comments into reconciliation context
  • Writes reconciled review to reviews/<org>/<repo>/pr-<number>.md
  • Writes versioned history to reviews/<org>/<repo>/pr-<number>/<timestamp>-<shortsha>.md
  • Saves raw reviewer outputs to reviews/<org>/<repo>/pr-<number>.raw.md
  • run-once --pr-url ... --use-saved-review reuses existing review and continues to posting/submission

Lint and test

uv run ruff check .
uv run ruff format .
uv run pytest

来源:GitHub · github.com