mdwiki
mdwiki is a small static site builder that turns a directory tree of markdown files into a blog-ready HTML site.
It keeps the authoring model simple:
- directories become URL segments
- each markdown file becomes one HTML page
- local images referenced from markdown are copied into the output site
- index pages and tag pages are generated automatically
Install
Use uv:
uv tool install mdwiki
Or install from source:
uv sync
uv run mdwiki_exec ./example-posts ./dist
CLI
Build a site from a markdown source tree:
mdwiki_exec <source_dir> <dist_dir>
Show the built-in help or version:
mdwiki_exec --help
mdwiki_exec --version
Run the safe incremental mode with a newline-separated changed file list:
mdwiki_exec --changed-files changed.txt ./post ./dist
Example:
mdwiki_exec ./post ./dist
source_dir usually contains:
- markdown posts under dated folders such as
post/2024/04/03/demo.md - optional local images next to each markdown file
- optional
CNAME - optional
config.json
Safe Incremental Build
mdwiki now supports a safe incremental mode aimed at static blog workflows:
- if only markdown files under
post/changed, it rebuilds the affected detail pages - if images or other local assets under
post/changed, it rebuilds posts in the same folder - it always refreshes index pages and tag pages so listing pages stay correct
- if
config.json,CNAME, or files outside the source tree changed, it falls back to a full rebuild
The builder writes a manifest file named .mdwiki-build.json into the output directory.
If the previous output directory is restored in CI, the next run can reuse that manifest and avoid rewriting every article page.
Optional GoatCounter support
You can enable real pageview counters by adding goatcounter_script to your config.json:
{
"goatcounter_script": "<script data-goatcounter=\"https://drunkpig.goatcounter.com/count\" async src=\"//gc.zgo.at/count.js\"></script>"
}
When this field is present:
- article pages render a counter next to the slug
- index pages fetch and display per-article pageviews
When it is absent, mdwiki renders 未知 instead of fake random numbers.
Optional source markdown link
You can also expose the original markdown source for crawlers and readers:
{
"source_markdown_base_url": "https://raw.githubusercontent.com/drunkpig/drunkpig.github.io/master/post"
}
When this field is present, article pages will:
- add a standard
<link rel="alternate" type="text/markdown">tag in<head> - keep the raw markdown URL available to crawlers without showing a visible banner in the page body
Build date in footer
The default footer template renders build_version as a YYYYMMDD date during site generation.
Because GitHub Pages is built from source on every deploy, this date updates for all generated pages on each successful build.
GitHub Pages workflow
The recommended deployment model is:
- Keep markdown source in your repository.
- Restore the previous
dist/directory from cache. - Build the site in GitHub Actions.
- Upload the generated
dist/directory as a Pages artifact. - Deploy with
actions/deploy-pages.
Example workflow:
name: Build and Deploy Pages
on:
push:
branches: ["master"]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- uses: actions/cache/restore@v4
with:
path: dist
key: pages-dist-${{ github.ref_name }}-${{ github.run_id }}
restore-keys: |
pages-dist-${{ github.ref_name }}-
- name: Detect changed files
run: |
if [ "${{ github.event.before }}" = "0000000000000000000000000000000000000000" ]; then
: > changed.txt
else
git diff --name-only "${{ github.event.before }}" "${{ github.sha }}" > changed.txt
fi
- name: Install mdwiki
run: pip install mdwiki
- name: Build site
run: |
if [ -s changed.txt ]; then
mdwiki_exec --changed-files changed.txt ./post ./dist
else
mdwiki_exec ./post ./dist
fi
- uses: actions/cache/save@v4
if: github.event_name == 'push'
with:
path: dist
key: pages-dist-${{ github.ref_name }}-${{ github.run_id }}
Develop with uv
uv sync
uv run mdwiki_exec ./post ./dist
uv build
Publish to PyPI:
git tag -a v0.3.7 -m "Release v0.3.7"
git push origin master v0.3.7
Pushing a new v* tag triggers the bundled GitHub Actions release workflow, which builds the package with uv and publishes it to PyPI.
Notes
CNAMEis optional.- The bundled default theme is stored under
mdwiki/templates/default. mdwiki_execis the supported public CLI entrypoint.
Metadata
Release files for mdwiki 0.3.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| mdwiki-0.3.7.tar.gz | 40.0 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mdwiki-0.3.7-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 80.2 kB
Release files / mdwiki-0.3.7.tar.gz
| Download URL | mdwiki-0.3.7.tar.gz |
|---|---|
| Size | 40.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
216607d4cc12bf957fe70c9aa10beb2ffb94a07dd3c440bd7d58dd8aac6d9b25
|
|
BLAKE2b-256 checksum How to use checksums |
d937d1f463398b3e8e682a3e5337b1810621b97889e1d93a3a8002ad30fd831f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / mdwiki-0.3.7-py3-none-any.whl
| Download URL | mdwiki-0.3.7-py3-none-any.whl |
|---|---|
| Size | 40.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5b5d2688a1884e076458d6508b7ab10178a29140b0a51733f4b877c7b9ba3958
|
|
BLAKE2b-256 checksum How to use checksums |
92414aaba39982102f266555479caebf5739ee9edbdd1b0b8bcef1ba1e0804c3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.9.18 {"installer":{"name":"uv","version":"0.9.18","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for mdwiki 0.3.7
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.