taggedzi/simplicitypress
SimplicityPress is a minimal, library-first static site generator designed for people who want a clean, predictable Markdown → HTML workflow without the complexity of full CMS platforms or heavyweight SSG ecosystems.
SimplicityPress
SimplicityPress is a minimal, library-first static site generator designed for people who want a clean, predictable Markdown → HTML workflow without the complexity of full CMS platforms or heavyweight SSG ecosystems.
If your needs are simple - posts, pages, tags, basic navigation, and clean output - SimplicityPress gives you a lightweight, transparent tool that is easy to understand, customize, and automate.
✨ What does SimplicityPress do?
- Converts Markdown files into static HTML pages using Jinja2 templates.
- Supports:
- Blog posts (with dates, tags, summaries)
- Static pages (About, Contact, FAQ, Projects…)
- Optional top navigation for pages
- Optional sitemap.xml output (disabled by default)
- Automatic tag index and tag detail pages
- Pagination for large post archives
- Outputs simple, portable HTML you can host anywhere:
- GitHub Pages
- Netlify
- Cloudflare Pages
- A static web server
- Ships with a working default theme so you can publish immediately.
- Includes a local development server for previewing builds.
- Optional fully static search that runs entirely in the browser (no backend).
- Optional RSS + Atom feeds with configurable scopes and output paths.
- Written to be library-first, so you can:
- Integrate it into other Python applications
- Wrap it with a GUI (future feature)
- Script builds programmatically
If you want a system that’s powerful enough to build a clean blog or microsite, yet simple enough to fully understand, SimplicityPress aims to be the perfect middle ground.
🚀 Quick Start
Install in editable mode:
python -m pip install -e .Create a new site:
simplicitypress init --site-root test-siteBuild the site:
simplicitypress build --site-root test-siteServe it locally:
simplicitypress serve --site-root test-site --port 8000🔍 Static Search
SimplicityPress ships an optional, fully static search experience. When enabled, the build emits a search page plus three small artifacts:
assets/search/search_docs.json– document metadata for rendering resultsassets/search/search_terms.json– a compact inverted indexassets/search/search.js– the browser-side search engine
Enable it in site.toml:
[search]
enabled = true
output_dir = "assets/search"
page_path = "search/index.html"
max_terms_per_doc = 300
min_token_len = 2
drop_df_ratio = 0.70
drop_df_min = 0
weight_body = 1.0
weight_title = 8.0
weight_tags = 6.0
normalize_by_doc_len = trueFine-tune the index with these keys:
| Key | Description |
|---|---|
max_terms_per_doc |
Keep only the top N tokens per document (default 300). |
min_token_len |
Minimum token length (default 2). |
drop_df_ratio / drop_df_min |
Drop tokens that appear in too many (ratio) or too few (min) documents. |
weight_body, weight_title, weight_tags |
Control how much each field contributes before TF-IDF scoring. |
normalize_by_doc_len |
When true, divide scores by sqrt(body_token_count) so short/long posts are comparable. |
See docs/static_search.md or docs/search_spec.md for a deeper walkthrough.
🗺️ Sitemap
Prefer crawlable archives? Enable the optional sitemap builder to emit a static
sitemap.xml alongside the rest of your output. Just provide a canonical site
URL and flip the feature switch:
[site]
url = "https://example.com"
[sitemap]
enabled = true
output = "sitemap.xml"
include_index = true
include_posts = true
include_pages = true
include_tags = trueThe sitemap lists every published post, page, tag view, and search page (when
enabled), sorted for stable diffs. Drafts are automatically skipped, and the
default theme exposes a footer link when the feature is on. See docs/sitemap.md
for full configuration details, including exclusion globs and custom output
paths.
📣 Feeds
Ship RSS 2.0 and Atom 1.0 feeds for your readers. Feeds are disabled by
default, require a canonical site.url, and only include posts unless you opt
into pages.
[site]
url = "https://example.com"
[feeds]
enabled = true
rss_enabled = true
atom_enabled = true
max_items = 20
include_posts = true
include_pages = false
include_tags = []
[feeds.summary]
mode = "excerpt"
max_chars = 240Additional knobs let you adjust output filenames, include drafts, or filter to
specific tags. The default theme automatically adds <link rel="alternate">
tags plus footer links when feeds are enabled. See docs/feeds.md for all
options and examples.
Build with overrides:
simplicitypress build --site-root test-site --output test-site/public --include-draftsServe a custom output directory without rebuilding:
simplicitypress serve --site-root test-site --output test-site/public --no-build📄 Pages
SimplicityPress treats pages as standalone, non-blog content - perfect for:
- About
- Contact
- Projects
- FAQ
- Resume
- Privacy Policy
Pages live under:
content/pages/Each page uses Markdown with TOML front matter. At minimum, pages require a title:
+++
title = "About"
slug = "about" # optional; defaults to filename
show_in_nav = true # optional; add this page to the top navigation
nav_title = "About" # optional; label shown in navigation
nav_order = 10 # optional; lower numbers appear earlier
+++
This is the **About** page body.Fields:
-
title(required)
Human-readable title. -
slug(optional)
Defaults to filename (about→/about/). -
show_in_nav(optional)
Adds this page to the top navigation bar. -
nav_title(optional)
Override display label in navigation. -
nav_order(optional)
Controls global nav ordering (lower = earlier). -
date(optional)
Provide a publish timestamp if you plan to include pages in feeds.
Output:
- URL →
/<slug>/ - File →
output/<slug>/index.html
📝 Posts
Posts appear on the blog index and support dates, tags, summaries, and optional cover images.
Posts live under:
content/posts/Example:
+++
title = "My First Post"
date = "2025-12-10"
slug = "my-first-post"
tags = ["meta", "intro"]
draft = false
summary = "A short teaser."
cover_image = "/static/img/posts/first-cover.jpg"
cover_alt = "Abstract purple shapes"
+++
This is the **post body**, written in Markdown.Post features:
-
Must include a
date. -
Casually support tags → generate:
/tags//tags/<tag>/
-
Appear in:
- Home page
- Pagination pages
- Tag listings
Output:
- URL →
/posts/<slug>/ - File →
output/posts/<slug>/index.html
🧭 Navigation
The default theme includes:
- Home (
/) - Tags (
/tags/) - Any pages that opt in with
show_in_nav = true
Navigation is intentionally simple - no dropdowns or multi-level menus.
To include a page:
show_in_nav = true
nav_title = "About"
nav_order = 10After building, navigation might look like:
<nav>
<a href="/">Home</a>
<a href="/tags/">Tags</a>
<a href="/about/">About</a>
<a href="/contact/">Contact</a>
</nav>Pages without show_in_nav = true remain accessible but unlisted.
📚 Documentation
See the docs/ directory for in-depth guides:
- Theme API & stability
- Template variables & context
- Writing templates from scratch
- SPDX header policy (
docs/spdx.md) - CycloneDX SBOM generation (
docs/sbom.md) - Release workflow & changelog automation (
docs/release.md) - Documentation policy (
docs/documentation_policy.md)
📦 Licensing
-
SimplicityPress is licensed under the MIT License.
See theLICENSEfile in the repository root. -
SimplicityPress depends on third-party libraries which may be licensed under different terms
(for example, PySide6, which is available under the LGPL).
See theLICENSES/directory for third-party license notices.
🤝 Contributing
See CONTRIBUTING.md for how to get involved, coding standards, and contribution guidelines.
🛡 Security
See SECURITY.md for reporting vulnerabilities.
🧠 AI Assistance
Portions of SimplicityPress were drafted with help from AI tools (such as ChatGPT/Codex) to accelerate writing and implementation. Maintainers review, test, and accept the final output, so accountability for released code and docs stays with the project. If AI assistance meaningfully shaped a contribution, please note it in the pull request description for transparency.