The base image is the foundation for all aibox container flavors. It provides a complete, opinionated development environment built on Debian Trixie Slim.
Network route/interface inspection for status segments
iputils-ping
Debian package
ICMP latency checks for status segments
bash-completion
Debian package
Shell completions
ca-certificates
Debian package
TLS root certificates
locales
Debian package
Locale support (en_US.UTF-8)
tzdata
Debian package
Timezone data
GitHub CLI (gh) and lazygit are provided by the optional
git-ui addon, not by the base image. Add
[addons.git-ui.tools] to aibox.toml when a project needs those tools.
Audio tools are provided by the internal audio-voice recipe, which is selected
automatically when [audio] enabled = true and install = true. File-preview and archive helpers
such as chafa, timg, poppler-utils, mupdf-tools, entr, and
resvg are provided by the optional preview-archive addon.
The Dockerfile keeps the runtime stage on Debian Trixie Slim and installs tmux
from the distro package set. That keeps the terminal multiplexer on the same
security update path as the rest of the base image and avoids a separate
prebuilt-binary fetch stage.
aibox-managed tmux plugins are preinstalled and pinned by the generated runtime
and image build. TPM is documented only as a user convenience layer for adding
personal tmux plugins after initialization; aibox does not rely on TPM to
install or update managed plugins.
tmux-resurrect and tmux-continuum are installed and available in the image,
but disabled by default until the workspace persistence policy is decided. Users
can opt into them in local tmux config, but generated layouts should not assume
session resurrection is active.
All bindings use Ctrl+g as a leader key — press Ctrl+g, release, then press the action key. This avoids conflicts with macOS Option key (which produces special characters like @, €, |) and with Vim/bash Ctrl bindings.
Key
Action
Ctrl+g then h/j/k/l
Navigate panes (vim-style)
Ctrl+g then n
New pane
Ctrl+g then d
Split down
Ctrl+g then r
Split right
Ctrl+g then x
Close focused pane
Ctrl+g then f
Toggle fullscreen
Ctrl+g then z
Toggle pane frames
Ctrl+g then e
Toggle embed/floating
Ctrl+g then = / -
Resize pane (increase / decrease)
Ctrl+g then t
New window
Ctrl+g then w
Close window
Ctrl+g then [ / ]
Previous / next window
Ctrl+g then 1-5
Jump to window N
Ctrl+g then i / o
Move window left / right
Ctrl+g then s
Session chooser
Ctrl+g then m
Session manager
Ctrl+g then u
Enter scroll mode
Ctrl+g then /
Search scrollback
Ctrl+q
Quit tmux
Press Escape or Ctrl+g again to cancel the leader and return to normal mode.
aibox ships four tmux layouts. Select one with aibox up --layout <name> (the default is dev). Layouts include harness windows based on the enabled entries in [ai].harnesses and [ai].harness_order; they include the lazygit window only when the git-ui addon selects lazygit.
Window work has Yazi and the 1st harness stacked on the left, with shell on the right. Further harnesses use the ai window; lazygit and shell get their own windows.
Window work has Yazi on the left and shell on the right. The ai window contains all harnesses split evenly across full-height panes; the lazygit window is generated when enabled.
Enter – opens file in vim in-place (suspends Yazi, :q returns to Yazi). Works in all layouts.
e – opens file in a full-screen vim popup and returns to Yazi when vim exits.
tmux vs Yazi
Ctrl+g then s opens the tmux session chooser. The sidebar file manager in
all layouts is Yazi, an external terminal file manager with richer features
(preview, bulk operations, async I/O).
Git config lives at /home/aibox/.config/git/config (XDG path, not ~/.gitconfig). The environment variable GIT_CONFIG_GLOBAL is set in the generated docker-compose.yml to point to this location.
Using a directory mount (rather than a single-file mount) allows a credentials file to coexist alongside config.
AI coding agents (Claude, Codex, Aider, Gemini, and others) are not
pre-installed in the base image. They are installed per-project when you select
them in the ordered [ai].harnesses list, for example
{ harness = "claude", enable = true, install = true }.
Set [audio] enabled = true to enable audio bridging. aibox then selects the
internal audio-voice recipe and configures the PulseAudio environment for the
container. See Audio Support for setup details.
All user configuration is persisted on the host under .aibox-home/ and bind-mounted into the container:
Host Path
Container Path
Contents
.aibox-home/.ssh/
/home/aibox/.ssh (read-only)
SSH keys
.aibox-home/.vim/
/home/aibox/.vim
Vim config and undo history
.aibox-home/.config/
/home/aibox/.config
Git, tmux, Yazi, prompt, and tool config
.aibox-home/.cache/
/home/aibox/.cache
Runtime caches
.aibox-home/.local/
/home/aibox/.local
Helper scripts, state, and local data
.aibox-home/.tmux/
/home/aibox/.tmux
tmux plugin and socket state
The Dockerfile bakes identical defaults into the image as a fallback. If no mounts are present, the container still works out of the box.
On first aibox init or aibox up, the .aibox-home/ directory is auto-seeded
from built-in templates. User-owned files are retained. Files explicitly
managed by aibox may be refreshed on aibox apply when their upstream template
changes.
Tool credentials saved below /home/aibox/.config, including a GitHub CLI
login stored in /home/aibox/.config/gh, therefore survive container
replacement and image rebuilds. They remain local secret-bearing files rather
than encrypted storage. See GitHub authentication
for the security tradeoffs and the recommended scoped-PAT alternative.
The base image ships the Yazi configuration and preview plugins. Install the
optional preview-archive addon for raster/SVG/PDF/archive helper binaries and
preview-enhanced for Markdown, EPS, video, and Ghostscript
support. PDF and SVG also support watch-mode preview when the required
preview tools are selected.
See the dedicated File Preview page for full documentation, including format coverage, standalone tools (chafa, timg), and the PDF/SVG watch-mode patterns.
aibox uses a small verb/resource grammar. aibox.toml is desired state, aibox apply reconciles generated files and images, and aibox up enters the workspace.
Usage profile: human-dev or warning-mode headless-runner
--context-mode <MODE>
processkit
Context layer: processkit or harness-only
--harness <NAME>
claude
AI harness, repeatable
--addon <NAME>
–
Addon name, repeatable
--theme <THEME>
gruvbox
Runtime UI theme family
--processkit-version <TAG>
latest prompt/default
Pin processkit
--include-prerelease
off
Include processkit prereleases when init selects a version; explicit prerelease pins always work
The hidden legacy --context <PKG> option is still accepted as a processkit
package selector for compatibility. New configs use [context].mode and,
when processkit is enabled, [context].packages.
--context-mode harness-only creates a container-and-harness project with no
processkit install, no processkit MCP gateway, no processkit hooks/preauth, no
processkit command adapters, and no processkit Migration entities.
Force a full image rebuild without using cached layers
--rebuild
Visible alias for --no-cache
--config-only
Regenerate files without building the image
--standardize-config
Rewrite aibox.toml through the current canonical grouped template after compatibility migrations. Recognized schema fields are preserved; unknown keys block the rewrite.
--fix-compliance-contract
Rewrite the processkit compliance block in AGENTS.md
--no-container
Skip runtime probing and image build for CI/nested containers
aibox up
aibox up --layout focus
aibox up --apply
aibox down
aibox get runtime
aibox get runtime --resources
aibox get runtime --resources -o json
aibox describe runtime
aibox delete runtime
up starts or creates the workspace container and attaches through tmux. down stops the compose project. delete runtime removes the container while preserving project files and .aibox-home/.
get runtime reports the configured container name and detected state
(running, stopped, or missing). With --resources, it reports a
best-effort resource pressure snapshot from the current Linux runtime by
reading cgroupfs and procfs directly rather than shelling out to ps or
free.
aibox get runtime --resources includes:
Field
Source
Meaning
memory_current_bytes
/sys/fs/cgroup/memory.current
Current cgroup memory usage in bytes
memory_max
/sys/fs/cgroup/memory.max
Cgroup memory limit, or unlimited when the kernel reports max
oom_kill_count
/sys/fs/cgroup/memory.events
Cumulative oom_kill counter for the cgroup
total_process_count
numeric entries under /proc
Total visible process count
processkit_mcp_python_process_count
/proc/*/cmdline
Python processes whose command line looks like a processkit MCP server
The default table output is compact and human-readable. -o json and
-o yaml emit the same field names for automation; unavailable cgroup values
are null, while process counts fall back to 0 if /proc cannot be read.
get is compact and scriptable. describe is detailed and human-readable. All list/detail commands support -o, --format table|json|yaml; --output is accepted as a visible alias.
bash
aibox get addon
aibox describe addon python
aibox describe addon-catalog -o json
aibox describe image-provenance-policy -o json
aibox get runtime --resources -o json
aibox describe provider-backends -o json
aibox describe workspace-manifest -o json
aibox get skill
aibox get skill --all --category engineering
aibox describe skill model-recommender-route
aibox get process
aibox describe process release-semver
aibox get migration
aibox get env
aibox describe env
aibox get kit
These describe resources are stable enough for local automation. The
workspace manifest has been promoted to aibox.workspace-manifest.v0 because
processkit now recognizes Artifact{kind=workspace-manifest}; the other
environment-contract projections remain aibox.*.v0-preview until processkit
publishes more detailed canonical Artifact schemas.
set changes config. Use --apply when you want to reconcile immediately.
bash
aibox set theme.mode dark --apply
aibox set theme.name tokyo-night --apply --restart-session
aibox set addon python enabled
aibox set addon python disabled --apply
aibox set skill model-recommender-route enabled
aibox set skill pandas-polars disabled --apply
aibox set migration MIG-20260430_1200 in-progress
reset project is the practical aibox soft reset. It stops the runtime,
backs up aibox-managed project files, preserves auth/cache state from
.aibox-home/, removes the managed scaffold, and writes a reset recovery
migration briefing when user content is found in the backup. It also removes
aibox.toml, so it is not a one-command reinit. Recreate or restore
aibox.toml, run aibox init or aibox apply, then review
context/migrations/pending/ for the recovery advice.
reset context is plan-only in this release. It reports the processkit-owned
context paths that a hard reset would replace from a selected processkit
baseline and the project-owned context paths that must be preserved or reviewed.
Use normal migrations unless the owner explicitly approves a hard context reset.
Named LaTeX documents are configured under [[latex.documents]]. aibox apply
deploys the following managed scripts to .aibox-home/.local/bin; they are on
PATH inside the development container and are not host CLI commands.
bash
aibox-latex-build # build all configured documentsaibox-latex-build overview # build one configured documentaibox-latex-watch overview # continuous foreground build inside the container
Host-side aibox up starts the read-only Compose preview sidecar when preview is
enabled. It serves every configured PDF and shows a selection page at its root
when more than one exists. See LaTeX Build and Preview
for container workflow, remote forwarding, and security details.
The aibox context system controls what project-level instructions and
structured working memory are available to AI harnesses. It has two modes:
processkit, which installs the full structured context layer, and
harness-only, which keeps only the generated container and harness setup.
As of v0.16.0, the system is split across two cleanly separated projects:
aibox owns the container — devcontainers, addons, the CLI, the
install/apply/migrate machinery, and the project skeleton (aibox.lock,
.gitignore, provider pointer files, and, in harness-only mode, a minimal
AGENTS.md).
processkit owns the
content — every skill, every primitive schema, every state machine, the
canonical AGENTS.md template, the processes, and the package YAMLs that
compose them.
The user-side context/ directory is shared territory in processkit mode.
aibox creates it, processkit fills it, and the user edits in place. An
immutable upstream snapshot is kept under
context/templates/processkit/<version>/ for the three-way diff that
aibox apply uses to detect upstream changes versus local edits.
AI coding agents like Claude operate best when they understand not just the
code, but the project’s goals, decisions, and current state. Without structure,
this information ends up scattered across chat histories, stale comments, and
the developer’s memory.
A single root-level instructions file is not enough for non-trivial projects.
It works well for instructions and preferences, but it does not provide a
standard place for decisions, backlog, progress tracking, or team conventions.
With the default context.mode = "processkit" and a real
[processkit].version pinned, your project looks something like this after
aibox init and aibox apply:
AGENTS.md at the project root is the canonical agent entry document. It
is either rendered from the processkit template (context.mode = "processkit")
or generated as a minimal aibox-owned file (context.mode = "harness-only").
It is write-if-missing during aibox init; aibox does not overwrite local
edits. The agents.md ecosystem convention is to read
this file from any AI harness.
When Claude is enabled in [ai].harnesses, aibox also writes a thin
CLAUDE.md at the project root that points at AGENTS.md. In processkit mode,
command adapters are projected into enabled harness surfaces, including
.claude/skills/<name>/SKILL.md for Claude Code. Canonical skill content still
lives under context/skills/; provider-specific files are generated shims. In
harness-only mode, only the pointer is written.
OWNER.md captures the developer’s identity and preferences. It is created
during aibox init (or by the owner-profile skill the first time the agent
asks), with fields that help AI agents understand who they are working with:
Name — how the developer prefers to be addressed
Domain expertise — areas of knowledge and experience
Primary languages — programming languages used most often
Communication language — natural language for responses (e.g., English, German)
Timezone — for scheduling and availability context
Working hours — typical availability window
Current focus — what the developer is currently working on or learning
Communication preferences — style and conventions for AI interactions
Skills and processes are owned by processkit and are only installed when
context.mode = "processkit". For full documentation on what’s available, how
skills are organised, and which packages to use, see:
Skills — how skills install and how to browse them
aibox.toml declares the desired image and processkit versions. aibox.lock
records the CLI version and exact resolved processkit release, checksum, addon
selection, and managed runtime-home state last applied to the project.
When the schema evolves, aibox doctor flags version mismatches and aibox apply
runs the relevant migrations. See Migration for details.
The [context] section in aibox.toml selects the context mode. The
[processkit] section is used only in processkit mode and pins which version
of the content repository this project consumes:
Convention over configuration. File names and locations are standardised
so AI agents can find them without special instructions.
Human-readable first. Context files and root instructions are Markdown.
They are useful without any tooling.
Editable in place. Everything under context/skills/, context/processes/,
context/schemas/, and context/state-machines/ is yours to edit. The
immutable snapshot under context/templates/processkit/<version>/ exists only
as the base of aibox apply’s three-way diff.
No lock-in. Context files are plain Markdown and YAML in a context/
directory, and harness-only instructions are plain root-level Markdown. Stop
using aibox and the files remain useful.
Clean boundary between container and content. aibox owns the box;
processkit owns what goes in it. Each ships on its own cadence.
# macOSbrew install --cask docker
# Then launch Docker Desktop# Linux — follow the official install guide# https://docs.docker.com/engine/install/
aibox auto-detects which runtime is available. If both are installed, Podman takes priority.
OrbStack works through its Docker-compatible runtime and Compose integration.
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.
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.
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:
Looks up each addon definition from YAML files in ~/.config/aibox/addons/
Merges your tool selections with addon defaults
Generates Dockerfile builder stages (for heavy builds like Rust, LaTeX)
Generates runtime RUN/COPY commands
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 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.
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.
Overview
What aibox does, what it owns, and when to use it.
aibox creates reproducible, AI-ready development workspaces from one project
configuration file. It is not a new container runtime and it is not a process
framework. It is the glue that turns a declared project shape into a standard
devcontainer, selected tool bundles, AI harness configuration, and either a
processkit-backed context layer or a harness-only project skeleton.
aibox init my-app --harness claude --addon python
aibox apply
aibox up
aibox init writes the initial project contract. aibox apply reconciles that
contract into generated files and content. aibox up starts or attaches to the
workspace.
.aibox-home/ with tmux, shell, prompt, theme, and tool config
Addons
tool and runtime selection from addons/ YAML definitions
Harness wiring
provider entry files, MCP registration, permissions, and runtime tabs
Diagnostics
aibox doctor, aibox get runtime, migration and integrity checks
The generated files use common formats on purpose. You can inspect them, run
Docker or Podman commands against them, and use the same project in VS Code Dev
Containers when that is useful.
package definitions such as managed, software, research, and product
the canonical AGENTS.md template
aibox installs processkit content into context/, keeps an immutable upstream
snapshot under context/templates/processkit/<version>/, and uses that snapshot
for three-way diff and migration workflows. The content itself remains
processkit-owned. This is the default [context].mode = "processkit" path.
When [context].mode = "harness-only", aibox skips processkit entirely. It
still writes the container, runtime home, harness config, and minimal
AGENTS.md, but it does not install processkit skills, templates, hooks,
command adapters, Migration entities, or processkit MCP gateway config.
a reproducible terminal-first workspace for AI-assisted development
selected AI harnesses and tool bundles declared in one file
project context on disk instead of only in chat history
consistent tmux layouts, themes, shell tooling, and runtime diagnostics
a clean handoff path between different agents and human contributors
Do not use aibox as a general infrastructure deployer. It manages development
workspaces. Production deployment, remote host provisioning, and service
orchestration belong in dedicated infrastructure tooling.
Run aibox apply after changing desired state. It regenerates managed files,
updates the lock file, and builds the image unless you ask it not to. In
processkit mode it also refreshes processkit content; in harness-only mode it
only touches the container, runtime, harness, and minimal project surfaces.
Run aibox up to enter the workspace. It starts the Compose project and
attaches through tmux.
Run aibox doctor when the environment looks wrong. Run
aibox get runtime --resources when the workspace feels slow or agents exit
without a clean error.
[aibox]project_name="my-app"# Human-readable project nameprofile="human-dev"# Usage profile: human-dev or headless-runner[container]name="my-app"# Container namehostname="my-app"# Container hostnameuser="aibox"# Container user (default: aibox)[container.image]release_version="latest"# aibox image/CLI version, or "latest"base="debian"# Base image flavor[container.paths]devcontainer_json=".devcontainer/devcontainer.json"docker_compose=".devcontainer/docker-compose.yml"docker_compose_override=".devcontainer/docker-compose.override.yml"dockerfile=".devcontainer/Dockerfile"dockerfile_local=".devcontainer/Dockerfile.local"local_env=".aibox-local.env"[container.lifecycle]post_create_command="npm install"# Command to run after container creationkeepalive=false# Periodic DNS keepalive for idle network timeouts[container.resource_thresholds]memory_mib_warn=4096# Optional warning limit for cgroup memory usage in MiBprocess_count_warn=400# Optional warning limit for total live processes; 0 disablesprocesskit_mcp_python_warn=50# Optional warning limit for live Python MCP server processes; 0 disablesoom_kill_warn=0# Optional warning threshold for cgroup OOM kill count[container.environment]NODE_ENV="development"# Project-wide env vars (non-secret; use .aibox-local.toml for secrets)[[container.extra_volumes]]source="~/.aws"# Host path (~ expanded)target="/home/aibox/.aws"# Container pathread_only=true[context]mode="processkit"# processkit | harness-onlypackages=["product"]# processkit package selection[processkit]source="https://github.com/projectious-work/processkit.git"version="latest"# newest stable release, "unset", or a real tag (including an explicit prerelease)src_path="src"# branch = "main" # Optional; tarball-first, branch as fallback# release_asset_url_template = "..." # Optional, for non-GitHub hosts[processkit.context]schema_version="1.0.0"# Context schema version (semver)[addons.python.tools]# Addon: Python runtimepython={version="3.14"}uv={version="0.12.5"}[addons.rust.tools]# Addon: Rust toolchainrustc={version="1.97.1"}clippy={}rustfmt={}[addons.git-ui.tools]# Optional: GitHub CLI and lazygitgh={}lazygit={}[integrations.github]credential_helper="auto"# auto | gh | none[ai]model_providers=["anthropic"]# Optional provider env hints (API key + base URL)harnesses=[# Harness order is list order{harness="codex",enable=true,install=true},# { harness = "claude", enable = true, install = true },][ai.agents]canonical="AGENTS.md"provider_mode="pointer"# pointer | full[ai.mcp]# Team-shared MCP servers merged into all generated MCP client configs# (see also [[mcp.servers]] in .aibox-local.toml for personal servers)[[ai.mcp.servers]]name="my-team-tool"# Unique server namecommand="npx"# Executable to runargs=["-y","@acme/team-server"]# Arguments# [ai.mcp.servers.env] # Optional environment variables# API_KEY = "..."[customization]theme="ayu"# Theme family; concrete legacy names still parsemode="auto"# Theme mode: auto, light, darkvariant="mirage"# Optional family-specific variantemphasis="auto"# auto, full, standard, minimal, noneprompt="default"# Starship preset (8 options)layout="dev"# tmux layout (4 options)[customization.emphasis_overrides]code_comment="italic dim"# Optional semantic role overridestatus_error="bold underline"[customization.tmux.status]mode="extended"# extended | plain | disabled (legacy: powerline -> extended)[customization.tmux.title]# The terminal tab title is owned by tmux while inside tmux.enabled=trueformat="{state_symbol}{project}:{window} — {directory}"max-length=60directory-style="basename"# basename | abbreviated | fulldone-ttl-seconds=10message-max-length=32[customization.tmux.title.states]working="● "question="❓ "done="✓ "error="! "idle=""[customization.tmux.notifications]enabled=falseprotocol="osc-9"# osc-9 | bellstates=["question","error"]include-message=true[customization.tmux.status.layout]# Row lists are ordered. Removing a name disables that status element.# Allowed line1-left entries:# - session: current tmux session name and prefix/copy-mode state# - windows: tmux window list## Allowed line1-right / line2-left / line2-right entries:# - aibox_log: aibox log health counts# - aibox_oom: cgroup OOM kill counters# - aibox_proc: live process count versus configured process warning limit# - aibox_ai: detected AI-agent/runtime process count# - aibox_mcp: processkit/MCP daemon and server process status (processkit mode)# - aibox_mig: pending processkit migration count (processkit mode)# - weather: weather segment from tmux-powerkit# - uptime: container uptime# - datetime: local date/time# - git: current repository branch/status# - github: GitHub/repository integration status# - kubernetes: Kubernetes context/status# - terraform: Terraform/OpenTofu workspace/status# - cloud: local cloud CLI/context status# - cloudstatus: networked public provider status checks; opt-in, not enabled by default# - hostname: container hostname# - externalip: detected external IP# - ssh: SSH agent/key status# - netspeed: network throughput# - ping: network latency# - cpu: CPU usage# - loadavg: system load average# - memory: memory usage# - swap: swap usage# - disk: disk usage# - gpu: GPU status when available# - modelstatus_<provider>: per-provider AI status segment; explicit layout entries render even when model-provider auto-add is offline1-left=["session","windows"]line1-right=["aibox_log","aibox_oom","aibox_proc","aibox_ai","aibox_mcp","aibox_mig","weather","uptime","datetime"]line2-left=["git","github","kubernetes","terraform","cloud"]line2-right=["hostname","externalip","ssh","netspeed","ping","cpu","loadavg","memory","swap","disk","gpu"][customization.tmux.status.labels]# Visible headers/icons for status segments. Layout controls which segments appear;# this section controls how those segments are labeled once rendered.# Values may be plain ASCII labels or symbols. ASCII is safest across terminals;# Nerd Font / Powerline symbols are compact but require the user's terminal font.# Practical symbol candidates from Nerd Fonts. Keep icons distinct across# configured PowerKit segments so adjacent status cells remain scannable.aibox-log=""aibox-oom=""aibox-proc=""aibox-ai=""aibox-mcp=""aibox-mig=""kubernetes=""cloud=""cloud-aws=""cloud-gcp=""cloud-azure=""cloud-multi=""uptime=""netspeed=""netspeed-download=""netspeed-upload=""[customization.tmux.status.separators]# PowerKit separator style. Options: normal | rounded | slant | slantup | trapezoid | flame | pixel | honeycomb | nonestyle="rounded"# Edge separators may use a different style at status boundaries.edge-style="rounded"# Spacing between elements. Options: false | true | both | windows | pluginselements-spacing="both"[customization.tmux.status.refresh]# Refresh/caching controls for extended tmux status.# interval-seconds: tmux redraw cadence. Higher values reduce shell process churn.# aibox-metrics-cache-ttl-seconds: LOG/OOM/PROC/AI/MCP/MIG cache TTL.# netspeed-cache-ttl-seconds: network throughput cache TTL.# kubernetes-cache-ttl-seconds: local kubeconfig context cache TTL.# cloud-cache-ttl-seconds: local cloud CLI/context cache TTL.# github-cache-ttl-seconds: local repo + GitHub issue/PR/discussion count cache TTL.interval-seconds=15aibox-metrics-cache-ttl-seconds=30netspeed-cache-ttl-seconds=10kubernetes-cache-ttl-seconds=120cloud-cache-ttl-seconds=120github-cache-ttl-seconds=120[customization.tmux.status.forge]# Exact GitHub SSH hostnames and aliases recognized by the Forge segment.github-hosts=["github.com","github-work"][customization.tmux.status.model-providers]# Optional networked model-provider health segments for the extended tmux status line.# Each configured provider becomes one PowerKit segment when enabled, for example OAI ✓ or ANT .# enabled: false avoids auto-adding all configured providers; explicit layout entries still render.# cache-ttl-seconds: minimum time between provider status requests per provider.# timeout-seconds: per-request HTTP timeout so status rendering cannot hang tmux.# show-ok: true shows healthy providers with ✓; false hides healthy providers and only shows degraded/unknown/outage.enabled=falsecache-ttl-seconds=300timeout-seconds=3show-ok=true# Provider entries:# - provider: stable key from the model roster (openai, anthropic, google, mistral, deepseek, cohere, xai, alibaba, aws, meta, microsoft, minimax, moonshot, nvidia, xiaomi, zai)# - label: short category header shown in the status segment; use text or a symbol that your font supports# - checks: any of overall, models, harness; worst status wins (outage > degraded > unknown > ok)# - status-url: JSON status endpoint; Statuspage summary APIs are supported, Google uses incidents.json# - overall-components/model-components/harness-components: optional component-name filters for providers with componentized status APIs# Symbols: ✓ ok, degraded, outage, ? unknown.[[customization.tmux.status.model-providers.providers]]provider="openai"label="OAI"checks=["overall","models","harness"]status-url="https://status.openai.com/api/v2/summary.json"model-components=["Responses","Chat Completions","Embeddings","Realtime","Images"]harness-components=["CLI","Codex API","Codex Web"][[customization.tmux.status.model-providers.providers]]provider="anthropic"label="ANT"checks=["overall","models","harness"]status-url="https://status.claude.com/api/v2/summary.json"model-components=["Claude API"]harness-components=["Claude Code"][[customization.tmux.status.model-providers.providers]]provider="google"label="GOOG"checks=["overall","models"]status-url="https://status.cloud.google.com/incidents.json"[audio]enabled=false# Enable audio bridgingbackend="pulseaudio"# Audio bridge backendinstall=true# Install container audio toolspulse_server="tcp:host.docker.internal:4714"
Usage profile: human-dev or experimental headless-runner
profile is currently a compatibility signal for addon selection and doctor
warnings. It does not change the generated image tag yet; headless-runner
is reserved for automation-safe configurations that avoid subscription CLI
tools and interactive desktop helpers.
For automation, aibox describe workspace-manifest -o json emits a sorted,
read-only aibox.workspace-manifest.v0 projection of this file. The projection
uses processkit’s canonical Artifact{kind=workspace-manifest} kind, while the
machine-readable JSON shape remains aibox-owned until processkit publishes a
more detailed Artifact schema.
aibox describe provider-backends -o json similarly emits
aibox.provider-backends.v0-preview, an aibox-local index of supported harness
backends, addon availability, and MCP registration/permission targets.
aibox doctor uses the same preview model to warn about selected backends that
cannot participate in MCP automation, have no permission projection, or conflict
with the headless-runner profile.
aibox describe image-provenance-policy -o json emits
aibox.image-provenance-policy.v0-preview, which summarizes the configured
GHCR image tag or tag template, generated Dockerfile/Compose files, runtime
version/profile markers, selected addons, and the host-side release phase
command template.
Container configuration. Controls the generated docker-compose.yml and Dockerfile.
Field
Type
Required
Default
Description
name
String
Yes
–
Container name (used by compose and runtime inspect)
hostname
String
No
"aibox"
Container hostname
user
String
No
"aibox"
Container user
post_create_command
String
No
–
Command to run after container creation
keepalive
Boolean
No
false
Periodic DNS keepalive for development environments with idle network timeouts.
environment
Map (String → String)
No
{}
Environment variables injected into the container. Suitable for non-secret project-wide values; use .aibox-local.toml for secrets.
extra_volumes
Array of ExtraVolume
No
[]
Additional bind mounts. Each entry has source, target, and optional read_only.
resource_thresholds
Table
No
see below
Warning thresholds used by aibox doctor for cgroup/procfs pressure signals.
Generated Compose files include a top-level project name, an explicit service
image, and container_name = [container].name. Container runtime and Compose
views should therefore show each aibox project under its configured
project/container identity instead of a generic devcontainer group.
These thresholds are warnings only. They do not stop aibox up or fail the
container build; they make aibox doctor surface resource pressure before the
operating system starts killing processes.
Field
Type
Default
Description
memory_mib_warn
Integer
unset
Warn when cgroup memory.current exceeds this many MiB.
process_count_warn
Integer
400
Warn when /proc contains more processes than this. Set to 0 to disable.
processkit_mcp_python_warn
Integer
50
Warn when many Python processkit MCP server processes are live. Only rendered and used in processkit mode. Set to 0 to disable.
oom_kill_warn
Integer
0
Warn when cgroup memory.events reports more OOM kills than this.
GitHub CLI configuration created inside the container does not need an extra
volume: /home/aibox/.config/gh is already persisted through the managed
.aibox-home/.config mount. See GitHub authentication
for the least-privilege PAT and persistent-login options.
Customizing ports, packages, volumes, and environment variables
Use Dockerfile.local for installing additional packages, and docker-compose.override.yml for ports and additional services. Both files are scaffolded by aibox init and are never overwritten by aibox apply.
Environment variables and bind mounts can also be configured directly in [container.environment] / [[container.extra_volumes]] in aibox.toml, or — for secrets and per-developer settings that should not be committed — in .aibox-local.toml.
.aibox-local.toml is a personal, gitignored overlay for per-developer settings that should never be committed — API keys, provider endpoint/base URL overrides, personal bind mounts, and similar secrets. It lives next to aibox.toml in the project root and is automatically added to .gitignore by aibox init and aibox apply.
Three sections are supported:
[container.environment] — merged on top of aibox.toml’s [container.environment]. Local values win on conflicts.
[[container.extra_volumes]] — appended after any volumes declared in aibox.toml.
[[mcp.servers]] — personal MCP servers appended to the team MCP servers from aibox.toml [ai.mcp]. All sources are merged into each generated MCP client config file.
All other configuration (container name, addons, processkit version, etc.) must remain in aibox.toml.
processkit installs the processkit-backed project context layer. harness-only skips processkit content and uses only generated container/harness configuration.
packages
Array of strings
No
["product"] in processkit mode, [] in harness-only mode
processkit package selection. Required to be non-empty in processkit mode. Ignored in harness-only mode.
schema_version
String (semver)
No
"1.0.0"
Accepted for compatibility. Canonical processkit-mode rendering stores the schema version under [processkit.context].
aibox init --context-mode harness-only writes:
toml
[context]mode="harness-only"
In harness-only mode, generated aibox.toml, AGENTS.md, provider pointer
files, MCP config, status comments, and migration surfaces do not mention
processkit. aibox apply still regenerates .devcontainer/, .aibox-home/,
selected harness config, addon files, and team/personal MCP servers; it does
not install context/skills/, context/templates/processkit/, processkit
hooks, processkit preauth, processkit command adapters, or processkit Migration
entities.
Use [skills].include and [skills].exclude for explicit skill-level
overrides when mode = "processkit".
lualatex, pdflatex, xelatex, or tectonic. Tectonic supports build but not watch.
cache_dir
Relative path
No
.latex-cache
Root for project-local TEXMFVAR and TEXMFCONFIG. Parent traversal is rejected.
options
Array
No
[]
Additional single-line engine arguments.
documents[].name
String
Yes
–
Unique command-safe document name.
documents[].source
Relative path
Yes
–
Main TeX source.
documents[].output_dir
Relative path
No
.latex-cache/output
PDF, log, and auxiliary output directory.
preview.enabled
Boolean
No
false
Generates one shared read-only Compose preview sidecar; host-side aibox up starts it and it serves every configured document.
preview.engine
String
No
embedpdf
Viewer implementation; currently only embedpdf is supported.
preview.bind
IP address
No
127.0.0.1
Compose host-publish address. Loopback is accessible only from that host; use 0.0.0.0 only for other machines.
preview.port
Integer
No
8765
Host-published port for the document index and all viewers. It maps to sidecar port 8765.
preview.document
String
No
first configured document
Default for legacy /document.pdf and /events routes. All configured documents are served.
preview.allow_public
Boolean
No
false
Required for a non-loopback host bind. The preview has no authentication.
Run aibox apply after changing this section. Besides refreshing the canonical
config comments, apply adds conditional LaTeX companion guidance to AGENTS.md
and installs the managed aibox-latex-build and aibox-latex-watch scripts
into the development container’s runtime home. Compilation and watch mode run
only in that main container. See LaTeX Build and Preview
for the workflow and remote access. aibox generates the read-only serving
sidecar and its port mapping; do not add a duplicate mapping to
docker-compose.override.yml.
Addons install language runtimes and tool bundles into the container. AI
harnesses are selected under [ai]; aibox may still use internal addon recipes
to install their CLIs.
Omit git-ui if the project does not need GitHub CLI or lazygit in the
container. The aibox repo may select it for maintenance workflows, but it is
not required for every generated project.
Run aibox get addon to see all available addons, or aibox describe addon <name> for tool details and supported versions. See the Addons page for full documentation.
Language-scoped groups compose shared tooling and automatically expand their
dependencies:
Every language addon supports infrastructure, security/supply-chain, and
release; Go also supports quality and lint. Existing flat selections such
as [addons.infrastructure.tools] and [addons.supply-chain.tools] remain
valid and require no migration. To adopt language scoping, move only the table
prefix—for example, [addons.supply-chain.tools] becomes
[addons.go.supply-chain.tools]; tool entries and overrides are unchanged.
Controls which skills from processkit are installed into context/skills/.
Fresh aibox.toml scaffolds list the standard processkit operating skills in
include. If include is empty, aibox falls back to installing every skill in
the pinned processkit version minus anything listed in exclude.
aibox apply reconciles newly introduced standard skills into existing
processkit projects while respecting explicit exclude entries. Tooling-linked
skills remain opt-in: an interactive apply asks before persisting a
recommendation. For example, selecting the latex addon offers to add
latex-authoring; a non-interactive apply prints the recommendation without
changing skill selection.
toml
[skills]include=["pk-doctor","status-briefing"]# install only these plus core skillsexclude=["research-with-confidence"]# omit from the default all-skills set
include and exclude are mutually exclusive: use one or the other, not both.
Both accept skill names (the filename without .md). enabled and disabled
are accepted as aliases for older configs. An empty [skills] table (or
omitting the section entirely) installs all skills.
See the Skills page for the full processkit boundary.
This section is omitted and ignored in context.mode = "harness-only".
AI harness and model-provider configuration. Harness entries are ordered; the
order of the harnesses list is the tmux/layout order. A harness participates
in generated agent/MCP config only when enable = true; CLI installation is
controlled independently by install = true.
Field
Type
Required
Default
Description
harnesses[].harness
String
Yes for each entry
none
Harness id. Supported values: claude, codex, gemini, aider, continue, cursor, copilot, opencode, hermes, tau. Tau reads project instructions from AGENTS.md and Agent Skills from .agents/skills/; Tau does not currently expose a built-in MCP client.
harnesses[].enable
Boolean
No
false
Include this harness in generated runtime, agent, and MCP config. Alias: enabled.
harnesses[].install
Boolean
No
false
Install the matching in-container CLI recipe when available. Cursor has no container CLI, so keep this false for cursor.
harnesses[].version
String
No
addon’s default
Optional CLI version pin.
model_providers
Array of strings
No
[]
Optional provider env hints: anthropic, openai, google, mistral. Each maps to both an API key env var and an optional base URL env var.
Harness controls live in the ordered harnesses list. Optional entries are
usually shown as one-line inline tables so they can be enabled by uncommenting
one line:
model_providers is a catalog hint only; it does not inject environment variables into Compose by itself. Set provider credentials explicitly in [container.environment], preferably in .aibox-local.toml:
Some provider CLIs/SDKs also support aliases (for example OPENAI_API_BASE).
Legacy compact harness lists, harness_order, providers = [...],
[ai.harness.<name>], and [addons.ai-*.tools] inputs are still accepted for
compatibility. Use aibox apply --standardize-config to rewrite a schema-clean
config into the current canonical shape.
The load-bearing content section. Configures the content source
the project consumes — skills, primitives, processes, package YAMLs, and the
canonical AGENTS.md template. The default upstream is the canonical
projectious-work/processkit
repo, but any processkit-compatible source works (forks, self-hosted, private
mirrors).
This section is only active when [context].mode = "processkit". In
harness-only mode it is omitted from generated configs and ignored by
aibox apply.
If version is the sentinel unset, both aibox init and aibox apply skip
the processkit fetch entirely. Pin a real tag (e.g. v0.27.4) to land the
content. The downloaded tarball is git-tracked under
context/templates/processkit/<version>/ so derived projects always have the
original to diff against.
Release-asset tarball — downloads a purpose-built .tar.gz from
the URL built from release_asset_url_template (or the GitHub-style
default {source}/releases/download/{version}/{name}-{version}.tar.gz).
When a sibling <asset>.sha256 file is present, the tarball bytes
are verified against it before extraction. The verified SHA256 is
recorded in aibox.lock as release_asset_sha256 for bit-exact
reproducibility.
Host auto-tarball — falls back to GitHub / GitLab’s auto-generated
archive/refs/tags/<version>.tar.gz when no release asset is
available.
Git clone of the tag — last resort for hosts that serve neither
tarball form (typical for self-hosted git over SSH).
The release-asset path lets producers (processkit and any compatible
content source) ship a smaller, explicit shippable artifact. Consumers
get bit-exact reproducibility for free.
A SHA256 mismatch is a hard error (does NOT fall through), since it
indicates either tampering or a producer bug; both are situations the
user should be told about.
MCP server definitions and permission configuration. aibox apply merges
servers from these sources and regenerates all MCP client config files:
Built-in processkit servers — only in context.mode = "processkit", either the processkit gateway or separate per-skill servers, depending on [ai.mcp.gateway]
aibox.toml [[ai.mcp.servers]] — team-shared servers committed to version control
.aibox-local.toml [[mcp.servers]] — personal servers, gitignored
Generated files (.mcp.json, .cursor/mcp.json, .gemini/settings.json, .codex/config.toml, .codex/hooks.json, .continue/mcpServers/) are gitignored. They are always reproducible from the config sources above and must not be committed — doing so would embed personal server definitions or credentials from .aibox-local.toml.
In harness-only mode, processkit servers and the processkit gateway are not
registered. Team and personal MCP servers are still generated for enabled
harnesses.
When the selected processkit release provides processkit-gateway, its stdio
proxy can start the matching localhost daemon on demand. It can replace the
one-process-per-skill MCP topology with a single processkit MCP entry.
toml
[ai.mcp.gateway]mode="auto"# auto | daemon | stdio | separatelazy_catalog=truehost="127.0.0.1"port=8765path="/mcp"
Mode
Behavior
auto
Register a self-starting processkit gateway daemon when the installed processkit version ships it; otherwise fall back to separate per-skill servers
daemon
Use one localhost processkit gateway daemon plus one stdio proxy per harness
stdio
Register processkit-gateway directly as a stdio MCP server
separate
Always register one MCP server per processkit skill
lazy_catalog = true is the default. It enables processkit’s lazy catalog
where the selected gateway topology supports it. Set it to false only when
troubleshooting gateway import behavior. Legacy values daemon-proxy and
granular are still accepted as aliases for daemon and separate.
The daemon-backed mode is localhost-only. Run aibox apply after changing
this section so generated harness configs stay in sync.
Credential-bearing personal servers belong in the gitignored
.aibox-local.toml[[mcp.servers]] section. Do not commit GitHub tokens in
aibox.toml; see GitHub authentication.
Controls which MCP servers harnesses are permitted to use, eliminating repetitive permission prompts. aibox apply expands glob patterns into concrete server names and regenerates harness-specific permission files for supported harnesses.
Global defaults:
Field
Type
Required
Default
Description
default_mode
String
No
"ask"
Default permission when no explicit pattern matches. Use "allow" only when every configured MCP server is trusted.
allow_patterns
Array of strings
No
[]
Glob patterns to auto-allow. Supports server patterns such as "processkit-*" and Claude-style aliases such as "mcp__processkit-*" or "mcp__processkit-skill-gate__*".
deny_patterns
Array of strings
No
[]
Glob patterns to auto-deny (takes precedence over allow). Use for restricting specific tool families.
Per-harness overrides (optional):
toml
[ai.mcp.permissions.harness.claude-code]default_mode="allow"# Override global default if neededallow_patterns=[]# Add harness-specific patterns[ai.mcp.permissions.harness.opencode]default_mode="allow"deny_patterns=[]# Restrict specific tools per harness
aibox maps this provider-neutral permission intent to each harness’s native
configuration format. Sandbox, approval, and network policy are configured
separately in [ai.execution].
Example:
toml
[ai.mcp.permissions]default_mode="ask"allow_patterns=["mcp__processkit-*"]deny_patterns=["mcp__processkit-dangerous-admin"]# Deny a specific pattern if needed[ai.mcp.permissions.harness.claude-code]# Use default settings; Claude Code will auto-allow all processkit tools[ai.mcp.permissions.harness.continue]# Continue defaults to "ask" for safety; override to "allow" to auto-approvedefault_mode="allow"
Personal MCP servers
Servers that require personal credentials or are not relevant to all team members belong in [[mcp.servers]] in .aibox-local.toml, not committed [[ai.mcp.servers]]. See Local Config.
Controls the default execution policy intent for AI harnesses. aibox uses stable
cross-harness vocabulary here and maps it to each harness where supported.
The legacy [ai.harness.<name>.execution] table is still accepted for existing
configs, but new scaffolds use [ai.execution.<name>].
filesystem = "container-full" means the devcontainer is the filesystem
security boundary. For Codex this maps to sandbox_mode = "danger-full-access",
which keeps .git writable inside a trusted aibox devcontainer. It is distinct
from Codex’s --dangerously-bypass-approvals-and-sandbox: approvals remain
controlled by the approval axis.
Unsupported axes for a harness are best-effort projections; they are retained in
aibox.toml as project intent even when the current harness has no exact native
setting.
Controls how aibox init scaffolds the canonical agent entry document
(AGENTS.md) and the provider-specific entry files (CLAUDE.md, future
CODEX.md, …). The principle is provider neutrality: every agent
harness reads the same AGENTS.md so a project doesn’t have to keep
N copies of the same instructions in sync. Provider files exist only
to satisfy specific harnesses’ auto-load conventions (Claude Code
auto-loads CLAUDE.md at startup, etc.).
Field
Type
Required
Default
Description
canonical
String
No
"AGENTS.md"
Filename of the canonical agent entry document. Almost no one should override this — the default matches the agents.md ecosystem convention.
provider_mode
String
No
"pointer"
How provider files are scaffolded. pointer (recommended): provider files are thin pointers that say “see AGENTS.md”. full: provider files contain the rich provider-flavoured content — use only when a project genuinely needs different instructions per harness.
aibox init always creates AGENTS.md (write-if-missing — never
overwrites). When the Claude harness is enabled, it also creates
CLAUDE.md, either as a thin pointer (default) or with the full rich
content (provider_mode = "full"). Other harnesses (Aider, Gemini,
Codex, Copilot, Continue) use config files rather than markdown
entries and are not affected by this section.
Existing files are never overwritten. If you already have a hand-written
AGENTS.md or CLAUDE.md, aibox init leaves it alone.
Visual and layout configuration. See Themes and Layouts for details.
Field
Type
Required
Default
Description
theme
String
No
"gruvbox"
One of 34 theme families, including Projectious, mono, contrast, and contrast-mono; see Themes.
mode
String
No
"auto"
Global theme mode overlay: auto, light, dark. auto follows the host OS appearance when detectable during aibox apply, aibox up, or aibox set theme.*; otherwise it preserves the selected concrete theme.
variant
String
No
unset
Optional family-specific variant such as mirage, deep, high-contrast-dark, or max. Invalid variants and incompatible explicit modes are rejected with the available choices.
emphasis
String
No
"auto"
Semantic font-decoration level: auto, full, standard, minimal, or none. auto probes terminal capabilities; NO_COLOR forces none. Max-contrast variants reject none.
emphasis_overrides.*
String
No
unset
Per-role whitespace-separated attributes (bold, italic, dim, underline, strikethrough). Unsupported attributes degrade according to the selected emphasis level and each tool’s capabilities.
prompt
String
No
"default"
Starship preset: default, plain, arrow, minimal, nerd-font, pastel, powerline-pastel, bracketed. Legacy pastel-powerline is accepted as an alias.
layout
String
No
"dev"
tmux layout: dev, focus, cowork, ai
tmux.status.mode
String
No
"extended"
tmux status presentation: extended uses the themed multi-line PowerKit status, plain keeps minimal tmux text, disabled turns the status line off. Legacy powerline is accepted as an alias for extended.
tmux.title.enabled
Boolean
No
true
Emit a configurable, state-aware terminal tab title from tmux. Set false to leave terminal title ownership to the terminal or shell.
GitHub integration behavior for generated runtime Git configuration.
Field
Type
Required
Default
Description
credential_helper
String
No
"auto"
auto writes a managed Git include when the git-ui addon installs gh; gh always writes it; none skips and removes the managed include. For github.com HTTPS remotes, the include resets earlier credential helpers before delegating to gh auth git-credential, and never stores token values.
This setting selects the generated Git credential helper; it does not select
or store a GitHub token. Configure scoped tokens or a persistent GitHub CLI
login through the local GitHub authentication guidance.
Records the owner’s decision to retain .aibox-home state for disabled AI harnesses. Without a decision, aibox apply retains the state and prints the preserve-or-purge path without creating a Migration.
purge_disabled_harness_state
Boolean
No
false
Explicitly removes retained state for disabled AI harnesses on the next aibox apply.
[container]name="my-project"# Container name (used by compose)hostname="my-project"# Container hostnameuser="aibox"# Container user (default: aibox)
The user field determines the non-root user inside the container. The default aibox user (UID 1000) is recommended. Set user = "root" only if needed for specific tools.
aibox apply generates a Compose file with an explicit top-level project name,
an explicit service image, and container_name = [container].name. Docker
Desktop, OrbStack, and Compose UIs therefore group aibox projects by their
project/container names instead of under a generic devcontainer identity.
The generated main service also sets Compose init: true. Compose starts a
small init process as PID 1 so orphaned child processes are reaped correctly
while the service still runs command: sleep infinity as its long-lived
container command. This prevents zombie buildup from tools that spawn helper
processes, including bubblewrap-based sandbox helpers.
init: true is part of the Compose Specification. Docker Compose and modern
Compose-spec providers support it. podman compose delegates to an external
Compose provider, so support depends on the configured provider; if an older
provider rejects the key, upgrade the provider rather than removing the reaper
from generated projects.
Use the configured container name when writing Compose overrides:
Prevent OrbStack/VM NAT from dropping idle connections:
toml
[container]keepalive=true
This sends a lightweight DNS lookup every 2 minutes via the devcontainer postStartCommand.
Custom Packages, Ports, Volumes, and Environment Variables#
Container customizations such as extra packages, port forwarding, volume mounts, and environment variables are handled through standard Docker mechanisms rather than aibox.toml.
Ports, Volumes, and Environment Variables — docker-compose.override.yml#
Use .devcontainer/docker-compose.override.yml to add port mappings, volume mounts, and environment variables:
yaml
services:my-project:# must match [container] name in aibox.tomlports:- "8080:80"- "5432:5432"volumes:- /host/data:/container/data:roenvironment:DATABASE_URL:"postgres://localhost/mydb"NODE_ENV:"development"
Both Dockerfile.local and docker-compose.override.yml are scaffolded by aibox init and are never overwritten by aibox apply.
For project-specific services (databases, sidecars, test companions), use Docker Compose’s standard override mechanism. During aibox init, an empty .devcontainer/docker-compose.override.yml is scaffolded with example usage.
Docker Compose automatically merges the override file with the generated docker-compose.yml using a strategic merge — maps (services, environment) are deep-merged by key, lists (ports, volumes) are appended, and scalars (image, command) are replaced.
When aibox apply detects the override file, it wires both files into devcontainer.json so VS Code picks them up.
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.
[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.1clippy={}# 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.
Go projects can compose production tooling without bloating the base runtime:
toml
[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.
[addons.latex.tools]texlive-core={}# Base TeX Live installationtexlive-recommended={}# Common packagestexlive-fonts={}# Font packagesbiber={}# Bibliography processortexlive-code={}# Code listing packagestexlive-diagrams={}# TikZ, PGF, circuit diagramstexlive-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.
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:
Internal procedures for building, testing, documenting, and releasing aibox.
The canonical step-by-step release note remains in context/notes/; this page
is the public contributor summary.
The public docs live in docs-site/ and use Hugo with the pinned
brand-theme-hugo-vanilla module. Hugo Extended, Go, and Node.js are required;
the project devcontainer enables all three through aibox addons.
bash
npm --prefix docs-site ci
./scripts/maintain.sh docs-serve
./scripts/build-docs.sh
./scripts/build-docs.sh is the local verification build. It writes the static
site to docs-site/public/ and prints Hugo render warnings.
docs-deploy builds the site and pushes the static output to the gh-pages
branch from the local checkout. It does not use GitHub Actions. Use
--dry-run to validate the production build without pushing; use the command
without that flag only when the current checkout is the source that should be
published. The release script runs the same deployment as part of the
container-side release phase.
Use the repository maintenance command for publication rather than
npm run deploy. The maintenance command preserves the project’s local-only
release flow, publishes the already configured /aibox/ site, and ensures
GitHub Pages serves the gh-pages branch.
validate immutable inputs, build/smoke Darwin and candidate images without credentials, emit evidence, then publish the fixed manifest
Both phases run locally. The project deliberately does not use GitHub Actions
for release validation, artifact builds, image publication, or deployment.
Release speed comes from bounded local concurrency, persistent caches, and
reuse of evidence for the exact release commit rather than from moving gates to
a hosted runner.
Do not create GitHub releases by hand with gh release create. The release
script attaches binaries and writes the release notes expected by users.
This command requires a clean working tree. It may stop after
sync-processkit if a newer processkit release changes the pinned default and
the CLI needs review before release.
The command performs:
dependency, addon, image, and harness state report in dist/RELEASE-STATE.md
processkit and host-context aibox doctor runs in dist/RELEASE-DOCTORS.md;
doctor errors block the release and warnings remain visible for review
processkit release sync check
cli/Cargo.toml and Cargo.lock version bump when needed
format, Clippy, and test checks
local temporary-workspace E2E and isolated tmux/asciinema probes
cargo audit
cargo update --dry-run review for lockfile-resolvable crate updates
Linux release builds for aarch64-unknown-linux-gnu and
x86_64-unknown-linux-gnu
binary version smoke check
annotated git tag push
GitHub release creation with Linux binaries
Hugo/projectious.work brand-theme docs deployment
dist/RELEASE-PROMPT.md for host-side completion
Independent validation gates run concurrently. The default worker limit is
two; set AIBOX_RELEASE_PARALLELISM to a positive integer that fits the local
machine. Linux release targets build concurrently inside the build gate, and
the version smoke reuses the matching release artifact instead of compiling a
third binary.
Successful gates write local evidence under
dist/release-evidence/vX.Y.Z/<commit>/. Evidence is bound to the exact commit,
Rust toolchain, clean-tree state, release phase, and gate-specific environment.
Audit evidence expires daily, and binary evidence rechecks archive checksums. Set
AIBOX_RELEASE_REUSE_EVIDENCE=0 to force every selected gate to run again.
Container-side timings are summarized in dist/RELEASE-TIMINGS.md; host-side
timings are summarized in dist/RELEASE-HOST-TIMINGS.md. Each summary is a
cumulative view of the append-only timing-events.tsv file beside the
candidate evidence, so retries and resumed release commands retain failed,
passed, and reused gate attempts instead of replacing the earlier timings.
Run ./scripts/maintain.sh release-check-state standalone when you want the
dependency and tool-state report without bumping, tagging, or building. Run
./scripts/maintain.sh release-doctors for the matching diagnostic report.
If a report finding is deferred, create a processkit WorkItem before continuing
the release and mention that WorkItem ID in the release notes or handover.
For cargo update --dry-run, either apply available crate updates in the
release with full validation, or create a WorkItem for the deferred
crate-update pass.
The container-side release prepares a checksummed source archive and provenance
record under tmp/host-gates/aibox-release/<run-id>/input/. It writes the
single owner command to dist/RELEASE-PROMPT.md:
For an evidence-only rehearsal, append --dry-run. Validation still performs
all candidate builds, probes, cleanup, SBOM generation, vulnerability scanning,
and manifest hashing, but it does not invoke GitHub or GHCR publication. The
validator prints the separate publisher command that can consume the verified
run directory later.
Interactive terminals use the Textual dashboard by default (--ui=auto). Use
--ui=textual to fail if the dashboard cannot start, or --ui=plain for
redirected and captured output. The UI presents a high-level progress bar, a
persistent task list, and a selectable task-filtered log. Space toggles follow,
w toggles wrapping, Ctrl+A/C selects and copies, y copies the selected task
log, End resumes the live tail, and p displays the authoritative evidence
path. The UI is presentation rather than evidence; full output is retained in
evidence/command-results.log.
Content-addressed container layers are reused by default. The Rust registry is
shared in a dedicated credential-free host-gate cache, while compiled artifacts
are isolated by candidate commit so a failed candidate can be retried without a
full two-target rebuild. Use --cold-cache only when deliberately investigating
cache behavior. Cold mode retains downloaded Rust packages but forces downstream
container layers to rebuild.
To retry after a conditional addon or lifecycle check fails, prepare a new run
and name the failed run as its checkpoint source:
The retry source must contain byte-identical immutable candidate inputs.
Completed conditional checks are reused only when their candidate-bound
checkpoint checksum is valid. The candidate lifecycle, SBOM, vulnerability
scan, cleanup, manifest assembly, and publication verification remain fresh.
The reviewed entry point accepts only that run-directory path. It rejects
traversal, symlinks, special files, hardlinks, unexpected inputs, unsafe
permissions, checksum drift, and tag/commit mismatches. A previous partial run
is never resumed in place: runtime/ and evidence/ must not exist in the new
run when it starts. Retry imports only validated conditional checkpoints.
The host checkout’s HEAD must match the attested candidate commit, but
unrelated tracked worktree edits do not invalidate the gate because all builds
and probes use the immutable checksummed source archive rather than worktree
contents.
Validation and publication are separate security stages within the one owner
invocation. Candidate-controlled native builds, build scripts, CLI commands,
and the generated runtime smoke receive a fixed environment and run under a
macOS sandbox that denies GitHub configuration, Docker configuration, SSH
material, and Keychain services. Docker uses an empty per-run configuration;
no publication credential, secret, broad mount, or runtime socket is exposed
to the development container or candidate container.
The entry point accepts owner-installed uv from the official standalone path
~/.local/bin/uv or the architecture-native Homebrew prefix. It verifies
ownership and rejects group/world-writable executables instead of searching an
inherited PATH. It lets uv resolve, install when necessary, and run exact
Python 3.14.6 under --no-project, fixed owner cache/managed-Python roots,
and a fully rebuilt environment. The gate invokes python as uv’s command
rather than handing the script to uv, so candidate inline script metadata is
not processed. Candidate project metadata and inherited UV_* settings cannot
select the interpreter or dependencies.
The validation stage builds both Darwin targets, natively smokes the current
architecture, builds the actual candidate foundation/runtime images, exercises
the generated Compose lifecycle and --forget-tmux-state, requires cleanup,
generates a CycloneDX SBOM, and applies the reviewed Grype policy. High or
Critical findings with a listed fixed version block the release; findings with
no listed fix remain explicit non-blocking warnings in the evidence. It also
verifies the checksummed comparison tag, commit, and changed-path list, then
runs affected addon build groups, the LaTeX watcher/preview lifecycle, and the
rootless Podman readiness probe when relevant inputs changed. The readiness
probe verifies the unprivileged binaries, subordinate ID ranges, namespace
helpers, storage/network helpers, and container configuration without granting
the outer development container privileges for nested user-namespace execution. No comparison tag selects
all three surfaces. Every command, selection reason, skip reason, and result is
retained beneath evidence/ with toolchain metadata, image inspection, runtime
logs, hashes, and a release manifest.
The terminal interface streams subprocess output as it is produced. Each
high-level operation reports running, passed, or failed state with elapsed
time, and quiet commands emit a heartbeat every ten seconds. The same
transitions are retained in evidence/steps.log; full argv and output remain
in commands.log and command-results.log, so interactive progress does not
replace auditable evidence.
The terminal groups High/Critical package matches by unique advisory and prints
a bounded summary with severity, affected package names, and disposition. The
complete scanner report remains at evidence/security/vulnerability-scan.json;
counts, grouped advisories, package versions, fix versions, and the blocking or
warning classification are publication-required evidence in
evidence/security/vulnerability-policy.json.
The gate selects the first responsive runtime in this order: the docker CLI
contract exposed by Docker Desktop or OrbStack, then Podman. All image builds,
Compose lifecycles, exec probes, inspection, cleanup, scanning, and publication
use that selected runtime. Docker-compatible builds explicitly enable BuildKit
for features such as COPY --chmod; OrbStack does not need Docker Desktop’s
separate Buildx component.
When Compose and Buildx are installed as Docker CLI plugins, the gate copies
only those owner/root-owned, non-group-writable executables into its empty
per-run DOCKER_CONFIG. It does not copy the owner’s Docker configuration,
registry credentials, contexts, or unrelated plugins.
Before the Darwin build, the gate fetches the exact locked Cargo dependency
graph into a per-run credential-free Cargo home. The actual compilation remains
offline, so a newly locked crate does not require a pre-warmed owner cache and
candidate build scripts do not receive network access.
Only after every gate succeeds does the separate publisher receive normal host
GitHub/GHCR authority. It revalidates the immutable manifest and can upload
only the two Darwin archives plus checksums and push only the fixed aibox
foundation-version, runtime-version, and runtime-latest tags. It cannot build,
run tests, execute candidate code, commit, merge, or accept extra arguments.
Remote asset and image inspection is mandatory.
On failure, keep the run directory as diagnostic evidence. Correct the source,
create a new candidate commit/tag, and prepare a new run ID; do not edit the
old input or selectively reuse its evidence. The owner must review changes to
the gate and publisher before using a changed version.
gh release view vX.Y.Z shows all expected binary assets.
curl -fsSL https://raw.githubusercontent.com/projectious-work/aibox/main/scripts/install.sh | VERSION=X.Y.Z bash installs the expected version.
aibox --version reports X.Y.Z.
For v0.26.x, docker pull ghcr.io/projectious-work/aibox:base-debian-vX.Y.Z or the matching Podman pull succeeds.
For v0.27.0+, docker pull ghcr.io/projectious-work/aibox:base-debian-runtime-vX.Y.Z and base-debian-runtime-latest succeed. Foundation images are published as base-debian-foundation-vX.Y.Z; source-hash marker tags are not published.
To remove historical source-hash marker tags from GHCR, first run ./scripts/maintain.sh ghcr-prune-source-tags --repair-mixed and review the mixed-version repair plan. Then run ./scripts/maintain.sh ghcr-prune-source-tags --repair-mixed --execute with read:packages, delete:packages, and Docker Buildx available on the host.
The docs site at https://projectious-work.github.io/aibox/ reflects the release.
The maintenance script can also operate this repository’s own devcontainer:
bash
./scripts/maintain.sh start
./scripts/maintain.sh status
./scripts/maintain.sh attach
./scripts/maintain.sh stop
Do not confuse .devcontainer/ in this repository with images/. The former
is the environment used to develop aibox. The latter contains image recipes
published for downstream projects.
By default, aibox init lays down a processkit-backed project skeleton:
devcontainer files, config, an empty context/ directory, and processkit
content (skills, processes, and the canonical AGENTS.md).
text
my-app/├──aibox.toml# Single source of truth (includes [processkit])├──AGENTS.md# Canonical agent entry — rendered from processkit scaffolding├──CLAUDE.md# Thin pointer to AGENTS.md (when Claude is enabled in [ai].harnesses)├──.gitignore# Generated with language-specific blocks├──aibox.lock# Records resolved CLI, image, addon, and processkit state├──.aibox-home/# Persistent config (git-ignored)├──.devcontainer/│├──Dockerfile# Generated from aibox.toml│├──docker-compose.yml# Generated — volume mounts, env vars│└──devcontainer.json# Generated — VS Code integration└──context/├──skills/# Editable skill copies — installed by processkit├──processes/# release, code-review, feature-development, bug-fix├──schemas/# primitive schemas├──state-machines/# state machine definitions└──templates/└──processkit/└──v0.27.4/# Immutable upstream snapshot, used by `aibox apply` for three-way diffs
For projects that only want the generated devcontainer and AI harness setup,
use harness-only mode:
bash
aibox init my-app --context-mode harness-only --harness claude
Harness-only projects still get aibox.toml, .devcontainer/, .aibox-home/,
selected harness config, AGENTS.md, and provider pointer files such as
CLAUDE.md. They do not get processkit content, context/skills/,
context/templates/processkit/, processkit MCP gateway config, processkit
hooks/preauth, processkit command adapters, or processkit Migration entities.
The minimal generated AGENTS.md contains no processkit references.
.aibox-local.toml — secrets and per-developer overrides
.aibox-local.toml is added to .gitignore by aibox init. Use it for API keys and host-specific bind mounts that should not be committed:
Shared settings stay in aibox.toml; personal secrets go here.
Use narrowly scoped PATs by default. For the alternative persistent
gh auth login flow and multi-token commands, see
GitHub authentication.
processkit version
By default, the interactive aibox init picker offers latest first, then the
10 newest stable processkit tags. Choosing latest writes
version = "latest" to aibox.toml so aibox apply tracks the newest
compatible content. Use --processkit-version to pin a specific tag
non-interactively:
bash
aibox init my-app --processkit-version v0.27.4
To evaluate prerelease processkit content without changing the stable default,
pin the prerelease explicitly or opt into prerelease selection:
The scaffolded config file comes with commented documentation for every option:
toml
# aibox.toml — project configuration for aibox.# All generated files (.devcontainer/) derive from this file.# Run `aibox apply` after editing to regenerate.## Full documentation: https://projectious-work.github.io/aibox/docs/reference/configuration[aibox]project_name="my-app"profile="human-dev"[container]name="my-app"hostname="my-app"# user = "aibox" # Container user (default: aibox)[container.image]release_version="latest"base="debian"[context]mode="processkit"packages=["product"][processkit]source="https://github.com/projectious-work/processkit.git"version="latest"[processkit.context]schema_version="1.0.0"# Addons install tool sets into the container.# Run `aibox get addon` to see all available addons.# [addons.python.tools]# python = { version = "3.14" }# uv = { version = "0.12.5" }# AI harnesses — controls which AI CLIs/configs are enabled.[ai]harnesses=[{harness="claude",enable=true,install=true},][customization]theme="gruvbox"mode="auto"prompt="default"layout="dev"# Audio support for PulseAudio bridging (e.g., Claude Code voice).# Requires host-side PulseAudio setup: run `aibox apply audio`[audio]enabled=false# pulse_server = "tcp:host.docker.internal:4714"
aibox apply # Reconcile config, regenerate files, build imageaibox up # Start the container and attach via tmux
You land in a tmux session with the dev layout: a work window with Yazi,
the 1st harness, and a shell, plus optional lazygit, further harness, and shell
windows.
Four layouts are available: dev (default), focus, cowork, and ai.
See Layouts.
The project root is mounted at /workspace. Persistent configuration lives in .aibox-home/ on the host, mounted into the container automatically.
Rich prompt with Nerd Font icons for OS, language runtimes, git status, Docker context, and system info. Requires a Nerd Font installed on the host terminal.
One-line pastel powerline prompt inspired by Starship’s Pastel Powerline preset. Directory, git, language runtimes, command duration, and character appear inline in connected colored segments. Nerd Font recommended.
Each segment wrapped in square brackets — [dir] [branch] [status]. Clean, structured appearance without special fonts. A good alternative to plain with more visual structure.
Airline/powerline-style prompt with hard chevron separators (►). Segments for directory, git branch, and git status appear as connected colored blocks, with command duration shown inline. Requires a Nerd Font or Powerline-patched font.
New aibox projects list the standard processkit operating skills explicitly in
[skills].include. This makes skill selection a direct comment/uncomment
workflow in aibox.toml without relying on legacy package tiers.
Use [skills].include for explicit additions and [skills].exclude for
explicit removals:
Legacy package tiers (minimal, managed, software, research, product)
are still accepted for compatibility under [context].packages when
[context].mode = "processkit", but explicit [skills] selection is the
preferred control surface.
aibox can enable audio support for voice-capable tools. Audio is bridged from
the container to the host via PulseAudio over TCP, and the required container
packages live in the optional audio-voice addon.
Claude Code supports voice interaction. For this to work inside a container, audio output (and optionally input) must be forwarded to the host’s sound system. aibox handles this by installing PulseAudio client utilities in the container and connecting them to a PulseAudio server running on the host.
Whether to set up audio environment variables in the container
backend
pulseaudio
Audio bridge backend. Only PulseAudio is currently supported
install
true
Whether to install the internal audio-voice tool recipe when audio is enabled
pulse_server
tcp:host.docker.internal:4714
PulseAudio server address
When enabled = true, the generated docker-compose.yml sets PULSE_SERVER in the container environment.
When install = true, it also selects the internal audio-voice recipe during
aibox apply, which installs Sox, PulseAudio client utilities, and ALSA
PulseAudio plugins in the container.
Docker Desktop and OrbStack provide host.docker.internal automatically. For Podman, check your machine’s network configuration — you may need to use the host IP directly:
Ensure port 4714 is accessible from the container network. On systems with strict firewalls, you may need to allow traffic from the Docker/Podman bridge interface.
When running claude auth inside a container with bridge networking (OrbStack, Docker Desktop), the OAuth callback may fail. Claude Code starts a temporary HTTP server on a random ephemeral port to receive the callback, but that port isn’t forwarded to the host browser.
Workaround: Use claude setup-token to authenticate manually, or authenticate on the host first. aibox bind-mounts Claude’s .claude/, .claude.json, and XDG cache/config/state locations, so credentials survive container rebuilds.
Upstream tracking
This is tracked at anthropics/claude-code#14528. A fix on the Claude Code side (e.g., configurable callback port) would resolve this properly without compromising container network isolation.
The seeded home configuration includes an .asoundrc file at
/home/aibox/.asoundrc. This configures ALSA to route through PulseAudio, so
applications that use ALSA rather than PulseAudio directly also get audio output
when the audio-voice addon is installed.
This is usually a network or resource issue. PulseAudio over TCP adds latency. Ensure the container has sufficient CPU resources and the host is not under heavy load.
If you do not need audio, set enabled = false in aibox.toml:
toml
[audio]enabled=false
This removes the PULSE_SERVER environment variable from the container. The audio packages (sox, pulseaudio-utils) remain installed in the base image but are inert without a server to connect to.
aibox deliberately has no container-runtime bridge from its development
container. Tests are placed according to the product behavior they prove, not
according to the historical runner that happened to execute them.
Real panes, layouts, keybindings, Yazi/Vim interaction, asciinema output
Release host
Owner-controlled macOS gate
Native Darwin binaries and genuine candidate-image build/start/probe/down behavior
Run the complete local suite with cd cli && cargo test. The compatibility
feature e2e no longer grants access to another machine or runtime. Opt-in
visual matrices run with:
The canonical release and local-E2E gates pass --test-threads=1. The visual
tests share host PTY and tmux scheduling even though each owns a separate
socket; keeping the default serialized prevents slow Yazi/Vim cases from
timing out behind another process-level visual test.
Every process-level visual test removes inherited TMUX and TMUX_PANE, owns
a socket beneath its TempDir, and cleans up only its own server. Tests must
not use global tmux kill-server, broad /tmp/tmux-* removal, or global
pkill; those operations can terminate the developer’s live session.
The former aibox-e2e-testrunner, SSH/SCP runner, nested Podman/systemd/kind
image, passwordless elevation, capabilities, devices, host module mount, and
relaxed security profile were removed for issue #372. No test required a
separate unprivileged clean-room service. The generic Alpine pull/run test was
also removed because it supplied weaker evidence than the actual generated
aibox image lifecycle.
The remaining runtime-only contracts are:
build the candidate foundation and runtime image from the release source;
generate a downstream project with the candidate Darwin binary;
run aibox apply and Compose up against that locally built image;
verify identity, non-root execution, readiness, tmux/Yazi/status tooling,
and the --forget-tmux-state attach behavior;
bring down only that run’s Compose project and fail if cleanup fails;
generate a CycloneDX SBOM and fail the vulnerability gate on high severity.
These contracts inherently need ordinary host Docker and therefore run only in
the macOS release gate. Missing Docker, Apple targets, Syft, Grype, or any other
mandatory prerequisite is a failure, never a passing skip.
Three expensive surfaces remain mandatory when their attested inputs change:
grouped builds for affected download-based addons;
a two-revision LaTeX watcher build with byte-identical preview-sidecar output;
the infrastructure addon’s nested Podman probe, including a true rootless report.
The immutable provenance records the previous version-line tag and commit plus
the exact changed-path list. The gate recomputes that diff before selecting
checks. Base-image, generator, addon-loader, template, or host-gate changes
select every conditional surface; an addon definition selects its group, and
LaTeX or infrastructure changes select their dedicated lifecycle probe. If no
comparison tag exists, all conditional checks run. Every selection and
non-selection is written to evidence. A selected check cannot pass by skipping.
Add --ui=textual to require the interactive dashboard or --ui=plain to
retain line-oriented output. --ui=auto is the default and selects Textual
only for a suitable TTY. The dashboard shows completed high-level tasks in a
progress bar, keeps passed/failed/skipped task rows visible, and lets the
operator filter a bordered log by task. Space toggles follow mode, w toggles
soft wrapping, Ctrl+A selects, Ctrl+C copies only the marked selection, l
selects the last 20 log lines, y copies the current task log, and e copies
the canonical warning/failure Problems bundle. The Problems panel can be
selected to filter the log. End returns to the live tail, and p reveals the
evidence path.
The dashboard is presentation, not evidence. Raw command output remains in
evidence/command-results.log and high-level transitions remain in
evidence/steps.log; use those files for complete copied or attached logs.
The completed run directory can later be published with the exact
release-host-publish.sh command printed by the validator. Do not rerun the
gate without --dry-run; populated runtime/ and evidence/ directories are
intentionally non-resumable.
The entry point accepts that one path plus optional fixed --dry-run,
--cold-cache, --retry-from=<failed-run-dir>, and
--ui=auto|textual|plain flags. It canonicalizes the path,
requires one direct child of the approved root, rejects symlinks, special
files, hardlinks, unexpected files, unsafe permissions, bad checksums, and
tag/commit mismatches, then creates runtime/ and evidence/ itself.
The entry point uses the owner-installed uv binary from a reviewed fixed path
and requires exact Python 3.14.6 with --no-project. It provisions the
hash-locked Textual 8.2.8 environment from scripts/release-host-ui.lock;
candidate PEP 723 and project metadata remain disabled. Its cache and
managed-Python roots are fixed beneath
~/Library/Caches/aibox-host-gates/uv and
~/Library/Application Support/aibox-host-gates/python; candidate
pyproject.toml, inline metadata, uv configuration, and inherited UV_*
variables cannot affect execution. The resolved uv, Python, Textual, lockfile,
and tool paths are recorded in evidence.
Content-addressed container layer reuse is the default. --cold-cache forces
downstream image rebuilding for cache investigations. Rust downloads live in a
dedicated credential-free cache and compiled output is scoped to the candidate
commit. --retry-from accepts only a separate run with byte-identical immutable
inputs and reuses checksummed successful conditional probes; core lifecycle,
security scanning, cleanup, and publication evidence are always regenerated.
Candidate compilation, build scripts, CLI execution, and runtime smoke run
with a fixed sanitized environment and a macOS sandbox that denies access to
GitHub configuration, Docker configuration, SSH material, and Keychain
security services. Docker receives an empty per-run configuration and no
secrets or host mounts. Tool runtime state is fixed under runtime/; no
candidate project configuration controls Python or package resolution.
Only after every required validation succeeds does the gate invoke the small
publisher. The publisher re-verifies the release manifest and hashes, uploads
exactly two Darwin archives plus their two checksum files, and pushes only the
fixed foundation-version, runtime-version, and runtime-latest image tags. It
does not build, test, execute candidate code, modify Git, or accept additional
arguments.
Evidence contains exact commands and results, toolchain/runtime metadata,
changed-path selection reasons, Darwin build and smoke records, image
inspection, generated-runtime and selected conditional-check logs, SBOM,
vulnerability scan, release manifest, and remote publication checks.
The gate is fail-closed and does not reuse a partially populated run directory.
On failure, preserve its evidence for diagnosis. After fixing the release
candidate and creating a new tag/commit, run the container-side release again
to prepare a new run ID. Do not edit an old input/, delete selected evidence,
or resume publication from an unverified partial run.
The owner must review the entry point before its first real invocation. Any
later change to the gate or publisher requires a fresh owner review before use.
In harness-only mode, omit [processkit], [processkit.context], and
[skills]; aibox apply will not create processkit skill mirrors or
processkit Migration entities.
Pin processkit before apply
Set [processkit].version to a real tag (e.g. v0.27.4) before the first
aibox apply. The default sentinel unset skips processkit content
installation entirely — you will get devcontainer files but no skills,
processes, or processkit-rendered AGENTS.md template.
This tip only applies when [context].mode = "processkit".
If your devcontainer setup is heavily customized, you can still use aibox for
context or harness configuration and skip the container lifecycle commands. Use
aibox.toml for the [aibox], [context], [ai], and, when applicable,
[processkit] sections, and manage .devcontainer/ yourself.
If you are upgrading from aibox ≤ v0.3.4, the persisted config directory was renamed from .root/ to .aibox-home/. This directory is gitignored and not tracked, so use a plain filesystem rename:
bash
mv .root .aibox-home
Do not use `git mv`
git mv .root .aibox-home will fail because .root/ is listed in .gitignore and was never committed. Use a regular mv command.
aibox will fall back to .root/ automatically if .aibox-home/ does not exist, so this migration is optional but recommended.
If your project already has context files (like DECISIONS.md or BACKLOG.md) that predate aibox, doctor can help identify what needs to change. See Migration for the full guide.
Node.js version pinning – use the node addon and --addon-tool or
[addons.node.tools] when you need a specific supported version.
postCreateCommand – use post_create_command in [container] config.
For git identity, prefer .aibox-home/.config/git/config.
VS Code extensions/settings – the generated devcontainer.json works with VS Code Dev Containers. For project-specific settings, keep a .vscode/settings.json.
Third-party CLI tools (Gemini, Jules) – mount from host via [[container.extra_volumes]], or add installation to post_create_command.
Existing generated containers – after adopting aibox, recreate the
runtime so Compose identity, image name, mounts, and init-reaper settings take
effect.
The built-in catalog is generated from one audited semantic dataset at cli/assets/aibox-theme-corrections.toml. Do not add a palette by copying unrelated built-in themes into individual tools: every concrete variant must define the same semantic contract and pass the same contrast checks.
A family also declares its mode and variant name. Add the corresponding concrete Theme and user-facing ThemeFamily resolution entries in cli/src/config.rs.
The shared emphasis model maps semantic roles—not individual color literals—to attributes. Syntax keywords and types are bold; comments and decorators are italic or dim; invalid and conflicted states gain bold and, at the full level, underline. Inactive and disabled roles are dim.
When adding a renderer, clamp those roles to the target tool’s supported attributes and use the documented degradation rules. Never silently remove the only channel distinguishing two roles.
A palette is complete only when these generated outputs use it:
Consumer
Output
tmux and PowerKit
Chrome, panes, tabs, menus, status states
Vim
UI, syntax, search, selection, diffs
Yazi
Manager, tabs, modes, status, Git and file types
Starship
Prompt palette and decorations
LazyGit
Borders, selection, search and Git states
bat and delta
Generated TextMate theme and diff surfaces
fzf and eza
Color and attribute environment specifications
less/man
Terminal capability sequences
lnav
Native generated theme definition
OpenCode
Native generated JSON theme
Codex
Native generated TextMate theme in $CODEX_HOME/themes/aibox.tmTheme
Other AI TUIs
Their exposed native theme controls and terminal inheritance
Run the theme matrix tests after any dataset or mapping change. They assert that every exposed concrete Theme has audited palette, chrome, cursor, and selection values and that every generated renderer resolves without placeholders.
The gallery is reproducible from the design review and audited TOML:
bash
cd docs-site
npm install
cd ..
node scripts/generate-theme-catalog.mjs
The script exports all approved, Projectious, and accessibility variants from
the same TOML into docs-site/data/theme_catalog.json. Hugo renders the
catalogue and terminal specimens as responsive HTML.
Files below .aibox-home/ are managed output and are overwritten by aibox apply. For durable project-specific changes, extend the audited dataset and generator in source instead of patching generated files.
aibox ships four tmux layouts. Harness placement follows [ai].harness_order:
the 1st harness is the first enabled harness in that order, then the 2nd, 3rd,
and so on. Enabled harnesses missing from harness_order are appended in
canonical order.
Generated layouts can include an extended PowerKit status bar with host,
network, development, cloud, resource, and aibox runtime segments.
.aibox-local.toml is a personal, gitignored overlay that sits next to aibox.toml in the project root. It exists for secrets and per-developer settings that must never be committed to version control — API tokens, personal credential paths, and similar values that differ between contributors.
aibox.toml is committed and shared across the team. That’s the right place
for project-wide settings: container name, context mode, processkit version
when processkit is enabled, addons, shared environment variables, and so on.
But tokens and personal bind mounts don’t belong there. .aibox-local.toml
gives every developer a private escape valve without requiring .gitignore
discipline on every secret.
Inject environment variables into the container. These are merged on top of any [container.environment] values in aibox.toml. If the same key appears in both files, the local value wins.
aibox apply writes these values to the gitignored .aibox-local.env, which
Docker Compose loads into the container. The values therefore survive
container replacement and image rebuilds. They are still normal container
environment variables: processes running as the container user, including an
AI agent, can read them.
Personal bind mounts appended after any volumes declared in aibox.toml. Each entry requires source (host path) and target (container path). read_only defaults to false.
Personal MCP servers appended to the generated MCP client configs on aibox apply. Use this section for servers you want only on your machine — internal tools, local scripts, or servers that require credentials you don’t want to share.
Each server entry is an [[mcp.servers]] table with the same fields as committed [[ai.mcp.servers]] in aibox.toml:
aibox apply merges personal servers with team servers (from
aibox.toml [ai.mcp]) and, in processkit mode, built-in processkit servers,
then regenerates all MCP client config files. The generated files are
gitignored — they are never committed to version control, so personal keys
and server definitions stay private.
Choose the authentication model according to how much GitHub access the
container and its AI agents should receive. A narrowly scoped personal access
token (PAT) is the recommended default. An interactive GitHub CLI login is more
convenient, but may grant the container substantially broader access.
Grant this token only the repositories and permissions the project normally
needs. When one workflow needs access to another repository or organization,
add a second, purpose-specific variable instead of broadening the default
token. For example, a derived project can receive permission to report issues
to an upstream project without receiving wider upstream access:
The temporary assignment overrides GH_TOKEN for that invocation only. The
default token remains active for subsequent commands. Give the additional PAT
only the target repository’s Issues: read and write permission plus the
metadata access GitHub requires.
This arrangement makes the authorization boundary visible in both the local
configuration and the command. It also lets a human decide exactly which
rights are available to an AI agent in the container.
For a fine-grained PAT that targets an organization repository, select that
organization as the token’s resource owner and include the target repository.
Organization policy may require an administrator to approve the token. The
fact that the user can create an issue in a public repository through the
GitHub website does not automatically authorize a repository-scoped PAT to do
the same through the API.
--insecure-storage tells GitHub CLI to store its OAuth token in its config
file instead of a system keyring. In an aibox container that file is under
/home/aibox/.config/gh/, backed by the project’s gitignored
.aibox-home/.config/gh/ directory. It survives container restarts,
replacements, and image rebuilds. The token is a GitHub bearer credential; it
is not tied to a particular container ID or image.
Remove token environment variables first
GH_TOKEN and GITHUB_TOKEN take precedence over credentials saved by
gh auth login. To use the stored login, remove both variables from
.aibox-local.toml and from any other container environment configuration,
then run aibox apply to regenerate .aibox-local.env and recreate or restart
the container as needed.
Check the effective authentication inside the container with:
bash
env | grep -E '^(GH_TOKEN|GITHUB_TOKEN)='gh auth status
gh api user --jq .login
The first command should produce no output.
The stored OAuth token is plaintext in .aibox-home/.config/gh/hosts.yml.
Gitignore prevents accidental normal commits, but it does not encrypt the
credential or protect it from the host user, container processes, AI agents,
backups, malware, or an explicit git add --force. Treat .aibox-home/ as
secret-bearing local state. Prefer scoped PATs when the container should not
inherit the human user’s broader GitHub authority.
After editing .aibox-local.toml, run aibox apply (or aibox apply --no-build for a config-only refresh) to regenerate .devcontainer/ files with the updated environment and volumes, and MCP client config files with the updated server list.
When the aibox context schema evolves between versions, existing projects may
need to update their context files. The aibox doctor command helps identify
schema gaps and produces review artifacts under .aibox/migration/.
Separate processkit content and generated-runtime changes are surfaced as
Migration entities under context/migrations/ in processkit mode.
v0.16.0 — `context/AIBOX.md` is gone
Pre-v0.16 releases generated a context/AIBOX.md “universal baseline” file
on every aibox apply. That file has been removed as part of the
aibox⇄processkit split. The canonical agent entry document is now AGENTS.md
at the project root. In processkit mode it is rendered from processkit
scaffolding; in harness-only mode it is a minimal aibox-owned file. In both
modes aibox init writes it only when missing.
Existing projects upgrading to v0.16.0 can safely delete context/AIBOX.md.
Anything you wrote into it by hand should be moved into AGENTS.md,
context/DECISIONS.md, or one of the work-instructions files, depending on
its nature.
aibox.toml contains the target context schema version. Current
canonical processkit-mode configs render this under [processkit.context];
[context].schema_version is still accepted for compatibility:
toml
[processkit.context]schema_version="1.0.0"
aibox.lock records the aibox CLI/runtime state last applied to the
project. Legacy .aibox-version files from older projects are absorbed into
aibox.lock and removed by the migration path.
When aibox doctor detects a schema mismatch, it flags the project as needing
migration and writes schema review artifacts.
When processkit content, runtime-home drift, model/provider changes, or similar
processkit-mode updates need human review, aibox emits Migration entities in
context/migrations/:
text
context/
└── migrations/
├── pending/ # Migrations queued but not yet started
├── in-progress/ # Migration currently being applied
└── applied/ # Completed migrations (archived for reference)
Each processkit Migration is identified by a MIG-ID and lives as a versioned
document in the appropriate subdirectory. These Migration entities are managed
through the normal resource grammar:
bash
aibox get migration # show pending/in-progress migrationsaibox set migration <id> in-progress # begin a pending migrationaibox apply migration <id> # mark a migration as appliedaibox delete migration <id> --reason "…"# reject and archive without applying
Migrations are the durable fix for schema, vocabulary, filename, ID, and
directory-layout drift. A clean project should satisfy the current schemas and
storage policy directly, not by carrying project-local compatibility allowlists.
Do not resolve doctor findings by adding legacy_known_* schema entries,
doctor suppressions, mixed-layout exceptions, or local notes that accept legacy
event names, IDs, filenames, or directory shapes as the steady state. If a
schema genuinely needs a new value or layout, introduce that as an explicit
schema migration and then migrate existing entities and references to the new
standard.
Compatibility shims are acceptable only as short-lived migration aids. Before a
migration is marked applied, the repository should contain canonical values,
canonical filenames, canonical directory placement, and updated references.
Run aibox set migration <id> in-progress to move the migration to context/migrations/in-progress/
Follow the migration document’s checklist
Run aibox apply migration <id> to archive the migration to context/migrations/applied/
Review before applying
Migration artifacts describe structural changes. They do not migrate content. If a file is renamed, the artifact tells you to create the new file – but you need to move the content yourself (or have an AI agent do it thoughtfully).
Never auto-migrate content. Structural changes (new files, renames) can be automated. Content changes (rewriting sections, reformatting entries) should always be reviewed by a human or guided AI session.
Migrate forward, do not grandfather. Fix schema and storage drift by moving
entities to the current vocabulary, filenames, IDs, and directory layout.
Project-local allowlists and doctor suppressions are not acceptable terminal
states.
Commit before migrating. Always commit your current state before applying migration changes. This gives you a clean rollback point.
Run doctor after migrating. After applying changes, run aibox doctor again to confirm everything is clean.
Keep aibox.lock in version control. It records the resolved CLI,
processkit, addon, and managed runtime state shared by the project. A legacy
.aibox-version file is migration input only and is removed by aibox apply.
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.
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.
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.
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.
toml
[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/playwright4.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:
// tests/browser/home.spec.ts
import{test,expect}from"@playwright/test";importAxeBuilderfrom"@axe-core/playwright";test("home page is keyboard reachable and accessible",async({page})=>{awaitpage.goto("/");awaitexpect(page.getByRole("main")).toBeVisible();awaitpage.keyboard.press("Tab");constresults=awaitnewAxeBuilder({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-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.
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.
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.
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.
Quick reference for all tools in the aibox environment. Press the tab for the tool you need.
!!! tip “In-app help”
- tmux: The status bar always shows available keys for the current mode
- Yazi: Press ~ or F1 to see all keybindings
- Vim: Type :help for built-in help
- lazygit: Press ? to see context-sensitive keybindings when the optional git-ui addon is enabled
=== “tmux”
## tmux (Terminal Multiplexer)
Leader key: ++ctrl+b++ — press and release, then press the action key.
### Pane Navigation
| Key | Action |
|-----|--------|
| `Ctrl+g` `h` / `Left` | Focus pane left |
| `Ctrl+g` `j` / `Down` | Focus pane down |
| `Ctrl+g` `k` / `Up` | Focus pane up |
| `Ctrl+g` `l` / `Right` | Focus pane right |
### Pane Management
| Key | Action |
|-----|--------|
| `Ctrl+g` `n` | New pane (best direction) |
| `Ctrl+g` `d` | Split down |
| `Ctrl+g` `r` | Split right |
| `Ctrl+g` `x` | Close current pane |
| `Ctrl+g` `f` | Toggle fullscreen |
| `Ctrl+g` `e` | Toggle embed / floating |
| `Ctrl+g` `z` | Toggle pane frames |
| `Ctrl+g` `=` | Increase pane size |
| `Ctrl+g` `-` | Decrease pane size |
### Window Management
| Key | Action |
|-----|--------|
| `Ctrl+g` `t` | New window |
| `Ctrl+g` `w` | Close window |
| `Ctrl+g` `[` | Previous window |
| `Ctrl+g` `]` | Next window |
| `Ctrl+g` `1`..`5` | Jump to window by number |
| `Ctrl+g` `i` | Move window left |
| `Ctrl+g` `o` | Move window right |
### Scroll & Search
| Key | Action |
|-----|--------|
| `Ctrl+g` `u` | Enter scroll mode |
| `Ctrl+g` `/` | Search scrollback |
**In scroll mode:**
| Key | Action |
|-----|--------|
| `j` / `k` | Scroll down / up |
| `d` / `u` | Half-page down / up |
| `f` / `b` | Full page down / up |
| `g` / `G` | Top / bottom |
| `/` | Search |
| `q` or `Esc` | Exit scroll mode |
**In search mode:**
| Key | Action |
|-----|--------|
| `n` / `N` | Next / previous match |
| `c` | Toggle case sensitivity |
| `w` | Toggle wrap |
| `o` | Toggle whole word |
### Session
| Key | Action |
|-----|--------|
| `Ctrl+g` `s` | Session chooser |
| `Ctrl+g` `m` | Session manager |
### Quit
| Key | Action |
|-----|--------|
| `Ctrl+g` `q` | Quit tmux |
| `Ctrl+q` | Quit tmux (global) |
!!! info "Default layout windows"
The generated `dev` layout opens with pre-configured tmux windows:
**work** (Yazi, 1st harness, shell), optional **lazygit**,
**ai** for further harnesses, and **shell**. Window numbers shift when
optional windows are omitted.
=== “Yazi”
## Yazi (File Manager)
Yazi uses Vim-style navigation. The aibox config adds a few custom bindings on top of the defaults.
### Navigation
| Key | Action |
|-----|--------|
| `h` / `Left` | Go to parent directory |
| `j` / `Down` | Move cursor down |
| `k` / `Up` | Move cursor up |
| `l` / `Right` / `Enter` | Open file or enter directory |
| `g` `g` | Go to first item |
| `G` | Go to last item |
| `~` | Go to home directory |
### Opening Files (aibox custom)
| Key | Action |
|-----|--------|
| `Enter` | Open file in-place (suspends Yazi, `:q` returns) |
| `e` | Open in adjacent Vim pane (stays in Yazi) |
| `O` | Interactive opener selection |
| `w` `h` | Open a no-wrap pager; use arrow keys to scroll horizontally |
| `w` `v` | Open the file read-only in Vim for mouse/Visual selection; `y` copies the selection to tmux and the host clipboard |
### File Operations
| Key | Action |
|-----|--------|
| `a` | Create new file or directory (append `/` for directory) |
| `r` | Rename file |
| `d` | Trash selected files |
| `D` | Permanently delete selected files |
| `y` | Yank (copy) selected files |
| `x` | Yank (cut) selected files |
| `p` | Paste yanked files |
| `Space` | Toggle selection on current file |
| `v` | Visual mode (select range) |
| `V` | Invert selection |
| `c` `c` | Copy the hovered file's contents to the tmux and host clipboard |
### Search & Filter
| Key | Action |
|-----|--------|
| `/` | Search files in current directory |
| `f` | Filter files (fuzzy match) |
| `.` | Toggle hidden files |
### Preview & Tabs
| Key | Action |
|-----|--------|
| `Tab` | Switch preview pane |
| `t` | Create new tab |
| `1`..`9` | Switch to tab by number |
| `[` / `]` | Previous / next tab |
The embedded Yazi preview is a rendered widget rather than an editable text
buffer, so it cannot provide Vim-style character selection. Use `w v` for
selectable raw text, or enter tmux copy mode (`Ctrl+g` then `[`) to select
rendered terminal cells with the keyboard or mouse.
### Misc
| Key | Action |
|-----|--------|
| `z` | Jump to directory (zoxide) |
| `:` | Open command shell |
| `~` / `F1` | View all keybindings |
| `q` | Quit Yazi |
=== “Vim”
## Vim (Editor)
Leader key: `Space`
### Leader Commands
| Key | Action |
|-----|--------|
| `Space` `w` | Save file |
| `Space` `q` | Quit |
| `Space` `x` | Save and quit |
| `Space` `n` | Next buffer |
| `Space` `p` | Previous buffer |
| `Space` `l` | List buffers |
| `Space` `e` | Open netrw file explorer |
### Split Navigation
| Key | Action |
|-----|--------|
| `Ctrl+h` | Move to left split |
| `Ctrl+j` | Move to split below |
| `Ctrl+k` | Move to split above |
| `Ctrl+l` | Move to right split |
### Essential Motions
| Key | Action |
|-----|--------|
| `h` `j` `k` `l` | Left, down, up, right |
| `w` / `b` | Next / previous word |
| `0` / `$` | Start / end of line |
| `gg` / `G` | Top / bottom of file |
| `Ctrl+d` / `Ctrl+u` | Half-page down / up |
| `%` | Jump to matching bracket |
| `f{char}` | Jump to next {char} on line |
### Editing
| Key | Action |
|-----|--------|
| `i` / `a` | Insert before / after cursor |
| `I` / `A` | Insert at start / end of line |
| `o` / `O` | New line below / above |
| `dd` | Delete line |
| `yy` | Yank (copy) line |
| `p` | Paste after cursor |
| `u` / `Ctrl+r` | Undo / redo |
| `.` | Repeat last change |
| `ciw` | Change inner word |
| `>>` / `<<` | Indent / dedent line |
### Search
| Key | Action |
|-----|--------|
| `/pattern` | Search forward |
| `?pattern` | Search backward |
| `n` / `N` | Next / previous match |
| `Esc` `Esc` | Clear search highlight |
| `*` | Search word under cursor |
### Commands
| Key | Action |
|-----|--------|
| `:w` | Save |
| `:q` / `:q!` | Quit / force quit |
| `:wq` or `:x` | Save and quit |
| `:e <file>` | Open file |
| `:%s/old/new/g` | Find and replace in file |
!!! note "Dev-box Vim settings"
- Relative line numbers are enabled for fast `{N}j`/`{N}k` jumps
- Tabs expand to 4 spaces (2 for YAML, JSON, HTML, CSS, JS, TS)
- Trailing whitespace is stripped on save
- Persistent undo is enabled across sessions
=== “lazygit”
## lazygit (Git TUI)
lazygit is panel-based. Press `?` at any time to see context-sensitive keybindings.
### Panel Navigation
| Key | Action |
|-----|--------|
| `1` | Status panel |
| `2` | Files panel |
| `3` | Branches panel |
| `4` | Commits panel |
| `5` | Stash panel |
| `h` / `l` | Switch panels left / right |
| `j` / `k` | Move up / down within panel |
| `[` / `]` | Previous / next tab within panel |
### Files Panel
| Key | Action |
|-----|--------|
| `Space` | Stage / unstage file |
| `a` | Stage / unstage all files |
| `c` | Commit staged changes |
| `A` | Amend last commit |
| `d` | Discard changes to file |
| `e` | Edit file in editor |
| `o` | Open file in default application |
| `i` | Add to .gitignore |
| `S` | Stash all changes |
| `Enter` | Focus on file to see diff hunks |
### Branches Panel
| Key | Action |
|-----|--------|
| `Space` | Checkout branch |
| `n` | New branch |
| `d` | Delete branch |
| `M` | Merge into current branch |
| `r` | Rebase current branch onto selected |
| `R` | Rename branch |
| `f` | Fetch branch |
| `P` | Push |
| `p` | Pull |
### Commits Panel
| Key | Action |
|-----|--------|
| `s` | Squash commit into one below |
| `r` | Reword commit message |
| `R` | Reword with editor |
| `d` | Delete commit |
| `e` | Edit commit (interactive rebase) |
| `c` | Copy commit (cherry-pick) |
| `v` | Paste (cherry-pick) commit |
| `F` | Create fixup commit |
| `S` | Squash all fixup commits |
| `g` | Reset to this commit |
| `t` | Tag commit |
### Stash Panel
| Key | Action |
|-----|--------|
| `Space` | Apply stash (keep in list) |
| `g` | Pop stash (apply + remove) |
| `d` | Drop stash entry |
### Global
| Key | Action |
|-----|--------|
| `?` | Show keybindings for current panel |
| `+` | Show command log |
| `@` | Show command log menu |
| `P` | Push |
| `p` | Pull |
| `z` / `Ctrl+z` | Undo last action |
| `q` | Quit lazygit |
!!! tip "Accessing lazygit"
lazygit is available only when the optional `git-ui` addon selects
`lazygit`. In generated layouts, aibox adds it as a fullscreen **git**
tab after any AI-agent tabs.
Custom presets can be added to cli/src/themes.rs in the starship_config() function. Each preset is a Starship TOML template with color variables ({bg}, {fg}, {accent}, {green}) that are replaced with theme-specific values at generation time.
See the existing presets (default, plain, minimal, nerd-font, pastel, powerline-pastel, bracketed, arrow) as reference patterns.
Documentation addons install static site generators and documentation tools.
Addon
Tool
Install Method
docs-mkdocs
MkDocs + Material theme
uv
docs-zensical
Zensical
uv
docs-docusaurus
Docusaurus
npm
docs-starlight
Starlight (Astro)
npm
docs-mdbook
mdBook
Binary download
docs-hugo
Hugo Extended
Binary 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.
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).
aibox containers ship with Yazi preview configuration and can install
TUI-native preview tools for raster images, vector graphics, PDF, archives, and
video through optional addons. Several formats also support watch-mode
preview, where the rendered output updates automatically whenever the source
file changes.
When you open Yazi (Ctrl+g s from the file manager pane, or via the layout sidebar), files are previewed automatically in the right panel as you navigate. No manual invocation needed.
Raster image, SVG, PDF, archive, and standalone terminal viewers require the
preview-archive addon. SQLite, CSV/TSV, and Excel previews require the
data-preview addon. Markdown rendering, EPS, and video thumbnails require
the preview-enhanced addon, which depends on preview-archive:
bash
aibox set addon preview-archive enabled --apply # adds chafa, timg, poppler, mutool, entr, p7zip, resvgaibox set addon data-preview enabled --apply # adds sqlite3 and csvkit for data previewsaibox set addon preview-enhanced enabled --apply # adds python3-rich, ffmpeg, ghostscript
Custom plugins (svg.yazi, eps.yazi) live at ~/.config/yazi/plugins/<name>.yazi/init.lua. They are seeded into .aibox-home/.config/yazi/ on first aibox init.
SVG — converted to PNG by resvg, a fast standalone Rust-based SVG renderer bundled as a static binary in /usr/local/bin/resvg. The rendered PNG is cached under Yazi’s cache directory. If resvg is absent from PATH, the plugin fails gracefully and Yazi falls back to the text previewer.
EPS — rendered to PNG at 150 DPI by gs (Ghostscript), then displayed as an image. Result is cached.
Markdown — when the preview-enhanced addon is enabled, .md and .markdown files are rendered through rich-preview.yazi, which uses Python Rich for terminal-native Markdown rendering. Without the addon, Yazi falls back to its built-in text/code preview.
PDF — page 1 is rendered by pdftoppm (from poppler-utils). Navigate multi-page documents with Yazi’s built-in PDF plugin controls.
Wide text previews — the seeded Yazi keymap includes a pager shortcut for the selected file using less -R -S. -R preserves ANSI color from rich/code output; -S disables wrapping so long lines can be inspected with horizontal scrolling.
SQLite — sqlite-preview.yazi opens databases read-only through sqlite3 and shows schema objects plus table/view columns. It is enabled only when the data-preview addon is configured.
CSV / TSV / Excel — tabular-preview.yazi formats CSV/TSV with csvlook; .xls and .xlsx are converted with in2csv before formatting. It is enabled only when the data-preview addon is configured.
.excalidraw files — Excalidraw’s native format is JSON. A graphical preview is not possible in a TUI environment. Yazi falls back to the text previewer showing the raw JSON. This is a known limitation — Excalidraw requires a browser to render.
Image protocol inside tmux
Image preview support depends on the host terminal and tmux passthrough
settings. The generated Yazi config favors terminal-safe fallbacks inside tmux;
use half-block mode when you need predictable rendering across terminals.
chafa converts images to terminal graphics using Sixel, Kitty protocol, half-block Unicode, or plain ASCII, auto-detecting the best mode for the current terminal.
bash
# View any raster imagechafa photo.jpg
# Force half-block mode (safe inside tmux)chafa --format=halfblock diagram.png
# SVG via librsvg (if chafa was compiled with librsvg support)chafa --format=halfblock logo.svg
# Constrain to a specific cell sizechafa -s 80x40 banner.png
Supported formats: JPEG, PNG, GIF (animated), WebP, BMP, TIFF, AVIF, and more. SVG support depends on whether chafa was built with librsvg — run chafa --version and check for SVG: yes.
timg renders images, animated GIFs, videos, and PDFs (page by page) directly in the terminal.
bash
# View an imagetimg photo.jpg
# View a PDF — renders all pages sequentiallytimg document.pdf
# View a specific PDF page (page 2)timg -p2 document.pdf
# Constrain output sizetimg -g 120x40 wide-image.png
# Clear previous output before rendering (useful in watch loops)timg --clear output.pdf
Supported formats: JPEG, PNG, GIF (animated), WebP, BMP, TIFF, PDF (via MuPDF), video (via ffmpeg).
Watch-mode preview automatically re-renders a file whenever it changes on disk. This is particularly useful for LaTeX, Typst, and other document workflows where you write source in one pane and see the rendered output update in real time in another.
The pattern uses entr (an inotify-based file watcher) combined with a rasteriser and timg --clear:
Watches output.pdf for changes (inotify, near-zero CPU at idle)
mutool draw
MuPDF rasteriser — renders a PDF page to PNG (fast, no X11 needed)
-o /tmp/p.png output.pdf 1
Output file, input file, page number
timg --clear
Renders the PNG inline, clearing the previous frame first
Yazi also seeds a PDF live-watch binding for selected .pdf files. It invokes pdf-watch so you can start the same live preview directly from the file manager.
Tips:
Change the final 1 to preview a different page number.
To watch all pages: mutool draw -o /tmp/p-%d.png output.pdf (produces /tmp/p-1.png, /tmp/p-2.png, …); then timg --clear /tmp/p-*.png.
Add -r 150 to mutool draw for higher resolution (default is 72 DPI).
Use timg -g 120x40 to constrain the rendered size to fit a specific pane.
resvg converts the SVG to a high-fidelity PNG. Unlike Inkscape or rsvg-convert, resvg is a static binary with no runtime dependencies and typically renders in under 100 ms for typical diagrams.
In the dev or cowork layouts, open a new horizontal pane below the editor (Ctrl+g d) and run the watch command there. The preview refreshes in that pane every time you save. Use Ctrl+g = to resize the pane to taste.
Claude’s configuration, cache, and account state are persisted under .aibox-home/
and mounted into the container. aibox preserves Claude’s primary config directory
(.claude/), top-level account state (.claude.json), and XDG state/cache
locations used by current Claude Code releases.
Key files:
.claude/settings.json — Claude Code settings
.claude.json — Claude Code account/install state
.cache/claude*, .config/claude/, .local/share/claude/, .local/state/claude/ — Claude Code login and runtime state
.claude/projects/ — Per-project memory and context
.claude/skills/<name>/SKILL.md — generated processkit command shims when Claude is enabled in processkit mode
The generated .claude/skills/ entries are adapters. The canonical skill
instructions remain in context/skills/. Harness-only projects do not generate
processkit command shims.
Claude Code’s native MCP client reads .mcp.json. aibox generates .mcp.json automatically on aibox apply, merging processkit built-in servers in processkit mode, team servers from aibox.toml [ai.mcp], and personal servers from .aibox-local.toml [mcp].
.mcp.json is gitignored — it is regenerated on every aibox apply and must not be committed.
The generated devcontainer is standard Compose output, but the normal workflow
should go through aibox so generated files, runtime home state, and diagnostics
stay aligned.
aibox up creates or starts the container and attaches through tmux. Use
--layout for a one-session layout override. Use --apply when you want aibox
to reconcile configuration before starting.
Use --no-cache after base-image, addon, or package-cache issues. --rebuild
is kept as a visible alias for the same behavior. Use --config-only when you
only want to regenerate files, and in processkit mode refresh processkit
content, without building the image. In harness-only projects,
--config-only regenerates config/runtime surfaces without processkit content
work.
aibox get runtime
aibox get runtime --resources
aibox get runtime --resources -o json
aibox describe runtime
The resource snapshot is designed for low-dependency environments. It reads
cgroupfs and procfs directly instead of relying on tools such as ps or free
being installed.
Key fields:
Field
What it tells you
memory_current_bytes
current cgroup memory usage
memory_max
memory limit or unlimited
oom_kill_count
whether the kernel has killed a process in the cgroup
total_process_count
total visible processes
processkit_mcp_python_process_count
live Python processkit MCP server processes
An oom_kill_count above zero is strong evidence that a missing agent or
terminated tool was killed by the operating system rather than by the CLI.
With current processkit releases, [ai.mcp.gateway].mode = "auto" registers a
processkit-gateway stdio proxy for MCP-capable harnesses. The proxy starts the
local gateway on demand when no listener exists, so generated devcontainer
startup no longer has to supervise one Python process per skill in the default mode.
Use separate only when a harness needs the older one-server-per-skill layout.
Harness-only projects do not register the processkit gateway.
aibox apply rewrites generated files, but it does not magically replace a
running container that was created from older Compose output. Recreate the
runtime when a change affects process model, mounts, image labels, init
behavior, or service identity:
bash
aibox down
aibox apply
aibox up
If a container has already accumulated zombie processes, the fix is still a
runtime recreate. A new generated init: true service can reap future orphaned
children, but it cannot change PID 1 in an already-created container.
Podman support depends on the Compose provider behind podman compose.
Generated files follow the Compose Specification, including init: true.
If an older provider rejects a spec key, upgrade the provider instead of
removing the generated setting.
Gemini CLI reads .gemini/settings.json. aibox generates this file automatically on aibox apply, merging processkit built-in servers in processkit mode, team servers from aibox.toml [ai.mcp], and personal servers from .aibox-local.toml [mcp].
.gemini/settings.json is gitignored — it is regenerated on every aibox apply and must not be committed.
To add MCP servers:
toml
# aibox.toml — team-shared servers[[ai.mcp.servers]]name="github"command="npx"args=["-y","@modelcontextprotocol/server-github"]# .aibox-local.toml — personal servers[[mcp.servers]]name="my-internal-tool"command="npx"args=["-y","@acme/internal-mcp-server"]
The ai-mistral addon installs the mistralai Python SDK, not an interactive coding CLI. It is intended for projects that call the Mistral API programmatically. For an interactive coding experience, use Claude, Gemini, OpenAI Codex, or Copilot instead.
Mistral AI provides large language models via Python SDK.
mistral is retained as a legacy harness value for old configs, but it is not
a current interactive CLI harness. Use the addon directly for SDK installs.
Run aibox apply. Inside the container the mistralai Python SDK is available
for scripting:
aibox generates .mcp.json (the Claude Code MCP format) on aibox apply when a compatible harness is enabled, merging processkit built-in servers in processkit mode, team servers from aibox.toml [ai.mcp], and personal servers from .aibox-local.toml [mcp]. A custom Mistral SDK-based tool you build can read MCP server registrations from this file.
.mcp.json is gitignored — it is regenerated on every aibox apply and must not be committed.
aibox maintains the v0.x and v1.x lines in parallel. A fix landing on either
line must be reconciled with the other line when applicable.
The release gate compares both maintained branches after the recorded
enforcement baselines in .github/version-line-port-baselines.toml. Every
non-merge source commit must have a matching port on the target line or an
explicit not-applicable disposition. This derives obligations from Git history,
so it does not depend on labels, manually created issues, or workflow tokens.
When the equivalent change lands on the other line, add this commit trailer:
The target line’s release gate recognizes and settles the matching obligation.
When a change genuinely cannot or should not cross lines, document the reason
in the commit body and add:
text
Version-Line-Port: not-applicable
Use not-applicable only for line-specific version metadata, generated release
artifacts, or code that does not exist on the other line. Do not use it to defer
an applicable fix.
Codex’s home-directory state is persisted in .aibox-home/.codex/, mounted at /home/aibox/.codex/. This survives devcontainer rebuilds, so device sign-in only needs to be completed once per host cache unless you clear it.
Key files:
.aibox-home/.codex/auth.json — cached ChatGPT/device authentication reused across rebuilds
.aibox-home/.codex/rules/ — home-directory Codex rules and local state
.aibox-home/.codex/sessions/ — Codex session history
Separately, aibox also generates project-local .codex/config.toml MCP server registration. In processkit mode it also generates .codex/hooks.json processkit hook configuration.
After aibox apply, processkit workflows are available through both Codex
invocation surfaces:
Type $pk-resume, $pk-doctor, and similar names to invoke the generated
project skills under .agents/skills/. You can also select them through
/skills.
Type /prompts:pk-resume, /prompts:pk-doctor, and similar names to use the
generated custom-prompt aliases persisted under
.aibox-home/.codex/prompts/.
Codex reserves top-level slash commands and does not support registering a
custom /pk-resume command. Custom prompts always use the /prompts:
namespace. Restart the Codex session after the first aibox apply if newly
generated prompt aliases do not appear immediately.
Codex has a native MCP client. aibox generates .codex/config.toml automatically on aibox apply, merging processkit MCP entries in processkit mode, team servers from aibox.toml [ai.mcp], and personal servers from .aibox-local.toml [mcp]. With current processkit releases and [ai.mcp.gateway].mode = "auto", Codex uses the processkit-gateway stdio proxy instead of one Python process per skill.
.codex/config.toml and .codex/hooks.json are gitignored — they are regenerated on every aibox apply and must not be committed.
To add MCP servers:
toml
# aibox.toml — team-shared servers[[ai.mcp.servers]]name="github"command="npx"args=["-y","@modelcontextprotocol/server-github"]# .aibox-local.toml — personal servers[[mcp.servers]]name="my-internal-tool"command="npx"args=["-y","@acme/internal-mcp-server"]
aibox images include Debian’s bubblewrap package so Codex can use the OS-provided Linux sandbox helper instead of falling back to its vendored copy. Codex still needs the container runtime and host kernel to allow unprivileged user namespaces; if namespace creation is blocked, Codex can start but sandboxed shell commands fail before the project command runs.
The preferred fix is to enable unprivileged user namespaces on the host or container runtime. Avoid privileged: true and avoid adding SYS_ADMIN to the main development container for Codex; those grants are broader than Codex’s bubblewrap sandbox requires. When Codex is selected, generated docker-compose.yml includes a narrow security_opt: seccomp=unconfined fallback because Docker/Podman seccomp profiles can block bubblewrap before the project command runs:
This does not grant privileged or SYS_ADMIN; it only relaxes the runtime syscall filter enough for user-namespace creation. Keep Codex in workspace-write with approvals.
aibox doctor checks the Codex sandbox posture when Codex is selected. It
verifies that bwrap/bubblewrap is available, runs a user-namespace smoke
probe that matches Codex’s sandbox requirement, warns if the generated service is missing Compose init: true, and
warns if the main aibox service uses broad grants such as privileged: true or
SYS_ADMIN.
GitHub Copilot CLI reads .mcp.json (the Claude Code MCP format). aibox generates .mcp.json automatically on aibox apply, merging processkit built-in servers in processkit mode, team servers from aibox.toml [ai.mcp], and personal servers from .aibox-local.toml [mcp].
.mcp.json is gitignored — it is regenerated on every aibox apply and must not be committed.
To add MCP servers:
toml
# aibox.toml — team-shared servers[[ai.mcp.servers]]name="github"command="npx"args=["-y","@modelcontextprotocol/server-github"]# .aibox-local.toml — personal servers[[mcp.servers]]name="my-internal-tool"command="npx"args=["-y","@acme/internal-mcp-server"]
Continue has a native MCP client with a per-server file model. aibox generates files in .continue/mcpServers/ (one file per server) automatically on aibox apply, merging processkit built-in servers in processkit mode, team servers from aibox.toml [ai.mcp], and personal servers from .aibox-local.toml [mcp].
.continue/mcpServers/ is gitignored — it is regenerated on every aibox apply and must not be committed.
To add MCP servers:
toml
# aibox.toml — team-shared servers[[ai.mcp.servers]]name="github"command="npx"args=["-y","@modelcontextprotocol/server-github"]# .aibox-local.toml — personal servers[[mcp.servers]]name="my-internal-tool"command="npx"args=["-y","@acme/internal-mcp-server"]
Continue CLI is installed via npm (npm install -g @continuedev/cli).
Agent attention titles
When an AI harness needs a human response, aibox can mark the tmux window in
the terminal tab title. This is useful when the agent is running in a
background pane or another tmux window: the title remains visible even when
that pane is not selected.
[customization.tmux.title]enabled=trueformat="{state_symbol}{project}:{window} — {directory}"max-length=60directory-style="basename"done-ttl-seconds=10message-max-length=32[customization.tmux.title.states]working="● "question="❓ "done="✓ "error="! "idle=""[customization.tmux.notifications]enabled=falseprotocol="osc-9"# or "bell"states=["question","error"]include-message=true
enabled = false disables generated title settings. The default title is
short and project-oriented; use a custom format when session or harness
identity is more useful than the directory:
State name: idle, working, question, done, or error
{project}
aibox project name
{session}
tmux session name
{window} / {window_index}
tmux window name or index
{pane}
active pane index
{directory}
Current directory in the selected directory style
{directory_path}
Full current-directory path
{repository} / {branch}
Git repository and branch, when available
{harness} / {agent}
Harness and agent identity, when supplied
{agent_suffix}
Conditional — agent@harness, — harness, or empty suffix
{task} / {message}
Short task or question/error text, sanitized and bounded
{elapsed}
Elapsed time captured at the most recent state aggregation
Use {agent_suffix} when the same format applies to both agent and non-agent
windows. It includes its own separator and omits the entire suffix when no
harness is active, avoiding dangling punctuation:
toml
format="{state_symbol}{repository}{agent_suffix}"
repository-style controls the value of {repository}:
The full form is derived from the configured Git remote path, not from a
forge API. It therefore works with HTTPS and SSH remotes on GitHub, GitLab,
Gitea, Forgejo, and compatible self-hosted instances. Nested namespaces are
preserved (for example, group/platform/repository). If no usable remote is
configured, both styles fall back to the repository root directory name.
The full form appends the active reasoning-effort level when the harness
exposes one reliably. Codex resolves both values from current local thread
metadata, Claude reads its hook payload and transcript, Gemini reads the
documented BeforeModel request, and OpenCode reads model-bearing plugin
events. Copilot and Cursor consume model metadata when their hook payload or
transcript provides it. Aider, Continue, Hermes, and Tau use their launch-time
configuration as a guarded fallback; an explicit runtime signal supersedes it
after an in-session model switch.
Every harness can also supply an exact runtime identity with --agent MODEL --effort LEVEL or the AIBOX_AGENT_NAME and
AIBOX_AGENT_REASONING_EFFORT environment variables.
{harness} remains the CLI harness reporting the lifecycle event. Explicit
arguments and environment variables take precedence over automatic detection.
State is aggregated across all panes in the window. The precedence is
error > question > working > done > idle, so a question in a background
pane cannot be hidden by an idle active pane. Completion markers are temporary
and use done-ttl-seconds.
prompt, permission/elicitation, stop, error, session end
Cursor
Partial
prompt and stop
Gemini and Codex classify an after-turn response ending in a question mark as
question. OpenCode uses its explicit question.asked, question.replied,
and question.rejected events. Copilot reports permission and elicitation
dialogs as questions; its stop payload does not expose final response text.
Codex permission replies resume the current turn without submitting a new
prompt, so aibox also maps Codex pre- and post-tool lifecycle events to
working; this clears the question marker when approved work continues.
aibox does not infer a question from process idleness. For a harness without a
question hook, signal it explicitly, for example:
sh
aibox-agent-signal question --harness my-harness --message 'Choose an option'aibox-agent-signal working --harness my-harness
aibox-agent-signal done --harness my-harness
Signals are scoped to the current tmux pane and are safe to repeat. Outside
tmux they are a no-op, so the same wrapper can be used in and out of aibox
workspaces without affecting the terminal.
Terminal emulators normally display the title emitted by tmux through the
standard title control sequence. Do not configure a competing fixed tab title
for an aibox tab. Inside tmux, tmux should be the sole title writer; otherwise
a shell precmd hook can overwrite the attention marker. This title path does
not depend on Ghostty or any other specific terminal emulator.
If you currently set the title from zsh, keep that behavior outside tmux only:
osc-9 for a message-bearing desktop notification on supporting terminals, or bell for the portable terminal attention signal
states
State transitions that trigger a notification; supported values are working, question, done, error, and idle
include-message
Include the sanitized question/error text when available (default true)
Notifications are emitted only from inside tmux and only on aggregate state
transitions. OSC 9 is supported by terminals including Ghostty and iTerm2 but
is not universal; choose bell when portability matters and configure the
terminal’s bell attention behavior as desired. Title rendering remains
independent and non-fatal if notifications are unavailable.
Agent-provided messages are stripped of terminal control characters and
truncated to message-max-length, then the complete title is bounded by
max-length. This prevents task text or a question from injecting terminal
escape sequences.
Each aibox release is tested against a specific processkit version. The table
below shows the minimum compatible processkit version for each aibox release.
aibox version
Min. processkit
Notes
0.34.2
v0.28.8
publishes the generated theme gallery and chooser, aligns terminal themes with the design reference, reliably clears answered Codex question state, and improves active tmux pane visibility
0.34.1
v0.28.8
expands theme palettes across the managed terminal toolchain, adds exact Codex syntax themes, restores the visual theme gallery, and clears Codex question state after permission answers
0.34.0
v0.28.8
adds configurable agent-aware tmux headers and replaces the legacy documentation stack with the projectious.work Hugo brand theme
0.33.2
v0.28.8
updates the default processkit release to v0.28.8, refreshes generated runtime metadata for Codex 0.148.0, and reconciles the completed live tmux layout and theme switching work
0.33.1
v0.28.6
restores generated AI harness startup under nounset, keeps Yazi directory previews compatible across supported image pins, and aligns PowerKit plugin spacing with window tabs
0.33.0
v0.28.6
adds configurable, terminal-neutral tmux titles and lifecycle attention signals for AI harness panes, with optional notifications
0.32.6
v0.28.6
refreshes curated tool pins, including Go 1.26.6, and routes every Yazi copy action through the tmux and host clipboard bridge
0.32.5
v0.28.6
embeds the canonical addon catalog so stale host installs cannot hide shipped tools, refreshes same-version installs, and adds Yazi/Vim clipboard and selectable-preview workflows
0.32.4
v0.28.6
keeps latest image resolution on the active v0 line, refreshes generated addon comments when the catalog changes, and fixes stale or collapsed Yazi Markdown previews
0.32.3
v0.28.6
makes the axe host fixture accessibility-clean and records structured violation diagnostics when a future browser probe fails
0.32.2
v0.28.6
uses an explicit Playwright BrowserContext for axe host validation and makes safe release-host caches and candidate-bound retries available by default
0.32.1
v0.28.6
makes the browser-testing host gate launch the full Chromium channel installed by Playwright --no-shell instead of requesting the omitted headless-shell executable
0.32.0
v0.28.6
adds a pinned Chromium-first Playwright and axe browser-testing addon with optional Firefox/WebKit, live release-host browser evidence, and a cleaner full-width Textual release dashboard
0.31.5
v0.28.6
retries transient OpenCode release downloads and makes Textual yanks selection-aware while preserving actionable failed-task diagnostics
0.31.4
v0.28.6
makes Hugo downloads resilient to transient network failures, improves the release-host Textual problem workflow, and serializes contention-sensitive E2E gates
0.31.3
v0.28.6
adds a locked Textual dashboard and reviewed content-addressed cache reuse to the restricted macOS host gate
0.31.2
v0.28.6
replaces privileged companion E2E coverage with isolated local contracts and an owner-controlled, evidence-producing macOS host gate
0.31.1
v0.28.6
repairs incomplete processkit upgrade caches, installs declared skill dependencies, removes stale pk-* command projections, and consumes source-specific MCP header manifests
0.31.0
v0.28.5
adds optional rootless Podman and Podman Compose tooling to the infrastructure addon, documents the Go supply-chain and release bundles, and repairs minimal infrastructure addon rendering
0.30.1
v0.28.5
refreshes the companion E2E contract, repairs Starship cache isolation, resolves Codex latest pins before container builds, and updates security-relevant pnpm and Tau curated defaults
0.30.0
v0.28.5
adds nested language addon groups, production Go quality tooling, and language-neutral supply-chain and release bundles with pinned versions, checksum verification, and per-tool overrides
0.29.0
v0.28.5
adds Tau as a first-class multi-provider coding-agent harness with pinned installation, persistent runtime state, AGENTS.md discovery, Agent Skills projection, and explicit reporting that Tau does not currently expose a built-in MCP client
0.28.19
v0.28.5
preserves prerelease identifiers when resolving the latest published GHCR image so v1.0.0-alpha.1 is not rewritten to the nonexistent v1.0.0 tag
0.28.18
v0.28.5
restores Codex processkit MCP startup by preserving uv run --script in gateway daemon-proxy commands, integrates processkit’s MCP 1.x compatibility bound, and restores zero-warning clippy under Rust 1.97
0.28.17
v0.28.4
repairs Go, Typst, AWS CLI, and Node.js add-on installers and adds a clean companion-container build gate for download-based add-on defaults
0.28.16
v0.28.4
installs Node.js from checksum-verified official release archives after the NodeSource signing-key endpoint became unavailable and refreshes generated runtime and processkit package-selection state
0.28.14
v0.28.4
ensures pk-reconcile and pk-repo-reconcile install their project-reconciliation and repo-management skill dependencies
0.28.15
v0.28.4
refreshes bundled maintenance tools, locks cargo-audit installation for Rust compatibility, and publishes the Hugo/Docsy documentation site
0.28.13
v0.28.4
adds open GitHub Discussion counts to the tmux Forge status segment and restores the complete generated Codex command projection set
0.28.12
v0.28.4
integrates processkit v0.28.4 and makes companion E2E validation work from linked release worktrees
0.28.11
v0.28.3
adds the cloudflare addon, which installs cloudflared from Cloudflare’s signed package repository rather than Debian’s archive
0.28.10
v0.28.3
reconciles standard processkit skills, recommends tooling-linked skills interactively, upgrades prerelease processkit surfaces, and serializes release Tier 2 E2E validation
0.28.6
v0.28.3
fixes Kubernetes addon checksum verification for Helm, Kustomize, and k9s archives on amd64 and arm64; and integrates processkit v0.28.3 authenticated GitHub repository reconciliation
0.28.5
v0.28.1
fixes Hermes Agent installation under the non-root runtime model; restores configured lazygit runtime surfaces; completes processkit reconciliation; and enforces traceable ports between maintained v0.x and v1.x lines
0.28.4
v0.28.1
integrates processkit v0.28.1 and refreshes the maintained v0.x processkit compatibility baseline
0.28.3
v0.27.6
integrates processkit v0.27.6; makes GitHub CLI authoritative for github.com HTTPS credentials; exposes exact GitHub SSH aliases through Forge; and preserves LaTeX preview state across rebuilds
restores Codex processkit aliases through /prompts:pk-*; adds local fuzzy documentation search; moves LaTeX build and watch ownership into the development container; and adds a hardened read-only, multi-document preview sidecar with full lifecycle coverage
0.28.0
v0.27.4
adds named LaTeX build, watch, status, and EmbedPDF live-preview workflows; manages preview lifecycle through aibox up/down; generates project-local agent guidance; and documents persistent, least-privilege GitHub authentication with explicit per-destination tokens
fixes the TeX Live historic installer mirror, resolves pk-doctor false positives, preserves disabled harness state, and accepts context mode in schema validation
0.27.6
v0.27.1
refreshes tool and harness pins, updates generated runtime/docs references, and adds the GitHub CLI credential-helper integration for HTTPS Git operations
0.27.5
v0.27.1
refreshes the shipped docs-hugo pin to Hugo 0.162.1 and aligns release-state/docs inventory with the current addon and harness defaults from v0.27.4
0.27.4
v0.27.1
refreshes all shipped addon and harness tool defaults to current upstream releases; fixes Yarn 4 and Python 3.14 installation paths; moves Hermes to the current hermes-agent package installer; updates Rust/docs dependencies; and quiets actionable pk-doctor false positives while making release-integrity checks bounded
0.27.3
v0.27.1
integrates processkit v0.27.1 derived-project health cleanup, including quieter pk-doctor sensitive-data checks, gateway-aware preauth validation, sqlite-vec availability for pk-doctor MCP runs, supply-chain policy no-policy INFO handling, and a Codex processkit-gateway startup timeout so uv-backed gateway startup does not trip Codex’s 30-second default
0.27.2
v0.27.0
fixes the docs-hugo addon checksum verification so Hugo archives downloaded to /tmp/hugo.tar.gz are checked against the matching release checksum entry instead of the upstream asset filename
0.27.1
v0.27.0
refreshes addon and user-facing toolchain pins, including documentation generators, language package managers, infrastructure tooling, Kubernetes tools, Helm, and OpenCode; adds release-state coverage for addon pins plus LaTeX and apt-managed inputs; keeps Python interpreter selection tied to the Debian base image package set; fixes OpenCode release asset naming and checksum verification; updates docs-site dependencies and clears npm audit findings
0.27.0
v0.27.0
integrates processkit v0.27.0 and the v0.26.17 supply-chain audit surface; switches the next-minor GHCR image scheme to foundation/runtime tags, stops publishing public source-hash marker tags, preserves legacy base-debian-v0.26.x compatibility, adds GHCR source-tag cleanup tooling, adds release LICENSE guardrails, and fixes pasted host newlines by removing global tmux C-j navigation
0.26.8
v0.26.16
integrates processkit v0.26.16; refreshes the processkit template mirror, provenance, MCP manifest, TeamMember privacy defaults, and team consistency checks; makes latest image resolution skip GHCR tags whose multi-arch manifest children have been pruned
0.26.7
v0.26.15
integrates processkit v0.26.15; adds provider-neutral AI execution policy axes and per-harness overrides, maps execution policy to Codex settings, preserves the processkit MCP manifest in derived installs, and refreshes documentation recordings
0.26.6
v0.26.14
integrates processkit v0.26.14; updates processkit metadata to the new release and preserves tmux/Vim/cheatsheet and clipboard behavior consistency
0.26.5
v0.26.13
re-architects theme selection around theme families plus mode/variant, adds the 61-theme gallery and per-theme recordings, ships PowerKit/cheatsheet/runtime theme fixes, and preserves legacy concrete theme intent during standardization
0.26.4
v0.26.10
integrates processkit v0.26.10; makes explicit tmux model-provider status elements render even without global provider polling; preserves Claude Code OAuth/state across container rebuilds via Claude XDG cache/config/state mounts; enables terminal extended-key passthrough for Alt-Enter; adds PowerKit GitHub issue/PR counts; and fixes aibox-status AI agent counting so vendor helper processes do not inflate provider instance totals
0.26.3
v0.26.9
fixes GHCR latest-version resolution by requesting larger tag-list pages and following Docker Registry v2 pagination links so freshly-published images are visible to aibox apply
0.26.2
v0.26.9
fixes duplicate [customization.tmux.status] table parsing, routes tmux helper scripts through the managed socket, removes structurally broken capture-pane visual tests, and keeps visual layout/theme work tracked for asciinema coverage
refreshes themes, live tmux layout/theme choosers, Yazi rich preview, Vim Alt-key handling, model-provider agent counts, statusline structure, and processkit v0.26.7 integration
0.25.14
v0.26.5
integrates processkit v0.26.5; restores generated and image fallback Alt-word movement in Vim/readline; adds managed .inputrc runtime projection; carries tmux clipboard/terminal feature improvements into generated and image fallback configs; keeps Rust cache mounts from shadowing image-provided cargo/rustc shims; and keeps the stricter processkit schema/file-layout migration path clean under pk-doctor
0.25.13
v0.26.2
fixes stale runtime-home propagation by making aibox-managed .aibox-home files authoritative on apply and clean runtime recreation; broadens generated runtime mounts for Vim and Cargo cache directories; updates generated compose/docs coverage; and adds regression coverage for stale tmux/Yazi managed file refresh
0.25.12
v0.26.2
fixes fresh-project tmux/PowerKit runtime projection by using broad writable runtime-home mounts, refreshing managed theme/Yazi/Codex files on apply, scoping preauth/MCP writes to enabled harnesses, recognizing nested processkit skill catalogs in doctor, and reducing host-side doctor probes for container-owned dependencies
0.25.11
v0.26.2
fixes source-checkout addon discovery, PowerKit status cache writability, generated runtime writability diagnostics, disabled-harness migration schema metadata, and tmux/Yazi status glyph defaults
0.25.10
v0.26.2
integrates processkit v0.26.2; adds configurable tmux status labels/layouts and model-provider health segments; reduces PowerKit refresh churn; stabilizes runtime MCP diagnostics; verifies release checksum sidecars; and improves image layer/cache reuse across apply/up and host release publishing
0.25.9
v0.26.1
integrates processkit v0.26.1; retires yazi-omp runtime support; migrates tmux status configuration to list-based slot ordering; preserves user-selected themes during standardization; suppresses Kubernetes/cloud PowerKit auth/probe flashes; and improves Yazi directory git status behavior
0.25.8
v0.26.0
improves the tmux log viewer, filters aibox log counts to the current container session, emits low-volume diagnostics sidecar lifecycle samples, moves PowerKit metrics into the owner-specified two-row layout, and updates generated tmux layouts around ordered harness semantics
0.25.7
v0.25.8
introduces generated-container cleanup controls, prunes SSH companion nested runtime state around Tier 2 E2E tests, adds aibox prune, and documents managed runtime cleanup policy
0.25.6
v0.25.8
expands tmux/PowerKit theme coverage with light/dark partner handling, generated theme comments, Docusaurus theme documentation, and runtime border/status color improvements
0.25.5
v0.25.8
refreshes managed tmux runtime files when recreating sessions so aibox.toml status/layout settings take effect, preserves the delayed Yazi pane startup path, and suppresses stale default-socket tmux kill-session noise on host attach
0.25.4
v0.25.8
repairs tmux release-host smoke probing after the managed tmux socket migration and fixes generated tmux status-right rendering by preserving the aibox runtime status segment
0.25.3
v0.25.8
fixes Yazi e editor handoff for tmux by targeting the existing Vim pane/window, documents tmux status modes and element toggles, makes skill-finder discover deselected skills from the template catalog, and tightens SSH companion guidance
0.25.2
v0.25.8
adds tmux-native prefix ? keybinding popup, upgrades the two-line PowerKit status with pane context/mode detail, labels status metrics in aibox-status, fixes startup layout targeting by selecting named tmux windows instead of $session:1, extends release/runtime caching behavior, and documents provider endpoint base URL hints (ANTHROPIC_BASE_URL, OPENAI_BASE_URL, GEMINI_BASE_URL, MISTRAL_BASE_URL)
0.25.0
v0.25.8
replaces the prior multiplexer runtime with tmux-native layouts and status, keeps the diagnostics sidecar and visual testing gates, documents TPM as a user convenience layer only, preinstalls and pins aibox-managed tmux plugins, and ships tmux-resurrect/tmux-continuum installed but disabled by default until persistence policy is decided
0.24.1
v0.25.8
fixes generated compose so the main service starts with the image default root entrypoint user again, allowing entrypoint.sh to remap/drop to aibox instead of failing with failed switching to "aibox": operation not permitted during release-host runtime smoke
0.24.0
v0.25.8
adds the bounded diagnostics sidecar, replaces the shell fan-out aibox-status helper with Rust snapshot readers, wires sidecar-backed Zellij status rows, adds aibox emergency <harness>, keeps legacy native/hidden status aliases while emitting sidecar/disabled, and reduces host release smoke to a minimal default tier with opt-in addon/full tiers
0.23.21
v0.25.8
repairs generated Yazi git/status initialization for Yazi 26; preserves native Zellij plugin permission caches across runtime starts; adds doctor and E2E guardrails for native Zellij permission-cache projection drift; installs the Yazi ya companion entrypoint in runtime images; slims visual E2E release gates with per-case progress logging and an opt-in exhaustive matrix
0.23.20
v0.25.8
makes the release runtime smoke harness host-safe by defaulting to shell Zellij status mode, capturing raw TUI output into logs instead of streaming escape sequences to the host terminal, and asserting on structured probe markers rather than terminal transcripts
0.23.19
v0.25.8
hardens generated runtime startup by keeping Vim eager while disabling its startup cursor-position probe; removes suspended generated AI panes; pre-seeds native Zellij plugin permissions; fixes service-specific Codex bubblewrap seccomp fallback; updates Yazi git/preview config; adds generated-runtime and opt-in visual E2E release gates
0.23.18
v0.25.8
updates generated Yazi config and theme filetype rules for Yazi 26’s url/mime matcher schema; provides writable XDG state mounts for lazygit and similar TUIs; records follow-up runtime diagnostics and host-phase runtime smoke work
0.23.17
v0.25.8
installs Claude Code from Anthropic’s signed apt repository with a stable /usr/local/bin/claude path; makes the native aibox Zellij status/key-hint plugin the generated default; starts shell and lazygit tabs hot across layouts; refreshes Zellij, Yazi, uv, and Cargo dependencies; improves release-state reporting and harness version-pin support
0.23.16
v0.25.8
moves Claude processkit command shims to Claude Code’s current Skills layout, cleans legacy managed .claude/commands files, fixes native Zellij key-hint rendering, keeps Vim editor panes hot for Yazi edit handoff, and adds a pre-release dependency/harness state report
0.23.15
v0.25.8
fixes a 0.23.14 --standardize-config regression where a blank [ai.harness.<name>] table could re-enable a commented-out harness; standard config rewrites also restore the standard processkit skill list instead of leaving every skill commented
0.23.14
v0.25.8
canonical generated aibox.toml now uses [ai.harness.<name>] tables instead of the compact harness list; aibox apply --standardize-config performs an opt-in schema-clean canonical rewrite; stale/deprecated generated comments were removed; Yazi e again opens files in the dedicated Vim pane/tab
0.23.13
v0.25.8
fixes 0.23.11-to-0.23.12 generated-config upgrades where a moved tool, such as gh, still sits under its old addon owner; aibox apply now migrates misplaced addon tool entries to their unique current catalog owner before strict validation and comment refresh
0.23.12
v0.25.8
processkit v0.25.8 Xiaomi MiMo model-routing content and cleanup-hint provenance, native aibox Zellij key/status bar refinements, semantic AI/audio config sections, stable Claude CLI install path, addon tool validation, and stale processkit-managed skill detection
0.23.11
v0.25.7
grouped aibox.toml schema around aibox, container, processkit, and ai sections; catalog-style AI harness/model-provider controls; generated path settings; product skill defaults; and managed Zellij status runtime repair
restores shell-backed Zellij status rows as the default, hardens aibox-status against /proc races, fixes Yazi edit actions, applies addon dependency fallback handling to aibox up, and integrates processkit v0.25.6 provider-neutral pk command projections
0.23.8
v0.25.5
native aibox Zellij status plugin now exports the literal WASM entrypoints Zellij loads, uses theme-default readable foreground text, and has no-container E2E coverage for the load/visibility regression
0.23.7
v0.25.5
host-generated Codex processkit-gateway MCP paths now target the devcontainer workspace mount, preserving subagent-safe absolute paths without leaking host-only paths; doctor warns about stale host-side Codex MCP script paths
0.23.6
v0.25.5
processkit v0.25.5 active interlocutor runtime binding, subagent MCP lifecycle guardrails, Codex MCP path fixes, addon fallback migrations, doctor schema/runtime-template diagnostics, lazygit-disabled cleanup, native Zellij status visibility, and stronger E2E coverage
0.23.5
v0.25.4
generated Dockerfile lazygit disablement cleanup no longer aborts when lazygit is absent as an apt package, while still removing inherited lazygit binaries
0.23.4
v0.25.4
processkit v0.25.4 gateway stdio-proxy daemon startup fixes, Codex pre_tool_use hook generation, Zellij status presentation control, and stale status-layout runtime sync repair
0.23.3
v0.25.3
processkit v0.25.3 model-spec/model-profile migrations and Codex seccomp fallback for bubblewrap
0.23.2
v0.25.1
processkit v0.25.1 model-recommender lifecycle metadata, task suitability classes, task-class-aware routing, and refreshed model roster
0.23.1
v0.25.0
stale runtime cleanup for old Compose project names, lazygit disablement fixes, and procps runtime diagnostics
In processkit mode, aibox apply compares the [processkit].version in your
aibox.toml against the minimum required version for the running aibox binary.
If the pinned processkit version is older than the minimum, a warning is
emitted:
text
Warning: processkit v0.24.0 is below the minimum recommended version v0.25.0 for aibox v0.23.0 ...
This is a warning, not an error — older processkit versions can still install
successfully when their layout is still supported. The warning is a nudge to
upgrade, not a blocker. Harness-only projects do not install processkit content,
so this matrix only matters when [context].mode = "processkit".
Run aibox apply on the host — the 3-way diff will show changed content
and generate processkit content migration documents in context/migrations/pending/.
Review and apply the pending migrations.
Lockfile schema bump v0.25.6 — what’s automatic, what to verify#
aibox v0.25.6 extends aibox.lock with two new optional sections. The
bump is fully automatic — aibox apply backfills the new fields on first
run. No manual editing is required, and existing lockfiles remain valid
(the new fields use #[serde(default)], so they are absent from old locks
without causing parse errors).
AddonsLockSection::previous_selection
(BTreeMap<String, BTreeSet<String>>) — records which tool names were
enabled under each addon family at the time of the last apply. Written
under [addons.previous_selection] in aibox.lock. Used on the next
apply to compute a removal diff when a tool is disabled, so stale addon
binaries baked into an earlier image layer can be purged cleanly.
[harnesses] section (HarnessLockSection) — records the set of
AI harness names that were active (previous_selection: BTreeSet<String>) and the timestamp when the record was taken
(recorded_at). Used by aibox apply to detect harnesses that were
active last time but are no longer configured, enabling targeted
cleanup of harness-specific state files (gated on
[apply].purge_disabled_harness_state, default false).
Both fields are populated automatically on the first aibox apply that
runs against an old v0.25.5 lockfile.
[addons.previous_selection] is absent after apply.
This is expected if no addon tools are enabled — the field serializes
only when non-empty (skip_serializing_if = "BTreeMap::is_empty"). Enable
at least one tool under [addons] in aibox.toml and re-run
aibox apply to see it populated.
aibox apply reports a lockfile parse error after upgrading from
v0.25.5.
A truncated or hand-edited aibox.lock may have a malformed [addons]
section. Check that [addons].resolved_at is present and is a valid
ISO 8601 timestamp. If the file is corrupt, delete aibox.lock and run
aibox apply — the CLI regenerates it from scratch.
aibox v0.25.6 removes Zellij entirely. tmux is now the only supported
terminal multiplexer. Any [customization.zellij_status] section in your
aibox.toml causes schema validation to hard-reject aibox apply — you
must remove it before upgrading. Stale Zellij directories and binaries are
purged automatically on the first aibox apply that runs against a
v0.25.6+ host CLI. No data from active work sessions is touched; only
Zellij runtime artifacts are removed.
The following items are removed or rejected in v0.25.6 (commit faa9a88,
decision DEC-20260508_1515-SilentAsh):
[customization.zellij_status] config key — the field is removed
from the Customization struct in cli/src/config.rs. The TOML
deserializer now hard-rejects any aibox.toml that still contains this
section, with a descriptive error pointing to this document.
--forget-zellij-state CLI flag — removed from the argument parser
in cli/src/cli.rs. Scripts or aliases that reference this flag will
fail to parse.
Unconditional purge on aibox apply — the following paths under
.aibox-home/ are deleted on every apply regardless of config:
.config/zellij/
.cache/zellij/
.local/share/zellij/
.local/bin/aibox-status (the shell-backed Zellij helper; superseded
by the tmux PowerKit plugin set)
The purge is performed by cleanup_legacy_zellij_files() in
cli/src/seed.rs, which calls unconditionally via LEGACY_MUX_RELPATHS.
aibox doctor errors — any surviving artifact from the list above
triggers an ERROR diagnostic (check_legacy_zellij_artifacts in
cli/src/doctor.rs). The error is not advisory; it blocks a clean
doctor run.
Complete these steps on the host before or immediately after upgrading
to v0.25.6:
a. Remove [customization.zellij_status] from your aibox.toml.
Open the file and delete the entire section (header and all keys beneath
it). If you have no such section, skip this step.
b. Migrate any custom status configuration to tmux. If you previously
used Zellij status customizations, set the tmux equivalent in aibox.toml:
toml
[customization.tmux.status]mode="extended"# or "minimal" for a compact single-line bar
The extended mode renders a two-line powerline bar with aibox metrics
(log/OOM/proc/AI/MCP/migration counters). The minimal mode renders a
single line. See docs-site/content/docs/customization/layouts.md for full
reference.
c. Run aibox apply from a v0.25.6+ host CLI. This purges the stale
Zellij artifacts listed above and records the new lockfile schema fields.
d. Verify with aibox doctor. After apply, run:
text
aibox doctor
A passing run reports no check_legacy_zellij_artifacts errors. If
artifacts survive (e.g., because a volume mount shadowed the purge),
the error output lists the exact paths to remove manually.
Zellij was introduced as an aibox sidecar multiplexer, but the WASM plugin
runtime, session-state model, and config schema diverged frequently from
aibox’s tmux-native layout engine. The persistent vim-pane handoff through
Zellij regressed every three to five releases, and the native Zellij status
plugin required a WASM build step that added both CI complexity and binary
supply-chain surface. tmux has been the canonical aibox multiplexer since
v0.25.0; keeping a Zellij compatibility layer alongside it caused drift in
every layout-generation codepath.
Decision DEC-20260508_1515-SilentAsh records the full rationale and the
choice of scorched-earth excision (Variant 1 hard-purge) over a softer
deprecation path.
aibox is actively maintained. The latest minor release line is supported;
security and correctness fixes are released on the newest version rather than
backported across older minor lines. See the repository
SECURITY.md
for private reporting instructions and response expectations.
The project uses several independent integrity layers:
Surface
Provenance control
Release validation
Rust CLI
cli/Cargo.lock pins the complete dependency graph
cargo test, Clippy with warnings denied, and cargo audit
Documentation
docs-site/go.mod, go.sum, and package-lock.json pin the brand theme and build dependencies
clean npm ci, verified Hugo module graph, production Hugo build, and npm audit
processkit
source, version, and release-asset SHA-256 are recorded in aibox.lock and live provenance
installer hash verification, three-way content comparison, and pk-doctor integrity checks
Base images
release-specific image tags, OCI source/profile labels, and generated version markers
cross-platform build, GHCR publication verification, and downstream runtime smoke
Addon downloads
pinned versions plus SHA-256, signed checksum, or upstream sidecar verification where available
release-state inventory and real container lifecycle tests
Release binaries
locally cross-compiled artifacts attached to a signed release tag
version smoke tests and evidence-bound artifact checksums
The release-state report records floating inputs and available updates before
each release. A clean security audit is mandatory; routine non-security drift
may be deferred only into a processkit WorkItem. Provenance exceptions are
documented next to the relevant installer instead of being silently accepted.
This review was consolidated for
aibox issue #80. It is
kept current through the local release gate and the public maintenance guide.
aibox does not provide a hosted service and does not send product telemetry.
The CLI operates on the local project, generates container configuration, and
contacts external services only for requested dependency, image, processkit,
GitHub, documentation, or release operations.
aibox.toml, generated .devcontainer/ files, and processkit context are
project data and are normally committed.
.aibox-local.toml, .aibox-home/, .aibox/, authentication state, SSH
material, local caches, diagnostics, and release evidence are local state and
must remain ignored unless a specific artifact has been reviewed for
publication.
Tokens enter containers through explicit local environment configuration.
Prefer separate least-privilege tokens and select cross-account tokens per
command instead of exposing a human account’s full authorization.
Enabled AI harnesses and MCP servers execute with the container user’s access
to the workspace and mounted credentials. Their providers may receive prompt,
tool, and file content according to the provider’s own service terms.
aibox doctor and pk-doctor inspect local state. Diagnostic reports must be
reviewed and redacted before they are attached to public issues.
No generated local credential, cache, or diagnostic directory belongs in a
release artifact. The release process builds from tracked source, verifies the
exact commit, and publishes only the declared binaries, documentation output,
and container images.
When [context].mode = "processkit" and aibox apply registers processkit
skills (such as processkit-gateway, workitem-management, etc.), it calls
into cli/src/mcp_registration.rs. For Codex, the generated project config
sets:
toml
[project]trust_level="trusted"
This means every installed skill’s mcp/server.py runs with project-user
trust inside the aibox container — the same trust level as the project owner
who launched the container. The MCP server process inherits the container
filesystem and environment, including any mounted credentials.
When [context].mode = "harness-only", aibox does not install or register
processkit skills, processkit hooks, processkit preauth rules, or the
processkit MCP gateway. Team and personal MCP servers configured under
[ai.mcp] / .aibox-local.toml [[mcp.servers]] are still generated for
enabled harnesses and carry their own trust review burden.
The Codex CLI uses bubblewrap for Linux sandboxing. Some container runtime
seccomp profiles block unprivileged user namespace creation before bubblewrap
can set up its own sandbox. To work around this, aibox apply can emit
seccomp=unconfined in the generated docker-compose.yml.
Explicit consent is required. Without the acknowledgement flag, aibox apply
will error with a remediation pointer. To opt in, add to aibox.toml:
toml
[security]acknowledge_seccomp_unconfined=true
This setting:
Allows aibox apply to emit seccomp=unconfined in docker-compose.yml.
Suppresses the aibox doctor warning about unapproved seccomp relaxation.
Documents in source control that the project owner has accepted the
trade-off: reduced seccomp filtering in exchange for Codex bubblewrap
user-namespace sandboxing, avoiding the broader privileged=true or
CAP_SYS_ADMIN escalations.
seccomp=unconfined does not grant root or additional Linux capabilities —
it only lifts the seccomp syscall filter, allowing bubblewrap to create
user namespaces.
Color themes
Configure audited color palettes and font decoration across the aibox terminal toolchain.
aibox themes are coordinated semantic systems, not a terminal-background setting. One selection controls terminal chrome, syntax, diffs, status states, prompts, file managers, Git tools, pagers, and supported AI TUIs.
Choose a family, light or dark mode, an optional family variant, and a font-decoration level:
toml
[customization]theme="projectious"mode="dark"# auto | light | darkvariant="deep"# optional; family-specificemphasis="auto"# auto | full | standard | minimal | none
Run aibox apply after editing. mode = "auto" follows the host appearance when aibox can detect it and otherwise resolves to dark. Containers do not receive host appearance changes live, so apply again after changing the host setting.
Legacy concrete names such as catppuccin-mocha still parse, but the family form is canonical.
Color is only one information channel. emphasis carries meaning through bold, italic, dim, underline, and strikethrough where the target tool supports them.
Value
Decorations
Intended use
auto
Capability detection, then graceful degradation
Recommended default
full
Bold, italic, dim, underline, strikethrough
Terminals and fonts with complete style support
standard
Bold, italic, dim
Normal capable terminals
minimal
Bold, dim
Fonts without a true italic face
none
No font decoration
Color-only compatibility mode
NO_COLOR makes auto resolve to none. When terminfo is available, aibox checks italic and dim capabilities; an inconclusive probe assumes standard.
Unsupported attributes degrade to another channel: italic becomes dim, underline becomes bold, and strikethrough becomes dim. Bold is retained. Mono and high-contrast variants require at least the standard typography channel; max requires explicit emphasis = "full" because several semantic roles intentionally share a color.
Override individual semantic roles when a project needs a stronger cue:
Keys are semantic roles rather than tool-specific settings. Values may contain bold, italic, dim, underline, and strikethrough; aibox validates them, clamps them to the selected level, and degrades unsupported attributes per tool. An explicit emphasis = "none" still disables overrides.
Set the value in the Variant column with variant = "…". Leave it unset for the default shown first.
Single-mode families reject an incompatible explicit mode, and every family rejects unknown or mode-incompatible variants with a message listing its available choices.
mono is a practical grayscale theme with a 4.5:1 text floor. contrast keeps distinct hues while raising every text role to at least 7:1 in high and 12:1 in max. contrast-mono combines those floors with grayscale and therefore depends most strongly on font decoration.
Projectious is now a five-variant brand family. Navy is the default dark page, deep preserves the older code-panel depth, and both modes have high-contrast alternatives. Selection colors use a stronger midnight step so short selected ranges remain visible.
Status and Git: success, information, warning, error, disabled, modified, staged, untracked, ignored, and conflicted.
The shipped audit enforces a 7:1 floor for normal foreground text, 4.5:1 for colored text roles, 3:1 for non-text borders, and a visible surface/selection step.
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.
Supported engines are lualatex, pdflatex, xelatex, and tectonic.
Continuous watch mode uses latexmk, so tectonic configurations support
one-shot builds only.
Run these commands inside the development container. aibox apply generates
them under .aibox-home/.local/bin, which is already on the container PATH:
bash
aibox-latex-build # every configured documentaibox-latex-build overview # one configured documentaibox-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.
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.
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:
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.
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:
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:
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.
The default bind address is loopback and is suitable for SSH forwarding:
bash
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.