Dialogues

April 19, 2026



What does it means to “publish” a blog post anymore? Once published, a post represents what I thought on that date. The back catalog is stale. But I keep musing and updating my thinking. Open source business models, growth engineering, customer engineering---these are conversations I’ve been having for years, with different people, and yet my posts remain frozen. Fine, if you think of a blog as a log, but what is that like for a new person (or agent) getting acquainted with me?

I wanted two things. First, the ability to resume a topic. Not write a new post that vaguely references an old one, but actually pick up where I left off, with the latest version always being my current thinking. Second, I wanted the process visible. Not just what I think now, but how I got here---which conversations changed my mind, which prompts from Claude sharpened an argument, which coffee chat made me rethink a paragraph.

The writing dialogue on my recent posts already showed the prompt-by-prompt drafting process with Claude. But those were stored as giant YAML files alongside each post---a parallel data structure that duplicated the content and had to be maintained separately. It worked, but it was brittle and manual.

Then I realized: git already tracks exactly what I want. Every edit to a post is a commit. The commit message can carry metadata---who I was talking to, what prompted the change, what type of input it was. The diff between commits is the evolution. I was maintaining a second system to track something my first system already did.

How it works

A dialogue is just a markdown file with a git history. Each commit that changes the file is an entry. The commit message carries structured metadata as git trailers:

I think taste and legibility are one and the same actually

taste is judged by other humans. legibility is convincing
other humans that you have taste.

With: Claude

The With: trailer names who or what precipitated the change---could be Claude, could be Sarah Chen <[email protected]>, could be Paul Graham. Commits without a With: trailer still show up in the timeline, but only as dates---silent edits with visible diffs.

The build pipeline

At build time, a script walks git log for each post file, parses the trailers, extracts the content at each commit, and writes a JSON file. Astro reads that JSON to render the dialogue viewer---the side panel on posts and the full /writing/{slug}/ pages.

The script caches against the latest commit hash per file, so npm run dev stays fast on repeat starts. In CI, the GitHub Actions workflow checks out with full history (fetch-depth: 0) and generates fresh.

A prepare-commit-msg git hook pre-fills the trailer template when I commit a post file, so I don’t have to remember the format.

Why not a database? Why not YAML? Why git?

Because the data is the history. Every version control system already stores exactly this---who changed what, when, and why. Adding a database or sidecar file to track changes to a file that’s already tracked by git is a category error. The commit message is the natural place for metadata about a change. The diff is the natural representation of what changed. I was building a shadow of a system I already had.

The tradeoff is commit message discipline. Every meaningful edit needs a well-written message with the metadata trailers. That’s a real cost. But it’s also a forcing function---it makes me think about why I’m changing something, not just what I’m changing. The git log becomes a publication artifact, not just a development tool.