build log · 26 entries · in progress

Colophon CMS: the build log

A content management system that can prove what it published and survives being killed at any moment. Rust and Svelte, built in the open, one proven milestone at a time.

Latest · P3 · 3.5: The Studio, designed

  1. D design 2 entries
  2. P0 foundation 7 entries
  3. P1 never lose an edit 8 entries
  4. P2 publish exactly once 4 entries
  5. P3 prove it reached the site 5 entries
  6. R roles you define next
  7. M content you can shape next
  8. P4 time travel next
  9. E editorial parity next
  10. DX developer parity next
  11. P5 safe automation next
  12. P6 running on its own next
tests 251 at 3.5

0.13.5

Colophon is a content management system: the place where you write, review and publish a website’s articles. In a book, the colophon is the note at the back that says how, when and by whom it was printed. Colophon does that for a website: every publish becomes a numbered release, with a record of exactly what went live and where it was seen.

I’m building it in Rust and Svelte with Claude Code, in the open, and writing up every step here, including the mistakes. My own site will be its first real user.

The promises it has to keep

  • Kill it at any moment, lose nothing. No saved edit disappears, no publish happens twice, no reader sees half of one.
  • Every bug is a number you can replay. Thousands of simulated runs with crashes and network trouble on every change; a failure comes with a seed that reproduces it exactly.
  • Time travel. See the whole site as it was at any release. Rolling back is just a new release.
  • Receipts, not spinners. “Published” only means published. The site update shows as pending until it’s actually seen.

The rules it lives by

  • Proof over features. A feature counts when its failures are tested, not when its screen exists.
  • No AI hype. Scripts and AI agents get safe, limited access. The headline is reliability.
  • Everything has a limit: time, retries, queue sizes, memory and disk.
  • No bragging without numbers. No speed claims until a benchmark with raw data backs them up.

Where it stands: the foundation (P0), the editing core (P1) and publishing (P2) are done, and P3, proving a publish reached the site, is nearly there: a cache that can’t serve an old release, unpublishing that reaches CDNs, a receipt for every publish, a site built from one release, and a Studio with a design of its own. Colophon can sign people in, keep each project’s content apart, save drafts that can’t be lost, handle two people editing the same article, review the exact change, and publish it as one numbered release, with background work that survives a crash. Content types and URL names are being finished now, and roles are becoming something owners define.

The goal got bigger in October: every feature Strapi and Sanity offer, a proper role and permission system, and a Studio simple enough for people who aren’t developers, all held to the same standard of proof. That’s about 9 to 12 months of work. It isn’t a CMS you can use yet: nothing runs anywhere but my laptop and CI. The plan and the code are public on GitHub at akira-shirase-oss/colophon-cms.

D design

Reading a 41-section spec, cutting it down to four promises, naming it, and writing the whole plan down before any code.

  • D.1 experiment
    A 41-section spec, cut to four promises

    I started with a complete specification for a CMS, with a shop, subscriptions and AI included. The first job was deciding what not to build.

  • D.2 experiment
    A name from the back of a book

    Naming the project, choosing a design system, and writing down how every part works and fails before writing any code.

P0 foundation

Pinned tools, an empty workspace that passes its checks, the local stack, and an editor whose output Rust can verify.

  • 0.1 experiment
    The compiler that ignored my instructions

    Pinning a Rust version takes one small file. On my laptop, that file was being silently ignored. So Colophon's first check makes sure its checks are real.

  • 0.2 experiment
    Healthy is not the same as working

    Colophon's local stack: a database, a cache, file storage and sign-in, all started with one command. Docker said every service was healthy, so I broke one on purpose to see whether anyone would notice.

  • 0.3 experiment
    Five million requests, and the bug they didn't find

    Colophon learned to say when something's wrong: one error format, honest health checks, a separate frontend that tests it, and load tests in the millions. The millions found nothing. The frontend found a bug on day one.

  • 0.4 experiment
    An editor that would rather refuse than lose a word

    Colophon's writing editor and the format behind it. The editor opens a document only if it can give it back byte for byte, because the library underneath quietly throws away whatever it doesn't understand.

  • 0.5 experiment
    The guard at the only door

    The editor keeps honest writers honest. The server has to stop everyone else. Colophon's validator refuses all 34 bad test documents with exactly the right error and location, and checks 71,000 documents a second.

  • 0.6 experiment
    The moment text becomes a web page

    Colophon's renderer turns a stored article into the page readers see. There's one of it, it refuses rather than guesses, and a test reads back everything it produces to make sure nothing in it can run.

  • 0.7 release
    Colours that pass the test

    Colophon's design system: Material 3 colours generated from one blue, checked for contrast in every theme by CI, and an accessibility scanner that found two real problems on its first run. With this, the foundation milestone is done.

P1 never lose an edit

Saves that either succeed or clearly fail, safe conflicts between two editors, and projects that can't see each other.

  • 1.1 release
    Signing in

    Colophon now knows who is asking: sign-in through a real identity provider, sessions only the server can end, and projects that the database itself hides from everyone but their members. Plus the first load test that has to talk to the database on every request.

  • 1.2 release
    A draft that can't be lost

    Colophon now saves articles. Every save is a new revision that can never be changed, a save on top of someone else's is refused instead of overwriting it, and the server can be killed just before or just after a save without losing it or saving it twice.

  • 1.3 release
    Two editors, one article

    The Studio now edits real drafts. It saves as you type, keeps your unsaved words on your own device, and when someone else saved first it shows both versions and lets you choose, instead of quietly overwriting anyone.

  • 1.4 release
    The first simulator run

    A simulator that runs thousands of repeatable, randomized days of editors colliding, answers going missing and browsers crashing, checking after every step that no acknowledged save was lost. It caught every bug I planted, agreed with the real database save for save, and found a real one in the Studio.

  • 1.5 release
    Content types you define

    Colophon stops assuming every entry is an article. A project defines its own content types (text, rich text, numbers, booleans, choices, dates), the server checks every entry against its type, a type can only change in ways that keep every stored entry valid, and the Studio draws its editor from the type.

  • 1.6 release
    The command line

    Colophon gets a command line. You sign in by approving a short code in the Studio, and then the terminal creates and lists exactly the same records the Studio edits, safely retried, with exit codes scripts can rely on. With this, the spec's first slice works end to end.

  • 1.7 release
    Inviting people

    Colophon stops being a one-person tool. An owner invites someone with a link that works once, the invitee sees exactly what they're joining before they join, one small table decides what owners, developers, editors and publishers may do, and a project can never be left without an owner, even when two owners step down at the same moment.

  • 1.8 release
    The first owner

    Signing in to Colophon no longer lets you create anything. The person who runs the server makes the first administrator once, from a terminal, and nobody can do it a second time; only administrators create projects, and everyone else arrives by invitation. With this, the first milestone's proof gate is met.

P2 publish exactly once

Reviewed changes become one numbered release, and background work survives being killed halfway.

  • 2.1 release
    Approving the exact change

    Colophon gets review. A changeset pins the exact versions of the entries in it, an approval is tied to a fingerprint of exactly that set, and editing anything afterwards means it has to be approved again. Two people can't approve a version neither of them is looking at.

  • 2.2 release
    One release, one number

    Colophon can publish. An approved changeset becomes a numbered release in a single step, two releases racing for the same number can't both win, anyone can read what's published (including any earlier release, exactly as it was), and the code that serves the public reads through a database account that can't see drafts at all.

  • 2.3 release
    Work that survives a crash

    Colophon now tells the outside world when it publishes. A background worker announces every release to your webhooks, keeps trying when they're down, gives up cleanly when they refuse, skips an older release once a newer one is queued, survives being killed halfway through, and only ever calls public addresses.

  • 2.4 release
    Killing it on purpose

    A simulator now races publishers, crashes workers and scrambles the network thousands of times a run, and a crash loop really kills the server over and over while it publishes. Building the simulator found a real ordering bug in the previous step; it's fixed, and neither the simulator nor the crash loop finds anything lost or doubled. The second milestone is done.

P3 prove it reached the site in progress

Caching that can't serve the wrong thing, and a receipt for every publish. The first public demo.

  • 3.1 release
    A cache that can't serve the wrong thing

    Colophon's public API now has a cache, built so it can't hand out an old release by mistake: every answer is filed under the exact release it came from, the current release is always checked against the database, a thousand requests for the same thing cause one database read, and if the cache dies, answers keep coming straight from the database.

  • 3.2 release
    Taking it back

    Colophon can now unpublish. A takedown is reviewed like any change, the server stops serving the article at once, even through links to old releases, and every CDN in front of it is told to drop its copies. Until a CDN confirms, the release says the removal is still pending.

  • 3.3 release
    A receipt for every publish

    Every release now gets one honest label: published in the CMS, website update pending, verified at so many locations, or needs attention. Probes look for each release from outside and keep what they saw, so 'verified' always comes with evidence and says where from. Along the way, logging finally named a slowdown CI had been tripping over for two steps.

  • 3.4 release
    A site built from one release

    Colophon now runs a real website: every release is built into a static site where every page says which release it is, checked, and swapped in all at once, so a reader never gets half a release. A probe then reads the live page, and the release's receipt says the site really shows it. It runs on my laptop for now: before it goes public, the Studio gets designed properly.

  • 3.5 release
    The Studio, designed

    The Studio got a design of its own, twice: the first one looked like every other generated dashboard, so I rebuilt it from a reference I liked. Editors can now search titles, see what's live and what changed, compare versions and review exact diffs. And the load test that seemed to say the redesign made saves slower turned out to be measuring my laptop's ever-growing test database.

  • 3.6
    Content types you can change

    Being built now.

  • 3.7
    Plain words, and publishing in one click
  • 3.8
    My site goes live, and the first public demo

R roles you define

Owners decide exactly who may do what, down to a field, and every path checks it the same way.

  • R.1
    Roles stored as data, and nothing else changes
  • R.2
    Roles you define, in the Studio
  • R.3
    Permissions down to a field, and “only their own”
  • R.4
    API tokens and an audit log

M content you can shape

References, reusable groups, lists and page builders, as Strapi and Sanity offer them, kept valid as they change.

  • planned
    References, reusable groups, lists and page builders
  • planned
    Migrations you can dry-run and approve

P4 time travel

Browse the site as it was at any release, roll back safely, and upload images without risk.

  • planned
    The release slider
  • planned
    Rollback is just a new release
  • planned
    Image uploads that can't hurt anyone

E editorial parity

Everything an editorial team does in Strapi or Sanity: languages, schedules, review stages, comments, live updates.

  • planned
    Every language its own version
  • planned
    Review stages, comments and tasks
  • planned
    Lists that update as others edit

DX developer parity

Queries, GraphQL, a typed SDK, webhooks and imports from Strapi and Sanity, through the same permissions.

  • planned
    A query API, GraphQL and a typed SDK
  • planned
    Import from Strapi and Sanity

P5 safe automation

Scripts and AI agents can help at a limited scale, and can never skip review.

  • planned
    Tokens with limits
  • planned
    An agent that can't approve its own work
  • planned
    Bulk edits that survive being interrupted

P6 running on its own

Backups, a real restore, upgrades, a 24-hour stress test, and version 0.1.

  • planned
    Backups, and a restore that actually works
  • planned
    A 24-hour stress test
  • planned
    Version 0.1

← Home