If you’ve been building software with ChatGPT, Claude, Cursor, or Copilot, you’ve probably had this experience: everything works, you ship it, and weeks later something breaks in a way you can’t explain. The AI built something that was locally correct but globally inconsistent. The problem isn’t the AI’s intelligence — it’s that your tools only show the AI a fragment of your project at a time.

Every AI coding tool on the market today works roughly the same way. You write a prompt. The tool searches your codebase for files that seem relevant — usually through some combination of embeddings, keyword matching, and file-path heuristics. It stuffs those files into the model’s context window. The model generates code.

Sometimes this works beautifully. More often, the result compiles but doesn’t belong.

The retrieval lottery

The fundamental issue is that retrieval is lossy in exactly the ways that matter. Your codebase isn’t a collection of independent documents — it’s a densely interconnected graph of types, patterns, conventions, and architectural decisions. When a retrieval system pulls UserService.ts but misses the error handling pattern established in BaseService.ts, the generated code will handle errors differently than every other service in your project.

This isn’t a bug in the retrieval system. It’s a fundamental limitation of the approach. The information the model needs is spread across dozens of files in implicit patterns that no retrieval query can reliably capture.

What “context” actually means

When an experienced developer writes code in a codebase they know well, they’re not consulting individual files. They carry a compressed mental model of the entire project: the type hierarchy, the data flow patterns, the naming conventions, the architectural boundaries. This mental model is what makes their code belong.

The question isn’t “which files are relevant?” — it’s “can the model build the same kind of compressed understanding that a human developer has?”

A different approach

What if, instead of retrieving files at query time, we maintained a continuously updated semantic representation of the entire project? Not the raw source code, but a live, navigable knowledge graph that captures the structural relationships retrieval misses.

This is the idea behind Kaiso. We call it the semantic graph — and it contains more than just code structure. It maps types and their relationships, call graphs and data flow, module boundaries and conventions, and crucially, domain semantics inferred by LLM annotation. What your variables represent. How data transforms as it moves through your system. What patterns are established and where.

Outside-in exploration

When you ask Kaiso for a change, the AI doesn’t do one-shot planning based on retrieved files. It navigates the semantic graph iteratively, the way a senior engineer thinks — starting from the highest-level interfaces, drilling into relevant subsystems, backing up when a path isn’t relevant, moving laterally to check for related patterns. It builds understanding before writing code.

This matters because the right approach to a change often depends on context that’s far from the files you’d naively retrieve. An experienced engineer knows to check the error handling pattern before writing a new service. To check whether a similar transformation exists before implementing one from scratch. To trace data flow upstream and downstream before modifying a step in a pipeline. Kaiso’s exploration loop does this systematically.

Pattern symmetry analysis

The most powerful consequence of the semantic graph is that it reveals absences — things that should exist but don’t.

Imagine a data pipeline that processes survey responses. The cleaning step handles numeric fields — clipping outliers, imputing missing values, normalizing ranges. But free-text fields pass through uncleaned. Date fields have no validation. Kaiso’s semantic graph tracks what operations are applied to what categories of data. It sees the asymmetry. It asks: did you intend for these to be treated differently?

No existing tool can do this, because the “bug” is the absence of code that was never written. No test can catch it. No linter can flag it. No retrieval-based system even has the structural understanding to notice it.

This is what we call pattern symmetry analysis — detecting omissions by analogy. Situations where a transformation or pattern is applied to one category of things but not to a structurally similar category where it logically should be. These are the bugs that separate code that works from code that’s correct.

Why this matters for you

You don’t need to understand dependency graphs or semantic compression to benefit from this. You need an IDE that thinks about your project the way an experienced engineer would — always aware of the whole picture, always checking for consistency, always asking “what about the thing you didn’t think of?” That’s what we’re building.

We’re building Kaiso now. If you’re interested in following along, sign up on our homepage.