devlog
A technical narrative, not a diff. Generate a Hacker News-style article as a single self-contained HTML file that explains what changed, why, and what to watch out for. The reader is a developer already familiar with the project — they don’t need an intro to the tech stack, they need to understand the change and make judgment calls about it.
This skill exists because code is no longer a sufficient level of abstraction for reviewing AI-generated changes. Reading every line is too slow; reading only the PR title is too shallow. The devlog sits in the middle: enough detail to catch architectural mistakes, enough narrative to stay in the loop, enough visuals to build intuition fast.
Read references/style-guide.md before writing anything — it encodes the writing rules, diagram constraints, and anti-slop patterns that keep the output from drifting into vague corporate summary.
Step 1 · Gather the material
Before writing, collect the raw material. The user will point you at one of:
| Input | What to gather |
|---|---|
| A pull request / diff | Changed files, commit messages, any linked issue or ticket |
| An agent plan | The plan document, any referenced code or architecture |
| An existing concept | The relevant source files, docs, or prior discussion |
| Code files or directories | The actual code, its structure, what it does and why |
If the input is ambiguous — “explain what the agent did” with no pointer — ask which changes or which plan. One question, not a form.
Skim the material for: (1) what problem this solves, (2) what approach was taken and why, (3) what the key implementation decisions were, (4) what’s risky or worth scrutinizing. These become your article sections.
Step 2 · Write the article
Read references/style-guide.md now. Then write the article as a story, not a report.
The one rule: it’s a story, not a summary
A devlog is a Hacker News post — someone telling the story of a change to a peer who missed the meeting. It has a beginning, a middle, and an end. A PR summary lists what changed; a devlog makes the reader feel the problem first, then walks them to the resolution.
The tell that you’ve written a summary instead of a story: interchangeable, fact-stating sections (“What and why”, “How it works”, “Key code”) that could be shuffled into any order without loss. If your draft survives reordering, it’s a changelog. A story doesn’t — each beat sets up the next, and pulling one out breaks the chain. Write the chain.
The beats below are a narrative arc, not buckets to fill. Don’t label sections after them (“Section 4: the resolution”); let the headings be assertions that carry the story forward.
The narrative arc
1. Headline + hook. An assertion-style title (not “Auth changes” but “JWT tokens now rotate on every refresh, closing the session-fixation gap”). Then one sentence that makes a scanning reader want the rest.
2. Open on the problem — the world before the fix. Put the reader where the thing was broken. What was the concrete symptom? What was quietly at stake — money, correctness, a blind spot nobody could see, a 3am page? Make them feel the pain before you show the patch. This is the cold open, and it’s exactly where most devlogs fail by jumping straight to the solution. Reference the ticket naturally if there is one.
3. Show why it was harder than it looked. The complication — why the obvious fix doesn’t work. A constraint, a false start, an assumption that broke, two things that turned out to be in tension. This beat is what separates a story from a changelog: it’s the tension the resolution will release. If there genuinely was no obstacle, explain what made the problem subtle instead — but there’s almost always an obstacle, and finding it is the job.
4. Walk to the resolution — what really changed. Now, and only now, the fix. Tell it as the payoff to the tension you just built, not as a feature list. Answer the question the reader is actually holding: what does the world look like after, that it didn’t before? Keep the change itself as the through-line — weave code and diagrams in as evidence inside the narrative (“here’s the line that does it”), never as a catalogue of everything touched.
5. Be honest about the loose ends. Every real change has soft spots — a guessed constant, a new dependency, a convention bent, an untested path, a threshold that’s really a placeholder. This is the story’s honest turn, and it’s what makes a devlog worth reading before you approve the change, not after. Keep it visually distinct (the scrutiny box) so a reviewer can find it fast, but write it as a continuation of the story, not a QA form. Be specific: name the function, the concrete risk, and what to check. Never “there may be edge cases” — name the edge case.
6. Land it. Close on the one thing worth remembering: what was deliberately deferred, what alternative was rejected and why, or the insight the whole change turned on. Short — a beat or two. End on a point, not a trailing bullet list.
Beats 2 and 4 are the spine — problem and resolution — and are always present. Fold 3 into 2 when the change is small. Beat 5 is required whenever there’s real code to review; skip it only for a pure plan with nothing concrete to scrutinize yet.
Write for visual thinkers
Assume the reader thinks in pictures. Default to showing over telling: when a concept has a shape — a flow, a topology, a before/after, a state transition, a decision tree — draw it rather than describing it in a dense paragraph. A good devlog gives every major idea a visual anchor the reader’s eye can land on while scanning.
This shifts the diagram bar upward from the old “only when nothing else works.” Reach for a diagram whenever it helps the reader see the change — which is most non-trivial changes. The before/after pair is especially powerful and underused: show the old world and the new world side by side, and the change explains itself. Aim for the top of the diagram counts in the calibration table, not the bottom.
A diagram does not have to earn its place by adding information the prose lacks. A diagram that simply re-draws what a paragraph just said is welcome — visual thinkers read the picture and the words as one pass, and the redundancy reinforces rather than wastes. So pair prose with a visual freely; you don’t have to choose.
The only bar that stays: a diagram must be true and legible — it faithfully depicts something real about the change, readable at a glance. What to cut is the meaningless diagram: boxes that misrepresent the actual topology, or pure decoration with no content (see the style guide’s diagram anti-patterns). Reinforcing the prose is good; misleading or empty is not.
Visuals aren’t only SVG. Use the whole toolkit to break up walls of text and let structure be seen at a glance:
- Before/after diagrams for anything restructured — the single highest-value visual.
- Comparison tables when the story weighs options, states, or outcomes against each other.
- Annotated code — a pointed inline comment on the one line that matters beats a paragraph pointing at it.
- Callout boxes (the scrutiny box, or a short highlighted aside) to make the honest turn and key insights visually distinct.
- Whitespace and short paragraphs — a visual reader bounces off a 12-line block. One idea per paragraph, generous rhythm.
Weaving in code and diagrams
Code and diagrams serve the story; they never interrupt it or get collected into an appendix.
- A code snippet lands at the moment the narrative needs to show the decision — 10 meaningful lines max, with a file-path + function label, and 2-3 sentences that read as part of the story even if the code were deleted. Show the lines that carry the decision; elide the rest with
// .... - A diagram lands wherever the reader benefits from seeing a shape — a topology, a flow, a before/after — whether or not the prose already described it. Pairing a visual with the paragraph that explains it is encouraged.
Never build a “key code” section or a diagram gallery. Place each fragment exactly where the story reaches for it, then keep telling the story.
Length calibration
Shorter is better; respect the reader’s time. A tight story beats a complete one.
| Change size | Prose words | Diagrams | Code snippets |
|---|---|---|---|
| Small (bug fix, config change) | 400–700 | 0–1 | 1–2 |
| Medium (feature, refactor) | 800–1200 | 1–2 | 2–4 |
| Large (redesign, new service) | 1200–1800 | 2–3 | 3–5 |
| Plan (no code yet) | 600–1000 | 1–2 | 0–2 |
Guides, not rules. A 500-word devlog that nails the problem-to-payoff arc beats a 1500-word one that covers every file. Skimmable in under 5 minutes; total HTML roughly 300–600 lines.
Step 3 · Build the HTML file
The output is a single self-contained HTML file. No external dependencies, no build step, no CDN links. It opens in any browser and looks clean.
HTML template structure
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{headline}}</title>
<style>
/* see CSS rules below */
</style>
</head>
<body>
<article>
<header>
<p class="eyebrow">devlog · {{date}}</p>
<h1>{{headline}}</h1>
<p class="lede">{{one-liner summary}}</p>
</header>
<!-- sections as <section> elements -->
<!-- diagrams as <figure> with <svg> and <figcaption> -->
<!-- code as <div class="code-block"> with <pre><code> -->
</article>
</body>
</html>CSS design rules
The visual design is minimal, warm, and readable. No gradients, no shadows, no rounded cards. The content is the interface.
Root tokens:
--bg: #fafaf8 warm off-white
--text: #1a1a1a near-black
--text-2: #555 secondary text
--text-3: #888 tertiary / metadata
--accent: #e8590c warm orange — used sparingly (links, focal diagram elements, eyebrow)
--accent-bg: #fff7ed accent tint for highlighted code/boxes
--border: #e5e5e0 subtle warm gray
--code-bg: #f5f5f0 code block background
--mono: 'SF Mono', 'JetBrains Mono', Consolas, 'Liberation Mono', monospace
--sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif
--serif: Charter, Georgia, 'Times New Roman', serif
Layout:
articlemax-width 720px, centered, generous vertical rhythm (1.7 line-height for body)- Body text in
--serifat 17px — this is for reading, not scanning - Headings (
h2,h3) in--sans, moderate weight - Eyebrow in
--mono, small uppercase,--accentcolor - Code blocks:
--monoat 13px on--code-bg, 1px--border, slight horizontal scroll for long lines. Include a small filename label above the code block in--text-3. - Diagrams: full-width within the article column,
<figcaption>in--serifitalic below - Scrutiny section: a subtle left-border accent (
--accent, 3px) to visually distinguish it
Responsive:
- On narrow screens (<640px), reduce article padding, let code blocks scroll horizontally
- SVG diagrams use
viewBoxand scale naturally
Diagram rules
Read references/style-guide.md § Diagrams before drawing. Summary:
- All diagrams are inline SVG within the HTML. No Mermaid, no JS libraries, no images.
- Show over tell, and reinforce freely. Draw a diagram wherever it helps the reader see the change — including when it just re-visualizes what a paragraph already said. The only diagrams to cut are inaccurate ones and pure decoration.
- One idea per diagram. Max 9 nodes. If you need more, it’s two diagrams.
- Focal rule: 1-2 elements in
--accentcolor, everything else in neutrals. The focal element is the new/changed component. - Arrow endpoints land exactly on node edges. All coordinates divisible by 4.
- Clean, not decorative. No drop shadows, no gradients, no rounded corners above 6px, no decorative icons. If it takes effort to decode the diagram, it’s losing.
- Label everything: boxes, arrows, data flow directions.
- Use
viewBoxfor responsive scaling. Typical:viewBox="0 0 700 340".
Diagram types to use:
| Showing | Diagram |
|---|---|
| System components and how they connect | Architecture (boxes + arrows) |
| Request/event/async flow with ordering | Sequence (vertical lifelines) |
| Data moving through a pipeline | Flow (left-to-right boxes + arrows) |
| State transitions | State machine (circles + labeled arrows) |
| Before/after comparison | Side-by-side architecture or flow |
| Layer relationships | Stacked layers |
For sequence diagrams, use a simple SVG layout with vertical dashed lifelines, horizontal arrows with labels, and activation boxes. Not a full UML sequence diagram — just enough to show who calls whom in what order.
Code snippet formatting
<div class="code-block">
<span class="code-label">src/auth/token.ts → rotateToken()</span>
<pre><code>async function rotateToken(session: Session): Promise<Token> {
const old = session.token;
const fresh = await signJWT({ sub: session.userId, jti: randomUUID() });
// Atomic swap: the old token is invalidated the moment
// the new one is persisted, preventing replay.
await db.transaction(async (tx) => {
await tx.revoke(old.jti);
await tx.persist(fresh);
});
return fresh;
}</code></pre>
</div>Rules for code snippets:
- 10 meaningful lines max per snippet, followed by 2-3 sentences of prose explanation
- Show only the lines that carry the decision — trim boilerplate, imports, obvious setup
- Use HTML entities for
<>&inside<code>blocks - Add a file-path + function-name label above each snippet
- If the full function is long, use
// ...to elide uninteresting parts - Write the prose so it reads coherently even if the code block were removed. The code illustrates; the prose explains.
Step 4 · Save and present
Save the article as a single self-contained HTML file named from the headline slug:
devlog-jwt-token-rotation.htmldevlog-cache-invalidation-redesign.htmldevlog-auth-migration-plan.html
Unless the user names a location, save it somewhere they’ll find it — the repo root, the current working directory, or the Desktop — and give them the full path so they can open it in a browser. If a hosted preview would help, offer to publish it as an Artifact.
Do not narrate the file creation process. Do not explain what you’re about to do. Just build the article, save it, and give the path.
Anti-slop checklist
Before finishing the HTML, verify:
| Check | Fail if |
|---|---|
| Specificity | Any sentence could describe a different PR. Name the actual functions, the actual files, the actual trade-off. |
| Assertion titles | Any heading is a label (“Authentication”) rather than a claim (“JWT tokens now rotate per-refresh”). |
| No throat-clearing | The first sentence of any section is filler (“In order to improve…”). Start with the real claim. |
| Reads like a story | The sections could be reordered without loss — it’s a summary, not a narrative. Rewrite so each beat sets up the next. |
| Problem before patch | The article opens on the solution. Open on the pain first — make the reader feel the problem before the fix appears. |
| Diagram is true, not empty | A diagram misrepresents the real topology or is pure decoration. Cut it. (Restating the prose is fine — reinforcement is welcome.) |
| Code earns its place | A snippet shows boilerplate or obvious code. Cut it, show the interesting part. |
| Scrutiny is honest | The “what to scrutinize” section is vague (“there may be edge cases”). Name the edge case. |
| No invented facts | Any metric, version number, or claim isn’t directly from the source material. |
| Prose stands alone | Remove all code blocks and diagrams — does the article still make sense? |
| Length check | The article takes more than 5 minutes to skim. Cut. |
Tone
Write the way you would explain this to a fellow engineer — someone smart and curious who works on the same project but wasn’t in the room when this decision was made. Casual but informed. You can be funny — a wry aside, a self-deprecating parenthetical — but the humor should emerge from the technical reality, not be stapled on.
Things to do:
- Explain why the obvious approach doesn’t work before showing what you did instead
- Be honest about uncertainty, false starts, and things that feel hacky
- Use concrete language: “the token expires after 15 minutes” not “the token has a configurable expiration”
- Show your reasoning, not just your conclusion
Things to avoid:
- Marketing language or hype (“revolutionary”, “cutting-edge”, “seamless”)
- Hedging that adds no information (“it’s worth noting that”, “interestingly enough”)
- Explaining things the reader obviously knows (how HTTP works, what a database is)
- AI corporate speak (“leverage”, “unlock”, “empower”, “streamline”)
- Being comprehensive when being clear is enough