Warning
printing-press is currently in preview and is not intended for production use.
OpenAPI documentation that is:
- High Quality
- Designed for Agents and Humans
- Beautiful & Clean
- Detailed & Rich
- Fast & Offline
- Instant & Complete
Install the latest tagged release binary with the shell installer:
curl -fsSL https://raw.githubusercontent.com/pb33f/printing-press/main/scripts/install_printing_press.sh | shThat installs the ppress executable.
Install the npm wrapper package:
npm i -g @pb33f/printing-pressInstall with Homebrew:
brew install pb33f/taps/printing-pressBoth the npm package and the Homebrew cask install the ppress executable.
If you prefer go install, Go will still name the binary printing-press because it derives command names from the module path:
go install github.com/pb33f/printing-press@latestFor CI environments, set GITHUB_TOKEN to avoid GitHub API rate limiting:
GITHUB_TOKEN="${GITHUB_TOKEN}" curl -fsSL https://raw.githubusercontent.com/pb33f/printing-press/main/scripts/install_printing_press.sh | shVerify the installed release binary:
ppress version
ppress version --verboseIf you installed via go install, use printing-press version instead.
Each tagged release also publishes a container image to GitHub Container Registry:
docker run --rm ghcr.io/pb33f/printing-press:latest versionTo work with local specs and generated docs, bind mount host directories into the container.
The image already uses ppress as its entrypoint and /work as its default working directory, so mounted files behave like local CLI inputs.
Render docs from your current directory:
docker run --rm -v "$PWD:/work" -w /work ghcr.io/pb33f/printing-press:latest ./openapi.yamlIf you want to keep the input tree read-only and write docs to a separate host directory:
mkdir -p ./api-docs
docker run --rm \
--mount type=bind,src="$PWD",target=/src,readonly \
--mount type=bind,src="$PWD/api-docs",target=/out \
-w /src \
ghcr.io/pb33f/printing-press:latest \
--output /out ./openapi.yamlOn Linux, add --user "$(id -u):$(id -g)" for bind-mounted runs so the container can read and write host files as your current user instead of hitting permission problems or leaving root-owned output behind:
docker run --rm \
--user "$(id -u):$(id -g)" \
--mount type=bind,src="$PWD",target=/work \
-w /work \
ghcr.io/pb33f/printing-press:latest \
./openapi.yamlTo serve docs from the container and view them in your browser, publish the container port to the host:
docker run --rm \
-p 9090:9090 \
--mount type=bind,src="$PWD",target=/work \
-w /work \
ghcr.io/pb33f/printing-press:latest \
--serve --port 9090 ./openapi.yamlThen open http://127.0.0.1:9090.
If you want a different host port, change the left side of -p. For example, -p 8080:9090 still runs ppress on port 9090 inside the container, but you would visit http://127.0.0.1:8080 on the host.
Tagged images are also published with the release version, for example ghcr.io/pb33f/printing-press:<release-version>.
Run a single spec:
ppress ./openapi.yamlScan a repo tree and build an API catalog:
ppress ./servicesBy default the output is written to ./api-docs in your current working directory.
go build -o ppress .
./ppress ./openapi.yamlppress [flags] <spec-path-or-url>
ppress [flags] <directory>Examples:
ppress ./openapi.yaml
ppress --publish --output ./api-docs ./openapi.yaml
ppress --serve --output ./api-docs ./openapi.yaml
ppress ./services
ppress --serve ./servicesIf the input is a file or URL, printing-press renders one documentation site.
Example:
ppress ./openapi.yamlTypical outputs:
index.htmloperations/*.htmlmodels/**/*.htmlbundle.jsonllms.txtAGENTS.md
If the input is a directory, printing-press scans the tree, discovers root OpenAPI documents, groups them into services and versions, and renders one catalog plus one full doc site per discovered spec entry.
Example monorepo:
services/
banking/specs/banking.yaml
auditing/src/things/specs/auditing.yaml
users/src/specs/usersv1.yaml
users/src/specs/usersv2.yaml
Run:
ppress ./servicesThat produces:
- a root catalog at
api-docs/index.html - grouped service/version docs under
api-docs/services/... - per-entry spec docs under
api-docs/services/<service>/versions/<version>/specs/<entry>/...
Catalog builds also emit an LLM discovery tree so an agent can start at the top and drill down into the exact spec it wants:
api-docs/AGENTS.mdapi-docs/llms.txtapi-docs/services/<service>/llms.txtapi-docs/services/<service>/versions/<version>/llms.txtapi-docs/services/<service>/versions/<version>/specs/<entry>/AGENTS.mdapi-docs/services/<service>/versions/<version>/specs/<entry>/llms.txt
The intent is:
- root
AGENTS.mdexplains the catalog and links to all visible services, versions, and spec-entry indexes - root
llms.txtis the compact catalog index - service and version
llms.txtfiles progressively narrow the search space - each spec entry still carries its own full
AGENTS.mdandllms.txt
- default: portable/offline HTML suitable for
file://use --publish: hosted/served HTML asset layout for static hosting, but does not start a server--serve: hosted/served HTML asset layout and starts a local preview server
For GitHub Pages, S3, Netlify, Cloudflare Pages, or similar static hosting, use --publish.
By default, printing-press renders:
- HTML documentation
- JSON artifacts
- LLM output
You can disable any of these with:
--no-html--no-json--no-llm
You can configure the CLI with printing-press.yaml or printing-press.yml.
The CLI will look for it:
- next to the input file or directory
- in the current working directory
CLI flag values take precedence over config file values.
You can also pass it explicitly:
ppress --config ./printing-press.yaml ./servicesExample:
title: Platform Catalog
description: Internal API documentation for all services.
output: ./api-docs
publish: true
scan:
root: ./services
ignoreRules:
- "**/vendor/**"
- "**/testdata/**"
grouping:
serviceOverrides:
- pattern: "services/payments/**"
value: "billing"
displayNameOverrides:
- pattern: "services/payments/**"
value: "Billing API"
build:
mode: fast
maxPools: 3
workersPerPool: 2
disableSkippedRendering: true
state:
namespace: platform-catalog
sqlite:
path: ./.printing-press-state.db--output,-o: Output directory for rendered docs--config: Path to aprinting-press.yamlconfig file--title: Override the API or catalog title--base-url: Base URL to use in generated HTML--base-path: Base path for resolving local file references--build-mode: Aggregate build mode:full,fast, orwatch--max-pools: Aggregate max concurrent render pools--theme: Terminal theme:dark,roger, ortektronix--no-logo,-b: Disable the pb33f banner--debug: Disable progress bars and stream build logs live--no-html: Skip HTML output--no-llm: Skip LLM output--no-json: Skip JSON artifact output--publish: Build hosted/served HTML assets without starting a local server--serve: Serve the rendered output after building--port: Port to use with--serve
Preview a single spec:
ppress --serve --output ./api-docs ./openapi.yamlPreview an API catalog:
ppress --serve --output ./api-docs ./servicesThis starts a local preview server at http://127.0.0.1:9090 by default.
Single spec:
ppress --publish --output ./api-docs ./openapi.yamlAPI catalog:
ppress --publish --output ./api-docs ./servicesThis produces the hosted asset layout without starting a local server.
ppress --debug ./openapi.yaml
ppress --debug ./servicesThis disables interactive progress bars and streams styled build, activity, and parser logs live.
