Intro

Wide horizontal logo of the Hugo static site generator
Hugo has such a cheerful, simple logo

After setting up Hugo, in a previous post My Friend Hugo, I kept going — experimenting with the actual writing workflow. Over time I’ve built a set of practices that make writing easier, faster, and more consistent: from my boilerplate.txt snippets and Espanso macros to how I think about alt tags and tactical inline HTML.

You’re welcome, both of you!

🧾 View Other Hugo Posts

Boilerplate and Snippets

Markdown is easy, with a simple syntax that abstracts away complexity and lets you focus on writing. If I had to write this site in pure HTML I’d never attempt long-form content. That simplicity is a big selling point for Hugo as a static site generator — but there are still some sticky bits. Certain Markdown extensions, custom shortcodes, or inline HTML are fiddly to remember.

So like many before me, I keep a crib sheet in a file called BOILERPLATE.txt.
It’s just a plain text file, but it has become my go-to reference: copy-and-paste snippets for the patterns I use over and over. Figure blocks, float-left images, GitHub buttons — all captured once, used consistently forever.

Pro-Tip: Keeping snippets literal in a text file avoids “magic.” You always know exactly what will get pasted in.


Scratch folder

A best practice I’ve settled on (and would repeat if I started fresh) is keeping a scratch/ directory at the root of my Hugo site. It’s ignored by Hugo at build time, so it won’t leak unless I write about it, but it’s a perfect place for experiments: HTML previews of fonts, screenshots, notes, and of course BOILERPLATE.txt itself.

┌──[ forfaxx@shinobi ]:~/codelab/adminjitsu/scratch  (main*)
└─$ ls -l 
-rw-r--r--  adminjitsu-fonts.html
-rw-r--r--  adminjitsu_palette_overview.png
drwxr-xr-x  bin
-rw-r--r--  BOILERPLATE.txt
-rw-r--r--  POST-IDEAS.txt
-rw-r--r--  SCRATCHPAD.txt
-rw-r--r--  Tags and Categories.txt
drwxr-xr-x  WIP archive

Inside bin/ I keep little helper tools I’ve built for the site — see My Friend Hugo for details on scripts like metaclean and tag-audit. I also symlink a couple of general-purpose commands from my dotfiles so I don’t duplicate code between projects. Having them right next to the Hugo content keeps everything tidy and self-contained.

┌──[ forfaxx@shinobi ]:~/codelab/adminjitsu/scratch/bin  (main*)
└─$ ls -l 
drwxr-xr-x  covers
-rw-r--r--  feather-demo.html
-rw-r--r--  feather-icon-demo.html
-rw-r--r--  feather-picker.html
-rw-r--r--  feather-picker.html.old
-rw-r--r--  font-preview.html
-rw-r--r--  font-preview2.html
-rw-r--r--  font-preview3-roboto.html
-rw-r--r--  font-preview4.html
-rwxr-xr-x  gen-bg.py
-rwxr-xr-x  generate-bg-wave.py
-rwxr-xr-x  generate-bg.py
-rwxr-xr-x  pal-preview.py
-rwxr-xr-x  tag-audit.py
-rwxr-xr-x  tag-scan.py
lrwxrwxrwx  metaclean -> ~/codelab/dotfiles/tools/metaclean/metaclean.py
lrwxrwxrwx  sync-adminjitsu.sh -> ~/codelab/dotfiles/bin/sync-adminjitsu.sh

Finally, I keep a Ninja Style-Dojo — a more complete collection of snippets and conventions, with live HTML previews. I publish it on my site for fun, but it could just as easily stay a draft and serve as a private reference. Either way, it’s a handy place to store the raw Markdown and see the rendered results side-by-side in a browser — something I’d definitely set up again on a new site.

Why it works for me

  • Consistency: BOILERPLATE.txt guarantees my figures, captions, and buttons always look the same.
  • Speed: Instead of hunting through old posts, I paste from my crib sheet or trigger an Espanso macro.
  • Safety: Scratch/ is local-only and never published — so I can stash messy drafts, half-baked snippets, and test assets without worry.
  • Organization: Keeping helper code and snippets inside the project keeps the mental overhead low — everything I need to write and polish a post lives right beside it.

Espanso Macros

Espanso is my free, cross-platform tool of choice for snippets that I can never quite keep in human RAM. (See Espanso and Friends for more detail.) Typing something like :figcenter and having it expand into the following skeleton makes life so much easier

<figure style="text-align:center; margin: 1em auto;">
  <img src="" 
       title=""
       alt="" 
       style="display:block; margin:0 auto; width:min(100%, 600px); height:auto;">
  <figcaption style="font-size: 85%; font-weight: normal; color: #666; line-height:1.4; margin-top:0.4em;">
    
  </figcaption>
</figure>

Filling that out after triggering a macro is far quicker than retyping or hunting through past posts. My rule of thumb: whenever I catch myself digging through BOILERPLATE.txt or searching old posts too often, that’s my cue to promote it into an Espanso snippet.

I have a few like :mailto, :btn-github, :btn-tag and :author and espanso makes them much easier to use consistently. For an initial rough-draft I sometimes use :lorem to drop a placeholder block like the following:

Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.

I’ve used TextExpander on macOS for years, and it’s definitely the more polished program. But Espanso works, it’s cross-platform, and it’s free. Best of all, it doesn’t force you to tie a literal keylogger to a cloud service — a baffling change that pushed many of us to look elsewhere.


Page Bundles are Where It’s At

This wasn’t obvious to me at first, but the best way I’ve found to structure content in Hugo is by using page bundles. Instead of scattering your Markdown, images, and other assets across different directories, a page bundle keeps everything for a single post together in one folder.

In Hugo, that usually means a directory with an index.md and all its supporting files side-by-side:

content/
└── posts/
    └── hugo-boilerplate/
        ├── index.md
        ├── hugo-logo-wide.svg
        ├── screenshot.png
        └── diagram.jpg

The magic: when you reference an image in your Markdown, Hugo automatically resolves relative paths from the bundle folder. That means you don’t need to manage long paths like /images/2025/08/foo.png — you just drop the asset into the bundle and link it as ![alt](screenshot.png).

Pro-Tip: Page bundles make it natural to keep figures, screenshots, and diagrams right alongside the post they belong to. When you move or archive the post, all its assets come with it.

I wish I’d embraced this earlier — it makes writing image-heavy posts far more portable and self-contained.

I still drop the occasional file in /static when there’s a reason, but page bundles keep the majority of posts tidy and script-friendly.


Leaf vs. Branch Bundles

This was also confusing at first, but now it’s clear:

  • Leaf bundle → a folder with index.md. Perfect for a single post and its images.
  • Branch bundle → a folder with _index.md. Used when the directory itself is a section and you want to organize child pages inside it.

For most posts, leaf bundles are the sweet spot: everything neatly wrapped up with its assets. But branch bundles shine when you want to customize sections or taxonomy pages.


Customizing a Tag Page

One practical example of a branch bundle is a taxonomy page. Hugo automatically generates list pages for each taxonomy (like tags or categories) — see the taxonomy docs for the full details. These pages are useful by default, but you can take them further by customizing them with an _index.md.

For example, my Hugo tag has its own logo and introduction at the top as seen here

To make this work, I created an _index.md file in content/tags/hugo/:

---
title: "Hugo"
---

<br>

<p align="center">
  <img src="hugo-logo-wide.svg" 
       alt="Hugo static site generator logo" 
       style="max-width:320px; margin-bottom:0.6em;">
  <br>
</p>

**Posts about Hugo** — workflows, scripts, and experiments with the PaperMod theme.  

*Here’s where I collect all my Hugo-related posts. From publishing scripts to styling tricks, these are my experiments in making Hugo work like a Unix-first tool.*

Pro-Tip: Any taxonomy term (tags, categories, series, etc.) can be customized this way. Just create a folder under content/<taxonomy>/<term>/ and drop in an _index.md. Hugo merges your intro with the generated list of posts.


The Art of Alt Text

Markdown images are dead simple: copy the file into your page bundle and drop in

![image](image.jpg)

That’s fine for quick drafts, but limited. I’ve standardized on using HTML5 <figure> blocks. They’re more verbose, but Espanso and BOILERPLATE.txt make them trivial to insert. One big advantage is how naturally they support alt text and captions.

A little 8-bit arcade-style ninja in blue, mid-kick. Playful tone.
<figure style="float:left; margin:0 1rem 1rem 0; width:clamp(260px, 45%, 200px);">
  <img src="blue-ninja2.png" 
       title="a title should appear when you hover over an image in your browser"
       alt="A little 8-bit arcade-style ninja in blue, mid-kick. Playful tone." 
       style="display:block; width:100%; height:auto;">
  <figcaption style="font-size:85%; color:#666; line-height:1.4; margin-top:0.4em;">
    insert caption here
</figcaption>
</figure>

The alt text here is:
“A little 8-bit arcade-style ninja in blue, mid-kick. Playful tone.”

That’s short, descriptive, and conveys both content and feel.

Pro-tip: “When you float an image (float:left or float:right), add <div style="clear:both"></div> immediately after the last paragraph you want to flow alongside it. That ends the float so the next block of text starts below the image instead of wrapping around it.”

Why Alt Text Matters

  • Accessibility → screen readers literally speak the alt text aloud. For some humans, the alt text is the image.
  • SEO & indexing → search engines rely on it to understand your images.
  • Future-you → when you’re skimming raw Markdown years later, it’s your memory cue for what the image was.

💡 Think of alt text as radio commentary for your images: short, vivid, and enough for someone who can’t see it to still get the point.


How I Write Mine

  1. Concise → don’t narrate everything, just the essence.
  2. Tone → if the image is playful, somber, or technical, hint at that.
  3. Context → what’s relevant in this post, not in general.

alt vs. title vs. figcaption

  • alt → mandatory description for accessibility & indexing. Invisible unless needed.
  • title → optional tooltip when you hover (not read by all screen readers). Best kept short.
  • figcaption → visible, human-facing caption under the image.

Examples

Good:

  • alt="Diagram of a TCP handshake with SYN, SYN-ACK, and ACK arrows"
  • alt="Screenshot of Hugo’s PaperMod theme with sidebar expanded"
  • alt="Cheesy photo of a 90s era hacker in a leather outfit with oversized, early VR goggles"

Bad:

  • alt="image123.png" (useless)
  • alt="screenshot" (too vague)
  • alt="This is a picture showing how computers work and it is very detailed and you should read the whole post to understand it" (too long and redundant)

Writing Workflow

Over the past months I’ve stumbled into a workflow that works well for me. It’s nothing fancy, but it keeps me moving from raw ideas to finished posts without getting stuck in the weeds:

  • Brainstorm
    I start with a physical journal on my desk — just date, time, and whatever’s on my mind. Tasks, quotes, fragments of ideas. If something excites me, it tends to show up on multiple days. Flipping back through recent pages often sparks connections. Sometimes I’ll highlight passages that feel like seeds for posts.

  • Braindump / First Draft
    When an idea is ready, I open a new leaf bundle in Hugo and start throwing content at the page. Sections, half-sentences, “insert brilliant analysis here.” Markdown helps because the draft already has structure — headers turn into an outline as I go. The point isn’t polish, just getting a skeleton that makes sense as a document.

  • Second Draft
    Here’s where the real work happens. I fill in the placeholders: research, repro steps, screenshots, code snippets. This is also where I fix flow problems and cut the junk. The second draft is “basically done” but still rough — good bones, not yet polished.

  • Final Draft / Polish & Publish
    Last step is to read it top to bottom as a reader would. Does it sound right? Are the facts straight? I check typos and grammar (still hunting for the perfect VS Code spellchecker) and make sure my snippets render correctly. When it feels solid, I fire up my publish script and call it a day. This is usually the point where I realize I made a glaring error despite the previous steps and polish some more.

This workflow isn’t revolutionary — brainstorm, draft, revise, polish — but the combination of Hugo + Markdown + my little tooling stack makes it doable. The tech gets out of the way so the writing can happen. That’s already hard enough without having to fight the platform.

Honestly, it feels closer to making a DIY punk zine than building a “traditional” website. That reminds me of what I liked about OS X Server’s old Wiki service: it made high-quality technical docs easy to produce without wrestling with the stack. Hugo has the same spirit, but with more power under the hood — full access to HTML, CSS, JS, and theming when I need it.

Tactical Inline HTML

Markdown gets you 90% of the way, but sometimes you need finer control — a <figure> block, a <div> wrapper, a styled <span>. That’s where inline HTML comes in.

By default Hugo uses the Goldmark Markdown processor, which escapes raw HTML unless you tell it otherwise. To enable inline HTML, set this in your site config:

[markup.goldmark.renderer]
unsafe = true

Now your raw HTML will render directly in posts.

Caveats

  • Trust yourself only: don’t paste untrusted HTML snippets (security risk).
  • Keep it minimal: inline HTML is great for captions, figures, or buttons — but if you find yourself nesting <div>s like it’s 2003, consider moving it into a shortcode or a partial.
  • Test on mobile: what looks good in desktop Chrome might break layout in a narrow column.

Examples

<span style="color:#7D83B9;">inline highlight</span>
<p style="text-align:center;">
  <a href="/tags/hugo" class="button">🧾 View Other Hugo Posts</a>
</p>

Inline HTML is a sharp tool: overdo it and your Markdown turns messy, but sprinkled tactically it can save you from endless CSS hacks or theme surgery.

Conclusion

Hugo + Markdown has been a great excuse to tinker, automate, and—most importantly—actually write. That’s my story, and I’m sticking to it.

If you’ve read this far, thanks for stopping by. I hope some of these odd little practices spark ideas for your own setup.

🧾 View Other Hugo Posts

Have a tip or trick? Did I miss something? I’d love to hear about it! Email me: feedback@adminjitsu.com