Skip to main content

A minimalistic, self-hosted, statically rendered, micro-blogging engine.

Project description

readthememo

A minimalistic, self-hosted, statically rendered, micro-blogging engine.


PyPI - Version builds.sr.ht status


Overview

readthememo (command: memos) is a simple tool that transforms memos into static HTML pages. It's designed for quick, low-friction publishing of short-form content without the complexity of traditional blogging platforms.

Features

  • Minimal dependencies: Built with Python 3.11+ using Jinja2, marko, and tyro
  • Static output: Generates standalone HTML files
  • CommonMark (markdown) input: Write your content in a simple, readable format
  • LogSeq-ready: Directory format works seamlessly with LogSeq
  • Responsive design: Uses Pico CSS for clean, semantic styling
  • CLI interface: Simple command-line tool for building your site
  • Self-contained: No database or server requirements

Installation

pipx install readthememo

Usage

Basic Usage

Build HTML from a single CommonMark file:

memos path/to/your/memos.md output.html

Build HTML from a directory with CommonMark files (e.g. LogSeq journals):

memos path/to/your/memos/ output.html

Standard Input/Output

Read from stdin and write to stdout:

cat memos.md | memos - > output.html

CommonMark Format

site.yaml:

---
title: "My Blog Title"
meta:
  author: "Your Name"
header:
  headline: "My Blog"
  motto:
  - "A description of your blog"
  - "by Your Name"
---

2025-01-01.md:

## My First Memo #InterstingTopic

This is the content of my first memo.

It can contain <strong>HTML tags</strong> and multiple paragraphs.

2025-01-02.md:

- ## Hello from LogSeq
    - This memo is bullet point heavy, as can be seen when reading raw content from a LogSeq journal.
    - The idea is to strip the first two levels of bullet points to "flatten" the structure.

Key features:

  • Natural prose: Write directly in markdown (CommonMark)
  • LogSeq compatible: Use YYYY-MM-DD.md or YYYY_MM_DD.md naming; strip the first two levels of bullet-points
  • Tag extraction: Add tags to titles using #tag format

Alternative: Single File with YAML Frontmatter

You can also use a single markdown file with YAML frontmatter:

---
title: "My Blog Title"
meta:
  author: "Your Name"
header:
  headline: "My Blog"
  motto:
  - "A description of your blog"
  - "by Your Name"
---

# 2025-01-01

## My First Memo

This is the content of my first memo.

It can contain <strong>HTML tags</strong> and multiple paragraphs.

# 2025-01-02

## Another Memo #tech #thoughts

This memo has tags listed after the title.

This format is useful for smaller blogs or when you prefer to keep everything in one file.

LogSeq Integration

The directory structure is designed to work seamlessly with LogSeq:

Setup:

  • No special care needed for LogSeq
  • Create a site.yaml file at the base of your LogSeq graph
title: "My Blog Title"
meta:
  author: "Your Name"
header:
  headline: "My Blog"
  motto:
  - "A description of your blog"
  - "by Your Name"

LogSeq workflow:

  • Open your memos directory as a LogSeq graph
  • Create daily notes using LogSeq's journal feature
  • Use ## Title #tag format for your memo titles
  • Write content underneath (nested)
  • Repeat for other articles on the same day

Publishing workflow:

memos path/to/logseq-graph > output.html

File naming compatibility:

  • LogSeq uses YYYY_MM_DD.md format by default (underscores), but will happily use files named using hyphens ( YYYY-MM-DD.md)
  • readthememo supports both YYYY-MM-DD.md and YYYY_MM_DD.md

LogSeq features that work:

  • Daily notes: Perfect for memo-style content
  • Tags: Use #tag in titles for automatic tag extraction
  • Block references: Can be used within memo content
  • Linked references: Work normally within LogSeq

What gets published:

  • Only files matching YYYY-MM-DD.md or YYYY_MM_DD.md patterns
  • Other LogSeq files (config, assets, etc.) are ignored
  • Content is processed as standard markdown with HTML passthrough

Project Structure

├── src/readthememo/        # Main application code
│   ├── templates/          # Jinja2 HTML templates
│   ├── cli.py              # Command-line interface
│   ├── core.py             # Core parsing and rendering logic
│   └── templates.py        # Template environment setup
├── static/                 # CSS and static assets
├── tests/                  # Test suite
├── docs/decisions/         # Architecture Decision Records
└── memos/                  # Example memos documenting this project itself

Development

You will need uv, install it first through your method of choice. For example with pipx:

pipx install uv

Running Tests

uv run pytest

Code Quality

The project uses ruff for linting and formatting:

uv run ruff check
uv run ruff format

Pre-commit Hooks

Set up pre-commit hooks:

uv run pre-commit install

Architecture

This project follows a functional core, imperative shell architecture:

  • Core: Pure functions for parsing TOML and rendering HTML
  • Shell: CLI interface and I/O operations
  • Templates: Jinja2 templates for HTML generation

See docs/decisions/ for detailed architecture decisions.

Versioning and Publishing

Version Management

This project follows Calendar Versioning using the YYYY.PATCH format:

  • Year: Current calendar year (e.g., 2025)
  • Patch: Incremental release number within the year (e.g., 8)
  • Example: 2025.8

To create a new release:

  1. Update the version:

    uv version --frozen --bump patch
    uv lock
    
  2. Update the changelog in CHANGELOG.md:

    • The information about the should be there already
    • What should be left is to add the release information:
    sed -i --posix -e "/## \[Unreleased]/ a \\\n## [$(uv version | awk '{print $2}')] - $(date --iso=date)" CHANGELOG.md
    
  3. Commit the changes:

    git commit -m "build: Release version $(uv version | awk '{print $2}')" pyproject.toml uv.lock CHANGELOG.md
    

Publishing to PyPI

  1. Build the package using uv:

    # Clean-up previous builds
    git clean -xdf dist/
    # Build now
    uv build
    
  2. Ensure the keyring tool is available for the tokens, and define the tokens (only once per machine or after the tokens are refreshed):

    uv tool install keyring
    keyring set https://test.pypi.org/legacy/ __token__
    keyring set https://upload.pypi.org/legacy/ __token__
    
  3. Publish to PyPI (for test releases):

    uv publish --index testpypi --username __token__
    
  4. Publish to PyPI:

    uv publish --username __token__
    

Automated CI/CD

The project uses SourceHut Builds for continuous integration:

  • Test Matrix: Runs tests across Python versions (3.11, 3.12, 3.13, and 3.14)
  • Package Testing: Validates both source distributions and wheels
  • Site Publishing: Automatically publishes to readthememo.app when changes are pushed to main

All CI configuration is in the .builds/ directory.

License

GPL-3.0-or-later

Contributing

  1. Check existing Architecture Decision Records in docs/decisions/
  2. Follow the functional core, imperative shell pattern
  3. Write tests for new functionality
  4. Ensure code passes ruff linting
  5. Update documentation as needed

Examples

See the memos/ directory for this very repository memos; with site.toml configuration and date-based .md files.

Also take a look at the test files (.md) in tests/cases/ for single-file examples.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

readthememo-2025.8.1.tar.gz (9.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

readthememo-2025.8.1-py3-none-any.whl (10.4 kB view details)

Uploaded Python 3

File details

Details for the file readthememo-2025.8.1.tar.gz.

File metadata

  • Download URL: readthememo-2025.8.1.tar.gz
  • Upload date:
  • Size: 9.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.0

File hashes

Hashes for readthememo-2025.8.1.tar.gz
Algorithm Hash digest
SHA256 eebdee344de251deb18f0e693bcaa6bf089bdbf978a2fae49f3d71c0e048448a
MD5 785d0bebe5aa513201da46a4a37d3eff
BLAKE2b-256 66676981a5b727c7dba4fea2d2ad3c69ad40d1ae457805640828ab75b6683ba0

See more details on using hashes here.

File details

Details for the file readthememo-2025.8.1-py3-none-any.whl.

File metadata

File hashes

Hashes for readthememo-2025.8.1-py3-none-any.whl
Algorithm Hash digest
SHA256 9e669c59f00cd4bb1169f7e3ad860d0b565aaee080e67fc2e0ee5abf4b2b3e5b
MD5 6ee7d14876d7993dd220ea8e267f01d0
BLAKE2b-256 f74ba3e785d9ebb3785842cf5063a65c00c38c9378208a6ac509ec646ace5a57

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page