Direction Is Not Memory
Why repeated agent corrections in real repositories need scoped repository direction, not more transcript memory.
The repository had already answered the question. That was the strange part.
The person doing the work did not know that, and neither did the agent.
A reviewer had explained why a behavior belonged at a shared boundary. The PR had changed direction, the code had merged, and the decision was not imaginary. It existed in the history of the work. Then, a few weeks later, another task reached the same edge from a different package, and an agent proposed the same locally reasonable shortcut.
The organization had learned.
The work did not inherit the learning.
The old decision existed somewhere. It just did not travel.
That is the gap I mean by direction: not the code that changed, not the full review thread, and not a transcript of what happened, but the small piece of repository guidance that should have followed the next piece of work.
That failure kept bothering me because it was not quite a documentation problem, not quite an agent orchestration problem, and not quite a memory problem. The team had coordinated. The review had happened. The patch had changed. But the next thread did not inherit the direction.
Software work is becoming more disposable: threads are shorter, attempts are cheaper, agents can run in parallel, and worktrees multiply. A path can be explored, rejected, corrected, and replaced in a single afternoon. But repository knowledge is still trapped in the places where it happened.
Git Remembers The Patch
Git is excellent at preserving what changed. It can tell you which commit introduced a line, how two branches diverged, what the final diff looked like, and what history led to the current tree. That is necessary, but it is not the same as preserving the direction that shaped the change.
The final patch usually does not preserve the rejected path. It does not tell the next agent that a tempting local shortcut was discussed and avoided. It does not tell a sibling thread that the behavior belongs in a shared layer because three feature paths depend on it. It does not reliably carry the reason a migration is halfway complete and should not be bypassed.
That gap matters more when agents are involved because agents are good at producing tidy local solutions. The code can look reasonable. The tests can pass. The patch can be clean. Then a reviewer says, “we do not do it that way here,” not because of a universal best practice, but because this repository has history.
Git remembers the artifact. It does not always remember the project direction that made the artifact look that way.
PRs Remember The Argument
Pull requests hold more of the story. They contain comments, suggestions, review threads, CI failures, approvals, links, and sometimes the exact sentence that changed the implementation. A lot of useful direction is born there, in the moment where a reviewer turns a local implementation detail into a reusable project constraint.
But PRs are not a good runtime for future direction. Someone has to know which PR matters. Someone has to search for the right discussion. Someone has to distinguish the reusable decision from the temporary argument around it. Someone has to know whether the comment still applies, whether the migration ended, whether the code actually implemented the decision, and whether the rejected path is still rejected.
That is the important distinction: a PR discussion is where direction often appears, but the discussion itself is not the direction. Most of a PR should not become durable repository knowledge. It includes uncertainty, half-ideas, local negotiation, stale assumptions, and comments that only mattered for that patch.
The reusable piece is usually much smaller:
In this scope, prefer this path.
This was the rationale.
This other path was rejected.
This evidence supports the decision.
This record is temporary, candidate, or durable.
That object is not a transcript. It is direction.
More Prompt Is Not The Answer
The obvious fix is to put the correction somewhere the agent will read it next time. Add it to AGENTS.md, add it to CLAUDE.md, add it to Cursor rules, write a bigger project guide, and make the agent read more before it writes.
That works for a while. Then the instruction file starts to collect every scar the team does not know where else to put.
Every painful correction wants to become a permanent warning. Few get retired. A package rule escapes its package. A temporary migration note survives the migration. A review comment from one PR becomes global doctrine because no better place existed. Eventually the useful warning disappears into prompt sediment.
Agents do need instructions, but they do not need all instructions equally. They need the active constraint for the work they are about to do. A routing decision should not follow a CSS change. A migration rule should not outlive the migration. A package-specific correction should not silently become repository-wide law.
A global prompt file is a noticeboard. Direction needs an address.
General Memory Is Too Broad
“Memory” sounds close to the answer because the failure looks like forgetting. A decision happened, then a later thread failed to inherit it. So the tempting answer is to remember more: conversations, PRs, review comments, docs, commits, and whatever else might become relevant later.
But remembering what happened is not the same as preserving what should guide future work.
A conversation is full of noise: brainstorming, wrong assumptions, abandoned plans, temporary constraints, private context, and details that stopped mattering once the branch changed. A PR has the same problem in a different shape. It may contain the sentence that matters, but it also contains the negotiation around that sentence.
Repository direction is smaller than that. It is the part of the past that has become useful guidance for the next task.
It does not only say, “this happened.” It says, “in this scope, this should shape future work.”
That is why general memory feels too broad. The missing primitive is not a bigger pile of remembered context. It is a scoped object that can survive the thread where it was discovered.
Direction Has Scope
Large repositories do not have one truth. They have local truths. Routing has its rules, caching has its constraints, build tooling has its weird edge cases, and product workflows have assumptions that make no sense outside their area. One package may be in the middle of a migration. Another may intentionally avoid a shared abstraction because it has different latency requirements. A rule can be obvious in one path and harmful in another.
So direction needs a boundary. A useful record can be scoped to a repository, issue, PR, configured area, path, or, rarely, the whole project. Then a thread can declare what it is working on and receive the active records that match that scope.
That matching should not depend on the model guessing what feels relevant. It should not require embedding search through old transcripts. It should not ask an agent to rummage through a memory pile and decide which past pain matters today. Given the same records, scope, configuration, receipts, and budget, the same direction should be selected.
That is boring in the right way. The system should be deterministic where the work needs determinism, and small enough that people can inspect why a record was projected into a thread.
Direction Has A Lifecycle
Not every direction should become law. Some records are live coordination, useful while sibling threads are active. Some are candidates, probably reusable but not yet confirmed. Some are durable because they were promoted after review or human confirmation. Some expire, some get challenged, and some conflict.
That lifecycle is part of the object. Without it, the repository accumulates stale rules until future agents become worse, not better. A direction system should make capture cheap, but promotion deliberate.
Agents can propose candidate records. Tools can mine PRs. Review workflows can suggest reusable direction. But durable promotion should stay human- or reviewer-confirmed. The point is not to turn every sentence into law. The point is to preserve the rare sentence that future work should not have to rediscover.
Availability Is Not Causality
One thing I wanted to avoid was explanation theater. A system should not claim that a rule caused a change just because the rule was somewhere in the context window.
A useful provenance view needs to separate availability from causality. It can say that a direction existed, matched the thread scope, was delivered, and was exposed to the model. Those are availability claims. They matter, but they do not prove influence.
Causality is a stronger claim. If an action explicitly declares that it was informed by a direction, or if a commit explicitly declares that it implements a direction, the system can record that relation. But those claims should not be inferred from text similarity. They should not be guessed from the final diff. They should be explicit causal relations asserted by an adapter, actor, commit, or tool.
If the system does not know, it should say unknown. Not “probably used,” not “semantically related,” and not “likely influenced.” Unknown. That makes the system less magical and more trustworthy.
The Repository Should Own It
Fabric is my attempt at making this idea concrete: a local-first protocol for persistent repository direction and causal provenance across agent threads, worktrees, and tools.
I do not think Fabric has to be the final shape of this problem. I am more interested in naming the missing primitive than pretending there is only one good implementation of it. Maybe the answer is a protocol, a convention, review tooling, agent runtime support, or several approaches at once. Fabric is the version I built because I wanted to see what the idea looked like when it had to touch Git, real repositories, and messy parallel work.
The first version is intentionally small. No account, no server, no daemon, no database, no LLM call, and no embedding pipeline. Just immutable protocol events stored in repository-controlled places, a CLI as the reference client, and a deterministic way to project scoped direction into work that needs it.
Candidate and durable records live in a tracked ledger. Live records can coordinate active work through shared Git runtime state. Generated Markdown exists for humans, but it is not the source of truth. The protocol is the important part. The CLI is only the first client.
I wanted Codex, Claude, IDE agents, CI tools, review systems, and future agent platforms to be able to point at the same repository decision graph without one provider owning the memory layer. Provider objects stay opaque. A message is still owned by the provider. A PR is still owned by GitHub. A commit is still Git. Fabric keeps references and relations, not private transcripts.
A Direction Record Is Small
A useful Fabric record is compact. It does not contain the whole conversation, it does not contain a patch, and it does not try to become a second Git history.
A basic flow looks like this:
fabric thread start --issue BILL-417 --area billing/invoices \
--path 'services/billing/**'
fabric preflight "add invoice adjustment reason" --issue BILL-417 \
--area billing/invoices --path 'services/billing/**'
fabric note --candidate --reason "Invoice adjustments must stay auditable across exports and refunds" \
"Extend the adjustment ledger instead of storing correction reasons only on the invoice view."
fabric sync
The command syntax is not the interesting part. The loop is.
A correction happens once. It becomes a compact scoped record. A related thread receives it before acting. Later, if an action or commit implements it, that relationship can be recorded explicitly. Now the repository can answer a question Git alone usually cannot: what direction was available before this change, what evidence supported it, whether it was merely exposed to the model, whether the action explicitly claimed it was causal, and which rejected path this work was supposed to avoid.
Conflicts Should Be Visible
Parallel work changes the storage model. If multiple worktrees can write direction, the system cannot silently resolve conflicts by picking the newest file. That would hide the exact disagreement it should surface.
So every mutation is an immutable event. A record is created once. Lifecycle changes append child events. If two lifecycle changes extend the same parent, that is a conflict. A reader reports the competing children instead of picking a winner by timestamp, file order, or ID order.
That matters because disagreement is not a storage bug. If one thread says old direction is expired and another says it is still active, that is repository state. A human may need to decide. The system should not quietly paper over it.
Capture Is The Hard Part
Writing event files is not the hard part. The hard part is deciding what deserves to become repository direction.
Most comments do not. Most agent observations do not. Some review feedback is too specific. Some findings are wrong. Some constraints expire. Some rules are preferences pretending to be architecture. If capture is too eager, the system becomes another place where old confusion goes to live forever.
So capture has to be sparse and reviewable. Agents can suggest direction. Tools can surface repeated corrections. PR workflows can expose decisions that look reusable. But promotion should be deliberate, because a direction record is not just a note about the past. It is a claim that future work should pay attention.
That is the boundary I care about most. Fabric should not become a transcript archive, an AI summarizer, or a provider-specific memory plugin. It should not rush into being an orchestration platform either.
Worktrees, cloud sandboxes, remote agents, CI jobs, and merge planners are higher layers. The core should stay smaller: repository direction should be scoped, lifecycle-aware, portable, and causally traceable.
The Repository Should Not Start Over
The thing I want to prove is simple: can a thread avoid a bad path because another thread already paid to discover it?
If yes, Fabric is worth continuing. Not because agents need to sound like they remember the repository, but because the repository should not have to start over every time a new thread begins.
Git remembers what changed. PRs remember where people argued. Transcripts remember what was said. Fabric is one attempt at preserving the smaller, sharper thing that should survive all three: the direction future work should inherit.
I would like to see more attempts at this. Different protocols, different storage models, different review flows, different ways of deciding what becomes durable and what expires. The important part is that we stop treating repeated agent correction as a context-window problem when it is starting to look like a repository coordination problem.