Code has logic. It does not have meaning.

Why repositories need semantic memory, not bigger context windows

Three weeks into a new project. I know the language. I know the framework. I still cannot ship a feature without asking someone. Not because the code is hard. Because nobody wrote down why this service exists, what it is actually responsible for, and what breaks when you touch it.

That knowledge is somewhere. A Slack thread from October. A meeting recording nobody will watch. The head of a developer who left in January. The code itself is perfectly legible. Every symbol is indexed. Every function has a name. And I still do not know why the order service calls the payment gateway twice, or why there is a retry loop that looks wrong but is not.

Humans survive this. You ask around. You read between the lines. You build a map in your head over weeks and months. It is slow, expensive, and completely invisible to the organization. But it works.

Now hand that same codebase to an AI agent.

The agent does not ask around. It does not read between the lines. It processes the text in front of it. If the meaning is missing from that text, the agent does not recover it. It guesses. Or it confidently writes code that violates a constraint nobody documented.

This is why agents look brilliant on small repositories and unreliable on large ones. The usual explanation is model quality. I do not think that is the problem. The problem is context shape.

Give the agent one file and it misses the system around it. Give it the whole repository and it drowns. One file breaks neighboring contracts. The entire repo turns into noise. A bigger context window does not fix that. Fifty thousand tokens of noise is still noise. You do not need more input. You need the right input.

The tricks that stop working

Rules files. Long system prompts. Context dumps. They all help for a while. Then the project grows. The rules file becomes a junk drawer where a global naming convention sits next to a quirk of one specific service. The prompt becomes a wall nobody reads. The dump becomes so large that the model ignores half of it.

There is no clean way to say "give me only the meaning of this part of the system." Not with any of these tools. That is not an intelligence problem. It is an information architecture problem.

What repositories remember and what they forget

Most repositories already have one kind of memory. Git remembers changes. Who changed what, when, and how.

What git does not remember is what the system is. Why a rule exists. What a module is responsible for. What constraints apply here. What else breaks when an interface changes. What business process this code participates in.

That knowledge exists in real teams. It is scattered, implicit, or gone. And it matters more now because agents are part of the team. A human joining a project can ask a senior engineer why something is the way it is. An agent cannot DM your former teammate. It will either guess, fail, or keep asking you until you become the context window yourself.

What I built

That is the idea behind Yggdrasil. Not a code generator. Not a graph database. Not another documentation ritual that humans will ignore in two months. Semantic memory for a repository.

The implementation is deliberately boring. Plain Markdown for content. Plain YAML for structure. A .yggdrasil/ folder inside the repo. It stores a structured map of modules, responsibilities, interfaces, constraints, cross-cutting aspects, and end-to-end business flows.

Here is what that looks like in practice:

.yggdrasil/
├── model/
│   └── orders/
│       └── order-service/
│           ├── yg-node.yaml        # type, relations, code mapping
│           ├── responsibility.md   # what it does and what it does NOT do
│           └── interface.md        # public methods, failure modes, contracts
├── aspects/
│   └── requires-audit/
│       └── content.md              # cross-cutting rule: all data changes need audit
└── flows/
    └── checkout/
        └── description.md          # full business flow: happy path, failures, invariants

A node's responsibility.md says things like: "OrderService creates orders, manages state transitions, orchestrates payment and inventory. It is NOT responsible for computing prices, managing stock levels, or sending emails." That negative boundary is as important as the positive one. It tells the agent what to leave alone.

The yg-node.yaml declares relations: this service calls that service, consumes these methods, and if the call fails, here is what happens. It also maps to actual source files so the agent knows where the code lives.

Aspects work like cross-cutting rules. You define "requires audit" once. Then you tag nodes with it. When the agent works on a tagged node, it gets the audit requirements automatically. If a node has an exception to the rule, that exception is declared right there in the node, not buried in a global file.

Flows describe business processes end to end. The checkout flow lists every participant, every path (happy, payment failed, inventory unavailable), and the invariants that must hold across all paths.

Small context, right context

The whole point is to give the agent 5,000 useful tokens instead of 50,000 random ones. Before the agent touches code, it gets a bounded package: the unit's responsibility, its interface, the constraints that apply to it, the interfaces of its dependencies, and the business flow it participates in. Nothing more. Nothing less.

This changes the question. Not "how do we show the model more of the repo." But "how do we make the repo legible." Those are not the same thing. A codebase can be fully visible and still semantically opaque. You can index every symbol and still not know what a service is actually responsible for, or what breaks if you change it. Search answers "where is X." It does not answer "what is X for."

Think of it as the difference between a compass and a map. A compass tells you a direction. A map tells you what exists, what connects to what, and what terrain you are standing on. The repository needs a map.

Why this does not rot like normal docs

Normal documentation rots because people stop reading it and stop updating it. Agent-facing semantic memory has a harsher test. If it is wrong, the output gets worse immediately. Bad memory produces bad code. That is painful enough to force maintenance.

In this model, code and graph are one unit of work. Change one without the other and you create drift. And drift is not a corner case. It is normal life. People hotfix things. They experiment. They edit code directly. They forget to update the knowledge around it. So the system treats drift as first class. Detect it. Force a decision. Either the graph absorbs reality, or the code gets brought back in line.

Adoption does not need to be all or nothing either. A project with 500 files should not model the entire world before getting value. Start where the pain is. One module where the agent keeps making the same mistake. One area where people keep re-explaining the same decision. Coverage grows where the work is happening.

The honest part

This does not replace source code. And it does not help equally in every situation.

The real advantage is cross-module reasoning. It helps when the question is "why was this designed this way," or "what else is affected by this change," or "how does this business flow work end to end." Declared relations, shared constraints, and flows create actual leverage over raw file reading.

But if I need to know the exact failure behavior of a call, the exact await pattern, the exact transaction boundary, or whether a feature exists in the implementation right now, I trust the code first. The graph is strongest at why, should we, and what else. The code is strongest at what exactly happens here. Those are complementary. Treating one as a replacement for the other is a mistake.

Another uncomfortable finding. Agents are much better at spotting contradictions than omissions. If the graph says something false and the code says something else, they often catch it. If an important rule is simply missing from the graph, they are much worse at noticing. That means incompleteness is more dangerous than inconsistency. The agent can confidently reason from a map that has a hole in it. The hard part is not keeping semantic memory correct. It is keeping it complete enough where it matters.

The bottom line

A huge amount of value in a software system has never lived in code. It lives in responsibility boundaries, business rules, rejected alternatives, architecture constraints, and the reason a strange decision was made six months ago. Humans carried that in their heads because they had to. Now we work with tools that cannot survive on tacit knowledge.

Git remembers changes. The repository should also remember meaning. If it does, the next engineer does not have to rebuild the whole map from scratch. And the next agent does not have to guess why the road bends there in the first place.