1 - Overview

Addons

aibox uses the Debian runtime image family (base-debian-v0.26.x for legacy releases, base-debian-runtime-v0.27.0+ after the image-tag cutover) with 36 composable addons that install language runtimes, tool bundles, documentation frameworks, and AI coding agents into your container.

Managing Addons

Via CLI

# See all available addons
aibox get addon

# Add an addon (updates aibox.toml and runs apply)
aibox set addon python

# Remove an addon
aibox delete addon python

# View addon details (tools, versions)
aibox describe addon rust

# Emit the machine-readable addon catalog index
aibox describe addon-catalog -o json

Via aibox.toml

[addons.python.tools]
python = { version = "3.14" }
uv = { version = "0.12.5" }

[addons.rust.tools]
rustc = { version = "1.97.1" }
clippy = {}
rustfmt = {}

[addons.node.tools]
node = { version = "26" }
pnpm = { version = "11.22.0" }

Each addon has default-enabled tools that are included automatically, and optional tools you can enable explicitly. Tools with version selection let you pick from curated, tested versions.

Language addons also expose composable nested groups. For example, [addons.go.quality], [addons.go.supply-chain], and [addons.go.release] select the canonical go-quality, supply-chain, and go-release recipes and expand their dependencies automatically. Nested [addons.<language>.<group>.tools] entries use the same version and enabled overrides as flat addons.

aibox describe addon-catalog -o json emits the stable aibox.addon-catalog.v0 index used by downstream automation. It includes each addon’s profile intent, automation usage class, supported aibox profiles, exported surfaces, dependencies, and tool metadata. Canonical processkit Artifact{kind=addon-spec} emission remains gated on the upstream processkit schema release.

After editing aibox.toml, run aibox apply to regenerate the Dockerfile and rebuild.

Available Addons

Language Runtimes

AddonDefault ToolsOptional Tools
pythonpython (3.12/3.13/3.14), uv (0.7/0.11.10/0.11.11/0.11.15/0.11.19/0.11.26/0.12.0/0.12.5)poetry (1.8/2.0/2.4.1), pdm (2.22/2.26.9/2.27.0/2.28.0/2.28.1)
rustrustc (1.90/1.91/1.92/1.93/1.94/1.94.1/1.96.0/1.96.1/1.97.1), clippy, rustfmt
nodenode (20/22/24/26), pnpm (9/10/11.1.3/11.5.2/11.10.0/11.18.0/11.20.0/11.21.0/11.22.0)yarn (4/4.16.0/4.17.0), bun (1.2/1.3.14)
gogo (1.25/1.26/1.26.3/1.26.4/1.26.5/1.26.6)
go-qualitygoimports, staticcheck, golangci-lint, govulncheck, gosec
typsttypst (0.13.1/0.14.2/0.15.0)
latextexlive-core, texlive-recommended, texlive-fonts, biber, texlive-code, texlive-diagrams, texlive-mathtexlive-music, texlive-chemistry

Tool Bundles

AddonDefault ToolsOptional Tools
infrastructureopentofu, ansible, packerpodman (rootless engine and Compose)
supply-chaingitleaks, osv-scanner, syft, grype, cosign
releaseshellcheck, hadolint
go-releasegoreleaser (requires go and release)
git-uigh, lazygit
preview-archivechafa, librsvg, poppler, timg, mupdf, entr, p7zip, resvg
preview-enhancedrich, ffmpeg, ghostscript
data-previewsqlite3, csvkit
audio-voicesox, pulseaudio-utils, ALSA PulseAudio plugins
kuberneteskubectl, helm, kustomizek9s
cloud-awsaws-cli
cloud-gcpgcloud-cli
cloud-azureazure-cli
browser-testing@playwright/test, @axe-core/playwright, ChromiumFirefox, WebKit

Documentation Frameworks

AddonTools
docs-mkdocsmkdocs + mkdocs-material
docs-zensicalzensical
docs-docusaurusdocusaurus
docs-starlightstarlight
docs-mdbookmdbook
docs-hugohugo

AI Harnesses

AI harnesses are selected under [ai], not as public addon blocks. aibox still uses internal install recipes for container CLIs when install = true.

[ai]
harnesses = [
  { harness = "claude", enable = true, install = true },
  { harness = "codex", enable = true, install = true, version = "latest" },
]

Legacy [addons.ai-*.tools] entries are accepted for compatibility, but fresh scaffolding keeps AI configuration in the [ai] section.

Addons and Skills

As of v0.16.0, all skills live in processkit. Projects using context.mode = "processkit" install processkit skills under context/skills/ independently from addons. Projects using context.mode = "harness-only" do not install processkit skills at all. There is no longer an addon-driven “auto-deploy a skill” mechanism.

The relevant skills for each addon’s tooling are still in the catalogue — agents pick them up via skill descriptions, not via addon membership:

AddonNaturally relevant skills
pythonpython-best-practices, fastapi-patterns, pandas-polars
rustrust-conventions, concurrency-patterns
goconcurrency-patterns and the Go-flavoured patterns shipped upstream
nodetypescript-patterns, tailwind
latex / typstdocumentation
git-uigit-workflow
kubernetescontainer-orchestration
cloudflareCloudflare Tunnel workflows
infrastructureterraform-flavoured patterns shipped upstream

See Skills (via processkit) for the full split.

How Addons Work

When you run aibox apply, the CLI:

  1. Reads [addons] from aibox.toml
  2. Looks up each addon definition from YAML files in ~/.config/aibox/addons/
  3. Merges your tool selections with addon defaults
  4. Generates Dockerfile builder stages (for heavy builds like Rust, LaTeX)
  5. Generates runtime RUN/COPY commands
  6. Builds the container image

Addons that need compilation (Rust, LaTeX, infrastructure, Kubernetes) use multi-stage Docker builds – heavy compilation happens in isolated builder stages, and only the final binaries are copied into the runtime image.

Addon Definition Format

Addon definitions are YAML files stored in ~/.config/aibox/addons/ with category subdirectories (languages/, tools/, docs/, ai/). They are installed automatically by the install script and updated when you upgrade aibox.

Extra Packages

For one-off apt packages not covered by addons, use extra_packages:

[container]
extra_packages = ["universal-ctags", "graphviz", "postgresql-client"]

These are installed during aibox apply via the generated Dockerfile. They persist across container restarts but are reinstalled on image rebuild.

Version Selection

Each tool in an addon has a curated list of supported versions. Use aibox describe addon <name> to see available versions:

$ aibox describe addon python
Add-on: python
Recipe version: 1.0.0

  TOOL      DEFAULT    VERSION  SUPPORTED
  python        yes       3.14  3.12, 3.13, 3.14
  uv            yes    0.12.5  0.7, 0.11.10, 0.11.11, 0.11.15, 0.11.19, 0.11.26, 0.12.0, 0.12.5
  poetry         no      2.4.1  1.8, 2.0, 2.4.1
  pdm            no     2.28.1  2.22, 2.26.9, 2.27.0, 2.28.0, 2.28.1

Tools marked “DEFAULT: yes” are included automatically when you set the addon. Tools marked “no” must be explicitly listed in your aibox.toml to be installed.

2 - Language Runtimes

Language Runtime Addons

Language runtimes install compilers, interpreters, and package managers into your container.

Python

[addons.python.tools]
python = { version = "3.14" }   # 3.12, 3.13, 3.14
uv = { version = "0.12.5" }    # 0.7, 0.11.10, 0.11.11, 0.11.15, 0.11.19, 0.11.26, 0.12.0, 0.12.5
# poetry = { version = "2.4.1" } # Optional: 1.8, 2.0, 2.4.1
# pdm = { version = "2.28.1" }   # Optional: 2.22, 2.26.9, 2.27.0, 2.28.0, 2.28.1

Installs Python, pip, venv, and uv (fast package manager). The base image pins uv to the curated default instead of following a floating latest image tag. Poetry and PDM are available but not enabled by default.

Rust

[addons.rust.tools]
rustc = { version = "1.97.1" }  # 1.90, 1.91, 1.92, 1.93, 1.94, 1.94.1, 1.96.0, 1.96.1, 1.97.1
clippy = {}                     # Linter (no version selection)
rustfmt = {}                    # Formatter (no version selection)

Installs the Rust toolchain via rustup with clippy and rustfmt. Uses a multi-stage Docker build — compilation happens in a builder stage and only the toolchain is copied to the runtime image.

Node.js

[addons.node.tools]
node = { version = "26" }       # 20, 22, 24, 26
pnpm = { version = "11.22.0" }  # 9, 10, 11.1.3, 11.5.2, 11.10.0, 11.18.0, 11.20.0, 11.21.0, 11.22.0
# yarn = { version = "4.17.0" } # Optional: 4, 4.16.0, 4.17.0
# bun = { version = "1.3.14" }  # Optional

Installs Node.js via NodeSource, plus pnpm as default package manager. Yarn and Bun are available but not enabled by default.

Go

[addons.go.tools]
go = { version = "1.26.6" }     # 1.25, 1.26, 1.26.3, 1.26.4, 1.26.5, 1.26.6

Installs Go and sets up GOPATH.

Production Go groups

Go projects can compose production tooling without bloating the base runtime:

[addons.go]

[addons.go.infrastructure]

[addons.go.quality.tools]
staticcheck = { enabled = false } # optional per-tool override

[addons.go.supply-chain]

[addons.go.release]

# Optional nested container engine without the other infrastructure defaults:
[addons.go.infrastructure.tools]
opentofu = { enabled = false }
ansible = { enabled = false }
packer = { enabled = false }
podman = {}

quality installs goimports, staticcheck, golangci-lint, govulncheck, and gosec, plus the Linux compiler and libc headers required by go test -race ./.... supply-chain adds gitleaks, osv-scanner, syft, grype, and cosign. release adds GoReleaser, ShellCheck, and Hadolint. The built-in gofmt, go vet, go test, fuzzing, and coverage commands remain part of the Go toolchain and need no extra binary. The optional podman selection installs a rootless container engine and its Compose provider. The explicit disables keep OpenTofu, Ansible, and Packer out when the project only needs nested container operations.

The same infrastructure, security/supply-chain, and release group names are accepted below every language addon. Go additionally exposes quality and its lint alias.

Typst

[addons.typst.tools]
typst = { version = "0.15.0" }  # 0.13.1, 0.14.2, 0.15.0

Installs the Typst typesetting system for modern document creation.

LaTeX

[addons.latex.tools]
texlive-core = {}               # Base TeX Live installation
texlive-recommended = {}        # Common packages
texlive-fonts = {}              # Font packages
biber = {}                      # Bibliography processor
texlive-code = {}               # Code listing packages
texlive-diagrams = {}           # TikZ, PGF, circuit diagrams
texlive-math = {}               # Math packages
# texlive-music = {}            # Optional: LilyPond, MusiXTeX
# texlive-chemistry = {}        # Optional: chemfig, mhchem

Installs TeX Live via a multi-stage Docker build. The full TeX Live installation happens in a builder stage and only the final tree is copied to the runtime image, keeping layer sizes manageable.

Use the LaTeX build and preview workflow to define named documents, run reproducible latexmk builds and watchers inside the development container, and serve completed PDFs through the read-only EmbedPDF sidecar.

Emoji rendering with LuaLaTeX

The runtime image ships fonts-noto-color-emoji so emoji glyphs render correctly in LuaLaTeX documents. To wire it up, add the following to your preamble:

\directlua{luaotfload.add_fallback("emojifallback",{"NotoColorEmoji:mode=harf;"})}
\setmainfont{FreeSans}[Scale=0.95,RawFeature={fallback=emojifallback}]

Without the fallback configured, emoji characters render as missing-glyph boxes even though the font is installed.

3 - Tool Bundles

Tool Bundle Addons

Tool bundles install infrastructure, orchestration, and cloud CLI tools.

Supply Chain

[addons.supply-chain.tools]
gitleaks = {}
osv-scanner = {}
syft = {}
grype = {}
cosign = {}

This language-neutral bundle covers secret scanning, dependency and artifact vulnerability checks, SBOM generation, and Sigstore signing. Release archives are pinned and checked against upstream-published checksums.

Release Validation

[addons.release.tools]
shellcheck = {}
hadolint = {}

The language-neutral release bundle validates shell scripts and Dockerfiles. Go projects should normally select [addons.go.release], which composes this bundle with the go-release recipe and GoReleaser.

Git UI

[addons.git-ui.tools]
gh = {}        # GitHub CLI
lazygit = {}   # Interactive Git TUI

The git-ui addon is optional. Select it when a project needs GitHub CLI automation or lazygit inside the container; omit it to avoid installing those tools. This aibox repo may enable it for maintenance workflows such as release checks and GitHub issue/release work, but downstream projects do not need it by default.

Browser Visual Testing

The browser-testing addon provides a pinned Node-based Playwright Test stack (@playwright/test plus @axe-core/playwright) for headless browser checks. Playwright-managed full Chromium is enabled by default; Firefox and WebKit are opt-in so a project can keep its image smaller when cross-engine coverage is not required.

[addons.browser-testing.tools]
# Playwright Test and @axe-core/playwright are enabled by default.
# Optional cross-engine coverage:
firefox = { enabled = true }
webkit = { enabled = true }

The v0.x catalog currently couples Playwright 1.62.1 with @axe-core/playwright 4.13.0 and the matching browser revisions. The addon provides that pinned runner/browser environment; keep the derived project’s package.json and lockfile authoritative, and install the packages locally when the project’s package manager does not resolve the environment’s global packages. After applying the configuration, a derived project can keep its tests and baselines beside the application, for example:

// playwright.config.ts
import { defineConfig, devices } from "@playwright/test";

export default defineConfig({
  testDir: "./tests/browser",
  use: {
    baseURL: "http://127.0.0.1:4173",
    ...devices["Desktop Chrome"],
    colorScheme: "light",
    reducedMotion: "reduce",
  },
  projects: [{ name: "chromium", use: { ...devices["Desktop Chrome"] } }],
});
// tests/browser/home.spec.ts
import { test, expect } from "@playwright/test";
import AxeBuilder from "@axe-core/playwright";

test("home page is keyboard reachable and accessible", async ({ page }) => {
  await page.goto("/");
  await expect(page.getByRole("main")).toBeVisible();
  await page.keyboard.press("Tab");
  const results = await new AxeBuilder({ page }).analyze();
  expect(results.violations).toEqual([]);
});

The example is only a starting point. The derived project owns the responsive viewport set, focus and keyboard flows, light/dark themes, reduced-motion behavior, accessibility assertions, and screenshot-baseline matrix. aibox tests validate the addon installation, generated contract, browser launch, and a minimal fixture; they do not prescribe an application’s visual matrix.

Preview and Archive Tools

[addons.preview-archive.tools]
chafa = {}
timg = {}
poppler = {}
mupdf = {}
entr = {}
p7zip = {}
resvg = {}

preview-archive contains the terminal image/PDF/SVG/archive helper binaries used by Yazi previews and watch-mode document workflows. Keep it disabled for lean headless projects that do not inspect media or generated documents inside the terminal.

preview-enhanced layers Markdown, EPS, video, and Ghostscript support on top of preview-archive.

Data Preview

[addons.data-preview.tools]
sqlite3 = {}
csvkit = {}

data-preview adds read-only SQLite inspection and CSV, TSV, XLS, and XLSX formatting for the generated Yazi preview plugins.

Audio and Voice

[audio]
enabled = true

Audio bridging uses the internal audio-voice recipe for Sox, PulseAudio client tools, and ALSA PulseAudio plugins. aibox selects this recipe automatically when [audio] enabled = true and install = true; projects normally do not need to add [addons.audio-voice.tools] manually.

Infrastructure

[addons.infrastructure.tools]
opentofu = {}      # Infrastructure-as-code (Terraform alternative)
ansible = {}       # Configuration management
packer = {}        # Machine image builder
podman = {}        # Optional rootless container engine + Compose

OpenTofu defaults to 1.12.5, Packer to 1.16.0, and Ansible to 14.3.1. OpenTofu and Packer are installed in a multi-stage builder. Ansible is installed via pip. Podman is optional and installs the Debian-packaged rootless engine, Compose provider, user-namespace helpers, and overlay/networking prerequisites. Nested containers still depend on the outer runtime allowing user namespaces; FUSE overlay is used when /dev/fuse is available, with Podman’s normal fallback otherwise.

Kubernetes

[addons.kubernetes.tools]
kubectl = {}       # Kubernetes CLI
helm = {}          # Package manager
kustomize = {}     # Configuration customization
# k9s = {}         # Optional: terminal UI for Kubernetes

kubectl defaults to 1.36.3, Helm to 4.2.4, Kustomize to 5.8.1, and k9s to 0.51.0. All tools are downloaded as static binaries in a multi-stage builder.

Cloud Providers

AWS

[addons.cloud-aws.tools]
aws-cli = {}

Installs the AWS CLI v2.

Google Cloud

[addons.cloud-gcp.tools]
gcloud-cli = {}

Installs the Google Cloud CLI via the official APT repository.

Azure

[addons.cloud-azure.tools]
azure-cli = {}

Installs the Azure CLI via pip.

4 - Documentation Frameworks

Documentation Framework Addons

Documentation addons install static site generators and documentation tools.

AddonToolInstall Method
docs-mkdocsMkDocs + Material themeuv
docs-zensicalZensicaluv
docs-docusaurusDocusaurusnpm
docs-starlightStarlight (Astro)npm
docs-mdbookmdBookBinary download
docs-hugoHugo ExtendedBinary download

Current curated pins are Docusaurus 3.10.1, Hugo 0.165.0, mdBook 0.5.4, MkDocs 1.6.1 with Material 9.7.7, and Zensical 0.0.55. Starlight remains scaffolded through the upstream create-starlight package.

Example

[addons.docs-docusaurus.tools]
docusaurus = {}

After aibox apply, the documentation tool is available inside the container. Initialize your docs project as usual (e.g., npx create-docusaurus@latest docs classic).

5 - LaTeX Build and Preview

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.