Templates¶
TeXSmith templates define the LATEX skeleton that wraps converted Markdown. Each template bundles assets, slot definitions, attribute schemas, and build metadata so you can aim the renderer at anything from articles to slide decks.
Templates are a core feature that allows TeXSmith to be extended for different use cases. You may use:
- Custom project templates stored in a
templates/folder. - Local user templates installed in your
~/.texsmith/templates/folder. - Published templates installed from PyPI.
- Built-in templates included with TeXSmith.
Built-in templates¶
TeXSmith includes standard templates for common document types:
article: academic-style article layout with title page, abstract, and sections.book: book-style layout with parts, chapters, preface, table of contents, appendices, and optionalpartbase-level override.letter: formal letters with sender/recipient metadata, fold marks, and signature.snippet: standalonetikzpictureframe for screenshots, stickers, and snippets.
Invoke them in the CLI with -tarticle or -tletter. Additional community templates remain available under templates/ or as separate PyPI packages.
Take a look at built-in fragments for full configuration options.
Quick start¶
# 1. Inspect a built-in template
texsmith --template article --template-info
# 2. Render a document with template slots + build
texsmith docs/intro.md \
--template article \
--slot mainmatter:@document \
--output-dir build/article \
--build
Need a blank template skeleton? Use the scaffold flag to copy any template into your working tree:
texsmith --template article --template-scaffold my-template
cd my-template
uv run hatch build # optional packaging smoke test
Publish by pointing pyproject.toml to the template/ package, then uv publish or twine upload dist/*.
For in-depth patterns (overrides, slots, metadata), see the Template Cookbook.
Write your own TeXSmith templates¶
TeXSmith uses Jinja2 templates to assemble LATEX documents from converted Markdown fragments. You can create your own templates to control the layout, styling, and structure of the final output.
You may start by copying an existing template package and modifying it to suit
your needs. Templates can either be published on PyPI for easy distribution or kept locally for personal use. By default, TeXSmith will look for templates installed in the current Python environment or in the current working directory under a templates/ folder.
Structure¶
├── README.md
├── __init__.py
├── pyproject.toml
├── overrides
│ └── fragment.tex
└── template
├── assets
│ └── latexmkrc
├── manifest.toml
├── template.tex
└── .sty, .cls...
TOML manifest¶
The manifest.toml file describes the template and its metadata.
[compat]
# Specify the compatible TeXSmith versions. Do not forget
# to set a maximum version to avoid future incompatibilities.
texsmith = ">=0.1,<1.0"
[latex.template]
name = "acme"
version = "0.1.0"
entrypoint = "template/template.tex"
# Useful for generic docker images or CI pipelines, where
# we only install the required packages.
texlive_year = 2023
tlmgr_packages = [
"babel",
"geometry",
"hyperref",
"microtype",
"fontspec",
"biblatex",
]
# Attributes:
# -----------
# Attributes are declared as nested tables describing the type, default
# value, and optional normalisation rules for each entry. Types are inferred
# from the default when omitted.
[latex.template.attributes.base_level]
default = 1
type = "integer"
[latex.template.attributes.title]
default = "Title"
type = "string"
escape = "latex"
allow_empty = false
[latex.template.attributes.subtitle]
default = ""
type = "string"
escape = "latex"
[latex.template.attributes.author]
default = "John Doe"
type = "string"
escape = "latex"
[latex.template.attributes.date]
default = "\\today"
type = "string"
escape = "latex"
[latex.template.attributes.language]
default = "english"
type = "string"
normaliser = "babel_language"
[latex.template.attributes.paper]
default = "a4paper"
type = "string"
normaliser = "paper_option"
[latex.template.attributes.orientation]
default = "portrait"
type = "string"
normaliser = "orientation"
choices = ["portrait", "landscape"]
[latex.template.attributes.bibliography_style]
default = "numeric"
type = "string"
# Slots definition:
# -----------------
# Each slot represents a section of the document that can be filled
# with content. The 'depth' parameter indicates the LaTeX sectioning
# command to use.
[latex.template.slots.mainmatter]
default = true
depth = "section"
[latex.template.slots.abstract]
depth = "section"
strip_heading = true
# Additional Assets:
# ------------------
# All additional assets to be included in the template package.
# They will be copied to the working directory when the template is used.
[latex.template.assets]
".latexmkrc" = { source = "template/assets/latexmkrc" }
Attribute schema¶
Each attribute table accepts the following keys:
default: (required) the value injected when no override is provided.type: optional primitive amongstring,integer,float,boolean,list,mapping,any. When omitted TeXSmith infers a type fromdefault.sources: the lookup paths (dot notation) used to pull overrides from document front matter. If omitted, TeXSmith probespress.press.<name>,press.<name>, then<name>.allow_empty: whenfalse, empty strings are coerced toNoneso templates fall back to defaults.required: whentrue, a missing override raises aTemplateError.choices: restricts string/integer values to the provided list.escape: currently supportslatexto automatically escape special characters coming from user input.normaliser: name of a registered normaliser that post-processes the value (see below).
Attributes are resolved before WrappableTemplate.prepare_context runs, meaning template classes only need to handle presentation-specific tweaks (for example, combining authors, building option strings, or removing temporary keys).
Attribute ownership & precedence¶
- Each attribute belongs to a single owner (template by default, fragment when declared in
fragment.toml). Conflicting owners raise aTemplateError. - Overrides flow: CLI/front matter → attribute resolver (type coercion, normalisers) → template emitters/fragment defaults. Empty strings are dropped when
allow_empty = false. - Attributes no longer live under ad-hoc dotted names (
press.*); normalisation collapses supported aliases onto the declared attribute name.
Template slots and built-ins¶
- Templates must declare at least one slot;
mainmatteris the default when absent. Slots surfacedepth,offset,strip_heading, and optionalbase_level. - Built-in
articleexposesmainmatter,abstract,appendix, andbackmatter.bookinsertsappendixbeforebackmatterand supportsparttoggling.letterusesmainmatteronly. - Deprecated attributes removed from built-ins:
article/bookno longer acceptcover,covercolor,twocolumn, or template-ownedemoji. Backmatter/preamble overrides moved into fragments where applicable.
Built-in normalisers¶
| Name | Purpose |
|---|---|
paper_option |
Validates paper sizes and emits <size>paper strings (for example letterpaper). |
orientation |
Normalises orientation flags and guarantees portrait or landscape. |
babel_language |
Maps ISO-like language codes to Babel identifiers (for example fr → french). |
Normalisers run after type coercion and before escaping. They can also reuse existing defaults to provide fallbacks (paper_option and orientation do this).
Metadata overrides¶
At runtime TeXSmith merges template defaults with document front matter. By default, overrides come from the press section:
---
press:
title: Sample Article
subtitle: Insights on Cheese
language: fr
authors:
- name: Ada Lovelace
affiliation: Analytical Engine
- name: Grace Hopper
---
With the manifest above TeXSmith will:
- Escape
titleandsubtitlefor LATEX compatibility. - Map
language: frtofrench. - Normalise author collections so individual templates can format them consistently.
- Populate both defaults (
author) and structured data (authors) that template classes can consume.
To pull metadata from alternative locations add explicit sources:
[latex.template.attributes.project_code]
default = ""
type = "string"
sources = ["press.project.code", "project.code"]
allow_empty = false
Slots¶
Slots control where converted content is injected. Each entry allows:
depth: maps to a LATEX sectioning command (section,chapter, etc.).base_levelandoffset: fine tune heading levels when rendering.default: mark exactly one slot as the primary sink for content.strip_heading: remove the first heading when populating the slot (useful for abstracts).
Slots become Jinja variables inside the template (\VAR{abstract}, \VAR{mainmatter}).
Overrides¶
TeXSmith uses partials to render different parts of the document such as bold text with adapters/latex/partials/bold.tex:
\textbf{\VAR{text}}
You may want to override some of these partials to customize the output of specific Markdown elements. To do so, create an overrides/ folder in your template package and add the partials you want to override.
When the manifest lists latex.template.override = ["partials/bold.tex"], TeXSmith searches the following locations in order:
<template>/overrides/<template>/template/overrides/- The template root itself.
- A sibling
overrides/directory next to the template package.
Placeholders inside override files can use the same Jinja syntax (\VAR{...}, \BLOCK{...}).
Slot strategies¶
Slots determine how multiple Markdown documents (or sections) flow into the LATEX structure. Typical patterns:
- Single document, single slot – map the only input with
--slot mainmatter:@document. - Front matter + main matter – convert two files (eg
intro.md,book.md) and pass--slot frontmatter:intro.mdand--slot mainmatter:book.md. - Selective sections – reference headings or IDs:
--slot abstract:paper.md:@abstract --slot mainmatter:paper.md:"Results"injects only the abstract heading and the “Results” section into separate slots. - Per-language appendices – define slots (
appendix_en,appendix_fr) and use front-matter metadata (press.slot.appendix_en: docs/en.md) so automation scripts do not need to pass CLI flags.
Slots are resolved by the document slot mapping across CLI flags, front matter (press.slot.*), and API overrides, so mix and match whichever suits your workflow.
Testing your template¶
Before publishing, run the built-in test suite against your template:
uv run pytest tests/test_template_attributes.py
This repository includes examples for the bundled templates; copy one into your package and adjust expectations to match your manifest. Automated tests help ensure attributes, slots, and metadata mappings keep working as the TeXSmith runtime evolves.
Next steps¶
- Study the Template Cookbook for practical recipes (title pages, metadata bindings, bibliography tweaks).
- Browse the API high-level guide to orchestrate templates programmatically with
ConversionService.