Skip to content

openlawteam/gate

Repository files navigation

Gate — Autonomous PR Review System

Gate is a Python/tmux AI-powered code review system that autonomously reviews every PR on your repository. It runs on a self-hosted machine as a persistent server, orchestrating Claude and Codex agents to perform multi-stage code reviews and auto-fixes.

Architecture

GitHub PR push
  └─▶ GHA thin trigger (gate-review.yml)
       └─▶ gate review --pr N --repo ... --head-sha ...
            └─▶ ReviewQueue (concurrent, up to 3 PRs)
                 └─▶ ReviewOrchestrator per PR
                      ├─▶ GitHub commit status created ("gate-review")
                      ├─▶ Gate 1–5 (labels, circuit breaker, fix-rerun, quota, cycles)
                      ├─▶ Stage 1: Triage (structured, Sonnet)
                      ├─▶ Stage 2: Build verification
                      ├─▶ Stage 2.5: Postconditions (structured, Sonnet, high/critical risk only)
                      ├─▶ Stage 3: Architecture review (agent, tmux)
                      ├─▶ Stage 4: Security review (agent, tmux)
                      ├─▶ Stage 5: Logic review (agent, tmux)
                      ├─▶ Stage 6: Verdict (structured, Sonnet)
                      ├─▶ Post review (GitHub review)
                      └─▶ Fix pipeline (if blocked — Claude senior + Codex junior)

Agent stages run interactively in tmux windows via gate process. Structured stages run inline via subprocess.run. All communication between the server, orchestrator, and runners uses Unix socket IPC (JSONL protocol).

Requirements

Requirement Details
Python 3.11+
OS macOS or Linux
tmux 3.3+
GitHub CLI gh authenticated
Claude CLI claude authenticated
Codex CLI codex (optional, for fix pipeline)

Quick Start

# 1. Clone and install
git clone <gate-repo-url>
cd gate
pip install -e ".[dev]"

# 2. Run interactive setup
gate init

# 3. Start Gate (inside tmux)
tmux new 'gate up'

To add additional repositories to an existing setup:

gate add-repo

CLI Commands

Command Description
gate init Interactive first-time setup
gate add-repo Add a repository to an existing config
gate up Start server and TUI dashboard
gate up --headless Start server without TUI
gate status Print current state (reviews, queue, health)
gate review --pr N ... Enqueue a PR review (called by GHA)
gate cancel --pr N Cancel an in-progress review
gate health Run all health checks
gate doctor Verify all prerequisites
gate cleanup Run log rotation and worktree pruning
gate digest Send daily metrics digest
gate update Pull latest code and reinstall
gate cleanup-pr --pr N Clean up state for a closed PR
gate process <id> <stage> Run a review stage in tmux (internal)
gate inspect-pr N [--repo ...] Pretty-print persisted review state for a PR

Development

Gate's test suite needs the dev extras — most importantly pytest-asyncio for the async TUI tests. Install with:

pip install -e '.[dev]'

A bare pip install -e . is not enough: it installs the runtime deps only, and pytest -q will fail at collection time via the guard in tests/conftest.py asking you to re-install with the extra. Use the one-line command above and you're good.

Common developer workflows:

pytest -q                 # full test suite (~110s on my box)
ruff check .              # lint
mypy gate                 # type-check (baseline; see pyproject for overrides)
gate inspect-pr 123       # inspect persisted findings for a PR

Supported Languages

Gate supports any project type through built-in profiles and custom build commands:

Language Profile Typecheck Lint Tests
TypeScript/JS node npx tsc --noEmit npm run lint:check npm run test:run
Python python ruff check . python -m pytest
Go go go vet ./... golangci-lint run go test ./...
Rust rust cargo check cargo clippy cargo test

gate init auto-detects the project type. You can override any command per-repo via build.* keys in gate.toml.

Configuration

config/gate.toml

[[repos]]
name = "your-org/your-repo"
clone_path = "~/your-repo"
project_type = "node"    # auto-detected: node, python, go, rust, none
worktree_base = "/tmp/gate-worktrees"

# Override default build commands per-repo:
# build.typecheck_cmd = "npx tsc --noEmit"
# build.lint_cmd = "npm run lint:check"
# build.test_cmd = "npm run test:run"

# Per-repo limit overrides:
# limits.max_fix_attempts_total = 0
# timeouts.agent_stage_s = 600

[models]
triage = "sonnet"
architecture = "sonnet"
security = "opus"
logic = "opus"
verdict = "sonnet"
fix_senior = "opus"
fix_rereview = "sonnet"

[timeouts]
agent_stage_s = 900
structured_stage_s = 120
hard_timeout_s = 1200

[limits]
max_diff_bytes = 500000
max_pr_body_bytes = 50000
max_review_cycles = 5

Environment Variables

Variable Purpose
GATE_PAT GitHub Personal Access Token (push, checks, reviews)
CLAUDE_CODE_OAUTH_TOKEN Claude CLI authentication
Codex auth codex login (ChatGPT account) or OPENAI_API_KEY env var
GATE_NTFY_TOPIC ntfy.sh topic for push notifications
GATE_DISCORD_WEBHOOK Discord webhook URL (optional)

Directory Layout

gate/
├── gate/                      # Python package
│   ├── __init__.py
│   ├── cli.py                 # CLI entry point
│   ├── server.py              # Unix socket JSONL server
│   ├── client.py              # Server client + GateConnection
│   ├── orchestrator.py        # Review pipeline state machine
│   ├── queue.py               # Concurrent review queue (ThreadPoolExecutor)
│   ├── runner.py              # ReviewRunner (agent tmux) + StructuredRunner (inline)
│   ├── claude.py              # tmux window spawner
│   ├── tmux.py                # tmux low-level operations
│   ├── fixer.py               # Fix pipeline (Claude senior + Codex junior)
│   ├── github.py              # GitHub API (checks, reviews, comments, labels)
│   ├── prompt.py              # Prompt loading and variable substitution
│   ├── schemas.py             # StageResult, FixResult, fallback builders
│   ├── config.py              # TOML config loader
│   ├── state.py               # Per-PR state persistence
│   ├── notify.py              # ntfy + Discord notifications
│   ├── health.py              # Infrastructure health monitoring
│   ├── cleanup.py             # Log rotation, worktree pruning, digest
│   ├── logger.py              # reviews.jsonl, live logs
│   ├── builder.py             # Build verification (per-project: typecheck, lint, tests)
│   ├── profiles.py            # Project type profiles (node, python, go, rust)
│   ├── quota.py               # Anthropic API quota checking
│   ├── workspace.py           # Git worktree management
│   ├── tui.py                 # Textual TUI dashboard
│   └── code.py                # gate-code Codex wrapper
├── config/
│   ├── gate.toml              # Main configuration
│   ├── cursor-rules.md        # Coding standards for review (customize for your project)
│   ├── fix-blocklist.txt      # Files excluded from auto-fix
│   └── com.gate.server.plist.example  # LaunchAgent config template
├── prompts/                   # 18 prompt templates (.md)
├── workflows/
│   └── gate-review.yml        # Thin GHA trigger workflow
├── docs/
│   ├── health-and-recovery.md
│   ├── metrics.md
│   ├── notifications.md
│   └── remote-access.md
├── tests/                     # pytest test suite
├── pyproject.toml
├── Makefile
└── README.md

Runtime data lives in the OS-native data directory (via platformdirs), not in the repo tree:

~/Library/Application Support/gate/       # macOS
~/.local/share/gate/                      # Linux
├── server.sock                           # Unix socket (IPC)
├── npm-cache/                            # npm cache for dependency installs
├── logs/
│   ├── reviews.jsonl                     # Structured review log (append-only)
│   ├── activity.log                      # Server activity log
│   ├── .health-alert-state               # Per-check alert cooldown state
│   └── live/                             # Per-PR live logs
└── state/
    ├── quota-cache.json                  # Anthropic quota cache
    └── {repo-slug}/prN/                  # Per-PR state
        ├── verdict.json
        ├── triage.json
        ├── architecture.json
        ├── security.json
        ├── logic.json
        ├── build.json
        ├── last_sha.txt
        ├── review_count.txt
        └── fix_attempts.txt

TUI Dashboard

The TUI runs inside tmux via gate up. Tokyo Night color scheme.

Key Action
q Quit
r Refresh all panels
c Cancel selected review
d Show tmux pane capture for selected review
l Toggle log tail panel

Panels: Active reviews (with status icons), queue, recent reviews (last 8), health checks, live log tail, 24h metrics bar.

GitHub Labels

Label Effect
gate-skip Skip review, auto-approve
gate-emergency-bypass Emergency bypass, auto-approve
gate-rerun Re-trigger a review (label is removed automatically after the review starts)
gate-no-fix Block the auto-fix pipeline for this PR — Gate still reviews but will not attempt any commits

Per-repo fix-pipeline knobs live in gate.toml (see config/gate.toml.example):

  • fix_on_approve_with_notes — run the polish loop on approve_with_notes verdicts. Default true.
  • graceful_noop_on_approve_with_notes — when the fix pipeline produces no diff, report success (no red check) instead of failure. Default true.
  • fix_polish_loop_enabled — master switch for the hopper-style per-finding polish loop. Set to false to fall back to the monolithic fix-senior call. Default true.
  • polish_loop_total_budget_s / polish_per_finding_timeout_seconds — wall-clock caps for the polish loop.

Operations

Cron Jobs

*/5 * * * *  gate health        → health monitoring + alerts
0 9 * * *    gate digest        → daily metrics summary
0 3 * * *    gate cleanup       → log rotation + worktree pruning

Ad-hoc:

  • gate prune — worktree-only pruning (safe to run any time; does not touch logs or review state).
  • gate prune --aggressive — also removes worktrees that have no active review marker regardless of age.

LaunchAgent

# Install (auto-start on login)
cp config/com.gate.server.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.gate.server.plist

# Control
launchctl unload ~/Library/LaunchAgents/com.gate.server.plist  # stop
launchctl list | grep gate                                      # check

Remote Access

# SSH + tmux
ssh your-gate-host
tmux attach -t gate

# Status check (no tmux needed)
ssh your-gate-host gate status

Troubleshooting

Problem Fix
Server not running tmux new 'gate up'
Runner offline cd <runner-dir> && ./svc.sh start
Claude auth expired claude auth login --method browser
Circuit breaker tripped Last 3 reviews were errors. Fix root cause; next success resets.
Check stuck in_progress gate health auto-cleans orphaned checks (fail-open)
No notifications Check echo $GATE_NTFY_TOPIC
Disk filling up gate cleanup
Machine sleeping sudo pmset -a disablesleep 1
Prerequisites broken gate doctor to diagnose

Documentation

About

Autonomous AI-powered PR review system — multi-stage code review with Claude/Codex agents, auto-fix pipeline, and Textual TUI dashboard

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages