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.
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).
| 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) |
# 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| 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 |
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 PRGate 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.
[[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| 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) |
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
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.
| 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 onapprove_with_notesverdicts. Defaulttrue.graceful_noop_on_approve_with_notes— when the fix pipeline produces no diff, report success (no red check) instead of failure. Defaulttrue.fix_polish_loop_enabled— master switch for the hopper-style per-finding polish loop. Set tofalseto fall back to the monolithicfix-seniorcall. Defaulttrue.polish_loop_total_budget_s/polish_per_finding_timeout_seconds— wall-clock caps for the polish loop.
*/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.
# 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# SSH + tmux
ssh your-gate-host
tmux attach -t gate
# Status check (no tmux needed)
ssh your-gate-host gate status| 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 |
- health-and-recovery.md — Health checks, failure scenarios, recovery
- metrics.md — Review metrics, log schema, TUI metrics
- notifications.md — ntfy + Discord setup
- remote-access.md — SSH, tmux, status commands