Aug 24, 2026

Ten smaller things

Part 9 of 9 of ./blog.sh v1.3

The rest of this release is ten additions that each need a paragraph rather than a post.

Pages

page: true gives a post a permanent address at the root — /about/ — out of the listings and the feeds, but in the sitemap and the search index. Ghost, WordPress, Squarespace and Substack import them as pages now instead of skipping them, and the import says where they landed and that nothing links to them yet. The engine will not write a nav: entry on your behalf; where a page belongs in your menu is your decision.

Series

series: groups posts and series_part: orders the one you published out of turn. Each series gets a listing, and every post in one links to the previous and next part — within the series only, never spilling into the archive around it. A draft's preview says whether its series name joins something that exists or founds something new, so a typo is caught while it is still free to fix.

Unlisted

unlisted: true keeps a published post on its ordinary address and takes it out of every listing, feed and index, noindex included. It is the draft's hidden address, generalised to a finished post. Deliberately not a password: publishing one no longer announces it either, and --force does not open that door — take the flag off first, so the decision is explicit.

./blog.sh stats

The archive counted from the posts on disk. No build, no network, no env.sh. This site, at the time of writing:

The archive
  43 post(s): 43 published, 0 draft(s), 0 scheduled, 0 page(s)

What they are
  text      ██████████████████ 28 (65 %)
  link      █████              7 (16 %)
  chat      █                  2 (5 %)
  image     █                  2 (5 %)
  audio     █                  1 (3 %)
  document  █                  1 (2 %)
  quote     █                  1 (2 %)
  video     █                  1 (2 %)

Words
  17,048 words in all, 396.5 per post on average, 416 in the middle
  longest: what-rots-quietly (828 words)
  reading the whole archive takes 1.4 hours

Media
  24 file(s), 27.6 MB, across 10 post(s)

Words carry both mean and median, deliberately: here they nearly agree, because these posts are all the same kind of thing. On an archive half made of imported tweets the mean sits far above the middle, and only the pair says so. --json prints the same figures unrounded.

Reading time and a table of contents

Reading time on every post page, and on every listing card, because the deciding happens in the listing and reading time is the one thing every post can report. A post too short to time says "under a minute" rather than rounding itself to zero. A contents list appears from four headings up, or whenever a post asks for one with toc:.

A feed per tag

For the tags the menu names, with autodiscovery on the tag's own page. Not for every tag in the archive — on a real archive that is thousands of files, rebuilt and re-diffed on every build, that nobody will ever fetch. A tag in nav: is the site saying this is a subject I publish on, which is the same statement as somebody might want to follow just this. A site still using the derived menu gets no tag feeds at all; that is the answer, not an oversight.

fediverse:creator

Mastodon puts the author's account on a shared link's preview card. No new configuration key — it is the social: entry already pointing at a profile on the instance the site announces to.

Blocking the training crawlers

seo.block_ai_crawlers writes a maintained list of them into robots.txt, and seo.robots_extra takes free text for whatever else you want in there. Off by default, and worth saying plainly: robots.txt is a request, not a fence.

A 404 page

Built by the site rather than left to whatever the host shows: the menu, the search field, noindex, and a signpost under the heading drawn inline in the palette's own colours, with its one accent arrow pointing the way on. A dead end on my site should still look like my site.

Nothing here, in this site's own colours

Keyboard, phone, and a search that ranks

Every page has an h1 now — listing headings were level two, and the front page had none at all. Focus is visible again, in the accent. prefers-reduced-motion is honoured, so transitions collapse and the back-to-top button jumps instead of scrolling. The lightbox can be opened, walked and closed without a mouse. On a phone the menu closes with Escape or a tap outside, and the search field sits in the bar rather than folded into the menu.

Search itself answers with its best results instead of its most recent ones — a title outranks the text, a whole word outranks the same letters inside a longer one, ties keep their date order — and a search has an address again, so ?q= can be sent, bookmarked and returned to.

Comments