This repository is tooling: a MkDocs plugin + build scripts + a composite GitHub Action for building “text projects” (Markdown chapters -> MkDocs site + EPUB).
There is also a sample content repo in whattodo/ (used as a fixture/demo).
text_forge/plugin.py: MkDocs plugin (theme overrides, editor integration, dev save endpoint)text_forge/build.py: Python build helpers wrapping the same scriptstext_forge/cli.py: CLI entrypoint (text-forge epub|build|info;combineis TODO)scripts/mkdocs-combine.py: Stage 1 combiner (mkdocs.yml nav-driven)scripts/pymdown-pandoc.lua: Stage 2 Pandoc Lua filter (PyMdown blocks -> Pandoc-friendly)scripts/process-epub-meta.py: Metadata placeholder processor forepub/book_meta.ymlscripts/tests.py: pytest tests using fixtures inscripts/fixtures/mkdocs/overrides/: Material theme overrides + editor UImkdocs/hooks/nobr_emoticons.py: MkDocs hook wrapping ASCII emoticons inmd-nobraction.yml: composite GitHub Action (runs pipeline inside GitHub Actions)
- Python:
>=3.11(seepyproject.toml) - Runner/package manager:
uv(seeuv.lock) - Tests:
pytest(dev dependency group) - Formatting/lint: Makefile references
ruff(ensure it exists in the uv env) - External:
pandocis required for EPUB generation
Note: some environments don’t have python on PATH. Prefer uv run python / uv run pytest.
make install- Runs
uv --project <repo> syncfor this repo.
- Runs
make format- Runs import sorting + formatting via ruff.
make lint- Runs ruff checks.
If ruff isn’t available, add it to the project dev deps and rerun make install.
make check-i18n- Validates
mkdocs/overrides/assets/js/translations.jsonagainst HTML/JS usage. - Script:
.github/skills/check-i18n/scripts/check_i18n.py.
- Validates
Content repos use the text-forge CLI commands directly (not the root Makefile).
Use whattodo/ as a local content repo for development.
-
Fast preview (no EPUB, no pandoc required):
cd whattodo && make serve
-
Build EPUB only (requires
pandoc):cd whattodo && make epub
-
Full build (EPUB + site):
cd whattodo && make all
-
Clean outputs:
cd whattodo && make clean
Primary tests are in tests/test_pipeline.py and validate pipeline functionality
using self-contained fixtures in tests/fixtures/.
Recommended full run (from text-forge root):
make test
Run a single test:
uv run pytest tests/test_pipeline.py -k test_combined_has_all_chapters -v
Examples:
uv run pytest tests/test_pipeline.py -k combined -v# All combined testsuv run pytest tests/test_pipeline.py -k pandoc -v# All pandoc testsuv run pytest tests/test_pipeline.py -k consistency -v# Consistency tests
Notes:
scripts/conftest.pyshortens pytest node IDs for cleaner output.- Tests will skip if expected outputs/fixtures are missing.
- Imports:
- stdlib, then third-party, then local; keep imports at top unless there is a clear reason (plugin code sometimes lazy-imports).
- Formatting:
- Prefer small helpers and clear intermediate variables over dense expressions.
- Use f-strings; keep line lengths reasonable.
- Types:
- Type public functions; keep
Optional[T]vsT | Noneconsistent within a file. - Use
pathlib.Pathfor filesystem paths.
- Type public functions; keep
- Naming:
snake_case(functions/vars),PascalCase(classes),UPPER_SNAKE_CASE(constants),_privateprefix for internal helpers.
- Error handling:
- Prefer specific exceptions (
FileNotFoundError,subprocess.CalledProcessError). - Use
subprocess.run(..., check=True); surface stderr on failure. - Avoid bare
except:; catch narrowly and re-raise when appropriate.
- Prefer specific exceptions (
- Logging/printing:
- Scripts/CLI:
print()/click.echo()is fine. - MkDocs plugin: use
logging.getLogger("mkdocs.plugins.text-forge").
- Scripts/CLI:
- Safety:
- Keep path-safety checks on the dev save endpoint (
/_text_forge/save), ensuring writes stay withindocs_dir.
- Keep path-safety checks on the dev save endpoint (
- Plain browser JS (no bundler). Current style is an IIFE with strict mode.
- Be defensive around DOM access and network calls.
- Avoid adding heavy dependencies; editor loads Pyodide dynamically.
- mkdocs.yml may use custom tags like
!ENV; loaders should ignore unknown tags rather than crash (seescripts/mkdocs-combine.py,scripts/process-epub-meta.py). - Keep action/workflow versions pinned and inputs documented.
Cursor rules:
- None found (
.cursorrulesand.cursor/rules/do not exist).
Copilot rules (from .github/copilot-instructions.md):
-
Pipeline stages:
- Combine chapters from
mkdocs.yml nav:->build/text_combined.mdviascripts/mkdocs-combine.py - Normalize PyMdown
/// ... ///blocks ->build/pandoc.mdviascripts/pymdown-pandoc.lua - Process metadata placeholders from
epub/book_meta.ymlviascripts/process-epub-meta.py - Render EPUB via
pandoc+epub/epub.css->build/text_book.epub - Build MkDocs site into
site_dir, then copy artifacts tosite_dirroot
- Combine chapters from
-
If you change
scripts/mkdocs-combine.pyorscripts/pymdown-pandoc.lua:- update fixtures in
scripts/fixtures/ - validate via
make CONTENT_ROOT=... test(tests live inscripts/tests.py)
- update fixtures in
-
Packaging note:
pyproject.tomlinstallsmkdocs/overrides+mkdocs/hooksintosys.prefix/share/text-forge/...TextForgePluginlooks there first and falls back to repo-relative paths for development