Changelog
Unreleased
Changed
- One footer for every format. HTML, EPUB, and ODT now honor
footer.include_tag,include_commit,include_date,include_branch, andrepo_url, and use the same layout as PDF and DOCX (parts joined by-, ending withMade with LeafPress · leafpress.dev). Previously they ignored those settings and showed the full version string. See Branding → Footer - EPUB now includes the logo on its cover page; it used to be dropped
- Logos are embedded everywhere. A remote
logo_pathis downloaded once (public hosts only, 10 MB cap) and embedded in HTML, PDF, DOCX, ODT, and EPUB, so a remote logo now works in ODT too, and HTML output no longer loads it from the web when opened. A logo that can't be fetched is skipped with a warning instead of failing a DOCX build - The desktop app's log now shows the pipeline's own output (detected config, extensions, skipped pages, missing images, files written) instead of only "Converting…" and "Done!"
- A crash inside any output renderer is now reported with a format-specific explanation. PDF and Markdown export previously surfaced it as an "Unexpected error"
Internal
- LaTeX importer: macro conversion is a dispatch table instead of a 120-line
ifchain. Macro/environment tables moved toimporter/tex_spec.pyand node/tabular helpers toimporter/tex_nodes.py. Output is unchanged, checked against every LaTeX input in the test suite pipeline.py: one table of output formats replaces six copy-pasted blocks, single-project and monorepo mode share one page-render loop, andconvert()is split into small steps.convert()takes an optionalconsole- Renderer error messages come from one rule table in
render_errors.pyinstead of five near-identical functions
0.8.3 — 2026-09-27
Security
docx.template_pathfrom a cloned repo'sleafpress.ymlis now confined to the repository (a template's body is kept, so it could pull one of your local Word documents into the output). Relative template paths now resolve fromleafpress.yml, as documented, instead of the current directory- HTML/EPUB footer injection:
footer.custom_textand the git branch name were joined into the HTML and EPUB footers without escaping, so a cloned repo'sleafpress.ymlcould inject<script>even with--sanitize-html. Each part is now escaped. (Found by ruff's bandit-styleS704rule.) pom.xml/.csprojversion detection parses withdefusedxml, since these manifests can come from an untrusted cloned repository- Fixes from the pre-release code review:
- A cloned repo's
leafpress.ymlcould name any readable file aslogo_pathand have it embedded in HTML/PDF output. Local logos from an untrusted repo config must now be inside the repo, and only real images are ever allowlisted. - Only real image files are embedded from disk (HTML/EPUB) or fetched by the PDF renderer, so page content can't pull in e.g. a CI workspace's
.envvia<img>orrel="attachment". - Downloads forwarded
Authorization/Cookieheaders across redirects to other hosts (e.g. the Lucidchart token following a redirect to a storage bucket); they are now dropped when the origin changes. - A cloned repo's
mermaid.servermust be a public host; an operator-setLEAFPRESS_MERMAID_SERVERis still trusted. - The internal-host check now unwraps IPv4 addresses tunnelled in IPv6 (NAT64, 6to4, Teredo, IPv4-mapped). DNS rebinding is documented as a known limitation.
- The PDF fetcher now uses the shared
requests-based download helper instead of reimplementing redirects and size caps with urllib. - Monorepo
projects[].urlmust be a git URL. A local path there skipped the containment check thatpath:gets. For cloned repos, the URL's host must also be public, androot:is confined. - A local project's
.envsettings are removed again after each conversion, so in the long-running desktop UI they no longer carry over into later runs. Previously they could switch off the untrusted-repo guards for a later git URL conversion. - The internal-host check also unwraps IPv4-compatible (
::a.b.c.d) and SIIT (::ffff:0:a.b.c.d) addresses.
- A cloned repo's
- Upgraded all locked dependencies to clear known advisories (
pip-auditnow reports none), including GitPython 3.1.62 (option-smuggling / config-injection RCEs during clone), pymdown-extensions 12.1 (snippetspath traversal, ReDoS), WeasyPrint 70.0 (url_fetcherbypass), lxml 6.1 (XXE via default entity resolution), Pillow 12.3 (image parser memory corruption), urllib3 2.8 / requests 2.34, soupsieve, idna, and pygments - Raised minimum dependency versions in
pyproject.tomlso fresh installs can't resolve to vulnerable releases:gitpython>=3.1.60,pymdown-extensions>=11.0.1,lxml>=6.1,requests>=2.33,pygments>=2.20,weasyprint>=70.0 - Untrusted repository hardening. Converting a repository you don't control (a git URL, monorepo
projects[].url, or a CI checkout) can no longer read local files or reach internal hosts. See Remote Sources.envis not loaded from cloned repositories. OnlyLEAFPRESS_*keys are read from local.envfiles, so a.envcan no longer setGIT_SSH_COMMANDorGIT_CONFIG_*- PDF rendering uses a restricted WeasyPrint URL fetcher:
file://is limited to the project, and private, loopback, and link-local hosts are blocked, including on redirects. This closes local file disclosure via<a rel="attachment" href="file:///...">and SSRF via<img> - Pages must resolve inside
docs_dir, anddocs_dirmust be inside the project...and absolutenaventries are dropped, and pages that symlink outsidedocs_dirare skipped - Images in PDF, DOCX, and ODT output must resolve inside the project, which blocks
../traversal, rawfile://URIs, and symlinks. ODT previously embedded any file's bytes pymdownx.snippetsandpymdownx.b64are confined to the project directory, andurl_downloadis disabledmodule:ClassNameextension references must name a MarkdownExtensionsubclass- Monorepo
projects[].pathin a cloned repository'sleafpress.ymlmust stay inside that repository - PDF header and footer text is now correctly escaped in CSS, since a trailing backslash could previously break out of the string.
watermark.coloris now validated as a hex color
- Supply chain & CI
- The GitHub Action now passes inputs through environment variables instead of interpolating
${{ inputs.* }}into its shell script, which closes a script-injection route. It also installs leafpress from the action's own ref rather than whatever is newest on PyPI - All workflow actions are pinned by commit SHA, checkouts no longer persist credentials, and the release job disables caching. CI runs with
contents: readand now runspip-audit - Added Dependabot for GitHub Actions, uv, and Docker, with a 7-day cooldown
- Docker: base images are pinned by digest, mounted repos are marked git
safe.directory(version info now works under any--user), and the image includes an unprivilegedleafpressuser. The docs recommend--user "$(id -u):$(id -g)"
- The GitHub Action now passes inputs through environment variables instead of interpolating
- Downloads (diagrams, Lucidchart, mermaid.ink, remote DOCX logos,
importfrom URL) go through one helper- http(s) only, streamed with size caps, and every redirect hop is re-validated
- Remote DOCX logos refuse private or internal hosts, matching the PDF fetcher
fetch-diagrams:destmust stay inside the project directory, which closes arbitrary file writes such asdest: ../../.bashrc. Lucidchart document IDs are validated- Credentials in git URLs (
https://user:TOKEN@…) are redacted from clone messages, errors, and monorepo chapter cover pages - TeX import:
\includegraphicspaths outside the.texfile's directory are skipped - Windows "open file" no longer runs through
cmd.exe(shell=True). It now usesos.startfile
Improvements
- Desktop UI convert window gains Git branch, Watermark, Mermaid diagrams (from config / render / keep as code), and Sanitize HTML (auto / on / off), matching the CLI flags
- Experimental Zensical support.
zensical.tomlprojects convert like MkDocs ones.- Reads
site_name,docs_dir,nav, andmarkdown_extensionsfrom[project]. - Dotted extension tables are flattened back to extension names.
- TOML 1.1 syntax is supported via
tomli, a new dependency. - When both files exist,
mkdocs.ymlstill wins;--mkdocs-config zensical.tomloverrides. - See Zensical Projects.
- Reads
- External-link entries in
nav(e.g.Book: https://…) are skipped instead of producing a "File not found" warning - LaTeX import overhaul, clearing every item in the LaTeX TODO list:
- Multi-file projects (
\input,\include,\subfile,\import) are inlined, confined to the document directory, with cycle detection - Theorem-like environments and
\newtheorem(shared counters, starred forms) render as numbered blockquotes;proofends with ∎ - Accents and symbols convert to Unicode, and
---/--/''` /~` become typographic characters \multicolumncell content is kept, and table cells are converted instead of left as raw LaTeX- Sub-figures render with
(a)/(b)captions - siunitx quantities convert:
\SI{3e8}{\metre\per\second}→ 3 × 10⁸ m·s⁻¹ - Equations get
\tag{n}, with\label/\nonumberremoved andalign*wrapped inaligned \ref/\eqref/\autoref/\cref/\namerefresolve to real numbers, including forward references- Beamer frames become headings with their content, and overlays are flattened. Frames were previously dropped entirely
- Multi-file projects (
LEAFPRESS_LOG_LEVELenv var (DEBUG/INFO/WARNING/ERROR/CRITICAL) sets console log verbosity without--verbose, which is useful in CI. Console log lines are now styled by level- HTML sanitizing. Uses nh3 to strip scripts, event handlers,
javascript:/data:links, iframes, forms, and resource-loading CSS from page HTML, while keeping normal MkDocs/Material markup.- Automatic for git URL sources and monorepo
url:projects, and a cloned repo'sleafpress.ymlcan't disable it. - Opt in for any source with
--sanitize-html,LEAFPRESS_SANITIZE_HTML, orsanitize_html: true.
- Automatic for git URL sources and monorepo
- Task-list checkboxes are now converted to ☑/☐ for plain
pymdownx.tasklistoutput too (previously only withcustom_checkbox: true), and conversion no longer depends on exact attribute formatting - Mermaid privacy controls. New
mermaid:config (enabled,server),LEAFPRESS_MERMAID_ENABLED/LEAFPRESS_MERMAID_SERVER, and--mermaid/--no-mermaid. These let you point at a self-hosted mermaid.ink or keep diagrams as code so nothing is sent to a third party
Fixes
- Monorepo Markdown export (
-f markdown) silently dropped every page; it now includes each project's pages LEAFPRESS_LOCAL_TIMEwas documented but never read; it now works like--local-time- The "missing extension" hint suggested the wrong package (
pip install pymdownx); it now names the PyPI package (pymdown-extensions,mkdocs-material, …) - DOCX skips a logo that isn't a real image instead of failing; the PDF error message linked to the wrong issue tracker
leafpress initnow includes themermaid:andsanitize_htmlsections;markdownadded to format lists in--helpand the GitHub Action- Images from monorepo
url:projects were lost because the clones were deleted before rendering; clones now live until output is written - Images elsewhere in a local source (e.g. a monorepo page using
../../shared/logo.png) were blanked by the new confinement; the folder being converted is now an allowed root - SVG images are embedded in ODT again, sized from their
viewBox, and so are SVG logos on the ODT cover. Units inviewBoxno longer crash, andstroke-widthis no longer mistaken forwidth - Image detection hardened:
- Images are detected by content: anything Pillow can open (TIFF, ICO, extensionless files, …) or an SVG, with up to 1 MB of prolog.
- Decompression bombs are rejected instead of crashing the conversion.
- Results are cached, so
-f allchecks each file once.
- The desktop UI's import window no longer hangs if opening the result fails (e.g. no
xdg-open) - A failed clone or missing source path left a duplicate console log handler attached (repeated warnings in the desktop UI)
- Desktop UI import:
- A failing file no longer aborts the rest of the batch.
- Same-named files can no longer overwrite each other's output.
- The result dialog lists every failure.
- The UI and
leafpress importnow share one importer dispatch,leafpress.importer.dispatch.import_document.
ui.mdcorrected:- the convert window doesn't cover every CLI option;
- the import output folder defaults to next to the source files;
- the local-timezone option and keyboard shortcuts are now documented.
- LaTeX import data loss:
- Accented letters and
\&,\%were silently dropped ("Schön" → "Schon", "100\%" → "100"). ~,--,---and TeX quotes vanished.\paragraphproduced an empty heading.\captionwas never parsed, so figure captions leaked out as loose text instead of becoming alt text.- Beamer slides were discarded.
- Accented letters and
- DOCX watermark font was written as
&quot;Calibri&quot;(double-escaped), so Word didn't get the intended font - Batch
import:- A failed file no longer aborts the batch, and errors now name the file that failed.
- A per-file summary table is shown after multi-file imports.
- Two inputs with the same name no longer silently overwrite each other's output.
- URL imports without
-oare written to the current directory. They were previously written into the download's temp directory and deleted.
convert --fetch-diagramssilently did nothing unless-cwas passed. It now auto-detectsleafpress.ymlin the source directory, and it warns when there is nothing to fetch or the source is a git URLfetch-diagrams:- Downloads run in parallel (up to 4 at a time).
- All failures are reported together instead of stopping at the first.
- Duplicate
destpaths and a missing Lucidchart token are caught before any request is made.
- HTML output is now actually self-contained. Local images and mermaid diagrams are embedded as
data:URIs. Previously they werefile://links that only worked on the machine that built the file - EPUB images now display. They are packaged inside the EPUB instead of linked with
file://, which e-readers can't open. Chapter titles are now escaped - ODT now embeds images. Images inside paragraphs (all normal Markdown images) were silently dropped. Images now also keep their aspect ratio instead of being forced to 4×2 inches
- The mermaid temp directory (
leafpress-mermaid-*) is now deleted after each conversion, including when a conversion fails. The console log handler is also detached on failure - Image
file://URIs containing percent-encoded characters (e.g. spaces) now embed correctly in DOCX - Relative
pymdownx.snippetsbase_pathentries now resolve from the project directory, as MkDocs does, instead of the current working directory
Documentation
- Corrections from a full docs review:
- CI and quick-start examples install
leafpress[pdf]before generating PDFs. - Footer format, version-string format,
copyright_text(EPUB metadata only), ODT SVG support, clone depth,--branch(no commit SHAs) andpage_size(any CSS size) are now described accurately. - Which env vars exist and the full precedence order (CLI flags first) are spelled out.
- The untrusted-repository page now separates protections for all sources from those for cloned repos only.
- CI and quick-start examples install
- README:
- adds Zensical, LaTeX and URL import, the untrusted-repo protections, the GitHub Action (pinned) and Docker;
- corrects the mermaid description (images via mermaid.ink or a self-hosted server, not inline SVG) and the desktop UI's option coverage;
- updates development commands and links CONTRIBUTING and SECURITY.
- Architecture page: new Security Layer section; covers Zensical parsing, the CLI package, shared import dispatch, image embedding, and the LaTeX pipeline; the module map and dependency tables are complete, now including pylatexenc, nh3, tomli and Pillow.
- Other pages:
- landing page cards for untrusted-repo safety, mermaid and Zensical;
- CLI reference covers batch import behavior, parallel diagram fetching and
zensical.tomlauto-detection; - the CI env-var table is complete;
- workflow examples use current action versions.
Tooling
- Pre-commit hook (
make setup-hooks): gitleaks on staged changes,ruff check(now including the bandit-styleSsecurity rules),ruff format --check, andtyat the CI-pinned version - CI: new
secretsjob runs a checksum-verified gitleaks over the full git history make lint/formatcover the whole repo,make typecheckuses the pinnedty, and a newmake secretstarget runs a full-history gitleaks scan- Test coverage raised to ~95% of lines and ~88% of branches (1,060+ tests):
- New end-to-end integration suite: a malicious repository converted to every format leaks nothing; images and mermaid are embedded in every format; CLI flags reach the output; a multi-file LaTeX import runs through the CLI.
- Docker tests cover running as the host user with git version detection.
- Security helpers' edge cases (redirect loops, size caps, unresolvable and multicast hosts, include depth) are now at 97–100%.
- Desktop UI tests (87% of
ui/app.py) now run in CI in a newuijob.
pillowis now a declared dependency (ODT image sizing imports it directly; it was previously only installed transitively via python-pptx)- Cross-format watermark tests check that the text appears (and is escaped) in PDF, DOCX, HTML, ODT, and EPUB
src/leafpress/cli.py(~700 lines) is split into aleafpress.clipackage with one module per subcommand. Theleafpress.cli:clientry point and--helpoutput are unchanged, and new tests cover the CLI error paths- Added
SECURITY.md(private vulnerability reporting) and expandedCONTRIBUTING.mdwith the test layout, fixtures, security-test expectations, and how to add renderers and importers - CIButler integration tests read their location from
LEAFPRESS_CIBUTLER_DOCSinstead of a hardcoded path, and the skip reason says how to enable them .gitignoreand ruff excludes forpytest-of-*/leafpress-mermaid-*are anchored to the repo rootuv_buildrange widened to<0.13(uv 0.12.x); ruff now targets Python 3.13 (matchingrequires-python); removed the unused mypy config/dependency in favor ofty, which now reports zero diagnostics
Upgrade notes
- pymdown-extensions 12 rewrote BetterEm/Tilde/Caret/Mark emphasis parsing to be CommonMark compliant — mid-word
~~,^^, and==are now allowed by default, and edge cases of nested emphasis may render slightly differently docs_diroutside the directory containingmkdocs.ymlis now an error, and image references outside the project are dropped with a warning (see Security above)
0.8.2 — 2026-04-25
Tests
- New unit tests for
importer/image_handler.py— coverssave_image(file writes, counter+hash naming, asset directory creation, full MIME→extension table, default fallback),handle_imagemammoth callback,content_type_for_extension(including.jpegalias), andsaved_imagescopy semantics - New unit tests for
importer/markdown_converter.py— covers ATX heading / dash bullet / asterisk emphasis options,convert_prefenced output (with and withoutlanguage-*class), andconvert_tablepipe-table generation (header separator, ragged-row padding, min column width, empty table, embedded newlines) - 779 total tests (up from 738), 91% overall coverage;
image_handlerandmarkdown_converternow at 100% / 98%
Fixes
- Loosened hard-coded page-count assertions in
test_cibutler_integration.py(== 14→>= 14) so the suite tolerates new pages being added to the upstream cibutler docs site
0.8.1 — 2026-04-09
Improvements
- PPTX converter — warnings are now aggregated by type instead of one per shape, producing cleaner output on decks with many unsupported objects
- PPTX alt text — image shapes now use the shape name as alt text in generated Markdown
- PPTX hyperlinks — bold/italic formatting on linked text is now preserved through the conversion
Fixes
- Type annotations corrected in
source.pyand several test helpers - Import sorting and unused-variable lint errors fixed across the test suite
ty.tomladded to suppress false positives from third-party stubs- Release workflow fixed; integration test path corrected
- Dict-unpacking test helpers replaced with explicit constructions
0.8.0 — 2026-04-04
Features
- LaTeX import — new
leafpress import paper.texconverter using pylatexenc AST walker, supporting sections, formatting, math passthrough, lists, tables, figures, code blocks, links, footnotes, and image extraction. 14 known limitations documented. - URL import —
leafpress import https://example.com/report.docxdownloads and converts in one step, with Content-Type fallback for extensionless URLs and automatic temp cleanup. Works for all four formats. - PPTX warnings — charts, embedded OLE objects, media, and linked objects now produce warnings identifying the slide and shape name instead of being silently skipped
- XLSX warnings — merged cells (with region count), embedded images, embedded charts, and blank workbooks now produce warnings instead of silent data loss
- Improved warning display — import CLI now shows up to 10 warnings with ⚠ prefix and a "… and N more" truncation indicator
Refactor
- Shared importer base — extracted
ImportResult,resolve_output_path,postprocess_markdown, androws_to_pipe_tablefrom the DOCX converter intoimporter/base.py, eliminating cross-converter import dependencies - Shared test helper — consolidated 4 duplicate
_make_png()implementations intotests/helpers.py - Fixed
tabular*regex — environments with multiple brace arguments now parse correctly
Docs
- Import — full LaTeX section with features table, 14-item limitations table, URL import section, and updated batch import examples
- CLI — updated argument description, added URL and LaTeX examples
- Architecture — added LaTeX import section, updated pipeline diagram and module map
- About, Home, UI — updated to reflect LaTeX and URL support
Tests
- 713 total tests (up from 644), 93% importer coverage
- Comprehensive programmatic fixtures for DOCX, PPTX, XLSX, and LaTeX
- Academic paper fixture (
academic_paper.tex) with 29 assertions - 8 URL import tests with mocked HTTP
- Edge case tests for LaTeX macros, environments, images, and error paths
0.7.0 — 2026-03-31
Features
- Asset validation warnings — missing image references are now detected during rendering and reported as warnings with the page name and path, instead of silently producing blank spots in output
- Consistent error messages — DOCX, HTML, ODT, and EPUB rendering failures now show format-specific actionable guidance following the "what happened → why → how to fix" pattern (matching the existing PDF error messages)
- Louder extension load failures — when a Markdown extension fails to load, the error message is now displayed along with an install suggestion (e.g.
pip install pymdownx) for missing packages - Mermaid cache integrity — cached mermaid diagram PNGs are now validated by checking PNG magic bytes; corrupted files (truncated writes, disk errors) are automatically re-rendered instead of silently producing broken images
- Mermaid sanitization refactor — the mermaid source sanitization pipeline is now split into three named, independently testable helpers:
_unescape_html_entities,_replace_literal_backslash_n, and_replace_newlines_in_quoted_labels
Docs
- Configuration — added "How navigation levels work" and "Troubleshooting monorepo builds" sections explaining heading level bumping and common error scenarios
- Architecture — added "Monorepo Pipeline" section describing per-project processing, nav level bumping, and chapter cover generation
- Extensions — added "Troubleshooting extension failures" section with common fixes
- CLI — updated verbose output description to reflect new warning details
- Diagrams — added "Mermaid diagram caching" section explaining content-addressed caching and integrity validation
Tests
- 27 new tests: asset validation tracking (4), extension error message capture (2), error formatter tests for DOCX (2), HTML (3), ODT (2), EPUB (3), PNG validation (4), cache integrity (2), sanitization helpers (6)
- 571 total tests
0.6.2 — 2026-03-28
Refactor
- BaseRenderer protocol and shared helpers — extracted
replace_checkboxes(),make_anchor_id(), andresolve_logo_uri()from PDF, HTML, and EPUB renderers into a newbase_renderer.pymodule, eliminating ~90 lines of duplicated code across renderers - Normalized checkbox CSS classes — PDF renderer now uses
.task-checkbox.checkedclass naming consistent with HTML and EPUB renderers
Docs
- Architecture — added BaseRenderer protocol and shared helpers section, updated module map and "Adding a New Output Format" guide
0.5.1 — 2026-03-13
Fixes
- DOCX watermark — Google Workspace compatibility —
v:shapetypedefinition is now emitted before thev:shapethat references it; without it the OOXML was technically invalid and Google Docs rejected the file entirely. Affects users withwatermark.textset inleafpress.yml - macOS PDF — WeasyPrint system library detection —
leafpress doctornow checks each required library (cairo,pango,gdk-pixbuf,libffi) individually and reports the resolved path or a targeted install hint; Apple Silicon users also get aDYLD_LIBRARY_PATHhint when libraries are installed but not found - macOS PDF — clearer error messages —
ImportError(WeasyPrint not installed) andOSError(system libs missing) are now handled separately with distinct, actionable messages; theOSErrorpath explicitly warns thatbrew install weasyprintis the wrong command
Docs
- Installation — replaced
brew install pangowith full macOS instructions (Apple Silicon / Intel tabs,DYLD_LIBRARY_PATHtip, warning againstbrew install weasyprint) - PDF — added macOS callout with correct brew packages and
leafpress doctorpointer - DOCX — added Google Workspace compatibility note
0.5.0 — 2026-03-11
Features
- Footer render date — new
include_render_dateoption appends the document generation date to the footer across all output formats; configurable vialeafpress.yml,--footer-date/--no-footer-dateCLI flags, orLEAFPRESS_FOOTER_INCLUDE_RENDER_DATEenv var - SVG logo validation — DOCX and ODT renderers now detect SVG logos and skip them with a clear warning instead of crashing; PDF and HTML continue to support SVG natively
- Actionable PDF error messages — rendering failures (e.g.
UnrecognizedImageError) now show specific troubleshooting steps: install librsvg, convert SVG to PNG, or runleafpress doctor - Pipeline warnings surfaced to console —
logger.warning()calls from renderers (SVG logo skip, extension load failures, image embed errors) are now automatically displayed in CLI output as yellow ⚠ messages;--verboseadditionally surfaces DEBUG-level detail - Mermaid diagram progress — each page with mermaid diagrams now reports a rendered count (e.g. "Rendered 3 mermaid diagram(s) in overview.md") with failure details if any diagrams fail
Fixes
- Mermaid
\nrendering — literal\ntext in mermaid diagram labels is now automatically converted to<br/>line breaks; actual newlines inside quoted labels are also handled - DOCX image embed warnings —
warnings.warn()calls in the DOCX HTML converter are now routed through the standard logger so they appear in CLI output
Tests
- 26 new tests:
_format_pdf_errorerror message branches (3),_is_svgdetection for DOCX (7) and ODT (5), SVG logo skip integration for DOCX (1) and ODT (1), PDFRenderErrorwrapping (1),_ConsoleWarningHandler(3), pipeline verbose param (1), mermaid diagram count summary (4) - 526 total tests
Docs
- Configuration updated with
include_render_datefield, env var, and SVG logo compatibility note - Branding updated with SVG logo warning, render date footer option, and CLI override
- CLI reference updated with
--footer-date/--no-footer-dateflag, and--verbosedescription - PDF page updated with new Troubleshooting section for image errors
- DOCX and ODT pages updated with SVG limitations
- Extensions updated with mermaid line break tip
0.4.0 — 2026-03-11
Features
- Monorepo support — list multiple MkDocs projects in
leafpress.ymlunderprojects; each project renders as a chapter of a single combined document with one cover page and unified TOC; per-project metadata overrides (author, document_owner, review_cycle, subtitle); supports git URL projects with optional branch - PowerPoint import —
leafpress import deck.pptxconverts presentations to Markdown; slide titles become H2 headings, speaker notes render as blockquotes, tables and images are extracted;--notes/--no-notesflag to toggle speaker notes - Multi-file import —
leafpress import *.docx *.pptxprocesses multiple files in one command with mixed format support and partial failure handling review_cycleconfig field — new optional field displayed on cover page of all output formats; configurable viaLEAFPRESS_REVIEW_CYCLEenv var
Tests
- 19 new PPTX import tests (slides, formatting, tables, images, notes, CLI integration)
- 17 new monorepo tests (page collection, chapter headings, nav bumping, per-project metadata, config normalization)
- 5 new multi-file import CLI tests (multiple DOCX, mixed formats, output validation, partial failure, backwards compat)
- 3 new dotenv loading tests
- 2 new
bump_nav_levelstests - 3 new
review_cycleconfig tests - 444 total tests
Docs
- New Document Import page with supported/unsupported feature tables for Word and PowerPoint
- New Architecture page with pipeline flowcharts, module map, and key dependencies
- Configuration updated with monorepo support section and
review_cyclefield - CLI reference updated with multi-file import, PPTX support, monorepo example, and
--notesflag - About updated with source control migration messaging
0.3.0 — 2026-03-10
Features
- Project auto-detection —
leafpress convertandleafpress infonow auto-detect the MkDocs project directory when nosourceargument is given; searches git root,docs/subdirectory, CWD, andCWD/docs/in order document_ownerconfig field — new optional field inleafpress.ymldisplayed on the cover page of all output formats (PDF, HTML, EPUB, DOCX, ODT); also configurable viaLEAFPRESS_DOCUMENT_OWNERenv var- Mermaid diagram rendering — fenced
mermaidcode blocks are rendered as inline SVG diagrams in all output formats - Annotation support — Material for MkDocs-style annotations (
(1),(2), etc.) are rendered as numbered footnotes --debugflag onleafpress doctorfor detailed diagnostic output
Tests
- 18 new project auto-detection tests (git root, docs subdir, CWD fallback, yaml extension, error cases)
- 3 new
document_ownerconfig tests (YAML loading, env override, env-over-YAML precedence) - 390 total tests
Docs
- New Markdown Extensions page documenting mermaid, annotations, admonitions, tabs, and task lists
- CLI reference updated with auto-detection behavior, search order, and examples
- Configuration updated with
document_ownerfield andLEAFPRESS_DOCUMENT_OWNERenv var
0.2.2 — 2026-03-10
Features
leafpress doctorcommand — diagnose your environment with a single command; checks Python version, WeasyPrint (package + system libs), PyQt6, and pyobjc; shows ✓/✗ status, versions, and suggested fixes for any missing dependencies--verboseflag ondoctorto also check all 18 core dependencies
Fixes
- Properly fixed Rich markup swallowing
[pdf]/[ui]in error messages — allconsole.print()error sites now userich.markup.escape()instead of embedding Rich-specific escapes in exception messages - Error messages for missing WeasyPrint now suggest running
leafpress doctorto diagnose - GitHub Releases now auto-created when tags are pushed —
release.ymlupdated withgh release createstep andcontents: writepermission
Tests
- 25 new doctor command tests (dataclasses, check functions, orchestrator, CLI integration, Rich escape regression)
Docs
- New
doctorsection in CLI reference with checks table, exit codes, and examples
0.2.1 — 2026-03-10
Fixes
- Fixed
[pdf]being swallowed by Rich markup in the WeasyPrint missing error message — users now correctly seepip install 'leafpress[pdf]'
0.2.0 — 2026-03-10
Features
- EPUB output format — new
leafpress convert -f epubproduces reflowable e-books via ebooklib, with cover page, table of contents, branding CSS, and watermark support - DOCX → Markdown import — new
leafpress importcommand converts Word documents to Markdown using mammoth + markdownify, with image extraction, custom code-style mapping, and pipe tables - Optional PDF extras — WeasyPrint moved from base dependency to
leafpress[pdf]; base install (pip install leafpress) no longer requires system libraries leafpress[pdf]— adds PDF output (WeasyPrint)leafpress[ui]— adds desktop UI (PyQt6)leafpress[all]— everything
Improvements
- Lazy renderer imports in pipeline —
leafpress --helpand non-PDF commands work without WeasyPrint system libraries installed - Friendly error message when PDF output is requested without
leafpress[pdf] convert -f allnow generates 5 formats (PDF, DOCX, HTML, ODT, EPUB)
Tests
- 21 new EPUB renderer tests (cover page, TOC, chapter splitting, branding, watermarks, metadata)
- 23 new DOCX import tests (headings, formatting, lists, tables, images, code blocks, pipe tables, CLI integration)
- 291 total tests, 91% coverage
Docs
- New EPUB documentation page with format details and examples
- Installation restructured with extras: base,
[pdf],[ui],[all] - CLI, CI/CD, and homepage updated to include EPUB format
- Dockerfile updated with
--extra pdffor optional dependency - GitHub Action updated to install
leafpress[pdf]
0.1.3 — 2026-03-10
Features
leafpress fetch-diagramscommand to pull diagrams from URLs and Lucidchart API--fetch-diagramsflag onconvertcommand to fetch diagrams as a pre-stepdiagramsconfig section inleafpress.ymlwith caching, Lucidchart token, and source listLEAFPRESS_LUCIDCHART_TOKENenvironment variable for secure token configuration
Tests
- 17 new DOCX HTML converter tests (strikethrough, superscript, subscript, highlight, line break, task lists, nested lists, images, emoji) — coverage from 90% to 99%
- 30 new diagram tests (config models, cache staleness, URL/Lucidchart fetch, CLI commands)
- Fixed internal link checker to skip fenced code blocks
Docs
- New Diagrams documentation page with configuration, CLI usage, Lucidchart setup, caching, and CI/CD examples
- Diagram Fetching feature card on homepage
- CLI reference updated with
fetch-diagramscommand and--fetch-diagramsflag - Configuration page updated with
diagramssection and field reference - CI/CD page updated with diagram fetching examples and
LEAFPRESS_LUCIDCHART_TOKEN
0.1.2 — 2026-03-10
Features
- Docker support with multi-stage build (Dockerfile, .dockerignore, docs page)
--versionflag documented in CLI reference
Fixes
- Fixed DOCX watermark rendering (VML namespace registration)
Tests
- Added 36 new tests bringing coverage from 87% to 91%
- Added optional Docker integration tests (
pytest -m docker) - New test files:
test_main.py,test_init.py - Expanded:
test_source.py,test_cli.py,test_git_info.py,test_docx_renderer.py,test_odt_renderer.py
Docs
- Added Docker documentation page and feature card on homepage
- Added Global Options section to CLI reference
0.1.1 — 2026-03-10
Features
- HTML single-file output format
- ODT (OpenDocument Text) output format
--local-timeCLI flag to use local timezone for cover page dates (default: UTC)leafpress convert -f allgenerates all four formats in one run- Improved
leafpress uierror message with install commands for uv, pip, and pipx - Watermark overlay support (
--watermarkCLI flag orwatermarkconfig section)
Improvements
- Single-source version via
importlib.metadata(only editpyproject.tomlto bump) - GitHub Action updated with
html,odt, andallformat options andlocal_timeinput - Desktop UI includes "Use local timezone for dates" checkbox
Tests
- Added 68 new tests (pipeline, DOCX converter, PDF/HTML/DOCX styles, security)
- YAML deserialization safety tests (safe_load enforcement, tag neutralization)
- Path traversal tests for
logo_pathandtemplate_path
Docs
- All documentation pages updated for HTML and ODT support
- CLI reference updated with
--local-timeflag and new format options - CI page updated with new action inputs and environment variables
- Fixed tab rendering in docs (added
pymdownx.tabbedextension)
0.1.0 — 2026-03-09
Initial release.
Features
- Convert MkDocs sites to PDF (WeasyPrint) and DOCX (python-docx)
- Branded cover page, table of contents, and footer
- Git version info embedded in output (tag, commit, date, branch)
leafpress.ymlbranding configLEAFPRESS_*environment variable overrides with.envsupport- Remote git URL sources
- Desktop UI (PyQt6 menu bar / system tray app)
- Composite GitHub Action (
uses: hutchins/leafpress@main) - "Made with LeafPress" attribution in all rendered footers