<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <id>http://localhost:3000/feed.xml</id>
  <title>Field Notes</title>
  <subtitle>Short notes on building software, published as a static site from markdown files.</subtitle>
  <updated>2026-09-06T00:00:00.000Z</updated>
  <link rel="alternate" href="http://localhost:3000/"/>
  <link rel="self" href="http://localhost:3000/feed.xml" type="application/atom+xml"/>
  <entry>
    <id>http://localhost:3000/hello-field-notes/</id>
    <title>Hello, Field Notes</title>
    <link rel="alternate" href="http://localhost:3000/hello-field-notes/"/>
    <updated>2026-09-06T00:00:00.000Z</updated>
    <published>2026-09-06T00:00:00.000Z</published>
    <category term="meta"/>
    <category term="writing"/>
    <summary type="html"><![CDATA[What this site is, how it is built, and what to expect here.]]></summary>
    <content type="html"><![CDATA[<p>This is a small site of notes: things learned while building software, written down before they are forgotten.</p>
    <h2 id="how-it-is-built">How it is built</h2>
    <p>Every post is a markdown file with a little YAML front matter at the top. The build reads the files, renders them once to HTML, and writes one static page per post — no server, no database, nothing to keep running.</p>
    <ul>
    <li>Posts live in <code>content/posts/</code></li>
    <li>The build runs <code>npm run build</code> and writes <code>dist/</code></li>
    <li><code>dist/</code> goes to any static host</li>
    </ul>
    <h2 id="what-to-expect">What to expect</h2>
    <p>Short notes, mostly. A longer piece now and then. Every post is also available as raw markdown at the same path with a <code>.md</code> extension, and there is an <a href="/feed.xml">RSS feed</a> if you would rather read from a feed reader.</p>
    ]]></content>
  </entry>
  <entry>
    <id>http://localhost:3000/writing-the-first-draft-fast/</id>
    <title>Writing the first draft fast</title>
    <link rel="alternate" href="http://localhost:3000/writing-the-first-draft-fast/"/>
    <updated>2026-09-04T00:00:00.000Z</updated>
    <published>2026-09-04T00:00:00.000Z</published>
    <category term="writing"/>
    <category term="process"/>
    <summary type="html"><![CDATA[Why the first draft should be written in one sitting, and how to make that possible.]]></summary>
    <content type="html"><![CDATA[<p>The first draft has one job: to exist. Everything else — structure, precision, the good sentence — comes from editing, and you cannot edit a blank page.</p>
    <h2 id="lower-the-bar-on-purpose">Lower the bar on purpose</h2>
    <p>Write badly, on purpose, and quickly. Leave placeholders like <em>[example here]</em> instead of stopping to find the example. Keep a list of questions at the bottom of the file instead of answering them inline.</p>
    <h2 id="separate-the-two-modes">Separate the two modes</h2>
    <p>Drafting and editing use different parts of the mind. Mixing them means doing both slowly. Draft in one sitting; edit tomorrow.</p>
    <blockquote>
    <p>The draft is for you. The edit is for the reader.</p>
    </blockquote>
    ]]></content>
  </entry>
  <entry>
    <id>http://localhost:3000/a-note-on-naming-things/</id>
    <title>A note on naming things</title>
    <link rel="alternate" href="http://localhost:3000/a-note-on-naming-things/"/>
    <updated>2026-09-01T00:00:00.000Z</updated>
    <published>2026-09-01T00:00:00.000Z</published>
    <category term="code"/>
    <category term="craft"/>
    <summary type="html"><![CDATA[Names are the cheapest documentation you will ever write.]]></summary>
    <content type="html"><![CDATA[<p>A good name answers the question the reader was about to ask. A bad one makes them open the file.</p>
    <h2 id="three-tests">Three tests</h2>
    <ol>
    <li><strong>Could it mean something else?</strong> If a name fits two things, it describes neither.</li>
    <li><strong>Does it say what the thing is, not what it is near?</strong> <code>userHelper</code> is near users; <code>formatUserName</code> is a thing.</li>
    <li><strong>Would a stranger place it?</strong> Read the name out of context. If it needs the folder to make sense, it is not finished.</li>
    </ol>
    <pre><code class="language-ts">// before
    const data = await get(id)
    // after
    const invoice = await fetchInvoice(id)
    </code></pre>
    <p>Renaming is cheap early and expensive late — a published API name is forever.</p>
    ]]></content>
  </entry>
  <entry>
    <id>http://localhost:3000/keeping-a-changelog-by-hand/</id>
    <title>Keeping a changelog by hand</title>
    <link rel="alternate" href="http://localhost:3000/keeping-a-changelog-by-hand/"/>
    <updated>2026-08-28T00:00:00.000Z</updated>
    <published>2026-08-28T00:00:00.000Z</published>
    <category term="process"/>
    <category term="writing"/>
    <summary type="html"><![CDATA[Generated changelogs list commits; a written one tells the reader what changed for them.]]></summary>
    <content type="html"><![CDATA[<p>A generated changelog is a list of commits. A written one is a list of consequences: what a user can do now that they could not do before, and what they must change.</p>
    <h2 id="one-line-per-change-for-strangers">One line per change, for strangers</h2>
    <p>Write each entry for someone who has never seen the code. Say what changed and why it matters, in their words. Internal narrative — which gate was wrong, what confused whom — does not belong there.</p>
    <h2 id="keep-it-as-you-go">Keep it as you go</h2>
    <p>An entry written the day of the change takes a minute. The same entry reconstructed a month later takes an hour and is worse.</p>
    ]]></content>
  </entry>
  <entry>
    <id>http://localhost:3000/the-case-for-static-sites/</id>
    <title>The case for static sites</title>
    <link rel="alternate" href="http://localhost:3000/the-case-for-static-sites/"/>
    <updated>2026-08-24T00:00:00.000Z</updated>
    <published>2026-08-24T00:00:00.000Z</published>
    <category term="web"/>
    <category term="meta"/>
    <summary type="html"><![CDATA[A site that is only files has nothing to break at three in the morning.]]></summary>
    <content type="html"><![CDATA[<p>A static site is a directory of files. That sentence is the whole operations manual.</p>
    <h2 id="what-you-give-up">What you give up</h2>
    <ul>
    <li>No per-request logic: personalisation happens in the browser or not at all.</li>
    <li>No database: content is files in the repository, edited like code.</li>
    </ul>
    <h2 id="what-you-get">What you get</h2>
    <ul>
    <li>Nothing to patch, restart, scale or back up.</li>
    <li>Every page is cacheable forever and served from the edge.</li>
    <li>The build is the only moving part, and it runs on your machine or in CI where you can watch it.</li>
    </ul>
    <p>For notes, documentation and most marketing pages, that trade is not close.</p>
    ]]></content>
  </entry>
  <entry>
    <id>http://localhost:3000/markdown-is-enough/</id>
    <title>Markdown is enough</title>
    <link rel="alternate" href="http://localhost:3000/markdown-is-enough/"/>
    <updated>2026-08-20T00:00:00.000Z</updated>
    <published>2026-08-20T00:00:00.000Z</published>
    <category term="writing"/>
    <category term="web"/>
    <summary type="html"><![CDATA[Plain text with a little structure outlives every editor that tried to replace it.]]></summary>
    <content type="html"><![CDATA[<p>Every few years a new editor promises rich blocks, embeds and collaboration. Every few years the notes written in it become hard to move. The markdown files from fifteen years ago still open.</p>
    <h2 id="structure-you-can-see">Structure you can see</h2>
    <p>Headings, lists, emphasis, links and code — that is the structure of almost every document worth reading, and markdown spells each one with a character you can type.</p>
    <table>
    <thead>
    <tr>
    <th>Need</th>
    <th>Markdown</th>
    </tr>
    </thead>
    <tbody><tr>
    <td>A heading</td>
    <td><code>## Title</code></td>
    </tr>
    <tr>
    <td>Emphasis</td>
    <td><code>*this*</code></td>
    </tr>
    <tr>
    <td>A link</td>
    <td><code>[text](url)</code></td>
    </tr>
    <tr>
    <td>Code</td>
    <td>backticks</td>
    </tr>
    </tbody></table>
    <h2 id="everything-else-is-a-plugin">Everything else is a plugin</h2>
    <p>Tables, footnotes and task lists are extensions; use them when the renderer supports them and the text still reads without them.</p>
    ]]></content>
  </entry>
  <entry>
    <id>http://localhost:3000/reading-logs-before-guessing/</id>
    <title>Reading logs before guessing</title>
    <link rel="alternate" href="http://localhost:3000/reading-logs-before-guessing/"/>
    <updated>2026-08-16T00:00:00.000Z</updated>
    <published>2026-08-16T00:00:00.000Z</published>
    <category term="code"/>
    <category term="debugging"/>
    <summary type="html"><![CDATA[One observed value beats thirty minutes of plausible theories.]]></summary>
    <content type="html"><![CDATA[<p>The most expensive debugging session is the one that starts with a theory. The cheapest starts with a log line.</p>
    <h2 id="start-at-the-entry-point">Start at the entry point</h2>
    <p>Print the actual input where it enters the system. Not what the docs say it should be — what it is. Half the bugs end right there.</p>
    <h2 id="then-work-inward">Then work inward</h2>
    <p>Follow the value one step at a time, printing as you go, until it stops being what you expect. That step is the bug. Everything before it was fine.</p>
    <pre><code class="language-ts">console.log(&#39;[handler] body =&#39;, JSON.stringify(req.body))
    </code></pre>
    <p>Delete the line afterwards. Keep the habit.</p>
    ]]></content>
  </entry>
  <entry>
    <id>http://localhost:3000/small-commits/</id>
    <title>Small commits</title>
    <link rel="alternate" href="http://localhost:3000/small-commits/"/>
    <updated>2026-08-12T00:00:00.000Z</updated>
    <published>2026-08-12T00:00:00.000Z</published>
    <category term="process"/>
    <category term="code"/>
    <summary type="html"><![CDATA[The commit is the undo button; keep it within reach.]]></summary>
    <content type="html"><![CDATA[<p>A commit is a point you can return to. Hours of uncommitted work is hours you cannot get back if the next command goes wrong.</p>
    <h2 id="one-logical-change">One logical change</h2>
    <p>If the message needs the word &quot;and&quot;, it is two commits. A reviewer can hold one idea in their head; a reverter can remove one idea without collateral.</p>
    <h2 id="commit-before-the-risky-step">Commit before the risky step</h2>
    <p>About to run a script over two hundred files? Commit first. Recovering from a bad sweep is a one-line <code>git revert</code> — if the good state was committed.</p>
    ]]></content>
  </entry>
  <entry>
    <id>http://localhost:3000/feeds-still-work/</id>
    <title>Feeds still work</title>
    <link rel="alternate" href="http://localhost:3000/feeds-still-work/"/>
    <updated>2026-08-08T00:00:00.000Z</updated>
    <published>2026-08-08T00:00:00.000Z</published>
    <category term="web"/>
    <category term="meta"/>
    <summary type="html"><![CDATA[RSS and Atom are the quietest, most durable way to publish.]]></summary>
    <content type="html"><![CDATA[<p>No algorithm decides who sees a feed. A reader subscribes, the site publishes, and that is the entire relationship.</p>
    <h2 id="publish-both">Publish both</h2>
    <p>RSS 2.0 and Atom 1.0 are both a few hundred bytes of XML per post. Readers handle either, so publish both and let them choose. This site does: <a href="/feed.xml">feed.xml</a> and <a href="/atom.xml">atom.xml</a>.</p>
    <h2 id="put-the-whole-post-in-the-feed">Put the whole post in the feed</h2>
    <p>A feed that holds only the first paragraph trains readers to leave. Put the full text in; the reader who wants the page will click anyway.</p>
    ]]></content>
  </entry>
  <entry>
    <id>http://localhost:3000/tests-for-the-next-person/</id>
    <title>Tests for the next person</title>
    <link rel="alternate" href="http://localhost:3000/tests-for-the-next-person/"/>
    <updated>2026-08-04T00:00:00.000Z</updated>
    <published>2026-08-04T00:00:00.000Z</published>
    <category term="code"/>
    <category term="craft"/>
    <summary type="html"><![CDATA[A test is a sentence about behaviour that a machine keeps true.]]></summary>
    <content type="html"><![CDATA[<p>The best tests read like the documentation you wish existed: <em>a signed-up user can log out and log back in</em>. The name says what is true; the body proves it.</p>
    <h2 id="test-the-outcome-not-the-mechanism">Test the outcome, not the mechanism</h2>
    <p>A test that asserts a function was called passes when the function does the wrong thing. A test that asserts the result the user sees fails when it should.</p>
    <h2 id="anchor-to-something-visible">Anchor to something visible</h2>
    <p>For user interfaces, at least one assertion per test should touch the screen — a heading, a button, a URL. A suite that only hits the API stays green while the page is blank.</p>
    ]]></content>
  </entry>
  <entry>
    <id>http://localhost:3000/deploying-a-directory/</id>
    <title>Deploying a directory</title>
    <link rel="alternate" href="http://localhost:3000/deploying-a-directory/"/>
    <updated>2026-07-30T00:00:00.000Z</updated>
    <published>2026-07-30T00:00:00.000Z</published>
    <category term="web"/>
    <category term="process"/>
    <summary type="html"><![CDATA[How this site ships: build, then copy a folder.]]></summary>
    <content type="html"><![CDATA[<p>The deploy for this site is two steps, and the second one is <code>cp</code>.</p>
    <h2 id="build">Build</h2>
    <pre><code class="language-sh">npm run build
    </code></pre>
    <p>The build type-checks, bundles the app, then prerenders every route to <code>dist/&lt;route&gt;/index.html</code> — in Node, with no browser involved — and writes the feeds, the sitemap and <code>llms.txt</code> next to them.</p>
    <h2 id="copy">Copy</h2>
    <p>Upload <code>dist/</code> to any static host. If the site lives under a sub-path, build with <code>BASE_PATH=/notes</code> and every link, asset and feed URL follows.</p>
    ]]></content>
  </entry>
  <entry>
    <id>http://localhost:3000/what-llms-txt-is-for/</id>
    <title>What llms.txt is for</title>
    <link rel="alternate" href="http://localhost:3000/what-llms-txt-is-for/"/>
    <updated>2026-07-26T00:00:00.000Z</updated>
    <published>2026-07-26T00:00:00.000Z</published>
    <category term="web"/>
    <category term="meta"/>
    <summary type="html"><![CDATA[A short index that tells a language model where the readable versions of your pages are.]]></summary>
    <content type="html"><![CDATA[<p><code>llms.txt</code> is a plain-text file at the root of a site: a title, a line about the site, and a list of links to markdown versions of its pages.</p>
    <h2 id="why-markdown">Why markdown</h2>
    <p>A language model reading HTML spends most of its attention on navigation, scripts and markup. The same page as markdown is a tenth of the size and all signal.</p>
    <h2 id="this-site39s-copy">This site&#39;s copy</h2>
    <p>Every post here is served twice: as a page, and as the original markdown at <code>/&lt;slug&gt;.md</code>. <a href="/llms.txt">llms.txt</a> lists the markdown copies with a one-line description each.</p>
    ]]></content>
  </entry>
</feed>