<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>cole.am</title>
<link>https://cole.am/</link>
<description>Personal portfolio and blog: security write-ups on things I find interesting, and the projects I ship.</description>
<language>en</language>
<lastBuildDate>Wed, 19 Aug 2026 22:13:21 -0500</lastBuildDate>
<item>
<title>Why this site is one Go binary and a folder of AsciiDoc</title>
<link>https://cole.am/posts/2026-08-19-hello/</link>
<guid>https://cole.am/posts/2026-08-19-hello/</guid>
<pubDate>Wed, 19 Aug 2026 00:00:00 +0000</pubDate>
<description>The stack behind this site: a single static Go generator, AsciiDoc content, and Cloudflare Pages. No JavaScript framework, no build pipeline.</description>
<content:encoded><![CDATA[<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>This site has no JavaScript framework, no bundler, no node_modules, and no
database. It is a single Go binary that reads a folder of AsciiDoc files and
writes a static site, which is then served from Cloudflare's edge for free.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="the_whole_pipeline">The whole pipeline</h2>
<div class="sectionbody">
<table class="tableblock frame-all grid-all stretch">
<colgroup>
<col style="width: 25%;">
<col style="width: 75%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Stage</th>
<th class="tableblock halign-left valign-top">Tool</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Authoring</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Any editor, plain <code>.adoc</code> files</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Rendering</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">~600 lines of Go, <code>asciidoctor-go</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Templates</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Go <code>html/template</code>, embedded in the binary</p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock">Hosting</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Cloudflare Pages, free tier</p></td>
</tr>
</tbody>
</table>
<div class="paragraph">
<p>Publishing a post means dropping one file in <code>content/posts/</code> and running one
command. The binary handles the rest: clean URLs, RSS, sitemap, Open Graph
tags, and JSON-LD structured data.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="what_asciidoc_gives_me_that_markdown_does_not">What AsciiDoc gives me that Markdown does not</h2>
<div class="sectionbody">
<div class="ulist">
<ul>
<li>
<p>Real document headers: title, revision, author, custom attributes</p>
</li>
<li>
<p>Tables, admonitions, callouts, and section cross-references</p>
</li>
<li>
<p>Built for technical writing, which is what lives here</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>A sample block, rendered by the same converter that renders this page:</p>
</div>
<div class="listingblock">
<div class="content">
<figure class="source" data-lang="go"><pre class="chroma"><code><span class="line"><span class="cl"><span class="c1">// the entire publish loop</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">Deploy</span><span class="p">(</span><span class="nx">root</span><span class="w"> </span><span class="kt">string</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nf">Build</span><span class="p">(</span><span class="nx">root</span><span class="p">,</span><span class="w"> </span><span class="kc">false</span><span class="p">)</span><span class="p">;</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">err</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nf">wrangler</span><span class="p">(</span><span class="nx">root</span><span class="p">,</span><span class="w"> </span><span class="s">&#34;public&#34;</span><span class="p">)</span><span class="w"> </span><span class="c1">// direct upload to Pages</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre></figure>
</div>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<div class="title">Tip</div>
</td>
<td class="content">
Posts marked with the <code>draft</code> attribute are excluded from production
builds but visible while drafting locally. No draft branch juggling.
</td>
</tr>
</table>
</div>
</div>
</div>
<div class="sect1">
<h2 id="why_cloudflare_pages">Why Cloudflare Pages</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Direct Upload means the deploy is just an authenticated API push of the
<code>public/</code> folder. The git repository stays private and is only a source of
truth for content, not a deploy trigger.</p>
</div>
<div class="paragraph">
<p>More on the <a href="https://developers.cloudflare.com/pages/">Cloudflare Pages docs</a>
if you care. Meanwhile, there is an <a href="/about/">about page</a> and a
<a href="/projects/">projects page</a>.</p>
</div>
</div>
</div>
</div>
<div id="footer">
<div id="footer-text">
</div>
</div>]]></content:encoded>
</item>
</channel>
</rss>
