The thoughts system
This is a machine for turning something half-said into something that holds up. It is built out of refusals — it will not write an essay from an idea that has not been pushed on, it will not publish one nobody has read, and it will not let a link exist that no sentence earned.
Six things, in the order each one has to be true before the next makes sense. Everything below is live: the numbers are the real ones, and the demos are the actual rules running in your browser.
01 — the input
A thought starts as a capture: I talk into my phone, and the words commit to
version control as they are. Not tidied, not summarised. It lands in thoughts/_inbox and
that file is then permanent — everything downstream is derived from it rather than replacing it.
This is the load-bearing idea, and it is why nothing is ever lost. If the reduction later turns out to be wrong, the thing it was reduced from is still sitting there.
There is exactly one way in. Not because more inputs would be worse ideas, but because two half-working inputs are worse than one working one: neither ever gets finished.
02 — the first derivation
The capture stays exactly as spoken. A seed is written from it — a title, a couple of sentences, and an address other thoughts can already link to. Under 200 words, deliberately: padding a stub toward essay length is the specific failure this whole thing exists to prevent.
“okay so crazy idea here, um, every tool that took over some thinking job got accused of making us stupider and the ceiling just… kept going up anyway, so maybe the accusation is the wrong shape”
committed · verbatim · never editedEvery tool that took over a cognitive task was accused of making us stupider, and the ceiling kept rising anyway.
a name and an address400–900 words, once it has cleared everything below.
both of the above still exist03 — the ladder
A thought is a position, not a document — so the stages are
seed → proposed → standing → retired: I have not worked this out → here is a
write-up, put to me → I stand behind this → I no longer do.
An essay is 400–900 words, target 650. Over 1500 it is two thoughts wearing one title. The band between 200 and 400 is the awkward middle — too real to be a stub, too thin to publish — and it is the band the interview exists to push an idea out of. Ask a model “is that 400 words?” and it says yes, so nobody asks: it is counted.
standing and retired can never light up by typing, and
that is the rule rather than a quirk of this demo: no model may set them. A write-up arrives as proposed and waits for me to press Accept. That is what makes standing mean “I read this” rather than “a model was happy with it”.
And retired does not mean deleted. A retired thought keeps its page, its URL and
its place in the graph, marked. The URL was public; unpublishing it would rewrite the record rather
than correct it.
04 — the gate
Length is necessary and nowhere near sufficient. Before a single word of the essay is written, the idea has to have cleared these — and the check happens before any of the writing starts, which is the entire point of having it.
Watch what weak does. Half a counter-argument blocks exactly like a missing one,
because “sort of” is how a thin thought sneaks through.
How it connects is the one that reports without blocking, and the reason is specific: the first thought in a collection has nothing to link to, and a manufactured edge to satisfy a checklist is precisely the failure the graph is meant to avoid.
05 — the part everyone gets wrong
People expect one dial, so this is the slippery bit. Stage asks “have I read it”. Visibility asks “may anyone else”. They are independent, and a thought reaches the site only if both say yes.
The default is private, and that is the safety property rather than
a preference: a file that never mentions visibility cannot reach the internet. An absent value must
never mean “publish this”. The loader refuses a configuration whose default would publish, so the
fail-closed behaviour cannot be switched off even deliberately.
06 — the graph
There is no “related” field and no “see also” list. An edge exists because a
sentence in one thought needed to point at another, written inline as
[[the exact title]]. Backlinks are derived. At most 4 links per thought, because past that
the graph is a hairball and it usually means two thoughts.
A link to a title that does not exist is not an error — it becomes a hollow node, so the graph doubles as the to-write list. Which creates one genuinely nasty failure, and it is the reason this demo is here rather than a prettier one.
And then
Once a thought is standing it can be rewritten for the ear — 2.5–7
minutes at 145 words a minute, which is where a video comes from. Only from
standing: a script built on an argument that might still change is a video built
on sand. The floor is derived rather than picked — the shortest legal essay is 400 words, which is
2.8 spoken minutes, so a 3-minute floor would have made it unscriptable.
mind, tools, inquiry, systems, culture, craft — because the tag picks a node’s colour on the graph, so a seventh means re-picking the palette. Not taste, a constraint.
The title is the label next to a node, and it is also the URL. Long ones collide, and the address must not encode anything that changes.
One file, lifecycle.json, is read by the validator, the linter, the site build and
this page. That is what makes the rules the same rules everywhere — and what makes this page unable to lie
about them.
A thought names what it came out of in its front matter, and the sources page runs that backwards — each book, paper or podcast says which thought came out of it. That reverse question is the whole reason a source is a file and not a repeated string.
Every demo above is the real arithmetic running in your browser. The rules are pure functions, so they run in a page as happily as they run on the API.
See the actual graph The sources Home
Stages, word bands, goal posts, tag palette and speaking rate on this page are generated from server/lifecycle.json at build time. The word count is the same function the linter enforces with, cross-checked against the server’s on every run of the corpus checker.