On this page

Chapter 1 of 7. No prerequisites. This course documents the editorial pipeline that turns one site's engineering devlog into published articles, and this opening chapter names the problem the whole system exists to solve: the graveyard of notes that never became posts.

Every developer who writes has the same directory somewhere. A notes app, an Obsidian vault, a drafts/ folder in a blog repo. It holds forty ideas, a dozen half-written openings, three pieces that are "basically done" and have been basically done for months. Nothing in it ships. The directory is not a backlog. It is a graveyard, and it grows.

This course is about a system built so that directory never forms. Not a productivity framework and not a prompt pack: an editorial pipeline, built in public on this site, that takes raw engineering notes at one end and produces published, cited articles at the other, instead of letting them settle into a graveyard. It has state machines, gates, an audit trail and a database, and every one of those parts exists because a simpler version failed first. Chapter 1 does one job: name the finishing-problem precisely, then name the shape of the system response, so the next six chapters can build it.

The graveyard is normal

Start with the comforting part: this is not a personal defect. The pattern shows up wherever developers talk about writing. One Indie Hackers post, titled "After 8 months of drafts, I completed my first blog post", puts a number on the shape of it: "During these 8 months, I have accumulated a handful of partial drafts and 30 or so ideas for posts." Eight months. Thirty ideas. One published post. That ratio is the graveyard in a single sentence, and it is not an isolated post; similar confessions recur across Indie Hackers.

The notes themselves are usually good. That is what makes the graveyard painful. A typical resident looks like this. The note below is a composite, not a transcript of a real incident, but you almost certainly have its twin:

## incident: the deploy that wiped prod assets
- FTP action had clean-slate flag left on after first deploy
- second deploy nuked uploads/ that the build didn't own
- fix: flag sequenced, true once then false forever
- TODO: write this up properly, it's a great story

Everything an article needs is there: a concrete incident, a concrete fix, a lesson that generalises. And the note sits untouched from the day it was written, with "write this up properly" doing the work of a tombstone inscription.

Why the first half is free and the second half costs

The honest version of the pain, at least as I have lived it: writing is fine from zero to about fifty percent. Capturing the idea costs nothing. Sketching the outline is pleasant. Drafting the opening paragraphs rides the energy of the incident being fresh. Then the piece hits the second half and stalls, because the second half is not writing. It is a chain of decisions.

What is the actual thesis, as opposed to the topic? Which claims can the notes back, and which need cutting? Does the voice sound like you or like a press release? What is the title, the slug, the publish date? Which older post does this contradict? Each decision is small. Together they form a wall, and in my experience perfectionism patrols it. The draft that is eighty percent done can still become anything, so it is safe. The published post is finished and fixed, so it can be judged. Keeping the draft at eighty percent is how a perfectionist protects it, indefinitely.

The obvious modern shortcut fails here too. Handing the half-draft to an LLM and asking it to finish produces text, and the text has a recognisable smell:

In today's fast-paced development landscape, deployment mishaps are more
common than you might think. In this post, we'll explore what happened,
why it matters, and the key takeaways every developer should know.

The Write that blog! survey by Cynthia Dunlop (181 respondents) measured the gap: "only 13% of those using LLM writing reported that the generated drafts sound like them." The finishing decisions the model made are generic because the model made them, and voice is a finishing decision like all the others. This course's companion, Writing AI prose that doesn't read like AI, spends seven chapters on that specific failure. This course attacks the layer underneath it: even a perfect voice cannot rescue a piece that never reaches the point of shipping.

So the diagnosis has two parts. Perfectionism supplies the resistance. The absence of a durable system supplies the opportunity, because willpower is being asked to make the same finishing decisions from scratch for every single piece, and willpower loses often enough that the graveyard fills.

A writing system for developers who want to publish more consistently

The response documented in this course rests on one structural move: separate the writing into three layers, and make the connections between them explicit.

  1. The devlog. One append-only markdown file per repository. Every entry is mechanical: a date, a type and scope, a subject line, a dense paragraph of what actually happened. Newest first. History is never edited; a correction is a new entry citing the old one. This layer has no quality bar to clear and no audience to fear. That is exactly why it never stalls: capture is cheap by design.

  2. The gate. A six-step editorial process that stands between notes and prose: Triage, Propose, Clarify, Draft, Edit, Ship. The load-bearing rule is that a thesis gets agreed before any prose exists. Drafting from an approved thesis removes most of the finishing decisions from the moment of finishing; they were made earlier, when they were cheap.

  3. The articles. Published posts, each one citing the specific devlog entries it draws from. The citation is recorded in a small local database, so the system always knows which notes have become articles and which are still raw material. The store is a single SQLite file that travels with the project; the SQLite documentation's own case for a database file as an application file format is the case for it here, and chapter 6 opens the schema.

The database matters for one reason above the others: it makes every idea's status explicit. When a topic is triaged, it receives one of four verdicts. Upgrade means proceed to a thesis. Leave means an existing post already covers it, intentionally. Skip means the source notes are too thin. Defer means good candidate, not now. Notice what is missing from that list: there is no named state for "sitting in a folder at eighty percent". An idea that closes, closes with a recorded verdict. Be precise about what that buys, because it is less than it sounds. An idea can still stall in a non-terminal state, agreed in principle and waiting on a draft that never arrives, and in this system's own history some did exactly that. What the verdicts buy is visibility: a stalled idea is a row you can query, with a reason attached, not a file you have quietly stopped opening. The machinery that then goes after the stalls, the sweeps, alarms and recovery rules for a missed slot, is what chapters 5 and 7 build.

Recording is not publishing

Here is the part that earns this chapter its honesty. The pipeline this course documents had the graveyard problem itself, at the system level, and the numbers are on the record in the post-mortem published on this site.

The article-scheduling layer shipped across six sprints. Sprints one to four built the mechanism to record a schedule. Sprint two shipped a pure free-text time parser with, per the devlog, "no external behaviour change yet". Sprint three wired the first user-visible controls: a schedule button on every finished draft, opening a six-option menu. Sprint four completed the loop: tap the button, reply "tomorrow 09:00" or "+3h" or a full timestamp, and the queue database gained a row with state scheduled.

And nothing fired. Four sprints of working, tested, demonstrable software, and not one article reached the site through it, because recording an intention and executing an intention are different subsystems. Only sprint five built the executor: a sweep daemon that wakes on a cadence, finds rows whose publish time has passed, and dispatches them, with a publisher lock so two sweep cycles cannot double-fire the same article. The sprint-five devlog entry says it plainly: "Scheduled articles now actually fire." Sprint six then hardened the edges.

The post-mortem names the pattern: record and execute have different failure modes. Recording fails through parsing and state-machine bugs. Execution fails through sweep intervals and lock races. Bundling both into one sprint makes every failure ambiguous, so splitting them was correct. The trap is stopping after the recording half, because the recording half demos beautifully. A row with state scheduled looks like progress. It is a note in a graveyard wearing a database schema.

Your notes app is the same architecture with the executor missing. It records flawlessly. Tags, backlinks, folders: a rich schema for intentions. Nothing sweeps it. No process wakes up, finds the note whose time has come, and pushes it toward publication. The lesson this system learned in six sprints is the lesson of the whole course: capture is necessary and capture is not the bottleneck. The bottleneck is the machinery that picks a note up and refuses to put it down until it reaches a terminal state.

No note dies without a verdict

Pull the threads together and the system response to the finishing-problem is three commitments.

First, capture is unconditional. The devlog takes every incident on the day it happens, in mechanical format, with no quality judgement attached. A finishing-problem cannot form at a layer that has nothing to finish.

Second, finishing is front-loaded. The gate forces the expensive decisions, thesis first among them, before drafting begins. A draft produced from an approved thesis has one job left: say the agreed thing well. That is a smaller wall than the one perfectionism patrols in a free-floating draft.

Third, every idea is driven toward an explicit end. Shipped, or skipped with a reason, or deferred with a reason, or left with a reason. The verdicts are recorded, so the question "whatever happened to that post about the deploy incident?" has an answer that is not a shrug at a folder. And where an idea stalls short of its verdict, the later layers of the system are built to notice.

None of this requires the automation the later chapters describe. All of it is what the automation enforces when willpower is having a bad week, and the rest of the course is the build. Chapter 2 constructs the capture layer: the devlog format, the parsing rules, and the triage that turns raw entries into candidates. Chapter 3 walks the six-step gate in detail. Chapters 4 and 5 cover voice enforcement and the human veto inside an automated flow. Chapter 6 opens the database: the tables and state machines that make "no note dies without a verdict" a schema constraint instead of a slogan. Chapter 7 ends at the sharp end, where a missed 09:00 slot has to become a decision instead of a silence.

The graveyard is normal. It is also optional. The difference is a system, and the system starts with the file you append to tomorrow morning.

// EXERCISE

Give every draft a verdict

Inventory your own graveyard and drive every item to an explicit state. Create a devlog.md in one active project using the append-only entry format, then list every existing draft, note and half-finished post you own and assign each exactly one of the four verdicts: upgrade, leave, skip or defer. Record each verdict durably, in a file or a table, with a one-line reason attached.

Expected behaviour
  • A devlog.md exists in one of your repos with at least three entries in the dated, append-only format, newest first
  • Every item in your drafts folder or notes app has exactly one recorded verdict: upgrade, leave, skip or defer
  • Each skip and each defer carries a written reason, and each defer carries a resurface date
  • No item remains in an unnamed limbo state; the count of unverdicted drafts is zero

PROVE IT Open your verdict record and answer, for any single old draft, the question: whatever happened to that post? The answer must come from the record, in one sentence, without opening the draft itself.

// CHECKPOINT — GRAVEYARD
multiple choice · auto-checked

Why does the devlog layer never stall the way a drafts folder does?

exact answer · auto-checked

The article-scheduling layer shipped across six sprints. Which sprint finally built the executor, the sweep daemon that made scheduled articles actually fire?

open · self-checked

The chapter calls a queue row with state scheduled a note in a graveyard wearing a database schema. Explain what that row is missing.

Show answer

Recording an intention and executing it are separate subsystems with different failure modes. The scheduled row proves the recording half works, but until an executor sweeps the queue, finds rows whose time has passed and dispatches them, nothing ships. A notes app has the same architecture with the executor missing: it records flawlessly and no process ever picks a note up and drives it to a terminal state.

↺ re-read: “Recording is not publishing

Lived experience

Sources

  • SQLite As An Application File Format
    SQLite Consortium (sqlite.org)
    Backs the choice of a single local database file as the pipeline's citation and status store introduced in this chapter
    sqlite.org
Back to guide overview