https://excalidraw.com/#json=xGk0JJ9K3Fj3w-jrNM1kw,iEepj-mogls0LeSUBi03JA
AI-powered code review that runs in your infrastructure. Three bots, zero bloat.
Bot 1 — Companion: Posts TL;DR comments on PRs with graphify-informed blast radius. Bot 2 — Riptide Review: Deep-think autonomous code review for large, settled PRs. Bot 3 — Proofshotter: Visual verification via Playwright captures on UI changes.
GitHub Webhook
→ FastAPI /webhook/github (verify signature, route event)
→ Companion thread (TL;DR + graphify blast radius)
→ GitHub API (post TL;DR comment)
Cron (every 15 min)
→ riptide/deepthink.py (poll open PRs, filter by LOC + staleness)
→ Hermes cron session (deep-think + graphify analysis)
→ GitHub API (post review comment)
Cron (every 10 min)
→ riptide/proofshotter.py (poll open PRs for UI changes)
→ Playwright captures on dev instance
→ GitHub API (post visual evidence comment)
Every PR triggers a friendly TL;DR comment explaining what changed and why it matters.
Trigger: pull_request (opened, reopened, synchronize)
Output: "## ✨ TL;DR" comment with ELI5 + Blast Radius + ProofShot (if UI)
Model: qwen2.5-coder:7b (via local Ollama)Example output:
## ✨ TL;DR
@alice — Adds atomic per-session draft persistence to reduce large-session
latency. Replaces full-session rewrites with atomic .drafts/ file writes
via DraftOptimization.save_draft().
Also touches: models.py, routes.py.
**📊 Blast Radius**
Analyzed 3 files, 12 related code paths found.
**🧒 ELI5**
This adds a new thing! Like getting a new piece for your LEGO set that
makes it even cooler.

---
<sub>🤖 Generated by Riptide · PR review via local Ollama (qwen2.5-coder:7b) ·
`@riptide-bot companion skip` to opt out</sub>
Reply to any PR comment with @riptide-bot:
| Command | Effect | Bot |
|---|---|---|
@riptide-bot review |
Trigger deep-think review now | Bot 2 |
@riptide-bot full review |
Same (alias) | Bot 2 |
@riptide-bot deepthink |
Same (alias) | Bot 2 |
@riptide-bot companion skip |
Stop companion TLDR on this PR | Bot 1 |
@riptide-bot companion resume |
Re-enable companion TLDR | Bot 1 |
Autonomous deep-think code review for large, settled PRs. Runs every 15 minutes.
Trigger: Cron polling (every 15 min)
Filter: >100 LOC changes + unchanged 30+ min + (our repo OR our PR)
Output: Hermes cron session with deep-think + graphify analysis
Skills: github-pr-lifecycle + deep-think
Model: custom:LongCat (LongCat-2.0) preferredThe deep-think loop:
- SURFACE — Fetch and restate what the PR changes
- EXPLORE — What code paths are affected? Graphify blast radius?
- CHALLENGE — Could the change have side effects? Simpler approach?
- SYNTHESIZE — Advise next steps (approve, request changes, follow-ups)
- VALIDATE — Run tests if claims are testable
Visual verification for UI changes. Runs every 10 minutes.
Trigger: Cron polling (every 10 min)
Filter: UI files changed + not draft + stale 5+ min
Output: PR comment with GIF + screenshots of UI changes
Config: proofshot.config.json (optional — defaults to localhost:8788)Proofshotter captures screenshots of the dev instance (default http://localhost:8788) and posts them as visual evidence on the PR. Requires Playwright installed on the host.
riptide/
├── riptide/
│ ├── github_app.py # JWT auth, GitHub API client
│ ├── companion.py # Bot 1: TL;DR + ELI5 + ProofShot comment generator
│ ├── deepthink.py # Bot 2: Cron polling + Hermes session spawner
│ ├── proofshotter.py # Bot 3: Cron-polled visual verification
│ ├── webhook.py # FastAPI server (companion trigger, installation sync)
│ └── __init__.py
├── server.py # Uvicorn entry point
├── requirements.txt # fastapi, uvicorn, pydantic, cryptography, requests, graphifyy
├── Dockerfile
├── docker-compose.yml
├── SKILL.md # AI agent skill definition
└── start.sh # Dev start script
- Python 3.11+
- Ollama with
qwen2.5-coder:7bandnomic-embed-text - GitHub App registered with webhook permissions
git clone <repo>
cd riptide
# Python deps
pip install -r requirements.txt
# Ollama models
ollama pull qwen2.5-coder:7b
ollama pull nomic-embed-text
# Graphify (for blast radius analysis)
pip install graphifyy# .env
GITHUB_APP_ID=4262983
GITHUB_PRIVATE_KEY_PATH=/home/sc/workspace/riptide/github-private-key.pem
GITHUB_WEBHOOK_SECRET=your_secret
GITHUB_APP_SLUG=riptide-review
RIPTIDE_DATA_DIR=/tmp/riptide-data
# Companion (Bot 1)
RIPTIDE_COMPANION_REPOS=owner/repo1,owner/repo2
RIPTIDE_COMPANION_MODEL=qwen2.5-coder:7b
COMPANION_ENABLE_GRAPHIFY=1
OLLAMA_BASE_URL=http://localhost:43311
# Riptide Review (Bot 2)
RIPTIDE_WATCHED_REPOS=ChonSong/riptide,ChonSong/hermes-webui
RIPTIDE_STALENESS_MINUTES=30
RIPTIDE_MIN_LOC_CHANGED=100# Development
bash start.sh
# Docker
docker compose up -d --build
# Production (Cloudflare Tunnel)
cloudflared tunnel --config ~/.cloudflared/config.yml run# Add to Hermes cron (every 15 minutes)
hermes cron create "*/15 * * * *" \
--name "riptide-review-poll" \
--script /home/sc/workspace/riptide/riptide/deepthink.py| Variable | Description | Default |
|---|---|---|
RIPTIDE_COMPANION_REPOS |
Comma-separated owner/repo list |
(disabled) |
RIPTIDE_COMPANION_MODEL |
Ollama model for TLDR generation | qwen2.5-coder:7b |
COMPANION_ENABLE_GRAPHIFY |
Enable blast radius analysis | 1 |
| Variable | Description | Default |
|---|---|---|
RIPTIDE_WATCHED_REPOS |
Comma-separated owner/repo list |
(all ChonSong repos) |
RIPTIDE_OUR_USERNAME |
GitHub username for authorship check | ChonSong |
RIPTIDE_OUR_ORG |
GitHub org for ownership check | ChonSong |
RIPTIDE_STALENESS_MINUTES |
Minutes since last update to qualify | 30 |
RIPTIDE_MIN_LOC_CHANGED |
Minimum LOC changes to trigger | 100 |
POST /webhook/github
Headers:
X-Hub-Signature-256: sha256=...
X-GitHub-Event: pull_request
X-GitHub-Delivery: uuid
GET /health
→ {"status": "ok", "app": "riptide"}
| Event | Action | Output |
|---|---|---|
pull_request opened/reopened/synchronize |
Companion TLDR | TL;DR comment |
issue_comment @riptide-bot companion skip/resume |
Control companion | Confirmation reply |
issue_comment @riptide-bot review / full review / deepthink |
Trigger Bot 2 deep-think | Confirmation reply |
installation created/deleted |
Sync repo list | Metadata DB updated |
| Riptide | Octopus | CodeRabbit | |
|---|---|---|---|
| Stack | Python / FastAPI | Next.js + tRPC | SaaS |
| Vector store | None (graphify for blast radius) | Qdrant (Docker) | Proprietary |
| Deployment | Single container | Multi-service | Cloud-only |
| Auth | GitHub App JWT | JWT + Prisma | OAuth |
| TLDR Comments | ✅ (Companion) | ❌ | ✅ |
| ELI5 Explanations | ✅ | ❌ | ❌ |
| Deep Thinking | ✅ (Bot 2) | ❌ | ❌ |
| Graphify Blast Radius | ✅ | ❌ | ❌ |
| Self-Hosted | ✅ | ✅ | ❌ |
# Syntax check
python -m py_compile riptide/companion.py riptide/deepthink.py riptide/webhook.py riptide/github_app.py# Send test payload
python3 -c "
import requests, json, hmac, hashlib
payload = {'action': 'opened', 'number': 1, 'pull_request': {'title': 'test', 'user': {'login': 'test'}, 'head': {'sha': 'abc'}},'repository': {'full_name': 'owner/repo', 'name': 'repo'}, 'installation': {'id': 123}}
body = json.dumps(payload)
sig = 'sha256=' + hmac.new(b'secret', body.encode(), hashlib.sha256).hexdigest()
requests.post('http://localhost:8477/webhook/github', data=body, headers={'X-Hub-Signature-256': sig, 'X-GitHub-Event': 'pull_request'})
"# Run unit tests
source .env 2>/dev/null # optional — tests with no-op fallback
python3 -m pytest riptide/tests/ -v
# Manual webhook smoke-test
python3 -c "
import requests, json, hmac, hashlib
payload = {'action': 'opened', 'number': 1, 'pull_request': {'title': 'test', 'user': {'login': 'test'}, 'head': {'sha': 'abc'}},'repository': {'full_name': 'owner/repo', 'name': 'repo'}, 'installation': {'id': 123}}
body = json.dumps(payload)
sig = 'sha256=' + hmac.new(b'secret', body.encode(), hashlib.sha256).hexdigest()
requests.post('http://localhost:8477/webhook/github', data=body, headers={'X-Hub-Signature-256': sig, 'X-GitHub-Event': 'pull_request'})
"
# Server health check (requires running service)
curl -s http://localhost:8477/healthModified MIT — see LICENSE.md.
Test commit for webhook GIF verification.