
How Does Compounding Intelligence Work in fAI?
What actually happens between a capture landing on disk and a coherent FAI-PROJECT.md: the seven vaults, how a synthesis pass picks what to read, and how it distills more material than fits at once without dropping anything.
Kilian CarrollHow Does Compounding Intelligence Work in fAI?
A capture lands as a commit within seconds, and nothing reads it. Later, a synthesis pass pulls back the captures that are relevant by meaning, chunks them to fit a token budget, and distills them in more than one step. What reaches FAI-PROJECT.md is the end of that chain, assembled by code into a fixed set of sections.
fAI is a workbench that runs underneath the AI coding tools you already use, keeping what it learns in ordinary git repositories on your machine. We have written about where that lives and why the result stays small. This post is the part in between: the machinery that turns one into the other.
Everything below was run against my fAI workbench at one moment on 2026-10-02. Counts move while you work, so they are all from that single snapshot.
What is a vault, and how many does fAI run?
A vault is a store with one job. It has a domain, its own git repository, its own idea of what is worth keeping in that domain, and its own schedule for thinking about it. fAI ships seven.
| Vault | What it keeps |
|---|---|
| Capture | Raw session output from the CLI, hooks, and MCP |
| Context | Working context that shapes what you are doing now |
| Decision | Choices you made, and why |
| Pattern | Approaches and techniques you keep reaching for |
| Petnames | The names you have established for things in your domain |
| Knowledge | The synthesis vault, composing four of the others |
| Session | The session manager, composing Capture and Knowledge |
On disk they are just directories, one per vault, next to the file they produce:
$ ls ~/.fai/workbenches/<hash>/
context decisions patterns petnames pages FAI-PROJECT.md
They are not seven peers. They come in three jobs.
Capture is mechanical. It takes whatever your agents emit, from the CLI, from hooks, from MCP, and writes it down. It does not interpret, classify, or judge. Everything else in fAI reads from what Capture wrote.
Context, Decision, Pattern and Petnames are the four that watch. Each one looks at the same raw material for a different kind of thing: what you chose and why, what you keep doing, what surrounds the work, and what you call things. They are independent, and in the routing code they are literally called drawers.
Knowledge and Session compose the others. Knowledge opens those four drawers and turns their contents into the sections of a synthesized file. Session opens Capture and Knowledge and produces your session brief. Neither has records of its own worth speaking of; their job is to read the others and write something coherent.
That is the shape worth holding onto: four vaults watching different things, and two more composing what they find.
What happens the moment fAI captures something?
It becomes a commit.
$ git -C ~/.fai/captures rev-list --count HEAD
42162
Capture is deliberately the cheap end. No model runs, nothing is interpreted, nothing is decided about whether the capture matters. It is written down and the session carries on. That is what makes it safe to capture constantly.
Each vault puts what it receives through some of six stages. The thing to know is that these are not six steps of one operation running start to finish. Most of them run on every capture, in milliseconds, and one of them does not.
| Stage | When it runs | What it does |
|---|---|---|
| Discerns | per capture | Raw text becomes typed entities |
| Learns | per capture | Entities get enriched or classified before storage |
| Preserves | per capture | File artifacts get written alongside the records |
| Recalls | per capture | The fields this vault declares get embedded, so they can be found later by meaning |
| Compounds | on a cadence | Reads back what was captured and rewrites the synthesis |
| Persists | per capture | Post-capture maintenance, such as sliding-window pruning |
Only Compounds calls a model. Everything else is bookkeeping, which is why your editor never stalls waiting for fAI to think.
The relationship between two of those stages is the one that matters later. Recalls is a standing declaration: it says which fields of this vault's records should be indexed for search. Compounds is the consumer: when it eventually runs, it searches that index. One writes the index as you work, the other reads it much later.
Each vault chooses which stages it needs, and how those commits get promoted from a working branch to settled state is its own subject.
How does a synthesis pass pick what to read?
By meaning, and the picking is done by the pass itself.
A pass is the Compounds stage firing. It is a scheduled job, not something you invoke, and when it wakes up it has a specific task: rebuild a section of your synthesized context, such as Key Decisions or Conventions & Patterns.
Captures are indexed by meaning as they arrive, with nothing for you to configure. The pass searches that index for whatever is relevant to the section it is rebuilding, and gets back the closest matches rather than the most recent ones.
That is why this holds up over time. A decision you recorded in July can surface in a September pass because it matches the subject, not because it happened lately.
The index is a small database sitting in your workbench. Embeddings are separate from synthesis, and on this machine they run locally:
$ cat ~/.fai/config.json
"Embedding": {
"Type": "ollama",
"Model": "nomic-embed-text:latest"
}
So the embedding of your work never leaves the machine, even when the synthesis model is hosted.
What if there is more to read than fits at once?
It gets split into batches, and how those batches are recombined is the part that matters.
The obvious approach is to summarise the first batch, carry that summary forward, add the next batch, and summarise again. It works, but everything from early on gets re-summarised at every step, so the oldest material quietly fades out.
fAI works the other way round. Each batch is read once, in full, and the results are combined afterwards. If the combined results are still too big, they get combined again, until everything fits. Nothing is repeatedly squeezed, so a detail from the first batch is still there at the end.
How much goes into one batch is set by a token budget, which you can see and change:
$ cat ~/.fai/config.json
"TokenBudget": 96000
When does a pass actually fire?
On a cadence, rather than on every capture.
Captures arrive constantly, so a threshold decides when a pass is worth running, and a pass already running is never stacked on top of itself.
fAI also records a fingerprint of each section's inputs after every pass, so it can tell what has moved since last time. Those fingerprints are not hidden. They sit in your workbench state file, one per section:
$ cat ~/.fai/workbenches/<hash>/'$state.json'
"SectionInputHash": {
"architecture-design": "11f12974664335e4",
"conventions-patterns": "35f1737564ead2f7",
"key-decisions": "fe20f1f73854c72e",
"environment-build": "7227605b112aa43d",
"vocabulary": "a94029373e35aedf"
}
Being able to read them matters more than it sounds. The decision to rebuild a section is a value you can inspect and compare between passes, not a judgement made out of sight.
Which file does all of this end up in?
Three of them, and they are not built the same way.
| File | Where | What it is |
|---|---|---|
FAI-SESSION.md | ~/.fai/sessions/<id>/ | What you are in the middle of right now |
FAI-PROJECT.md | ~/.fai/workbenches/<hash>/ | What is true about this codebase |
FAI-PERSONAL.md | ~/.fai/personal/ | How you work, across every project |
Project and Personal are the same machinery pointed at different scopes. Knowledge opens the four drawers, and each prescribed section declares which drawers feed it. For a project:
Section of FAI-PROJECT.md | Built from |
|---|---|
| Architecture & Design | Decision + Context |
| Conventions & Patterns | Pattern |
| Key Decisions | Decision |
| Environment & Build | Context |
| Vocabulary | Petnames |
Two drawers there feed more than one section. A decision record could belong under Architecture & Design or under Key Decisions, and the routing does not duplicate it or guess. It scores the record against each candidate section and sends it to the nearer one, using the same embeddings that made it findable in the first place.
Personal uses the same four drawers and a different set of sections: Working Style & Preferences, Communication & AI Framing, Tooling & Environment Defaults, and Vocabulary. Nothing about the machinery changes. The scope decides which questions get asked of the same material, and each scope is told explicitly what belongs to the other, so your project file does not fill up with how you like to work.
The session file is built differently, which is why it reads differently. It has no section pages behind it. It is built by carrying a running summary forward, the approach the knowledge files deliberately avoid, and that is the right shape here: a session brief is about what is live right now, so letting older material fall away is the point rather than the problem.
Its headings are prescribed too, and they are the questions you would ask on returning to your desk:
$ grep '^## ' ~/.fai/sessions/<id>/FAI-SESSION.md
## Current Focus
## Active Decisions
## Key Patterns for This Work
## Open Loops
## Vocabulary & Communication
## Environment Quick Reference
Open Loops is the one to notice. A pass derives its recall query from the loops left open in the last seal, so the session brief is pulled toward the work you have not finished rather than the work you happened to do most recently.
What does a rebuild actually look like?
Like a rewrite, not an append.
$ git -C ~/.fai/workbenches/<hash> diff --stat HEAD~3 HEAD
$state.json | 14 +-
.agent-response.md | 2 +-
FAI-PROJECT.md | 745 +++++++++++++++++++-----------------
pages/architecture-design.md | 133 ++++----
pages/conventions-patterns.md | 198 ++++++-----
pages/environment-build.md | 121 +++----
pages/key-decisions.md | 251 ++++++++------
pages/vocabulary.md | 30 +-
8 files changed, 738 insertions(+), 756 deletions(-)
That is one pass. 738 lines arrived and 756 left, so material is leaving on roughly the same order as material is arriving. This one came out slightly shorter; others have come out longer. What it is not doing is accumulating.
Every page moved, and the primary moved with them, because the primary is a concatenation of those pages under prescribed headings with no model involved in the joining.
A sixth section shows up sometimes. ## Coherence Notes has no page behind it and is written by a separate pass that reads every section at once looking for contradictions between them, which is the one job no single-section rebuild can do. It appears only when that pass has actually found something: on this workbench it was carrying two findings a few days ago and is absent today. That pass is its own story; the short version is that it states disagreements rather than averaging them away.
What your assistant is handed at the start of a session is a pointer to the assembled file:
$ fai orient --no-capture
fai session active. Read /Users/you/.fai/workbenches/<hash>/FAI-PROJECT.md
for project context.
That is the whole loop. A capture costs nothing and is never read. A pass selects by meaning, distills without dropping anything, and rebuilds the pages. The file your assistant reads tomorrow is a different file, built from a record that never loses anything.
Install fAI, work for a fortnight, then run git diff on your own FAI-PROJECT.md and read what left.
On macOS or Linux:
curl -fsSL https://www.fathym.com/fai/install.sh | sh
On Windows:
iwr -useb https://www.fathym.com/fai/install.ps1 | iex
Your vault stays in ~/.fai/. Yours to keep.
Read more: Your AI's Context Should Stop Growing ->
Two commands. Your vault loads in under 3 seconds.
deno run -A "https://www.fathym.com/fai/install.deno"New posts on AI workbenches, developer ownership, and compounding intelligence — when they're ready, not on a schedule.