Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Listsome Documentation

A static site generator for sharing DIY project guides. Write standard Markdown with YAML frontmatter, get a deployable static site.

What It Does Today

CommandWhat It Does
listsome initScaffolds a new site with config, projects directory, and .gitignore
listsome newCreates a new project with index.md, frontmatter template, and assets directory
listsome buildParses projects, renders HTML from templates, copies assets, generates index page and Atom feed
listsome serveDev server with live reload via WebSocket, auto-rebuilds on file changes
listsome checkValidates project structure and frontmatter
listsome listLists projects with filtering by category, difficulty, and draft status

Every project lives in projects/<slug>/index.md. Step headers (## Step N: Title, ## Part N: Title) are automatically extracted. Tables with Item/Qty/Cost/Source columns are parsed as bill-of-materials.

Philosophy

  • Standard Markdown: No proprietary syntax. Your files render everywhere.
  • Single Binary: One Rust binary, no runtime, no database.
  • Opinionated: Sensible defaults for DIY project sites.
  • Portable Output: Deploy anywhere that serves static files.

Project Structure

my-site/
├── listsome.toml          # Site configuration
├── projects/              # Your project directories
│   └── my-project/
│       ├── index.md       # Project content with frontmatter
│       └── assets/        # Images, downloads, etc.
├── output/                # Generated site (gitignored)
└── README.md              # Your site's README (generated by init)

Quickstart

Prerequisites

  • Rust 1.75 or later

Install

cargo install listsome

Create a Site

listsome init my-projects
cd my-projects

This creates listsome.toml, a projects/ directory, and a .gitignore. Edit listsome.toml to set your site name, author, URL, and webmention endpoint. See the configuration reference for details.

Add a Project

listsome new smart-thermostat --title "Smart Thermostat" --difficulty intermediate

Edit projects/smart-thermostat/index.md with your content.

Build

listsome build

Generates output/index.html, output/<slug>/index.html for each project, and output/rss.xml.

Preview

listsome serve --open

Opens a browser at http://127.0.0.1:8080 with live reload. Edit your project files and the browser refreshes automatically.

Deploy

Copy the output/ directory to any static host (Netlify, Codeberg Pages, S3, nginx, etc.).

Command-Line Tool Reference

CommandDescription
listsome init [PATH]Initialize a new site
listsome new <SLUG>Create a new project
listsome buildBuild the static site
listsome serveStart development server
listsome check [PROJECT]Validate projects
listsome listList projects with filters
listsome webmention fetch|show|testWebmention management (coming soon)

Global flags: -v (verbose), -q (quiet), -C <FILE> (config path), --color <WHEN>.

Project Format Reference

Philosophy

Write standard Markdown with YAML frontmatter. Listsome recognizes patterns through convention, not custom syntax. Your files render anywhere Markdown does.

Folder Structure

projects/
└── smart-thermostat/
    ├── index.md          # Project content (required)
    └── assets/           # Images, downloads (optional)
        ├── hero.jpg
        ├── wiring-diagram.png
        └── firmware.ino
  • index.md is required, everything else is optional
  • Metadata goes in frontmatter, not separate config files
  • Assets referenced by relative path: ./assets/hero.jpg

Example Project

---
title: DIY Smart Thermostat
description: A $20 ESP32-based smart thermostat for Home Assistant
difficulty: intermediate
time: 4 hours
cost: 23.50
categories: [home-automation, electronics]
author: Your Name
date: 2026-03-08
---

# DIY Smart Thermostat

![Finished project](./assets/hero.jpg)

Replace your old thermostat with a smart, WiFi-enabled version
that integrates with Home Assistant.

## What You'll Need

| Item | Qty | Cost | Source |
|------|-----|------|--------|
| ESP32 DevKit | 1 | $6.00 | [Example](https://example.com) |
| DHT22 Sensor | 1 | $4.50 | [Adafruit](https://adafruit.com) |
| 5V Relay Module | 1 | $3.00 | [Example](https://example.com) |

## Step 1: Test Your Components

Connect the DHT22 to the ESP32 (VCC → 3.3V, GND → GND, Data → GPIO4)
and upload the test sketch.

## Step 2: Wire the Relay

Connect 24VAC control: R to relay COM, W to relay NO.

**Warning:** Turn off power at the breaker before proceeding.

## Step 3: Install the Software

Flash the firmware with PlatformIO, then configure WiFi and MQTT.

Frontmatter Schema

Required fields:

title: "Project Name"            # Display title (3-100 chars)
description: "Short summary"     # For listings, SEO (10-200 chars)

Optional:

difficulty: beginner             # beginner | intermediate | advanced
time: 4 hours                    # Estimated duration
cost: 23.50                      # Estimated total cost
currency: USD                    # ISO 4217 code
categories: [electronics]        # Primary categories
tags: [arduino, sensor]          # Searchable tags
author: Your Name                # Display name
date: 2026-03-08                 # ISO 8601

Advanced:

featured: true                   # Highlight on index page
hidden: false                    # Exclude from listings
draft: true                      # Work in progress
related: [other-project-slug]    # Related projects
dangerous: true                  # Shows warning banner
hero: ./assets/hero.jpg          # Image for index listings

Section Conventions

Listsome recognizes these H2 headers and extracts structured data:

HeaderExtracted as
## What You'll Need / ## Materials / ## BOMBill of Materials
## Tools / ## EquipmentTool list
## Step N: / ## Part N: / ## Phase N:Numbered steps
## Troubleshooting / ## FAQ / ## Common IssuesCollapsible sections
## Downloads / ## Files / ## AssetsDownload links with metadata

BOM Tables

Tables under a materials header are parsed as structured BOM data. Recognized column names (case-insensitive):

  • Item: Item, Part, Component, Name, Material
  • Qty: Qty, Quantity, Count, Amount
  • Cost: Cost, Price, Unit Cost, Each
  • Source: Source, Link, Buy, Vendor, Supplier
  • Notes: Notes, Description, Comment, Note
| Item | Qty | Cost | Source | Notes |
|------|-----|------|--------|-------|
| ESP32 | 1 | $6.00 | [Buy](link) | Any ESP32 works |

Step Headers

Headers matching ## Step N: Title, ## Part N: Title, or ## Phase N: Title are extracted as numbered steps. A table of contents is generated from the step titles.

Emoji Callouts

Bold text starting with a recognized prefix renders as a styled callout box:

Warning: High voltage present Tip: Buy in bulk to save 40% Note: App requires iOS 14+

Recognized prefixes include: warning, hot, tip, note, pro tip, caution.

Asset Conventions

Naming

assets/
├── hero.jpg              # Main image for listings
├── thumbnail.jpg         # Optional listing thumbnail override
├── step-01-breadboard.jpg   # Step images
├── step-02-wiring.jpg
├── diagram.svg           # Vector graphics
├── firmware.ino          # Code downloads
└── schematic.pdf         # PDF documents

Referencing Assets

# Standard image
![Alt text](./assets/photo.jpg)

# Video
<video src="./assets/demo.mp4" poster="./assets/demo-thumb.jpg"></video>

# Download link (renders as button)
[Download STL](./assets/model.stl)

Minimal Example

---
title: Paperclip Antenna
description: Free TV antenna from a paperclip
difficulty: beginner
time: 5 minutes
cost: 0
---

# Paperclip Antenna

Need free over-the-air TV? Unbend a paperclip.

## What You Need

| Item | Qty | Cost |
|------|-----|------|
| Paperclip | 1 | $0 |
| Coax adapter | 1 | $5 (optional) |

## Steps

1. Unbend paperclip into "L" shape
2. Insert into TV's coax input center pin
3. Auto-scan for channels

Done. No amplifier needed if you're close to broadcast towers.

Under 50 lines including frontmatter. Listsome makes it look professional.

Site Configuration

Listsome is configured via listsome.toml in your site root. Run listsome init to generate a default config, then edit it to match your setup.

Full Example

[site]
name = "My DIY Projects"
url = "https://projects.example.com"
description = "Step-by-step guides for things I built"
language = "en"
author = "Your Name"
about = "https://yourdomain.com/about"
email = "you@example.com"
source_repo = "https://codeberg.org/username/my-projects"

[site.fediverse]
mastodon = "@username@mastodon.social"

[build]
output_dir = "./output"
theme = "default"
drafts = false
parallel_jobs = 8
incremental = true

[webmention]
enabled = true
endpoint = "https://webmention.io/yourdomain.com/webmention"
require_approval = true
notify = false

[dev]
base_url = "http://localhost:8080"
port = 8080

[deploy]
host = "your-server.local"
user = "deploy"
path = "/var/www/site"

[fediverse]
enabled = false
mastodon_instance = "https://mastodon.social"
mastodon_token = ""
auto_syndicate = false
default_hashtags = ["#DIY", "#makers"]

[site]: Site Metadata

FieldTypeDescription
namestringSite title, shown in header and page titles
urlstring (optional)Production URL. Used for absolute links in feeds and sitemaps
descriptionstringShort site description, shown below the site name in the header
languagestringLanguage code for the HTML lang attribute (default: en)
authorstringDefault author name for projects without an explicit author in frontmatter. Also used in the footer copyright
aboutstring (optional)URL to your about page. Sets the u-url on your author h-card for IndieWeb identity verification
emailstring (optional)Contact email. Shown as a “Reply via email” link on project pages
source_repostring (optional)Repository URL. Enables “Edit This Page” links that point to the source markdown

Fediverse Handles (under [site.fediverse])

These live under [site.fediverse] and are optional: they enable sharing features on project pages.

FieldTypeDescription
mastodonstring (optional)Your full Mastodon handle (for example, @username@mastodon.social). Enables a “Share on Mastodon” link on project pages
pixelfedstring (optional)Your Pixelfed username (for photo gallery integration)
peertubestring (optional)Your PeerTube channel
blueskystring (optional)Your Bluesky handle (secondary)

[build]: Build Settings

FieldTypeDefaultDescription
output_dirstring./outputWhere the generated site is written
themestringdefaultTheme name (currently unused, single built-in theme)
draftsbooleanfalseInclude projects with status: draft in builds
parallel_jobsintegernumber of CPU coresHow many projects to build concurrently
incrementalbooleantrueSkip projects whose source has not changed since last build
base_urlstring (optional)noneSet this for production deployments where the site lives at a subpath

[webmention]: Webmention Settings

Webmentions let other sites notify you when they link to your projects. Requires endpoint to be configured.

FieldTypeDefaultDescription
enabledbooleantrueEnable webmention sending
endpointstringhttps://webmention.io/yourdomain.com/webmentionYour webmention endpoint (get one at webmention.io)
require_approvalbooleantrueHold incoming webmentions for review instead of publishing automatically
notifybooleanfalseSend email notifications for new webmentions (requires your endpoint to support this)

[dev]: Development Settings

Configure the local development server.

FieldTypeDefaultDescription
base_urlstring (optional)noneBase URL for local development (e.g., http://localhost:8080)
portinteger8080Port for the local development server

[deploy]: Deployment Settings

Configure remote deployment via listsome deploy.

FieldTypeDefaultDescription
hoststring (optional)noneRemote host (e.g., your-server.local)
userstring (optional)noneSSH user for remote deployment
pathstring (optional)noneRemote path where the site will be deployed
portstring (optional)nonePort for accessing the deployed site (used in output messages)

[fediverse]: Fediverse Syndication

Configure automatic posting to Mastodon when you publish or update a project.

FieldTypeDefaultDescription
enabledbooleanfalseEnable auto-syndication
mastodon_instancestringhttps://mastodon.socialYour Mastodon instance URL
mastodon_tokenstring(empty)Your Mastodon API token
auto_syndicatebooleanfalseAutomatically post when a project is published or updated
default_hashtagsarray["#DIY", "#makers"]Hashtags to include in syndicated posts

To get a Mastodon API token: settings → Development → New Application, then copy the access token.

Author Fallback

When creating a project, the author is determined in this order:

  1. --author flag on listsome new
  2. author field in the project’s frontmatter
  3. site.author from listsome.toml
  4. USER or USERNAME environment variable
  5. "Anonymous" as final fallback

Command-line Tool Flags

These fields can also be set via command-line tool flags on listsome init:

FlagConfig Field
--namesite.name
--authorsite.author
--urlsite.url
--aboutsite.about

Roadmap

Current State (v0.1.0)

Listsome is functional for creating and publishing DIY project sites. See overview for what works today.

Planned

The following features are documented in design specs but not yet implemented:

Short Term

  • Webmention support: Fetch, display, and send webmentions
  • Image optimization: Automatic resizing and WebP/AVIF conversion
  • Syntax highlighting: Code blocks with syntect-based highlighting
  • Search index: Full-text search without external services
  • Category and tag pages: Auto-generated listing pages per category/tag

Longer Term

  • POSSE syndication: Publish to Mastodon, Pixelfed, PeerTube from the command-line tool
  • Print stylesheets: Built-in print-friendly CSS for generated sites
  • Import tools: Import from Instructables, Hackaday, and other platforms
  • Video support: Transcoding and thumbnail generation
  • Multi-language sites: i18n support for international makers
  • Plugin system: Extend Listsome with custom generators and themes
  • 3D model viewer: Inline STEP/STL viewing in project pages

Design Status

  • IndieWeb integration: Documented; microformats2 markup is generated by default templates, webmention command-line tool is stubbed
  • Fediverse syndication: Configuration model exists in listsome.toml, no implementation
  • Interactivity: Research done on webmentions, email replies, and Giscus integrations for adding comments/reactions to project pages

Contributors Guide

Architecture

Listsome follows a pipeline architecture: source content → parse → render → output.

projects/*/index.md  ──►  Parser  ──►  Renderer (MiniJinja)  ──►  output/
(frontmatter + MD)        (pulldown-cmark)  +                   (static HTML)
                                              templates/

Modules

ModuleResponsibility
src/cli.rsCommand-line argument parsing with clap
src/commands.rsCommand implementations that wire up the pipeline
src/config.rslistsome.toml loading, default config creation
src/parser/mod.rsFrontmatter extraction, Markdown→HTML, step/BOM parsing
src/render/mod.rsMiniJinja template rendering, context builders
src/generator/mod.rsSite generation orchestration (discover, parse, render, copy assets, generate index + feed)
src/server/mod.rsAxum-based dev server with WebSocket live reload and file watching
src/model/project.rsProject, Step, ProjectMetadata, Difficulty, ProjectStatus
src/model/site.rsSiteConfig, BuildConfig, WebmentionConfig, FediverseConfig
src/error.rsListsomeError enum with typed error variants
src/templates/Built-in MiniJinja templates (base.html, index.html, project.html, feed.atom)

Data Flow

  1. listsome build loads listsome.toml via config::find_and_load_config()
  2. generator::SiteGenerator::discover_projects() walks projects/ looking for index.md
  3. Each file is parsed by parser::parse_project() which extracts frontmatter and renders Markdown to HTML
  4. Headers matching ## Step N: Title become Step structs; BOM tables become MaterialItems
  5. render::TemplateRenderer renders each project into HTML using MiniJinja templates
  6. Assets from projects/<slug>/assets/ are copied to output/<slug>/assets/
  7. output/index.html (project listing) and output/feed.atom are generated

Design Patterns

  • Pure functions with no shared mutable state
  • Result<T, ListsomeError> throughout for error handling
  • Immutable Project and ProjectMetadata structs
  • SiteConfig with sensible defaults via Default trait
  • Template renderer is created once and reused across all projects

Building

cargo build
cargo build --release   # Optimized binary

Testing

cargo test              # Run all tests
cargo test -- --nocapture  # Show test output

Tests are in #[cfg(test)] modules within each source file (parser, render, generator, config, server).

Code Style

  • cargo clippy: Pedantic and nursery lints enabled (warnings during dev, not errors)
  • cargo fmt: 100-character line width, Unix line endings
  • Conventional commit messages for pull requests

How to Contribute

  1. Open an issue to discuss your proposed change
  2. Fork the repository
  3. Make your changes with tests
  4. Run cargo test and cargo clippy
  5. Submit a pull request