The queue wins
PRs sit for days. Branches drift, conflicts pile up, and the review that finally happens is a scroll to the bottom of a diff nobody has the context for any more.
v1.0.0 · Source-available · Elastic License 2.0
AI-assisted development moved the bottleneck to the pull request queue. CodeCapitan tells you which PRs are safe to approve unattended, and which ones genuinely need a human — as an auditable, rule-by-rule verdict you can still defend a week later.
$ make review URL=https://github.com/example-org/example-repo/pull/4521
======== codecapitan: 🔴 RED ========
PR #4521: Add bulk export endpoint
author: octocat
head_sha: 9f3c1a2b7e04
+412 -37 across 14 files
Score: amber=6 threshold=8 verdict=RED
Cost: $0.2140 total agent spend
RED rules:
[FAIL] secrets.aws_key (weight=10)
• src/config/settings.py:88 — AKIA… literal added
[FAIL] agent.broken_object_authz (weight=10, $0.0180)
• src/api/export.py:141 — export id from query,
no ownership or tenant scope
AMBER rules:
[FAIL] agent.type_rigor (weight=4, $0.0090)
• src/api/export.py:96 — any-type escape hatch
[PASS] agent.naming_clarity (weight=3, $0.0071)
GREEN rules:
[PASS] green.tests_added — 3 test files touched
31 rules N/A (use --verbose to list)
$ echo $?
2
The bottleneck moved
Assistants made writing code cheap. Reviewing it costs exactly what it always did. Every team that has hit that wall ends up in one of three places — and all three of them are a risk decision made by default rather than on purpose.
PRs sit for days. Branches drift, conflicts pile up, and the review that finally happens is a scroll to the bottom of a diff nobody has the context for any more.
Approvals keep pace by getting shallower. At volume, an LGTM is indistinguishable from no review at all — right up until the thing it waved through lands in production.
Required reviews get switched off "temporarily" so the team can move. Velocity goes up, and the audit trail that told you why anything was approved goes away with it.
The fourth option
Point CodeCapitan at a pull request and it tells you — with reasons, file and line — whether that PR is safe to approve unattended, or risky enough that a human should really look at it.
It isn't a rubber stamp and it isn't a blocker. It's a risk assessment you can read, disagree with, re-run, and hand to somebody who wasn't there.
The scan, step by step
A scan is a pipeline, and it behaves like one: fixed order, every step reports, results streaming back as they land. Five steps run 14 agent groups, 73 lenses and 291 sub-checks between them — and the half that catches the worst of it costs nothing.
Step 1
Secrets, tampered CODEOWNERS, trojan source, size gates, a red pipeline — plus a language pack for whatever the PR happens to touch.
Step 2
Fourteen groups, each multiplexed into one model call behind a cheap gate that decides whether the group is worth running at all.
Step 3
A council argues every finding — one advocate to suppress it, one to keep it, a judge to rule. False positives are a defect here.
Step 4
Confidentiality, integrity, availability and privacy are each rated, then re-rated against each other into one whole-PR risk band.
Step 5
Every result is scored into a single light, CODEOWNERS resolves the reviewers, and the report states exactly what it intends to do.
The one short-circuit. If a critical rule fails, the agent pool and the risk stage are skipped and reported as N/A. Everything else always runs to completion — a test in the suite exists purely to stop anyone reintroducing an early exit.
The verdict
That is the only question CodeCapitan answers. Green means safe to approve unattended, amber means a human should look, red and critical mean decline.
A categorical failure that makes evaluating the rest moot — a red pipeline, or a PR that disables a CI gate.
The PR is dead on arrival: the paid agent pass is skipped entirely. The deterministic tier still runs and reports in full.
A hard security, integrity or hygiene failure. Secrets in the diff, CODEOWNERS tampering, an unticked checklist, an unreviewable diff.
Any failing red rule makes the verdict red, whatever the amber score says. Decline, and label the PR for a human.
A quality concern: poor abstraction, weak error handling, loose types, cryptic naming, authentication used badly.
Weighted. When the failing weights cross amber_threshold, the verdict is amber — escalate to a human reviewer.
A positive signal: tests added, docs updated, types tightened.
Failing one is never penalising, and passing one adds nothing to the verdict maths. Logged as a signal, nothing more.
Precedence runs down the list: the highest severity with a failing rule is the verdict, and nothing below it can argue that away.
The catalogue
Every lens declares its own sub-checks, and the report tells you which one tripped — not just which lens. Here's a slice of the catalogue.
security_review_trust · never gated
Most review tools assume the diff is arguing in good faith. This group assumes it isn't. It's the one group that never gets gated away, because the PRs worth catching are exactly the ones that look cheap to skip.
agent.injection_risk · agent.ssrf · agent.path_traversal · agent.xss_output_encoding · agent.xxe · agent.redos
SQL built by concatenation, shell and eval with interpolated input, server-side requests to an attacker-controlled host, zip-slip, unescaped template output, regexes that backtrack catastrophically.
agent.auth_safety · agent.broken_object_authz · agent.security_posture_delta · agent.mass_assignment · agent.cors_misconfig
An authz check quietly removed, a route that went from authenticated to public, an object resolved straight from a client-supplied id with no tenant scope, credentialed CORS reflecting any origin.
agent.secret_in_code · agent.crypto_misuse · agent.transport_security_downgrade · agent.sensitive_data_in_logs
Hardcoded keys and connection strings, MD5 and ECB, predictable RNG for tokens, certificate verification switched off, auth headers and card numbers landing in logs.
agent.correctness_defect · agent.concurrency_risk · agent.input_validation_at_boundary
Inverted conditions, off-by-ones, swapped arguments, swallowed exceptions, a lock held across a blocking call, a handle that isn't released on every path.
agent.rollout_safety · agent.migration_safety · agent.terraform.risky_change
Schema and code shipped in one deploy, a non-nullable column with no backfill, a dropped endpoint, a Terraform change that forces replacement or broadens an IAM trust policy.
agent.abstraction_appropriate · agent.naming_clarity · agent.type_rigor · agent.incomplete_change · agent.test_quality
Wrappers around a single caller, any-type escape hatches, renames left half-done, and tests that exercise behaviour without asserting anything.
agent.suspicious_dependency · agent.supply_chain.license_risk · composer.* · docker.*
Dependencies from non-canonical sources, install hooks, typo-squats, loosened pins, lockfile integrity mismatches, copyleft arriving without an SPDX id.
agent.docs.sensitive_disclosure · agent.docs.content_quality · agent.comment_quality
Real customer names, live credentials or personal data in prose, instructions that contradict themselves, and comments that restate the code or narrate the edit instead of the intent.
PHP · JavaScript · Python · Go · Terraform · Docker · Lambda · NestJS · GraphQL
Gated on what the PR actually touches: Doctrine N+1s and missing migrations, floating promises and React hook deps, goroutine leaks, bare excepts, root Docker users, unguarded GraphQL resolvers.
Load-bearing contracts
A review tool is only worth running if it can't be talked out of its own answer. These seven properties are enforced by the engine itself and guarded by tests — not by anyone remembering to be careful.
Rules emit findings. The verdict is computed from each rule's status and its declared severity — never from anything the model wrote. An adversarial prompt can't approve itself by asking the model to type "approved".
.codecapitan.yml is read from the repo's default branch, never from the PR's head or base ref. A pull request can't weaken the policy that's judging it, and nobody can smuggle a permissive config in on a side branch.
One fetch pulls the PR, its diff, checks, review threads and CODEOWNERS before a single rule runs. Nothing re-reads GitHub mid-scan, so two rules can never disagree about what the PR contained.
Prompts are told to stay inside the lines the PR added. The engine then post-filters every finding against the added-line set regardless. The backstop is the filter, not the prompt.
A finding carries the file, the line, the rule that raised it and that rule's weight. The report is the audit trail: hand it to someone who wasn't there and they can check the call themselves, or argue with it.
Nothing reaches the report without surviving the council — advocate for suppressing, advocate for keeping, judge to rule. Noise is a defect, because the first tool anyone stops reading is the one that cries wolf.
Every rule runs even after a red. You get every reason a PR was declined in one report, the way a CI run gives you every failing job — not just the first one.
Dashboard
The same engine sits behind a Django and Vite dashboard. Trigger a scan and the results stream in live: every lens and every sub-check ticks from waiting to running to a result as the pipeline works, so a long scan stays legible while it's still going and a failure points at the exact sub-check that tripped.
When a scan comes back green, Approve PR leaves a real review on GitHub, gated behind TOTP. Nothing merges on its own: CodeCapitan is read-only by design and never merges a pull request.
Nothing binds a host port by default. Browser access normally goes through a Cloudflare tunnel into the internal Caddy ingress; PORTS=1 publishes Caddy on localhost when you'd rather not run a tunnel.
Quickstart
make test, make typecheck and make lint all run keyless against fixtures and stubs. You only need keys once you point it at a live PR.
# GITHUB_PAT needs repo:read. ANTHROPIC_API_KEY
# is only needed when agent rules run.
cp .env.example .env
make dev
make invoke
→ {"statusCode": 200, "body": "ok"}
make review URL=https://github.com/example-org/\
example-repo/pull/4521
# deterministic only — no API key, no spend
codecapitan review <pr-url> --no-agent-rules
# machine-readable, for batch runs
codecapitan review <pr-url> --format json
# .codecapitan.yml
custom_rules:
- id: no-active-record-in-controllers
severity: amber
weight: 4
type: prompt
paths_include: ["app/Controllers/**"]
prompt: "Flag Active Record calls inside
controller methods."
Licence
Use it, copy it, modify it, self-host it — including commercially, inside your own organisation. You may not offer CodeCapitan to third parties as a hosted or managed service, and you may not alter, remove or obscure the licensing and copyright notices.