Cairn

Notebook

Splitting the tool from the graph

For most of its life Cairn was one repo: scripts/ and nodes/ side by side. That is the right shape for a tool with exactly one user, and the wrong shape the moment anyone else wants it — because a tool for recording research decisions can be shared, and a research record cannot.

So there are two now, and two variables:

variablemeansholds
$CAIRN_PATHthe tool bin/ scripts/ skills/ docs/ site/
$CAIRN_ROOTa graph — yours nodes/ papers/ meetings/ inbox/ build/

Confusing them is now the first thing that goes wrong, which is a real cost. In exchange, one tool can serve several graphs, and a pre-split clone keeps working unchanged, because CAIRN_ROOT falls back to the tool repo when it is unset.

The cost, named before it was discovered

One thing the conflation was genuinely buying: git log attributed tool commits and node commits in one history, so “what changed in Cairn the week I wrote that node?” was one command. After the split it is two.

That is worth writing down rather than finding out later and calling it a regression. The graph repo kept its full history — 61 commits — and the tool repo was filtered to the 28 that touch the tool, which is why the contemporaneity numbers in build/report.md are still computed from the graph's own log.

What the split forced into existence

Two things, and both were overdue:

And one question it opened

Where does Cairn's own design record live? Those nodes are the tool's rationale and the best possible demonstration of what the tool is for — a real graph with real dead ends, which no synthetic example can be. Carrying them in the tool repo is far more attractive than leaving the public repo with no example graph.

It is also not free. Those bodies name internal hosts, an internal GitHub, a dozen project keys, per-project token figures, and one internal platform's architecture. Publishing them is a content review, not a copy.

Hence cairn export_example, which does two things a cp would not: it rewrites internal hostnames through an explicit table, so what leaves is deliberate rather than whatever happened to be in a host: field; and it refuses — grepping the selected bodies for things a human has to clear, printing them with file and line, and writing nothing until the review is acknowledged.

A flag in a script is not a review. The flag exists to make the human's pass explicit, not to replace it — publication is not recoverable by apologising afterwards.