I built a tool that fails your CI when your code comments start lying
The comment that cost me a day
A comment said // writes to the ledger. So I trusted it, built on top of it, and shipped a bug. The function had stopped writing to the ledger four refactors ago. The comment never moved, because nothing in my toolchain could tell it was now false.
This is the quiet tax on every large codebase. The code is the truth, but it is illegible at scale. The artifacts that are legible (comments, docs, wikis) are untrustworthy, because nothing checks them. A new hire or a first-time open-source contributor opens a file with a million lines behind it and has to reverse-engineer intent from syntax, because the stated intent might be a lie from 2019.
We have linters for style. Type checkers for types. Tests for behavior. We have nothing that checks whether the stated intent of a piece of code still matches what the code actually does.
So I built Lore.
The idea: one graph, two layers
Lore maintains an intent graph over your codebase with two layers:
The derived layer is the what. Lore parses your source with tree-sitter and extracts structure: functions, the calls between them, the state each one reads and writes. This layer is true by construction. It needs zero annotations and it cannot lie, because it is the code.
The declared layer is the why. This is the human knowledge no parser can recover: why something exists, who owns it, what it is supposed to affect. You write it as lightweight @lore blocks inside your normal comments.
# @lore
# purpose: "Record every money movement, append-only"
# owner: "payments-team"
# affects: Payment.ledger
def charge(method, amount):
...
ledger.append(entry)
Nothing exotic. Line comments, in the language you already write. The block binds to the declaration right below it.
The honesty mechanism: reconciliation
Two layers on their own would just be documentation with extra steps. The point is what happens when they meet.
For every claim in the declared layer, Lore checks it against the derived layer and assigns one of four labels:
Verified the code does what the claim says. The derived layer agrees.
Unverified Lore cannot find supporting evidence, but cannot disprove it either.
Contradicted the code provably does not do this. The claim is false.
Unverifiable this claim is outside what static analysis can check, and Lore says so rather than pretending.
A Contradicted claim fails your CI, exactly like a failing test.
Here is the before/after that is the whole pitch:
# @lore
# affects: Payment.ledger
def charge(method, amount):
ledger.append(entry) # claim is Verified, CI is green
Delete the line that writes the ledger:
# @lore
# affects: Payment.ledger
def charge(method, amount):
pass # claim flips to Contradicted, build goes red
The comment and the code now police each other. The moment intent and reality drift apart, you find out, at the moment it happens, in the place you already look: CI.
What you actually do with it
Reconciliation keeps the graph honest. The graph is what you query.
You can ask what writes to a piece of state, what a function touches, what reaches the payment service, who owns a module, what is still marked unknown. For onboarding the killer query is show:
$ lore ask "show(PaymentService.charge)"
which prints the node card: purpose, owner, every declared clause, and the in/out edges with their layer and status. The mental model a newcomer builds over weeks, printed on demand.
And you can see it. lore graph --dot --focus PaymentService.charge --depth 2 exports a slice of the graph to Graphviz, so you get a picture of how one piece connects to the rest of the system instead of a wall of files.
The principle I refused to break: never guess
This is where most "AI understands your code" tools lose me, so I built the opposite constraint into the foundation.
Lore never presents a guess as a fact. Every derived edge carries a confidence label: Exact (same-file resolution, effectively certain), Resolved (cross-file via real import resolution), or Heuristic (pattern-based, could misclassify). When a call cannot be resolved, Lore drops it and counts it, rather than inventing an edge. A wrong edge is poison; a missing one is just honest.
The same principle is why Unverifiable is a first-class answer. Some claims (an event being published, a dependency on an external service) cannot be checked language-agnostically with static analysis. Lore does not paper over that with a confident green check. It tells you the claim is unverifiable and moves on. When forced to choose between coverage and certainty, it chooses certainty every time.
The engineering bit: adding a language is a folder, not a fork
Lore works today on Python, TypeScript, Rust, Go, and Java. The interesting part is that there is no per-language Rust code behind that list.
A supported language is a language pack: a single lore-lang.toml manifest, two tree-sitter query files (bind.scm for declarations, derive.scm for calls/imports/state-touches), and a mandatory conformance fixture suite. One generic adapter loads all of them. The manifest declares a tier (scan, bind, or derive) so a half-finished pack states honestly how far it goes instead of pretending to be complete. A pack whose conformance suite has not passed for its exact content simply does not load. The five-language matrix and the no-Rust-per-language constraint are the same fact.
That means adding the next language is writing declarative queries and fixtures in a folder, not forking the engine. Which is exactly the kind of contribution I am hoping to get.
Where it stands
Phase 1, the language-agnostic annotation and reconciliation tool, is feature-complete and open source. It is pre-1.0 and you build it from source today. The derived layer is deliberately conservative, so it under-reports rather than over-claims, by design.
Repo and 5-minute quickstart: https://github.com/YassineKaibi/Lore
I want one specific piece of feedback. If you have onboarded onto a large unfamiliar codebase recently: what is the one question you most wished you could ask the code directly and trust the answer? That question is the next query I want Lore to answer.
