Skip to main content

text-compositor

日本語版 (Japanese version)

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 — pipx or a venv does 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 any venv/pipx environment 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. Run text-compositor --check-env afterward to confirm the environment is set up correctly.

There are two ways to install and run this tool.

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 playwright package 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-latest ships 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 d2 command 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).

--watch keeps running after the first build and rebuilds whenever it detects a save in the config, the input files, or a custom .typ template. A failed build does not stop it; fix the file and save again. Press Ctrl+C to stop. Changes to files outside the project directory (e.g. images referenced via ../) are not detected.

--if-changed skips the build, like make, when the output PDF is newer than the config, the input files, the template, and text-compositor itself (judged by modification time only). Without it, the PDF is always regenerated. Changes to Typst's version, to files outside the project directory, or to environment variables used by variables are not detected. On CI, actions/checkout resets every file's modification time, so restore the output directory from a cache if you want the skip to take effect.

--clean deletes the output PDF and the intermediate files under .text-compositor/ (temp_build.typ, _template.typ, _common.typ) without building. --clean-cache additionally deletes the diagram cache (.text-compositor/cache/). Input files and the config are never deleted.

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/SampleDocument.pdf. Two more samples show other templates: sample/paper/ (two-column paper layout, template.path: paper) and sample/universe-ilm/ (a Typst Universe template used through an adapter; needs network access on the first build).

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

MIT License

Release files for text-compositor 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for text-compositor 0.3.0
File Size Uploaded
text_compositor-0.3.0.tar.gz 99.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for text-compositor 0.3.0
File Interpreter ABI Platform
text_compositor-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size:177.6 kB

Release files / text_compositor-0.3.0.tar.gz

Download URL text_compositor-0.3.0.tar.gz
Size 99.7 kB
Tags Source
SHA-256 checksum
How to use checksums
d5cd7ac858ffce0756c854521e4bcfc95b404d458fd6030e630eb4230db3efaf
BLAKE2b-256 checksum
How to use checksums
84fda1d10a3b5eec7abfa803d82e0abdfbcf37d96e1259116c985fe5f831a052
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 19, 2026.

Transparency log

Release files / text_compositor-0.3.0-py3-none-any.whl

Download URL text_compositor-0.3.0-py3-none-any.whl
Size 77.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2f5a6b182f9f41f1fd8e7cb5ad23cf5bda11dd4bc66eb489c2dbc764d8b5c5dc
BLAKE2b-256 checksum
How to use checksums
56cd9011b72339baf4d1b4e6c430e6ce9bd0548ca846180989c2c8f2e67f905e
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 19, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page