Project Story

Inspiration

Every developer has experienced it.

You join a new project, open an unfamiliar repository, and immediately start asking questions.

  • What calls this function?
  • Where does this API route end up?
  • What breaks if I change this class?
  • Why does authentication work this way?

Finding those answers usually means opening dozens of files, jumping through IDE references, and slowly building a mental model of the codebase.

Large language models made this easier—but not reliable.

Most AI coding assistants retrieve a handful of files and ask an LLM to infer how the repository works. Sometimes that works. Sometimes it confidently explains relationships that don't actually exist because the model never saw the complete picture.

That led us to one realization:

The problem isn't explaining code. The problem is investigating code.

Instead of asking AI to understand a repository directly, we wanted to build a system that first understands the repository itself.

That became Trace.


What it does

Trace is an AI-powered code investigation platform.

Instead of searching files or relying entirely on embeddings, Trace converts an entire repository into a structured knowledge graph that represents how the code actually fits together.

Developers can ask questions like:

What calls processPayment?

How does authentication work?

What would break if I changed UserService?

Trace this API route to the database.

Rather than sending the repository directly to an LLM, Trace performs a deterministic investigation first.

It identifies symbols, traverses call graphs, follows imports, analyzes dependencies, and gathers evidence before any AI explanation is generated.

The result is a system where AI explains facts instead of inventing them.


How we built it

The biggest architectural decision was making Trace language-agnostic.

Our first prototype used separate parsers for Python and TypeScript.

It worked—but every new language meant writing another parser.

That architecture wasn't going to scale.

So we threw it away.

Instead, we redesigned the ingestion pipeline around Tree-sitter and built a universal AST walker.

The pipeline now looks like this:

Repository
↓
Language Detection
↓
Tree-sitter Grammar
↓
Universal AST Walker
↓
Normalized Intermediate Representation
↓
Knowledge Graph
↓
Deterministic Investigation Engine
↓
Evidence
↓
AI Explanation

Instead of embedding language-specific behavior into parser code, every language now provides a small declarative specification that maps Tree-sitter nodes into common concepts such as:

  • Function
  • Method
  • Class
  • Import
  • Call
  • Route
  • Module

Whether a repository is written in Python, TypeScript, or another supported language, Trace produces the same normalized graph.

Once the graph exists, Jac walkers perform deterministic investigations over incoming and outgoing relationships.

Rather than asking AI to search the repository, Trace already knows exactly how symbols connect before the explanation begins.


Challenges we ran into

The hardest challenge wasn't parsing code.

It was deciding where AI should and shouldn't be trusted.

Early on we realized that even the best language model becomes unreliable if it starts from incomplete context.

That completely changed our architecture.

Instead of building an AI that searched repositories, we built a graph engine that investigates repositories.

The AI became the final layer instead of the first.

The second challenge came from supporting multiple programming languages.

Python and TypeScript expose completely different syntax trees. Initially we handled them independently, but we quickly realized that every new language would multiply maintenance costs.

The universal parser solved that problem by separating language-specific syntax from language-independent concepts.

Finally, while testing multiple repositories, we discovered a subtle correctness issue.

Two repositories could contain functions with the same name.

Without repository-aware symbol resolution, Trace could investigate the correct function name in the wrong repository and still produce a perfectly reasonable—but completely incorrect—answer.

Finding that issue changed our roadmap.

Before making Trace smarter, we had to make it more trustworthy.


Accomplishments that we're proud of

The accomplishment we're most proud of isn't adding another AI model.

It's reducing the amount of AI required.

Trace doesn't rely on an LLM to discover how code works.

It discovers relationships deterministically and lets AI explain those relationships afterward.

We're also proud that we replaced separate language-specific parsers with one universal parsing engine while preserving identical graph output.

That allowed us to expand the system without rewriting the investigation engine.

Perhaps our favorite moment came during testing.

When we discovered repository-scoping issues before building the planner, we deliberately stopped adding features and fixed the architecture first.

It wasn't the fastest path—but it made the foundation dramatically stronger.


What we learned

We learned that retrieval isn't understanding.

Finding the right files doesn't necessarily answer an engineering question.

Understanding a codebase requires understanding relationships.

We also learned that good AI systems depend far more on system architecture than prompt engineering.

A language model cannot recover from incorrect evidence.

But if the evidence is correct, even a simple explanation becomes remarkably useful.

The biggest lesson was that AI shouldn't replace software engineering.

It should amplify good software engineering.


What's next for Trace

The next step is building an investigation planner.

Instead of relying on keyword matching, Trace will use an LLM to convert natural language into structured investigation plans.

The planner won't inspect the repository itself.

It will decide how the investigation should run.

The graph engine will execute the plan deterministically, gather evidence, and return verified results before the explanation layer generates a response.

Beyond that, we want to expand framework understanding, support additional programming languages, and build investigations for architectural analysis, onboarding, debugging, pull request reviews, and impact analysis.

AI is making it easier than ever to generate software.

We believe the next challenge is understanding the millions of lines of code that already exist.

Trace is built for that future.

Built With

  • jac
Share this project:

Updates