Run in CI
Run the same container in CI that you test locally. Build the documentation first, mount its static output read-only, and publish the PDF directory as a pipeline artifact.
Pipeline shape
Section titled “Pipeline shape”build the docs → inspect Site Build → export manuals → publish PDFsThe export should run only after the documentation production build succeeds, and mounts the directory that build produced.
Worked examples
Section titled “Worked examples”Each supported framework has a repository carrying a runnable project and the workflow that exports it on every push — a complete pipeline to copy rather than a fragment:
| Framework | Repository |
|---|---|
| Docusaurus | Working Docusaurus integration — manuscrio/docusaurus-pdf-export |
| Starlight | Working Starlight integration — manuscrio/starlight-pdf-export |
| MkDocs Material | Working MkDocs Material integration — manuscrio/mkdocs-pdf-export |
All three drive the image with the manuscrio-pdf command rather than docker run, because a
GitHub-hosted runner already has Node and the command supplies the mounts and the ownership flags
for you. Name your own build directory — the three above produce build, dist and site:
- run: npm ci && npm run build # MkDocs: pip install -r requirements.txt && mkdocs build
- name: Export the docs to PDF
- uses: actions/upload-artifact@v7 with: name: manual path: manuscrio-output/*.pdfPin the version, as above. One manuscrio version resolves to exactly one image, so re-running an
old pipeline renders what it rendered the first time.
There is no Manuscrio plugin or GitHub Action to install, and nothing to add to your documentation site. The rest of this page is the container form: what to use on a runner without Node, or wherever you would rather every path were written out.
Pass the licence as a secret
Section titled “Pass the licence as a secret”For CI systems that store multiline secrets as text, expose the signed licence through
MANUSCRIO_PDF_LICENSE:
mkdir -p manuscrio-outputdocker run --rm --init --ipc=host \ --user "$(id -u):$(id -g)" \ -e MANUSCRIO_PDF_LICENSE \ -v "$PWD/build:/input:ro" \ -v "$PWD/manuscrio-output:/output" \ ghcr.io/manuscrio/manuscrio-pdf:1.0.0 export /input --output-dir /outputIf the CI system writes secrets to files, mount the file the runner wrote and point
MANUSCRIO_PDF_LICENSE_FILE at its in-container path. Below, the runner supplies the host path through
MANUSCRIO_PDF_LICENSE_HOST_FILE; the first line validates and gives it the shorter local name
licence_file. MANUSCRIO_PDF_LICENSE_FILE is the separate, in-container path Manuscrio reads:
licence_file=${MANUSCRIO_PDF_LICENSE_HOST_FILE:?the CI runner must provide the licence file path}mkdir -p manuscrio-outputdocker run --rm --init --ipc=host \ --user "$(id -u):$(id -g)" \ -e MANUSCRIO_PDF_LICENSE_FILE=/run/secrets/manuscrio-license \ -v "$PWD/build:/input:ro" \ -v "$licence_file:/run/secrets/manuscrio-license:ro" \ -v "$PWD/manuscrio-output:/output" \ ghcr.io/manuscrio/manuscrio-pdf:1.0.0 export /input --output-dir /outputA job with no licence still succeeds and produces complete manuals carrying the evaluation watermark. A lapsed subscription does not remove a licence automatically: the existing file is honoured during its 30-day grace period and then fails. Returning to Evaluation Mode requires deliberately removing the licence.
Keep the artifacts collectable
Section titled “Keep the artifacts collectable”Pass --user "$(id -u):$(id -g)", as above. Without it the PDFs belong to the image’s own user,
and a later step that tries to move or archive them may not be able to. The
container invocation page covers the other flags.
PDF file names come from manual titles, so they contain spaces and change when an editor retitles a manual. Quote the paths in archive steps, and do not build a downstream contract on the names — see manual IDs and output file names.
Size the runner
Section titled “Size the runner”Manuscrio renders up to four manuals in parallel by default. Set a lower value when the runner is memory constrained:
mkdir -p manuscrio-outputdocker run --rm --init --ipc=host \ --user "$(id -u):$(id -g)" \ -v "$PWD/build:/input:ro" \ -v "$PWD/manuscrio-output:/output" \ ghcr.io/manuscrio/manuscrio-pdf:1.0.0 export /input --concurrency 2 --output-dir /outputConcurrency is the control that matters most, because each parallel render is a browser. Published CPU, memory, and timeout envelopes are not part of the Public Preview yet; size the runner against your own largest manual and keep that measurement with the pipeline.
Keep release checks fail-closed
Section titled “Keep release checks fail-closed”Do not pass --no-fail-on-clipped in a release pipeline. The default clipping check prevents a
successful job from publishing a manual with content silently cut off. When an export
fails explains what the failure output means and which failures are
contained to a single manual.
Pin the container image to the immutable reference supplied for the release. This keeps local, CI, and rerun behavior aligned.