Architecture, explained without the jargon
AI-powered peer code review
Liffy reads a programmer's proposed change to a piece of software and writes back the kind of feedback a senior engineer would give — except it has already read the entire project, and it never runs out of time.
The situation
Before new code joins a project, another programmer is supposed to read it and catch the mistakes. This is called code review. It is the single best moment to catch a bug — and the one everybody is too busy to do properly.
The gap
Automated checkers already exist, but they only catch spelling-level problems. They cannot tell you "this contradicts how the rest of your project works." For that you need something that has read the whole project.
What Liffy does
It reads the entire codebase once and remembers it. Then, every time someone proposes a change, it pulls up the parts of the project that are relevant, reads the change against them, and writes specific, line-by-line feedback.
Why it is not just "ask an AI"
An AI asked cold gives generic advice. Liffy hands the AI the surrounding code first. That is the whole product — and it is the difference between "consider adding error handling" and "this breaks the pattern in line 40."
Liffy is not one program. It is six pieces that hand work to each other, and none of them knows how the others are built internally — they only know what to pass along. That is deliberate: any one piece can be swapped out without touching the rest.
FastAPI · Nginx
Every request from a browser or from GitHub arrives here first. It checks who is asking, then passes the work to whoever handles it.
GitHub OAuth 2.0 · JWT
Nobody creates a Liffy password. You sign in with the GitHub account you already have, and Liffy is handed a permission slip for exactly the repositories you approve.
Webhook · Diff parser
GitHub knocks here the instant someone proposes a change. This piece verifies the knock is genuinely from GitHub, then breaks the change into readable pieces.
Tree-sitter · ChromaDB
Reads the whole codebase and files every function away by meaning, so it can later be asked "show me the code most similar to this" and answer in milliseconds.
LangChain · Claude Opus 5
Gets the change plus the relevant surrounding code, and writes the actual review. It is required to answer in a strict format so nothing downstream has to guess.
Scoring engine · Feedback store
Collects the thumbs-up and thumbs-down a developer gives each comment, and turns them into a score for how good Liffy's reviews actually are.
Supporting cast
Three more pieces do the unglamorous work: PostgreSQL is the filing cabinet where every review is permanently stored; Redis is the ticket queue holding jobs waiting to be done; Celery is the back-room worker that picks tickets off that queue. They exist because a review takes up to a minute, and nobody should stare at a spinner while it happens.
Where it starts
A code review tool has to be trusted with private source code, so the sign-in has to be beyond question. Liffy sidesteps the problem entirely: it has no accounts and no passwords of its own. GitHub vouches for you.
Liffy sends your browser to GitHub, attaching a one-time random string it also stores in a cookie.
That random string is an anti-forgery measure. If the reply that comes back doesn't carry the same string, Liffy knows the reply was manufactured by somebody else and throws it away.
GitHub shows its own consent screen listing what Liffy is asking for: permission to read your repositories, and your username.
This screen is GitHub's, not Liffy's. Your password is typed into GitHub and never travels anywhere near Liffy.
GitHub sends your browser back to Liffy carrying a short-lived code. Liffy exchanges that code, server to server, for an access key tied to your account.
A short-lived day pass that expires after fifteen minutes, and a long-lived membership card good for thirty days that can be traded for a fresh day pass at any time.
Two passes instead of one because of what happens if a pass leaks. A stolen day pass is worthless in fifteen minutes. The membership card is stored in Liffy's own database, so if it is ever stolen it can be cancelled immediately — and it is replaced with a new one every single time it is used, so a copied card stops working the moment the real owner uses theirs.
The part that makes Liffy different
When you connect a repository, Liffy sits down and reads every file in it. This happens once, in the background, and takes a few minutes. Everything Liffy ever says afterwards is grounded in what it learned here.
Liffy walks the repository through GitHub's API, skipping images, compiled binaries and anything over 200 KB — those are almost always machine-generated bundles, not code a human wrote.
A parser called Tree-sitter reads the file the way a linguist diagrams a sentence — identifying which lines form a function, which form a class, where each one begins and ends.
This is the same technology code editors use to colour your code. Liffy uses it to find the natural seams in a file.
The file is split into chunks — one complete function or class each. A file in a language Liffy has no grammar for still gets chunked, just by fixed line windows instead.
This is the decision the whole system rests on. Chopping code every 50 lines regardless of content would cut functions in half, and half a function means nothing to anybody. Cutting at the seams means every chunk is a complete thought.
Every chunk is passed through a model that converts it into a list of 384 numbers. Chunks that do similar things end up with similar numbers.
Think of it as giving every function a position on a map, where distance means "how alike are these two pieces of code." Two functions that both validate an email address land near each other even if they share not one word. This model runs on Liffy's own machine — nothing is sent anywhere to do it.
The coordinates go into ChromaDB, a database built for exactly one question: given this position, what are the nearest neighbours? Every repository gets its own private shelf.
Separate shelves per repository, deliberately. Letting one project's code turn up while reviewing another's would produce confident, irrelevant advice — and would be impossible to debug.
Liffy records a fingerprint of every chunk's contents. Next time it re-reads the repository, anything whose fingerprint is unchanged is skipped.
So the first read is slow and every read after it is nearly instant — only what actually changed gets re-read.
Thirteen steps, about a minute, nobody watching
On GitHub, a proposed change is called a pull request — "please pull my work into the main project." Everything below happens automatically, in the seconds after that button is pressed.
A developer finishes a piece of work and asks for it to be merged into the project.
GitHub immediately sends a message to a dedicated address on Liffy's server. This is called a webhook — GitHub pushing news out, rather than Liffy repeatedly asking "anything new?"
The address is public, so anyone could send it a fake message. GitHub signs every message with a shared secret; Liffy recomputes that signature and compares. Anything that doesn't match is discarded unread.
Like a wax seal. Only someone who holds the same stamp can produce a matching impression — and the comparison is done in a way that gives an attacker no clue how close a guess was.
The knock carries only headline details, so Liffy calls GitHub back for the full diff — the exact list of lines added and removed.
The raw diff is one long block of text. Liffy parses it into structured pieces — which file, which lines, added or removed — keeping a map back to the real line numbers.
That map matters at step 11. A comment is only useful if it lands on the right line of the right file.
The job is put on a queue and Liffy answers GitHub instantly. A separate background worker picks the ticket up and does the slow part.
Reviews take tens of seconds. If Liffy held the line until it was finished, GitHub would give up waiting and the review would be lost. The queue also means a crash costs nothing: the ticket is still there when the worker restarts.
Each changed piece goes through the same model used during indexing, producing a position on the same map.
For each changed piece, Liffy pulls the five most similar pieces of existing code from that repository's shelf.
This is the retrieval step — the "R" in RAG, and the reason Liffy can say "you've written this before, over here" instead of guessing.
Liffy assembles one document for the AI: who it is meant to be (a senior engineer), exactly what shape its answer must take, the change under review, and the retrieved surrounding code.
The order is fixed on purpose — the unchanging part goes first so it can be cached between reviews, which cuts both cost and waiting time.
The model returns an overall summary, a verdict, and a list of comments — each pinned to a file and line, tagged with a category and a severity.
Liffy is not tied to one AI. The same slot accepts Claude, OpenAI, or a model running on your own laptop for free — the rest of the system doesn't change.
The reply is validated field by field against a strict schema. Anything malformed is rejected and the model is asked again. Then each comment's line numbers are translated from diff coordinates back to real file line numbers.
An AI can produce beautifully-worded nonsense. This step makes structural nonsense literally unable to enter the database.
Review and comments are written to the database, along with which model was used, how many tokens it consumed and how long it took — the raw material for measuring quality later.
The dashboard has been checking for updates the whole time. The finished review renders over the code diff in the same editor component that powers VS Code, each comment attached to the line it is about.
The clock
Liffy's target is under 90 seconds from GitHub's knock to a finished review. Measuring that honestly is harder than it sounds: the knock arrives at one program and the review finishes in a different one, so the time spent waiting in the queue sits between them and is easy to accidentally leave out. Liffy now stamps the arrival time onto the ticket itself so the full wait is counted, not just the working time.
Steps 08 and 09, and why they exist
Every AI code review tool sends the change to a model. The question is what else it sends. On the left, nothing. On the right, the five most relevant pieces of the project's existing code. Same model, same change.
"Consider adding error handling to this function, and make sure the variable names are descriptive."
True of almost any code ever written. Nothing here required reading this project, so nothing here tells the developer something they did not already know.
"The macOS script replaces the whole line here; this one replaces only the prefix, so the generated secret gets written in front of the placeholder instead of over it."
Only possible because the other script was retrieved and put in front of the model. This is a real comment Liffy wrote — and the bug was real. See Plate 06.
Where the name comes from
RAG — retrieval-augmented generation. Retrieve the relevant material first, then generate the answer with it in hand. It is the difference between an open-book exam and a closed-book one, and it is why Liffy is a system rather than a wrapper around somebody else's model.
Pull request #58 · lucenity0/Liffy
The change added one-command setup scripts for macOS and Windows. Liffy read it with no human help and returned eight comments. Every one was then checked by hand.
Note the clock: two minutes, against a target of ninety seconds. That gap is the honest reason the timing measurement described in Plate 04 exists — a target nobody measures properly is a target nobody misses. Liffy now records both numbers on every review, the working time and the full wait, and reports the median of each.
Liffy rated this critical — its highest severity. It was correct, and the bug was already sitting in the project's main branch where nobody had noticed it.
"This replaces the substring JWT_SECRET_KEY= with
JWT_SECRET_KEY=<hex>, which prepends the generated secret to
whatever placeholder value is already there. The macOS script correctly replaces the
whole line. Rewrite the line, not the key prefix."
In plain terms: the Windows setup script was supposed to
write a freshly generated security key into a settings file. Instead of replacing the
placeholder text, it wrote the new key in front of it — producing a key with
the word changeme stuck on the end. Every Windows user would have got a
silently broken installation. Liffy caught it by comparing the Windows script against
the macOS one, which does it correctly.
All eight comments were verified by hand. This is the real result, not a highlight reel.
Liffy sorts every comment into one of six categories — logic error, security, performance, architecture, convention, improvement. Tracking that spread is how the team will notice if it starts obsessing over one kind of problem and going blind to the others.
Steps 14 and 15 — the loop that closes
Everything up to here produces a review. This last act is what stops the quality being a matter of opinion. Without it, there would be no way to answer the only question that matters: is Liffy actually any good?
Each comment carries a thumbs up and a thumbs down. One click, stored immediately against that specific comment and that specific person.
Deliberately the smallest possible ask. A feedback form nobody fills in produces no data, and no data means no way to improve.
Once a week, a scheduled task walks every completed review and computes its approval rate. Reviews scoring below 50% are flagged for a human to read.
The flagged reviews get read. If the same kind of wrong comment keeps appearing, the instructions given to the AI at step 09 are rewritten to prevent it — and the next week's scores show whether that worked.
This is the loop that closes. Liffy does not learn on its own; it produces the evidence its builders need in order to improve it deliberately.
A contradiction found in our own specification — and settled
The first two targets cannot both be met as written. If a developer's only options are thumbs up and thumbs down, then "comments marked as not an issue" is exactly "comments not given a thumbs up" — so the second number is always 100% minus the first. Asking for above 70% and below 20% asks for 70 + 80 = 150%. It was caught while writing the code, and written down rather than quietly implemented wrong.
The resolution: both numbers are still stored, because they are the two columns the schema promises, but approval rate is the operative target and false-positive rate is recorded as its arithmetic complement, not as a second opinion. Telling the two genuinely apart needs a third answer in the vote — "wrong" as distinct from "not useful" — which is a schema change worth making when there is enough feedback for the finer number to mean anything.
Nothing in Liffy is held in memory and hoped for. Every drawer below is a real table in the database, and each one links to the next so a single comment can always be traced back to the person, project and change it came from.
users
Everyone who has signed in through GitHub.
repositories
Which repositories are connected, who connected them, and when each was last read.
pull_requests
Every pull request Liffy has been asked to look at.
reviews
One per attempt: the summary, the verdict, which AI wrote it, what it cost, how long it took.
review_comments
The individual remarks — file, line, category, severity, the text, and any suggested fix.
comment_feedback
Who gave which comment a thumbs up or down.
repo_embeddings
The chunk fingerprints, so re-reading a project only touches what changed.
eval_scores
The weekly quality result for each review.
Steps 1 to 13 — sign in, connect a project, read it, receive a pull request, retrieve context, write the review, display it — all work end to end against real repositories and a real AI. So do steps 14 and 15: comments are rated, a weekly job turns those ratings into scores, and an analytics page shows them.
Why posting to GitHub was left until last
Liffy could have posted its comments straight onto the pull request from day one. It deliberately did not. An automated reviewer that starts commenting on people's work before anyone has established whether it is any good is just noise — and noise gets muted permanently. The dashboard came first so the quality could be judged privately. Only once a real review had been checked comment by comment did posting go in — and it ships switched off. Turn it on and it still only leaves a comment; approving a pull request or formally blocking a merge is a second, separate opt-in. An automated reviewer that can hold up a human's work uninvited is the kind of tool people mute permanently.
Every one of those 1,347 tests runs automatically before any change is allowed into the project. Nothing merges red.