Entry 1
The format is the asset, so the spec is written down first
Documented in The cairns spec, cairns.toml, The entry, log.json, Publishing.
Filesdocs/spec/crates/cairns-core/src/
The worklog format grew up inside
hellbender as tools/worklog.py plus a
skill, and it works - 55 entries, a generated index, numbering that holds. What
it could not do is leave that repo. Three things were tangled in the one skill
file: the format, the tool, and fifteen hard-coded areas, several of them
specific to one 1996 game. Only the first of those is worth sharing, so this
project separates them and writes the format down as a spec under docs/spec/
before implementing any of it.
The tool is one implementation. A worklog whose tooling is lost is still a worklog, which is the whole reason the markdown stays the source of truth and nothing here needs a database.
What got decided
Rust, one binary. The original is 200 lines of Python and the port buys
nothing on its own; it buys distribution. Anyone handed a binary runs it, and
the core compiles to wasm32 with --no-default-features, which is what keeps
a future hosted version a deployment rather than a rewrite.
The static site renders from log.json, not from the markdown. One path
from entries to structured data, so a second reader can never disagree with the
first about something subtle in an output nobody is looking at. It also means
an ingest contract can be designed against real payloads before any server
exists - publish --target hosted --dry-run prints the request body today.
Front matter is not YAML. It is a strict key: value subset, defined in
entry.md, with no quoting, nesting, blocks or comments.
A real YAML parser reads it correctly, but that is a convenience rather than a
promise. The subset has exactly one reading and cannot grow ambiguity, which
matters more for a file format meant to be legible in twenty years than
nesting nobody needs.
An entry's id is {project}/{number}, not the number. Costs one line of
config now; retrofitting it invalidates every URL already handed out the moment
two projects sit in one place.
content_hash is the SHA-256 of the file's bytes, so it verifies with
shasum -a 256 and no knowledge of this format at all. It is what lets a
publish send only what changed, and it works identically for a local directory
and for an ingest endpoint that does not exist yet.
No secrets in cairns.toml. A token must be an environment variable
reference beginning with $, and check fails on a literal - catching the
leak in the commit that introduces it rather than after the push.
What is built
cairns-core parses and validates entries and builds the canonical document.
cairns-site renders a payload from it, which today is log.json alone.
The command surface is settled - new, next, index, check, open,
build, export, publish, init, migrate - and the read half of it
works. The write half is the parity port, and it is not built yet.
whether the derived first-sentence summary is good enough in practice, or whether entries will need summary: written by hand often enough that the tool should prompt for it.