RepoFold generates documentation wikis from GitHub repositories. Early in the project I learned the lesson that shaped its entire architecture: the failure mode of AI documentation is never missing information. It is confident, wrong information that reads as right.
The first version produced beautiful pages. It also documented an authentication middleware the repo never had, described a retry mechanism that did not exist, and invented a configuration option complete with a plausible default value. A human reviewer would need to know the codebase deeply to catch any of it, and someone who knows the codebase deeply does not need generated docs.
So the rule became: no sentence ships unless it can prove itself.
Citations as a data format, not a suggestion
Every generated page must ground its claims in citation tokens with a fixed format:
The worker downloads the repository tarball and hashes every
blob before analysis begins [[cite:worker/pipeline.ts:42-88]].A token points at a file path and a line range in the indexed commit. In the rendered wiki it becomes a link that opens the actual source, so a reader can check any statement in one click.
The obvious approach is to put "always cite your sources with real line numbers" in the prompt. We do that. It is nowhere near enough.
Prompting is a request. Validation is a guarantee.
Models comply with citation instructions the way toddlers comply with bedtime. Across thousands of generated pages we have seen every variant of creative non-compliance:
- Citing plausible line numbers that point at whitespace or an unrelated function
- Citing the README for claims about code behavior
- Citing module directories or package names instead of files
- Citing files that were mentioned in a summary but never provided as source
- Perfect-looking citations for claims the cited code does not support
The fix is a deterministic validation pass that runs before any page is published. It does not ask the model to behave. It checks the output against a parsed model of the repository:
- The path must exist in the indexed commit, as a file. Directory and module citations are rewritten to plain links or dropped.
- The line range must be real and must overlap a symbol that the parser (tree-sitter, not regex) actually extracted from that file: a function, class, type, or method.
- Citations that fail are demoted, not silently kept: the claim loses its specific range, falls back to a file-level citation, or is flagged so the page regenerates.
A second fact-check pass rereads high-stakes pages (architecture, API reference, getting started) against the raw source and corrects claims the material does not support. The model writes; the machine verifies.
This split turned out to be the whole trick, and it generalizes: any rule you care about must be enforced in code, not requested in a prompt. We relearned this repeatedly. Asking the model to reuse unchanged text verbatim during updates? It rewords anyway; we now splice unchanged sections byte-for-byte in code. Asking it to avoid a punctuation habit? It complies for three paragraphs; a post-processor guarantees it forever.
Staying true is harder than being true once
A verified wiki that slowly drifts from the code becomes exactly the thing it replaced. So RepoFold re-syncs on every push, which creates a new problem: cost. Naively regenerating a wiki on each commit multiplies your inference bill by push frequency.
The update pipeline is tiered by how much actually changed:
- Nothing relevant changed: the page is skipped by comparing input hashes. Zero model calls.
- Only code moved: if the prose inputs are identical and cited code just shifted position, citations are re-anchored by matching symbols between the old and new parse, with no model call at all. The re-anchoring is strict: same name, kind, and signature, consistent offset, and full revalidation afterwards, otherwise it falls through to regeneration.
- A section changed: the model returns a patch naming which sections need rewriting; unchanged sections are spliced from the previous version byte-for-byte, so output cost scales with the size of the change instead of the size of the page.
- Everything else: full regeneration, which after the first index is the rare case.
Measured on this repository: the first index of 178 files costs about $0.12, a typical commit costs one or two cents to process, and a trivial change costs under a cent. Those numbers are the difference between per-push documentation being a demo and being a product.
What this does not solve
Honesty requires admitting the boundary. Validation proves that a claim matches specific lines of code. It does not prove those lines are the authoritative implementation. In a messy monorepo with generated clients and duplicated types, a claim can be technically true against the wrong copy. We filter generated and vendored code at ingest (build directories, lockfiles, codegen patterns, "@generated" markers) and rank sources by their position in the import graph, which handles the common cases, but "which file is the source of truth" is a judgment that currently emerges from heuristics rather than being explicit. That gap is real and it is next on the list.
The other boundary: the wiki documents what the code does, not what anyone intended. If the code and the intention disagree, the wiki sides with the code. We consider that a feature.
Try it
RepoFold is in free beta. Connect a repository and read documentation about your own code where every sentence carries its proof: repofold.dev. If it gets your codebase wrong, that is exactly the feedback the beta exists for.