Freeze structured data into document-native modules.
docpack turns external data sources into checked-in document assets.
Feed it CSV, JSON, YAML, TOML, or XLSX. Get back generated Typst or LaTeX code that you can commit, diff, review, and ship with the rest of your document sources.
It is built for the cases where runtime data loading is the wrong tradeoff:
- reproducible reports
- compliance or approval workflows
- offline or single-file document bundles
- generated artifacts that need stable diffs
Manifest-first: usedocpack buildfor repeatable project outputs.CLI-friendly: usedocpack emitfor one-shot pipes and previews.Backend-aware: Typst and LaTeX outputs share one normalized data model.Explicit failures: format, inference, sheet, and shape errors are surfaced with concrete diagnostics.Reviewable output: generated artifacts are plain text modules, not opaque caches.
| Area | Support |
|---|---|
| Inputs | csv, json, yaml, toml, xlsx |
| Backends | typst, latex |
| Artifacts | data-module, table-fragment |
| Typst styles | typst-official, typst-table |
| LaTeX styles | latex-expl3, latex-classic-macro, latex-booktabs-longtable, latex-plain-tabular |
| Workflow modes | build, emit, inspect, init |
cargo install docpackOr via Homebrew:
brew tap acture/tools
brew install docpackemit is the fast path. If you do not pass --output, generated code is written to stdout.
docpack emit data/profile.json --backend typstExample output:
#letprofile= ("name": "Alice", "role": "Engineer")docpack emit data/table.csv \
--output build/table.tex \
--artifact table-fragmentStdin requires an explicit format, and stdout requires an explicit backend.
cat data/input.yaml | docpack emit - --format yaml --backend typstdocpack initdocpack buildMinimal docpack.toml:
[project]
name = "quarterly-report"output_dir = "generated"
[[sources]]
id = "sales"path = "data/sales.csv"format = "csv"
[[outputs]]
id = "sales_typst"source = "sales"path = "sales.typ"backend = "typst"artifact = "data-module"style = "typst-official"root_name = "sales"
[[outputs]]
id = "sales_tex"source = "sales"path = "sales.tex"backend = "latex"artifact = "table-fragment"style = "latex-booktabs-longtable"Then:
docpack builddocpack build [manifest-path]
docpack emit <input> [--output <path>] [--format <format>] [--backend <backend>]
docpack inspect <input-or-manifest> [--as <source|manifest>] [...]
docpack init [path] [--force]build: resolve a manifest and write all outputs in order.emit: convert one source into one artifact.inspect: show normalized shape, metadata, and resolved render defaults.init: generate a starter manifest.
| Backend | Artifact | Default | Alternatives |
|---|---|---|---|
| Typst | data-module | typst-official | none |
| Typst | table-fragment | typst-table | none |
| LaTeX | data-module | latex-expl3 | latex-classic-macro |
| LaTeX | table-fragment | latex-booktabs-longtable | latex-plain-tabular |
docpack is intentionally small at the center:
source bytes
-> input normalization
-> Value + SourceMeta
-> backend render request
-> Typst / LaTeX artifact
Current library layers:
core: normalized value tree and source metadatainput: format adapters and normalizationbackend: Typst and LaTeX renderingmanifest: project resolution, inference, and build planningerror: structured failure model
docpack inspect data/sales.csv --output build/sales.typThis prints:
- source format
- normalized top-level shape
- tabular metadata
- inferred backend / artifact / style / root name
docpack emit workbook.xlsx \
--sheet Sales \
--backend typst \
--artifact table-fragmentdocpack emit data/profile.json \
--backend latex \
--style latex-classic-macroWhat is already in place:
- manifest-driven build flow
- one-shot emit and inspect flow
- Typst data modules and table fragments
- LaTeX
expl3, classic macro,longtable, and plaintabularoutputs - reference fixture coverage across
json,yaml,toml,csv, andxlsx - real
pdflatexsmoke coverage for classic macro output - structured diagnostics for format inference, tabular shape mismatches, and missing sheets
What is still open:
- benchmark fixtures for large
csv/xlsxsources - memory profiling for larger manifest builds
cargo fmt
cargo clippy --all-targets --all-features -- -D warnings
cargo testRelease automation is tag-driven. See docs/releasing.md.
docpack is not trying to become a general-purpose ETL framework or a plugin platform.
The core idea is narrower and more useful:
- normalize external structured data once
- render it into document-native code
- keep the generated artifact reviewable and reproducible
docpack is licensed under AGPL-3.0-only.