Files

1 line
67 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "asdqwe21212/pr-review-agent", "files": {"README.md": {"8b64e330a171fe0425a68a626e42aaa418c72df5": {"t": 1785746410.6272058, "n": 17831, "h": "53e4d9213c4e4509", "c": "# PR Review Agent\n\nAI-powered pull request code review system using Claude API with multi-turn reasoning.\nDesigned for teams handling 50+ PRs/week with ~2M tokens weekly budget.\n\n## Architecture\n\n```\n┌──────────────────────────────────────────────────────────────────────┐\n│ PR Review Agent │\n│ │\n│ GitHub PR ──► Agent ──► Turn 1: Bug & Security Scan │\n│ │──► Turn 2: Performance & Quality │\n│ │──► Turn 3: Structured JSON Report │\n│ └──► Post Comment to GitHub PR │\n│ │\n│ FastAPI Server ──► REST API ──► Dashboard UI │\n│ GitHub Webhook ──► Auto-trigger on PR open/update/label │\n│ Task Queue (arq) ──► Async Processing ──► Worker Pool │\n│ Job Store ──► In-Memory / File (JSONL) / Redis │\n│ Monitoring ──► Prometheus Metrics ──► Grafana │\n└──────────────────────────────────────────────────────────────────────┘\n```\n\n## Quick Start\n\n### 1. Clone & Install\n\n```bash\ngit clone <this-repo>\ncd pr-review-agent\npip install -r requirements.txt\n```\n\n### 2. Configure Environment\n\n```bash\ncp config/.env.example config/.env\n# Edit config/.env with your API keys\n```\n\nRequired:\n- `ANTHROPIC_API_KEY` (or any provider key — see [Multi-Provider LLM Support](#multi-provider-llm-support)) — for Anthropic\n- `GITHUB_TOKEN` — GitHub Personal Access Token with `repo` scope\n\n### 3a. CLI Usage (Quick)\n\n```bash\ncd backend\n# Load env vars\nexport $(cat ../config/.env | xargs) # Linux/Mac\n# Or on Windows: use set or a .env loader\n\n# Review a PR (posts comment to GitHub)\npython cli.py --repo owner/repo-name --pr 42\n\n# Dry run (no GitHub comment)\npython cli.py --repo owner/repo-name --pr 42 --no-comment\n\n# Save full JSON result\npython cli.py --repo owner/repo-name --pr 42 --output result.json\n```\n\n### 3b. Web Server + Dashboard\n\n```bash\ncd backend\nexport $(cat ../config/.env | xargs)\npython server.py\n\n# Open http://localhost:8000\n```\n\n### 3c. Worker (Production)\n\nFor production deployments with async task queue:\n\n```bash\n# Start the arq worker\npython scripts/start_worker.py\n\n# Worker reads REDIS_URL and WORKER_CONCURRENCY from environment\n```\n\n### 3c. GitHub Actions (Automated)\n\nCopy `.github/workflows/pr-review.yml` to your repository. Add these secrets:\n- `ANTHROPIC_API_KEY`\n- `GITHUB_TOKEN`\n\nEvery PR open/sync/reopen triggers an automatic review.\n\n## Multi-Provider LLM Support\n\nThe agent is not locked to Anthropic — the LLM provider is configurable end-to-end. The backend speaks two wire formats:\n\n| Backend format | Used by |\n|----------------|---------|\n| `anthropic` | Native Anthropic Messages API. The **Base URL** is optional — set it to point at any Anthropic-protocol proxy. The **Model** field accepts any id (e.g. `claude-3-5-sonnet-20241022`, `claude-3-opus-20240229`, `claude-3-haiku-20240307`, or a custom id your proxy exposes). |\n| `openai-compatible` | OpenAI Chat Completions and any drop-in compatible endpoint (OpenAI, DeepSeek, Moonshot, Zhipu GLM, Ollama, vLLM, Together, Groq, OpenRouter, …). The **Model** field accepts any id (e.g. `gpt-4o`, `gpt-4o-mini`, `deepseek-chat`, `llama3.1`, fine-tunes, etc.). |\n\nIn short: **both formats support custom model names**, and the Anthropic format additionally supports pointing at a custom endpoint (LiteLLM, AWS Bedrock, gateway, etc.).\n\n### Switching providers from the dashboard\n\nThe fastest way is via the web UI. Start the server (`python backend/server.py`) and open `http://localhost:8000`. Click **Settings** in the top-right corner to open the LLM configuration dialog:\n\n- Pick a **Provider** preset:\n - **Anthropic (Claude)** — official Anthropic endpoint, no base URL needed\n - **Custom (Anthropic-compatible)** — point at any Anthropic-protocol proxy and supply a model id\n - **OpenAI / DeepSeek / Moonshot / 智谱 GLM / Ollama / Custom (OpenAI-compatible)** — covers the OpenAI wire format\n- The dialog auto-fills a sensible **Base URL** and **Model** for each preset; you can override either with your own value\n- Paste your **API Key** (stored server-side only; never echoed back to the browser)\n- Adjust **Temperature** if you want\n\nThe provider is persisted at `data/llm_config.json` and is hot-reloaded on every review job, so the next PR you submit uses the new provider.\n\n### Dashboard language\n\nThe dashboard ships with **English** and **简体中文** and exposes a one-click toggle in the header (the pill that reads `EN` or `中`):\n\n- The active language is stored in `localStorage` under `pr-review.lang`, so the choice persists across reloads and browser restarts\n- On first visit the language is auto-detected from `navigator.language` — anything starting with `zh` lands on Chinese, anything else on English\n- Switching languages re-translates all dashboard chrome, the Settings dialog (including provider notes and hints), the job list status pills, the review detail labels, the loading messages, and the error/alert text\n- LLM-generated review content (the `summary`, `bugs`, `security`, `performance`, `quality`, `positives` fields) is left in the language the model produced it in — that is controlled by your prompt and provider, not by the UI language\n\n### Switching providers via environment variables\n\nIf you'd rather configure at deploy time, the same fields can be set as env vars. The dashboard `data/llm_config.json` (if it exists) takes precedence over the env.\n\n| Env var | Description |\n|---------|-------------|\n| `LLM_PROVIDER` | `anthropic` or `openai-compatible` |\n| `LLM_API_KEY` | Provider API key. `ANTHROPIC_API_KEY` is still respected as a fallback for `anthropic`. |\n| `LLM_MODEL` | Model id — free-form. `claude-sonnet-4-20250514`, `claude-3-opus-20240229`, `gpt-4o-mini`, `deepseek-chat`, `llama3.1`, fine-tunes, custom proxy ids, etc. |\n| `LLM_BASE_URL` | Optional for `anthropic` (omit to use the official endpoint), required for `openai-compatible`. e.g. `https://api.openai.com/v1`, `http://localhost:11434/v1`, `https://your-litellm-proxy.example.com` |\n| `LLM_TEMPERATURE` | `0.0` – `2.0` (default `0.2`) |\n\n### Example: DeepSeek via env\n\n```bash\nexport LLM_PROVIDER=openai-compatible\nexport LLM_API_KEY=sk-...\nexport LLM_BASE_URL=https://api.deepseek.com/v1\nexport LLM_MODEL=deepseek-chat\n```\n\n### Example: Local Ollama\n\n```bash\nexport LLM_PROVIDER=openai-compatible\nexport LLM_BASE_URL=http://localhost:11434/v1\nexport LLM_MODEL=llama3.1\n# Ollama ignores the key, but the field must be non-empty to be sent\nexport LLM_API_KEY=ollama\n```\n\n### Example: Anthropic-compatible proxy (LiteLLM, gateway, …)\n\n```bash\nexport LLM_PROVIDER=anthropic\nexport LLM_API_KEY=sk-anything-the-proxy-expects\nexport LLM_BASE_URL=https://your-litellm-proxy.example.com\n# Any model id your proxy exposes — LiteLLM accepts Anthropic model names,\n# OpenAI model names, or any custom routing key\nexport LLM_MODEL=claude-3-5-sonnet-20241022\n```\n\nThe agent will speak the Anthropic Messages protocol but talk to your proxy instead of `api.anthropic.com`. Useful for centralized key management, audit logging, on-prem deployments, or routing through Cloudflare / VPC.\n\n### How requests are dispatched\n\n| Provider type | Endpoint called | Auth header |\n|---------------|-----------------|-------------|\n| `anthropic` (no `base_url`) | Anthropic SDK → `https://api.anthropic.com` | handled by SDK |\n| `anthropic` (with `base_url`) | Anthropic SDK → `{base_url}` | handled by SDK |\n| `openai-compatible` | `POST {base_url}/chat/completions` | `Authorization: Bearer <key>` |\n\nReview output structure is identical across providers — switching providers does not change the GitHub comment format, the score, or the issue categories the agent reports.\n\n## How Multi-Turn Reasoning Works\n\nThe agent uses 3 sequential Claude API calls per review, each building on prior context:\n\n| Turn | Focus | Approach |\n|------|-------|----------|\n| 1 | Bugs & Security | Deep scan: logic errors, null refs, injection risks, auth flaws |\n| 2 | Performance & Quality | O(n^2) detection, N+1 queries, naming, complexity, test gaps |\n| 3 | Structured Report | Synthesize all findings into final JSON review object |\n\n## Review Output Structure\n\n```json\n{\n \"summary\": \"High-level assessment\",\n \"severity\": \"critical|high|medium|low\",\n \"overall_score\": 0-100,\n \"approve\": true|false,\n \"bugs\": [{\"line\": \"file.py:42\", \"description\": \"...\", \"suggestion\": \"...\"}],\n \"security\": [...],\n \"performance\": [...],\n \"quality\": [...],\n \"positives\": [\"Good error handling in X\", ...]\n}\n```\n\n## Configuration Reference\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `ANTHROPIC_API_KEY` | (required) | Anthropic API key (fallback for `LLM_API_KEY` when provider is `anthropic`) |\n| `LLM_PROVIDER` | `anthropic` | `anthropic` or `openai-compatible` |\n| `LLM_API_KEY` | — | Provider API key. Overrides `ANTHROPIC_API_KEY` when set. |\n| `LLM_MODEL` | `claude-sonnet-4-20250514` | Model id sent to the provider |\n| `LLM_BASE_URL` | — | Required for `openai-compatible` providers |\n| `LLM_TEMPERATURE` | `0.2` | Sampling temperature (0.0 – 2.0) |\n| `GITHUB_TOKEN` | (required) | GitHub PAT with `repo` scope |\n| `GITHUB_WEBHOOK_SECRET` | (required for webhooks) | HMAC-SHA256 webhook verification |\n| `API_KEY` | — | Optional API key for endpoint authentication |\n| `CORS_ORIGINS` | `http://localhost:8000,http://127.0.0.1:8000` | Comma-separated allowed CORS origins |\n| `CLAUDE_MODEL` | `claude-sonnet-4-20250514` | Legacy alias for `LLM_MODEL` |\n| `PR_REVIEW_MODE` | `full` | `full` / `diff-only` / `auto` |\n| `PR_REVIEW_MAX_FILES` | `20` | Max files to include in context |\n| `PR_REVIEW_MAX_FILE_CHARS` | `5000` | Max chars per file content |\n| `PR_REVIEW_MAX_CONTEXT_CHARS` | `80000` | Total context size cap |\n| `PR_REVIEW_FULL_CONTENT_THRESHOLD` | `500` | Max additions to fetch full content |\n| `PR_REVIEW_CONTEXT_ENABLED` | `true` | Load CONTEXT.md from PR branch |\n| `TOKEN_BUDGET_WEEKLY` | `2000000` | Weekly token budget for alerts |\n| `TOKEN_BUDGET_ALERT_THRESHOLD` | `0.8` | Alert at 80% budget consumed |\n| `LOG_LEVEL` | `INFO` | Logging level |\n| `REDIS_URL` | — | Redis connection (required for production) |\n| `WORKER_CONCURRENCY` | `10` | Max concurrent review tasks per worker |\n| `MAX_QUEUE_SIZE` | `100` | Max pending reviews in queue |\n| `ENVIRONMENT` | `production` | Environment identifier for logging |\n| `SENTRY_DSN` | — | Optional Sentry error tracking DSN |\n\n## API Endpoints\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `POST` | `/api/review` | Start a new review job |\n| `GET` | `/api/jobs` | List all jobs (filter: `?repo=`, `?days=`) |\n| `GET` | `/api/jobs/{id}` | Get job status & result |\n| `GET` | `/api/stats` | Aggregate statistics (filter: `?days=`) |\n| `GET` | `/api/config/llm` | Read the current LLM provider config (api_key is masked) |\n| `POST` | `/api/config/llm` | Persist the LLM provider config; leave `api_key` blank to keep the existing key |\n| `GET` | `/api/metrics` | Combined quality + throughput + tokens |\n| `GET` | `/api/metrics/tokens` | Weekly budget, daily breakdown, per-review stats |\n| `GET` | `/api/metrics/quality` | Score distribution, severity, approval rate |\n| `GET` | `/api/metrics/throughput` | Reviews/day, files reviewed |\n| `POST` | `/webhook/github` | GitHub webhook handler |\n| `GET` | `/api/health` | Health check (Redis, queue status) |\n| `GET` | `/api/health/ready` | Kubernetes readiness probe |\n| `GET` | `/api/health/live` | Kubernetes liveness probe |\n| `GET` | `/metrics` | Prometheus metrics endpoint |\n\n## Token Usage\n\nTypical per-PR consumption:\n- **Small PR** (< 5 files): ~15K–30K tokens\n- **Medium PR** (5–20 files): ~40K–80K tokens\n- **Large PR** (20+ files): ~80K–150K tokens\n\nUse `PR_REVIEW_MODE=diff-only` to cut token usage ~50% for large PRs.\n\n## Production Deployment\n\n### Job Store\n\nThree backends, auto-selected:\n\n| Backend | Trigger | Persistence |\n|---------|---------|-------------|\n| `InMemoryJobStore` | (fallback) | Lost on restart |\n| `FileJobStore` | Default | JSONL file at `data/jobs.jsonl` |\n| `RedisJobStore` | Set `REDIS_URL` | Redis, with 7-day TTL, status indexing |\n\n### Task Queue (arq + Redis)\n\nFor production workloads, the system uses an async task queue:\n\n```bash\n# Start the API server\npython server.py\n\n# Start worker(s) in separate processes\npython scripts/start_worker.py\n```\n\nFeatures:\n- Async task processing with automatic retries (3 attempts)\n- Request deduplication prevents duplicate reviews\n- Result caching (1 hour TTL based on PR head SHA)\n- Graceful shutdown with active task tracking\n\n### Process Manager\n\n```bash\n# Single worker (fine for < 100 PRs/week)\npython server.py\n\n# Multi-worker production with gunicorn\ngunicorn server:app -w 4 -k uvicorn.workers.UvicornWorker\n```\n\n### Token Budget Monitoring\n\nSet `TOKEN_BUDGET_WEEKLY` and check the dashboard for real-time budget tracking.\nThe stats bar shows a color-coded progress bar: green (< 50%), yellow (50–80%), red (> 80%).\n\n## Security\n\n### API Authentication\n\nSet `API_KEY` environment variable to enable bearer token authentication on all `/api/*` endpoints. When set, requests must include:\n\n```\nAuthorization: Bearer your-api-key-here\n```\n\n### Webhook Security\n\n`GITHUB_WEBHOOK_SECRET` is **required** for webhook endpoints. Webhooks without a valid HMAC-SHA256 signature will be rejected. Generate a secret with:\n\n```bash\nopenssl rand -hex 32\n```\n\n### CORS Configuration\n\nConfigure allowed origins with `CORS_ORIGINS` (comma-separated). Defaults to localhost only.\n\n## GitHub Token Permissions\n\nMinimum required scopes: `repo` (private repos) or `public_repo` (public). This allows reading PR diffs and posting review comments.\n\n## Project-Specific Review Rules\n\nAdd `.pr-review-rules.md` to your repository root (or `.github/pr-review-rules.md`). The agent will inject these rules into the review prompt. Example:\n\n```markdown\n# PR Review Rules\n- All API endpoints must validate input with Pydantic models\n- Database queries must use parameterized queries\n- All new functions must have type hints\n- No console.log or print() in production code\n```\n\nAlso supported: `CONTEXT.md` / `.pr-review-context.md` / `CONTRIBUTING.md` for general project context.\n\n## Changelog\n\n### v1.3.0 - Multi-Provider LLM Support\n\n**New Features:**\n- Dashboard **Settings** dialog to switch LLM provider, model, base URL, API key, and temperature without restarting the server\n- Provider presets: Anthropic, OpenAI, DeepSeek, Moonshot (Kimi), Zhipu GLM, Ollama, Custom OpenAI-compatible, **Custom Anthropic-compatible** (LiteLLM, gateways, etc.)\n- Custom model support: the **Model** field is free-form on both wire formats, so any model id works (claude-3-opus-*, claude-3-haiku-*, gpt-4o-*, deepseek-*, llama*, fine-tunes, proxy routing keys, …)\n- Anthropic provider now accepts an optional **Base URL**, so you can route Anthropic-protocol traffic through a proxy while keeping the same review output\n- Header status indicator reflects the active provider and shows a warning dot when no API key is set\n- Dashboard language toggle: one-click switch between **English** and **简体中文** in the header, with `localStorage` persistence and `navigator.language` auto-detection on first visit\n- Added `LLM_PROVIDER`, `LLM_API_KEY`, `LLM_MODEL`, `LLM_BASE_URL`, `LLM_TEMPERATURE` environment variables (dashboard `data/llm_config.json` still wins when present)\n\n**Notes:**\n- No breaking changes. Existing `ANTHROPIC_API_KEY` + `CLAUDE_MODEL` deployments continue to work without any edit.\n\n### v1.2.0 - Production Readiness\n\n**New Features:**\n- Async task queue with arq + Redis for concurrent processing\n- Request deduplication to prevent duplicate reviews\n- Result caching with SHA-based keys (1 hour TTL)\n- Prometheus metrics endpoint (`/metrics`)\n- Kubernetes health probes (`/api/health/ready`, `/api/health/live`)\n- Graceful shutdown with active task tracking\n- Thread-safe singleton pattern for all managers\n- Comprehensive unit tests for core modules\n\n**Bug Fixes:**\n- Fixed deprecated `datetime.utcnow()` (Python 3.12+ compatible)\n- Fixed frontend polling memory leak using AbortController\n- Fixed asyncio event loop handling with `asyncio.to_thread()`\n- Enhanced RedisJobStore with status indexing for faster queries\n\n**Infrastructure:**\n- Added `backend/tasks.py` - arq task definitions\n- Added `backend/dedup.py` - request deduplication\n- Added `backend/cache.py` - result caching\n- Added `backend/shutdown.py` - graceful shutdown\n- Added `backend/metrics_middleware.py` - Prometheus middleware\n- Added `backend/singleton.py` - thread-safe singleton decorator\n- Added `scripts/start_worker.py` - Worker startup script\n- Added comprehensive test suite in `tests/`\n\n### v1.1.0 - Security & Reliability Improvements\n\n**Security Fixes:**\n- Fixed XSS vulnerability in frontend dashboard\n- Added optional API key authentication (`API_KEY` env var)\n- Webhook signature verification now required (no more bypass)\n- CORS origins now configurable (defaults to localhost only)\n\n**Bug Fixes:**\n- Fixed job ID collision when submitting multiple reviews rapidly\n- Fixed KeyError crash in stats endpoint with incomplete data\n- Fixed fragile JSON parsing for Claude responses\n- Fixed metrics dead code in throughput calculation\n- Fixed token tracker week start normalization\n- Updated deprecated `datetime.utcnow()` calls\n- Fixed GitHub Actions workflow to install all dependencies\n\n**New Features:**\n- Added `CORS_ORIGINS` configuration\n- Added `API_KEY` for endpoint authentication\n- Added `backend/__init__.py` for proper module imports\n"}, "6ca0444b043338cb98f4086e2a89ae57b54ef073": {"t": 1785763651.3577068, "n": 16764, "h": "808ee402168ab157", "c": "# PR Review Agent\n\nAI-powered pull request code review system using Claude API with multi-turn reasoning.\nDesigned for teams handling 50+ PRs/week with ~2M tokens weekly budget.\n\n## Architecture\n\n```\n┌──────────────────────────────────────────────────────────────────────┐\n│ PR Review Agent │\n│ │\n│ GitHub PR ──► Agent ──► Turn 1: Bug & Security Scan │\n│ │──► Turn 2: Performance & Quality │\n│ │──► Turn 3: Structured JSON Report │\n│ └──► Post Comment to GitHub PR │\n│ │\n│ FastAPI Server ──► REST API ──► Dashboard UI │\n│ GitHub Webhook ──► Auto-trigger on PR open/update/label │\n│ Task Queue (arq) ──► Async Processing ──► Worker Pool │\n│ Job Store ──► In-Memory / File (JSONL) / Redis │\n│ Monitoring ──► Prometheus Metrics ──► Grafana │\n└──────────────────────────────────────────────────────────────────────┘\n```\n\n## Quick Start\n\n### 1. Clone & Install\n\n```bash\ngit clone <this-repo>\ncd pr-review-agent\npip install -r requirements.txt\n```\n\n### 2. Configure Environment\n\n```bash\ncp config/.env.example config/.env\n# Edit config/.env with your API keys\n```\n\nRequired:\n- `ANTHROPIC_API_KEY` (or any provider key — see [Multi-Provider LLM Support](#multi-provider-llm-support)) — for Anthropic\n- `GITHUB_TOKEN` — GitHub Personal Access Token with `repo` scope\n\n### 3a. CLI Usage (Quick)\n\n```bash\ncd backend\n# Load env vars\nexport $(cat ../config/.env | xargs) # Linux/Mac\n# Or on Windows: use set or a .env loader\n\n# Review a PR (posts comment to GitHub)\npython cli.py --repo owner/repo-name --pr 42\n\n# Dry run (no GitHub comment)\npython cli.py --repo owner/repo-name --pr 42 --no-comment\n\n# Save full JSON result\npython cli.py --repo owner/repo-name --pr 42 --output result.json\n```\n\n### 3b. Web Server + Dashboard\n\n```bash\ncd backend\nexport $(cat ../config/.env | xargs)\npython server.py\n\n# Open http://localhost:8000\n```\n\n### 3c. Worker (Production)\n\nFor production deployments with async task queue:\n\n```bash\n# Start the arq worker\npython scripts/start_worker.py\n\n# Worker reads REDIS_URL and WORKER_CONCURRENCY from environment\n```\n\n### 3c. GitHub Actions (Automated)\n\nCopy `.github/workflows/pr-review.yml` to your repository. Add these secrets:\n- `ANTHROPIC_API_KEY`\n- `GITHUB_TOKEN`\n\nEvery PR open/sync/reopen triggers an automatic review.\n\n## Multi-Provider LLM Support\n\nThe agent is not locked to Anthropic — the LLM provider is configurable end-to-end. The backend speaks two wire formats:\n\n| Backend format | Used by |\n|----------------|---------|\n| `anthropic` | Native Anthropic Messages API. The **Base URL** is optional — set it to point at any Anthropic-protocol proxy. The **Model** field accepts any id (e.g. `claude-3-5-sonnet-20241022`, `claude-3-opus-20240229`, `claude-3-haiku-20240307`, or a custom id your proxy exposes). |\n| `openai-compatible` | OpenAI Chat Completions and any drop-in compatible endpoint (OpenAI, DeepSeek, Moonshot, Zhipu GLM, Ollama, vLLM, Together, Groq, OpenRouter, …). The **Model** field accepts any id (e.g. `gpt-4o`, `gpt-4o-mini`, `deepseek-chat`, `llama3.1`, fine-tunes, etc.). |\n\nIn short: **both formats support custom model names**, and the Anthropic format additionally supports pointing at a custom endpoint (LiteLLM, AWS Bedrock, gateway, etc.).\n\n### Switching providers from the dashboard\n\nThe fastest way is via the web UI. Start the server (`python backend/server.py`) and open `http://localhost:8000`. Click **Settings** in the top-right corner to open the LLM configuration dialog:\n\n- Pick a **Provider** preset:\n - **Anthropic (Claude)** — official Anthropic endpoint, no base URL needed\n - **Custom (Anthropic-compatible)** — point at any Anthropic-protocol proxy and supply a model id\n - **OpenAI / DeepSeek / Moonshot / 智谱 GLM / Ollama / Custom (OpenAI-compatible)** — covers the OpenAI wire format\n- The dialog auto-fills a sensible **Base URL** and **Model** for each preset; you can override either with your own value\n- Paste your **API Key** (stored server-side only; never echoed back to the browser)\n- Adjust **Temperature** if you want\n\nThe provider is persisted at `data/llm_config.json` and is hot-reloaded on every review job, so the next PR you submit uses the new provider.\n\n### Switching providers via environment variables\n\nIf you'd rather configure at deploy time, the same fields can be set as env vars. The dashboard `data/llm_config.json` (if it exists) takes precedence over the env.\n\n| Env var | Description |\n|---------|-------------|\n| `LLM_PROVIDER` | `anthropic` or `openai-compatible` |\n| `LLM_API_KEY` | Provider API key. `ANTHROPIC_API_KEY` is still respected as a fallback for `anthropic`. |\n| `LLM_MODEL` | Model id — free-form. `claude-sonnet-4-20250514`, `claude-3-opus-20240229`, `gpt-4o-mini`, `deepseek-chat`, `llama3.1`, fine-tunes, custom proxy ids, etc. |\n| `LLM_BASE_URL` | Optional for `anthropic` (omit to use the official endpoint), required for `openai-compatible`. e.g. `https://api.openai.com/v1`, `http://localhost:11434/v1`, `https://your-litellm-proxy.example.com` |\n| `LLM_TEMPERATURE` | `0.0` – `2.0` (default `0.2`) |\n\n### Example: DeepSeek via env\n\n```bash\nexport LLM_PROVIDER=openai-compatible\nexport LLM_API_KEY=sk-...\nexport LLM_BASE_URL=https://api.deepseek.com/v1\nexport LLM_MODEL=deepseek-chat\n```\n\n### Example: Local Ollama\n\n```bash\nexport LLM_PROVIDER=openai-compatible\nexport LLM_BASE_URL=http://localhost:11434/v1\nexport LLM_MODEL=llama3.1\n# Ollama ignores the key, but the field must be non-empty to be sent\nexport LLM_API_KEY=ollama\n```\n\n### Example: Anthropic-compatible proxy (LiteLLM, gateway, …)\n\n```bash\nexport LLM_PROVIDER=anthropic\nexport LLM_API_KEY=sk-anything-the-proxy-expects\nexport LLM_BASE_URL=https://your-litellm-proxy.example.com\n# Any model id your proxy exposes — LiteLLM accepts Anthropic model names,\n# OpenAI model names, or any custom routing key\nexport LLM_MODEL=claude-3-5-sonnet-20241022\n```\n\nThe agent will speak the Anthropic Messages protocol but talk to your proxy instead of `api.anthropic.com`. Useful for centralized key management, audit logging, on-prem deployments, or routing through Cloudflare / VPC.\n\n### How requests are dispatched\n\n| Provider type | Endpoint called | Auth header |\n|---------------|-----------------|-------------|\n| `anthropic` (no `base_url`) | Anthropic SDK → `https://api.anthropic.com` | handled by SDK |\n| `anthropic` (with `base_url`) | Anthropic SDK → `{base_url}` | handled by SDK |\n| `openai-compatible` | `POST {base_url}/chat/completions` | `Authorization: Bearer <key>` |\n\nReview output structure is identical across providers — switching providers does not change the GitHub comment format, the score, or the issue categories the agent reports.\n\n## How Multi-Turn Reasoning Works\n\nThe agent uses 3 sequential Claude API calls per review, each building on prior context:\n\n| Turn | Focus | Approach |\n|------|-------|----------|\n| 1 | Bugs & Security | Deep scan: logic errors, null refs, injection risks, auth flaws |\n| 2 | Performance & Quality | O(n^2) detection, N+1 queries, naming, complexity, test gaps |\n| 3 | Structured Report | Synthesize all findings into final JSON review object |\n\n## Review Output Structure\n\n```json\n{\n \"summary\": \"High-level assessment\",\n \"severity\": \"critical|high|medium|low\",\n \"overall_score\": 0-100,\n \"approve\": true|false,\n \"bugs\": [{\"line\": \"file.py:42\", \"description\": \"...\", \"suggestion\": \"...\"}],\n \"security\": [...],\n \"performance\": [...],\n \"quality\": [...],\n \"positives\": [\"Good error handling in X\", ...]\n}\n```\n\n## Configuration Reference\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `ANTHROPIC_API_KEY` | (required) | Anthropic API key (fallback for `LLM_API_KEY` when provider is `anthropic`) |\n| `LLM_PROVIDER` | `anthropic` | `anthropic` or `openai-compatible` |\n| `LLM_API_KEY` | — | Provider API key. Overrides `ANTHROPIC_API_KEY` when set. |\n| `LLM_MODEL` | `claude-sonnet-4-20250514` | Model id sent to the provider |\n| `LLM_BASE_URL` | — | Required for `openai-compatible` providers |\n| `LLM_TEMPERATURE` | `0.2` | Sampling temperature (0.0 – 2.0) |\n| `GITHUB_TOKEN` | (required) | GitHub PAT with `repo` scope |\n| `GITHUB_WEBHOOK_SECRET` | (required for webhooks) | HMAC-SHA256 webhook verification |\n| `API_KEY` | — | Optional API key for endpoint authentication |\n| `CORS_ORIGINS` | `http://localhost:8000,http://127.0.0.1:8000` | Comma-separated allowed CORS origins |\n| `CLAUDE_MODEL` | `claude-sonnet-4-20250514` | Legacy alias for `LLM_MODEL` |\n| `PR_REVIEW_MODE` | `full` | `full` / `diff-only` / `auto` |\n| `PR_REVIEW_MAX_FILES` | `20` | Max files to include in context |\n| `PR_REVIEW_MAX_FILE_CHARS` | `5000` | Max chars per file content |\n| `PR_REVIEW_MAX_CONTEXT_CHARS` | `80000` | Total context size cap |\n| `PR_REVIEW_FULL_CONTENT_THRESHOLD` | `500` | Max additions to fetch full content |\n| `PR_REVIEW_CONTEXT_ENABLED` | `true` | Load CONTEXT.md from PR branch |\n| `TOKEN_BUDGET_WEEKLY` | `2000000` | Weekly token budget for alerts |\n| `TOKEN_BUDGET_ALERT_THRESHOLD` | `0.8` | Alert at 80% budget consumed |\n| `LOG_LEVEL` | `INFO` | Logging level |\n| `REDIS_URL` | — | Redis connection (required for production) |\n| `WORKER_CONCURRENCY` | `10` | Max concurrent review tasks per worker |\n| `MAX_QUEUE_SIZE` | `100` | Max pending reviews in queue |\n| `ENVIRONMENT` | `production` | Environment identifier for logging |\n| `SENTRY_DSN` | — | Optional Sentry error tracking DSN |\n\n## API Endpoints\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `POST` | `/api/review` | Start a new review job |\n| `GET` | `/api/jobs` | List all jobs (filter: `?repo=`, `?days=`) |\n| `GET` | `/api/jobs/{id}` | Get job status & result |\n| `GET` | `/api/stats` | Aggregate statistics (filter: `?days=`) |\n| `GET` | `/api/config/llm` | Read the current LLM provider config (api_key is masked) |\n| `POST` | `/api/config/llm` | Persist the LLM provider config; leave `api_key` blank to keep the existing key |\n| `GET` | `/api/metrics` | Combined quality + throughput + tokens |\n| `GET` | `/api/metrics/tokens` | Weekly budget, daily breakdown, per-review stats |\n| `GET` | `/api/metrics/quality` | Score distribution, severity, approval rate |\n| `GET` | `/api/metrics/throughput` | Reviews/day, files reviewed |\n| `POST` | `/webhook/github` | GitHub webhook handler |\n| `GET` | `/api/health` | Health check (Redis, queue status) |\n| `GET` | `/api/health/ready` | Kubernetes readiness probe |\n| `GET` | `/api/health/live` | Kubernetes liveness probe |\n| `GET` | `/metrics` | Prometheus metrics endpoint |\n\n## Token Usage\n\nTypical per-PR consumption:\n- **Small PR** (< 5 files): ~15K–30K tokens\n- **Medium PR** (5–20 files): ~40K–80K tokens\n- **Large PR** (20+ files): ~80K–150K tokens\n\nUse `PR_REVIEW_MODE=diff-only` to cut token usage ~50% for large PRs.\n\n## Production Deployment\n\n### Job Store\n\nThree backends, auto-selected:\n\n| Backend | Trigger | Persistence |\n|---------|---------|-------------|\n| `InMemoryJobStore` | (fallback) | Lost on restart |\n| `FileJobStore` | Default | JSONL file at `data/jobs.jsonl` |\n| `RedisJobStore` | Set `REDIS_URL` | Redis, with 7-day TTL, status indexing |\n\n### Task Queue (arq + Redis)\n\nFor production workloads, the system uses an async task queue:\n\n```bash\n# Start the API server\npython server.py\n\n# Start worker(s) in separate processes\npython scripts/start_worker.py\n```\n\nFeatures:\n- Async task processing with automatic retries (3 attempts)\n- Request deduplication prevents duplicate reviews\n- Result caching (1 hour TTL based on PR head SHA)\n- Graceful shutdown with active task tracking\n\n### Process Manager\n\n```bash\n# Single worker (fine for < 100 PRs/week)\npython server.py\n\n# Multi-worker production with gunicorn\ngunicorn server:app -w 4 -k uvicorn.workers.UvicornWorker\n```\n\n### Token Budget Monitoring\n\nSet `TOKEN_BUDGET_WEEKLY` and check the dashboard for real-time budget tracking.\nThe stats bar shows a color-coded progress bar: green (< 50%), yellow (50–80%), red (> 80%).\n\n## Security\n\n### API Authentication\n\nSet `API_KEY` environment variable to enable bearer token authentication on all `/api/*` endpoints. When set, requests must include:\n\n```\nAuthorization: Bearer your-api-key-here\n```\n\n### Webhook Security\n\n`GITHUB_WEBHOOK_SECRET` is **required** for webhook endpoints. Webhooks without a valid HMAC-SHA256 signature will be rejected. Generate a secret with:\n\n```bash\nopenssl rand -hex 32\n```\n\n### CORS Configuration\n\nConfigure allowed origins with `CORS_ORIGINS` (comma-separated). Defaults to localhost only.\n\n## GitHub Token Permissions\n\nMinimum required scopes: `repo` (private repos) or `public_repo` (public). This allows reading PR diffs and posting review comments.\n\n## Project-Specific Review Rules\n\nAdd `.pr-review-rules.md` to your repository root (or `.github/pr-review-rules.md`). The agent will inject these rules into the review prompt. Example:\n\n```markdown\n# PR Review Rules\n- All API endpoints must validate input with Pydantic models\n- Database queries must use parameterized queries\n- All new functions must have type hints\n- No console.log or print() in production code\n```\n\nAlso supported: `CONTEXT.md` / `.pr-review-context.md` / `CONTRIBUTING.md` for general project context.\n\n## Changelog\n\n### v1.3.0 - Multi-Provider LLM Support\n\n**New Features:**\n- Dashboard **Settings** dialog to switch LLM provider, model, base URL, API key, and temperature without restarting the server\n- Provider presets: Anthropic, OpenAI, DeepSeek, Moonshot (Kimi), Zhipu GLM, Ollama, Custom OpenAI-compatible, **Custom Anthropic-compatible** (LiteLLM, gateways, etc.)\n- Custom model support: the **Model** field is free-form on both wire formats, so any model id works (claude-3-opus-*, claude-3-haiku-*, gpt-4o-*, deepseek-*, llama*, fine-tunes, proxy routing keys, …)\n- Anthropic provider now accepts an optional **Base URL**, so you can route Anthropic-protocol traffic through a proxy while keeping the same review output\n- Header status indicator reflects the active provider and shows a warning dot when no API key is set\n- Added `LLM_PROVIDER`, `LLM_API_KEY`, `LLM_MODEL`, `LLM_BASE_URL`, `LLM_TEMPERATURE` environment variables (dashboard `data/llm_config.json` still wins when present)\n\n**Notes:**\n- No breaking changes. Existing `ANTHROPIC_API_KEY` + `CLAUDE_MODEL` deployments continue to work without any edit.\n\n### v1.2.0 - Production Readiness\n\n**New Features:**\n- Async task queue with arq + Redis for concurrent processing\n- Request deduplication to prevent duplicate reviews\n- Result caching with SHA-based keys (1 hour TTL)\n- Prometheus metrics endpoint (`/metrics`)\n- Kubernetes health probes (`/api/health/ready`, `/api/health/live`)\n- Graceful shutdown with active task tracking\n- Thread-safe singleton pattern for all managers\n- Comprehensive unit tests for core modules\n\n**Bug Fixes:**\n- Fixed deprecated `datetime.utcnow()` (Python 3.12+ compatible)\n- Fixed frontend polling memory leak using AbortController\n- Fixed asyncio event loop handling with `asyncio.to_thread()`\n- Enhanced RedisJobStore with status indexing for faster queries\n\n**Infrastructure:**\n- Added `backend/tasks.py` - arq task definitions\n- Added `backend/dedup.py` - request deduplication\n- Added `backend/cache.py` - result caching\n- Added `backend/shutdown.py` - graceful shutdown\n- Added `backend/metrics_middleware.py` - Prometheus middleware\n- Added `backend/singleton.py` - thread-safe singleton decorator\n- Added `scripts/start_worker.py` - Worker startup script\n- Added comprehensive test suite in `tests/`\n\n### v1.1.0 - Security & Reliability Improvements\n\n**Security Fixes:**\n- Fixed XSS vulnerability in frontend dashboard\n- Added optional API key authentication (`API_KEY` env var)\n- Webhook signature verification now required (no more bypass)\n- CORS origins now configurable (defaults to localhost only)\n\n**Bug Fixes:**\n- Fixed job ID collision when submitting multiple reviews rapidly\n- Fixed KeyError crash in stats endpoint with incomplete data\n- Fixed fragile JSON parsing for Claude responses\n- Fixed metrics dead code in throughput calculation\n- Fixed token tracker week start normalization\n- Updated deprecated `datetime.utcnow()` calls\n- Fixed GitHub Actions workflow to install all dependencies\n\n**New Features:**\n- Added `CORS_ORIGINS` configuration\n- Added `API_KEY` for endpoint authentication\n- Added `backend/__init__.py` for proper module imports\n"}, "6bc23a0e70c52ae7a1db74230b7dc53dfd3872a8": {"t": 1785763653.0626216, "n": 10575, "h": "0715bed0ee4f0583", "c": "# PR Review Agent\n\nAI-powered pull request code review system using Claude API with multi-turn reasoning.\nDesigned for teams handling 50+ PRs/week with ~2M tokens weekly budget.\n\n## Architecture\n\n```\n┌──────────────────────────────────────────────────────────────────────┐\n│ PR Review Agent │\n│ │\n│ GitHub PR ──► Agent ──► Turn 1: Bug & Security Scan │\n│ │──► Turn 2: Performance & Quality │\n│ │──► Turn 3: Structured JSON Report │\n│ └──► Post Comment to GitHub PR │\n│ │\n│ FastAPI Server ──► REST API ──► Dashboard UI │\n│ GitHub Webhook ──► Auto-trigger on PR open/update/label │\n│ Task Queue (arq) ──► Async Processing ──► Worker Pool │\n│ Job Store ──► In-Memory / File (JSONL) / Redis │\n│ Monitoring ──► Prometheus Metrics ──► Grafana │\n└──────────────────────────────────────────────────────────────────────┘\n```\n\n## Quick Start\n\n### 1. Clone & Install\n\n```bash\ngit clone <this-repo>\ncd pr-review-agent\npip install -r requirements.txt\n```\n\n### 2. Configure Environment\n\n```bash\ncp config/.env.example config/.env\n# Edit config/.env with your API keys\n```\n\nRequired:\n- `ANTHROPIC_API_KEY` — from [console.anthropic.com](https://console.anthropic.com)\n- `GITHUB_TOKEN` — GitHub Personal Access Token with `repo` scope\n\n### 3a. CLI Usage (Quick)\n\n```bash\ncd backend\n# Load env vars\nexport $(cat ../config/.env | xargs) # Linux/Mac\n# Or on Windows: use set or a .env loader\n\n# Review a PR (posts comment to GitHub)\npython cli.py --repo owner/repo-name --pr 42\n\n# Dry run (no GitHub comment)\npython cli.py --repo owner/repo-name --pr 42 --no-comment\n\n# Save full JSON result\npython cli.py --repo owner/repo-name --pr 42 --output result.json\n```\n\n### 3b. Web Server + Dashboard\n\n```bash\ncd backend\nexport $(cat ../config/.env | xargs)\npython server.py\n\n# Open http://localhost:8000\n```\n\n### 3c. Worker (Production)\n\nFor production deployments with async task queue:\n\n```bash\n# Start the arq worker\npython scripts/start_worker.py\n\n# Worker reads REDIS_URL and WORKER_CONCURRENCY from environment\n```\n\n### 3c. GitHub Actions (Automated)\n\nCopy `.github/workflows/pr-review.yml` to your repository. Add these secrets:\n- `ANTHROPIC_API_KEY`\n- `GITHUB_TOKEN`\n\nEvery PR open/sync/reopen triggers an automatic review.\n\n## How Multi-Turn Reasoning Works\n\nThe agent uses 3 sequential Claude API calls per review, each building on prior context:\n\n| Turn | Focus | Approach |\n|------|-------|----------|\n| 1 | Bugs & Security | Deep scan: logic errors, null refs, injection risks, auth flaws |\n| 2 | Performance & Quality | O(n^2) detection, N+1 queries, naming, complexity, test gaps |\n| 3 | Structured Report | Synthesize all findings into final JSON review object |\n\n## Review Output Structure\n\n```json\n{\n \"summary\": \"High-level assessment\",\n \"severity\": \"critical|high|medium|low\",\n \"overall_score\": 0-100,\n \"approve\": true|false,\n \"bugs\": [{\"line\": \"file.py:42\", \"description\": \"...\", \"suggestion\": \"...\"}],\n \"security\": [...],\n \"performance\": [...],\n \"quality\": [...],\n \"positives\": [\"Good error handling in X\", ...]\n}\n```\n\n## Configuration Reference\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `ANTHROPIC_API_KEY` | (required) | Anthropic API key |\n| `GITHUB_TOKEN` | (required) | GitHub PAT with `repo` scope |\n| `GITHUB_WEBHOOK_SECRET` | (required for webhooks) | HMAC-SHA256 webhook verification |\n| `API_KEY` | — | Optional API key for endpoint authentication |\n| `CORS_ORIGINS` | `http://localhost:8000,http://127.0.0.1:8000` | Comma-separated allowed CORS origins |\n| `CLAUDE_MODEL` | `claude-sonnet-4-20250514` | Claude model to use |\n| `PR_REVIEW_MODE` | `full` | `full` / `diff-only` / `auto` |\n| `PR_REVIEW_MAX_FILES` | `20` | Max files to include in context |\n| `PR_REVIEW_MAX_FILE_CHARS` | `5000` | Max chars per file content |\n| `PR_REVIEW_MAX_CONTEXT_CHARS` | `80000` | Total context size cap |\n| `PR_REVIEW_FULL_CONTENT_THRESHOLD` | `500` | Max additions to fetch full content |\n| `PR_REVIEW_CONTEXT_ENABLED` | `true` | Load CONTEXT.md from PR branch |\n| `TOKEN_BUDGET_WEEKLY` | `2000000` | Weekly token budget for alerts |\n| `TOKEN_BUDGET_ALERT_THRESHOLD` | `0.8` | Alert at 80% budget consumed |\n| `LOG_LEVEL` | `INFO` | Logging level |\n| `REDIS_URL` | — | Redis connection (required for production) |\n| `WORKER_CONCURRENCY` | `10` | Max concurrent review tasks per worker |\n| `MAX_QUEUE_SIZE` | `100` | Max pending reviews in queue |\n| `ENVIRONMENT` | `production` | Environment identifier for logging |\n| `SENTRY_DSN` | — | Optional Sentry error tracking DSN |\n\n## API Endpoints\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `POST` | `/api/review` | Start a new review job |\n| `GET` | `/api/jobs` | List all jobs (filter: `?repo=`, `?days=`) |\n| `GET` | `/api/jobs/{id}` | Get job status & result |\n| `GET` | `/api/stats` | Aggregate statistics (filter: `?days=`) |\n| `GET` | `/api/metrics` | Combined quality + throughput + tokens |\n| `GET` | `/api/metrics/tokens` | Weekly budget, daily breakdown, per-review stats |\n| `GET` | `/api/metrics/quality` | Score distribution, severity, approval rate |\n| `GET` | `/api/metrics/throughput` | Reviews/day, files reviewed |\n| `POST` | `/webhook/github` | GitHub webhook handler |\n| `GET` | `/api/health` | Health check (Redis, queue status) |\n| `GET` | `/api/health/ready` | Kubernetes readiness probe |\n| `GET` | `/api/health/live` | Kubernetes liveness probe |\n| `GET` | `/metrics` | Prometheus metrics endpoint |\n\n## Token Usage\n\nTypical per-PR consumption:\n- **Small PR** (< 5 files): ~15K–30K tokens\n- **Medium PR** (5–20 files): ~40K–80K tokens\n- **Large PR** (20+ files): ~80K–150K tokens\n\nUse `PR_REVIEW_MODE=diff-only` to cut token usage ~50% for large PRs.\n\n## Production Deployment\n\n### Job Store\n\nThree backends, auto-selected:\n\n| Backend | Trigger | Persistence |\n|---------|---------|-------------|\n| `InMemoryJobStore` | (fallback) | Lost on restart |\n| `FileJobStore` | Default | JSONL file at `data/jobs.jsonl` |\n| `RedisJobStore` | Set `REDIS_URL` | Redis, with 7-day TTL, status indexing |\n\n### Task Queue (arq + Redis)\n\nFor production workloads, the system uses an async task queue:\n\n```bash\n# Start the API server\npython server.py\n\n# Start worker(s) in separate processes\npython scripts/start_worker.py\n```\n\nFeatures:\n- Async task processing with automatic retries (3 attempts)\n- Request deduplication prevents duplicate reviews\n- Result caching (1 hour TTL based on PR head SHA)\n- Graceful shutdown with active task tracking\n\n### Process Manager\n\n```bash\n# Single worker (fine for < 100 PRs/week)\npython server.py\n\n# Multi-worker production with gunicorn\ngunicorn server:app -w 4 -k uvicorn.workers.UvicornWorker\n```\n\n### Token Budget Monitoring\n\nSet `TOKEN_BUDGET_WEEKLY` and check the dashboard for real-time budget tracking.\nThe stats bar shows a color-coded progress bar: green (< 50%), yellow (50–80%), red (> 80%).\n\n## Security\n\n### API Authentication\n\nSet `API_KEY` environment variable to enable bearer token authentication on all `/api/*` endpoints. When set, requests must include:\n\n```\nAuthorization: Bearer your-api-key-here\n```\n\n### Webhook Security\n\n`GITHUB_WEBHOOK_SECRET` is **required** for webhook endpoints. Webhooks without a valid HMAC-SHA256 signature will be rejected. Generate a secret with:\n\n```bash\nopenssl rand -hex 32\n```\n\n### CORS Configuration\n\nConfigure allowed origins with `CORS_ORIGINS` (comma-separated). Defaults to localhost only.\n\n## GitHub Token Permissions\n\nMinimum required scopes: `repo` (private repos) or `public_repo` (public). This allows reading PR diffs and posting review comments.\n\n## Project-Specific Review Rules\n\nAdd `.pr-review-rules.md` to your repository root (or `.github/pr-review-rules.md`). The agent will inject these rules into the review prompt. Example:\n\n```markdown\n# PR Review Rules\n- All API endpoints must validate input with Pydantic models\n- Database queries must use parameterized queries\n- All new functions must have type hints\n- No console.log or print() in production code\n```\n\nAlso supported: `CONTEXT.md` / `.pr-review-context.md` / `CONTRIBUTING.md` for general project context.\n\n## Changelog\n\n### v1.2.0 - Production Readiness\n\n**New Features:**\n- Async task queue with arq + Redis for concurrent processing\n- Request deduplication to prevent duplicate reviews\n- Result caching with SHA-based keys (1 hour TTL)\n- Prometheus metrics endpoint (`/metrics`)\n- Kubernetes health probes (`/api/health/ready`, `/api/health/live`)\n- Graceful shutdown with active task tracking\n- Thread-safe singleton pattern for all managers\n- Comprehensive unit tests for core modules\n\n**Bug Fixes:**\n- Fixed deprecated `datetime.utcnow()` (Python 3.12+ compatible)\n- Fixed frontend polling memory leak using AbortController\n- Fixed asyncio event loop handling with `asyncio.to_thread()`\n- Enhanced RedisJobStore with status indexing for faster queries\n\n**Infrastructure:**\n- Added `backend/tasks.py` - arq task definitions\n- Added `backend/dedup.py` - request deduplication\n- Added `backend/cache.py` - result caching\n- Added `backend/shutdown.py` - graceful shutdown\n- Added `backend/metrics_middleware.py` - Prometheus middleware\n- Added `backend/singleton.py` - thread-safe singleton decorator\n- Added `scripts/start_worker.py` - Worker startup script\n- Added comprehensive test suite in `tests/`\n\n### v1.1.0 - Security & Reliability Improvements\n\n**Security Fixes:**\n- Fixed XSS vulnerability in frontend dashboard\n- Added optional API key authentication (`API_KEY` env var)\n- Webhook signature verification now required (no more bypass)\n- CORS origins now configurable (defaults to localhost only)\n\n**Bug Fixes:**\n- Fixed job ID collision when submitting multiple reviews rapidly\n- Fixed KeyError crash in stats endpoint with incomplete data\n- Fixed fragile JSON parsing for Claude responses\n- Fixed metrics dead code in throughput calculation\n- Fixed token tracker week start normalization\n- Updated deprecated `datetime.utcnow()` calls\n- Fixed GitHub Actions workflow to install all dependencies\n\n**New Features:**\n- Added `CORS_ORIGINS` configuration\n- Added `API_KEY` for endpoint authentication\n- Added `backend/__init__.py` for proper module imports\n"}, "8e4a1790c9276492958c343a14fdc03ad29a3d3b": {"t": 1785763654.5584946, "n": 7956, "h": "c73e4ad9f3dd3b64", "c": "# PR Review Agent\n\nAI-powered pull request code review system using Claude API with multi-turn reasoning.\nDesigned for teams handling 50+ PRs/week with ~2M tokens weekly budget.\n\n## Architecture\n\n```\n┌──────────────────────────────────────────────────────────┐\n│ PR Review Agent │\n│ │\n│ GitHub PR ──► Agent ──► Turn 1: Bug & Security Scan │\n│ │──► Turn 2: Performance & Quality │\n│ │──► Turn 3: Structured JSON Report │\n│ └──► Post Comment to GitHub PR │\n│ │\n│ FastAPI Server ──► REST API ──► Dashboard UI │\n│ GitHub Webhook ──► Auto-trigger on PR open/update/label │\n│ Job Store ──► In-Memory / File (JSONL) / Redis │\n└──────────────────────────────────────────────────────────┘\n```\n\n## Quick Start\n\n### 1. Clone & Install\n\n```bash\ngit clone <this-repo>\ncd pr-review-agent\npip install -r requirements.txt\n```\n\n### 2. Configure Environment\n\n```bash\ncp config/.env.example config/.env\n# Edit config/.env with your API keys\n```\n\nRequired:\n- `ANTHROPIC_API_KEY` — from [console.anthropic.com](https://console.anthropic.com)\n- `GITHUB_TOKEN` — GitHub Personal Access Token with `repo` scope\n\n### 3a. CLI Usage (Quick)\n\n```bash\ncd backend\n# Load env vars\nexport $(cat ../config/.env | xargs) # Linux/Mac\n# Or on Windows: use set or a .env loader\n\n# Review a PR (posts comment to GitHub)\npython cli.py --repo owner/repo-name --pr 42\n\n# Dry run (no GitHub comment)\npython cli.py --repo owner/repo-name --pr 42 --no-comment\n\n# Save full JSON result\npython cli.py --repo owner/repo-name --pr 42 --output result.json\n```\n\n### 3b. Web Server + Dashboard\n\n```bash\ncd backend\nexport $(cat ../config/.env | xargs)\npython server.py\n\n# Open http://localhost:8000\n```\n\n### 3c. GitHub Actions (Automated)\n\nCopy `.github/workflows/pr-review.yml` to your repository. Add these secrets:\n- `ANTHROPIC_API_KEY`\n- `GITHUB_TOKEN`\n\nEvery PR open/sync/reopen triggers an automatic review.\n\n## How Multi-Turn Reasoning Works\n\nThe agent uses 3 sequential Claude API calls per review, each building on prior context:\n\n| Turn | Focus | Approach |\n|------|-------|----------|\n| 1 | Bugs & Security | Deep scan: logic errors, null refs, injection risks, auth flaws |\n| 2 | Performance & Quality | O(n^2) detection, N+1 queries, naming, complexity, test gaps |\n| 3 | Structured Report | Synthesize all findings into final JSON review object |\n\n## Review Output Structure\n\n```json\n{\n \"summary\": \"High-level assessment\",\n \"severity\": \"critical|high|medium|low\",\n \"overall_score\": 0-100,\n \"approve\": true|false,\n \"bugs\": [{\"line\": \"file.py:42\", \"description\": \"...\", \"suggestion\": \"...\"}],\n \"security\": [...],\n \"performance\": [...],\n \"quality\": [...],\n \"positives\": [\"Good error handling in X\", ...]\n}\n```\n\n## Configuration Reference\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `ANTHROPIC_API_KEY` | (required) | Anthropic API key |\n| `GITHUB_TOKEN` | (required) | GitHub PAT with `repo` scope |\n| `GITHUB_WEBHOOK_SECRET` | (required for webhooks) | HMAC-SHA256 webhook verification |\n| `API_KEY` | — | Optional API key for endpoint authentication |\n| `CORS_ORIGINS` | `http://localhost:8000,http://127.0.0.1:8000` | Comma-separated allowed CORS origins |\n| `CLAUDE_MODEL` | `claude-sonnet-4-20250514` | Claude model to use |\n| `PR_REVIEW_MODE` | `full` | `full` / `diff-only` / `auto` |\n| `PR_REVIEW_MAX_FILES` | `20` | Max files to include in context |\n| `PR_REVIEW_MAX_FILE_CHARS` | `5000` | Max chars per file content |\n| `PR_REVIEW_MAX_CONTEXT_CHARS` | `80000` | Total context size cap |\n| `PR_REVIEW_FULL_CONTENT_THRESHOLD` | `500` | Max additions to fetch full content |\n| `PR_REVIEW_CONTEXT_ENABLED` | `true` | Load CONTEXT.md from PR branch |\n| `TOKEN_BUDGET_WEEKLY` | `2000000` | Weekly token budget for alerts |\n| `TOKEN_BUDGET_ALERT_THRESHOLD` | `0.8` | Alert at 80% budget consumed |\n| `LOG_LEVEL` | `INFO` | Logging level |\n| `REDIS_URL` | — | Redis connection (optional, for prod) |\n\n## API Endpoints\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `POST` | `/api/review` | Start a new review job |\n| `GET` | `/api/jobs` | List all jobs (filter: `?repo=`, `?days=`) |\n| `GET` | `/api/jobs/{id}` | Get job status & result |\n| `GET` | `/api/stats` | Aggregate statistics (filter: `?days=`) |\n| `GET` | `/api/metrics` | Combined quality + throughput + tokens |\n| `GET` | `/api/metrics/tokens` | Weekly budget, daily breakdown, per-review stats |\n| `GET` | `/api/metrics/quality` | Score distribution, severity, approval rate |\n| `GET` | `/api/metrics/throughput` | Reviews/day, files reviewed |\n| `POST` | `/webhook/github` | GitHub webhook handler |\n| `GET` | `/api/health` | Health check |\n\n## Token Usage\n\nTypical per-PR consumption:\n- **Small PR** (< 5 files): ~15K–30K tokens\n- **Medium PR** (5–20 files): ~40K–80K tokens\n- **Large PR** (20+ files): ~80K–150K tokens\n\nUse `PR_REVIEW_MODE=diff-only` to cut token usage ~50% for large PRs.\n\n## Production Deployment\n\n### Job Store\n\nThree backends, auto-selected:\n\n| Backend | Trigger | Persistence |\n|---------|---------|-------------|\n| `InMemoryJobStore` | (fallback) | Lost on restart |\n| `FileJobStore` | Default | JSONL file at `data/jobs.jsonl` |\n| `RedisJobStore` | Set `REDIS_URL` | Redis, with 7-day TTL |\n\n### Process Manager\n\n```bash\n# Single worker (fine for < 100 PRs/week)\npython server.py\n\n# Multi-worker production\ngunicorn server:app -w 4 -k uvicorn.workers.UvicornWorker\n```\n\n### Token Budget Monitoring\n\nSet `TOKEN_BUDGET_WEEKLY` and check the dashboard for real-time budget tracking.\nThe stats bar shows a color-coded progress bar: green (< 50%), yellow (50–80%), red (> 80%).\n\n## Security\n\n### API Authentication\n\nSet `API_KEY` environment variable to enable bearer token authentication on all `/api/*` endpoints. When set, requests must include:\n\n```\nAuthorization: Bearer your-api-key-here\n```\n\n### Webhook Security\n\n`GITHUB_WEBHOOK_SECRET` is **required** for webhook endpoints. Webhooks without a valid HMAC-SHA256 signature will be rejected. Generate a secret with:\n\n```bash\nopenssl rand -hex 32\n```\n\n### CORS Configuration\n\nConfigure allowed origins with `CORS_ORIGINS` (comma-separated). Defaults to localhost only.\n\n## GitHub Token Permissions\n\nMinimum required scopes: `repo` (private repos) or `public_repo` (public). This allows reading PR diffs and posting review comments.\n\n## Project-Specific Review Rules\n\nAdd `.pr-review-rules.md` to your repository root (or `.github/pr-review-rules.md`). The agent will inject these rules into the review prompt. Example:\n\n```markdown\n# PR Review Rules\n- All API endpoints must validate input with Pydantic models\n- Database queries must use parameterized queries\n- All new functions must have type hints\n- No console.log or print() in production code\n```\n\nAlso supported: `CONTEXT.md` / `.pr-review-context.md` / `CONTRIBUTING.md` for general project context.\n\n## Changelog\n\n### v1.1.0 - Security & Reliability Improvements\n\n**Security Fixes:**\n- Fixed XSS vulnerability in frontend dashboard\n- Added optional API key authentication (`API_KEY` env var)\n- Webhook signature verification now required (no more bypass)\n- CORS origins now configurable (defaults to localhost only)\n\n**Bug Fixes:**\n- Fixed job ID collision when submitting multiple reviews rapidly\n- Fixed KeyError crash in stats endpoint with incomplete data\n- Fixed fragile JSON parsing for Claude responses\n- Fixed metrics dead code in throughput calculation\n- Fixed token tracker week start normalization\n- Updated deprecated `datetime.utcnow()` calls\n- Fixed GitHub Actions workflow to install all dependencies\n\n**New Features:**\n- Added `CORS_ORIGINS` configuration\n- Added `API_KEY` for endpoint authentication\n- Added `backend/__init__.py` for proper module imports\n"}, "c9fb806fc9a1a114e835bed35409452441fed825": {"t": 1785763656.1090593, "n": 6341, "h": "d91793f344a7cfc1", "c": "# PR Review Agent\n\nAI-powered pull request code review system using Claude API with multi-turn reasoning.\nDesigned for teams handling 50+ PRs/week with ~2M tokens weekly budget.\n\n## Architecture\n\n```\n┌──────────────────────────────────────────────────────────┐\n│ PR Review Agent │\n│ │\n│ GitHub PR ──► Agent ──► Turn 1: Bug & Security Scan │\n│ │──► Turn 2: Performance & Quality │\n│ │──► Turn 3: Structured JSON Report │\n│ └──► Post Comment to GitHub PR │\n│ │\n│ FastAPI Server ──► REST API ──► Dashboard UI │\n│ GitHub Webhook ──► Auto-trigger on PR open/update/label │\n│ Job Store ──► In-Memory / File (JSONL) / Redis │\n└──────────────────────────────────────────────────────────┘\n```\n\n## Quick Start\n\n### 1. Clone & Install\n\n```bash\ngit clone <this-repo>\ncd pr-review-agent\npip install -r requirements.txt\n```\n\n### 2. Configure Environment\n\n```bash\ncp config/.env.example config/.env\n# Edit config/.env with your API keys\n```\n\nRequired:\n- `ANTHROPIC_API_KEY` — from [console.anthropic.com](https://console.anthropic.com)\n- `GITHUB_TOKEN` — GitHub Personal Access Token with `repo` scope\n\n### 3a. CLI Usage (Quick)\n\n```bash\ncd backend\n# Load env vars\nexport $(cat ../config/.env | xargs) # Linux/Mac\n# Or on Windows: use set or a .env loader\n\n# Review a PR (posts comment to GitHub)\npython cli.py --repo owner/repo-name --pr 42\n\n# Dry run (no GitHub comment)\npython cli.py --repo owner/repo-name --pr 42 --no-comment\n\n# Save full JSON result\npython cli.py --repo owner/repo-name --pr 42 --output result.json\n```\n\n### 3b. Web Server + Dashboard\n\n```bash\ncd backend\nexport $(cat ../config/.env | xargs)\npython server.py\n\n# Open http://localhost:8000\n```\n\n### 3c. GitHub Actions (Automated)\n\nCopy `.github/workflows/pr-review.yml` to your repository. Add these secrets:\n- `ANTHROPIC_API_KEY`\n- `GITHUB_TOKEN`\n\nEvery PR open/sync/reopen triggers an automatic review.\n\n## How Multi-Turn Reasoning Works\n\nThe agent uses 3 sequential Claude API calls per review, each building on prior context:\n\n| Turn | Focus | Approach |\n|------|-------|----------|\n| 1 | Bugs & Security | Deep scan: logic errors, null refs, injection risks, auth flaws |\n| 2 | Performance & Quality | O(n^2) detection, N+1 queries, naming, complexity, test gaps |\n| 3 | Structured Report | Synthesize all findings into final JSON review object |\n\n## Review Output Structure\n\n```json\n{\n \"summary\": \"High-level assessment\",\n \"severity\": \"critical|high|medium|low\",\n \"overall_score\": 0-100,\n \"approve\": true|false,\n \"bugs\": [{\"line\": \"file.py:42\", \"description\": \"...\", \"suggestion\": \"...\"}],\n \"security\": [...],\n \"performance\": [...],\n \"quality\": [...],\n \"positives\": [\"Good error handling in X\", ...]\n}\n```\n\n## Configuration Reference\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `ANTHROPIC_API_KEY` | (required) | Anthropic API key |\n| `GITHUB_TOKEN` | (required) | GitHub PAT with `repo` scope |\n| `GITHUB_WEBHOOK_SECRET` | — | HMAC-SHA256 webhook verification |\n| `CLAUDE_MODEL` | `claude-sonnet-4-20250514` | Claude model to use |\n| `PR_REVIEW_MODE` | `full` | `full` / `diff-only` / `auto` |\n| `PR_REVIEW_MAX_FILES` | `20` | Max files to include in context |\n| `PR_REVIEW_MAX_FILE_CHARS` | `5000` | Max chars per file content |\n| `PR_REVIEW_MAX_CONTEXT_CHARS` | `80000` | Total context size cap |\n| `PR_REVIEW_FULL_CONTENT_THRESHOLD` | `500` | Max additions to fetch full content |\n| `PR_REVIEW_CONTEXT_ENABLED` | `true` | Load CONTEXT.md from PR branch |\n| `TOKEN_BUDGET_WEEKLY` | `2000000` | Weekly token budget for alerts |\n| `TOKEN_BUDGET_ALERT_THRESHOLD` | `0.8` | Alert at 80% budget consumed |\n| `LOG_LEVEL` | `INFO` | Logging level |\n| `REDIS_URL` | — | Redis connection (optional, for prod) |\n\n## API Endpoints\n\n| Method | Path | Description |\n|--------|------|-------------|\n| `POST` | `/api/review` | Start a new review job |\n| `GET` | `/api/jobs` | List all jobs (filter: `?repo=`, `?days=`) |\n| `GET` | `/api/jobs/{id}` | Get job status & result |\n| `GET` | `/api/stats` | Aggregate statistics (filter: `?days=`) |\n| `GET` | `/api/metrics` | Combined quality + throughput + tokens |\n| `GET` | `/api/metrics/tokens` | Weekly budget, daily breakdown, per-review stats |\n| `GET` | `/api/metrics/quality` | Score distribution, severity, approval rate |\n| `GET` | `/api/metrics/throughput` | Reviews/day, files reviewed |\n| `POST` | `/webhook/github` | GitHub webhook handler |\n| `GET` | `/api/health` | Health check |\n\n## Token Usage\n\nTypical per-PR consumption:\n- **Small PR** (< 5 files): ~15K–30K tokens\n- **Medium PR** (5–20 files): ~40K–80K tokens\n- **Large PR** (20+ files): ~80K–150K tokens\n\nUse `PR_REVIEW_MODE=diff-only` to cut token usage ~50% for large PRs.\n\n## Production Deployment\n\n### Job Store\n\nThree backends, auto-selected:\n\n| Backend | Trigger | Persistence |\n|---------|---------|-------------|\n| `InMemoryJobStore` | (fallback) | Lost on restart |\n| `FileJobStore` | Default | JSONL file at `data/jobs.jsonl` |\n| `RedisJobStore` | Set `REDIS_URL` | Redis, with 7-day TTL |\n\n### Process Manager\n\n```bash\n# Single worker (fine for < 100 PRs/week)\npython server.py\n\n# Multi-worker production\ngunicorn server:app -w 4 -k uvicorn.workers.UvicornWorker\n```\n\n### Token Budget Monitoring\n\nSet `TOKEN_BUDGET_WEEKLY` and check the dashboard for real-time budget tracking.\nThe stats bar shows a color-coded progress bar: green (< 50%), yellow (50–80%), red (> 80%).\n\n## GitHub Token Permissions\n\nMinimum required scopes: `repo` (private repos) or `public_repo` (public). This allows reading PR diffs and posting review comments.\n\n## Project-Specific Review Rules\n\nAdd `.pr-review-rules.md` to your repository root (or `.github/pr-review-rules.md`). The agent will inject these rules into the review prompt. Example:\n\n```markdown\n# PR Review Rules\n- All API endpoints must validate input with Pydantic models\n- Database queries must use parameterized queries\n- All new functions must have type hints\n- No console.log or print() in production code\n```\n\nAlso supported: `CONTEXT.md` / `.pr-review-context.md` / `CONTRIBUTING.md` for general project context.\n"}, "c2c9f2d370d033a8fdb5226625b25d0bb03880ab": {"t": 1785763657.4740846, "n": 3965, "h": "18c0ce650fc2f51e", "c": "# 🤖 PR Review Agent\n\nAI-powered pull request code review system using Claude API with multi-turn reasoning.\n\n## Architecture\n\n```\n┌─────────────────────────────────────────────────────────┐\n│ PR Review Agent │\n│ │\n│ GitHub PR ──► Agent ──► Turn 1: Bug & Security Scan │\n│ │──► Turn 2: Performance & Quality │\n│ │──► Turn 3: Structured JSON Report │\n│ └──► Post Comment to GitHub PR │\n│ │\n│ FastAPI Server ──► REST API ──► React Dashboard UI │\n│ GitHub Webhook ──► Auto-trigger on PR open/update │\n└─────────────────────────────────────────────────────────┘\n```\n\n## Quick Start\n\n### 1. Clone & Install\n```bash\ngit clone <this-repo>\ncd pr-review-agent\npip install -r requirements.txt\n```\n\n### 2. Configure Environment\n```bash\ncp config/.env.example config/.env\n# Edit config/.env with your API keys\n```\n\nRequired:\n- `ANTHROPIC_API_KEY` — from [console.anthropic.com](https://console.anthropic.com)\n- `GITHUB_TOKEN` — GitHub Personal Access Token with `repo` scope\n\n### 3a. CLI Usage (Quick)\n```bash\ncd backend\nexport $(cat ../config/.env | xargs)\n\n# Review a PR (posts comment to GitHub)\npython cli.py --repo owner/repo-name --pr 42\n\n# Dry run (no GitHub comment)\npython cli.py --repo owner/repo-name --pr 42 --no-comment\n\n# Save full JSON result\npython cli.py --repo owner/repo-name --pr 42 --output result.json\n```\n\n### 3b. Web Server + Dashboard\n```bash\ncd backend\nexport $(cat ../config/.env | xargs)\npython server.py\n\n# Open http://localhost:8000\n```\n\n### 3c. GitHub Actions (Automated)\nCopy `.github/workflows/pr-review.yml` to your repository.\n\nAdd secrets in GitHub repo settings:\n- `ANTHROPIC_API_KEY`\n- (GITHUB_TOKEN is provided automatically)\n\nEvery PR open/update will trigger an automatic review.\n\n## How Multi-Turn Reasoning Works\n\nThe agent uses 3 sequential Claude API calls per review:\n\n| Turn | Focus | Approach |\n|------|-------|----------|\n| 1 | Bugs & Security | Deep scan of logic errors, null refs, injection risks, auth flaws |\n| 2 | Performance & Quality | O(n²) algos, N+1 queries, naming, complexity, missing tests |\n| 3 | Structured Report | Synthesize all findings into final JSON review object |\n\nEach turn builds on the previous conversation, enabling deeper chain-of-thought reasoning than a single prompt.\n\n## Review Output Structure\n\n```json\n{\n \"summary\": \"High-level assessment\",\n \"severity\": \"critical|high|medium|low\",\n \"overall_score\": 0-100,\n \"approve\": true|false,\n \"bugs\": [{\"line\": \"file.py:42\", \"description\": \"...\", \"suggestion\": \"...\"}],\n \"security\": [...],\n \"performance\": [...],\n \"quality\": [...],\n \"positives\": [\"Good error handling in X\", ...]\n}\n```\n\n## API Endpoints\n\n| Method | Path | Description |\n|--------|------|-------------|\n| POST | `/api/review` | Start a new review job |\n| GET | `/api/jobs` | List all jobs |\n| GET | `/api/jobs/{id}` | Get job status & result |\n| GET | `/api/stats` | Aggregate statistics |\n| POST | `/webhook/github` | GitHub webhook handler |\n| GET | `/api/health` | Health check |\n\n## Token Usage\n\nTypical usage per PR review:\n- **Small PR** (< 5 files): ~15K–30K tokens\n- **Medium PR** (5–20 files): ~40K–80K tokens \n- **Large PR** (20+ files): ~80K–150K tokens\n\nAt 50 PRs/week, estimated weekly consumption: ~1.5M–3M tokens.\n\n## GitHub Token Permissions\n\nMinimum required scopes:\n- `repo` (for private repos) or `public_repo` (for public)\n- This allows reading PRs and posting comments\n\n## Production Deployment\n\nFor production, replace the in-memory job store with Redis:\n\n```python\n# In server.py, use redis-py:\nimport redis\nr = redis.Redis()\nr.setex(f\"job:{job_id}\", 3600, json.dumps(job_data))\n```\n\nUse a process manager like `gunicorn` with `uvicorn` workers:\n```bash\ngunicorn server:app -w 4 -k uvicorn.workers.UvicornWorker\n```\n"}}}}