The shape of the thing

A document goes in once. What comes out is a set of facts, each of which still knows where it came from.

Retrieval-augmented systems usually cut a document into chunks and hope an embedding finds the right one. A chunk has no idea what it asserts, which version of the product it is talking about, or whether the paragraph three pages later contradicts it.

RTFM separates four things that are normally collapsed into one: the source (the document as it was), the observation (what was seen in it), the claim (a single statement the document makes) and the evidence (what supports it). Keeping them apart is what makes a citation checkable later.

What a fact carries

Every stored fact answers these questions before an agent has to ask.

Statement

One assertion, in one line. Not a paragraph, not a chunk.

Subject

What the statement is about, as an id in the graph — so facts about the same thing gather, whatever words each document used.

Applies to

The version or scope the source attached to it. “For 1.5” and “for 2.0” are two facts, and an agent can tell them apart.

Source

Which document, and which revision of it. The pack carries a `locator` field for the position inside that document; the pipeline records one on extracted evidence today, and it is not yet filled in on every fact.

Confidence and maturity

How sure the extractor was, and how far the fact has come through review. Extracted is a proposal; verified is a deliberate human act.

Polarity

Whether the source asserts the statement or denies it. A denial is a fact too, and losing it turns “X is not supported” into “X”.

Provenance survives editing

A citation that stops being checkable the moment someone edits the file is not provenance.

Sources are versioned. When a document changes, the previous revision is kept as an immutable snapshot instead of being overwritten, and facts drawn from it keep pointing at the revision they were taken from.

So a quote captured in March can still be verified against the March text, even after the document has moved on — and the difference between “the source changed” and “we read it wrong” stays visible.

Standing: not all documents are equal

When two documents speak to the same point, the one that governs should win — and it should be obvious why.

Normative

A document that is in force: a contract, a specification, a decision record. It outranks the rest.

Historical

A record of what was once true: a changelog, a report, minutes. Useful, and explicitly not current.

Reference

Outside material. The default, because nothing becomes authoritative by accident.

The role and the date of a document are stated once, on the source, and each fact points at it by id. Repeating that pair on every fact would be duplication in a payload someone pays tokens to read.

What is missing is stored too

Absence of knowledge is not the same as falsehood, so RTFM records it.

A knowledge gap is a first-class entity: a subject, the open questions about it, and a priority. When a query lands on a subject with open gaps, they come back in the pack — the agent is told what is not known, instead of being left to guess whether silence means “no” or “nobody wrote it down”.

Disagreements are kept

Two sources contradicting each other is information, not a bug to hide.

When a new fact contradicts a stored one, RTFM does not overwrite it. Both are kept and flagged as conflicting, and both come back in the pack with the documents behind them. Deciding which is right needs context the system does not have; presenting the disagreement is the honest move.

Superseding is a separate, deliberate act. Nothing is deleted — a withdrawn fact is archived and stays readable on purpose.

What an agent gets back

The whole reply to a question, in the shape `rtfm_facts` returns — the same structure over MCP and over HTTP. Nothing in it was written by a model.

rtfm_facts — the shape of a response
{
  "question": "does Simple support guest checkout?",
  "found": true,
  "note": "",
  "subject": "module:opencart/simple",
  "subject_title": "Simple",
  "facts": [
    {
      "id": "claim:opencart/simple--opencart-simple-docs-2cdea105",
      "statement": "Simple supports guest checkout without account registration",
      "subject": "module:opencart/simple",
      "polarity": "assert",
      "applies_to": null,
      "source": "source:opencart/simple-docs",
      "locator": null,
      "confidence": "medium",
      "conflicting": true,
      "conflicts_with": ["claim:opencart/simple--vendor-simple-review-2cdea105"]
    },
    {
      "id": "claim:opencart/simple--opencart-simple-changelog-3b215e37",
      "statement": "Simple 2.4 adds a one-click express checkout option",
      "subject": "module:opencart/simple",
      "polarity": "assert",
      "applies_to": "2.4",
      "source": "source:opencart/simple-changelog",
      "locator": null,
      "confidence": "medium",
      "conflicting": false,
      "conflicts_with": []
    }
  ],
  "sources": [
    {
      "id": "source:opencart/simple-docs",
      "title": "OpenCart Simple documentation",
      "authority": "normative",
      "date": "2026-03-11",
      "dated": true,
      "version": 3,
      "uri": null
    },
    {
      "id": "source:opencart/simple-changelog",
      "title": "OpenCart Simple changelog",
      "authority": "historical",
      "date": "2026-05-02",
      "dated": true,
      "version": 1,
      "uri": null
    }
  ],
  "open_gaps": [
    {
      "id": "knowledge_gap:opencart/simple-knowledge",
      "title": "Needs knowledge: module:opencart/simple",
      "subject": "module:opencart/simple",
      "gap_status": "open",
      "priority": "high",
      "questions": ["What does the licence cost?"]
    }
  ],
  "conflicts": []
}

Illustrative values over the demo canon, not a captured transcript; every field shown is one the payload really carries. found=false with an empty facts list is the honest refusal: nothing cleared the threshold, and there was no generator to paper over it.