AI-powered distributed coordination linter for GitLab MRs and GitHub PRs.
Quorum reviews merge requests for coordination anti-patterns that static linters and generic AI reviewers can't catch — missing fencing tokens, incomplete saga compensations, retries without jitter, lost updates, transactional outbox violations, and more. It posts structured findings as comments, generates draft fix PRs for critical issues, and outputs SARIF for GitHub Code Scanning.
"SonarQube doesn't have rules for saga compensation. Semgrep can't reason across service boundaries. CodeRabbit can't search the full repo. Quorum can."
Quorum has found real coordination bugs in real open-source projects across GitHub and GitLab, filed as public issues:
| Project | Language | Platform | Bug found | Rule | Reference |
|---|---|---|---|---|---|
atlanhq/atlas-metastore |
Java | GitHub | AsyncIngestionConsumerService writes to JanusGraph then publishes to Kafka with no outbox — phantom events / lost writes on failure. calculateExponentialBackoff() uses pure delay * 2.0 multiplier, no jitter |
RULE_09 🔴 + RULE_06 🟠 | PR #6699 review |
containerd/nerdbox |
Go | GitHub | waitForShimPipe retries with fixed time.Sleep(retryDelay) — all shims sleep for exactly the same duration and retry simultaneously on Windows pipe failures. PR #218 merged with jitter fix applied after Quorum's comment. |
RULE_06 🟠 | PR #218 (merged) · Issue #219 |
vllm-project/vllm |
Python | GitHub | _load_lora_config retries with interval *= 2 — no jitter, thundering herd when multiple workers load same LoRA adapter |
RULE_06 🟠 | Issue #44245 |
aio-libs/aiokafka |
Python | GitHub | Fixed retry backoff uses retry_backoff_ms with no jitter — thundering herd under leader election. Draft fix PR opened after maintainer confirmed no response on issue. |
RULE_06 🟠 | Issue #1165 · Draft fix PR #1167 |
thelabnyc/django-logpipe |
Python | GitLab | ProvisionedThroughputExceededException retry uses fixed time.sleep(5) — all consumers wake simultaneously under Kinesis throttling |
RULE_06 🟠 | Issue #15 |
Alexandre_Toto/architecture-event-driven-cdc |
Python | GitLab | enable_auto_commit=True in payment Kafka consumer + lost update on balance |
RULE_08 🔴 + RULE_10 🔴 | Issue #1 |
lhyou/fastapi-test |
Python | GitLab | AIOKafkaConsumer with enable_auto_commit=True — offset committed before processing |
RULE_08 🔴 | Issue #1 |
7 independent open-source projects · 3 languages (Java, Go, Python) · 2 platforms · zero false positives across all runs.
Validated on four dedicated benchmark MRs in a purpose-built demo repository, confirming surface detection and Gemini reasoning across 4 additional languages:
| Project | Language | Platform | Bug | Rule | Reference |
|---|---|---|---|---|---|
quorum-hackathon/multi-lang-coordination-demo |
TypeScript | GitLab | kafkajs autoCommit:true — offset committed before eachMessage handler completes |
RULE_08 🔴 | MR !1 |
quorum-hackathon/multi-lang-coordination-demo |
Go | GitLab | time.Sleep(retryDelay) — fixed 2s constant, no jitter, thundering herd on inventory service |
RULE_06 🟠 | MR !2 |
quorum-hackathon/multi-lang-coordination-demo |
Ruby | GitLab | redis.set(key, "locked") — static lock value, no fencing token |
RULE_01 🔴 | MR !3 |
quorum-hackathon/multi-lang-coordination-demo |
Java | GitLab | Thread.sleep(RETRY_DELAY_MS) — fixed 3s constant, no jitter on payment gateway retries |
RULE_06 🟠 | MR !4 |
All 4 review comments posted live. RULE_07 and RULE_11 correctly PASS on the Java MR (catch-block retry ≠ test sleep, re-interrupt is the correct Go idiom).
Quorum was also run (dry-run, no comment posted) on three open MRs in GitLab's own production repositories. All three produced correct PASS verdicts — confirming Quorum does not false-positive on well-written distributed systems code:
| Project | Language | MR | Surfaces triggered | Verdict | Reason |
|---|---|---|---|---|---|
gitlab-org/gitaly |
Go | !8812 | RULE_06, RULE_09, RULE_11 | 🟢 PASS | Retries route to a different peer each attempt via rendezvous hashing — fixed delays don't cause thundering herd |
gitlab-org/gitlab-runner |
Go | !6806 | RULE_02 | 🟢 PASS | context.WithTimeout — not a distributed lock; TTL concern doesn't apply |
gitlab-org/gitlab |
Ruby | !233672 | RULE_10 | 🟢 PASS | Pessimistic FOR UPDATE lock already present in the query |
A full Quorum review comment was also posted on gitlab-org/gitaly !8812 (note_id 3424838512): view comment
Quorum runs as a three-stage agent pipeline:
MR / PR opened
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Stage 1 — SurfaceDetectorAgent (zero API calls, ~5ms) │
│ │
│ Regex + keyword pre-filter on the diff. │
│ Detects: locks · sagas · retries · idempotency · kafka · outbox │
│ → If nothing detected: exits immediately, no Gemini cost │
└───────────────────────────┬─────────────────────────────────────────┘
│ surfaces detected
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Stage 2 — DeepReasoningAgent (Gemini 2.5 Pro, multi-turn) │
│ │
│ Builds investigation prompt → enters tool-calling loop: │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Gemini reasons about diff │ │
│ │ │ │ │
│ │ ▼ tool call │ │
│ │ semantic_code_search ──► GitLab MCP / GitHub API │ │
│ │ │ │ │
│ │ ▼ search results │ │
│ │ Gemini reasons with cross-repo context │ │
│ │ │ │ │
│ │ ▼ (repeats up to max_tool_rounds) │ │
│ │ → JSON findings with severity + confidence │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ Features: │
│ · thinking_budget=-1 (dynamic reasoning depth per turn) │
│ · Google Search grounding (CVE / incident report citations) │
│ · Context-aware severity (RULE_08 → CRITICAL in payment service, │
│ HIGH in metrics service — same bug, different blast radius) │
└───────────────────────────┬─────────────────────────────────────────┘
│ findings
▼
┌─────────────────────────────────────────────────────────────────────┐
│ Stage 3 — ReportFormatterAgent │
│ │
│ · Formats findings as structured Markdown comment │
│ · Posts comment to MR / PR │
│ · For CRITICAL findings (opt-in): generates corrected file, │
│ creates branch, commits fix, opens a DRAFT fix MR │
│ · Outputs SARIF 2.1.0 (--format sarif) for GitHub Code Scanning │
│ · Exits 1 to block merge if CRITICAL findings found │
└─────────────────────────────────────────────────────────────────────┘
The semantic_code_search call is what makes Quorum better than a regex linter. It can find the missing compensation handler in a different service, or confirm a fencing token is never passed downstream — anywhere in the project.
Quorum ships with 14 named rules. Each is a standalone Python module — adding a new rule is a single-file contribution.
| ID | Rule | Severity | Reference |
|---|---|---|---|
| RULE_01 | Fencing Token Missing | 🔴 CRITICAL | Kleppmann (2016) |
| RULE_02 | Wall-Clock TTL in Lock Lease | 🟠 HIGH | antirez — Is Redlock safe? |
| RULE_03 | Saga Compensation Missing | 🔴 CRITICAL | microservices.io — Saga pattern |
| RULE_04 | Idempotency Key Generated Internally | 🟠 HIGH | AWS Builders' Library |
| RULE_05 | @Transactional Wraps Distributed Lock | 🔴 CRITICAL | Leapcell — Redis Lock Pitfalls (2025) |
| RULE_06 | Retry Without Jitter | 🟠 HIGH | AWS — Exponential Backoff and Jitter |
| RULE_07 | Unsafe Test Coordination | 🟡 MEDIUM / 🟠 HIGH | Jepsen — Latency tolerance |
| RULE_08 | Kafka Auto-Commit With Manual Ack | 🔴 CRITICAL | Confluent — Offset Management |
| RULE_09 | Transactional Outbox Missing | 🔴 CRITICAL | microservices.io — Transactional outbox |
| RULE_10 | Lost Update (SELECT without FOR UPDATE) | 🔴 CRITICAL | Kleppmann — Designing Data-Intensive Applications §7 |
| RULE_11 | Context Error Masking | 🟠 HIGH | Go blog — Contexts and structs |
| RULE_12 | Dead Letter Queue Missing | 🟠 HIGH | Confluent — Error Handling in Apache Kafka |
| RULE_13 | Idempotent Consumer Missing | 🔴 CRITICAL / 🟠 HIGH | Confluent — Exactly-Once Semantics |
| RULE_14 | Cascading Timeout Missing | 🟠 HIGH | Google SRE Book Ch. 22 — Cascading Failures |
The surface detector fires on coordination patterns across 6 languages. Gemini's reasoning is language-agnostic for all of them.
| Language | Detected patterns |
|---|---|
| Python | All 14 rules — redis-py, kafka-python, aiokafka, SQLAlchemy, Temporal, Saga, requests, httpx |
| Java | RULE_03 (Axon Saga), RULE_06 (Thread.sleep), RULE_08 (@KafkaListener), RULE_09 (JPA/Hibernate), RULE_10 (@Version), RULE_12 (KafkaConsumer DLQ), RULE_13 (ConsumerRecord), RULE_14 (RestTemplate/WebClient) |
| Go | RULE_01 (go-redis SetNX), RULE_03 (Temporal workflow.ExecuteActivity), RULE_06 (time.Sleep), RULE_08 (sarama AutoCommit, kafka-go CommitInterval≠0), RULE_09 (GORM), RULE_10 (row.Scan), RULE_11 (select ctx.Done), RULE_14 (http.Get/DefaultClient) |
| JavaScript / TypeScript | RULE_01 (ioredis NX), RULE_03 (NestJS @Saga), RULE_06 (setTimeout), RULE_08 (kafkajs autoCommit), RULE_09 (TypeORM repository.save), RULE_10 (findById/findOne), RULE_12 (eachMessage), RULE_13 (eachMessage body write), RULE_14 (fetch/axios) |
| Ruby | RULE_01 (redis.setnx), RULE_06 (sleep), RULE_08 (karafka), RULE_10 (find/find_by) |
| Rust / .NET | RULE_06 (tokio::time::sleep / Task.Delay), RULE_01 (LockTake/StringSet), RULE_08 (Confluent .NET), RULE_09 (SaveChangesAsync) |
Real-world validated on open-source projects: Python (5), Java (1), Go (1). TypeScript and Ruby validated via dedicated benchmark MRs.
## Quorum · Distributed Coordination Review
> Scanned 6 coordination surfaces · 4 critical, 1 high · checked 6 rules
---
### 🔴 CRITICAL — RULE_01: Static lock value — no fencing token
**Confidence: 100%** | `src/orderservice/lock_manager.py:12`
redis.set(key, "locked", nx=True) uses a static string as the lock value.
If this process pauses (GC, network blip) and the TTL expires, a second
process acquires the lock. When the first resumes, the database has no way
to reject the stale write — there is no fencing token to compare against.
**Found via semantic search:**
Searched entire project for UUID/counter lock values — none found.
OrderRepository.save() accepts no version parameter.
**Suggested fix:** Use uuid.uuid4() as the lock value and pass it as a
conditional check to every write while the lock is held.
→ Draft fix: MR !8 ← Quorum opened this automatically
---
<details>
<summary>🟢 Passed checks (1)</summary>
🟢 **PASS** — RULE_07: Sleep correctly identified as task mock, not flaky test · `tests/test_fetcher.py:343` (100%)
</details>
Quorum works on both GitLab and GitHub.
| Tier | Client | Tools | Semantic search | Requirements |
|---|---|---|---|---|
| glab (recommended) | glab mcp serve |
191 | ✅ AI-semantic (needs Duo/Ultimate) | glab v1.80+ on PATH |
| zereight (community) | @zereight/mcp-gitlab |
107 | ❌ (REST lexical fallback) | Node.js + npx |
| rest (fallback) | GitLab REST API | — | ❌ (lexical) | Nothing extra |
Auto-detection: glab on PATH → uses glab; otherwise → rest.
Override: QUORUM_MCP_MODE=glab|zereight|rest
quorum review --platform github \
--project-id owner/repo \
--mr-iid 42Uses GitHub REST API (QUORUM_GITHUB_TOKEN). project_id is owner/repo, mr-iid is the PR number.
quorum review --platform github \
--project-id owner/repo --mr-iid 42 \
--no-comment --format sarif \
> results.sarifProduces SARIF 2.1.0 JSON on stdout (logs go to stderr). Upload to GitHub Code Scanning for inline PR annotations:
# Drop this in .github/workflows/quorum-scan.yml
- name: Run Quorum
run: |
quorum review --platform github \
--project-id "${{ github.repository }}" \
--mr-iid "${{ github.event.pull_request.number }}" \
--format sarif --no-comment > results.sarif
continue-on-error: true
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarifThe full workflow is at .github/workflows/quorum-scan.yml.
When QUORUM_CREATE_FIX_MRS=true and a CRITICAL finding is confirmed, Quorum:
- Asks Gemini to generate the corrected file
- Creates a branch
quorum-fix/rule-XX-<timestamp>from the source branch - Commits the corrected file
- Opens a Draft MR titled
Draft: [Quorum] Fix RULE_XX: <title> - Adds a link to the fix MR inside the findings comment:
→ Draft fix: MR !N
QUORUM_CREATE_FIX_MRS=true \
quorum review --project-id myorg/myrepo --mr-iid 42The default backend is Gemini 2.5 Pro (full features: thinking, Google Search grounding, function calling). For contributors who don't have a Gemini key, any LiteLLM-compatible model works:
# Local Ollama (free, no cloud key)
QUORUM_LLM_BACKEND=ollama/mistral quorum review ...
# OpenAI
QUORUM_LLM_BACKEND=openai/gpt-4o quorum review ...
# Anthropic
QUORUM_LLM_BACKEND=anthropic/claude-3-5-sonnet-20241022 quorum review ...Install the extra dependencies:
pip install "quorum[alt-backends]"Requirements for non-Gemini backends:
- The model must support OpenAI-compatible tool/function calling
- Minimum 16K token context (our prompt + rules + diff is ~6K tokens)
- Recommended:
qwen2.5-coder:7b,mistral:7b,llama3.1:8b,gpt-4o, or Claude 3.5 Sonnet
Note: Gemini-specific features (dynamic thinking depth, Google Search grounding) are not available on LiteLLM backends. Quality on non-tool-capable models will be lower.
Create .quorum.yml in your project root to override settings without touching env vars:
# .quorum.yml — committed to the repo
rules:
disabled: [RULE_07] # skip rules that are noisy for this project
confidence_threshold: 75 # higher bar than the global default of 60
ignore_paths:
- tests/
- "**/*_test.py"
- vendor/
create_fix_mrs: true # auto-open fix MRs for critical findings
platform: gitlab # gitlab or github
llm_backend: gemini/gemini-2.5-pro # override per projectPriority: .quorum.yml > environment variables > built-in defaults.
- Python 3.10+
- A Gemini API key (get one) — or set
QUORUM_LLM_BACKENDto use another backend - For GitLab:
glabCLI v1.80+ (install) recommended for semantic search - For GitHub: a GitHub PAT with
repo+read:discussionscope
pip install quorum
# With LiteLLM backends (ollama, openai, anthropic):
pip install "quorum[alt-backends]"Or from source:
git clone https://github.com/KaustubhUp025/quorum
cd quorum
pip install -e ".[dev]"cp .env.example .env
# Edit .env — fill in QUORUM_GITLAB_TOKEN and QUORUM_GEMINI_API_KEYMinimal .env for GitLab:
QUORUM_GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx
QUORUM_GEMINI_API_KEY=AIza...Minimal .env for GitHub:
QUORUM_GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx
QUORUM_GEMINI_API_KEY=AIza...GitLab MR:
quorum review --project-id myorg/myrepo --mr-iid 42
quorum review --project-id myorg/myrepo --mr-iid 42 --dry-run # print comment, don't post
quorum review --project-id myorg/myrepo --mr-iid 42 --rest-only # no glab requiredGitHub PR:
quorum review --platform github --project-id owner/repo --mr-iid 7
quorum review --platform github --project-id owner/repo --mr-iid 7 --format sarifWith alternate LLM backend:
QUORUM_LLM_BACKEND=ollama/mistral \
quorum review --project-id myorg/myrepo --mr-iid 42 --dry-runFile issues for findings in a review:
# Preview what would be filed (no API calls)
quorum file-issue --platform github --project-id owner/repo --mr-iid 42 --dry-run
# File issues for all HIGH+ findings (issues disabled → opens draft fix PR instead)
quorum file-issue --platform github --project-id owner/repo --mr-iid 42
# Only CRITICAL findings
quorum file-issue --project-id myorg/myrepo --mr-iid 42 --min-severity CRITICALReads the audit log for the given MR, then for each qualifying finding:
- Opens an issue in the target repo (if issues are enabled).
- If issues are disabled (e.g. enterprise repos using Jira), opens a draft fix PR with the finding body instead.
- If both fail, logs a structured warning with the finding text for manual filing.
Enable automatic issue filing after every review with QUORUM_AUTO_FILE_ISSUES=true.
List all rules:
quorum list-rulesquorum-review:
stage: review
image: python:3.12-slim
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
before_script:
- pip install --quiet quorum
script:
- quorum review
variables:
QUORUM_BLOCK_ON_CRITICAL: "true"
QUORUM_MIN_CONFIDENCE: "60"CI/CD variables to set in GitLab project settings:
| Variable | Required | Description |
|---|---|---|
QUORUM_GITLAB_TOKEN |
✅ | PAT with api scope |
QUORUM_GEMINI_API_KEY |
✅ | Gemini API key |
QUORUM_CREATE_FIX_MRS |
optional | true to auto-open fix MRs |
QUORUM_DISABLED_RULES |
optional | RULE_07,RULE_08 to skip rules |
gcloud auth login
gcloud config set project YOUR_PROJECT_ID
echo -n "glpat-xxx" | gcloud secrets create quorum-gitlab-token --data-file=-
./deploy/cloud_run.sh YOUR_PROJECT_ID us-central1After deploying:
- GitLab webhook: project → Settings → Webhooks →
https://<service>.run.app/webhook/gitlab - Enable: Merge request events
All settings use the QUORUM_ prefix (e.g. QUORUM_GITLAB_TOKEN).
| Variable | Default | Description |
|---|---|---|
QUORUM_PLATFORM |
gitlab |
Target platform: gitlab or github |
QUORUM_GEMINI_API_KEY |
— | Gemini API key |
QUORUM_USE_VERTEX_AI |
false |
Use Vertex AI (Application Default Credentials) |
QUORUM_GOOGLE_CLOUD_PROJECT |
— | GCP project (Vertex AI) |
QUORUM_GOOGLE_CLOUD_LOCATION |
us-central1 |
GCP region |
QUORUM_GEMINI_MODEL |
gemini-2.5-pro |
Gemini model (used when backend is gemini/*) |
QUORUM_LLM_BACKEND |
gemini/gemini-2.5-pro |
LLM backend — prefix gemini/ uses native SDK; others use LiteLLM |
QUORUM_GITLAB_URL |
https://gitlab.com |
GitLab instance base URL |
QUORUM_GITLAB_TOKEN |
— | GitLab PAT with api scope |
QUORUM_GITHUB_TOKEN |
— | GitHub PAT with repo + read:discussion scope |
QUORUM_MCP_MODE |
auto | GitLab MCP tier: glab, zereight, or rest |
QUORUM_MIN_CONFIDENCE |
60 |
Suppress findings below this confidence (0–100) |
QUORUM_BLOCK_ON_CRITICAL |
true |
Exit 1 (fail pipeline) when CRITICAL findings found |
QUORUM_MAX_SEARCH_RESULTS |
5 |
Max code snippets per semantic search call |
QUORUM_MAX_TOOL_ROUNDS |
10 |
Hard cap on Gemini tool-call rounds per review |
QUORUM_DISABLED_RULES |
— | Comma-separated rule IDs to skip (e.g. RULE_07,RULE_08) |
QUORUM_CREATE_FIX_MRS |
false |
Auto-open draft fix MRs for CRITICAL findings |
QUORUM_FIX_MR_MAX_COUNT |
1 |
Max fix MRs opened per review |
QUORUM_CORRELATE_CI |
false |
Check failing CI pipeline and correlate with findings |
QUORUM_WEBHOOK_SECRET |
— | HMAC secret for validating incoming GitLab/GitHub webhooks |
QUORUM_AUTO_FILE_ISSUES |
false |
Auto-file issues after every quorum review (opt-in) |
QUORUM_AUTO_FILE_ISSUES_MIN_SEVERITY |
HIGH |
Minimum severity to auto-file: CRITICAL, HIGH, or MEDIUM |
QUORUM_AUDIT_LOG |
~/.quorum/audit_log.json |
Path to the persistent audit log |
QUORUM_PORT |
8080 |
Port for Cloud Run webhook server |
QUORUM_LOG_LEVEL |
INFO |
Log level |
quorum check runs Stage 1 only (surface detector — no Gemini, no API calls, ~5 ms). Use it as a git pre-commit hook to catch coordination patterns before they reach CI.
# Install once per repo
quorum check --install-hook
# Or run manually
quorum check --staged # default: staged changes
quorum check --last-commit # last committed diff
git diff main... | quorum check --diff -Exit code 0 = clean. Exit code 1 = surfaces detected → run quorum review before merging.
Contributing a rule is a single-file addition. See docs/CONTRIBUTING.md for the full guide.
Quick version:
- Create
src/quorum/rules/rule_12_your_rule_name.py - Define a
RULE = Rule(...)with keywords, patterns, search query templates, and reasoning guidance - Add
tests/fixtures/bad/rule_12_*.pyandtests/fixtures/good/rule_12_*.py - Add a surface-detector assertion to
tests/test_detector.py - Open a PR — the registry auto-discovers new rules at startup
Quorum has been audited for prompt injection and supply-chain risks. Key protections:
- Prompt injection: All externally-sourced content (diff, code search results, file contents, MR description, CI logs) is wrapped in
<untrusted_*>XML boundary tags. The system prompt contains ABSOLUTE RULES explicitly banning instruction-following from any untrusted content. - SSRF:
QUORUM_GITLAB_URLrejects requests to cloud metadata endpoints (169.254.169.254,metadata.google.internal), loopback addresses, and RFC 1918 private ranges. - Webhook auth: Incoming webhooks are validated with
hmac.compare_digestagainstQUORUM_WEBHOOK_SECRET. The server logs a warning at startup if the secret is not set. - Input validation:
.quorum.ymlllm_backendis validated against a provider prefix allowlist (gemini/,openai/,ollama/, …) — rejectsfile://and arbitrary URIs. - Secret scrubbing:
_scrub_secrets()redactsghp_,glpat-,AIzaSy, andAKIApatterns from CI logs and error messages before they reach the LLM or logs.
See SECURITY.md for the full disclosure policy.
Every quorum review run is appended to ~/.quorum/audit_log.json.
Override the path with QUORUM_AUDIT_LOG=/path/to/log.json.
quorum history # all runs, most-recent first
quorum history --last 5 # last 5 runs
quorum history --repo vllm # filter by repo name (partial match)
quorum history --json # raw JSON for scripting / dashboardsSample output:
╭──────────────────────────────────────────────────────────────────╮
│ Quorum Audit Log │
│ 8 reviews · 12 findings · 🔴 5 critical 🟠 4 high 🟢 3 │
╰──────────────────────────────────────────────────────────────────╯
Findings by severity
────────────────────────────────────────────────
🔴 CRITICAL ████████████████████░░░░ 5 (42%)
🟠 HIGH ████████████████░░░░░░░░ 4 (33%)
🟡 MEDIUM ████░░░░░░░░░░░░░░░░░░░░ 1 ( 8%)
🟢 PASS ████████████░░░░░░░░░░░░ 3 (25%)
Reviews (showing 8 of 8)
┌────┬────────────┬──────────┬──────────────────────────┬───────┬───┬───┬─────────┬─────────────┐
│ # │ Date │ Platform │ Repo │ PR/MR │ 🔴│ 🟠│ Blocked │ Issue/Fix │
├────┼────────────┼──────────┼──────────────────────────┼───────┼───┼───┼─────────┼─────────────┤
│ 8 │ 2026-06-01 │ github │ vllm-project/vllm │ #34981│ 0 │ 1 │ — │ Issue #44245│
│ 7 │ 2026-06-01 │ gitlab │ rjackson-education/... │ !19 │ 0 │ 1 │ — │ — │
│ 4 │ 2026-05-31 │ github │ aio-libs/aiokafka │ #1164 │ 0 │ 1 │ — │ Issue #1165 │
└────┴────────────┴──────────┴──────────────────────────┴───────┴───┴───┴─────────┴─────────────┘
The --json flag outputs the raw JSON array, making it easy to pipe into jq or import into a dashboard.
The following features are planned for future releases. Community contributions are welcome — see CONTRIBUTING.md.
When Quorum files an issue or posts a review comment, the issue URL is stored in the audit log. A planned quorum follow-up command will:
- Check every open issue Quorum has filed — has the maintainer pushed a fix?
- Re-run the surface detector on the updated file at the commit that closed the issue.
- If the pattern is no longer present, post one final confirmation comment: "Fixed in
<sha>— confirmed by Quorum."
This turns Quorum from a one-shot reviewer into a persistent collaborator that closes the loop without human intervention.
For organisations deploying Quorum as a shared service (GitHub App / GitLab App):
- OAuth login — Quorum acts on each user's behalf using their own token; no shared PAT.
- Per-org dashboard — repos reviewed, findings by rule and severity, fix-acceptance rate over time.
- Persistent backend — Firestore or PostgreSQL stores findings across deployments, enabling trend analysis and regression detection.
- Automated resolution tracking — webhook subscription on issues automatically marks a Quorum finding as resolved when the filed issue is closed.
pip install -e ".[dev]"
pytest # run all 156 tests
ruff check src/ tests/ # lint
mypy src/ # type check| Component | Technology |
|---|---|
| LLM (primary) | Gemini 2.5 Pro — google-genai 2.6.0 — thinking_budget=-1, Google Search grounding |
| LLM (alternate) | Any LiteLLM backend — litellm 1.86.2 — OpenAI-compatible tool calling |
| GitLab MCP | glab mcp serve (191 tools, official) · @zereight/mcp-gitlab (107 tools, community) |
| GitHub client | GitHub REST API via httpx 0.28.1 |
| Data models | Pydantic 2.13.4 |
| Config | pydantic-settings 2.14.1 + .quorum.yml (pyyaml 6.0.3) |
| Webhook server | FastAPI 0.136.3 + Uvicorn 0.48.0 |
| CLI | Click 8.4.1 |
| Output formats | Markdown MR comment · SARIF 2.1.0 |
| Cloud deployment | Google Cloud Run + Vertex AI Agent Engine |
Design principles:
- Two-phase design: Surface detector is a cheap pre-filter (regex/keyword). Gemini is only called when the diff touches a coordination pattern. A typical CRUD MR exits in milliseconds with zero API calls.
- Rules are data: Keywords, patterns, search templates, and reasoning guidance — not if/else chains. Detection intelligence lives in the Gemini system prompt. Easy to review and contribute.
- Cross-repo context:
semantic_code_searchis load-bearing. A diff-only reviewer has high false-positive rates. Cross-project search is what lets Quorum say "this lock has no fencing token anywhere in the codebase" with 100% confidence. - Confidence threshold: Gemini self-reports confidence (0–100) per finding. Findings below
QUORUM_MIN_CONFIDENCEare suppressed. Tunable per project via.quorum.yml. - Resilient tool-call loop: When using Gemini context caching (tools embedded in the cache), the model occasionally emits tool invocations as plain text instead of structured function-call parts. The agent detects three encoding variants (
call:<name>{},<execute_tool>XML,tool_namein raw text) and nudges the model back to the structured API rather than crashing.
Apache 2.0 — see LICENSE.
Built for the Google Cloud × GitLab Hackathon 2026.