Source packs: the citation manifest that gates your build
The unit of fact honesty in an AI content pipeline is not the article. It is the source pack: a small manifest listing every cited fact the article is allowed to state, each entry a claim, an exact value, and a source URL. The writing step is constrained to it, and no-fabricate gate enforces it at build time, so the manifest is not documentation of what you hoped happened. It is the boundary of what can ship.
The shape: claim, value, URL
A source pack is a JSON file with two keys. The "sources" array holds the cited facts: each entry pairs the claim being made, the exact value as it may appear in copy, and the URL it comes from. The README's worked example records the value "41%" against the claim "share of enterprises with AI in production" and its study URL. The "ignore" list holds regex patterns for numbers that are yours rather than claims about the world: your own prices, your own version strings. Those never need a citation.
The gate requires the claim and the URL alongside every value, by design. Without them the manifest would decay into a bare allowlist of numbers, and an allowlist proves nothing. With them, the manifest doubles as the citation record for the page: every figure in production has a named source you can hand to anyone who asks "says who?".
Matching that survives real HTML
Served pages do not present statistics the way manifests record them. Inline markup splits a figure from its unit, and formatting inserts commas and whitespace. The gate normalizes both sides before comparing: matching is case-insensitive, comma-insensitive, and whitespace-insensitive, so a value recorded once in the manifest keeps matching after templating, emphasis tags, and number formatting have done their work.
Structural numbers are exempt automatically, years, ordinals, listicle counts, and section references, so the gate stays quiet on the numbers that are part of how documents are organized rather than claims about the world.
The pipeline: research writes it, the gate enforces it
The pattern the gate is built for has three steps. First, research produces the source pack: real figures, from real URLs, recorded before any prose exists. Second, the writing step receives the manifest as its entire numeric universe, with an instruction to use no number that is not a value in it. Third, the gate runs pre-publish, in a pre-commit hook or a CI job, and blocks anything the writing step invented anyway.
The third step is the one that matters. Steps one and two describe intent; models drift from intent. The gate is what converts "the draft should only use sourced numbers" from a hope into a property of the build. A prompt rule without a gate is a suggestion.
The exit code is the contract: 0 when every data-claim traces to the manifest, 1 when any figure is unsourced, and 2 on a usage or manifest error. The error case fails closed on purpose: a malformed manifest refuses to pass the build rather than silently approving everything.
Start on an existing site
You do not need to pause publishing to adopt the pattern. Run the gate with the non-blocking flag to get a baseline of every unsourced statistic already in your content, then work the list: source the figures worth keeping, cut the ones nobody can stand behind, and move your own prices into the ignore list. When the baseline is clean, drop the flag and let the exit code hold the line from then on.
- node cli.mjs --manifest sources.json --warn-only ./public (audit: list unsourced claims, exit 0)
- node cli.mjs --manifest sources.json ./public (enforce: exit 1 on any unsourced claim)
Keep reading, then get the source.
- no-fabricate gate: what it is
- Why AI invents numbers, and how to catch it
- Why it is safe to install
- The same pattern for style: de-AI gate in CI
- View the source on GitHub
no-fabricate gate is open source under the MIT license. Write your first source pack and let the build enforce it.
Get no-fabricate gate on GitHubFAQ
Who writes the source pack?
Whoever does the research, human or agent. The point of the shape is that it is written before the prose: the research step records real figures with real URLs, and the writing step is constrained to them. Recording a source is a deliberate act, which is exactly what fabrication is not.
What goes in the ignore list?
Numbers that are yours rather than claims about the world: your own prices, your own version strings. They are configured as regex patterns in the manifest, never hardcoded in the gate, so what counts as "yours" stays a per-site decision under version control.
What happens if the manifest itself is broken?
The build fails. A missing sources array, an entry without a claim, value, or URL, or a malformed ignore list is a usage error with its own exit code, distinct from an unsourced-claim failure. The gate fails closed: it never treats a broken manifest as permission.