Files
ai-sandbox/config/config.example
T
ducoterra 8ee535f6ae bridge the host pi config, with the credential by env only
The image ships pi with no provider and no preferences, so a sandboxed run
meant configuring the model twice. ai-sandbox now reads the host
~/.pi/agent/{models,settings}.json and rewrites them instead of copying them:
every provider apiKey becomes "$AI_API_TOKEN" (pi resolves an env reference
itself, so no value is written to disk), '!command' header values are dropped
rather than executed, settings that point into $HOME are dropped because that
path is not mounted, and auth.json / models-store.json / sessions / extensions
are never read.

The rewritten pair is seeded into /home/sandbox/.pi/agent at container start,
owned by uid 1000 and mode 600, and is treated as managed: a host change is
re-seeded, an edit made inside the sandbox is kept and reported, a deletion
takes the host version again.

The token follows the existing environment rules -- one variable, passed by
name through the 0600 env file, announced when auto-passed. A bridged run
whose token variable is unset or empty is refused instead of starting a pi
that cannot reach its model, and the bridge never widens the allowlist: it
warns with the exact --allow to add.

Docs and examples now use a self-hosted gateway (https://aipi.reeseapps.com)
instead of vendor API endpoints, since that is the only thing this tool is
used against. 391 assertions pass (make lint, ./tests/run.sh --e2e).

LLM-Generated: true
2026-10-27 17:29:17 -04:00

96 lines
3.6 KiB
Plaintext

# config for ai-sandbox -- copy to ~/.config/ai-sandbox/config and edit
#
# Format: key = value. '#' starts a comment.
# Precedence: built-in default < this file (user) < ./.ai-sandbox/config (repo)
# < AISB_* environment variable < command line flag.
#
# Keys listed under "repeatable" accumulate; every other key replaces.
# --- network ---------------------------------------------------------------
# none | allow | full. allow is the safe default and requires an allowlist.
net = allow
# Address that stands for the host's loopback inside the container
# (--network=pasta:--map-host-loopback,<addr>). Change only if it collides
# with a real network you need to reach.
# gate_addr = 100.64.0.1
# Preferred first port for the per-session egress gate; the next free port is
# used if it is busy.
# gate_port = 18081
# --- harness ---------------------------------------------------------------
# Default in-container command: pi | codex | claude | none | "<your command>"
# harness = pi
# --- mounts and layout -----------------------------------------------------
# workdir = /project
# --- limits ----------------------------------------------------------------
# cpus = 4
# memory = 4g
# pids = 512
# tmpfs_size = 1g
# --- image -----------------------------------------------------------------
# One base for both images (the gate is squid from this distro's apt, not a
# third-party image). base_image may itself be pinned: name@sha256:...
# base_image = docker.io/library/ubuntu:24.04
# node_version = 22.23.4
# pi_version = 1.4.0
#
# The tag is resolved to a registry digest and that digest becomes part of the
# image tag, so builds are reproducible and a base patch is visible instead of
# quietly folding into an existing image. Every base_ttl_days the digest is
# re-resolved -- a manifest read, not a download. 0 re-resolves on every build,
# -1 never does.
# base_ttl_days = 7
#
# 0 keeps the recorded digest even past its TTL: nothing reaches the registry
# unless you say so. An explicit refresh is `ai-sandbox update [--check]`.
# base_auto_update = 1
# --- pi --------------------------------------------------------------------
# Bridge ~/.pi/agent/{models,settings}.json into the sandbox, with every provider
# apiKey replaced by an environment reference (nothing secret is written into the
# container). 0 = pi starts with its own defaults.
# pi_config = 1
#
# The variable the bridged config reads the credential from, and whether ai-sandbox
# passes that one variable automatically when it is set. If it reaches neither, the
# run is refused instead of launching a pi that cannot talk to its model.
# pi_token_env = AI_API_TOKEN
# pi_token_auto = 1
#
# Where to read the host config from (default ~/.pi/agent).
# pi_agent_dir = ~/.pi/agent
# --- behaviour -------------------------------------------------------------
# SELinux bind-mount option: ':z' (shared), ':Z' (private) or empty to disable.
# Defaults to ':z' when getenforce exists.
# selinux = :z
# Persist /home/sandbox in a named volume so harness logins and tool caches
# survive between runs. 0 = use a throwaway tmpfs instead.
# home_cache = 1
# Appended verbatim to the podman invocation (power users; word-split).
# extra_args = --annotation io.k8s.description="agent sandbox"
# --- repeatable keys -------------------------------------------------------
# These may appear more than once, and are merged with --allow / --env / etc.
#
# allow = aipi.reeseapps.com
# allow = registry.npmjs.org:443
# allow = 10.20.0.5:5432
#
# env = AI_API_TOKEN
# env = CI_JOB_TOKEN
#
# mount = ~/.ssh:ro
# mount = ../docs:/docs:ro
#
# install = postgresql-client
#
# label = team=platform