Create, preview, inspect, verify, and compile deterministic PDF documents with Fullbleed.
Fullbleed PDF Engine is a deterministic, self-contained document-generation runtime for Python and Rust. It turns structured data plus static HTML/CSS into reports, invoices, statements, letters, forms, certificates, accessible PDFs, print-ready documents, and high-volume compiled VDP output—without a browser or system PDF stack.
It is designed for human developers, automation, and AI agents alike: the installed runtime exposes its exact version, capabilities, commands, schemas, compliance profiles, examples, limitations, and tool-selection boundary as a generated machine contract.
License: MIT.
pip install fullbleedfullbleed init . && python report.pyfullbleed agent-contract --format jsonoutput/report.pdf--repro-record / --repro-check)--json-only, --schema)Fullbleed is a deterministic, offline-first document rendering engine for structured print-document and transactional/VDP pipelines (not a browser, not a hosted web-to-print SaaS, and not a general editor for arbitrary existing PDF content).
HTML and CSS are used as a familiar DSL for layout, styling, and data placement in transactional documents.
An agent does not need release-specific Fullbleed knowledge. The installed binary generates one canonical contract containing its actual version, selection boundary, capabilities, parser-derived CLI surface, result schemas, PDF profiles, examples, limitations, Agent Skill metadata, MCP tools, and acceptance tasks:
fullbleed agent-manifest --json
# Equivalent canonical form:
fullbleed agent-contract --format json
The committed fullbleed-agent-contract.json, cli_schema.md, and llms.txt are generated from the built wheel. CI rejects version, command, schema, profile, or capability drift. Runtime introspection remains authoritative.
The first-party, versionless skills/fullbleed/SKILL.md teaches tool selection and the render/preview/diagnose/verify loop without duplicating the manual. It is bundled in the wheel and can be exported into any absent or empty agent-skill directory:
fullbleed agent skill-path --json
fullbleed agent export-skill .agents/skills/fullbleed --json
For tool-calling agents, install the separately versioned adapter so the core package remains dependency-free:
python -m pip install fullbleed-mcp
fullbleed-mcp --root .
The stdio server confines document paths to the selected workspace and delegates every engine operation to the installed Fullbleed runtime. It exposes semantic discovery, project creation, render/preview, inspect, verify, assets, and fixed/reflow compiled VDP tools. The dependency-free core also provides fullbleed mcp --root ..
Use Fullbleed when the requested artifact is a deterministic print document built from structured content. Use a browser when the requested artifact is a screenshot or interactive state of an arbitrary live website. Use a general PDF editor when existing page content itself must be rewritten.
Cold-agent testing is available through fullbleed agent-acceptance; compact copyable workflows live in examples/agent_workflows, and the approach-neutral benchmark scaffold lives in agentdocbench.
This README is the canonical usage guide for:
fullbleed CLI (human workflows + machine/agent automation)fullbleed Python bindings (PdfEngine, AssetBundle, batch APIs)Additional focused references are in docs/:
docs/install-non-technical.md (step-by-step setup for non-technical users)docs/css-coverage.md (validated CSS coverage, parity status, and active gaps)docs/README.mddocs/engine.mddocs/performance-architecture.mddocs/performance-pass-2026-08-04.mddocs/python-api.mddocs/ui-accessibility.mddocs/cli.mddocs/pdf-templates.md--repro-record and --repro-check.1.7 as the production-stable default target.--emit-image) without external PDF raster runtime dependencies.new list, new search, new remote).render_pdf_batch_parallel(...) and parallel-to-file variants).Fullbleed 2.2 retains exact TrueType glyph subsetting and adds compiled fixed-geometry variable-data binding. Across the five independent benchmark fixtures, PDFs are 95.5-97.3% smaller and ordinary warm rendering is 2.90x faster by geometric mean than released 2.0.0.
The new compile-once API freezes an immutable Q32.32 display document and can link it repeatedly
without rerunning HTML parsing, selector matching, layout, pagination, or command planning. For
identical untagged copies in one ordered PDF, CompiledDocument.render_pdf_batch(...) shares each
source page's content stream across the copied page dictionaries. The measured 20-copy lane is
200.7x faster per page by geometric mean than the released 2.0.0 warm renderer; a 1,000-page stress
run sustained 304,479-666,622 pages/s.
The 2.2 compiler includes a genuine fixed-geometry variable-data lane. A compiled invoice with six bound fields rendered 100,000 distinct records in a five-run median of 283.807 ms to memory (352,352 pages/s) and 295.999 ms directly to a flushed 88.1 MB PDF (337,839 pages/s). Including the one-time 4.168 ms compile gives 333,147 direct-file pages/s. The harness verified all 100,000 unique invoice IDs in page order, exact page count, resolved markers, deterministic bytes, and equal buffer/file SHA-256. Reproduce it with:
python tools/benchmark_fullbleed_vdp.py --records 100000 --repeats 5
Fixed-geometry slots may remain inside immutable page-space transforms and clips. The compiler captures that active coordinate-state program once and replays it in each compact record overlay; it does not rerun layout or clone the complete page display list.
Base-14/WinAnsi slot paint keeps the measured byte-patch linker. Registered embedded fonts use a command-level overlay program so each bound value is shaped and included in the font subset while the compiled layout, pagination, and static page stream remain shared. The throughput figures above describe the Base-14 fast lane; they are not claims for registered-font shaping.
The fixed-copy result remains scoped to identical content; the variable-data result is scoped to
paint-only text whose geometry does not reflow. Neither is a claim that arbitrary new HTML or
size-changing records render 200x faster. See
docs/performance-pass-2026-08-04.md for measurements and
docs/performance-architecture.md for the packed vector IR,
typed-binding, virtual-linker, and shader roadmap.
Fullbleed 2.2.5 hardens the third compiler lane introduced in 2.2.4 for
size-changing records: CompiledDocument.render_pdf_reflow_bindings(...). It parses and recovers
the template DOM once and compiles encountered structural flow variants into guarded fixed-point
display programs. Matching records bind directly into those programs; workers execute pre-shaped
text/TJ paint slots, cached static PDF page segments, page-local Deflate, and one ordered linker.
Explicit trusted structural slots use data-fb-bind-html="slot". A value that no compiled variant
can safely place runs ordinary fixed-point layout once to add another variant.
On the independent 1,000-distinct-record case study, the 29-sample hot direct-file median was
216.160 ms: 4,626 records/s and 8,096 pages/s. The 168.995 ms best sample reached 5,917
records/s and 10,355 pages/s. It produced
the exact 1,750-page 500/300/150/50 reflow distribution and verified all 24,900 markers. The
throughput-tuned 6,870,320-byte PDF was deterministic across all samples. With the compact
compression setting, compiled output was also byte-for-byte identical to ordinary rendering:
5,298,961 bytes and SHA-256 bb3c441313a08fb00d3bd15f23a567981f3bbbd550908e3a9fe7a07ca5d7f138.
This is a hot compiled-variant result, not a claim for previously unseen structure. The first
variant-discovery render measured 0.509 s (3,437 pages/s), and the fully cold job including setup,
bindings, compilation, discovery, and write measured 0.588 s (2,975 pages/s). The independently
observed hot-median speedup over the ordinary path was 43.8x.
New to Python or setting up on a fresh machine? Start with docs/install-non-technical.md.
python -m pip install fullbleed
From a local wheel:
python -m pip install C:\path\to\fullbleed-2.4.0-cp310-abi3-win_amd64.whl
From a source checkout with Rust installed, no Python build package is needed:
python -m pip install --no-build-isolation --no-deps --editable .
To create deterministic release artifacts directly:
python build_backend/fullbleed_build_backend.py wheel --out dist
python build_backend/fullbleed_build_backend.py sdist --out dist
Platform artifact policy:
manylinux2014 on x86-64, x86, ARM64, ARMv7, s390x,
and ppc64le, plus musllinux_1_2 on x86-64, x86, ARM64, and ARMv7.Verify command surface:
fullbleed --help
fullbleed capabilities --json
fullbleed doctor --json
Initialize project scaffold:
fullbleed init .
fullbleed init now vendors Bootstrap (5.0.0) into vendor/css/bootstrap.min.css,
vendors Bootstrap Icons (1.11.3) into vendor/icons/bootstrap-icons.svg,
vendors inter into vendor/fonts/Inter-Variable.ttf, writes license notices
(vendor/css/LICENSE.bootstrap.txt, vendor/icons/LICENSE.bootstrap-icons.txt, vendor/fonts/LICENSE.inter.txt),
and seeds assets.lock.json with pinned hashes.
The scaffolded report.py also runs a component mount smoke validation before
main render and writes output/component_mount_validation.json (fails fast on
missing glyphs, actual pagination overflow, or CSS miss signals). On current engines,
render-time pagination is authoritative for overflow; conservative JIT placement bounds
remain the compatibility fallback for older engines.
Scaffolded components now include components/primitives.py with reusable
layout/content helpers (Stack, Row, Text, table/list helpers, key/value rows, etc.).
Each scaffolded project also includes SCAFFOLDING.md, which should be your
first read before restructuring components.
It also includes AGENTS.md, which preserves the installed-runtime-first
document workflow across future coding-agent sessions without making other
document tools categorically forbidden.
Install additional project assets (defaults to ./vendor/... in project context):
fullbleed assets install inter --json
Bootstrap baseline note:
5.0.0) as the default styling baseline for project workflows.fullbleed assets install bootstrap --json only if you want to explicitly refresh/bootstrap-manage outside init.Render using the scaffolded component pipeline:
python report.py
Expected artifacts from scaffolded report.py:
output/report.pdfoutput/report_page1.png (or equivalent page preview from engine image APIs)output/component_mount_validation.jsonoutput/css_layers.jsonCanonical static PDF reference:
python examples/canonical_reference/report.py
examples/canonical_reference/ is the exhaustive scaffold-shaped reference for
component composition, layered CSS, bundled fonts/SVG, inline SVG, raster data
URIs, linked and standalone HTML artifacts, PDF output, PNG previews, and
validation reports.
fullbleed new)Use local starters:
fullbleed new local invoice ./my-invoice
fullbleed new local statement ./my-statement
fullbleed new local accessible ./my-accessible-doc
fullbleed new local reference ./my-reference-doc
Discover remote starters from registry:
fullbleed new list --json
fullbleed new search i9 --tag vdp --json
fullbleed new remote i9-stamped-vdp ./i9-job --json
fullbleed new local accessible is the verbose accessibility-first starter and
demonstrates the fullbleed.accessibility runtime surface (engine verifier,
PMR, PDF/UA-targeted seed checks, and non-visual trace artifacts).
fullbleed new local reference vendors the canonical static PDF reference shape
as a scaffolded project with component layers, assets, PDF/PNG outputs, page data,
and validation reports.
Optional registry override (for private/canary registries):
fullbleed new list --registry https://example.com/manifest.json --json
or:
set FULLBLEED_TEMPLATE_REGISTRY=https://example.com/manifest.json
fullbleed new search statement --json
fullbleed init is designed for component-first authoring rather than a single large HTML template.
Typical scaffold layout:
.
|-- SCAFFOLDING.md
|-- COMPLIANCE.md
|-- report.py
|-- components/
| |-- fb_ui.py
| |-- primitives.py
| |-- header.py
| |-- body.py
| |-- footer.py
| `-- styles/
| |-- primitives.css
| |-- header.css
| |-- body.css
| `-- footer.css
|-- styles/
| |-- tokens.css
| `-- report.css
|-- vendor/
| |-- css/
| |-- fonts/
| `-- icons/
`-- output/
Best-practice authoring model:
SCAFFOLDING.md first for project conventions.report.py.components/primitives.py.components/header.py, components/body.py, components/footer.py.components/styles/*.css.styles/tokens.css and styles/report.css.Recommended CSS layer order:
styles/tokens.csscomponents/styles/primitives.csscomponents/styles/header.csscomponents/styles/body.csscomponents/styles/footer.cssstyles/report.cssRecommended iteration loop:
report.py.components/*.py.components/styles/*.css and styles/*.css.python report.py.output/report_page1.png, output/component_mount_validation.json, and output/css_layers.json.Optional scaffold diagnostics:
FULLBLEED_DEBUG=1 to emit JIT traces.FULLBLEED_PERF=1 to emit perf traces.FULLBLEED_EMIT_PAGE_DATA=1 to persist page data JSON.FULLBLEED_IMAGE_DPI=144 (or higher) for preview resolution.FULLBLEED_VALIDATE_STRICT=1 for stricter validation gates in CI.Render inline HTML/CSS with reproducibility artifacts:
fullbleed --json render \
--html-str "<html><body><h1>Hello</h1></body></html>" \
--css-str "body{font-family:sans-serif}" \
--emit-manifest build/render.manifest.json \
--emit-jit build/render.jit.jsonl \
--emit-perf build/render.perf.jsonl \
--deterministic-hash build/render.sha256 \
--repro-record build/render.repro.json \
--out output/hello.pdf
--deterministic-hash writes the output PDF SHA-256 by default; when --emit-image is enabled, it writes an artifact-set digest (fullbleed.artifact_digest.v1) over PDF SHA-256 plus ordered page-image SHA-256 hashes. JSON outputs expose outputs.deterministic_hash_mode (pdf_only or artifact_set_v1), with outputs.artifact_sha256 and outputs.image_sha256 when images are emitted.
Re-run and enforce reproducibility against a stored record:
fullbleed --json render \
--html templates/report.html \
--css templates/report.css \
--repro-check build/render.repro.json \
--out output/report.rerun.pdf
Generate PNG page artifacts from an existing validation render:
fullbleed --json verify \
--html templates/report.html \
--css templates/report.css \
--emit-pdf output/report.verify.pdf \
--emit-image output/report_verify_pages \
--image-dpi 200
Compile-only plan (no render):
fullbleed --json plan \
--html templates/report.html \
--css templates/report.css
Template compose planning (no finalize write):
fullbleed --json plan \
--html templates/overlay.html \
--css templates/overlay.css \
--template-binding config/template_binding.json \
--templates config/template_catalog.json \
--emit-compose-plan output/compose_plan.json
When overlaying variable data onto a source PDF, use the built-in Rust template compose path.
Minimal CLI auto-compose flow:
fullbleed --json render \
--html templates/overlay.html \
--css templates/overlay.css \
--asset templates/source.pdf --asset-kind pdf --asset-name source-template \
--template-binding config/template_binding.json \
--templates config/template_catalog.json \
--out output/composed.pdf
Compose image semantics:
--emit-image PNGs are rasterized from finalized composed pages and report outputs.image_mode=composed_pdf.render/verify runs, --emit-image reports outputs.image_mode=overlay_document.Minimal template_binding example:
{
"default_template_id": "source-template",
"feature_prefix": "fb.feature.",
"by_feature": {
"front": "source-template",
"back_blank": "source-template"
}
}
Python API compose flow:
import fullbleed
engine = fullbleed.PdfEngine(template_binding=binding_spec)
overlay_bytes, _page_data, _bindings = engine.render_pdf_with_page_data_and_template_bindings(html, css)
open("output/overlay.pdf", "wb").write(overlay_bytes)
plan_result = engine.plan_template_compose(
html,
css,
[("source-template", "templates/source.pdf")],
0.0,
0.0,
)
plan = [
(
row["template_id"],
row["template_page"],
row["overlay_page"],
row["dx"],
row["dy"],
)
for row in plan_result["plan"]
]
fullbleed.finalize_compose_pdf(
[("source-template", "templates/source.pdf")],
plan,
"output/overlay.pdf",
"output/composed.pdf",
annotation_mode="link_only", # optional: link_only | none | carry_widgets
)
See docs/pdf-templates.md and examples/template-flagging-smoke/ for full production examples.
| Command | Purpose | JSON Schema |
|---|---|---|
render | Render HTML/CSS to PDF with optional PNG page artifacts | fullbleed.render_result.v1 |
verify | Validation render path with optional PDF and PNG emits | fullbleed.verify_result.v1 |
plan | Compile/normalize inputs into manifest + warnings | fullbleed.plan_result.v1 |
run | Render using Python module/file engine factory | fullbleed.run_result.v1 |
inspect pdf | Inspect PDF metadata and composition compatibility | fullbleed.inspect_pdf.v1 |
inspect pdf-batch | Inspect multiple PDFs with per-file status | fullbleed.inspect_pdf_batch.v1 |
inspect templates | Inspect template catalog metadata/compatibility | fullbleed.inspect_templates.v1 |
compliance | License/compliance report for legal/procurement | fullbleed.compliance.v1 |
debug-perf | Summarize perf JSONL logs | fullbleed.debug_perf.v1 |
debug-jit | Filter/inspect JIT JSONL logs | fullbleed.debug_jit.v1 |
doctor | Runtime capability and health checks | fullbleed.doctor.v1 |
capabilities | Machine-readable command/engine capabilities | fullbleed.capabilities.v1 |
assets list | Installed and optional remote packages | fullbleed.assets_list.v1 |
assets info | Package details + hashes/sizes | fullbleed.assets_info.v1 |
assets install | Install builtin/remote package | fullbleed.assets_install.v1 |
assets verify | Validate package and optional lock constraints | fullbleed.assets_verify.v1 |
assets lock | Write/update assets.lock.json | fullbleed.assets_lock.v1 |
cache dir | Cache location | fullbleed.cache_dir.v1 |
cache prune | Remove old cached packages | fullbleed.cache_prune.v1 |
init | Initialize project scaffold | fullbleed.init.v1 |
new | Create starter template files or query/install remote templates | fullbleed.new_template.v1, fullbleed.new_list.v1, fullbleed.new_search.v1, fullbleed.new_remote.v1 |
Schema discovery for any command/subcommand:
fullbleed --schema render
fullbleed --schema assets verify
fullbleed --schema inspect pdf
fullbleed --schema inspect templates
Global machine flags:
--json: structured result payload to stdout--json-only: implies --json and --no-prompts--schema: emit schema definition and exit--no-prompts: disable interactive prompts--config: load defaults from a config file--log-level error|warn|info|debug: control CLI log verbosity--no-color: disable ANSI color output--version: print CLI version and exitRender/verify/plan key flags:
--html, --html-str, --css, --css-str
--html accepts .svg files for direct SVG-document rendering; --html-str accepts inline SVG markup.--page-size, --page-width, --page-height, --margin, --page-margins--reuse-xobjects, --svg-form-xobjects, --svg-raster-fallback, --shape-text, --unicode-support, --unicode-metrics--pdf-version, --pdf-profile, --color-space, --document-lang, --document-title
Stable default is --pdf-version 1.7 for shipping workflows.
Profile targets: none, pdfa1a, pdfa1b, pdfa2a, pdfa2b, pdfa2u, pdfa3a, pdfa3b, pdfa3u, pdfa4, pdfa4e, pdfa4f, pdfx4, pdfua1, pdfua2, pdfvt1, wtpdf1r, wtpdf1a, tagged.
Aliases: a, ua, vt, wt1r, wt1a, pdf/a, pdf/ua, pdf/vt.
Output intent metadata (--output-intent-identifier|--output-intent-info|--output-intent-components) requires --output-intent-icc.
pdfx4 and pdfvt1 force PDF 1.6 and require a title and explicit write date
(--timestamp current, a fixed UTC date, or --timestamp-source SOURCE_DATE_EPOCH).
PDF/VT composition documents record hierarchies, --pdf-vt-job,
private DPM, conservative reuse hints, and the independent release-validation boundary.
Run python tools/validate_pdf_profiles.py --download-verapdf --install-pdf-oxide --strict-external
to regenerate profile specimens, capture inspect/JIT evidence, replay
deterministic hashes, validate PDF/A and PDF/UA with veraPDF, and validate
PDF/X-4 with pdf_oxide. WTPDF profiles are validated with veraPDF
wt1r/wt1a and include PDF Declaration evidence. pdfa4f emits and
checks an associated EmbeddedFiles name tree. pdfvt1 also emits and checks a parsed
DPart graph (DPartRoot, DPartRootNode, NodeNameList [/Job /Record /Document], leaf page range,
and page /DPart references), including a supplemental multipage specimen
for /Start and /End, reported as granular booleans plus
pdfvt_dpart_graph_valid; use a dedicated PDF/VT preflight tool
for third-party PDF/VT certification, or wire one into the same harness with
--pdfvt-cmd "tool --input {pdf}" --pdfvt-version-cmd "tool --version" --require-dedicated-pdfvt.--watermark-text, --watermark-html, --watermark-image, --watermark-layer, --watermark-semantics, --watermark-opacity, --watermark-rotation--emit-jit, --emit-perf, --emit-glyph-report, --emit-page-data, --emit-compose-plan, --emit-image, --image-dpi, --deterministic-hash--asset, --asset-kind, --asset-name, --asset-trusted, --allow-remote-assets--profile dev|preflight|prod--fail-on overflow|missing-glyphs|font-subst|budget--allow-fallbacks (keeps fallback diagnostics, but does not fail missing-glyphs / font-subst gates)--repro-record <path>, --repro-check <path>--budget-max-pages, --budget-max-bytes, --budget-max-msdoctor --strict, compliance --strict --max-audit-age-days <n>Fullbleed supports SVG in three practical CLI paths:
--html <file.svg>--html-str "<svg ...>...</svg>"--asset <file.svg> (kind auto-infers to svg)Standalone SVG file to PDF:
fullbleed --json render \
--html artwork/badge.svg \
--out output/badge.pdf
Inline SVG markup to PDF:
fullbleed --json render \
--html-str "<svg xmlns='http://www.w3.org/2000/svg' width='200' height='80'><rect width='200' height='80' fill='#0d6efd'/><text x='16' y='48' fill='white'>Hello SVG</text></svg>" \
--out output/inline-svg.pdf
HTML template with explicit SVG asset registration:
fullbleed --json render \
--html templates/report.html \
--css templates/report.css \
--asset assets/logo.svg \
--asset-kind svg \
--out output/report.pdf
SVG render behavior flags:
--svg-form-xobjects / --no-svg-form-xobjects--svg-raster-fallback / --no-svg-raster-fallbackDistributed Python wheels enable the svg_raster engine feature, so
--svg-raster-fallback can rasterize unsupported SVG constructs such as SVG
text, filters, masks, and foreignObject into deterministic image content.
Custom source builds must include --features python,svg_raster to advertise
and use that fallback path.
Machine discovery:
fullbleed capabilities --json
Inspect the svg object in fullbleed.capabilities.v1 for SVG support metadata. The engine
object also reports compiled-document/reflow availability and supported per-call compression modes.
It reports the compiled svg_raster build feature plus a feature matrix for
native-vector SVG, raster-fallback-required SVG, and unsupported/known-loss SVG
features.
Launch-safe image claims:
svg_raster is enabled.<img>, CSS background-image: url(...), list-style images,
and watermark images.<picture>, srcset, sizes, density descriptors,
and browser-style responsive image selection.AssetBundle inputs; remote assets must be explicitly allowed.page_1, page_2, page_n)Fullbleed uses ordered page templates internally. In docs, this is easiest to think of as:
page_1: first page templatepage_2: second page templatepage_n: repeating template for later pagesConfiguration mapping:
--page-margins keys: 1, 2, ... and optional "n" (or "each" alias).PdfEngine(page_margins=...): same key model.margin.Minimal CLI example:
{
"1": {"top": "12mm", "right": "12mm", "bottom": "12mm", "left": "12mm"},
"2": {"top": "24mm", "right": "12mm", "bottom": "12mm", "left": "12mm"},
"n": {"top": "30mm", "right": "12mm", "bottom": "12mm", "left": "12mm"}
}
fullbleed --json render \
--html templates/report.html \
--css templates/report.css \
--page-margins page_margins.json \
--header-each "Statement continued - Page {page} of {pages}" \
--out output/report.pdf
Minimal Python example:
import fullbleed
engine = fullbleed.PdfEngine(
page_width="8.5in",
page_height="11in",
margin="12mm",
page_margins={
1: {"top": "12mm", "right": "12mm", "bottom": "12mm", "left": "12mm"}, # page_1
2: {"top": "24mm", "right": "12mm", "bottom": "12mm", "left": "12mm"}, # page_2
"n": {"top": "30mm", "right": "12mm", "bottom": "12mm", "left": "12mm"} # page_n
},
header_first="Account Statement",
header_each="Statement continued - Page {page} of {pages}",
footer_last="Final page",
)
Note:
--header-each / --footer-each (and --header-html-each / --footer-html-each).first/last header/footer variants (header_first, header_last, footer_first, footer_last), use the Python API.List installed + available packages:
fullbleed assets list --available --json
Install builtin assets:
fullbleed assets install bootstrap
fullbleed assets install bootstrap-icons
# `@bootstrap` / `@bootstrap-icons` are also supported aliases
PowerShell note:
@ aliases (for example "@bootstrap") to avoid shell parsing surprises.Install remote asset package:
fullbleed assets install inter
Install broad Unicode fallback package (larger font payload):
fullbleed assets install noto-sans
Install to a custom vendor directory:
fullbleed assets install bootstrap --vendor ./vendor
Install to global cache:
fullbleed assets install inter --global
Install common barcode fonts (license-safe defaults):
fullbleed assets install libre-barcode-128
fullbleed assets install libre-barcode-39
fullbleed assets install libre-barcode-ean13-text
Verify against lock file with strict failure:
fullbleed assets verify inter --lock --strict --json
Preview cache cleanup without deleting files:
fullbleed cache prune --max-age-days 30 --dry-run --json
Notes:
@ references (bootstrap == @bootstrap, bootstrap-icons == @bootstrap-icons, noto-sans == @noto-sans).noto-sans is available as a builtin fallback package, but it is intentionally larger than inter; use it when your document requires broader glyph coverage../vendor/ when project markers are present (assets.lock.json, report.py, or fullbleed.toml in CWD).assets install defaults to global cache unless --vendor is explicitly set.%LOCALAPPDATA%/fullbleed/cache/...; use assets install --json and consume installed_to.vendor/fonts/, vendor/css/).assets lock --add is currently aimed at builtin package additions.Libre Barcode).assets install; use local vetted font files and track licensing separately.Bootstrap builtin package details:
bootstrap (alias: @bootstrap)5.0.0bootstrap.min.css)vendor/css/bootstrap.min.css (project mode)MIThttps://raw.githubusercontent.com/twbs/bootstrap/v5.0.0/LICENSEBootstrap Icons builtin package details:
bootstrap-icons (alias: @bootstrap-icons)1.11.3bootstrap-icons.svg)vendor/icons/bootstrap-icons.svg (project mode)MIThttps://raw.githubusercontent.com/twbs/icons/v1.11.3/LICENSEBootstrap notes:
--asset @bootstrap or AssetBundle); external HTML <link rel="stylesheet"> is not an execution path.For the full, maintained coverage statement, see docs/css-coverage.md.
Summary as of May 19, 2026:
2222/22 in_progress86/86 fixtures passing with 603 assertion/paint checkstools/generate_css_parity_status.py --check --json)_css_working/css_parity_status.json_css_working/tmp/fixture_full_latest.json_css_working/css_broad_coverage_sprint_s14.mdThe complete pinned independent Wheel265 gate closed on August 9, 2026 with 1,642 PASS,
0 FAIL, and 20 REFERENCE-DISPUTED across 1,662 fixtures. That is strict 100% parity for
every adjudicable fixture in this named corpus; disputed references remain visible and are not
relabeled as implementation passes. Broader web-platform coverage remains bounded by the module
and known-gap contract in docs/css-coverage.md.
Flow/reflow hardening validated on August 5, 2026 adds fixed-height block,
one-column grid, and column-flex continuation slicing; avoids content
duplication; retains empty styled captions inside avoided figures; preserves
display: contents grid paint phase; and keeps positioned containing blocks
atomic. The independent review's targeted 18-case regression cluster passes
18/18 (13 pixel-exact, maximum above-floor difference 0.97030199%). This
targeted diagnostic does not replace the full external-corpus report.
Current validated behavior includes first-class parser -> evaluator -> calculator -> layout/paint coverage across broad static-document CSS domains (values math, layout primitives, pagination/fragmentation baselines, transforms phase-1, gradient/effects subsets including color-first and interleaved-color filter: drop-shadow(...) with computed lengths, modern rgb() shadow colors with mm lengths, duplicate drop-shadow(...) color rejection, empty optional filter-function defaults, explicit/currentColor backdrop-filter: drop-shadow(...) raster paint, strict box-shadow length/color grammar with modern rgb() plus mm paint coverage, softened blurred inset edge paint, and directional inset offset edge paint, overflow-gated text-overflow: ellipsis, physical min/max box constraints, horizontal-tb RTL direction inline inset/margin/padding/border mapping, vertical writing-mode direction: rtl inline inset remapping, vertical-rl logical sizing/insets/margin/padding/border/min-max constraints, vertical-lr logical sizing/min-max/insets/margin/padding/border remapping, basic vertical text columns with vertical-rl leftward and vertical-lr rightward line progression, and deterministic diagnostics).
Known gap categories are explicitly tracked for the final parity push:
url() filters, advanced drop-shadow() forms beyond the current flexible-color-order foreground and baseline backdrop coverage, and PDF-native foreground filtersclip-path grammar beyond the current basic-shape subset, including SVG clip sources, SVG-specific geometry boxes, and deeper edge grammarurl(...) explicit-size/auto-auto-intrinsic/negative-size-invalid/contain/cover/auto-dimension-size/single-value-size/alpha-stack/default-repeat-repeat/repeat-y/repeat/repeat-no-repeat/no-repeat-repeat/space-space/round-round/round-space/space-round/round-repeat/round-no-repeat/no-repeat-round/no-repeat-space/space-no-repeat/repeat-space/repeat-round/space-repeat/logical-repeat-aliases/multi-layer-repeat-axis/background-list-repetition/percentage-position/edge-offset-position/logical-position-aliases/shorthand-position-size-repeat/content-box-origin-clip/multi-layer-origin-clip/background-blend-normal/background-blend-multiply/screen-mode/overlay-mode/exclusion-mode/hard-light-mode/darken-mode/lighten-mode/color-dodge-mode/color-burn-mode/soft-light-mode/hue-mode/saturation-mode/color-mode/luminosity-mode/plus-lighter-mode/list-repetition/truncation/raster-blend/raster-layer-mapping/mixed-raster-gradient-mapping/mixed-gradient-raster-mapping subset, including broader mixed raster stack combinationsrun Command (Python Factory Interop)run lets the CLI use a Python-created engine instance.
report.py:
import fullbleed
def create_engine():
return fullbleed.PdfEngine(page_width="8.5in", page_height="11in", margin="0.5in")
CLI invocation:
fullbleed --json run report:create_engine \
--html-str "<h1>From run</h1>" \
--css templates/report.css \
--out output/report.pdf
Entrypoint formats:
module_name:factory_or_enginepath/to/file.py:factory_or_engineFor Rust-based visual/source frontends, the engine also provides document-context chart compilation: normal CSS font selection and size, project-font legend measurement/wrapping, semantic tables, and observable layout failures. Generated SVG is derived output, not authoring source.
import fullbleed
engine = fullbleed.PdfEngine(
page_width="8.5in",
page_height="11in",
margin="0.5in",
pdf_version="1.7",
pdf_profile="none",
color_space="rgb",
)
html = "<html><body><h1>Invoice</h1><p>Hello.</p></body></html>"
css = "body { font-family: sans-serif; }"
bytes_written = engine.render_pdf_to_file(html, css, "output/invoice.pdf")
print(bytes_written)
Register local assets with AssetBundle:
import fullbleed
bundle = fullbleed.AssetBundle()
bundle.add_file("vendor/css/bootstrap.min.css", "css", name="bootstrap")
bundle.add_file("vendor/fonts/Inter-Variable.ttf", "font", name="inter")
engine = fullbleed.PdfEngine(page_width="8.5in", page_height="11in")
engine.register_bundle(bundle)
engine.render_pdf_to_file("<h1>Styled</h1>", "", "output/styled.pdf")
These signatures are verified from the installed package via inspect.signature(...).
PdfEngine constructor:
PdfEngine(
page_width=None,
page_height=None,
margin=None,
page_margins=None,
font_dirs=None,
font_files=None,
reuse_xobjects=True,
svg_form_xobjects=False,
svg_raster_fallback=False,
unicode_support=True,
shape_text=True,
unicode_metrics=True,
pdf_version=None,
pdf_profile=None,
output_intent_icc=None,
output_intent_identifier=None,
output_intent_info=None,
output_intent_components=None,
color_space=None,
document_lang=None,
document_title=None,
header_first=None,
header_each=None,
header_last=None,
header_x=None,
header_y_from_top=None,
header_font_name=None,
header_font_size=None,
header_color=None,
header_html_first=None,
header_html_each=None,
header_html_last=None,
header_html_x=None,
header_html_y_from_top=None,
header_html_width=None,
header_html_height=None,
footer_first=None,
footer_each=None,
footer_last=None,
footer_x=None,
footer_y_from_bottom=None,
footer_font_name=None,
footer_font_size=None,
footer_color=None,
watermark=None,
watermark_text=None,
watermark_html=None,
watermark_image=None,
watermark_layer="overlay",
watermark_semantics="artifact",
watermark_opacity=0.15,
watermark_rotation=0.0,
watermark_font_name=None,
watermark_font_size=None,
watermark_color=None,
paginated_context=None,
jit_mode=None,
debug=False,
debug_out=None,
perf=False,
perf_out=None,
)
Module exports:
PdfEngineCompiledDocumentCompiledFlowCompressionAssetBundleAssetAssetKindWatermarkSpec(kind, value, layer='overlay', semantics=None, opacity=0.15, rotation_deg=0.0, font_name=None, font_size=None, color=None)concat_css(parts)vendored_asset(source, kind, name=None, trusted=False, remote=False)inspect_pdf(path)inspect_template_catalog(templates)finalize_stamp_pdf(template, overlay, out, page_map=None, dx=0.0, dy=0.0)finalize_compose_pdf(templates, plan, overlay, out, annotation_mode='link_only')fetch_asset(url)PdfEngine methods:
| Method | Return shape |
|---|---|
register_bundle(bundle) | None |
compile_pdf(html, css) | CompiledDocument |
render_pdf(html, css, deterministic_hash=None) | bytes |
render_pdf_to_file(html, css, path, deterministic_hash=None) | int (bytes written) |
render_image_pages(html, css, dpi=150) | list[bytes] |
render_image_pages_to_dir(html, css, out_dir, dpi=150, stem=None) | list[str] |
render_finalized_pdf_image_pages(pdf_path, dpi=150) | list[bytes] |
render_finalized_pdf_image_pages_to_dir(pdf_path, out_dir, dpi=150, stem=None) | list[str] |
render_pdf_with_glyph_report(html, css) | (bytes, list) |
render_pdf_with_page_data(html, css) | (bytes, page_data_or_none) |
render_pdf_with_page_data_and_glyph_report(html, css) | (bytes, page_data_or_none, glyph_report_list) |
render_pdf_with_page_data_and_template_bindings(html, css) | (bytes, page_data_or_none, template_bindings_or_none) |
render_pdf_with_page_data_and_template_bindings_and_glyph_report(html, css) | (bytes, page_data_or_none, template_bindings_or_none, glyph_report_list) |
plan_template_compose(html, css, templates, dx=0.0, dy=0.0) | dict |
render_pdf_batch(html_list, css, deterministic_hash=None) | bytes |
render_pdf_batch_parallel(html_list, css, deterministic_hash=None) | bytes |
render_pdf_batch_to_file(html_list, css, path, deterministic_hash=None) | int |
render_pdf_batch_to_file_parallel(html_list, css, path, deterministic_hash=None) | int |
render_pdf_batch_to_file_parallel_with_page_data(html_list, css, path, deterministic_hash=None) | (bytes_written, page_data_list) |
render_pdf_batch_with_css(jobs, deterministic_hash=None) | bytes |
render_pdf_batch_with_css_to_file(jobs, path, deterministic_hash=None) | int |
CompiledDocument methods:
| Method | Return shape |
|---|---|
stats() | dict |
render_pdf(deterministic_hash=None) | bytes |
render_pdf_to_file(path, deterministic_hash=None) | int |
render_pdf_batch(copies, deterministic_hash=None) | bytes |
render_pdf_bindings(bindings, deterministic_hash=None) | bytes |
render_pdf_bindings_to_file(bindings, path, deterministic_hash=None) | int |
render_pdf_reflow_bindings(bindings, deterministic_hash=None, *, compression="throughput") | bytes |
render_pdf_reflow_bindings_to_file(bindings, path, deterministic_hash=None, *, compression="throughput") | int |
The compiled lane runs parsing/layout once. render_pdf_batch virtualizes identical untagged page
content. The fixed binding methods accept columnar dict[str, list[str]] data and emit distinct
fixed-geometry text overlays per record while sharing static paint. They require exact slot keys,
equal non-zero column lengths, page-local text, and an untagged profile. Base-14 text uses the
direct byte-patch lane; registered fonts are shaped into a command-level overlay. Bound values do
not trigger layout or reflow.
The reflow binding methods use the same exact-column contract but execute the compiled parsed-DOM
program. {{slot}} values are literal text and may reshape, wrap, resize blocks, and change page
counts. Empty elements can opt into trusted generated markup with
data-fb-bind-html="slot"; those values replace the element's children. One DOM is reused per
native worker and record output is linked in input order through a bounded queue. Structural slot
values are parsed as trusted markup: sanitize untrusted input or use scalar {{slot}} bindings,
which remain literal text. Choose CompiledFlowCompression.Throughput (default) or
CompiledFlowCompression.Compact per render; modes can be mixed safely in one process. See
docs/python-api.md for the trust boundary and current limitations.
When deterministic_hash is set, engine writes PDF SHA-256 to the provided file path.
AssetBundle methods:
add_file(path, kind, name=None, trusted=False, remote=False)add(asset)assets_info()css()Canonical scaffold reference:
python examples/canonical_reference/report.py
Text watermark + diagnostics:
import fullbleed
engine = fullbleed.PdfEngine(
page_width="8.5in",
page_height="11in",
margin="0.5in",
pdf_version="1.7",
watermark_text="INTERNAL",
watermark_layer="overlay",
watermark_semantics="artifact",
watermark_opacity=0.12,
watermark_rotation=-32.0,
debug=True,
debug_out="build/invoice.jit.jsonl",
perf=True,
perf_out="build/invoice.perf.jsonl",
)
html = "<h1>Invoice</h1><p>Status: Ready</p>"
css = "h1{margin:0 0 8px 0} p{margin:0}"
written = engine.render_pdf_to_file(html, css, "output/invoice_watermarked.pdf")
print("bytes:", written)
Batch render + glyph/page-data checks:
import fullbleed
engine = fullbleed.PdfEngine(page_width="8.5in", page_height="11in", margin="0.5in")
jobs = [
("<h1>Batch A</h1><p>Alpha</p>", "h1{color:#0d6efd}"),
("<h1>Batch B</h1><p>Beta</p>", "h1{color:#198754}"),
]
written = engine.render_pdf_batch_with_css_to_file(jobs, "output/batch.pdf")
print("batch bytes:", written)
pdf_bytes, glyph_report = engine.render_pdf_with_glyph_report("<p>Hello</p>", "")
print("glyph entries:", len(glyph_report))
pdf_bytes, page_data = engine.render_pdf_with_page_data("<p>Hello</p>", "")
print("page data available:", page_data is not None)
Minimal, self-contained Python example (no external template files) showing:
{sum:items.amount}.{total:items.amount}.page_data totals for automation and reconciliation checks.from pathlib import Path
import fullbleed
rows = []
for i in range(1, 121): # enough rows to force multiple pages
amount = 10.00 + ((i * 7) % 23) + 0.25
rows.append(
f'<tr data-fb="items.amount={amount:.2f}">'
f"<td>2026-01-{(i % 28) + 1:02d}</td>"
f"<td>Txn {i:03d}</td>"
f'<td class="num">${amount:.2f}</td>'
"</tr>"
)
html = f"""<!doctype html>
<html>
<body>
<h1>Monthly Statement</h1>
<table>
<thead>
<tr><th>Date</th><th>Description</th><th class="num">Amount</th></tr>
</thead>
<tbody>
{''.join(rows)}
</tbody>
</table>
</body>
</html>
"""
css = """
body { font-family: sans-serif; font-size: 10pt; color: #111; }
h1 { margin: 0 0 8pt 0; }
table { width: 100%; border-collapse: collapse; }
th, td { padding: 4pt; border-bottom: 1pt solid #e1e1e1; }
thead th { background: #f3f6fa; text-transform: uppercase; font-size: 9pt; }
.num { text-align: right; }
"""
engine = fullbleed.PdfEngine(
page_width="8.5in",
page_height="11in",
margin="12mm",
page_margins={
1: {"top": "12mm", "right": "12mm", "bottom": "12mm", "left": "12mm"},
2: {"top": "28mm", "right": "12mm", "bottom": "12mm", "left": "12mm"},
"n": {"top": "28mm", "right": "12mm", "bo
Source-derived launch command. Check the maintainer’s required arguments and credentials before running:
uvx fullbleed-mcpMerge this template into ~/Library/Application Support/Claude/claude_desktop_config.json. Keep existing servers. Add any arguments, credentials, and permissions required by the maintainer; this template has not been install-tested.
{
"mcpServers": {
"io-github-fullbleed-engine-fullbleed-mcp": {
"command": "uvx",
"args": [
"fullbleed-mcp"
]
}
}
}Restart Claude Desktop completely for changes to take effect. Confirm the server appears connected in the client’s tool list, then try a read-only example from its documentation.
Claude Desktop setup referencefullbleed-mcppypiFullbleed PDF Engine works with any MCP-compatible client. Copy the config snippet from the Configuration section above and add it to the file shown for your client, then restart the application.
~/Library/Application Support/Claude/claude_desktop_config.jsonRestart Claude Desktop completely for changes to take effect.~/.cursor/mcp.jsonRestart Cursor for changes to take effect..vscode/mcp.jsonReload VS Code window for changes to take effect.~/.codeium/windsurf/mcp_config.jsonRestart Windsurf for changes to take effect..mcp.jsonSave at the project root, then start Claude Code in that project and review the MCP server approval prompt. Keep real credentials out of shared files.