Skip to main content

LaTeX Build and Preview

The latex addon supplies TeX Live, latexmk, bibliography tools, fonts, and common package groups. aibox adds a project-level build contract on top so humans and agents use the same engine, cache, output paths, and document names.

Configure documents

Enable the addon and declare one or more documents:

[addons.latex.tools]
texlive-core = {}
texlive-recommended = {}
texlive-fonts = {}
biber = {}

[latex]
engine = "lualatex"
cache_dir = ".latex-cache"
options = []

[[latex.documents]]
name = "overview"
source = "docs/overview/overview.tex"
output_dir = ".latex-cache/overview"

[[latex.documents]]
name = "appendix"
source = "docs/appendix/appendix.tex"
output_dir = ".latex-cache/appendix"

[latex.preview]
enabled = true
engine = "embedpdf"
bind = "127.0.0.1"
port = 8765
# document = "overview" # optional compatibility-route default
allow_public = false

Supported engines are lualatex, pdflatex, xelatex, and tectonic. Continuous watch mode uses latexmk, so tectonic configurations support one-shot builds only.

Build and watch

Run these commands inside the development container. aibox apply generates them under .aibox-home/.local/bin, which is already on the container PATH:

aibox-latex-build # every configured document
aibox-latex-build overview # one configured document
aibox-latex-watch overview # foreground watcher; stop with Ctrl-C

Builds use non-interactive, file-and-line-error, halt-on-error flags. Watch mode adds latexmk -pvc -view=none, leaving browser preview ownership to the sidecar. TEXMFVAR and TEXMFCONFIG live below latex.cache_dir, so TeX does not write mutable state to the user's global TeX tree.

Compilation never runs on the host or in the preview sidecar. The scripts use the TeX installation in the main development container, keep the watch process in the foreground, and write PDFs below each configured output_dir. Run one watcher per document when several documents should rebuild concurrently.

Running aibox apply adds a concise, conditional aibox-managed LaTeX section to AGENTS.md. This is the primary instruction surface for AI agents and gives them the configured container commands, companion health check, preview URLs, and document paths without adding another root-level guidance file.

Live PDF preview

When preview is enabled, aibox apply generates a dedicated Compose sidecar and port mapping. Host-side aibox up starts that sidecar, which serves every configured document from the project workspace mounted read-only. The sidecar does not contain a TeX toolchain and cannot modify the workspace. latex.preview.document chooses the preferred document used by compatibility routes; it does not exclude the others.

Inspect its logs with:

docker compose -f .devcontainer/docker-compose.yml logs <project-container-name>-latex-preview

aibox down stops the sidecar with the rest of the Compose project. A subsequent aibox up starts it again. With multiple documents, the root URL displays a selection page. Each PDF also has a stable direct URL:

http://127.0.0.1:8765/
http://127.0.0.1:8765/documents/overview/
http://127.0.0.1:8765/documents/appendix/

The stable URL is http://127.0.0.1:8765/. The service watches the completed PDF output for every document, waits for its metadata to remain stable across multiple polls, and then sends a document-specific SSE revision event. This prevents the browser from fetching a partially-written PDF. The browser requests a versioned PDF URL on reload so a stale cache cannot hide a new build. Page and zoom state are retained separately for each document.

The viewer uses the pinned @embedpdf/snippet browser package. Its default toolbar provides navigation, zoom, search, thumbnails, and outline support when the PDF contains an outline. The browser must be able to reach jsDelivr to load the pinned viewer module; the PDF itself is served by the local preview sidecar.

Host and network access

The preview helper listens on 0.0.0.0:8765 inside its isolated sidecar. The generated Compose mapping publishes that internal port only on the configured host address and port. The secure default is therefore accessible from the host browser but not from other machines:

[latex.preview]
enabled = true
bind = "127.0.0.1"
port = 8765
allow_public = false

Run aibox apply after changing this configuration, then run aibox up on the host. Do not add a manual override mapping; aibox generates 127.0.0.1:8765:8765 in .devcontainer/docker-compose.yml.

For access from another machine on the local network, explicitly expose the unauthenticated endpoint:

[latex.preview]
enabled = true
bind = "0.0.0.0"
port = 8765
allow_public = true

This generates 0.0.0.0:8765:8765. Open http://<host-ip>:8765/ and ensure the host firewall permits the port. Prefer the loopback default plus SSH forwarding when possible.

Remote hosts over SSH

The default bind address is loopback and is suitable for SSH forwarding:

ssh -L 8765:127.0.0.1:8765 user@remote-host

Then open http://127.0.0.1:8765/ locally. Publishing on a non-loopback host address is rejected unless allow_public = true is also set. That opt-in exposes an unauthenticated PDF endpoint; prefer an SSH tunnel.