Installing system packages with packages.apt
Pai supports installing Debian/Ubuntu system packages at session startup via packages.apt on an Agent. This covers CLI tools (ffmpeg, poppler-utils, git) and shared libraries that cannot be installed with pip or npm.
How it works
When packages.apt is non-empty, the controller injects a dedicated pai-apt-install init container that runs before the harness starts:
apt-get updaterefreshes the package indexapt-get downloadfetches the requested.debarchivesdpkg-deb --extractunpacks each archive into/opt/pai-packages/apt/- The harness container inherits
/opt/pai-packages/apt/usr/binand/opt/pai-packages/apt/usr/sbinonPATH, and/opt/pai-packages/apt/usr/libonLD_LIBRARY_PATH
The init container runs as root (uid 0). The agent container itself continues to run as non-root (uid 65532) — the root exception is isolated to this platform-controlled init step.
Usage
apiVersion: pai.io/v1
kind: Agent
metadata:
name: pdf-processor
spec:
models:
- anthropic/claude-sonnet-4-6
packages:
apt:
- poppler-utils # provides pdftotext, pdfinfo
- imagemagick # provides convert
pip:
- pypdf
tools:
- type: bash
- type: read
- type: write
system: |
You are a PDF processing agent. Use pdftotext to extract text and
pypdf for structured data. Save results to /workspace/output/.
Once installed, packages are available in bash tool commands:
pdftotext input.pdf - # extract all text to stdout
pdfinfo input.pdf # metadata: page count, dimensions, author
convert input.pdf[0] page1.png # rasterize first page (imagemagick)
Combining with other package managers
packages.apt works alongside all other package managers. The apt init container runs first, so system libraries are available when pip/npm/go packages are built:
packages:
apt:
- libpq-dev # PostgreSQL headers (needed to build psycopg2)
- ffmpeg # video processing CLI
pip:
- psycopg2 # needs libpq-dev at build time
- moviepy
Limitations
The dpkg-deb --extract approach covers the majority of use cases but has some constraints:
| Works well | Requires custom image |
|---|---|
CLI tools (ffmpeg, git, curl) | Packages that register system services |
Shared libraries (libpq, libssl) | Packages requiring ldconfig cache updates |
Language runtimes (ruby, php) | Kernel modules or device drivers |
| Font packages | Packages with postinst scripts that need a live system |
For packages that fall into the "requires custom image" column, build a custom harness image:
FROM pai-harness:latest
USER root
RUN apt-get update && apt-get install -y --no-install-recommends \
your-complex-package && \
ldconfig && \
rm -rf /var/lib/apt/lists/*
USER 65532
Then set PAI_HARNESS_IMAGE=your-registry/pai-harness-custom:latest on the controller.
Security note
The pai-apt-install init container is the only container in an agent pod that runs as root. It has no access to the agent's credentials or network connections — it only writes to the shared /opt/pai-packages emptyDir volume. The agent container itself is always non-root.