pysocha is a static site generator of as simple a variety as we can make for our needs.
Pysocha requires Python 3.8 or newer.
Install from PyPI when a release is available:
python -m pip install pysochaInstall with uv:
uv tool install pysochaInstall directly from this repository:
python -m pip install git+https://github.com/catalystcommunity/pysocha.gitFor local development, use uv from the repository root:
uv sync
uv run pysocha --helpCreate a site with this shape:
site/
config.yaml
content/
pages/
index.md
blog_posts/
first-post.md
extra_files/
main.css
templates/
page.jinja2
blog.jinja2
listing.jinja2
tags.jinja2
tag.jinja2
authors.jinja2
author.jinja2
Build the site:
pysocha build --config-file config.yamlShow generated file paths while building:
pysocha build --config-file config.yaml --verbosePreview the generated site locally:
pysocha preview --config-file config.yamlThe generated files are written to outputDir from your config. Extra files are
copied from content/extra_files into that output directory.
Blog posts are Markdown files in content/blog_posts. Required fields:
---
Title: "Post title"
PostedDate: "2026-07-14T10:00:00-06:00"
Author: "Author Name"
AuthorEmail: "author@example.com"
---AuthorEmail is required for RSS output. Atom uses Author for display names.
Optional fields:
Tags: list of tags for tag pagesUnlisted: set totrueto keep a post out of listings and feedshookorsummary: feed summary textTemplate: per-post template overrideExtension: per-post output extension override
When blogConfig.atomFeeds is true, Pysocha generates feeds for listed blog
posts:
atom.xmlrss.xml
RSS is generated only when disableRSS is not true and every listed post has
AuthorEmail in frontmatter. The atomFeeds name is kept for compatibility
with existing configs.
blogConfig:
atomFeeds: True
disableRSS: FalsePysocha can syntax-highlight triple-backtick fenced code blocks at build time with
Pygments. The generated pages stay static: highlighting is emitted as HTML, and
with the default noclasses: True setting the color styles are emitted inline.
Syntax highlighting is enabled by default.
markdown:
syntaxHighlighting:
enabled: True
style: "catppuccin-mocha"
cssClass: "highlight"
noclasses: Truestyle defaults to catppuccin-mocha. Pysocha includes all Catppuccin flavors:
catppuccin-lattecatppuccin-frappecatppuccin-macchiatocatppuccin-mocha
You can also use any style name installed with Pygments, such as monokai,
dracula, or friendly.
To keep CSS out of the generated markup, set noclasses: False; Pygments will
emit token classes instead of inline token colors. In that mode, include matching
Pygments CSS in your template or copied static files.
To disable highlighting for a site:
markdown:
syntaxHighlighting:
enabled: FalseThemes are Pygments Style classes. Register one before rendering markdown:
from pygments.style import Style
from pygments.token import Keyword, Name, Text
from pysocha.markdown import register_pygments_style
class MyTheme(Style):
background_color = "#111111"
default_style = "#eeeeee"
styles = {
Text: "#eeeeee",
Keyword: "#ffcc66",
Name.Function: "#66d9ef",
}
register_pygments_style("my-theme", MyTheme)Then select it in config:
markdown:
syntaxHighlighting:
enabled: True
style: "my-theme"