The concept tree: nodes, frontier, and how to read a node page

The concept tree is the spine of this site: every llms file, pack and vocabulary here hangs off a node of it, and every gap in it is a thing not yet researched. Browse it at /tree/; each node has its own page at /tree/<slug>/.

What a node is

A node is one researched concept. The tree is stored as a flat list of nodes linked by name — each node names its parent and its children as strings, not as pointers — so a rename is a one-place edit and a reader can hold the whole file in mind. The site’s copy is generated from concept-tree/tree.json by site/tools/gen_tree.py into src/data/tree.json, which is what both /tree/ and the per-node pages read. Nothing on this site queries the hub at request time.

Frontier is derived, never stored

A frontier concept on this site is a name that appears in some node’s childConcepts and has no node of its own. It is computed on every build from the two sides of that comparison, never stored as a status: a stored status can disagree with the tree, and a derived one cannot. Research is what removes such a name from the frontier — writing a node for it — and nothing else.

The hub itself derives frontier from two sources, and this site publishes only the first. hub/scripts/concept_tree.py merges child references with the unchecked rows of concept-tree/RESEARCH_QUEUE.md — a concept a person queued by hand, which the hub tags source: "research-queue" rather than source: "child-reference". The site’s snapshot copies concept-tree/tree.json and not that queue, so site/tools/gen_tree.py can only implement the child-reference half. Everything /tree/ and /tree/3d/ count as frontier is therefore a child reference; a concept queued by hand and named by nobody’s childConcepts is frontier in the hub and invisible here.

Frontier children are shown greyed and are not links, because there is no page to link to. They are listed on their parent’s page under Frontier under this node.

The fields on a node page

FieldMeans
conceptthe node’s name, and the string its parent and children link it by
slugits URL segment; stable, and the key the API in step 3 will use
parentthe concept it hangs from — linked, unless the node is a root
childrenthe concepts it names, each either researched (linked) or frontier (greyed)
aliasesother names the same concept goes by; the filter matches these too
researchedAtthe date the research run that created the node finished
sourcesCounthow many sources that run read
conceptsCounthow many concepts that run identified under this one
skillIdthe skill the research produced, when it produced one
stateresearched for every node with a page; frontier only for a named child without one

sourcesCount and conceptsCount describe the run that created the node, not the tree: a node with nine concepts and two children is a node whose run found nine and whose author has since written up two.

How the filter works

The filter box on /tree/ matches a substring against each concept and its aliases, and a branch survives if it or any descendant matches — so filtering hides non-matching branches without ever hiding the path to a hit. That is the rule the hub-manager Concepts tab uses, widened to aliases, which are exactly the names a reader who does not know ours will type.

The tree is small enough to ship whole: the page embeds the generated JSON and filters it in the browser, so there is no request per keystroke and the page works with JavaScript off — the filter is the only part that needs it.

What is not here yet

Queueing a frontier concept for research, forking the tree, and attaching your own files to a node are per-user actions, and this site has no accounts yet. The read-only half — the tree, the node pages, the 3D view — is served as build-time JSON rather than from an API, because it changes only when the hub changes.