Read Markdown.
Deploy static HTML.
Good Reader is a static site generator that reads your Markdown posts and produces a fully pre-rendered, deployable site. No server runtime. No JavaScript required. Works in Lynx.
Features
Everything you need, nothing you don't
A complete publishing toolchain for personal blogs and journals. Every page is real HTML with clean URLs, proper metadata, and semantic structure.
Markdown Posts
Write in Markdown with YAML front matter. Titles, dates, tags, slugs, featured images, descriptions, authors, and fediverse handles. Plain text content, zero build-time dependencies.
SEO & Discovery
Open Graph, Twitter Cards, JSON-LD structured data, canonical URLs, auto-generated sitemap.xml, robots.txt, and RSS feeds with real enclosure lengths. Built for search engines and social sharing.
Fediverse-Native
<meta name="fediverse:creator"> tags + <link rel="me"> profile verification. Site-wide defaults with per-author and per-post overrides. Multiple Mastodon handles supported.
6 Built-in Themes
Default (dark/sepia/light toggle), Terminal (retro monospace), Newspaper (classic broadsheet), Book (elegant reading), Solarized (precision palette), and Vintage (warm aged-paper). All zero JS.
Built-in Dev Server
Preview your site instantly with node cli.js serve. No Python or external tools needed. Supports custom ports with --port. Builds first, then serves - one command to see your changes.
Incremental Build Cache
Enable incrementalBuild for large sites and edit loops. Good Reader reuses unchanged Markdown parses, rendered pages, related-post data, Markdown HTML, static assets, and gzip files while rebuilding only dependent output.
Content Management CLI
Create, edit, delete, and list posts and pages from the terminal with post, page, edit, delete, and list commands. New posts auto-generate full front matter and open your $EDITOR. When that editor is vi, you'll get a friendly guide to :wq.
Tag Archives & Affinity
Automatic tag pages, tag index grid with counts, per-tag RSS feeds, and "You may also like" related posts using IDF-weighted tags plus TF-IDF content similarity. Related vectors are cached for fast rebuilds.
Multi-Author
Per-post author overrides, authors index page, individual author pages with post listings, and per-author RSS feeds. All posts without an author assigned go to the site-wide author.
Paginated Homepage
Optional pagination splits the homepage into multiple pages. Configurable posts-per-page. Generates /page/2/, /page/3/, etc. Client-side search still searches all posts regardless of pagination.
Custom URL Patterns
Configurable URL structure for posts via urlPattern. Choose from /:year/:month/:day/:slug/, /blog/:slug/, /posts/:year/:month/:slug/, or any combination of :year, :month, :day, :slug, :hour, :minute, and :second tokens.
Template Profiles
Switch between template profiles with templateProfile in config. Default (search, theme toggle, images), Minimal (content-only, no JS), Reader (text-first, reading-focused), or Newspaper (lead-article homepage). Each inherits from the next - override only what you need.
RSS & Atom Feeds
Full RSS 2.0 feeds with proper <content:encoded> namespace, real enclosure length and MIME type. Timezone-aware dates. Optional full-content mode. Per-tag and per-author feeds too.
Asset Precompression
Gzips every HTML, CSS, JS, JSON, RSS, and SVG file at build time (level 9). With incremental builds, unchanged files keep their existing .gz siblings instead of being compressed again.
60+ BSSG Themes
Use any of the 60 BSSG themes via automatic CSS conversion, alongside 6 built-in themes. Full layout passthrough - not just colors, but structural styling. From modern minimal to retro computing aesthetics.
BSSG Drop-in Compatible
All posts and pages are fully compatible with the BSSG format - swap between Good Reader and BSSG without changing a single Markdown file. Same front matter, same URL structure, same output semantics. Treat either one as your source of truth.
Client-Side Search
Instant full-text search powered by a generated data.json file. Tag-based filtering. All search runs in the browser - no external service, no tracking, no API keys.
Browser Post Editor
A full-featured, offline browser-based Markdown editor at /post-editor.html, just like BSSG. Live preview, auto-save, keyboard shortcuts, and your site's theme. Write posts right from the browser - no server required.
Text-Browser Friendly
Accessible in Lynx, Elinks, and other text browsers. Semantic HTML5, skip-to-content links, proper heading hierarchy, screen-reader labels, and ARIA attributes throughout.
Themes
Choose your aesthetic
Six built-in themes: Default (dark/sepia/light toggle), Terminal (retro), Newspaper (broadsheet), Book (elegant), Solarized (precision palette), and Vintage (aged-paper). Or pick from 60+ BSSG themes.
How it works
Three commands, a deployed blog
No build pipeline to configure. No plugin ecosystem to maintain. Just Markdown files and a Node.js build step.
Write
Drop Markdown files into contents/ with YAML front matter, or use node cli.js post my-blog my-title to auto-generate a template with all front matter fields and open your editor immediately. Drafts get a .draft suffix.
Build
Run node cli.js build my-blog to generate everything, or node cli.js serve my-blog to build and preview at http://localhost:8080/ with the built-in dev server. Turn on incrementalBuild for dependency-aware rebuilds that skip unchanged Markdown, templates, static files, related-post data, and gzip output. Tag archives, author pages, RSS feeds, sitemap - all generated in seconds. The engine and your content stay in separate directories.
Deploy
Upload the output/ directory to any static host. Clean URLs, no server rewrites needed. Every page is a real index.html file in its own directory.
Share
Fediverse meta tags are baked in. RSS feeds are live. Social previews work out of the box with featured images and SEO metadata pre-rendered into each page.
Configuration
Simple JSON config
One file controls site name, theme, template profile, related posts, RSS, authors, image downloads, compression, incremental caching, and every other feature.
Good Reader & BSSG
Why Good Reader and not BSSG?
The two were born years apart, for different reasons. I started BSSG more than ten years ago, kept it private for most of that time, and only released it about a year ago. Good Reader goes back roughly four years. I set it aside for a while, then picked it up again with one purpose: to make it a fast alternative to BSSG, one you could move to without rewriting a thing.
BSSG: simplicity and portability
Pure Bash. It runs almost anywhere, with nothing to install beyond a Markdown processor. It is the most compatible, lowest-maintenance choice. It favours simplicity and portability, and accepts that raw speed isn't the point.
Good Reader: performance first
On a large site, BSSG can get a little slow. That's where Good Reader steps in. It carries a few more dependencies, then uses a dependency-aware cache so no-op builds can skip parsing, rendering, related-post work, copies, and gzip compression.
That's why Good Reader speaks BSSG's format exactly. Same Markdown, same front matter, same structure: move your content across, keep (roughly) the same theme, and switch back whenever you like. BSSG found its people, and I'm grateful for that. Good Reader wasn't built against it. It was built thanks to it.
Ready to publish?
Clone the engine, init a site, drop in your Markdown, build, preview with the built-in dev server, then upload. Your personal blog, deployed in under two minutes.