Getting Started¶
Prerequisites¶
Install the following tools on your host machine before running:
-
uv: Manages the Python environment and dependencies for the host-side build/run scripts.
- On macOS:
brew install uv - Other platforms:
curl -LsSf https://astral.sh/uv/install.sh | sh build.shandrun.shinvokeuv run. Theuv runcommand creates.venvand installs the declared dependencies (including thehfCLI andhuggingface_hub) automatically on first use. You do not need a manualpip install.
- On macOS:
-
podman: the only supported container runtime.
- On macOS:
brew install podman, thenpodman machine init --memory 4096andpodman machine start - On Linux (Debian/Ubuntu):
sudo apt install podman, or your distro's package manager
- On macOS:
The podman machine needs at least 4 GB of memory (macOS/Windows, where podman
runs in a VM). The default is 2 GiB, which is not enough. build.sh compiles CPython,
podman and netavark from source, and one CPython PGO job peaks near 900 MiB. With
2 GiB total, the build is OOM-killed. More memory buys more parallel compile
jobs, since the caps are memory-derived rather than core-count-derived. On an existing
machine:
build.sh checks this before it starts building and tells you if there is not
enough room, so a short machine fails in a second rather than several minutes in.
Docker is not supported. pa-container's isolation model (and nested containers in particular) depends on the agent container running inside a user namespace where container uid 0 maps to an unprivileged host user. Stock Docker does not provide this. See Configuration.
- llama.cpp: Specifically
llama-server.- Build with pa-container (recommended):
./build.sh --llama(or./build.sh --llama-latestto build latest release) - On macOS:
brew install llama.cpp - On Linux (Debian/Ubuntu):
sudo apt install llama.cpp - On Linux (other): build from source
- On WSL2:
sudo apt install llama.cpp
- Build with pa-container (recommended):
You declare Python dependencies (huggingface_hub[cli], pyyaml) in
pyproject.toml. uv installs them. You do not install them manually.
Hardware Requirements¶
Use the following hardware to run this environment comfortably, especially with the full 128k context window:
- Processor:
- Apple Silicon (M2-series Max/Ultra or above) for high memory bandwidth.
- On Linux/WSL2: A modern multi-core CPU with AVX2 support.
- Memory (RAM):
- Minimum: 32 GB (Performance may degrade with large contexts).
- Recommended: 64 GB or more (For optimal performance).
- podman machine (macOS/Windows):
- Required: 4 GB (
podman machine set --memory 4096). The 2 GiB default cannot build the toolchain image. - Recommended: 8 GB, and more again if you enable nested containers.
- Required: 4 GB (
- Storage: 50 GB of available SSD space.
Platform-Specific Notes¶
Linux / WSL2¶
- Container runtime: podman (auto-detected).
- Network: The default bridge interface is
podman0and the proxy upstream network defaults topodman. Override viaBRIDGE_INTERFACEandPROXY_UPSTREAM_NETWORKin~/.config/pa-container/config.yamlor environment variables if needed. - LLaMA backend: The
llama-serverbinary runs natively on Linux/WSL2. For GPU acceleration on Linux, build llama.cpp with CUDA or ROCm support. - WSL2: Ensure WSL2 is properly configured with a Linux distro. podman runs inside it.
macOS¶
- Container runtime: podman.
- Network: The defaults apply automatically. You need
BRIDGE_INTERFACEandPROXY_UPSTREAM_NETWORKonly to override them. - LLaMA backend: Runs natively using Apple's Metal GPU acceleration.
- podman on macOS: containers run inside a Linux VM (no
podman0bridge exists on the host). The system does not usesocat. The proxy reaches hostllama-serverviahost.containers.internal(gvproxy). The isolated network is created--internal --disable-dns. The proxy's interfaces are pinned (interface_name=eth0/interface_name=eth1) so the isolated network is deterministicallyeth1. Seesrc/runtimes.py. - Machine sizing: 4 GB is the minimum (
podman machine set --memory 4096). The 2 GiB default cannot build the toolchain image.resources.agent.memorydefaults to16g, which the VM can never actually provide. Raise the machine further before enabling nested containers. Do this especially beforestorage: tmpfs.
Build and Run¶
1. Configure Environment¶
pa-container automatically seeds its global configuration at ~/.config/pa-container/config.yaml on first launch.
Set ADMIN_PASSWORD in your OS keyring before running — the proxy's mitmweb UI requires a password:
Optionally, build an optimized minimal llama-server binary for your host hardware:
See Configuration for the full list of configuration options.
2. Build the Container Images¶
build.sh (and run.sh) run through uv. uv creates the .venv and installs dependencies from uv.lock on first invocation. You do not need a separate setup step. Run uv sync to provision the environment ahead of time.
This builds three images, in this order:
-
pa-container-agent-builder:local— the toolchain image. Compiles CPython 3.14 (PGO), podman and netavark/aardvark-dns from source, and stages Node from the official nodejs.org tarball. A few minutes on a 9-core/8 GB machine.NODE_SOURCE=build ./build.shcompiles Node from source instead, which takes about an hour (measured: ~65 min at 3 compile jobs). It buys a trixie-native build rather than the generic-glibc official one. Node has no build tags worth choosing, so unlike podman there is no correctness argument for it. The defaultprebuiltmode stages byte-for-byte the same Node the oldnode:base image shipped, since that image is this same tarball extracted into/usr/local.Compile parallelism is capped by available memory rather than core count, so a bigger machine directly shortens this step (
MAKE_JOBS=<n>overrides the cap). Later builds skip the image entirely unless one of its pinned versions changes, and each component is a separate stage, so bumping podman does not rebuild Node.Every version, git commit and SHA-256 it builds from is an
ARGincoding-agent-builder/Containerfile. That one file is where you bump a component. 2.pa-container-agent-proxy:local— the transparent proxy, which copies its CPython anduvout of the builder image so that it runs the same Python as the agent. 3.pa-container-agent:local— the main agent, which copies the mitmproxy CA certificate out of the proxy image and its whole toolchain out of the builder image.
The order is not optional: the proxy image COPY --froms the builder, and the agent image COPY --froms both of the others.
3. Run the Agent¶
The run.sh script manages the entire lifecycle. The script validates the environment, starts llama-server instances for each local model allowed in models.yaml, sets up the proxy container with its transparent proxy rules, and launches the agent container.
# Recommended: alias for convenience
alias pa="~/workspace/pa-container/run.sh"
# Run with an optional session ID
pi --session 1234abcd-ef56-78ab-cd90-1234abcd56ef
The script reads <project>/.pa-container/models.yaml (seeded from the coding-agent/default/project/ template on first run) to determine which LLM providers and gateways are allowed. Global definitions under ~/.config/pa-container/models/ and ~/.config/pa-container/gateways/ supply model weights, server flags, and gateway endpoints. Each workspace gets its own proxy container and isolated network (named by a hash of the project path). Concurrent invocations from the same workspace share that workspace's proxy via a refcount.
4. Using the Agent¶
Once the server is ready, you can interact with the agent through the terminal. The current directory is mounted to /workspace inside the container, allowing the agent to read and write files in your project.
The agent's entrypoint runs project-specific setup scripts (baked into the image at build time), points the container's default route and DNS at the proxy, and applies the host's git config. Reaching the host llama-server is handled by the proxy (via host.containers.internal on macOS or directly on Linux). See Architecture and Dependency definition files.
5. Using the Proxy¶
The transparent proxy web UI (mitmweb) is published on an auto-assigned host port — run.py logs the exact http://127.0.0.1:<port> URL at startup (each workspace's proxy gets its own port). See Proxy overview for details on proxy operation, CA certificate installation, and addons.