Your Git-Bro that spots you on every PR.
github-bro is a self-hosted AI code reviewer that automatically analyzes your GitHub pull requests and posts detailed reviews. It catches security vulnerabilities, bugs, performance issues, and bad practices before they reach production.
Runs a local LLM by default (private, no data leaves your machine). Optionally switch to cloud via OpenRouter for faster results.
- Automatic PR reviews β triggered by GitHub webhooks or polling
- Local-first β runs Qwen2.5-Coder-7B locally by default, 100% private
- Apple Metal GPU β auto-detects Metal for fast inference on Apple Silicon
- Cloud option β switch to OpenRouter (50+ models) from the Settings UI
- Smart token management β uses tiktoken for accurate token counting and diff truncation
- Markdown reviews β renders code blocks, tables, and formatting in the dashboard
- Pagination & filtering β browse reviews by page and filter by project
- Real PR reviews β posts as a GitHub review or comment with verdict
- Self-review fallback β automatically posts a comment when reviewing your own PR (GitHub blocks self-reviews)
- Local-only mode β optionally store reviews only in github-bro without posting to GitHub
- Provider toggle β switch between Local and Cloud from the UI, no restart needed
- JWT authentication β password-protected UI with bcrypt + JWT
- Delete reviews β manage reviews directly from the dashboard
- Docker-ready β one command to deploy
GitHub Webhook / Polling
|
PR opened / updated
|
v
+-------------------+
| github-bro |
| (Express/TS) |
+--------+----------+
|
+--------------+--------------+
| | |
v v v
+---------+ +-----------+ +-----------+
| SQLite | | GitHub | | LLM |
| reviews | | API | | Provider |
+---------+ +-----+-----+ +-----+-----+
| |
fetch diff analyze code
| |
v v
+-------------------------+
| POST review/comment |
| or store locally |
+-------------------------+
LLM Provider:
+------------------+ +------------------+
| Local Worker | | OpenRouter |
| (Python/GGUF) | OR | (cloud) |
| 100% private | | 50+ models |
+------------------+ +------------------+
| Category | Examples |
|---|---|
| Security | SQL injection, XSS, RCE, eval(), hardcoded secrets, insecure auth |
| Performance | Sync operations in async context, N+1 queries, memory leaks |
| Code quality | Missing error handling, unused imports, naming issues |
| Best practices | Missing input validation, improper auth patterns, untyped env vars |
## github-bro Review
**Summary:** Found 2 security issues and 1 performance concern
### π΄ Critical
> **SQL Injection** (`src/users.ts:8`)
>
> User input concatenated into query without sanitization.
> ```suggestion
> db.prepare("SELECT * FROM users WHERE name = ?").get(user)
> ```
### π‘ Warning
> **Blocking I/O** (`src/auth.ts:13`)
>
> bcrypt.compareSync blocks the event loop. Use bcrypt.compare instead.
### π’ Suggestion
> **Env validation**
>
> Ensure JWT_SECRET is defined at startup.
**Verdict:** REQUEST_CHANGES
-- github-broPR #1 β Security vulnerabilities detected: SQL injection, path traversal, rate limiting bypass
PR #2 β Clean refactor, no issues found. Verdict: APPROVE
git clone https://github.com/antoniociccia/github-bro.git
cd github-bro
cp .env.example .envEdit .env:
GITHUB_TOKEN=ghp_your_token # GitHub PAT with repo scope
GITHUB_WEBHOOK_SECRET=your-secret # Optional: webhook signature verificationdocker compose --profile local up -dThis starts both github-bro and the local LLM worker. On first startup, the worker downloads Qwen2.5-Coder-7B-Instruct from HuggingFace (~4.5GB) and caches it in ./models/.
For Metal GPU acceleration on Mac:
# Backend
npm install && npm run build:server && npm run build:ui
node dist/index.js
# Worker (in a separate terminal)
cd worker
python -m venv .venv && source .venv/bin/activate
bash setup.sh # auto-detects Metal/CUDA/CPU
python server.pyThe setup.sh script automatically detects your GPU:
- CUDA (NVIDIA) β compiles with
DGGML_CUDA=on - Metal (Apple Silicon) β compiles with
DGGML_METAL=on - CPU β fallback, no GPU flags
Open http://your-server:3010 in a browser. On first visit you'll be prompted to create an account (email + password). This enables JWT authentication on all API endpoints. The password is hashed with bcrypt and stored in the local SQLite database.
github-bro polls antoniociccia/github-bro by default. Change the repos in Settings > GitHub > Repositories to poll.
To use webhooks instead:
- Go to your repo Settings > Webhooks > Add webhook
- Payload URL:
https://your-server:3010/webhook - Content type:
application/json - Secret: same value as
GITHUB_WEBHOOK_SECRET - Events: select Pull requests
Switch between Local and Cloud from the Settings page:
- Local (default) β uses the bundled worker, no API key needed
- Cloud β shows API Key and Model fields, uses OpenRouter
An Advanced checkbox reveals the Base URL field for custom endpoints.
Changes apply immediately β no restart required.
To use OpenRouter, switch to Cloud in Settings and enter your API key. Or set it in .env:
OPENROUTER_API_KEY=sk-or-v1-...
OPENROUTER_MODEL=qwen/qwen3.5-35b-a3b
LLM_BASE_URL=https://openrouter.ai/api/v1Qwen2.5-Coder-7B-Instruct Q4_K_M β ~4.5GB, optimized for code review. Best quality reviews among local models tested. Runs great on Apple Silicon with Metal GPU acceleration.
Swap it for any GGUF model by setting these in .env:
MODEL_REPO=Qwen/Qwen2.5-Coder-7B-Instruct-GGUF
MODEL_FILE=qwen2.5-coder-7b-instruct-q4_k_m.gguf
CONTEXT_SIZE=16384
GPU_LAYERS=-1Other tested models:
| Model | Size | Speed | Quality |
|---|---|---|---|
| Qwen2.5-Coder-7B | 4.5GB | ~50s/review | Best |
| Phi-4-mini | 2.5GB | ~15s/review | Good |
| Platform | Backend | How |
|---|---|---|
| Apple Silicon | Metal | Run worker natively with setup.sh, or set LLAMA_BACKEND=metal |
| NVIDIA GPU | CUDA | docker build --build-arg LLAMA_BACKEND=cuda ./worker |
| CPU only | CPU | Default in Docker (no GPU passthrough on macOS Docker) |
Note: Docker on macOS cannot access Metal GPU. For best performance on Mac, run the worker natively.
github-bro uses tiktoken for accurate token counting. Diffs are automatically truncated using binary search to fit within the model's context window while maximizing the amount of code reviewed.
When APP_SECRET is set in .env, github-bro signs short-lived JWTs to authenticate with the worker. The worker verifies them. Set the same APP_SECRET for both services (docker-compose handles this automatically).
Control how reviews are posted from Settings > GitHub:
- Post to GitHub: ON (default) β reviews are posted on the PR and stored locally
- Post to GitHub: OFF β reviews are stored locally only, visible in the dashboard
Note: GitHub does not allow a user to post a formal review on their own PR. When this happens, github-bro automatically falls back to posting a regular PR comment instead.
github-bro uses password-based JWT authentication:
- First visit β the UI shows a "Create Account" form (email + password)
- Subsequent visits β login with your credentials
- JWT tokens β valid for 7 days, stored in
localStorage - Protected endpoints β all
/api/*routes require a valid token (except/api/auth-required,/api/setup,/api/login) - Public endpoints β
/webhook,/health, and static UI files remain open
If no account has been created, all API endpoints are open (backward compatible).
npm install
npm run build:server
npm test55 tests covering database operations, JWT auth, token counting, diff truncation, GitHub integration, and polling logic. CI runs automatically on pull requests via GitHub Actions.
Test the review pipeline without a real PR:
npm install
npm run dry-runSends a fake diff to the LLM and outputs the formatted review to stdout.
| Variable | Description | Default |
|---|---|---|
GITHUB_TOKEN |
GitHub PAT with repo scope |
required |
GITHUB_WEBHOOK_SECRET |
Webhook signature secret | optional |
OPENROUTER_API_KEY |
OpenRouter API key | not needed (local mode) |
OPENROUTER_MODEL |
Model identifier | local |
LLM_BASE_URL |
LLM API endpoint | http://worker:8000/v1 |
APP_SECRET |
Shared secret for JWT signing and worker auth | auto-generated |
PORT |
Server port | 3010 |
POLL_REPOS |
Repos to poll (owner/repo, comma-separated) |
antoniociccia/github-bro |
POLL_INTERVAL |
Polling interval in seconds | 300 |
CONTEXT_SIZE |
Context window for token truncation | 16384 |
| Variable | Description | Default |
|---|---|---|
MODEL_REPO |
HuggingFace repo ID | Qwen/Qwen2.5-Coder-7B-Instruct-GGUF |
MODEL_FILE |
GGUF filename | qwen2.5-coder-7b-instruct-q4_k_m.gguf |
CONTEXT_SIZE |
Context window size | 16384 |
GPU_LAYERS |
Layers offloaded to GPU (-1 = all) |
-1 |
LLAMA_BACKEND |
Force GPU backend: metal, cuda, or cpu |
auto-detected |
APP_SECRET |
Must match github-bro's APP_SECRET |
optional |
| Setting | Description | Default |
|---|---|---|
llm_provider |
local or cloud |
local |
post_to_github |
Post reviews on GitHub PRs | true |
poll_repos |
Repos to watch | antoniociccia/github-bro |
poll_interval |
Polling interval in seconds | 300 |
Any model on OpenRouter, including:
qwen/qwen3.5-35b-a3b(cheap, fast)anthropic/claude-sonnet-4-6(best quality)meta-llama/llama-3.1-8b-instruct(open source)
github-bro/
βββ src/
β βββ index.ts # Express server, webhook handler
β βββ api.ts # API routes (auth + config + reviews)
β βββ auth.ts # JWT middleware and token signing
β βββ github.ts # GitHub API (fetch diff, post review)
β βββ reviewer.ts # LLM client, tiktoken-based truncation
β βββ db.ts # SQLite (reviews, config, users)
β βββ poller.ts # Polling mode
β βββ dry-run.ts # Local test with fake diff
β βββ seed-demo.ts # Seed a demo review into the database
β βββ __tests__/ # Unit tests (vitest)
βββ ui/
β βββ src/
β βββ App.tsx # Auth-aware shell
β βββ api.ts # apiFetch helper (auto Bearer token)
β βββ pages/
β βββ Dashboard.tsx # Review list with markdown, pagination, filters
β βββ Settings.tsx # Provider toggle + config
β βββ Login.tsx # Login / setup form
βββ worker/
β βββ server.py # FastAPI + llama-cpp-python + JWT auth
β βββ setup.sh # Auto-detect GPU backend (Metal/CUDA/CPU)
β βββ requirements.txt
β βββ Dockerfile
βββ .github/workflows/
β βββ docker.yml # Build & push images to ghcr.io
β βββ test.yml # Run tests on PRs
βββ docker-compose.yml
βββ Dockerfile
βββ .env.example
| Component | Technology |
|---|---|
| Server | TypeScript, Express 5, dotenv |
| GitHub integration | Octokit |
| LLM client | OpenAI SDK (compatible with local worker + OpenRouter) |
| Token counting | tiktoken (accurate BPE tokenization) |
| Authentication | bcrypt, jsonwebtoken (JWT) |
| Database | better-sqlite3 |
| UI | React, Tailwind CSS, react-markdown |
| Testing | vitest |
| Local inference | Python, FastAPI, llama-cpp-python |
| GPU support | Metal (Apple Silicon), CUDA (NVIDIA) |
| Default model | Qwen2.5-Coder-7B-Instruct (GGUF Q4_K_M, ~4.5GB) |
| Containerization | Docker, multi-stage builds |


