We compile your codebase into a semantic model that enables coding agents to understand it better. This allows quicker, cheaper and more reliable results than the classic text search approach. On top of this, we add a suite of tools that aim to empower human workflow in the agentic era.
Giving agents the right tools
Coding agents are great at reasoning over code, but much of their effort goes into finding the right code first. Ask one for a change and it spends time searching its way through your codebase before the real work can begin.
What’s more, it may declare the search done without having actually scanned all the right files. A necessary throttle, saving you from spending all your tokens on one exhaustive search. But wouldn’t it be nice to know if the search was really complete?
billing — agent ◂ -zsh — 80×24
◆ agent
cwd: ~/billing
>
Coding agents work from text. They can read your files, search your folders and reason about them. But raw text does not provide the full picture. It doesn’t tell the agent which method a call actually refers to, or whether personal data reaches a logger. Grep matches names, not bindings.
If we provide an agent with a model of the underlying connections instead, it can follow calls directly and know when it has seen everything.
The semantic model
What is it?
At Abstraction, we compile your codebase into a semantic model of your whole system. The model has two layers:
Building blocks, compiled. Every language is broken down into the same building blocks: functions, variables and types, inside files, modules and packages. The calls, type uses, imports and dataflow between them are resolved by the compiler, not guessed from names.
Higher-order abstractions, inferred. An LLM layer reads those building blocks and adds what the code doesn’t say outright: what each function does, the role it plays (HTTP handler, auth check, logger and so on) and which data is personal. It runs when the model is built, not on every query.
Instead of searching text, we follow relationships and read the source only where it matters. When something isn’t there, it answers from an exhaustive search of the model and tells you which parts it couldn’t trace. But most of all - it allows for quick queries at a low cost with impressive accuracy. All of our tools are based on this model.
Build once, use forever
The model is built once, and the result is saved. Everything on top reuses it, so there’s no more heavy lifting once your model is built.
When your code changes, we compile the change into a semantic diff. Only the packages that changed are compiled again, and only the parts of the model that the change invalidated are regenerated.
Language-agnostic by nature
The analysis runs on one representation shared by every language. Your Svelte frontend, Go backend and Python data pipelines are compiled into one model and answer to one query language. Explore any part of your system without switching context or workspace.
Works with
Python
Go
TypeScript
JavaScript
Java
Svelte
React
At the time of writing, we support Python, Go, TypeScript, JavaScript, Java, Svelte and React. We’re constantly adding more languages, and if your language isn’t on the list, stick around or reach out to us so we can prioritize by demand.
An example
Take a question like “does every HTTP handler reach an auth check?” Grep can often find both by name, but knowing whether one reaches the other means reading the code of every call path in between, which gets expensive fast. In the model the answer is one query away, however big the codebase.
Auth on every handler
Hi, please check that every HTTP and RPC handler in the backend is behind auth control
Finding the handlers and the auth checks, then drafting the rule.3
Here is a check for it. It takes every function with the HTTP or RPC handler role and fails each one whose calls never reach an auth check. 3 of the 41 handlers get through without one.
Hi, please check that every HTTP and RPC handler in the backend is behind auth control
Finding the handlers and the auth checks, then drafting the rule.3
Here is a check for it. It takes every function with the HTTP or RPC handler role and fails each one whose calls never reach an auth check. 3 of the 41 handlers get through without one.
Our agent turns the question into a few lines of AQL (Abstraction Query Language) and runs them against the model. The roles come from the LLM layer, and the calls between them from the compiled graph.
The answer is no: three of the 41 handlers never reach an auth check, and the details show which ones.
That answers the question for today’s code. Saved, the query becomes a rule, what we call a check, and runs again on workspace updates or every pull request. It’s a query rather than an LLM call, so it’s cheap enough to run on every PR and gives the same answer every time.
What we build on it
Our main use of the model is reviewing pull requests. We compile both the base and the head of a PR and review the semantic diff between them: which functions changed, who calls them and what data they touch, even when none of that shows up in the diff. The checks you’ve saved run beside the review.
The same model is behind our agent wherever you ask it: in the app, in Slack, on a pull request or from your own coding agent over MCP.
Closing remarks
Thank you for reading our first blog post! We hope you’ll follow along on our journey to help humans stay in control of their software.