By ·

Spec files for agents deserve an editor that renders

Spec files for agents deserve an editor that renders

Most of my working day is a 13-inch screen with a markdown file on one side and a terminal on the other. An agent runs in the terminal. The markdown file describes what that agent should build. It is not a note, it is the input, and my text editor assumes a person will read prose later.

A spec or context file I write for an agent is closer to a program than to an essay, which is why I want the editor for it to render the structure instead of showing me asterisks.

I tried the official Milkdown extension for VS Code first, because I already liked Milkdown and it is the editor in my blog’s CMS too. It renders markdown properly. What it does not do is fit: 120px of padding sits on each side of the text, sized the way a documentation site is sized. Half a 13-inch screen leaves a column so narrow that a table wraps mid-word and a heading runs to three lines. So I forked it.

What I write in these files

1.00

A new agentic project of mine starts with a corpus, not with code. One main document saying what the project has to do, then subfolders of documents saying what each module or system inside it has to do. The split is not even. I pick the few pillars that genuinely need human guidance and write those out properly, because those are the places where an agent left to itself guesses wrong in ways that cost a day. Everything else gets a short note and room to move.

Three properties fall out of writing it that way:

  • The agent reads a slice of the corpus per task, not the whole of it, so the structure of the documents ends up being the structure of the work.

  • The document outlives the conversation. A chat context is gone by the next session; a spec file is on disk tomorrow, and it is where the next session gets pointed.

  • I can review a spec as I review code, because its structure is visible. A 200-line document with four headings and a table reads differently when the table is a table.

What Milkpad is

A fork of Milkdown VSCode, published as Milkpad, with the editor engine underneath left alone. My blog’s CMS runs the same engine, which is coincidence and not the reason: I already liked how Milkdown writes, and the fork exists because the extension around it would not fit in the pane where I work. Four days of work, 54 commits, most of them made with agentic coding tools. The changes are the visual layer, plus rendering raw HTML that the engine otherwise prints as tags. The source is on GitHub.

Three decisions and what they cost

Making it fit the pane

The engine stays untouched and the fixing happens in the numbers around it: content padding split into a left and a right value (44px and 8px, down from 120px on each side), four sizing dials for headings, body text, the floating toolbar and the block handle, and a block handle stacked vertically so it costs one button of width in the gutter instead of two.

What that cost: the upstream theme is hardcoded px with no rem anywhere, so there is no root font size to turn and each size that has to change gets enumerated by hand. That list belongs to me now, and it will not grow itself when the engine ships something new. The left padding also has a floor under it, because the block handle lives in the gutter to the left of a block, and below about 44px it lands off the edge of the pane with nothing left to grab.

Rendering the markup

1.00

Some of my files carry markup and not markdown: an avatar strip, a small table, a badge. Milkdown treats raw HTML as characters, so those files showed me tags where a picture should have been, and markup I cannot see is markup I cannot check. The fork draws it as markup, with an edit box behind each block that shows the source and takes edits as you type.

What that cost: the moment an editor draws whatever a file contains, the file is untrusted input. A markdown file can arrive from anywhere, and an image tag carrying an error handler would execute inside the editor. So anything executable is stripped before it renders, and the whole editor runs under a content security policy that permits no network requests at all. A sanitiser and a policy are mine to look after now, which is more surface than I set out to maintain. One limit I have not fixed: a bold tag used mid-sentence styles nothing, because a raw tag stands alone as its own node and only a paragraph that is entirely markup gets rebuilt into one block.

What rendering hides

This is the half that costs me something. Once a document renders, the syntax producing it stops being visible, so a file I edit is saved back in the editor’s habits and not mine: list bullets become asterisks, a run of blank lines collapses to one, a bare web address picks up angle brackets. All of it renders identically. The diff of a file I touched, though, is not only my edit.

The unflattering parts

1.00

No test suite exists. CI checks formatting, lint and types and then builds the package, so what is checked is style, and nothing verifies behaviour.

Nobody but me has used it. It went up on the Marketplace this morning, so this is a day one post: no issues filed, no second installer, nothing past my own use. Anything I say about someone else’s setup is a guess.

Part of what it advertises came free with the engine. The feature list covers full GFM support and maths support, among others, and I have not walked that list one item at a time.

One fix inside it lives in a patch to a dependency, with nothing in my source to show for it. The image block stores three things in the two fields markdown offers, so it writes the image ratio into the alt text and reads the ratio out again, and saving a document therefore replaced real alt text with a number. The first save I made turned “profile picture of Saul Mirone” into “1.00”. Repairing that properly meant patching the dependency, and the patch is pinned to one version on purpose, so the next upgrade of that package stops the install instead of dropping the fix in silence. A stopped install is the failure I want there, though it does mean maintenance will arrive as a broken build.

And the small one that keeps biting: editing my own README in Milkpad rewrites its list markers, my CI checks formatting, so two commits in that repository exist only to run the formatter over a file the editor had saved.

Right now

It is my default, installed as the editor for markdown, and it will get changes as bugs and improvements turn up. Nothing is on that list today, which I read as a good sign and not a finished one. I hope people use it, and find it as good as I am finding it.

If you write specs or context files for agents in markdown, what is worth trying this week is not a different model. Open one of those files somewhere it renders. The corpus and the rendering are separate decisions, and the second one needs no fork. If you want the one I ended up with, it is on the Marketplace.

What transfers

1.00

When the writing is the input to a machine, the writing surface joins the toolchain. Nobody reviews code in an editor that hides its structure, and a document an agent reads deserves the same treatment. That stopped being abstract for me here: I forked an editor because 120px of padding on each side left nothing readable beside the terminal, and the useful half of the result was seeing the file’s structure, not making its text prettier.

Related reading