doxtr-hugo
A Sphinx builder for the doxtr ecosystem that turns a Sphinx documentation source into content for the Hugo static site generator.
Author in reStructuredText/Sphinx and deploy the result as a Hugo site: the
extension adds a hugo builder (sphinx-build -b hugo) that walks the resolved
doctree and emits one Markdown file per document plus co-located assets, laid
out as a buildable Hugo site. It emits only formats Hugo renders natively
(CommonMark/Goldmark Markdown with front matter, and diagrams/figures
pre-rendered to static images — SVG preferred, PNG fallback), so no Hugo
modules, render-hook JavaScript, or the asset pipeline are required on the
consumer side.
Status: early development. See
doxtr-hugo-implementation-guide.mdfor the full specification andIMPLEMENTATION_STATUS.mdfor progress.
Features
Supported constructs and capabilities:
- Content translation — section headings, paragraphs, inline markup
(emphasis/strong/literal), bullet and enumerated lists (nested), line blocks,
block quotes, definition lists, field lists, images and figures, and
.. rubric::. - Code blocks — literal/
.. code-block::blocks emitted as fenced Goldmark code blocks with language hints. - Tables — GFM pipe tables by default, with a raw-HTML fallback for cells
that span rows/columns (
doxtr_hugo_tables). - Admonitions — typed directives (note, warning, tip, caution, danger,
error, hint, important, attention, seealso) and generic
.. admonition::titles, emitted as a Hugo shortcode by default or portable raw HTML (doxtr_hugo_admonitions). - Cross-references —
:doc:/:ref:and internal references emitted as Hugo{{< relref >}}(build-time validated) by default, or plain relative links (doxtr_hugo_link_style); external links and raw-HTML passthrough. - toctree → sections — toctree drives the Hugo section/weight model (branch
vs. leaf pages, deterministic per-parent weights,
_index.mdgeneration) and on-page navigation lists, with no hand-written front matter. - Diagrams — five backends pre-rendered to static images: PlantUML,
Graphviz, Mermaid, d2 (
doxtr_d2), and sphinx_diagrams (thediagramsPython library, PNG-only). SVG is preferred, PNG is the portable fallback, and a missing backend degrades gracefully (doxtr_hugo_on_missing_backend). Custom backends register viadoxtr_hugo.register_backend. - Math — pre-rendered to transparent PNG by default (zero extra binary via
matplotlib mathtext), with
mathjaxandmathml-passthroughopt-in (doxtr_hugo_math). - Invisible nodes — RST comments (
.. a comment), substitution definitions, docutils system messages,.. meta::, and transformpendingplaceholders are stripped from the output (their text never leaks into the page); resolved substitution usages still render.
Installation
pip install doxtr-hugo
The diagram backends are optional. To pull in the Sphinx-side extensions that
provide diagram directives (PlantUML, Mermaid, d2, and the diagrams library),
install the diagrams extra:
pip install "doxtr-hugo[diagrams]"
To install every optional feature at once (all diagram backends plus PyYAML for
YAML front matter), use the all extra:
pip install "doxtr-hugo[all]"
The external rendering binaries (plantuml, dot, mmdc, d2) are not
Python dependencies — the builder only invokes them when present on PATH and
degrades gracefully otherwise (doxtr_hugo_on_missing_backend).
Usage
Enable the extension in your Sphinx conf.py:
extensions = [
"doxtr_hugo",
]
Then build the Hugo site:
# Either form works:
make hugo # -> build/hugo/
# or:
sphinx-build -b hugo source build/hugo
Previewing locally
The extension does not ship or modify any Makefile. Registering the
builder via app.add_builder() is the entire integration surface; the
Makefile generated by sphinx-quickstart already forwards unknown targets to
sphinx-build, so make hugo works without any extension-side change.
With the default doxtr_hugo_emit_skeleton = "full", the output in
build/hugo/ is a self-contained, runnable Hugo site:
# Build the Hugo site (either form works)
make hugo # -> build/hugo/
# or:
sphinx-build -b hugo source build/hugo
# Preview it (requires the default emit_skeleton = "full")
cd build/hugo
hugo server
Notes:
- The output lands in
build/hugo/(themake/sphinx-buildBUILDDIR), which is a self-contained, runnable Hugo site because the builder'sfinish()emittedhugo.toml+layouts/. hugo serverrequiresemit_skeleton = "full"(the default). In"content-only"mode there is nohugo.toml/layouts/, so preview must happen from within the consumer's own Hugo project.- Drafts: pages are emitted with
draft = false, so plainhugo servershows them;hugo server -Dis only needed if the consumer later sets pages to draft.
Using with a third-party Hugo theme
The default emit_skeleton = "full" output ships doxtr-hugo's own
layouts/_default/ so the site builds standalone. Those layouts override a
theme: Hugo's template precedence puts a site-level layouts/_default/ above
any --theme, so building the full output under a theme makes every theme
render the skeleton's HTML rather than its own. To deploy under a third-party
theme, emit the theme-portable form instead:
sphinx-build -b hugo \
-D doxtr_hugo_emit_skeleton=content-only \
source build/hugo-content
doxtr_hugo_emit_skeleton = "content-only"writes onlycontent/**(section_index.mdfiles + co-located assets) — nohugo.toml, nolayouts/. Drop thatcontent/**into your own themed Hugo site.- In
content-onlymode the builder defaultsdoxtr_hugo_admonitionsto"html"automatically (portable raw HTML), because a third-party theme does not ship doxtr-hugo'sadmonitionshortcode — shortcode admonitions would fail there withtemplate for shortcode 'admonition' not found. Setdoxtr_hugo_admonitionsexplicitly to override (e.g."shortcode"if your site provides its ownadmonitionshortcode). - If you instead keep the default
"full"emit and add a theme, be aware the emittedlayouts/will shadow the theme; use"content-only"(above) for real theme deployment.
See the configuration knobs doxtr_hugo_emit_skeleton and
doxtr_hugo_admonitions for the full surface.
Configuring a theme (ready-to-serve output)
Instead of hand-assembling a themed site from the content-only output, you
can configure the theme once in your Sphinx conf.py and have
sphinx-build -b hugo emit a complete, version-controllable Hugo site under
build/hugo/ whose hugo.toml is correctly configured for that theme:
# conf.py
doxtr_hugo_theme = "docsy" # a shipped profile, or any theme name
doxtr_hugo_theme_config = { # deep-merged into hugo.toml (you win)
"params": {"github_repo": "https://github.com/me/docs"},
}
# Optional: override how the theme is obtained (defaults to a Hugo Module).
doxtr_hugo_theme_source = {"kind": "module", "url": "github.com/google/docsy"}
Building then produces, in build/hugo/:
- a merged
hugo.toml= core defaults (goldmarkunsafe+ extensions) + the theme profile (e.g. docsy'stype="docs"cascade, hugo-book'sBookSection="*") + yourdoxtr_hugo_theme_config(highest precedence); - a
README-hugo.mdlisting the exact one-time commands still needed for that theme (e.g.hugo mod get, installing Dart Sass,npm install) beforehugo server— the extension documents these, it never runs them; - the image render hook so math/diagram images resolve under any theme.
Shipped profiles (edition/toolchain/config captured so the output just works):
archie, hugo-terminal, hyde, risotto, notepadium, hugo-book,
docsy. A theme with no shipped profile still works — it is emitted with core
defaults plus your doxtr_hugo_theme_config, and you supply the theme + config.
The emitted build/hugo/ is Hugo input: commit it, then run the README's
commands and hugo server. For light themes vendored into themes/ nothing
extra is needed; SCSS themes like docsy require the documented extended
Hugo + Dart Sass + npm steps.
Overlay (escape hatch) and hooks
Anything the declarative config cannot express goes in a sidecar overlay
directory, copied verbatim into build/hugo/ on top of the emitted site (your
files win):
source/.doxtr/hugo/ # doxtr_hugo_theme_overlay_dir (confdir-relative)
config/overlay.toml # extra raw Hugo config fragments
layouts/partials/head.html # custom/partial template overrides
assets/scss/_variables_project.scss
static/img/logo.png
The extension auto-excludes .doxtr/** from Sphinx's document scan, so overlay
files are never parsed as reStructuredText. For programmatic post-processing,
doxtr_hugo_theme_hook = "mypkg.mymod:callable" runs your own project code last
(called with outdir, config, app), after all files are written.
Configuration keys: doxtr_hugo_theme, doxtr_hugo_theme_config,
doxtr_hugo_theme_source, doxtr_hugo_theme_overlay_dir,
doxtr_hugo_theme_hook.
Page titles (no duplicate heading)
By default (doxtr_hugo_title_heading = "frontmatter") the page's leading
top-level heading is not emitted into the Markdown body — it is carried by
the title front matter, which every Hugo theme (and the built-in skeleton)
renders. Emitting it in the body too would show the title twice. Deeper headings
(## and below) are always kept. Set doxtr_hugo_title_heading = "body" to
restore the legacy behavior of writing the leading # Title into the body (for
a theme that does not render .Title itself).
Changelog
See CHANGELOG.md for the release history.
License
MIT — see LICENSE.
Metadata
Release files for doxtr-hugo 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| doxtr_hugo-0.1.0.tar.gz | 127.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| doxtr_hugo-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 222.3 kB
Release files / doxtr_hugo-0.1.0.tar.gz
| Download URL | doxtr_hugo-0.1.0.tar.gz |
|---|---|
| Size | 127.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
124ca3e14d79614a9eacc7ee2a83bf857332bda1db31e98a21d0065cb2db425a
|
|
BLAKE2b-256 checksum How to use checksums |
1f3b0d0d245110fc79e613fc6a95cbc5161b7d31584acf39c540c9eda4989977
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency logRelease files / doxtr_hugo-0.1.0-py3-none-any.whl
| Download URL | doxtr_hugo-0.1.0-py3-none-any.whl |
|---|---|
| Size | 95.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
43c5b707357cef7dd4627b1941319b289fb5bdda1b540b139071079bf1f34d3c
|
|
BLAKE2b-256 checksum How to use checksums |
0f78a0f831f8f9f55768b23ab95e2d7b55c123459d7a94873afcc53a133c0b3f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 18, 2026.
Transparency log