This is the repository that backs my Pelican-powered static blog. It's here for anyone to take a peek at.
- Python 3.14+ (recommended via pyenv)
- A GitHub personal access token (for fetching pinned repos)
-
Clone the repository:
git clone https://github.com/jantman/blog.git cd blog -
Create and activate a virtual environment:
python -m venv venv source venv/bin/activate -
Install dependencies:
pip install -r requirements.txt
-
Set up GitHub token for pinned repos (optional but recommended):
export GITHUB_TOKEN="your_token_here" # or export GH_TOKEN="your_token_here"
This project uses Invoke for task automation. List all available tasks with:
inv --list| Task | Description |
|---|---|
inv build |
Build the site with Pelican |
inv clean |
Remove output directory and recreate it |
inv rebuild |
Clean and build (combines both) |
inv serve |
Start HTTP server in output directory (port 8000) |
inv devserver |
Start Pelican dev server with live reload |
inv reserve |
Build and serve |
inv regenerate |
Watch for file changes and regenerate |
inv preview |
Build with production settings (publishconf.py) |
inv post |
Scaffold a new blog post (interactive) |
inv drafts |
List all draft posts |
inv categories |
Show all current blog post categories |
Local development with live reload:
inv devserverThen open http://localhost:8000 in your browser. The site will automatically rebuild when you edit content.
Create a new blog post:
inv postThis will interactively prompt for title and category, then create a new post file and open it in your $EDITOR.
Production preview:
inv preview
inv serveDeployment is automated via GitHub Actions. When you push to the master branch:
- GitHub Actions builds the site using
publishconf.pysettings - Fetches pinned GitHub repos via GraphQL API
- Deploys to GitHub Pages
Pull requests trigger a build-only job for validation.
Note: The GitHub repository must have Pages configured to deploy from "GitHub Actions" (not "Deploy from a branch").
blog/
├── content/ # Blog posts (Markdown)
├── pages/ # Static pages
├── theme/ # Vendored pelican-bootstrap3 theme (Flatly)
├── plugins/ # Local Pelican plugins
│ └── i18n_null.py # Null translations for Jinja2 i18n
├── output/ # Generated site (git-ignored)
├── pelicanconf.py # Development configuration
├── publishconf.py # Production configuration
├── tasks.py # Invoke tasks
├── requirements.txt # Python dependencies
└── .github/workflows/ # CI/CD configuration
pelicanconf.py- Development settings (relative URLs, etc.)publishconf.py- Production settings (absolute URLs, feeds enabled)
The blog uses a vendored fork of pelican-bootstrap3 with the Bootstrap 3 Flatly theme. The theme is located in the theme/ directory.
- sitemap - Installed via pip (
pelican-sitemap), generatessitemap.xml - i18n_null - Local plugin in
plugins/, provides null translations for Jinja2 i18n extension
- Google Analytics 4 - Configured via
GOOGLE_ANALYTICSinpelicanconf.py - Disqus Comments - Configured via
DISQUS_SITENAMEinpelicanconf.py - Shariff Social Sharing - Privacy-friendly sharing buttons (Facebook, LinkedIn, Diaspora)
- GitHub Pinned Repos - Sidebar widget showing pinned GitHub repositories
See requirements.txt:
pelican[markdown]==4.11.0.post0- Static site generator with Markdown supportpelican-sitemap- Sitemap generation plugintypogrify- Typography enhancementsinvoke- Task runnerrequests- HTTP client (for GitHub API)
Content is my own; see individual posts for licensing. Code/configuration is provided as-is for reference.