Skip to content

./blog.sh 1.0

Choose a tag to compare

@DanielSnor DanielSnor released this 31 Jul 22:39
7e245b7

./blog.sh 1.0 — the first stable release.

A minimalist, file-based blog engine: posts are JSON files, the site is a static build, authoring happens in a terminal, and comments live on the Fediverse. No database, no admin server, no PHP. Ruby stdlib and bash — zero gems, zero npm (one documented asterisk: the optional Pixelfed/RSS widgets need rexml, a default gem some distros package separately).

What 1.0 ships:

  • Content model — one post = one JSON file of typed blocks (text, headings, quotes with attribution, lists, task lists, tables, code, chat, images, video, audio, links, rules). Inline formatting stored as offsets into plain text, so nothing ever parses Markdown twice.
  • Authoring — an interactive CLI wizard: add, edit, publish, schedule, unpublish, delete/restore, toot, rebuild, preview, list. Drafts deploy to hidden, shareable preview URLs with a QR code in the terminal. incoming/ staging for writing from a phone over SFTP. Degrades to plain line prompts in a pipe, respects NO_COLOR and TERM=dumb.
  • Markdown — a deliberate subset with a cheat sheet generated by the parser itself, localized, including a section on what's deliberately not supported and why.
  • Build — static HTML via ERB, no framework. Tag and content-type archives, anchored pagination, RSS, sitemap, client-side search (phrases, -exclusion, diacritics-insensitive), memoized rendering that writes only changed files.
  • Comments & announcements — every published post announces on Mastodon or Bluesky (never both); replies are the comments, loaded by the browser from the public API. unpublish deletes the announcement too.
  • Deploy — six backends (Surfer, local, rsync, git-pages, rclone, SFTP) behind one manifest-driven diff with SHA-256 checksums, --dry-run, opt-in --prune, and shrink/growth guards that stop a broken build before it wipes a live site.
  • Import — eight sources (Bluesky, Instagram, Tumblr, Mastodon, Pixelfed, Twitter/X, WordPress, RSS/Atom), verified against real archives. Media downloads next to its post; the origin becomes a tag; re-imports update in place and never duplicate.
  • i18n — English, Czech and German. A language is one YAML file with per-key fallback; adding yours is the easiest way to contribute.
  • Appearance — a complete theme from 7 colour keys per mode (light + dark), config-compiled CSS, banner with corner-scoped scrim, automatic photo grids with lightbox.
  • Security by subtraction — CSP meta, self-hosted assets, zero third-party requests from the engine, noindex drafts, escaping everywhere.

Seen in the wild: blogsh.app — the project site, which runs on this engine and demonstrates every feature above in its posts — and sean.cz, the original deployment it was built around.

Docs: README · install · operations · importing · localization

MIT licensed.