Your coding agent is good at reading code.
Point Claude Code or Cursor at a repo
and it will figure out the language, the framework, the build command — it just costs you tokens and a few tool calls every session to re-derive what it forgot.
What it can't read is the part that isn't in the code: who the project is for,and why it exists. So it guesses. Confidently, in the same tone it uses for the facts it actually verified.
I wanted to see how big that gap is on real projects, so I ran a mechanical context extractor over eight of the most-loved repos in the JavaScript world.
The method
faf git <url> clones a repo and fills in a small typed context file (project.faf) from what it can find — README, package.json, project structure, config. No hand-authoring, no LLM writing prose. It fills what's there and leaves the rest blank. Nine-ish slots: the identity (name, goal, language) and the six W's — who, what, why, where, when, how.
Run it yourself: npx faf-cli git https://github.com/facebook/react
The result
| repo | extracted | who |
why |
|---|---|---|---|
| facebook/react | 56% | — blank — | — blank — |
| vercel/next.js | 44% | — blank — | — blank — |
| expressjs/express | 50% | — blank — | — blank — |
| colinhacks/zod | 67% | — blank — | — blank — |
| sveltejs/svelte | 88% | — blank — | — blank — |
| prettier/prettier | 75% | — blank — | — blank — |
Eight repos in total (React, Next.js, Express, Zod, Hono, Svelte, Vue, Prettier). Every one of them: who is this for and why does this exist came back empty. Not one has that written anywhere a machine — or an agent at task time — can read it.
Svelte scored 88%. The who and why are still blank. This isn't a documentation-quality problem, and it's not a knock on any of these projects. The stack lives in the files. The intent lives in maintainers' heads, design docs, old RFC threads, and Discord history — none of which your agent has open when it's editing a file.
Why the two halves behave differently
The scores range from 44% to 88%, and that whole spread is one thing: how much stack the repo exposes in config files. Svelte's monorepo setup fills seven stack slots (framework, runtime, build, CI…) and lands at 88%. React's root exposes one, and lands at 56%. More config → higher score.
So the recoverable half — language, framework, build — varies 2× across these repos. A cold agent can dig all of it out; you just pay for the dig, every session, in tokens and latency.
The unrecoverable half doesn't vary at all. who and why came back empty in every one of the eight, regardless of repo size, fame, or documentation.
No amount of spelunking through src/ tells you that a library was built to replace one specific painful pattern, or that it targets library authors and not app developers, or that an architectural choice you're about to "clean up" was deliberate. That information was never committed in a form the agent can consume.
So the agent fills the blank with a plausible story. On React it'll probably land close. On your internal service, or a library with a subtle audience, it won't — and it'll refactor accordingly, with confidence.
The fix is about ten minutes
faf go walks a maintainer through the six questions once, writes the answers into project.faf, and you commit it. From then on every agent — Claude Code, Cursor, Codex — reads the same authored context instead of guessing, and it's one file that projects out to CLAUDE.md, AGENTS.md, .cursor/rules/ so
those can't drift apart.
faf-cli's own project.faf looked much like these until someone sat down and filled it in. React's team could close their gap in a single commit.
(The first project.faf I ever wrote was for a Svelte app — which makes it a little funny that sveltejs/svelte topped this table at 88% and still can't tell an agent who Svelte is for.)
If you want the number
Fill the gaps first with faf go, then faf bench measures the delta directly: it asks a model the questions about your repo cold, then again after reading project.faf, and grades the answers mechanically (no LLM judge). Questions are derived from the populated slots — the .faf is the answer key — so a repo that still has who/why blank can't be graded on them; that's what faf gois for. The delta is the accuracy your agent is leaving on the table, and where the cold misses cluster tells you which parts of your project only exist in your head.
npx faf-cli go # fill project.faf (the ten minutes)
npx faf-cli bench questions # the questions, derived from your repo
npx faf-cli bench grade answers.json --cold
npx faf-cli bench grade answers.json --faf
A low cold score isn't a verdict on the model. It's a diagnosis that the project is under-described for an agent to work in — and the output ends in faf go, not a leaderboard.
Notes: faf git's percentage reflects how much is in the repo, so a high score means good docs, not a good tool — and the who/why blanks are honest, the information genuinely isn't there to extract. project.faf is one typed source (the .faf format is an IANA-registered media type,application/vnd.faf+yaml) that the per-tool context files are generated from, rather than another markdown file to maintain by hand.
Top comments (2)
This hits home from a different angle — I ran into the exact same thing on the
product side with llms.txt. Before I wrote an explicit "here's what this is, who
it's for, running since when" file, LLMs would describe my platform with total
confidence and get the basics wrong: wrong founding year, inflated numbers pulled
from stale copy. The fix was literally your thesis — the who/why lives in the
maintainer's head, and until you write it down machine-readable, the AI just
guesses convincingly.
Curious how you see project.faf sitting next to llms.txt — same core idea (explicit
intent for machines), but repos vs products/sites? Feels like they'd want to
converge rather than compete, not fight over who owns the "who/why".
That’s the same miss on the published product. Until who/why is written down, the model invents a year and a number and says it like a fact.
I don’t see them competing. llms.txt is the site door. project.faf is the repo door. Same human facts. The maintainer owns who/why — neither file does.
.faf could project an llms.txt the same way it already faces out to AGENTS.md / CLAUDE.md. Write the answers once.