GatPack is a CLI and Python API for automating LaTeX and PDF document generation using Jinja templating. This was originally developed for creating professional looking packets for AI safety coursework at MIT AI Alignment.
Built With
- Typer (For the CLI)
- LaTeX (For creating documents from text)
- Jinja (For templating and placeholders)
- Pydantic (For specifying the config file schema)
See who is using
- MIT AI Alignment (MAIA)
- AI Safety Student Team (AISST) at Harvard
- Columbia AI Alignment Club (CAIAC)
Let us know if your team is using it an how!
- Python 3.10+
- LaTeX (
pdflatex
specifically, see more instructions on installing below)
Run the following command to install globally:
python3 -m pip install gatpack
Further Install Instructions
Run the following command to install globally (or install into a virtual environment and activate, whichever you prefer.):
python3 -m pip install gatpack
To use gatpack build
which will convert a LaTeX document to a PDF, you will need pdflatex
to be available on your path. You can check for this with
pdflatex --verison
If this command isn't found, then you need to install a LaTeX compiler to your machine.
For mac you can install MacTeX. Using Homebrew:
brew install --cask mactex
Note: Eventually this LaTeX requirement will be removed
You can then run the following to confirm GatPack has been successfully installed (will not check for a valid pdflatex):
gatpack --help
cd into the directory you would like to create your project and run
gatpack init
Follow the set up steps to name your project.
Source code for the project template can be found here
The example compose file comes with one preset pipeline called reading-packet
which contains the instructions to build a packet with a cover, readings, and a final page with additional readings.
gatpack compose reading-packet --overwrite
When finished, you should have an output/output.pdf
file.
The CLI commands are NOT documented in any dedicated page. Instead commands are documented from within the CLI itself. gatpack --help
will provide usage information. gatpack COMMAND --help
will provide usage information on subcommands.
The Jinja placeholders for LaTeX were modified to ensure compatability and a good user experience:
Function | LaTeX-Modified | Standard | Usage |
---|---|---|---|
Expresssions & Variables | \VAR{variable_name} |
{{ variable_name }} |
Insert a variable value |
Statements & Control Structures | \BLOCK{for item in items} |
{% for item in items %} |
Control structures (loops, conditionals) |
Comments | \#{comment text} |
{# comment text #} |
Add template comments |
Line Statements | %- |
# |
Single line statements |
Line Comment | %# |
## |
Single line comments |
See the Jinja API for more information. Apart from the delimeter syntax, everything should work the same. These placeholders will be filled in with variable assignments made from your compose.gatpack.json
's context
object when you run gatpack infer
(ex: gatpack infer --from example.jinja.tex --to example.tex
).
Why this Modification is Needed
Standard Jinja placeholders: {{ variable_name }}
, {% for item in items %} {% endfor %}
, etc. don't play well with LaTeX. It becomes very difficult to view your LaTeX template since you run into syntax errors and some LaTeX syntax conflicts with Jinja tags, leading to errors from both systems.
The Jinja placeholders above are meant to fix this issue.
Get placeholder highlighting in your LaTeX document
% Define Jinja placeholder commands for better editor visualization
\usepackage{xcolor}
\definecolor{jinjaColor}{HTML}{7B68EE} % Medium slate blue color for Jinja
\definecolor{jinjaVarBg}{HTML}{E6E6FA} % Light lavender for variables
\definecolor{jinjaBlockBg}{HTML}{FFE4E1} % Misty rose for blocks
\definecolor{jinjaCommentBg}{HTML}{E0FFFF} % Light cyan for comments
\newcommand{\VAR}[1]{\colorbox{jinjaVarBg}{\detokenize{#1}}}
\newcommand{\BLOCK}[1]{\colorbox{jinjaBlockBg}{\detokenize{#1}}}
\newcommand{\COMMENT}[1]{\colorbox{jinjaCommentBg}{\detokenize{#1}}}
If you need more than just LaTeX and PDFs, it's recommended that you check out pandoc -- a software that can convert most files from one format to another (Ex: LaTeX to Markdown, HTML, etc.). It of course doesn't work quite as well as natively writing the document in that language, but I generally recommend it.
Here is the compose.gatpack.json
file that comes with the sample gatpack init
project:
{
"$schema": "https://raw.githubusercontent.com/GatlenCulp/gatpack/refs/heads/feature/compose-actions/gatpack/schema/json/GatPackCompose.schema.json",
"name": "Intro Fellowship Reading Packet",
"description": "Packet for CAIAC's Spring 2025 Intro Fellowship",
"version": "1.0",
"context": {
"program_long_name": "Intro Fellowship",
"time_period": "Spring 2025",
"chron_info": "WEEK 0",
"title": "Introduction to machine learning",
"subtitle": "READINGS",
"primary_color": "0B0D63",
"primary_color_faded": "789BD6",
"core_readings": [
{
"title": "Neural Networks",
"read_on_device": true,
"subsection": "Chapters 1-6",
"author": "3Blue1Brown",
"year": 2024,
"url": "https://youtube.com/playlist?list=PLZHQObOWTQDNU6R1_67000Dx_ZCJB-3pi&feature=shared",
"thumbnail_path": ""
}
],
"further_readings": [
{
"title": "A short introduction to machine learning",
"subsection": "",
"author": "Ngo",
"year": 2021,
"url": "https://www.alignmentforum.org/posts/qE73pqxAZmeACsAdF/a-short-introduction-to-machine-learning",
"thumbnail_path": ""
},
// ... More readings
{
"title": "A (long) peek into reinforcement learning",
"subsection": "",
"author": "Weng",
"year": 2018,
"url": "https://lilianweng.github.io/posts/2018-02-19-rl-overview/",
"thumbnail_path": ""
}
]
},
"pipelines":[
{
"description": "Create the full reading packet.",
"id": "reading-packet",
"steps": [
{
"name": "Render cover page",
"from": "cover/cover.jinja.tex",
"to": "cover/cover.pdf"
},
// ... More Steps ...
{
"name": "Combine all readings into packet.pdf",
"combine": [
"cover/cover.pdf",
"device_readings/device_readings.pdf",
"further_readings/further_readings.pdf"
],
"to": "output/packet.pdf"
}
]
}
]
}
The context
object contains variable assignments used to fill in Jinja placeholders.
"context": {
"program_long_name": "Intro Fellowship",
"time_period": "Spring 2025",
"chron_info": "WEEK 0",
"title": "Introduction to machine learning",
"subtitle": "READINGS",
"primary_color": "0B0D63",
"primary_color_faded": "789BD6",
// ...
}
The pipelines
list contains sequential steps. Each pipeline
requires and is referred to by an id
key
"pipelines": [
{
// Required ID to refer to the pipeline
"id": "reading-packet",
// Optional description
"description": "Create the full reading packet.",
// Steps that define the pipeline operations
"steps": [
{
"name": "Render cover page",
"from": "cover/cover.jinja.tex",
"to": "cover/cover.pdf"
},
//... More pipeline steps ...,
{
"name": "Combine all readings into packet.pdf",
"combine": [
"cover/cover.pdf",
"device_readings/device_readings.pdf",
"further_readings/further_readings.pdf"
],
"to": "output/packet.pdf"
}
]
}
]
Additionally, pipelines
defines a single pipeline
: a sequential set of steps to perform for some operation. Running gatpack compose
in the same directory as your compose.gatpack.json
file will show all available pipelines.
Each step in a pipeline must contain a name
key. The only two operations supported in steps now are: gatpack infer
and gatpack combine
// Gatpack Infer Example Step
{
"name": "Render cover page",
// File to convert (*.tex or *.jinja.tex file)
"from": "cover/cover.jinja.tex",
// File to save to
"to": "cover/cover.pdf"
}
// Gatpack Combine Example Step
{
"name": "Combine all readings into packet.pdf",
// List of PDFs to combine
"combine": [
"cover/cover.pdf",
"device_readings/device_readings.pdf",
"further_readings/further_readings.pdf"
],
// Location to save combined PDF to
"to": "output/packet.pdf"
}