Recipe 11 — Building a topical file
Goal
Build a file about a concept rather than a site: every fact the pool holds about
“prompt caching” (or “cookies”, or “llms.txt”), from every source, filed under the
subject’s child concepts, deduplicated, with disagreements kept visible. The result is a
/t/<slug>/ family — llms.txt + llms-facts.txt + manifest.json — served beside the
source-axis families and listed under ## Topics on the root index.
When not to use it
- One source covers the concept completely. A source-axis family already has that page; link to it.
- The pool has no units about the subject. The builder will produce a file of
## Sharedand nothing else; extract first, or widen the pool. - You want a full concept pack (facets, vocabulary, concept graph). That is the abstractor
(
/lca), which uses this builder as one step.
Steps
-
Gather the pool. Any mix of
units.jsonl,llms-facts.txtandreference.mdfiles. The subject must be a concept-tree node; its children become the sections. -
Build. Assignment runs keyword → file-affinity → embedding centroid →
## Shared;--no-embedskips the centroid step and costs no embeddings.PYTHONPATH=scripts .venv/bin/python -m docset_refine topical \ --from outputs/exports/docs.claude.com.llms/llms-facts.txt \ --from outputs/exports/platform.openai.com.llms/llms-facts.txt \ --from outputs/exports/openrouter.ai.llms/llms-facts.txt \ --subject "prompt caching" \ --out llms-topical/prompt-caching.llms/ \ --base-url http://127.0.0.1:8788/t/prompt-caching \ --register--registerwritesllmsFileonto the tree node so the node page and the MCP lookup know the file exists. -
Read the assignment.
manifest.jsonrecords how many facts each section took and how many fell to## Shared. A large## Sharedmeans the children are wrong or missing — a tree question, not a builder bug. Hand edits go inmanifest.overrides, which survives a rebuild (generate, don’t edit). -
Test it as an agent would. The lint’s deterministic passes first, then the agent test: the optimizer hands a model the file and a bank of questions about the subject and counts how many it answers in at most two hops.
.venv/bin/python scripts/llms_lint.py check llms-topical/prompt-caching.llms/ --json /ldo llms-topical/prompt-caching.llms/llms.txt --agent-test -
Serve.
llms_serve.pypicks the directory up at/t/prompt-caching/…and lists it under## Topicson the root.
Expected output
llms.txt with an H1 naming the subject, a blockquote stating the source count and the
pool, and one H2 per child concept, each link carrying its unit count; llms-facts.txt in
the unit grammar with every line keeping its original source anchor — a fact from the
OpenAI docs still points at platform.openai.com. Where two sources make competing claims
the lines sit together under the same section; in this step neither is dropped, and the
precedence ladder is the designed mechanism for choosing.
manifest.json for a three-source pool of a few thousand units typically shows most facts
assigned by keyword, a minority by centroid, and a ## Shared in the low tens.
The agent test reports N/10 answered in ≤ 2 hops; the bar the optimizer uses is 8 for an
index.
Cost
Estimated: the build is seconds for a few thousand units with --no-embed, or one
embedding per unassigned unit without it (the centroid step embeds only what keyword and
file-affinity did not place). The agent test is the only model spend — a bank of ten
questions, each a short model call — estimated at a few tens of thousands of model tokens
per run, to be replaced by the CI-measured figure when the runnable examples land.
Runnable in step 4 (playground).