Deployment Guide
Run Reviewflow in production on a Linux VPS.
Overview
This guide covers:
- Running the server as a systemd service (auto-start on boot)
- Exposing it to the internet via Cloudflare Tunnel
Prerequisites
- Linux server with systemd (Ubuntu, Debian, etc.)
- Node.js 20+ installed
claudeCLI ≥ v2.1.139 (the--bgbackground dispatch mode is required)claude auth statusreturns OAuth — never setANTHROPIC_API_KEYin the systemd environment, Reviewflow auto-pauses dispatch if it detects the API pool is in usecloudflaredinstalled (download)- A domain on Cloudflare (for permanent URL)
- Disk headroom on
$HOMEfor~/.reviewflow/worktrees/— one full project checkout per active MR (typical: a few hundred MB per worktree, reclaimed automatically by the daily sweep)
Quick Test (Temporary Tunnel)
For testing without permanent setup. The URL changes on each restart.
# Terminal 1: Server
cd ~/reviewflow
yarn install && yarn build
yarn start
# Terminal 2: Tunnel (3847 is the default config port)
cloudflared tunnel --url http://localhost:3847Copy the generated URL and use it for your webhook configuration.
Production Setup
1. Build the project
cd ~/reviewflow
yarn install
yarn build2. Configure
# Environment
cp .env.example .env
nano .env # Add your webhook tokens
# Application
cp config.example.json config.json
nano config.json # Add your repos3. Install systemd service
# Copy template
sudo cp docs/deployment/templates/review-flow.service /etc/systemd/system/
# Edit with your values
sudo nano /etc/systemd/system/review-flow.service
# Replace YOUR_USER and paths
# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable --now review-flow
# Check status
sudo systemctl status review-flow4. Set up Cloudflare Tunnel
# Login to Cloudflare
cloudflared tunnel login
# Create tunnel
cloudflared tunnel create review-flow
# Note the tunnel ID
# Configure DNS
cloudflared tunnel route dns review-flow review.your-domain.com
# Create config
mkdir -p ~/.cloudflared
cp docs/deployment/templates/cloudflared-config.yml ~/.cloudflared/config.yml
nano ~/.cloudflared/config.yml
# Replace YOUR_TUNNEL_ID, YOUR_USER, and domain
# Install tunnel service
sudo cp docs/deployment/templates/cloudflared.service /etc/systemd/system/cloudflared-review-flow.service
sudo nano /etc/systemd/system/cloudflared-review-flow.service
# Replace YOUR_USER
# Enable and start
sudo systemctl daemon-reload
sudo systemctl enable --now cloudflared-review-flow5. Verify
# Check services
sudo systemctl status review-flow
sudo systemctl status cloudflared-review-flow
# Test endpoint — expect status: "ok" and supervisor.state: "up"
curl https://review.your-domain.com/health | jq .
# If supervisor.state is "down", the 60s scheduler will respawn it on
# the next tick. Persistent "down" usually means `claude` is not in
# PATH or OAuth is not configured for the systemd user.
# View logs
journalctl -u review-flow -fThe /health payload includes a supervisor block reporting the live state of the Claude agents daemon:
{
"status": "ok",
"supervisor": {
"state": "up",
"reason": null,
"lastCheckedAt": "2026-05-26T10:42:00.000Z"
}
}When supervisor.state === "down", overall status becomes "degraded" — Reviewflow still accepts webhooks but reviews will fail dispatch until the supervisor is back up. See the Supervisor troubleshooting section.
Templates
See the templates/ directory for:
review-flow.service- systemd unit for the servercloudflared.service- systemd unit for the tunnelcloudflared-config.yml- Cloudflare tunnel configuration
Updating
# Stop service
sudo systemctl stop review-flow
# Update code
cd ~/reviewflow
git pull
yarn install
yarn build
# Restart
sudo systemctl start review-flowWorktrees survive restarts
The worktree state lives at ~/.reviewflow/worktrees/ (independent of the source checkout). A restart does not invalidate active worktrees; in-flight reviews resume on the next webhook with ensureWorktree fast-forwarding the existing worktree.
Operating worktrees
Each active MR has a dedicated worktree at ~/.reviewflow/worktrees/<platform>-<slug>-<mrNumber>. They are created on first review, fast-forwarded on followup, removed on merge/close, and a sweep every 24h (anchored to server startup, also fires immediately on boot) reclaims anything stale.
# Disk usage overview
du -sh ~/.reviewflow/worktrees/*
# Manual cleanup (rare — sweep handles this)
rm -rf ~/.reviewflow/worktrees/<platform>-<slug>-<mrNumber>
cd /path/to/source/checkout && git worktree pruneFull state machine: Worktree Lifecycle.
Troubleshooting
See Troubleshooting for common issues (services, tunnels, webhooks).