AI code review that learns your project — multi-agent orchestration, 17 static-analysis tools, and persistent review memory.
Website · Documentation · Live Dashboard · Install GitHub App
Read this in: English · Español
GHAGGA is a production AI code-review system — not a prompt wrapper. One review engine, four delivery surfaces: a hosted GitHub App, a GitHub Action, a CLI for local pre-push review, and a fully self-hosted Docker deployment.
What makes it different:
- Static analysis runs first. 17 deterministic tools (Semgrep, Trivy, Gitleaks, Ruff, clippy, …) catch known issues before a single LLM token is spent. Findings are injected into the review prompt so the model spends its attention on logic and architecture, not lint.
- It remembers. Past decisions, bugfixes, and patterns persist across reviews (PostgreSQL, SQLite, or Engram) and feed back into future ones — with full-text search, strength decay, and privacy stripping.
- Five orchestration strategies. From a single fast pass to multi-agent consensus voting, chosen per review by the cost/confidence tradeoff you want.
- Forge-agnostic core. The review engine speaks in provider-neutral ports; the CLI posts findings back to GitHub pull requests (
--pr) and GitLab merge requests (--mr), with Gitea modeled in the same abstraction. - No runner infrastructure. Server mode injects an inline GitHub Actions workflow into each target repo and dispatches it — heavy analysis runs on the repo's own free CI minutes, secured with per-dispatch HMAC secrets.
| Production code | ~62,000 lines of strict TypeScript across 8 workspaces |
| Test code | ~73,000 lines — more test code than production code |
| Test suite | 4,500+ test cases in 231 test files (Vitest), plus mutation testing with Stryker |
| Static analysis | 17 tools — 7 always-on, 10 auto-detected by stack |
| Review modes | 5 orchestration strategies (single-pass → multi-agent consensus) |
| Distribution | GitHub App (SaaS) · GitHub Action · npm CLI · self-hosted Docker |
A reusable core owns the review pipeline; thin adapters translate transport and IO. ghagga-core knows nothing about HTTP, dashboard auth, or terminal rendering, and ghagga-forge keeps it from knowing whether it's talking to GitHub, GitLab, or Gitea.
graph TB
subgraph Distribution["Distribution Layer"]
Server["Server<br/>Hono + BullMQ"]
Action["GitHub Action"]
CLI["CLI"]
end
subgraph Worker["Async Worker"]
BullMQ["BullMQ Worker<br/>Review Jobs"]
end
subgraph Inline["Inline Workflow (per target repo)"]
InlineYml[".github/workflows/ghagga.yml<br/>injected by server"]
InlineTools["Static Analysis<br/>on the repo's own runner"]
end
subgraph Core["ghagga-core"]
SA["Static Analysis<br/>17-tool registry"]
Agents["AI Agents<br/>5 review modes"]
Memory["Memory<br/>Search / Persist / Decay / Versioning"]
Scope["Scope<br/>Tree-sitter symbol extraction"]
end
subgraph Forge["ghagga-forge"]
Ports["Forge-agnostic ports<br/>GitHub / GitLab / Gitea"]
end
subgraph DB["ghagga-db"]
PG["PostgreSQL 16<br/>+ tsvector FTS"]
Crypto["AES-256-GCM<br/>Encryption"]
end
Server -- enqueue --> BullMQ
BullMQ --> Core
BullMQ -- "inject + workflow_dispatch" --> InlineYml
InlineYml --> InlineTools
InlineTools -- "HMAC-signed callback" --> Server
Action --> Core
CLI --> Core
Core --> Forge
Core --> DB
Every review follows the same pipeline, regardless of entry point:
flowchart LR
DIFF["diff"] --> VAL["validate"]
VAL --> PARSE["parse & filter"]
PARSE --> STACKS["detect stacks"]
STACKS --> BUDGET["token budget"]
BUDGET --> SA["static analysis + memory search"]
SA --> AGENTS["agent execution"]
AGENTS --> MERGE["merge findings"]
MERGE --> MEM["persist memory"]
MEM --> RESULT["ReviewResult"]
The pipeline degrades gracefully: missing tools, unreachable memory, or an unconfigured LLM never hard-fail a review.
GitHub App (hosted) — install the App, configure your provider chain in the dashboard, open a PR.
GitHub Action:
# .github/workflows/ghagga.yml
name: Code Review
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
pull-requests: write
jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: JNZader/ghagga@v3CLI — review local changes before they hit CI:
npm install -g ghagga
ghagga login # authenticate with GitHub (free AI models)
ghagga review --staged # review staged changes
ghagga review --mode consensus # multi-agent vote
ghagga review --pr 42 # review a GitHub PR and post findings back
ghagga review --mr 42 # review a GitLab merge request and post findings back
ghagga health --top 10 # project health score
ghagga hooks install # pre-commit + commit-msg hooksSelf-hosted — full stack with server, worker, PostgreSQL, and Redis:
git clone https://github.com/JNZader/ghagga.git
cd ghagga
cp .env.example .env
docker compose up -dFull setup guides: Quick Start · GitHub Action · CLI · Configuration
Five strategies with explicit cost/confidence tradeoffs:
| Mode | How it works | Token cost | Best for |
|---|---|---|---|
simple |
Single LLM pass | ~1x | Small PRs, fast feedback |
consensus |
3 stances (advocate / critic / observer) + algorithmic vote | ~3x | High-confidence approval decisions |
fan-out |
5 independent lenses (security, typing, performance, a11y, error handling) merged by severity | ~5x | Broad category coverage, custom lenses |
workflow |
5 specialists in parallel + synthesis step | ~6x | Thorough multi-angle reviews |
diagnostic |
Hypothesis-driven analysis with adaptive follow-up queries | varies | Digging into suspicious changes |
fan-out is the multi-agent workhorse: independent lenses review the same diff in parallel, then findings are merged by severity into one result. Custom lenses can be supplied with --lenses and --lens-dir.
flowchart TD
DIFF["PR diff + memory context"] --> FO["fan-out mode"]
FO --> SEC["Security lens"]
FO --> TYP["Typing lens"]
FO --> PERF["Performance lens"]
FO --> A11Y["a11y lens"]
FO --> ERR["Error-handling lens"]
SEC --> MERGE["Merge by severity"]
TYP --> MERGE
PERF --> MERGE
A11Y --> MERGE
ERR --> MERGE
MERGE --> RESULT["Unified ReviewResult + health score"]
Deterministic checks run before the expensive stochastic layer. All tools are optional and skipped gracefully when missing.
- Always-on (7): Semgrep, Trivy, Gitleaks, ShellCheck, CPD, markdownlint, Lizard
- Auto-detected by stack (10): Ruff + Bandit (Python), golangci-lint (Go), Biome (JS/TS), clippy (Rust), PMD (Java), Psalm (PHP), Hadolint (Docker), zizmor (GitHub Actions), SonarQube (via MCP)
The GitHub Action bundles the 16 tools that run directly on the runner; SonarQube is available in server mode over MCP, for 17 total in the full registry.
In server mode, this layer runs as an inline workflow injected into the target repo — no separate runner repository to provision, no RAM-hungry analysis on the API server. Callbacks are verified with per-dispatch HMAC-SHA256 secrets under a TTL.
The part that makes reviews compound over time:
- Search before review — relevant past observations are injected into prompts as context.
- Persist after review — significant findings are stored as typed observations (
decision,pattern,bugfix,architecture, …) with deduplication. - Strength decay — stale observations fade out of context instead of polluting it forever.
- Versioning — git-like branch / snapshot / merge / rollback over memory state.
- Privacy stripping — 16 redaction patterns (API keys, provider tokens, JWTs, PEM/SSH keys, env secrets, URL-embedded credentials) run before any write.
Backends: PostgreSQL (tsvector + ts_rank) for server mode, SQLite (FTS5 + BM25) for CLI/Action, or Engram over HTTP.
| Control | Implementation |
|---|---|
| Provider API keys | AES-256-GCM encryption at rest, per-installation keys |
| GitHub webhooks | HMAC-SHA256 with constant-time comparison |
| Runner callbacks | Per-dispatch derived HMAC secrets + embedded-timestamp TTL |
| Memory writes | Privacy stripping (16 redaction patterns) |
| Outbound gateway URLs | SSRF guard — IP-range + DNS validation at persist time, re-validated at execution time |
| LLM prompts | Trust boundary — repo content, memory, and prior findings framed and sanitized as untrusted input |
| Job queue | Credentials never enter Redis payloads — workers re-fetch encrypted keys from PostgreSQL |
| Injected workflow | permissions: contents: read, secret masking, output normalization |
| Test coverage | Dedicated security suite: encryption tamper detection, HMAC correctness, no-secret-logging, no-eval, prototype-pollution checks |
Vulnerability reports: see SECURITY.md.
ghagga/
├── packages/
│ ├── core/ # Review engine: agents, 17-tool registry, memory, tree-sitter scoping
│ ├── db/ # Drizzle schema, PostgreSQL queries, AES-256-GCM crypto, migrations
│ ├── forge/ # Forge-agnostic ports & domain types (GitHub / GitLab / Gitea)
│ └── types/ # Shared API contracts
├── apps/
│ ├── server/ # Hono API + BullMQ workers + GitHub App integration
│ ├── action/ # GitHub Action runtime (SQLite memory via @actions/cache)
│ ├── cli/ # npm CLI: review, memory, hooks, health, audit, feedback
│ └── dashboard/ # React 19 SPA: provider chains, review history, memory browser
├── templates/ # Inline static-analysis workflow template
└── docs/ # Documentation site (GitHub Pages)
Published packages: ghagga (CLI), ghagga-core, ghagga-db, and ghagga-forge.
Stack: TypeScript (strict) · Hono · BullMQ + Redis · PostgreSQL 16 + Drizzle · React 19 + Vite + Tailwind 4 · Vitest + Stryker · Biome · pnpm + Turborepo
LLM providers: everything routes through a provider chain with ordered fallback — gateway (any model via mcp-llm-bridge), cli-bridge (local Claude / Gemini / Copilot CLIs), or ollama (local models).
A few decisions worth calling out:
- Core/adapter split. The review engine is transport- and forge-agnostic; server, Action, and CLI are thin IO translators. Adding a delivery mode doesn't touch the pipeline.
- Tests outweigh production code (~73k vs ~62k LOC), with mutation testing (Stryker) guarding core, server, and Action against assertion-free tests.
- v2 was a real rewrite, not a patch: v1's Deno + Node + Python sprawl collapsed into a single-runtime Node monorepo with async orchestration (BullMQ), a 17-tool registry (up from Semgrep-only), and an actually-used memory system.
- Graceful degradation everywhere. Missing static tools, unreachable memory backends, blocked workflow injection — every layer falls back instead of failing the review.
pnpm install
docker compose up postgres redis -d
cp .env.example .env
pnpm --filter ghagga-db db:push
pnpm exec turbo typecheck build testDeep dives live in the documentation site: Architecture · Memory System · API Reference · Database Schema
Contributions are welcome. Start with CONTRIBUTING.md and the Code of Conduct. Security issues go through SECURITY.md, not public issues.
Inspired by Gentleman Guardian Angel (GGA) and Engram by Gentleman Programming.
MIT. See LICENSE.