text-compositor
A tool that treats multiple text files as independent fragments and deterministically composes them into a single human-readable PDF document. Works equally well for AI-generated drafts refined by humans and for existing, hand-authored documents you want to organize and consolidate.
This README covers only the essentials needed to get started quickly. For a full walkthrough of config.yaml and how to write your source documents, see the usage guide (which can also be built into a PDF with cd doc/usage && python ../../build.py). For detailed design rationale and implementation status, see doc/spec.md. Differences from general-purpose tools like Quarto are summarized in doc/diff.md.
Features
- Combines multiple text files (chapters) into a single PDF
- Markdown → AST via markdown-it-py → deterministic conversion to Typst syntax → PDF output
- Outputs other text files to the PDF unchanged
- Separates the tool itself from the documentation (source files), which can live anywhere outside the repository
- Python-centric with minimal downloads, no dependency on external servers or SaaS (runs the same way on GitHub Actions and locally on Windows/Linux/macOS)
Files listed in chapters are handled differently depending on their extension:
.md/.markdown: converted as Markdown.yaml/.yml/.json: rendered as monospaced text with syntax highlighting.dot/.gv,.mmd,.puml/.plantuml/.pu,.d2: each rendered as a one-chapter diagram (Graphviz, Mermaid, PlantUML, D2 respectively).csv: rendered as a structured Typst table- everything else (plain text, code files, etc.): rendered as plain monospaced text
See the usage guide for details.
Requirements
- Python 3.10+
Windows note — Microsoft Store Python is not supported, even inside
pipx/venv: If Python was installed from the Microsoft Store, this tool cannot be used with it, full stop —pipxor avenvdoes not work around this.Windows redirects that Python's writes under
%LOCALAPPDATA%into a package-private folder, and this redirection follows the Store installation into anyvenv/pipxenvironment created from it (verified by testing), breaking every subprocess-based feature (PlantUML, Mermaid, D2) even though the files appear to exist to Python itself.Before installing this tool, install Python from python.org (or another non-Store distribution such as
winget install Python.Python.3.12) and use that Python for the steps below. Runtext-compositor --check-envafterward to confirm the environment is set up correctly.
There are two ways to install and run this tool.
Option A: pip install (recommended)
pipx install text-compositor
pipx installs the tool into an isolated environment and exposes the text-compositor command — recommended for most users. If you're developing this tool itself, use a venv instead so an editable install (pip install -e .) picks up code changes immediately:
python -m venv .venv
.venv/bin/pip install -e . # Windows: .venv\Scripts\pip install -e .
Option B: Clone and run directly (no installation)
pip install -r requirements.txt
No Typst compiler binary is bundled; it's obtained from the typst package (PyPI wheel) installed via pip install above. No additional downloads or installation steps are needed.
Using Mermaid diagrams (optional)
This is only needed if your source documents use ```mermaid fences (or specify an .mmd file directly in chapters). With Option A, install the mermaid extra:
pipx install "text-compositor[mermaid]"
# or, if already installed: pipx inject text-compositor playwright==1.62.0
With Option B (clone and run directly):
pip install playwright==1.62.0
- A Google Chrome or Microsoft Edge installation already present on your system (no new download by default; it's auto-detected and reused at build time)
- The
playwrightpackage above (used only to connect to the existing browser via CDP; Playwright's own browser-download feature is not used by default)
Node.js/npm is not required. At build time, the official single-file Mermaid bundle (mermaid.min.js, ~3.4MB) is fetched and loaded into a headless browser to convert diagrams to SVG (the bundle JS itself is cached under an OS-standard user cache directory — e.g. %LOCALAPPDATA%\text-compositor\Cache on Windows, ~/.cache/text-compositor on Linux — and conversion results are cached under .text-compositor/cache/; neither is re-fetched afterward). None of this is needed for documents that don't use Mermaid.
If no Chrome/Edge is found on the system, the build fails by default. Setting plugins: { mermaid_auto_download: true } instead auto-fetches Playwright's own Chromium, but this download is about 700MB (this setting exists as a last resort for when no pre-installed browser is available; downloading that much by default is intentionally avoided).
Using PlantUML diagrams (optional)
No extra config.yaml settings are needed to use ```plantuml fences in your source documents (or to specify a .puml file directly in chapters) — plugins.plantuml defaults to true and no additional pip install is required.
- If Java (11+) is available locally, it's reused as-is
- Otherwise, Eclipse Temurin JRE (Adoptium distribution, ~49.7MB) is auto-fetched and cached by default under the same user cache directory as above. Setting
plugins: { plantuml_auto_download: false }disables the auto-fetch and fails the build instead - GitHub Actions'
ubuntu-latestships with Java by default, so no extra download happens on CI
The layout engine is the pure-Java Smetana implementation, so no external binary like Graphviz (dot) is required. PlantUML itself (MIT edition, ~17.6MB) is cached under the same user cache directory, and conversion results are cached under .text-compositor/cache/, same as Mermaid.
Using D2 diagrams (optional)
No extra config.yaml settings are needed to use ```d2 fences in your source documents (or to specify a .d2 file directly in chapters) — plugins.d2 defaults to true and no additional pip install is required.
- If the
d2command is available locally, it's reused as-is - Otherwise, the official D2 CLI binary (a single Go executable, ~13MB) is auto-fetched and cached by default under the same user cache directory as above. Setting
plugins: { d2_auto_download: false }disables the auto-fetch and fails the build instead
Unlike Java (used by PlantUML) or a browser (used by Mermaid), GitHub Actions' ubuntu-latest does not ship with D2 preinstalled, so a d2 diagram triggers this ~13MB download on every CI run (this project's workflows don't persist the cache directory across separate runs).
Usage
If installed via pip/pipx (Option A):
text-compositor --config <path/to/text-compositor.config.yaml>
If cloned and run directly (Option B):
python build.py --config <path/to/text-compositor.config.yaml>
If --config is omitted, text-compositor.config.yaml (or .json) located directly in the current directory is auto-detected.
cd my-project/
python /path/to/text-compositor/build.py
Run text-compositor --check-env (or python build.py --check-env) to check your environment (dependencies, Typst version, cached assets, Mermaid/PlantUML/D2 prerequisites) without running a build.
Other flags control runtime behavior only (not document content, which stays entirely in config.yaml): -q/--quiet suppresses [Info]-level logging, -v/--verbose adds extra detail (which chapter is being processed, cache reuse), and --keep-temp keeps the intermediate temp_build.typ around after a successful build instead of deleting it (useful for debugging; it's always kept after a failed build).
See sample/text-compositor.config.yaml for how to write the config file, and the usage guide for details on document:/plugins:, front matter, Marp directives, and more. The Markdown files listed in chapters are concatenated in order to produce the PDF.
Trying the sample
cd sample/
python ../build.py
This generates sample/System_Specification.pdf.
Implementation status
The core feature implemented so far is combining multiple files into a single PDF according to the config file specified via --config (or auto-detected). Expanding CLI options (e.g., overriding the output path) is still in the planning stage. See GitHub Issues for known issues and upcoming plans.
License
Release files for text-compositor 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| text_compositor-0.2.0.tar.gz | 71.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| text_compositor-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size:134.0 kB
Release files / text_compositor-0.2.0.tar.gz
| Download URL | text_compositor-0.2.0.tar.gz |
|---|---|
| Size | 71.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
83b1b8f1dca652d9f51ad44c34e9b869720288580c72dffeb419b503c4603f75
|
|
BLAKE2b-256 checksum How to use checksums |
43ec00786ed55b60dc43f5b8b2014e68c6a8375e4bdd0cafcb5a337713d28704
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency logRelease files / text_compositor-0.2.0-py3-none-any.whl
| Download URL | text_compositor-0.2.0-py3-none-any.whl |
|---|---|
| Size | 62.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
1b0b22d29f06af248d5511398ef11e047b94adae5439fb3eba9d732dc88da192
|
|
BLAKE2b-256 checksum How to use checksums |
0d63e7c798278beaabbd50fa0ba0624445359a26609ccf62ec5c74eec39edcae
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 17, 2026.
Transparency log