← Blogs
BlogEnglishSep 19, 2026 Türkçe →

co-maintainer,
an imitator of yours

Every repository holds knowledge nobody wrote down. It lives in whoever has reviewed every pull request for three years, and it leaves when they do.

northwind/payments-api · 1,284 files pull request #312 2 files · +41 −6 everything that decides whether those 41 lines are correct
Fig. 01An AI reviewer is handed the band. A human reviewer is handed the band and also happens to be carrying the field.
01 · the repetition

You have written this comment before

Three pull requests, six months apart, three contributors. The same comment every time, worded a little differently every time. The rule is real and everyone knows it. It is just nowhere a machine can read it.

MKmuratreviewed #218 Mar 3
We keep amounts as integer minor units. amount * 0.029 turns a Money into a float, and the rounding is already gone by the time it reaches the ledger. Use mulRate.
MKmuratreviewed #264 Jun 11
Same thing as #218. This multiplies a Money by a float. mulRate(amount, 29, 1000) does it in one rounding step.
MKmuratreviewed #301 Sep 2
Float math on money again, third time this quarter. mulRate.
co-maintainer noted this in CODEBASE.md

Money is an integer count of minor units, defined in src/money.ts. Never multiply or divide a Money by a float. Rate math goes through mulRate(amount, numerator, denominator), which rounds once, at the end.

Fig. 02Nobody typed the sentence at the bottom. co-maintainer read the repository's review history and wrote it, in the repository's own words.
02 · the gap

What the diff does not say

A reviewer reads the patch while quietly holding four years of this codebase. Here is what that is worth.

in the diff · src/billing/refund.ts
src/billing/refund.ts#312
40export function refundFee(amount: Money) {
41 const fee = amount * 0.029;
42 return { fee, net: amount - fee };
43}
tests pass·types pass·lint passes
not in the diff · untouched for 14 months
src/money.tsmain
7// minor units. 1299 is 12.99
8export type Money = number & { __minor: true };
9
10export const mulRate = (m, n, d): Money =>
11 Math.round((m * n) / d) as Money;
ledger.post() rejects37.671at runtime, in production
Fig. 03The changed line is in the patch. The reason it is wrong is in a file nobody touched.

The types compile, because a branded number is still a number. The fee comes out fractional, ledger.post() asserts integers, and the refund throws on the first amount that does not divide evenly.

A missed finding is usually a missing input, not a weak model.

03 · the reading

Read the repository once, not once per review

Handing the model a whole repository on every review is possible, and absurd. So the reading happens once, off to the side, and what comes out is small enough to carry.

probe

Start with the part that costs nothing

It reads the repository through the GitHub API and prints the init line you should run, limits already filled in. No model is called, nothing is written.

init · extract

A cheap model turns the repository into evidence

Tree, files, pull requests, their diffs, the discussions on them, commit history. Every observation stays bound to the file or pull request that produced it, because a rule nobody can trace back is how a review tool starts inventing them.

init · synthesise

A reasoning model turns evidence into three guides

How to contribute here, how the code is actually written, and what reviewers here have historically stopped pull requests for. They land in your config directory, not in the clone, so a fresh checkout keeps them.

remake

Then keep it alive for the price of a diff

It refetches, reuses every piece of evidence the cache says is unchanged, and rewrites only the guides the new commits touch. init is the once. This is the loop.

REPOSITORY 1,284 files · 312 pull requests probe northwind/payments-api 312 pull requests sampled, 4,180 commits seen no model called, nothing written to disk prints the init line it recommends EVIDENCE extract low cost model each one bound to a file or a pull request synthesise reasoning model GUIDES ON DISK SKILL.md 14.2 KB how to contribute here CODEBASE.md 9.8 KB how the code is written PR_REVIEW_GUIDE.md 6.1 KB what reviewers stop PRs for 30 KB, reused by every review after this LATER · 3 COMMITS LAND ON MAIN remake rewritten unchanged rewritten cached evidence is reused, only touched guides are paid for again
zsh · ~/src/payments-apionce per repository
$ co-maintainer probe northwind/payments-api --auth=gh repository northwind/payments-api default branch main pull requests 312 sampled over 14 months commits 4,180 on main recommended co-maintainer init northwind/payments-api --include-codebase \ --include-pull-requests --include-pull-request-changes \ --include-commit-history --max-pr-months=12 --max-commits=500 no model was called, nothing was written $ co-maintainer init northwind/payments-api --auth=gh --ai=openrouter extract 1,284 files, 312 pull requests low model synth SKILL.md CODEBASE.md PR_REVIEW_GUIDE.md high model written ~/.config/co-maintainer/repos/northwind/payments-api done in 6m 12s
Fig. 04Two commands, one of which is free. Output trimmed to the shape of it.

The reason it happens once:

18.9K reused repository context 1.35M the repository, re-read per review 71× same pull requests · same model
Fig. 05Drawn to scale. The small square is what a review costs when the repository was read in advance.
04 · the artifact

The guides are the product

Models are rented. Whichever one is best this quarter will not be best next quarter. The context is the part you own.

SKILL.md14.2 KB
## Shipping
Pull requests run CI via .github/workflows/ci.yml, which defines a test job and a contract job that replays recorded provider webhooks.
Run npm run verify-pack before tagging a release.
## Tests
A new provider adapter is expected to ship with a webhook replay fixture under test/fixtures/providers/.
how to contribute here
CODEBASE.md9.8 KB
## Money
Money is an integer count of minor units, defined in src/money.ts. Never multiply or divide a Money by a float. Rate math goes through mulRate(amount, numerator, denominator).
ledger.post() asserts an integer amount, so a float that reaches it throws rather than rounding quietly.
## Code layout
Each provider adapter lives in src/providers/ and exports only charge, refund and webhook.
how the code is actually written
PR_REVIEW_GUIDE.md6.1 KB
## What reviewers here ask for
Float arithmetic on an amount is the most frequently raised issue in this repository's history (#218, #264, #301).
Three adapters have been blocked for shipping without a replay test. Treat a missing fixture as blocking, not as a nit.
## Tone
Reviewers here state the consequence, then the fix, in that order.
what reviewers here stop PRs for
Fig. 06Generated text, not hand written. The highlighted line is the one from Fig. 02, and the numbers under it are the pull requests it came from.

Read them out loud and they sound like the person who has been merging into this repository for two years. That is where the title comes from. It is not trying to be a better reviewer than your team, it is trying to be a cheap imitation of the one you already have, awake at 2am, on the boring pull requests too.

05 · the review

What it writes on the diff

A pull request opens. The guides are already on disk, so the reviewer starts from a repository it has read instead of a patch it has never seen.

Charge providers: percentage refund fee #312 northwind:feat/refund-fee Open
Review / co-maintainer reading guides and diff…2 findings, 1 blocking 24sDetails
co-maintainerbot reviewed just now
Reviewed against SKILL.md, CODEBASE.md and PR_REVIEW_GUIDE.md for this repository, with codegraph enabled.
1 blocking 1 non blocking 9,312 tokens 24.7s $0.0041
src/billing/refund.ts+3−0
3939export function refundFee(amount: Money) {
40 const fee = amount * 0.029;
41 return { fee, net: amount - fee };
4042}
P1 · blocking

refundFee() returns a fractional amount. ledger.post() asserts an integer count of minor units, so every refund whose fee does not divide evenly throws in production instead of rounding. CODEBASE.md puts rate math through mulRate for exactly this reason.

src/billing/refund.ts:41 · 3 call sites reach this

Suggested change
41 const fee = amount * 0.029;
41 const fee = mulRate(amount, 29, 1000);
Commit suggestion Add to batch
Fig. 07The green check is not the interesting part. The comment naming an assertion in a file the patch never touched is.

Without the guides there are two honest options here. Say nothing, because a percentage fee is a normal thing to write. Or say something vague about floating point, which everybody has learned to scroll past.

  • Findings carry over. Push a fix, run it again, and the finding closes instead of being raised twice.
  • A blocking finding exits non zero. That is all CI needs.
  • --json on stdout, logs on stderr. Findings, counts, tokens, duration, codegraph state, one document.
  • Codegraph is optional. On by default, and the binary is installed on request, not behind your back.
06 · the three doors

Same guides, three ways in

There are only three answers people actually want: the mess in my working tree, that pull request over there, and the first one without making every laptop pay for init.

reviewlocal review
review owner/repo 312pull request review
review --remoteremote review
what it reads
Staged, unstaged and untracked files in your clone
The pull request and its patch through gh, no checkout
The same local diff as the first column
where the guides are
Your disk, your own init
Your disk, your own init
The server, built once for the team
where the model runs
Your machine, your key
Your machine, your key
The server, with its key
what you need
A clone and an init
gh and an init
A host and a token
when you reach for it
Before you open the pull request
Reviewing someone else's work
Your first week on a new team
Fig. 08Pull request review and remote review do not combine. One takes a number, the other takes a diff.
07 · remote

Use shared context without running init on your machine

Somebody joins on Monday and clones the repository. Local review wants guides, guides want init, and init wants minutes and money. Paying that once per laptop is how a tool dies in its third week.

your laptop
$co-maintainer review --remote
·git diff against main, 2 files
·codegraph runs here, on your clone
·no guides, no provider key, no init
never leaves this machine
the clone · your credentials · everything you did not stage
diff
tool call
tool result
findings
co-maintainer serve
·guides for northwind/payments-api
·built once, by whoever set the server up
·the model runs here, with the team key
·job queue, per token concurrency
never sees
your working tree · your history · anything outside the diff
1 · handshaketoken cmr_…, schema and body limits agreed
2 · submitthe diff goes up, and only the diff
3 · queuethe server runs the model against its own guides
4 · tool bridgeit asks your laptop to run codegraph and waits
5 · syncfindings come back, identical to a local run
Fig. 09The tool bridge is the part worth staring at. The model is on the server, the code it needs to inspect is on your machine.

The boring safety bits. Tokens are hashed at rest, and deactivating one cancels every review in flight for it. The CLI prints a one time notice per host the first time it uploads a diff, so nobody finds out by reading the source six months later.

08 · the server

When you want the boring half automated

co-maintainer serve is one process and one app.db. It carries the GitHub App webhook, a job worker, the dashboard, and the remote review API from the last act.

localhost:5000
The co-maintainer dashboard listing one repository with its status, knowledge freshness, auto review toggle, review count and 30 day cost.
Fig. 10The knowledge column is the one that matters. It says needs update when main has moved past the guides, and a remake is one click from there.

Add a repository and init runs as a job you can watch. Flip auto review on and a pull request opening is enough to start one. The repo above has been connected for 8 days. Everything, init, remake and every review included, cost $1.20 in total.

09 · the evidence

Does any of this actually work

Thirty pull requests on a repository of mine. Fourteen carry a deliberately seeded, hand verified defect. Sixteen are clean controls, which is the part most review benchmarks skip and the part that makes precision measurable.

recall 0.857 12 of the 14 seeded defects, found
precision 0.353 it flags clean code too, this is the honest half
cost per PR $0.0045 $0.134 for the whole run
time per PR 28.9s 8.5K tokens on average
repo_wide 1.000 needs codegraph, cross file reasoning
convention 1.000 needs CODEBASE.md
history 1.000 needs PR_REVIEW_GUIDE.md
diff_local 0.800 needs nothing, it is all in the patch
file_local 0.500 needs the rest of the same file
Fig. 11bench core v3, GroophyLifefor/heap-analysis, Sep 14, 2026. Recall by what kind of context the defect needed.

Every defect that needed something outside the diff was caught. The two misses are on the axes where everything needed was already sitting in the patch, which is funny and slightly humbling: the context machinery works, ordinary close range reading is what still slips.

Thirty pull requests, no repeat runs, so variance is unmeasured. It raises about one unnecessary finding per clean pull request, and that number is what decides whether a team keeps a review bot or mutes it.

10 · the point

Context optimisation is not a loss of yield

The question was never which model reviews best. Models change every few months and the answer expires with them. The question is what the model is holding when it starts. Giving it more context does not make the prediction more accurate.

  1. 01less context
  2. 02less hallucination
  3. 03faster reviews
  4. 04more accurate predictions
get startednode 24+
$ npm install -g co-maintainer $ co-maintainer probe owner/repo --auth=gh then run the init line it prints, then: $ co-maintainer review