Documentation
Configure, operate, extend, and contribute to aibox.
aibox Documentation
Start with Installation for a new setup or
Existing Project when adopting aibox.
The reference section documents the complete configuration and CLI surfaces.
Container, addon, provider, customization, and migration guides explain the
corresponding workflows in depth.
1 - Contributing
Contributing
Thank you for your interest in contributing to aibox!
Getting Started
Fork and clone the repository:
git clone https://github.com/projectious-work/aibox.git
cd aibox
Start the development container:
cd .devcontainer
docker compose up -d
docker compose exec aibox bash
Or open in VS Code with the Dev Containers extension.
Build the CLI:
Run the tests:
cargo test
cargo clippy -- -D warnings
cargo fmt -- --check
Project Structure
cli/ — Rust CLI source codeimages/ — Published container image Dockerfilesaddons/ — Addon definitions (language runtimes, tool bundles, AI agents)docs-site/ — Hugo/Docsy documentation source.devcontainer/ — This project’s own dev environment
Process content (skills, packages, primitives, processes, the canonical
AGENTS.md) lives in processkit,
not in this repository. As of v0.16.0 aibox no longer ships a templates/
directory or a schemas/ directory — both have moved upstream to processkit.
See CLAUDE.md for detailed architecture notes.
Development Workflow
CLI Changes
- Make your changes in
cli/src/ - Run
cargo test to verify all tests pass - Run
cargo clippy -- -D warnings for lint checks - Run
cargo fmt to format code
Image Changes
- Edit the relevant Dockerfile in
images/ - Build locally to verify:
docker build -t aibox-test images/<flavor>/ - Test that derived images still build if you changed the base
Documentation Changes
- Edit or add pages in
docs-site/docs/ - Update
docs-site/sidebars.js if adding new pages - Preview locally:
./scripts/maintain.sh docs-serve
Pull Requests
- Keep PRs focused on a single change
- Include a clear description of what and why
- Ensure all tests pass and clippy is clean
- Update documentation if your change affects user-facing behavior
Reporting Issues
File issues at github.com/projectious-work/aibox/issues.
When filing an issue, please:
- Use a descriptive title
- Label it:
bug for broken behavior, enhancement for feature requests, documentation for doc gaps - Include steps to reproduce (for bugs) or a use case description (for enhancements)
- Mention the aibox version (
aibox --version) and container image flavor if relevant
1.1 - Maintenance
Maintenance
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.
Development Checks
cd cli && cargo fmt -- --check
cd cli && cargo clippy --all-targets -- -D warnings
cd cli && cargo test
The helper script wraps the same checks:
./scripts/maintain.sh test
Documentation Site
The public docs live in docs-site/ and use Hugo with the Docsy theme.
git submodule update --init --recursive docs-site/themes/docsy
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.
The maintenance script also exposes:
./scripts/maintain.sh docs-serve
./scripts/maintain.sh docs-deploy --dry-run
./scripts/maintain.sh docs-deploy
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.
Published Image
aibox publishes the base Debian image used by generated downstream projects:
./scripts/maintain.sh build-images
./scripts/maintain.sh build-images --no-cache
./scripts/maintain.sh push-images X.Y.Z
Generated project images are built per project by aibox apply. They are not
published from this repository.
Release Boundary
Releases are intentionally split:
| Phase | Where | Command | Purpose |
|---|
| Container side | aibox devcontainer | ./scripts/maintain.sh release X.Y.Z | check dependency/harness state, sync processkit default, bump CLI version, test, audit, build Linux binaries, tag, create GitHub release, deploy docs |
| Host side | macOS host | ./scripts/maintain.sh release-host X.Y.Z | build macOS binaries, upload them to the release, build and push GHCR images, run the generated-runtime smoke, then refresh repo-owned runtime surfaces |
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.
Version-line branches
Long-lived branches are protected: direct pushes, force-pushes, and deletion
are disabled; changes arrive through pull requests with resolved conversations.
No GitHub Actions or required hosted checks are used.
| Line | Development | Release authority | Purpose |
|---|
| v0 maintenance | v0.x-dev | v0.x-release | Stable v0 releases and hotfixes |
| v1 prerelease | v1.x-dev | v1.x-pre-release | Alpha, beta, and release-candidate tags |
| v1 GA | v1.x-dev | v1.x-release (created at GA) | Stable v1 releases |
main is the published-history branch. After a tag is cut on its designated
release branch, merge that branch into main through a pull request. Apply or
verify the policy from an administrator checkout with:
./scripts/configure-branch-protection.sh
Do not create GitHub releases by hand with gh release create. The release
script attaches binaries and writes the release notes expected by users.
Container-Side Release
./scripts/maintain.sh release X.Y.Z
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
- tracked
release-notes/vX.Y.Z.md, compatibility-matrix, README, contributor
guidance, and Hugo/Docsy production-build validation - Tier 2 SSH companion E2E tests, including generated runtime and visual
asciinema probes
cargo auditcargo 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/Docsy 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.
Companion evidence includes the companion fingerprint, 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 written to dist/RELEASE-TIMINGS.md.
The docs-check gate is mandatory whenever a tag or GitHub release is
selected. It runs before publication, so missing release notes, stale
compatibility metadata, incomplete v1 branch guidance, or a broken Hugo build
cannot leave a published release with incomplete documentation. The later
docs step deploys exactly that candidate’s site.
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.
Host-Side Release
Run this on the macOS host after the container-side release succeeds. Sync the
matching version-line release branch first; the container-side release may have
pushed tag-prep commits from another clone. For a v0 release:
git fetch origin v0.x-release
git switch v0.x-release
git reset --keep origin/v0.x-release
./scripts/maintain.sh release-host X.Y.Z
release-host derives the protected release branch from the version:
v0.x-release for v0, v1.x-pre-release for v1 prereleases, and
v1.x-release for v1 GA. It fetches only that branch and the requested tag,
then verifies that the tag is reachable from the branch before building.
This phase builds Darwin binaries, uploads them to the existing GitHub release,
pushes GHCR images, then runs a fresh downstream-style runtime smoke against
the pushed release tag. The smoke creates a temporary project, runs
aibox init and aibox apply --no-cache --standardize-config, starts the
generated container, probes Yazi, the aibox status helper, tmux state, and the
diagnostics sidecar, and writes a bundle to
dist/release-smoke/vX.Y.Z/<timestamp>/.
By default, this smoke runs with AIBOX_RELEASE_SMOKE_TIER=addons, so git-ui
(lazygit) startup is exercised in addition to the core runtime contract.
It is host-side because macOS binaries and host runtime access are not
available from the Linux devcontainer.
For a final v1 release candidate, retain the two Linux archives, two macOS
archives, their checksum sidecars, the container- and host-release logs, and an
exact-version rollback/reinstall log under one project-relative rehearsal
directory. Record the completed rehearsal against the exact candidate and
tested binary:
The final line of each retained log is the corresponding completion marker:
release phase=container status=passed candidate=<40-character-commit>
release phase=host status=passed candidate=<40-character-commit>
rollback status=passed candidate=<40-character-commit> version=<version>
Append a marker only after its command succeeds. The recorder also opens every
archive, verifies the expected target-named binary, validates every checksum,
and refuses symlinked inputs.
RELEASE_CANDIDATE_SHA=<40-character-commit> \
AIBOX_RELEASE_BINARY_SHA256=sha256:<tested-binary-digest> \
./scripts/record-v1-platform-rehearsal.sh \
dist/v1-platform-rehearsal/1.0.0 1.0.0
Stable readiness remains blocked if this evidence is missing, stale, bound to a
different candidate, or references a missing or modified artifact.
The two macOS targets build concurrently. The host release also overlaps that
build lane with source-hash-aware image reuse or publication, then joins both
lanes before uploading binaries and starting the runtime smoke. Healthy tmux
smoke probes advance on observed session, window, pane, and status readiness;
their timeouts are failure ceilings rather than fixed delays. Host timings are
written to dist/RELEASE-HOST-TIMINGS.md.
The Linux-side Tier 2 E2E companion is separate from this host phase. From the
devcontainer, verify that companion over SSH/SCP; do not use local
Docker/Podman availability in the main devcontainer as the reachability check.
release-doctors is an aibox CLI development exception to the normal
host/container diagnostic split. Inside the workspace container, ordinary
dogfood diagnostics use pk-doctor; aibox doctor is host-side. During release
Phase 0, however, ./scripts/maintain.sh release-doctors runs aibox doctor
as a host-context simulation so the CLI’s host diagnostic behavior remains
gated.
Verification
After release:
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.
Project Devcontainer
The maintenance script can also operate this repository’s own devcontainer:
./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.
1.2 - E2E Test Catalogue
E2E Test Catalogue
This page describes every end-to-end and integration test in cli/tests/e2e/
in plain language. Each entry states the precondition and the expected outcome,
followed by a reference to the exact test function for traceability.
Test tiers
| Tier | Where it runs | What it needs |
|---|
| Tier 1 | Local temp directory | The compiled aibox binary only |
| Tier 1 + Mock | Local temp directory | Binary + mock docker/podman scripts on PATH |
| Tier 2 | Remote SSH companion | aibox-e2e-testrunner container reachable (feature flag e2e) |
Tier 1 tests run automatically with cargo test. Tier 2 tests require the
companion container and the --features e2e flag. The expensive visual matrix
tests are opt-in and are not included in the default Tier 2 command.
From inside the aibox devcontainer, the companion is a remote SSH target, not a
local Docker/Podman dependency. Check it with:
ssh -i /workspace/.aibox-e2e-runner-home/.ssh/id_ed25519 testuser@aibox-e2e-testrunner 'echo ok'
Missing docker or podman in the main devcontainer does not mean Tier 2
cannot talk to the companion. The tests deploy the current aibox binary and
addons with SCP, then use the companion’s own runtime for lifecycle checks.
Rebuilding the Kubernetes-capable companion
The release-gated disposable-cluster test requires the companion to run
systemd as PID 1, use cgroup v2 delegation for rootless Podman, expose the
read-only host /lib/modules tree, and contain both kind and kubectl.
./scripts/maintain.sh test-e2e verifies this contract before it runs Cargo;
when the reachable companion is an older image, it automatically rebuilds and
recreates the service.
If a host daemon restart or a failed build prevents automatic recreation, run
this from the repository root on the Docker host, then rerun the E2E command:
docker compose -f .devcontainer/docker-compose.yml -f .devcontainer/docker-compose.override.yml \
up -d --build --force-recreate aibox-e2e-testrunner
./scripts/maintain.sh test-e2e
Do not accept SSH reachability alone as evidence that this companion is ready:
an old SSH-only image reports sshd as PID 1 and fails the preflight without
mutating a disposable cluster.
aibox commands inside the devcontainer
In normal dogfood use, the workspace container is the processkit/runtime side of
the project: run pk-doctor there. aibox doctor is a host-side diagnostic and
should not be used from inside the container to judge the live dogfood project.
It still can run inside containers when that container is intentionally
simulating a host environment for CLI development.
The aibox repository has deliberate exceptions because it develops the aibox
CLI. Those exceptions simulate host-user behavior in controlled test projects:
- Tier 1 tests run
aibox init, aibox apply, aibox doctor, and related
commands in temporary directories, usually without starting containers. - Tier 1 mock tests put fake
docker/podman scripts on PATH to verify host
runtime behavior without requiring a real runtime in the main devcontainer. - Tier 2 tests deploy the current binary to
aibox-e2e-testrunner over SSH and
may run aibox apply, aibox up, or aibox doctor there because the
companion owns the nested container runtime for the test. - Release Phase 0 runs
./scripts/maintain.sh release-doctors, which invokes
aibox doctor as an explicit host-context simulation.
Use these exceptions only in aibox CLI development/release harnesses. They are
not general dogfood escape hatches.
The container-side release command runs Tier 2 as part of Phase 1 with
cargo test --features e2e --test e2e, so the SSH companion, generated
runtime probes, and non-ignored asciinema checks are release gates.
Tier 1 modules are excluded from feature-enabled test binaries because the
default cargo test invocation already covers them.
The default Tier 2 suite intentionally performs only one full generated
container build/start/probe. File-generation contracts use --no-container,
and ./scripts/maintain.sh test-e2e removes only E2E-owned containers,
networks, volumes, and workspaces before and after the suite. Images and
BuildKit caches survive for later runs.
The suite defaults to four test threads. Workspace-isolated tests run in
parallel, while tests that mutate the companion runtime and tests that own
interactive tmux/Yazi state use separate keyed serialization lanes. Override
the worker count with AIBOX_E2E_TEST_THREADS; use 1 when diagnosing ordering
or isolation failures.
The release process also has a host-side generated-runtime smoke:
./scripts/maintain.sh release-runtime-smoke X.Y.Z. It is not an SSH
companion test; it runs on the macOS host during release-host, creates a
fresh downstream-style project, runs aibox init and
aibox apply --standardize-config, starts the generated container, probes
tmux-native status output and the diagnostics sidecar, and writes logs under
dist/release-smoke/vX.Y.Z/. The default AIBOX_RELEASE_SMOKE_TIER=addons
includes git-ui (lazygit) probes. Use minimal only for a quicker
non-addon pass, or full to include preview addons and force --no-cache.
Opt-in visual E2E
Use these commands when the release diff touches generated runtime visuals or
when the periodic full visual sweep is due:
| Command | Covers |
|---|
./scripts/maintain.sh test-e2e-visual-status | all generated layouts across all themes, tmux status/key rows, and theme RGB signatures |
./scripts/maintain.sh test-e2e-visual-tabs | tmux window traversal, Yazi surface, Vim, shell, lazygit, and every enabled AI harness |
./scripts/maintain.sh test-e2e-visual-yazi | Yazi preview plugins, optional preview tools, git symbols, and preview modes |
./scripts/maintain.sh test-e2e-visual | all visual tiers |
./scripts/maintain.sh test-e2e-doc-captures | all visual tiers plus .cast, .screen.txt, tmux log, and metadata artifacts under docs-site/static/img/e2e/ |
Set AIBOX_E2E_VISUAL_ARTIFACT_DIR to write documentation capture artifacts
elsewhere. The artifacts are intended as source material for current-release
website screenshots and screencasts.
Lifecycle — lifecycle.rs
Companion is reachable
If the SSH connection to aibox-e2e-testrunner is attempted, then the host
must respond with ok, confirming the companion container is up and reachable
before any other Tier 2 test runs. The test also asserts that the companion
image has the expected tmux and Yazi tools for the visual/runtime tests; stale
companion images fail here with a rebuild hint.
[lifecycle.rs · companion_is_reachable]
Init then apply produces valid project
If aibox init is run followed by aibox apply, then
aibox.toml, .devcontainer/Dockerfile, .devcontainer/docker-compose.yml,
and CLAUDE.md must all exist in the workspace.
[lifecycle.rs · lifecycle_init_apply]
Generated container starts
If a fresh project is initialized, applied, and the generated Compose service is
started on the companion runtime, then the running container must expose
/etc/aibox-version, tmux, Yazi, and valid aibox-status --plugin-json
output.
[lifecycle.rs · lifecycle_apply_starts_generated_container]
CLAUDE.md user content is preserved on apply
If a user edits CLAUDE.md after aibox init and then runs aibox apply,
then the edited content must still be present — aibox must not overwrite
user-modified files.
[lifecycle.rs · claudemd_preserved_on_sync]
Generated files are overwritten on apply
If a generated file (e.g. .devcontainer/Dockerfile) is manually tampered
with and aibox apply is run, then the file must contain regenerated content
and the tampered content must be gone.
[lifecycle.rs · generated_files_overwritten_on_sync]
Status reports missing when no container exists
If aibox get runtime is run in a project with no running container, then the
output must contain missing or equivalent wording.
[lifecycle.rs · status_without_container_shows_missing]
Default processkit mode writes the project skeleton
If aibox init --harness claude is run, then the slim project skeleton must
exist: aibox.toml, an empty context/ directory, AGENTS.md, and the thin
provider pointer files for enabled harnesses. This is the default processkit
mode, so a later aibox apply with a real [processkit].version can install
processkit content under context/. The single-file context tracks
(BACKLOG.md, DECISIONS.md, STANDUPS.md) are not scaffolded by init
— the corresponding processkit skills create entities in place on first use.
[lifecycle.rs · init_with_managed_preset_creates_context_files]
Legacy processkit package selection is recorded in aibox.toml
If aibox init --context software is run, then the same processkit-mode
project skeleton must exist and the package selection is recorded under
[context].packages. The --context <PKG> option is retained as a hidden
legacy package selector; new flows should use [context].mode for the context
backend and [skills] for explicit processkit skill selection.
[lifecycle.rs · init_with_software_preset_creates_code_files]
Addon management — addon.rs
Addon add writes to aibox.toml
If aibox set addon python is run in an initialized project, then
aibox.toml must contain an [addons.python] section afterwards.
[addon.rs · set_addon_modifies_toml]
Addon remove cleans aibox.toml
If a project is initialized with the python addon and then aibox delete addon python is run, then the [addons.python] section must no
longer appear in aibox.toml.
[addon.rs · delete_addon_cleans_toml]
Addon content appears in generated Dockerfile after apply
If a project is initialized with the python addon and aibox apply is run,
then .devcontainer/Dockerfile must contain Python-related content (install
commands or references to uv).
[addon.rs · addon_rebuild_includes_tools_in_dockerfile]
Addon list shows available addons
If aibox get addon is run in an initialized project, then the output must
list known addons such as python.
[addon.rs · addon_list_shows_available]
Reset and backup — reset.rs
Reset with backup removes files and creates backup directory
If aibox reset project --yes is run in an initialized project, then aibox.toml
must be deleted and .aibox/backup/ must be created containing the backed-up
files.
[reset.rs · reset_creates_backup]
Reset with –no-backup removes all files without creating a backup
If aibox reset project --no-backup --yes is run, then aibox.toml and
.devcontainer/ must be deleted and .aibox/backup/ must not be created.
[reset.rs · reset_no_backup_deletes_all]
Doctor diagnostics — doctor.rs
Doctor without a config reports an error
If aibox doctor is run in a directory that has no aibox.toml, then the
output must mention the missing config or config error and the command must
still exit 0 (doctor is always non-fatal).
[doctor.rs · doctor_reports_missing_files]
Doctor after init reports healthy checks
If aibox doctor is run immediately after a successful aibox init, then
the output must contain at least one passing check indicator (ok, ✓, or
similar).
[doctor.rs · doctor_after_init_reports_healthy]
Version upgrade flows — version_upgrade.rs
Generated Dockerfile contains version label
If aibox init is run, then the generated .devcontainer/Dockerfile must
contain a LABEL aibox.version line so the built image carries a
machine-readable version stamp.
[version_upgrade.rs · dockerfile_contains_aibox_version_label]
Generated Dockerfile writes version to /etc/aibox-version
If aibox init is run, then the generated .devcontainer/Dockerfile must
contain a RUN statement that writes to /etc/aibox-version inside the
image, making the build version queryable from within a running container.
[version_upgrade.rs · dockerfile_contains_etc_aibox_version_write]
Up fails when container image version mismatches config
If an existing container was built from image v0.0.1 (mock label) and
aibox.toml pins the current version, then aibox up must exit non-zero
and output a message containing mismatch and a suggestion to run
aibox apply.
[version_upgrade.rs · start_fails_on_image_version_mismatch]
Up succeeds when container image version matches config
If an existing container reports the same image version as the one pinned in
aibox.toml, then aibox up must not produce a version mismatch error.
[version_upgrade.rs · start_does_not_error_when_versions_match]
Update -y exits zero without hanging
If aibox self update -y is run (the global --yes flag), then the command must
exit 0 regardless of registry availability — confirming the flag is correctly
wired to cmd_update and does not block on an interactive prompt.
[version_upgrade.rs · update_yes_flag_exits_zero]
Update –dry-run does not mention .aibox-version
If aibox self update --dry-run is run, then the output must not contain the
phrase Would update .aibox-version — that write was removed in BACK-060
because the image version is now tracked exclusively in aibox.toml.
[version_upgrade.rs · update_dry_run_does_not_mention_aibox_version_file]
Doctor warns when running container has a stale image label
If the running container reports aibox.version=0.0.1 (mock label) but
aibox.toml pins the current version, then aibox doctor must emit a
warning containing mismatch while still exiting 0.
[version_upgrade.rs · doctor_warns_on_container_version_mismatch]
Doctor warns when .aibox-version is outdated
If .aibox-version is overwritten with 0.0.1 (an old CLI version) and
aibox doctor is run, then the output must contain CLI version mismatch
and suggest running aibox apply to update generated files.
[version_upgrade.rs · doctor_warns_on_cli_version_file_mismatch]
Migration — migration.rs
Apply absorbs legacy .aibox-version into aibox.lock
If .aibox-version is overwritten with 0.1.0 (an old version) and
aibox apply is run, then .aibox-version must be removed and aibox.lock
must contain the current [aibox].cli_version sync state.
[migration.rs · apply_absorbs_legacy_version_file_into_lock]
Update command — update.rs
Update exits zero when registry returns an error
If aibox self update is run in a project where the GHCR registry is unreachable
or returns a non-2xx response, then the command must still exit 0 — the error
must be treated as a warning, not a hard failure.
[update.rs · update_runs_without_crashing_in_derived_project]
Update –check exits zero
If aibox self update --check is run in an initialized project, then the command
must exit 0 and print output containing either Current CLI version: or
Checking for updates, regardless of whether the registry is reachable.
[update.rs · update_check_exits_cleanly]
Appearance — appearance.rs
All themes render without error and without leftover placeholders
If aibox init is run for each of the seven supported themes
(gruvbox-dark, catppuccin-mocha, catppuccin-latte, dracula,
tokyo-night, nord, projectious), then the seeded config files must
contain no unreplaced template placeholders such as AIBOX_THEME or
AIBOX_VIM_COLORSCHEME.
[appearance.rs · all_themes_render_without_error]
Gruvbox theme sets the correct vim colorscheme and tmux theme
If aibox init --theme gruvbox-dark is run, then vimrc must contain
gruvbox or retrobox as the colorscheme and tmux.conf must reference
gruvbox-dark.
[appearance.rs · theme_gruvbox_renders_correctly]
Catppuccin-mocha theme is reflected in tmux config
If aibox init --theme catppuccin-mocha is run, then tmux.conf must
reference catppuccin-mocha.
[appearance.rs · theme_catppuccin_mocha_renders]
Changing the theme updates all themed tool configs
If a project is initialized with gruvbox-dark and the theme is changed to
dracula via aibox apply, then tmux.conf must contain dracula and no
longer gruvbox-dark, and vimrc, yazi/theme.toml, and starship.toml
must be updated. Lazygit config is optional and is checked only when the
git-ui addon enables it.
[appearance.rs · theme_change_auto_applies_untouched_runtime_files]
Each theme produces matching configs across all tools
If aibox init is run for each of five themes with known vim colorscheme
names, then vimrc must contain the exact colorscheme <name> line,
tmux.conf must reference the theme name, yazi and starship configs must
be non-empty, and lazygit config must be non-empty when present.
[appearance.rs · theme_alignment_all_tools_match_selected_theme]
Yazi keymap includes the open-in-editor binding
If aibox init is run, then yazi/keymap.toml must contain an "e" key
binding that invokes open-in-editor.
[appearance.rs · yazi_keymap_includes_edit_in_pane_binding]
All prompt presets produce a non-empty starship config
If aibox init is run for each prompt preset (default, plain,
minimal, nerd-font, pastel, powerline-pastel, bracketed, arrow), then
starship.toml must exist and be non-empty.
[appearance.rs · all_prompts_render_without_error]
Default prompt includes directory and git_branch modules
If aibox init --prompt default is run, then starship.toml must contain
both directory and git_branch module sections.
[appearance.rs · prompt_default_generates_starship]
Plain prompt uses ASCII-only symbols
If aibox init --prompt plain is run, then starship.toml must not contain
Nerd Font glyph characters (e.g. no \ue0b0 powerline arrow).
[appearance.rs · prompt_plain_no_nerd_font]
Config coverage — config_coverage.rs
Container name appears in docker-compose.yml
If aibox.toml specifies a container name and aibox apply is run, then
docker-compose.yml must contain that name.
[config_coverage.rs · container_name_in_compose]
Container hostname appears in docker-compose.yml
If aibox.toml specifies a hostname and aibox apply is run, then
docker-compose.yml must contain that hostname.
[config_coverage.rs · container_hostname_in_compose]
Port mappings appear in docker-compose.yml
If aibox.toml defines ports (e.g. "8080:80") and aibox apply is run,
then docker-compose.yml must contain those port entries.
[config_coverage.rs · container_ports_in_compose]
Extra packages appear in the generated Dockerfile
If aibox.toml lists extra packages and aibox apply is run, then
.devcontainer/Dockerfile must contain those package names in an apt install
block.
[config_coverage.rs · container_extra_packages_in_dockerfile]
Environment variables appear in docker-compose.yml
If aibox.toml defines environment variables and aibox apply is run, then
docker-compose.yml must contain those key-value pairs.
[config_coverage.rs · container_environment_in_compose]
Extra volumes appear in docker-compose.yml
If aibox.toml defines extra volume mounts and aibox apply is run, then
docker-compose.yml must contain those source and target paths.
[config_coverage.rs · container_extra_volumes_in_compose]
Claude AI provider adds volume mount
If aibox.toml lists claude as an AI provider and aibox apply is run,
then docker-compose.yml must contain a volume mount for the .claude
config directory.
[config_coverage.rs · ai_claude_provider_volume_mount]
Aider AI provider adds volume mount
If aibox.toml lists aider as an AI provider and aibox apply is run,
then docker-compose.yml must contain a volume mount for the .aider
config directory.
[config_coverage.rs · ai_aider_provider_volume_mount]
Multiple AI providers each add their own volume mounts
If aibox.toml lists both claude and gemini as providers and aibox apply is run, then docker-compose.yml must contain volume mounts for both
.claude and .gemini.
[config_coverage.rs · ai_multiple_providers_volume_mounts]
Audio enabled adds PulseAudio mounts and socket
If aibox.toml enables audio and aibox apply is run, then
docker-compose.yml must contain audio-related volume mounts or socket
references.
[config_coverage.rs · audio_enabled_adds_mounts]
Audio disabled produces no audio mounts
If aibox.toml has audio disabled (the default) and aibox apply is run,
then docker-compose.yml must not contain audio-related content.
[config_coverage.rs · audio_disabled_no_mounts]
Python addon adds install commands to Dockerfile
If aibox.toml includes the python addon and aibox apply is run, then
.devcontainer/Dockerfile must contain Python install instructions.
[config_coverage.rs · addon_python_in_dockerfile]
Rust addon adds rustup install to Dockerfile
If aibox.toml includes the rust addon and aibox apply is run, then
.devcontainer/Dockerfile must contain rustup installation instructions.
[config_coverage.rs · addon_rust_in_dockerfile]
Multiple addons each contribute to the Dockerfile
If aibox.toml includes both the python and rust addons and aibox apply
is run, then .devcontainer/Dockerfile must contain install content for
both.
[config_coverage.rs · addon_multiple_in_dockerfile]
Legacy minimal package creates processkit project skeleton
If aibox init --context minimal is run, then aibox.toml, aibox.lock,
an empty context/ directory, and a thin CLAUDE.md pointer must exist.
The single-file context tracks (BACKLOG.md, DECISIONS.md, STANDUPS.md)
are not created at init time — the corresponding processkit skills create
them in place on first use.
Default processkit mode is the recommended full context path
If aibox init --harness claude is run, then the slim project skeleton must
exist. With a real [processkit].version pinned, aibox apply then installs
the selected processkit skill catalogue under context/skills/ and the
immutable upstream snapshot under context/templates/processkit/<version>/.
Product / research / software packages
The legacy processkit packages (minimal, managed, software, research,
product) are declarative metadata in [context].packages when
[context].mode = "processkit". Current projects should prefer explicit
[skills] selection for installed processkit skills. Harness-only mode ignores
processkit package and skill selection entirely and does not create processkit
content or processkit references.
File preview — preview.rs
svg.yazi plugin is seeded into .aibox-home after init
If aibox init is run, then
.aibox-home/.config/yazi/plugins/svg.yazi/init.lua must exist.
[preview.rs · svg_yazi_plugin_seeded]
eps.yazi plugin is seeded into .aibox-home after init
If aibox init is run, then
.aibox-home/.config/yazi/plugins/eps.yazi/init.lua must exist.
[preview.rs · eps_yazi_plugin_seeded]
svg.yazi plugin invokes resvg for conversion
If svg.yazi/init.lua is read after init, then its content must reference
resvg as the SVG-to-PNG conversion tool.
[preview.rs · svg_yazi_plugin_uses_resvg]
eps.yazi plugin invokes ghostscript for conversion
If eps.yazi/init.lua is read after init, then its content must reference
gs (ghostscript) as the EPS-to-PNG conversion tool.
[preview.rs · eps_yazi_plugin_uses_ghostscript]
yazi.toml has a [plugin] section with prepend_previewers
If aibox init is run, then yazi.toml must contain a [plugin] section
that defines prepend_previewers.
[preview.rs · yazi_toml_has_plugin_section]
*yazi.toml routes .svg to the svg previewer
If aibox init is run, then yazi.toml must contain a
prepend_previewers entry matching *.svg with run = "svg".
[preview.rs · yazi_toml_svg_previewer_entry]
*yazi.toml routes .eps to the eps previewer
If aibox init is run, then yazi.toml must contain a
prepend_previewers entry matching *.eps with run = "eps".
[preview.rs · yazi_toml_eps_previewer_entry]
SVG and EPS entries appear before built-in image entries
If aibox init is run, then the *.svg and *.eps entries in
prepend_previewers must appear at a lower byte offset than the *.jpg
entry, ensuring first-match semantics dispatch SVG/EPS to the custom
plugins rather than the built-in image previewer.
[preview.rs · yazi_toml_svg_and_eps_precede_builtin_previewers]
sample.svg fixture is valid XML
If tests/e2e/fixtures/sample.svg is read, then its content must start
with <svg or <?xml, confirming the fixture file is intact.
[preview.rs · fixture_sample_svg_is_valid_xml]
sample.eps fixture has a valid EPS header
If tests/e2e/fixtures/sample.eps is read, then its content must start
with %!PS-Adobe or contain %%BoundingBox, confirming the fixture file
is intact.
[preview.rs · fixture_sample_eps_has_eps_header]
Generated runtime — runtime_generated.rs
Generated runtime tools are usable
If a fresh project is initialized with git-ui and shell status enabled, then
aibox apply --no-container --standardize-config must generate Yazi config
that parses with the pinned Yazi binary, lazygit state directories that permit
startup, and an aibox-status --plugin-json payload with required fields.
[runtime_generated.rs · generated_runtime_yazi_lazygit_and_status_are_usable]
Generated tmux status renders
If the generated dev layout is launched under asciinema with tmux status
enabled, then the cast must show key/status row text and runtime status output.
[runtime_generated.rs · generated_runtime_tmux_status_renders_key_and_status_rows]
Visual matrix — visual_matrix.rs
These tests are ignored by default and run only through the explicit visual
E2E commands above.
Generated layouts render across all themes
If each generated layout is launched for each supported theme, then the
recording must include the theme RGB signature and tmux status/key row text.
[visual_matrix.rs · visual_generated_layouts_render_across_all_themes]
Generated tools and harness windows render when enabled
If all harnesses and visual runtime addons are enabled, then window traversal must
show the expected Yazi surface, Vim, shell, lazygit, and every harness marker.
[visual_matrix.rs · visual_generated_tools_and_harness_windows_render_when_enabled]
Yazi previews, git symbols, and optional plugins render
If the Yazi preview addons are enabled, then generated Yazi config must parse,
preview plugins must be installed, git symbols must be configured, and directory,
Markdown, CSV, TSV, and SQLite previews must render their markers.
[visual_matrix.rs · visual_yazi_previews_git_symbols_and_optional_plugins_render]
Smoke tests — smoke.rs
These tests validate that the Tier 2 companion container’s container runtime
is functional end-to-end (Tier 2 only).
Container runtime is available on the companion
If the companion container is queried for its selected runtime, then the
command must succeed and the output must contain either docker or podman.
[smoke.rs · runtime_available_on_companion]
Container runtime can pull and run a container
If the selected runtime runs alpine echo hello-e2e on the companion, then
the image pull, container creation, and command execution must succeed, and the
output must contain hello-e2e.
[smoke.rs · runtime_can_pull_and_run_container]
1.3 - Version-line porting
Version-line porting
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:
Version-Line-Port: ported-from=<full source commit SHA>
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:
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.
Before publishing, run:
scripts/check-version-line-ports.sh check v0
scripts/check-version-line-ports.sh check v1
The release workflow automatically runs the gate for the major version being
published.
1.4 - V1 adoption pilots
V1 adoption pilots
Stable-v1 readiness requires four repeatable journeys against the exact
candidate and binary:
- a new Compose workspace can compile and render a deterministic plan;
- a representative v0 project can preview, apply, and roll back a reviewed
v1 intent without exposing secrets or touching v1 deployment records;
- an existing Kubernetes target passes the complete live M7c lifecycle;
- exact-pinned processkit install, verify, unchanged update, recovery, and
uninstall pass through the direct opaque boundary.
After the live M7c and M5 producer evidence has been generated, run:
RELEASE_CANDIDATE_SHA="$(git rev-parse HEAD)" \
AIBOX_RELEASE_BINARY_SHA256="sha256:<tested-binary-digest>" \
./scripts/test-v1-adoption-pilots.sh
The harness refuses missing or candidate-mismatched prerequisites. It executes
the local Compose and migration journeys, verifies the live Kubernetes and
direct-processkit scenario sets, and writes
.aibox/release-evidence/v1-readiness/adoption-pilots.json. Stable publication
reruns this automatically and verifies the retained log digest.
This automated evidence establishes repeatability, not user sentiment. Record
configuration friction, plan comprehension, recovery steps, terminology
confusion, and documentation gaps from external pilots in their tracking
issues. Do not convert an unrun or unsuccessful external pilot into a passing
release marker.
2 - Overview
What aibox does, what it owns, and when to use it.
Overview
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.
The Short Version
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.
What aibox Owns
| Area | Output |
|---|
| Project contract | aibox.toml desired state and aibox.lock resolved state |
| Devcontainer | .devcontainer/Dockerfile, Compose files, devcontainer.json |
| Runtime home | .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.
What processkit Owns
processkit owns the project-process content:
- skills and
SKILL.md files - schemas and state machines
- work processes
- 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.
Why This Split Matters
The split keeps the system forkable and maintainable:
- aibox can improve containers, addons, and runtime operations without changing
process semantics.
- processkit can improve skills, primitives, and workflows without shipping a
new container tool.
- projects can pin or fork processkit independently through
[processkit] in
aibox.toml when they use processkit mode. - projects that only want installed harnesses and a reproducible container can
choose harness-only mode without carrying processkit references.
When To Use aibox
Use aibox when you want:
- 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.
Daily Mental Model
aibox.toml is desired state.
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.
3 - Skills (via processkit)
Skills
As of aibox v0.16.0, skills are no longer bundled with aibox. They live in
processkit — a separate,
versioned content repository that ships skills, primitives, processes, packages,
and the canonical AGENTS.md template.
aibox owns the container (devcontainers, addons, the CLI, the install/apply
machinery). processkit owns the content (skills, packages, processes,
state machines). The boundary is deliberate and load-bearing: it lets the two
projects move at their own velocity without dragging each other through breaking
changes.
Where skills land in your project
After running aibox init and aibox apply in your project, processkit content
is materialised under your context/ directory when
[context].mode = "processkit":
context/
├── skills/ # Active, editable skill copies
└── templates/
└── processkit/
└── v0.27.4/ # Immutable upstream snapshot, git-tracked
├── context/
│ └── skills/
├── .processkit/
└── AGENTS.md
The version in the path (v0.27.4) is whatever you pinned in aibox.toml:
[context]
mode = "processkit"
[processkit]
source = "https://github.com/projectious-work/processkit.git"
version = "v0.27.4"
When [context].mode = "harness-only", aibox does not install processkit
skills, does not create context/templates/processkit/, and does not project
processkit command adapters into harness-specific surfaces. The generated
AGENTS.md is a minimal aibox-owned file with no processkit references.
The context/skills/ copies are yours to edit. The context/templates/processkit/<version>/
copies are the immutable upstream snapshot — aibox apply uses them as the base
side of a three-way diff to detect upstream changes that should be pulled into
your local edits.
Skill catalogue and documentation
processkit documentation is not yet deployed as a standalone site.
Until then, browse the upstream source directly:
Every skill is a directory with at least a SKILL.md (the agent-readable
instructions) and may include references/, mcp/, assets/, and scripts/
siblings. Skills follow the open Agent Skills specification.
Browsing installed skills
aibox get skill # list installed skills, grouped by category
aibox get skill --all # include available-but-not-installed skills
aibox get skill --category ai # filter by category
aibox describe skill <name> # frontmatter + description for one skill
Skill Selection
New projects list the standard processkit operating skills explicitly in
[skills].include. Use [skills].include and [skills].exclude for
skill-level overrides in processkit mode:
[skills]
include = [
"pk-doctor",
"status-briefing",
]
exclude = [
# "skill-to-omit",
]
Legacy package selections are still accepted for compatibility, but new
aibox.toml files use explicit skill selection as the primary control surface.
enabled and disabled are accepted as aliases for older configs. [skills]
is omitted and ignored in harness-only mode.
Custom skills
To add a project-specific skill, drop a directory under context/skills/:
context/skills/my-custom-skill/
└── SKILL.md
Local skills are not touched by aibox apply. They are also not part of any
processkit package — they exist purely for the local project.
Core skills
Some processkit skills carry metadata.processkit.core: true in their
frontmatter (e.g. skill-finder). Core skills are installed regardless of any
[skills].include / [skills].exclude configuration. aibox doctor warns if
you attempt to exclude a core skill.
Why this split?
- Independent release cadence. processkit can ship a new skill or fix a
prompt without forcing an aibox CLI release.
- Reusable content. Other tools can consume processkit directly without
taking a dependency on aibox or its container stack.
- Forkable content. A team can fork processkit, point
[processkit].source
at the fork, and ship a private skill catalogue without forking aibox itself. - Smaller aibox. The aibox binary stays focused on container lifecycle and
the install/diff/migrate machinery.
See [processkit] configuration for
the full set of fields, including release-asset URL templates and SHA256
verification.
4 - Getting Started
4.1 - Installation
Installation
Prerequisites
aibox requires a container runtime and a Compose-compatible provider on your
host machine.
Podman (recommended)
# macOS
brew install podman
podman machine init
podman machine start
# Fedora / RHEL
sudo dnf install podman podman-compose
# Ubuntu / Debian
sudo apt install podman podman-compose
Docker
# macOS
brew 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.
Install script (recommended)
Install the latest stable release:
curl -fsSL https://raw.githubusercontent.com/projectious-work/aibox/main/scripts/install.sh | bash
Downloads the correct pre-built binary for your platform (Linux or macOS, x86_64 or ARM64) and installs it to ~/.local/bin/.
Install the v1 alpha
The v1 line is a prerelease and is never selected by the stable channel.
After the GitHub prerelease exists, install its exact version:
curl -fsSL https://raw.githubusercontent.com/projectious-work/aibox/main/scripts/install.sh |
VERSION=1.0.0-alpha.1 bash
aibox --version
Do not use a moving branch name as the installed version. Exact pins make
reinstallation and rollback reproducible.
Roll back from the alpha
Reinstall the last known-good v0 release by exact version:
curl -fsSL https://raw.githubusercontent.com/projectious-work/aibox/main/scripts/install.sh |
VERSION=0.28.17 bash
aibox --version
This replaces the CLI binary; it does not destroy v1 deployments or rewrite
their receipts. Remove a v1 deployment with the v1 CLI’s guarded
aibox deploy destroy flow before rolling back when cleanup is required.
Configuration rollback is separate: use the exact backup created by
aibox config migrate-v1 --apply, and preview restoration before applying it.
Other options
# Install a specific version
curl -fsSL https://raw.githubusercontent.com/projectious-work/aibox/main/scripts/install.sh | VERSION=X.Y.Z bash
# Install to a custom directory
curl -fsSL https://raw.githubusercontent.com/projectious-work/aibox/main/scripts/install.sh | INSTALL_DIR=/usr/local/bin sudo -E bash
Manual download
Download the binary for your platform from the releases page:
# Example for macOS ARM64
tar xzf aibox-vX.Y.Z-aarch64-apple-darwin.tar.gz
mv aibox-vX.Y.Z-aarch64-apple-darwin ~/.local/bin/aibox
chmod +x ~/.local/bin/aibox
Replace X.Y.Z with the release version you downloaded.
Available binaries:
| Platform | File |
|---|
| macOS ARM64 (Apple Silicon) | aibox-vX.Y.Z-aarch64-apple-darwin.tar.gz |
| macOS x86_64 (Intel) | aibox-vX.Y.Z-x86_64-apple-darwin.tar.gz |
| Linux ARM64 | aibox-vX.Y.Z-aarch64-unknown-linux-gnu.tar.gz |
| Linux x86_64 | aibox-vX.Y.Z-x86_64-unknown-linux-gnu.tar.gz |
Build from source
Requires a Rust toolchain:
git clone https://github.com/projectious-work/aibox.git
cd aibox
cargo install --path cli
Installs the binary to ~/.cargo/bin/.
Verify
aibox --version
# aibox X.Y.Z
Shell completion scripts
# Add to your shell profile for persistent completion scripts:
# Bash (~/.bashrc)
eval "$(aibox self completion bash)"
# Zsh (~/.zshrc)
eval "$(aibox self completion zsh)"
# Fish (~/.config/fish/config.fish)
aibox self completion fish | source
Next steps
4.2 - New Project
New Project
This guide walks through creating a new project from scratch with aibox.
Initialize the Project
mkdir my-app && cd my-app
git init
aibox init my-app --harness claude --addon python
The init command accepts these options:
| Option | Default | Description |
|---|
--base | debian | Base image |
<NAME> | Current directory name | Container and hostname |
--profile | human-dev | Usage profile: human-dev or warning-mode headless-runner |
--harness | claude | AI harnesses (can be repeated): claude, codex, gemini, aider, etc. |
--addon | — | Addon names (can be repeated): python, rust, node, go, latex, etc. |
--theme | gruvbox | Theme family |
--context-mode | processkit | Context layer: processkit or harness-only |
--processkit-version | latest stable tag | processkit content release to pin; explicit prerelease pins are supported |
If you omit options, aibox init runs interactively and prompts for each value.
What Gets Created
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).
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:
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:
[container.environment]
ANTHROPIC_API_KEY = "sk-ant-..."
GH_TOKEN = "github_pat_project_scoped_token"
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:
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:
aibox init my-app --processkit-version v1.0.0-alpha.3
aibox init my-app --include-prerelease
This picker is skipped when --context-mode harness-only is selected.
The Generated aibox.toml
The scaffolded config file comes with commented documentation for every option:
# 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.0" }
# 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"
After editing, regenerate devcontainer files:
Build and Start
aibox apply # Reconcile config, regenerate files, build image
aibox 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.
VS Code Integration
The generated devcontainer.json works with VS Code’s Dev Containers extension:
- Open the project folder in VS Code
- When prompted, click “Reopen in Container”
- VS Code builds and starts the container automatically
Both aibox up (terminal) and VS Code can use the same container simultaneously.
Next Steps
4.3 - Existing Project
Existing Project
This guide covers adding aibox to a project that already exists.
Create aibox.toml
If your project does not yet have a aibox.toml, create one manually or use init:
cd my-existing-project
aibox init my-existing-project --harness claude
init will not overwrite
If aibox.toml already exists, init will refuse to run. Either delete the existing file or edit it directly.
If you prefer to write it by hand:
[aibox]
project_name = "my-existing-project"
[container]
name = "my-existing-project"
hostname = "my-existing-project"
[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"
[ai]
harnesses = [
{ harness = "claude", enable = true, install = true },
]
[audio]
enabled = false
For a container-and-harness-only adoption with no processkit content, use:
[context]
mode = "harness-only"
[ai]
harnesses = [
{ harness = "claude", enable = true, install = true },
]
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".
Apply Devcontainer Files
Run apply to create the .devcontainer/ directory from your config:
This creates:
.devcontainer/Dockerfile.devcontainer/docker-compose.yml.devcontainer/devcontainer.json
Replacing Hand-Written Devcontainer Files
If your project already has a .devcontainer/ directory with hand-written files, you have two options:
Option A: Let aibox take over
- Back up your existing files:
cp -r .devcontainer .devcontainer.bak
- Run
aibox apply – it will overwrite the existing files - Move any custom configuration into
aibox.toml:- Environment variables go in
[container.environment] - Bind mounts go in
[[container.extra_volumes]] (or .aibox-local.toml for secrets and per-developer paths)
- Rebuild without cached image layers:
aibox apply --no-cache (--rebuild is an alias)
Option B: Keep hand-written files
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.
Running Diagnostics
Use doctor to validate your project structure:
This checks:
- Config file validity and version
- Container runtime availability (podman or docker)
.aibox-home/ directory existence.devcontainer/ directory existence- Image and process settings
Example output:
==> Running diagnostics...
✓ Config version is compatible
✓ Container runtime detected
✓ .aibox-home/ directory exists
✓ .devcontainer/ directory exists
✓ Generated compose enables an init reaper
✓ Runtime resource pressure is below configured thresholds
✓ Diagnostics complete
Migrating from .root/ to .aibox-home/
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:
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.
Migrating Context Structure
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.
Common gaps to watch for
- 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.
Build and Start
Once aibox.toml and .devcontainer/ are in place:
aibox apply # Regenerate files and build image
aibox up # Start and attach
The workflow is identical to a new project from this point forward.
Next Steps
5 - Container
5.1 - Base Image
Base Image
The base image is the foundation for all aibox container flavors. It provides a complete, opinionated development environment built on Debian Trixie Slim.
| Tool | Version / Source | Purpose |
|---|
| tmux | Debian package | Terminal multiplexer |
| Yazi | 25.4.8 (prebuilt binary from GitHub releases) | Terminal file manager |
| Vim | Debian package (vim + vim-runtime) | Editor |
| Git | Debian package | Version control |
| Claude CLI | Official install script | AI assistant |
ripgrep (rg) | Debian package | Fast recursive search (grep replacement) |
| fd | Debian package | Fast file finder (find replacement) |
| bat | Debian package | Syntax-highlighting cat replacement |
| eza | Debian package | Modern ls replacement with git integration |
| zoxide | Debian package | Smarter cd that learns your habits |
| fzf | Debian package | Fuzzy finder for files, history, and more |
| delta | Debian package | Syntax-highlighting diff viewer (used by git) |
| starship | Prebuilt binary | Minimal, fast shell prompt with context |
| curl | Debian package | HTTP client |
| jq | Debian package | JSON processor |
| less | Debian package | Pager |
| unzip | Debian package | Archive extraction |
| iproute2 | Debian package | 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.
Build Architecture
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.
tmux Configuration
Plugin Policy
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.
Key Bindings
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.
Layouts
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.
dev (default)
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.
Each tool gets the entire screen in its own window. Switch with Ctrl+g [/] or Ctrl+g 1-5.
Windows: files (yazi) | one window per harness | optional lazygit | shell
cowork – side-by-side coding with AI
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.
Opening Files from Yazi
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).
Theme
Gruvbox dark, defined in themes/gruvbox.conf.
Vim Configuration
Notable settings baked into the image:
- Leader key: Space
- Line numbers: Relative + absolute (hybrid)
- Indentation: 4 spaces default, 2 spaces for YAML, JSON, KDL, HTML, CSS, JavaScript
- Undo: Persistent undo files stored in
/home/aibox/.vim/undo - No swap files – clean container environment
- Color column at 88 (Black/PEP8 default)
- Grep program: ripgrep if available (
rg --vimgrep --smart-case) - Netrw: Tree mode, no banner, 25% width
- Colorscheme:
desert (ships with vim-runtime, no plugins needed)
Git Configuration
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
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 }.
Audio Support
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.
Configuration Persistence
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.
File Preview
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.
Container Entrypoint
CMD ["sleep", "infinity"]
The container stays alive and idle. Both VS Code and aibox up exec into it. tmux is never the container entrypoint – it is launched on attach.
5.2 - Container Configuration
Container Configuration
The [container] section in aibox.toml controls per-project container settings.
Container Identity
[container]
name = "my-project" # Container name (used by compose)
hostname = "my-project" # Container hostname
user = "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:
services:
my-project:
ports:
- "8080:80"
Post-Create Command
Run a command after the container is first created:
[container]
post_create_command = "npm install"
This maps to devcontainer.json’s postCreateCommand.
Network Keepalive
Prevent OrbStack/VM NAT from dropping idle connections:
[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.
Install additional apt packages by adding them to .devcontainer/Dockerfile.local, which is appended to the generated Dockerfile at build time:
RUN apt-get update && apt-get install -y --no-install-recommends \
universal-ctags graphviz postgresql-client \
&& rm -rf /var/lib/apt/lists/*
Ports, Volumes, and Environment Variables — docker-compose.override.yml
Use .devcontainer/docker-compose.override.yml to add port mappings, volume mounts, and environment variables:
services:
my-project: # must match [container] name in aibox.toml
ports:
- "8080:80"
- "5432:5432"
volumes:
- /host/data:/container/data:ro
environment:
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.
Compose Override
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.
Example — add a PostgreSQL sidecar:
services:
postgres:
image: postgres:16
environment:
POSTGRES_PASSWORD: dev
ports:
- "5432:5432"
Example — add depends_on to the main service:
services:
my-project: # must match [container] name in aibox.toml
depends_on:
- postgres
The override file is never overwritten by aibox apply — you own it, just like Dockerfile.local.
5.3 - Audio Support
Audio Support
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.
Why Audio Matters
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.
Architecture
Container Host
┌─────────────────────┐ ┌─────────────────────┐
│ Claude Code │ │ PulseAudio Server │
│ │ │ │ │ │
│ pulseaudio-utils │────>│ TCP :4714 │
│ sox │ │ │ │
│ .asoundrc │ │ Speakers / Mic │
└─────────────────────┘ └─────────────────────┘
The container sets PULSE_SERVER to point at the host’s PulseAudio TCP module. Audio data flows over the network socket.
Configuration in aibox.toml
[audio]
enabled = true
backend = "pulseaudio"
install = true
pulse_server = "tcp:host.docker.internal:4714"
| Field | Default | Description |
|---|
enabled | false | 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.
Host Setup
The fastest way to set up audio on your host is the built-in CLI command:
# Check if your host is ready
aibox doctor audio
# Automatic setup (macOS: installs PulseAudio, configures TCP, creates launchd agent)
aibox apply audio
aibox apply audio handles:
- Installing PulseAudio via Homebrew (macOS) if not present
- Configuring
~/.config/pulse/default.pa with the TCP module on port 4714 - Creating a launchd agent with
KeepAlive so PulseAudio auto-starts and restarts on crash (macOS) - Loading the TCP module immediately
aibox doctor audio diagnoses: PulseAudio installation, daemon status, TCP module, persistence config, port listening, launchd agent (macOS), and connectivity.
Both commands accept --port to override the default port (4714).
Manual setup
If you prefer manual configuration:
macOS
Install PulseAudio:
Enable the TCP module. Add to ~/.config/pulse/default.pa:
load-module module-native-protocol-tcp port=4714 auth-anonymous=1
Start PulseAudio:
Verify it is listening:
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:
[audio]
enabled = true
pulse_server = "tcp:192.168.64.1:4714"
Linux
PulseAudio is likely already running. Enable the TCP module:
pactl load-module module-native-protocol-tcp port=4714 auth-ip-acl=127.0.0.1;172.16.0.0/12;10.0.0.0/8;192.168.0.0/16
To make this persistent, add to ~/.config/pulse/default.pa:
load-module module-native-protocol-tcp port=4714 auth-ip-acl=127.0.0.1;172.16.0.0/12;10.0.0.0/8;192.168.0.0/16
Use host.docker.internal (Docker 20.10+) or the Docker bridge IP:
[audio]
enabled = true
pulse_server = "tcp:host.docker.internal:4714"
Firewall
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.
Claude Code OAuth in Containers
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 .asoundrc File
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.
Troubleshooting
No sound output
Verify PulseAudio is running on the host:
pulseaudio --check && echo "running" || echo "not running"
Verify the TCP module is loaded:
pactl list modules | grep module-native-protocol-tcp
Test from inside the container:
paplay /usr/share/sounds/freedesktop/stereo/bell.oga
If the file does not exist, use sox to generate a test tone:
play -n synth 0.5 sine 440
Connection refused
The PULSE_SERVER address is not reachable from the container.
- Check that the PulseAudio TCP module is listening on the correct port
- Check that
host.docker.internal resolves from inside the container:# From inside the container
getent hosts host.docker.internal
- Try using the host’s explicit IP address instead
Audio works but is choppy
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.
Disabling audio
If you do not need audio, set enabled = false in aibox.toml:
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.
5.4 - File Preview
File Preview
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.
Overview
There are two independent preview mechanisms:
| Mechanism | When to use |
|---|
| Yazi file preview | Browsing files — preview appears automatically in the right panel as you navigate |
| Standalone TUI viewers | Viewing a specific file in a pane, or piping output from a build tool |
Watch-mode (live-updating preview) is available via the standalone tools — see Watch-Mode Preview.
Yazi File Preview
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.
| Format | Extensions | Previewer | Requirement |
|---|
| JPEG / PNG | .jpg .jpeg .png | image (built-in) | chafa |
| GIF (incl. animated) | .gif | image (built-in) | chafa |
| WebP | .webp | image (built-in) | chafa |
| BMP | .bmp | image (built-in) | chafa |
| TIFF | .tiff .tif | image (built-in) | chafa |
| SVG | .svg | svg.yazi plugin | resvg or rsvg-convert |
| EPS | .eps | eps.yazi plugin | ghostscript (addon) |
| PDF | .pdf | pdf (built-in) | poppler-utils |
| Markdown | .md .markdown | rich-preview.yazi plugin | preview-enhanced addon |
| SQLite | .sqlite .sqlite3 .db | sqlite-preview.yazi plugin | data-preview addon |
| CSV / TSV | .csv .tsv | tabular-preview.yazi plugin | data-preview addon |
| Excel | .xls .xlsx | tabular-preview.yazi plugin | data-preview addon |
| Video | .mp4 .mkv .webm .avi | video (built-in) | ffmpeg (addon) |
| Text / code | most text formats | code (built-in) | — |
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:
aibox set addon preview-archive enabled --apply # adds chafa, timg, poppler, mutool, entr, p7zip, resvg
aibox set addon data-preview enabled --apply # adds sqlite3 and csvkit for data previews
aibox set addon preview-enhanced enabled --apply # adds python3-rich, ffmpeg, ghostscript
How previewer dispatch works
Yazi matches files against a list of prepend_previewers in ~/.config/yazi/yazi.toml. The first matching entry wins:
[plugin]
prepend_previewers = [
{ url = "*.svg", run = "svg" },
{ url = "*.eps", run = "eps" },
{ url = "*.md", run = "rich-preview" },
{ url = "*.jpg", run = "image" },
{ url = "*.jpeg", run = "image" },
{ url = "*.png", run = "image" },
{ url = "*.gif", run = "image" },
{ url = "*.webp", run = "image" },
{ url = "*.bmp", run = "image" },
{ url = "*.tiff", run = "image" },
{ url = "*.tif", run = "image" },
]
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.
Standalone TUI Viewers
These tools are available directly in the shell for viewing a specific file or
integrating into a pipeline when the preview-archive addon is enabled.
chafa — universal image renderer
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.
# View any raster image
chafa 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 size
chafa -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 — terminal image and document viewer
timg renders images, animated GIFs, videos, and PDFs (page by page) directly in the terminal.
# View an image
timg photo.jpg
# View a PDF — renders all pages sequentially
timg document.pdf
# View a specific PDF page (page 2)
timg -p2 document.pdf
# Constrain output size
timg -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
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:
source file changes → entr triggers → rasteriser produces PNG → timg renders PNG in terminal
Install the preview-archive addon to get the watch-mode tools (entr,
mupdf-tools, resvg, timg).
PDF watch preview ⟳
Run this in a dedicated pane while editing your LaTeX or Typst source:
pdf-watch wraps the underlying entr + mutool draw + timg --clear pipeline and re-renders page 1 whenever the PDF changes:
ls output.pdf | entr -s 'mutool draw -o /tmp/p.png output.pdf 1 && timg --clear /tmp/p.png'
| Part | Role |
|---|
entr | 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.
SVG watch preview ⟳
ls diagram.svg | entr -s 'resvg diagram.svg /tmp/d.png && timg --clear /tmp/d.png'
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.
General pattern
The same entr + rasteriser + timg pattern works for any file format that has a headless rasteriser:
# Watch a file and re-render on change
ls <file> | entr -s '<rasterise-command> && timg --clear <output.png>'
| Source format | Rasteriser command |
|---|
| PDF (page 1) | mutool draw -o /tmp/p.png file.pdf 1 |
| SVG | resvg file.svg /tmp/p.png |
| EPS | gs -dBATCH -dNOPAUSE -sDEVICE=png16m -r150 -sOutputFile=/tmp/p.png file.eps |
Pane layout for watch preview
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.
| Format | Yazi preview | chafa | timg | Watch-mode |
|---|
| JPEG / PNG | ✓ | ✓ | ✓ | — |
| GIF (animated) | ✓ | ✓ | ✓ | — |
| WebP | ✓ | ✓ | ✓ | — |
| BMP | ✓ | ✓ | ✓ | — |
| TIFF | ✓ | ✓ | ✓ | — |
| SVG | ✓ (resvg) | ✓ (librsvg) | — | ✓ (resvg) |
| EPS | ✓ (ghostscript) | — | — | ✓ (ghostscript) |
| PDF | ✓ (poppler) | — | ✓ | ✓ (mutool) |
| Video | ✓ (ffmpeg) | — | ✓ | — |
.excalidraw | text fallback | — | — | — |
5.5 - Runtime Operations
How to start, inspect, rebuild, and troubleshoot a running aibox workspace.
Runtime Operations
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.
Start and Attach
aibox up
aibox up --layout focus
aibox up --apply
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.
Stop or Remove
aibox down
aibox delete runtime
down stops the Compose project. delete runtime removes the container while
preserving project files and .aibox-home/.
Rebuild
aibox apply
aibox apply --no-cache
aibox apply --config-only
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.
Inspect Runtime State
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.
Resource Thresholds
Configure warning thresholds in aibox.toml:
[container.resource_thresholds]
memory_mib_warn = 4096
process_count_warn = 400
processkit_mcp_python_warn = 50
aibox doctor uses these values when reporting runtime pressure.
Compose Identity
Generated Compose output includes:
- a top-level project name derived from
[container].name - an explicit image name
- a main service named after the project
container_name = [container].nameinit: true for PID 1 process reaping
This keeps Docker Desktop, OrbStack, and Compose UIs from grouping unrelated
aibox projects under a generic devcontainer identity.
Existing Containers After Generator Changes
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:
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.
Common Symptoms
| Symptom | First checks |
|---|
| AI process disappears | aibox get runtime --resources, then inspect oom_kill_count |
| OrbStack groups projects oddly | rerun aibox apply, then recreate the container |
| Network drops after idle time | set [container] keepalive = true |
| Build keeps using stale layers | run aibox apply --no-cache |
| Runtime starts but tools are missing | check selected addons with aibox describe workspace-manifest |
Podman Notes
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.
6 - Tutorials
End-to-end aibox v1 project walkthroughs.
Tutorials
These tutorials start with an empty directory and finish with a working result.
Use them when you want the complete sequence rather than a command reference.
6.1 - Create a local project with processkit
Build and deploy a new project locally with aibox v1, then install the processkit process base.
Create a local project with processkit
This tutorial starts with an empty directory, deploys a workspace through the
v1 Compose backend, and installs the processkit v1 process base into the
project. Both products are prereleases, so the example uses exact versions.
Before you begin
Install a Docker- or Podman-compatible Compose runtime, curl, tar, and
sha256sum. Then install the exact aibox v1 release shown on the
releases page:
curl -fsSL https://raw.githubusercontent.com/projectious-work/aibox/main/scripts/install.sh |
VERSION=1.0.0-alpha.1 bash
aibox --version
If that release is not published yet, use the latest v1 prerelease shown on the
releases page and substitute its version below.
Scaffold the project
mkdir hello-aibox
cd hello-aibox
aibox init hello-aibox --context-mode harness-only --harness codex --no-container
harness-only keeps aibox’s legacy processkit installer out of the project.
The process base is installed later by the processkit v1 CLI, through its own
native boundary.
Add an application and image source:
# image-source/Containerfile
FROM docker.io/library/alpine:3.22
CMD ["sh", "-c", "while true; do date; sleep 30; done"]
Create image-source/ and save the file there. Build and push the image to a
registry you can access:
aibox image build --push --output json
Before running that command, add a complete [orchestration] contract to
aibox.toml. Replace the image reference, digest, and owner with your values:
[orchestration]
enabled = true
[orchestration.image]
reference = "ghcr.io/YOUR-ACCOUNT/hello-aibox:dev"
digest = "sha256:0000000000000000000000000000000000000000000000000000000000000000"
platform = "linux-amd64"
[orchestration.image.build]
context = "image-source"
dockerfile = "Containerfile"
[orchestration.fleet]
name = "hello-aibox"
services = [{ name = "workspace" }]
[orchestration.target]
backend = "compose"
reference = "docker-context:default"
scope = "hello-aibox"
[orchestration.deployment]
name = "hello-aibox-local"
owner_id = "YOUR-STABLE-OWNER-ID"
[[orchestration.connections]]
name = "shell"
service = "workspace"
transport = "compose-exec"
command = ["sh"]
The first build uses that syntactically valid, all-zero placeholder digest.
After the push,
copy the returned registry manifest digest into orchestration.image.digest.
The deployment never consumes a mutable tag by itself.
Plan and deploy locally
aibox config compile --output json
aibox deploy plan --output json
aibox deploy apply --output json
aibox deploy status
aibox connect shell
The plan is read-only. Apply creates only the Compose resources carrying this
deployment’s ownership labels and writes its local deployment record.
Install the processkit process base
Download one exact processkit v1 release, verify both release assets, and run
the native installer. The filenames and checksums are published with every
processkit release.
PROCESSKIT_VERSION=v1.0.0-alpha.4
PROCESSKIT_TARGET=aarch64-unknown-linux-gnu
PROCESSKIT_DIR=.aibox/processkit-release
mkdir -p "${PROCESSKIT_DIR}"
curl -fL -o "${PROCESSKIT_DIR}/processkit.tar.gz" \
"https://github.com/projectious-work/processkit/releases/download/${PROCESSKIT_VERSION}/processkit-${PROCESSKIT_VERSION}.tar.gz"
curl -fL -o "${PROCESSKIT_DIR}/processkit.tar.gz.sha256" \
"https://github.com/projectious-work/processkit/releases/download/${PROCESSKIT_VERSION}/processkit-${PROCESSKIT_VERSION}.tar.gz.sha256"
curl -fL -o "${PROCESSKIT_DIR}/processkit" \
"https://github.com/projectious-work/processkit/releases/download/${PROCESSKIT_VERSION}/processkit-${PROCESSKIT_VERSION}-${PROCESSKIT_TARGET}"
curl -fL -o "${PROCESSKIT_DIR}/processkit.sha256" \
"https://github.com/projectious-work/processkit/releases/download/${PROCESSKIT_VERSION}/processkit-${PROCESSKIT_VERSION}-${PROCESSKIT_TARGET}.sha256"
(cd "${PROCESSKIT_DIR}" && sed 's/ .*/ processkit.tar.gz/' processkit.tar.gz.sha256 | sha256sum --check)
(cd "${PROCESSKIT_DIR}" && sed 's/ .*/ processkit/' processkit.sha256 | sha256sum --check)
chmod +x "${PROCESSKIT_DIR}/processkit"
tar -xzf "${PROCESSKIT_DIR}/processkit.tar.gz" -C "${PROCESSKIT_DIR}"
"${PROCESSKIT_DIR}/processkit" install \
--root . \
--distribution "${PROCESSKIT_DIR}/processkit-${PROCESSKIT_VERSION}" \
--profile managed \
--harness codex \
--yes
"${PROCESSKIT_DIR}/processkit" verify --root . --json
Choose the target matching your host (aarch64-unknown-linux-gnu is the
current v1 alpha target). The managed profile installs the shared process
base, canonical AGENTS.md, and runtime policy. verify checks installed
provenance and managed-path drift without changing the project.
Commit aibox.toml, aibox.lock, AGENTS.md, and the installed context/
tree. Do not commit .aibox/processkit-release/; it is only a download staging
directory.
Clean up
aibox deploy destroy --output json
Destroy refuses resources that do not match the recorded identity and ownership
labels.
7 - Addons
7.1 - Overview
Addons
aibox uses the Debian runtime image family (base-debian-v0.26.x for legacy releases, base-debian-runtime-v0.27.0+ after the image-tag cutover) with 31 composable addons that install language runtimes, tool bundles, documentation frameworks, and AI coding agents into your container.
Managing Addons
Via CLI
# See all available addons
aibox get addon
# Add an addon (updates aibox.toml and runs apply)
aibox set addon python
# Remove an addon
aibox delete addon python
# View addon details (tools, versions)
aibox describe addon rust
# Emit the machine-readable addon catalog index
aibox describe addon-catalog -o json
Via aibox.toml
[addons.python.tools]
python = { version = "3.14" }
uv = { version = "0.12.0" }
[addons.rust.tools]
rustc = { version = "1.97.1" }
clippy = {}
rustfmt = {}
[addons.node.tools]
node = { version = "26" }
pnpm = { version = "11.18.0" }
Each addon has default-enabled tools that are included automatically, and optional tools you can enable explicitly. Tools with version selection let you pick from curated, tested versions.
aibox describe addon-catalog -o json emits the stable aibox.addon-catalog.v0
index used by downstream automation. It includes each addon’s profile intent,
automation usage class, supported aibox profiles, exported surfaces,
dependencies, and tool metadata. Canonical processkit Artifact{kind=addon-spec}
emission remains gated on the upstream processkit schema release.
After editing aibox.toml, run aibox apply to regenerate the Dockerfile and rebuild.
Available Addons
Language Runtimes
| Addon | Default Tools | Optional Tools |
|---|
python | python (3.12/3.13/3.14), uv (0.7/0.11.10/0.11.11/0.11.15/0.11.19/0.11.26/0.11.32/0.12.0) | poetry (1.8/2.0/2.4.1), pdm (2.22/2.26.9/2.27.0/2.28.0) |
rust | rustc (1.90/1.91/1.92/1.93/1.94/1.94.1/1.96.0/1.96.1/1.97.1), clippy, rustfmt | — |
node | node (20/22/24/26), pnpm (9/10/11.1.3/11.5.2/11.10.0/11.17.0/11.18.0) | yarn (4/4.16.0/4.17.0), bun (1.2/1.3.14) |
go | go (1.25/1.26/1.26.3/1.26.4/1.26.5) | — |
typst | typst (0.13.1/0.14.2/0.15.0) | — |
latex | texlive-core, texlive-recommended, texlive-fonts, biber, texlive-code, texlive-diagrams, texlive-math | texlive-music, texlive-chemistry |
| Addon | Default Tools | Optional Tools |
|---|
infrastructure | opentofu, ansible, packer | — |
git-ui | gh, lazygit | — |
preview-archive | chafa, librsvg, poppler, timg, mupdf, entr, p7zip, resvg | — |
preview-enhanced | rich, ffmpeg, ghostscript | — |
data-preview | sqlite3, csvkit | — |
audio-voice | sox, pulseaudio-utils, ALSA PulseAudio plugins | — |
kubernetes | kubectl, helm, kustomize | k9s |
cloud-aws | aws-cli | — |
cloud-gcp | gcloud-cli | — |
cloud-azure | azure-cli | — |
Documentation Frameworks
| Addon | Tools |
|---|
docs-mkdocs | mkdocs + mkdocs-material |
docs-zensical | zensical |
docs-docusaurus | docusaurus |
docs-starlight | starlight |
docs-mdbook | mdbook |
docs-hugo | hugo |
AI Harnesses
AI harnesses are selected under [ai], not as public addon blocks. aibox still
uses internal install recipes for container CLIs when install = true.
[ai]
harnesses = [
{ harness = "claude", enable = true, install = true },
{ harness = "codex", enable = true, install = true, version = "latest" },
]
Legacy [addons.ai-*.tools] entries are accepted for compatibility, but fresh
scaffolding keeps AI configuration in the [ai] section.
Addons and Skills
As of v0.16.0, all skills live in processkit.
Projects using context.mode = "processkit" install processkit skills under
context/skills/ independently from addons. Projects using
context.mode = "harness-only" do not install processkit skills at all. There
is no longer an addon-driven “auto-deploy a skill” mechanism.
The relevant skills for each addon’s tooling are still in the catalogue —
agents pick them up via skill descriptions, not via addon membership:
| Addon | Naturally relevant skills |
|---|
python | python-best-practices, fastapi-patterns, pandas-polars |
rust | rust-conventions, concurrency-patterns |
go | concurrency-patterns and the Go-flavoured patterns shipped upstream |
node | typescript-patterns, tailwind |
latex / typst | documentation |
git-ui | git-workflow |
kubernetes | container-orchestration |
cloudflare | Cloudflare Tunnel workflows |
infrastructure | terraform-flavoured patterns shipped upstream |
See Skills (via processkit) for the full split.
How Addons Work
When you run aibox apply, the CLI:
- Reads
[addons] from aibox.toml - 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.
For one-off apt packages not covered by addons, use extra_packages:
[container]
extra_packages = ["universal-ctags", "graphviz", "postgresql-client"]
These are installed during aibox apply via the generated Dockerfile. They persist across container restarts but are reinstalled on image rebuild.
Version Selection
Each tool in an addon has a curated list of supported versions. Use aibox describe addon <name> to see available versions:
$ aibox describe addon python
Add-on: python
Recipe version: 1.0.0
TOOL DEFAULT VERSION SUPPORTED
python yes 3.14 3.12, 3.13, 3.14
uv yes 0.12.0 0.7, 0.11.10, 0.11.11, 0.11.15, 0.11.19, 0.11.26, 0.11.32, 0.12.0
poetry no 2.4.1 1.8, 2.0, 2.4.1
pdm no 2.28.0 2.22, 2.26.9, 2.27.0, 2.28.0
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.
7.2 - Language Runtimes
Language Runtime Addons
Language runtimes install compilers, interpreters, and package managers into your container.
Python
[addons.python.tools]
python = { version = "3.14" } # 3.12, 3.13, 3.14
uv = { version = "0.12.0" } # 0.7, 0.11.10, 0.11.11, 0.11.15, 0.11.19, 0.11.26, 0.11.32, 0.12.0
# poetry = { version = "2.4.1" } # Optional: 1.8, 2.0, 2.4.1
# pdm = { version = "2.28.0" } # Optional: 2.22, 2.26.9, 2.27.0, 2.28.0
Installs Python, pip, venv, and uv (fast package manager). The base image pins uv to the curated default instead of following a floating latest image tag. Poetry and PDM are available but not enabled by default.
Rust
[addons.rust.tools]
rustc = { version = "1.97.1" } # 1.90, 1.91, 1.92, 1.93, 1.94, 1.94.1, 1.96.0, 1.96.1, 1.97.1
clippy = {} # Linter (no version selection)
rustfmt = {} # Formatter (no version selection)
Installs the Rust toolchain via rustup with clippy and rustfmt. Uses a multi-stage Docker build — compilation happens in a builder stage and only the toolchain is copied to the runtime image.
Node.js
[addons.node.tools]
node = { version = "26" } # 20, 22, 24, 26
pnpm = { version = "11.18.0" } # 9, 10, 11.1.3, 11.5.2, 11.10.0, 11.17.0, 11.18.0
# yarn = { version = "4.17.0" } # Optional: 4, 4.16.0, 4.17.0
# bun = { version = "1.3.14" } # Optional
Installs Node.js via NodeSource, plus pnpm as default package manager. Yarn and Bun are available but not enabled by default.
Go
[addons.go.tools]
go = { version = "1.26.5" } # 1.25, 1.26, 1.26.3, 1.26.4, 1.26.5
Installs Go and sets up GOPATH.
Typst
[addons.typst.tools]
typst = { version = "0.15.0" } # 0.13.1, 0.14.2, 0.15.0
Installs the Typst typesetting system for modern document creation.
LaTeX
[addons.latex.tools]
texlive-core = {} # Base TeX Live installation
texlive-recommended = {} # Common packages
texlive-fonts = {} # Font packages
biber = {} # Bibliography processor
texlive-code = {} # Code listing packages
texlive-diagrams = {} # TikZ, PGF, circuit diagrams
texlive-math = {} # Math packages
# texlive-music = {} # Optional: LilyPond, MusiXTeX
# texlive-chemistry = {} # Optional: chemfig, mhchem
Installs TeX Live via a multi-stage Docker build. The full TeX Live installation happens in a builder stage and only the final tree is copied to the runtime image, keeping layer sizes manageable.
Use the LaTeX build and preview workflow to define named
documents, run reproducible latexmk builds and watchers inside the development
container, and serve completed PDFs through the read-only EmbedPDF sidecar.
Emoji rendering with LuaLaTeX
The runtime image ships fonts-noto-color-emoji so emoji glyphs render
correctly in LuaLaTeX documents. To wire it up, add the following to
your preamble:
\directlua{luaotfload.add_fallback("emojifallback",{"NotoColorEmoji:mode=harf;"})}
\setmainfont{FreeSans}[Scale=0.95,RawFeature={fallback=emojifallback}]
Without the fallback configured, emoji characters render as
missing-glyph boxes even though the font is installed.
7.3 - Tool Bundles
Tool bundles install infrastructure, orchestration, and cloud CLI tools.
Git UI
[addons.git-ui.tools]
gh = {} # GitHub CLI
lazygit = {} # Interactive Git TUI
The git-ui addon is optional. Select it when a project needs GitHub CLI
automation or lazygit inside the container; omit it to avoid installing those
tools. This aibox repo may enable it for maintenance workflows such as release
checks and GitHub issue/release work, but downstream projects do not need it by
default.
[addons.preview-archive.tools]
chafa = {}
timg = {}
poppler = {}
mupdf = {}
entr = {}
p7zip = {}
resvg = {}
preview-archive contains the terminal image/PDF/SVG/archive helper binaries
used by Yazi previews and watch-mode document workflows. Keep it disabled for
lean headless projects that do not inspect media or generated documents inside
the terminal.
preview-enhanced layers Markdown, EPS, video, and Ghostscript support on top
of preview-archive.
Data Preview
[addons.data-preview.tools]
sqlite3 = {}
csvkit = {}
data-preview adds read-only SQLite inspection and CSV, TSV, XLS, and XLSX
formatting for the generated Yazi preview plugins.
Audio and Voice
Audio bridging uses the internal audio-voice recipe for Sox, PulseAudio
client tools, and ALSA PulseAudio plugins. aibox selects this recipe
automatically when [audio] enabled = true and install = true; projects normally do not need to add
[addons.audio-voice.tools] manually.
Infrastructure
[addons.infrastructure.tools]
opentofu = {} # Infrastructure-as-code (Terraform alternative)
ansible = {} # Configuration management
packer = {} # Machine image builder
OpenTofu defaults to 1.12.5, Packer to 1.16.0, and Ansible to 14.2.0.
OpenTofu and Packer are installed in a multi-stage builder. Ansible is installed via pip.
Kubernetes
[addons.kubernetes.tools]
kubectl = {} # Kubernetes CLI
helm = {} # Package manager
kustomize = {} # Configuration customization
# k9s = {} # Optional: terminal UI for Kubernetes
kubectl defaults to 1.36.3, Helm to 4.2.3, Kustomize to 5.8.1, and k9s to 0.51.0.
All tools are downloaded as static binaries in a multi-stage builder.
Cloud Providers
AWS
[addons.cloud-aws.tools]
aws-cli = {}
Installs the AWS CLI v2.
Google Cloud
[addons.cloud-gcp.tools]
gcloud-cli = {}
Installs the Google Cloud CLI via the official APT repository.
Azure
[addons.cloud-azure.tools]
azure-cli = {}
Installs the Azure CLI via pip.
7.4 - Documentation Frameworks
Documentation Framework Addons
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.164.0, mdBook 0.5.4,
MkDocs 1.6.1 with Material 9.7.7, and Zensical 0.0.52. Starlight remains
scaffolded through the upstream create-starlight package.
Example
[addons.docs-docusaurus.tools]
docusaurus = {}
After aibox apply, the documentation tool is available inside the container. Initialize your docs project as usual (e.g., npx create-docusaurus@latest docs classic).
7.5 - LaTeX Build and Preview
LaTeX Build and Preview
The latex addon supplies TeX Live, latexmk, bibliography tools, fonts, and
common package groups. aibox adds a project-level build contract on top so
humans and agents use the same engine, cache, output paths, and document names.
Enable the addon and declare one or more documents:
[addons.latex.tools]
texlive-core = {}
texlive-recommended = {}
texlive-fonts = {}
biber = {}
[latex]
engine = "lualatex"
cache_dir = ".latex-cache"
options = []
[[latex.documents]]
name = "overview"
source = "docs/overview/overview.tex"
output_dir = ".latex-cache/overview"
options = []
extra_dirs = []
[[latex.documents]]
name = "appendix"
source = "docs/appendix/appendix.tex"
output_dir = ".latex-cache/appendix"
options = ["-shell-escape"]
extra_dirs = ["figs"]
[latex.preview]
enabled = true
engine = "embedpdf"
bind = "127.0.0.1"
port = 8765
# document = "overview" # optional compatibility-route default
allow_public = false
Supported engines are lualatex, pdflatex, xelatex, and tectonic.
Continuous watch mode uses latexmk, so tectonic configurations support
one-shot builds only.
Build and watch
Run these commands inside the development container. aibox apply generates
them under .aibox-home/.local/bin, which is already on the container PATH:
aibox-latex-build # every configured document
aibox-latex-build overview # one configured document
aibox-latex-watch overview # foreground watcher; stop with Ctrl-C
Builds use non-interactive, file-and-line-error, halt-on-error flags. Watch mode
adds latexmk -pvc -view=none, leaving browser preview ownership to the sidecar.
TEXMFVAR and TEXMFCONFIG live below latex.cache_dir, so TeX does not write
mutable state to the user’s global TeX tree.
Compilation never runs on the host or in the preview sidecar. The scripts use
the TeX installation in the main development container, keep the watch process
in the foreground, and write PDFs below each configured output_dir. Run one
watcher per document when several documents should rebuild concurrently.
Running aibox apply adds a concise, conditional aibox-managed LaTeX section
to AGENTS.md. This is the primary instruction surface for AI agents and gives
them the configured container commands, companion health check, preview URLs,
and document paths without adding another root-level guidance file.
Live PDF preview
When preview is enabled, aibox apply generates a dedicated Compose sidecar and
port mapping. Host-side aibox up starts that sidecar, which serves every
configured document from the project workspace mounted read-only. The sidecar
does not contain a TeX toolchain and cannot modify the workspace.
latex.preview.document chooses the preferred document used by compatibility
routes; it does not exclude the others.
Inspect its logs with:
docker compose -f .devcontainer/docker-compose.yml logs <project-container-name>-latex-preview
aibox down stops the sidecar with the rest of the Compose project. A
subsequent aibox up starts it again. With multiple documents, the root URL
displays a selection page. Each PDF also has a stable direct URL:
http://127.0.0.1:8765/
http://127.0.0.1:8765/documents/overview/
http://127.0.0.1:8765/documents/appendix/
The stable URL is http://127.0.0.1:8765/. The service watches the completed
PDF output for every document, waits for its metadata to remain stable across
multiple polls, and then sends a document-specific SSE revision event. This
prevents the browser from fetching a partially-written PDF. The browser
requests a versioned PDF URL on reload so a stale cache cannot hide a new
build. Page and zoom state are retained separately for each document.
The viewer uses the pinned
@embedpdf/snippet
browser package. Its default toolbar provides navigation, zoom, search,
thumbnails, and outline support when the PDF contains an outline. The browser
must be able to reach jsDelivr to load the pinned viewer module; the PDF itself
is served by the local preview sidecar.
Host and network access
The preview helper listens on 0.0.0.0:8765 inside its isolated sidecar. The
generated Compose mapping publishes that internal port only on the configured
host address and port. The secure default is therefore accessible from the
host browser but not from other machines:
[latex.preview]
enabled = true
bind = "127.0.0.1"
port = 8765
allow_public = false
Run aibox apply after changing this configuration, then run aibox up on the
host. Do not add a manual override mapping;
aibox generates 127.0.0.1:8765:8765 in .devcontainer/docker-compose.yml.
For access from another machine on the local network, explicitly expose the
unauthenticated endpoint:
[latex.preview]
enabled = true
bind = "0.0.0.0"
port = 8765
allow_public = true
This generates 0.0.0.0:8765:8765. Open http://<host-ip>:8765/ and ensure
the host firewall permits the port. Prefer the loopback default plus SSH
forwarding when possible.
Remote hosts over SSH
The default bind address is loopback and is suitable for SSH forwarding:
ssh -L 8765:127.0.0.1:8765 user@remote-host
Then open http://127.0.0.1:8765/ locally. Publishing on a non-loopback host
address is rejected unless allow_public = true is also set. That opt-in
exposes an unauthenticated PDF endpoint; prefer an SSH tunnel.
8 - AI Providers
8.1 - Claude
Claude Code
Claude Code by Anthropic is a terminal-based AI coding assistant. It’s the default provider in aibox.
Setup
[ai]
harnesses = [
{ harness = "claude", enable = true, install = true },
]
Run aibox apply, then inside the container:
claude # Launches Claude Code CLI
On first launch, Claude prompts for authentication via browser login.
Configuration
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.
Audio (Voice)
Claude Code supports voice input. To enable it, configure audio bridging:
MCP Integration
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.
To add MCP servers:
# aibox.toml — team-shared servers
[[ai.mcp.servers]]
name = "github"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-github"]
# .aibox-local.toml — personal servers (not committed)
[[mcp.servers]]
name = "my-internal-tool"
command = "npx"
args = ["-y", "@acme/internal-mcp-server"]
tmux Integration
When Claude is configured as a provider, tmux layouts include a dedicated Claude pane:
- dev layout: Claude gets its own window
- focus layout: Claude gets its own window
- cowork layout: Claude appears in a side-by-side pane next to the editor
8.2 - Aider
Aider
Aider is an open-source AI pair programming tool that works with multiple LLM providers from the terminal.
Setup
[ai]
harnesses = [
{ harness = "aider", enable = true, install = true },
]
Run aibox apply, then inside the container:
aider # Launches Aider CLI
API Key
Aider requires an API key for the LLM provider you want to use. Set it in your environment:
[container.environment]
ANTHROPIC_API_KEY = "sk-ant-..."
# Or for OpenAI:
# OPENAI_API_KEY = "sk-..."
Alternatively, create a .aider.conf.yml in .aibox-home/.aider/.
Configuration
Aider’s configuration is persisted in .aibox-home/.aider/, mounted at /home/aibox/.aider/.
Installation
Aider is installed via uv tool install aider-chat — a fast, isolated Python tool installation.
8.3 - Gemini
Gemini
Gemini CLI is Google’s command-line interface for Gemini AI models.
Setup
[ai]
harnesses = [
{ harness = "gemini", enable = true, install = true },
]
Run aibox apply, then inside the container:
gemini # Launches Gemini CLI
API Key
[container.environment]
GOOGLE_API_KEY = "..."
Configuration
Gemini’s configuration is persisted in .aibox-home/.gemini/, mounted at /home/aibox/.gemini/.
MCP Integration
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:
# 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"]
Installation
Gemini CLI is installed via npm (npm install -g @google/generative-ai-cli), with a pip fallback.
8.4 - Mistral
Mistral (SDK)
SDK addon — not an interactive CLI
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.
Setup
[ai]
model_providers = ["mistral"]
[addons.ai-mistral.tools]
mistral = {}
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:
from mistralai import Mistral
client = Mistral(api_key="...")
API Key
[container.environment]
MISTRAL_API_KEY = "..."
MCP Integration
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.
Installation
The Mistral AI SDK is installed via pip (pip install --no-cache-dir mistralai).
8.5 - OpenAI (Codex CLI)
OpenAI Codex CLI
Codex CLI is OpenAI’s open-source terminal coding agent. Built in Rust, GA since April 2025.
Setup
[ai]
harnesses = [
{ harness = "codex", enable = true, install = true },
]
Run aibox apply, then inside the container:
codex # Launches OpenAI Codex CLI
API Key
[container.environment]
OPENAI_API_KEY = "sk-..."
Alternatively, use a ChatGPT Plus/Pro/Team/Enterprise account — Codex prompts for authentication on first launch.
Configuration
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.aibox-home/.codex/prompts/pk-*.md — generated processkit custom-prompt aliases
Separately, aibox also generates project-local .codex/config.toml MCP server registration. In processkit mode it also generates .codex/hooks.json processkit hook configuration.
processkit commands
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.
MCP Integration
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:
# 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"]
Installation
Codex CLI is installed via npm (npm install -g @openai/codex). To pin a specific version, set it in aibox.toml:
[ai]
harnesses = [
{ harness = "codex", enable = true, install = true, version = "0.1.0" },
]
Sandbox prerequisites
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:
services:
<container-name>:
security_opt:
- seccomp=unconfined
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.
See OpenAI’s Codex sandbox prerequisites for the upstream requirements.
8.6 - Copilot (GitHub)
GitHub Copilot CLI
GitHub Copilot CLI is GitHub’s terminal coding agent. GA since February 2026, validated as a Dev Container feature.
Setup
[ai]
harnesses = [
{ harness = "copilot", enable = true, install = true },
]
Run aibox apply, then inside the container:
copilot /login # Authenticate on first launch
copilot # Launches GitHub Copilot CLI
Requirements
A GitHub Copilot subscription (Individual, Business, or Enterprise) is required.
Configuration
Copilot’s configuration is persisted in .aibox-home/.copilot/, mounted at /home/aibox/.copilot/.
Key files:
.copilot/config.json — Copilot settings (overridable via COPILOT_HOME)
MCP Integration
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:
# 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"]
Installation
GitHub Copilot CLI is installed via npm (npm install -g @github/copilot).
8.7 - Continue
Continue CLI
Continue is an open-source, provider-agnostic coding agent CLI. Designed for headless environments and containers (Apache 2.0).
Setup
[ai]
harnesses = [
{ harness = "continue", enable = true, install = true },
]
Run aibox apply, then inside the container:
cn # Interactive mode
cn -p "..." # Headless/non-interactive mode (great for scripts and CI)
Note: the binary is cn, not continue.
API Key
Continue is provider-agnostic — configure the LLM you want to use:
[container.environment]
CONTINUE_API_KEY = "..." # Generic key for headless use
# Or provider-specific:
# ANTHROPIC_API_KEY = "sk-ant-..."
# OPENAI_API_KEY = "sk-..."
Configuration
Continue’s configuration is persisted in .aibox-home/.continue/, mounted at /home/aibox/.continue/.
MCP Integration
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:
# 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"]
Installation
Continue CLI is installed via npm (npm install -g @continuedev/cli).
9 - Project Context
9.1 - Context Overview
Context System Overview
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.
The Problem
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.
How Context Files Work
With the default context.mode = "processkit" and a real
[processkit].version pinned, your project looks something like this after
aibox init and aibox apply:
my-project/
├── AGENTS.md # Canonical agent entry — rendered from processkit scaffolding
├── CLAUDE.md # Thin pointer to AGENTS.md (provider entry file)
├── aibox.toml
├── .devcontainer/
└── context/
├── skills/ # Editable skill copies
├── processes/ # release, code-review, feature-development, bug-fix
├── schemas/ # primitive schemas
├── state-machines/ # state machine definitions
└── templates/
└── processkit/
└── v0.27.4/ # Immutable upstream snapshot, base of three-way diffs
With context.mode = "harness-only", aibox writes only the container and
harness surfaces:
my-project/
├── AGENTS.md # Minimal project instructions generated by aibox
├── CLAUDE.md # Thin pointer to AGENTS.md when Claude is enabled
├── aibox.toml
├── .aibox-home/
└── .devcontainer/
Harness-only mode intentionally omits processkit content, processkit MCP
gateway config, processkit hooks/preauth, processkit command adapters, and
processkit Migration entities. Generated text surfaces contain no processkit
references.
AGENTS.md, CLAUDE.md, and provider files
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 — Developer Identity
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
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:
Version Tracking
Resolved versions are split between desired and applied state:
[context]
mode = "processkit"
packages = ["product"]
[processkit]
version = "v0.27.4"
[processkit.context]
schema_version = "1.0.0"
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.
Relationship to aibox.toml
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:
[context]
mode = "processkit"
packages = ["product"]
[processkit]
source = "https://github.com/projectious-work/processkit.git"
version = "v0.27.4"
Run aibox apply after editing [processkit].version to pull a new release.
For harness-only projects, set only:
[context]
mode = "harness-only"
Design Principles
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.
9.2 - Skill Selection
Skill Selection
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:
[skills]
include = [
"pk-doctor",
"status-briefing",
]
exclude = [
# "skill-to-omit",
]
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.
Where the Content Lands
After aibox init and aibox apply with [context].mode = "processkit" and
[processkit].version pinned:
context/
├── skills/ # Editable copies of installed skills
├── processes/ # release, code-review, feature-development, bug-fix
├── schemas/ # primitive schemas
├── state-machines/ # state machine definitions
└── templates/
└── processkit/
└── v0.25.7/
├── context/
│ ├── skills/
│ └── schemas/
├── .processkit/
│ └── packages/ # The package YAMLs themselves
└── AGENTS.md
The version path (v0.25.7 above) is whatever [processkit].version is pinned
to in aibox.toml.
Harness-only projects do not install this content and do not create
context/templates/processkit/.
Upstream Source
The skills are owned by processkit:
To consume a fork or a private mirror, point [processkit].source at it (see
[processkit] configuration).
9.3 - Migration
Migration
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.
How Version Tracking Works
Two pieces track the version:
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:
[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.
Running Doctor
Doctor performs the following checks:
- Validates
aibox.toml syntax and field values - Detects the container runtime (podman or docker)
- Checks for
.aibox-home/ and .devcontainer/ directories - Compares the current embedded context schema against the configured target
schema version
- Validates expected context/processkit files for the chosen context mode
Example output when migration is needed:
==> Running diagnostics...
✓ Config version: 0.1.0
✓ Image: python
✓ Process: product
✓ Container name: my-app
✓ Container runtime: podman
✓ .aibox-home/ directory exists at .aibox-home
✓ .devcontainer/ directory exists
! Context schema: current 1.0.0, target 2.0.0 (migration needed)
✓ Diagnostics complete
Migration Artifacts
When a schema mismatch is detected, doctor generates review artifacts in
.aibox/migration/:
.aibox/
└── migration/
├── schema-current.md
├── schema-target.md
├── diff.md
└── migration-prompt.md
When processkit content, runtime-home drift, model/provider changes, or similar
processkit-mode updates need human review, aibox emits Migration entities in
context/migrations/:
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:
aibox get migration # show pending/in-progress migrations
aibox set migration <id> in-progress # begin a pending migration
aibox apply migration <id> # mark a migration as applied
aibox delete migration <id> --reason "…" # reject and archive without applying
Applying a Migration
Strict Schema And Storage Policy
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.
With an AI agent (recommended)
- Run
aibox doctor to identify gaps and queue migration artifacts - Run
aibox set migration <id> in-progress to begin the next pending migration - Open the migration document from
context/migrations/in-progress/ - Paste its contents into a Claude Code session (or let the agent find it via
AGENTS.md) - Review the changes the agent makes
- Run
aibox apply migration <id> to mark the migration complete
Manually
- Run
aibox doctor to generate migration artifacts - 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).
Best Practices
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.
Schema documents in the schemas/ directory define the expected structure for each version. They specify:
- Which files each process flavor should contain
- Required sections within each file
- File naming conventions
- Directory structure requirements
These schemas are used by doctor to validate the project and by migration tooling to compute diffs between versions.
10 - Migrations
10.1 -
Moving from v0 containers to v1 deployments
v1 deployment orchestration is opt-in. A v0 project remains a v0 container project until its aibox.toml explicitly enables [orchestration]; aibox apply, up, and down from the v0 lifecycle do not discover, modify, or remove a v1 deployment receipt.
Prepare the configuration
Preview first. This reads only aibox.toml, reports digests rather than printing configuration contents, and does not contact a container runtime or a cluster:
aibox config migrate-v1 --output json
The preview maps the safe, deterministic part of the old configuration:
container.name becomes the proposed fleet, first service, and deployment
name. It then returns an unresolvedDecisions array for facts that aibox must
not guess:
- immutable image reference and digest;
- target platform;
- Compose context/scope or Kubernetes context/namespace;
- stable deployment owner;
- connection transports;
- credential references for any v0 environment entries;
- a remove-or-redesign disposition for host bind mounts.
The report never includes environment values. readyToEnable remains false
until these operator decisions have explicit v1 values. This makes the command
a migration planner, rather than a textual marker that implies the v0
configuration was fully converted.
Create a reviewed TOML document containing only one complete
[orchestration] tree, then apply it with the migration:
aibox config migrate-v1 --apply --intent-file v1-intent.toml --output json
The intent file may say enabled = true for validation, but the migration
always writes it as enabled = false. Aibox validates the complete image,
fleet, target, deployment, connection, and credential-reference contract
offline before it creates the backup or changes aibox.toml. Extra top-level
tables, incomplete intent, symlinked files, and raw credential values are
rejected. The result reports readyToEnable: true; activation remains a
separate reviewed edit followed by aibox config compile and
aibox deploy plan.
Apply the narrow migration only after reviewing the preview:
aibox config migrate-v1 --apply
The command creates an exact original copy under .aibox/backups/v1-config/ before atomically replacing aibox.toml. The only new configuration is:
[orchestration]
enabled = false
That disabled boundary is intentional. Add the reported unresolved values
explicitly, run aibox config compile, review aibox deploy plan, and only
then set enabled = true.
Roll back configuration
The apply result prints the backup path. Restore it explicitly:
aibox config migrate-v1 --restore .aibox/backups/v1-config/v0-<stamp>-<digest>.toml
Restore accepts only regular backups inside the project backup directory and uses an atomic replacement. It restores the config alone: it deliberately does not read, alter, or delete .aibox/deployments/ records or any remote resource. Use aibox deploy destroy while the v1 configuration and ownership record are still available if you intend to remove an existing v1 deployment.
Coexistence boundary
Do not point v0 generated Compose files at v1 deployment artifacts. v1 Compose deployments use their own rendered artifacts and ownership labels; Kubernetes deployments use namespace-scoped labels and a durable DeploymentRecord. The v0 lifecycle has no authority to operate either form of v1 state.
This boundary makes rollback safe but not magical: reverting a config does not roll back a remote deployment. Treat deployment removal as a separate, guarded operation with its own record and evidence.
10.2 -
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).
What changed
cli/src/lock.rs adds:
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.
Troubleshooting
[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.
10.3 -
Zellij end-of-life migration (v0.25.5 → v0.25.6)
TL;DR
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.
What changed
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.
What you need to do
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:
[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/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:
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.
Why
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.
Need help
Open an issue at https://github.com/projectious-work/aibox/issues and
tag it zellij-migration. Include the output of aibox doctor and the
relevant section of your aibox.toml.
11 - Customization
11.1 - Prompt Presets
Starship Prompt Presets
aibox includes 8 Starship prompt presets that work with any theme. Set a preset in aibox.toml:
[customization]
prompt = "default"
Available Presets
default
Full-featured two-line prompt with directory, git branch/status, language versions, and command duration. Uses Nerd Font symbols.
~/workspace/myproject main ✓ v1.75.0 took 2s
❯
plain
Same information as default but uses ASCII characters only — no Nerd Font or special font needed. Works in any terminal.
~/workspace/myproject [main +1 !2] [v1.75.0] took 2s
>
Good for remote SSH sessions or environments without font customization.
minimal
Directory and git branch only, with a ❯ indicator. Two-line. For distraction-free, low-noise work.
~/workspace/myproject on main
❯
nerd-font
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.
~/workspace main +1 !2 v1.75.0 🐳 dev 3s
❯
pastel
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.
~/workspace/myproject main +1
❯
powerline-pastel
Explicit name for the one-line pastel powerline prompt. The legacy pastel-powerline name is still accepted as an alias.
bracketed
Each segment wrapped in square brackets — [dir] [branch] [status]. Clean, structured appearance without special fonts. A good alternative to plain with more visual structure.
[~/workspace/myproject] [main] [+1 !2]
❯
arrow
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.
~/workspace/myproject main +1 !2 took 3s
❯
Changing Presets
Edit aibox.toml:
[customization]
prompt = "arrow"
Run apply:
The Starship config is regenerated at .aibox-home/.config/starship.toml. Colors are derived from the active theme.
Font Requirements
| Preset | Font requirement |
|---|
default | Nerd Font recommended (for ❯ symbol) |
plain | Any font — ASCII only |
minimal | Nerd Font recommended (for ❯ symbol) |
nerd-font | Nerd Font required |
pastel | Nerd Font or Powerline font required |
powerline-pastel | Nerd Font or Powerline font required |
bracketed | Any font — no special glyphs |
arrow | Nerd Font or Powerline font required |
Install a Nerd Font from nerdfonts.com and configure it in your terminal emulator to use icon-based presets.
11.2 - Custom Themes
Creating Custom Themes
aibox ships 7 built-in themes. You can create a custom theme by adding entries to the CLI source code.
Theme Structure
Each theme defines colors for 5 tools:
| Tool | Config Location | Format |
|---|
| tmux | .config/tmux/themes/<name>.conf | tmux style settings |
| Vim | .vim/colors/<name>.vim | Vim colorscheme |
| Yazi | .config/yazi/theme.toml | TOML with hex colors |
| lazygit | .config/lazygit/config.yml | YAML gui.theme section |
| Starship | .config/starship.toml | TOML with palette |
Color Mapping
A theme needs these terminal color slots for tmux:
| Slot | Purpose |
|---|
fg | Default foreground text |
bg | Background |
black | Dark background variant |
red | Errors, unstaged changes |
green | Success, staged changes |
yellow | Warnings, search highlights |
blue | Primary accent |
magenta | Secondary accent |
cyan | Tertiary accent, links |
white | Bright foreground |
orange | Special highlights |
Adding a Theme
To add a new theme to aibox, you need to modify cli/src/themes.rs (theme data) and cli/src/config.rs (Theme enum). See the existing themes as reference patterns.
The projectious theme (cli/src/themes.rs) is a good starting point — it uses a simple palette with clear semantic mappings.
Manual Overrides
If you don’t want to modify the CLI, you can manually edit the config files in .aibox-home/ after aibox apply. Note that aibox apply will overwrite theme-dependent files, so manual edits need to be reapplied after each apply.
11.3 - Layouts
Layouts
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.
Available Layouts
ai
| Window | Contents |
|---|
| 1 · work | left 50%: yazi · right 50%: 1st harness |
| 2 · ai | all further harnesses, split as full-height even horizontal panes |
| 3 · lazygit | lazygit, when git-ui selects lazygit |
| 3/4 · shell | bash |
dev
| Window | Contents |
|---|
| 1 · work | left 50%: yazi top 50% / 1st harness bottom 50% · right 50%: shell |
| 2 · lazygit | lazygit, when git-ui selects lazygit |
| 2/3 · ai | all further harnesses, split as full-height even horizontal panes |
| final · shell | bash |
focus
| Window | Contents |
|---|
| 1 · files | yazi |
| 2..n · harness name | one fullscreen window per harness in harness_order |
| next · lazygit | lazygit, when git-ui selects lazygit |
| final · shell | bash |
cowork
| Window | Contents |
|---|
| 1 · work | left 50%: yazi · right 50%: shell |
| 2 · ai | all harnesses, split as full-height even horizontal panes |
| 3 · lazygit | lazygit, when git-ui selects lazygit |
Setting The Default Layout
[customization]
layout = "dev"
Options: dev, focus, cowork, ai.
Per-Session Override
This does not change the default in aibox.toml.
11.4 - Custom Prompts
Creating Custom Prompts
aibox generates Starship prompt configurations from the selected preset and theme. You can customize the prompt by editing the generated config.
Generated Config Location
After aibox apply, the Starship config is at:
.aibox-home/.config/starship.toml
Manual Customization
Edit .aibox-home/.config/starship.toml directly with any valid Starship configuration. Changes take effect immediately in new shell sessions.
Apply overwrites
aibox apply regenerates starship.toml from the preset and theme. To preserve manual edits, either avoid running apply or back up your config first.
Adding Custom Presets
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.
11.5 - Color Themes
Themes
aibox supports consistent color theming across all terminal tools. Set a theme in aibox.toml:
[customization]
theme = "gruvbox-dark"
mode = "auto"
Or during project initialization:
aibox init --theme catppuccin-mocha
The selected theme is applied to tmux, Vim, Yazi, lazygit, and Starship simultaneously.
mode = "auto" follows the host OS light/dark appearance when a host signal is detectable during aibox apply, aibox up, or aibox set theme.*. Containers do not receive live macOS/Windows/Linux appearance-change events, so rerun one of those commands to regenerate mounted runtime theme files after changing the host appearance. If the host appearance cannot be detected, auto preserves the selected concrete theme.
mode = "light" and host-light auto use the selected theme family’s light partner when one exists. Genuinely dark-only themes stay on the selected concrete theme instead of falling back to an unrelated light theme.
Available Themes
aibox supports the tmux-powerkit popular theme roster plus aibox-specific
extensions:
tokyo-night, tokyo-night-storm, tokyo-night-daycatppuccin-mocha, catppuccin-macchiato, catppuccin-frappe, catppuccin-lattedracula, dracula-soft, nord, gruvbox-dark, gruvbox-lightrose-pine, rose-pine-moon, rose-pine-dawnmaterial, material-ocean, material-palenight, material-lighter, material-darkersolarized-dark, solarized-lightgithub-dark, github-dark-dimmed, github-dark-high-contrast, github-light, github-light-high-contrastayu-dark, ayu-mirage, ayu-light, night-owl, night-owl-light, moonlighteverforest-dark, everforest-light, kanagawa-wave, kanagawa-dragon, kanagawa-lotusmin-dark, min-light, one-dark-pro, one-light, slack-dark, slack-ochinvitesse-dark, vitesse-light, vitesse-black, vscode-dark-plus, vscode-light-plusandromeeda, aurora-x, houston, laserwave, monokai, plastic, poimandres, red, snazzy-light, synthwave-84, vesperprojectious
Light/Dark Partners
| Family | Dark variants | Light variant |
|---|
| Tokyo Night | tokyo-night, tokyo-night-storm | tokyo-night-day |
| Catppuccin | catppuccin-mocha, catppuccin-macchiato, catppuccin-frappe | catppuccin-latte |
| Gruvbox | gruvbox-dark | gruvbox-light |
| Rose Pine | rose-pine, rose-pine-moon | rose-pine-dawn |
| Material | material, material-ocean, material-palenight | material-lighter |
| Solarized | solarized-dark | solarized-light |
| GitHub | github-dark | github-light |
| Ayu | ayu-dark, ayu-mirage | ayu-light |
| Night Owl | night-owl | night-owl-light |
| Everforest | everforest-dark | everforest-light |
| Kanagawa | kanagawa-wave, kanagawa-dragon | kanagawa-lotus |
| Min | min-dark | min-light |
| One Dark | one-dark-pro | one-light |
| Slack | slack-dark | slack-ochin |
| Vitesse | vitesse-dark, vitesse-black | vitesse-light |
| VS Code | vscode-dark-plus | vscode-light-plus |
Dark-only or single-variant themes with no light partner: andromeeda,
aurora-x, houston, laserwave, monokai, moonlight, nord, plastic,
poimandres, projectious, red, snazzy-light, synthwave-84, and vesper.
gruvbox-dark (default)
Retro groove color scheme with warm, earthy tones. High contrast and easy on the eyes.
- Background:
#282828 (dark brown-gray) - Accent:
#D79921 (warm yellow) - Style: Dark, warm, retro
catppuccin-mocha
Soothing pastel theme with a dark background. The most popular modern terminal theme.
- Background:
#1E1E2E (deep purple-black) - Accent:
#89B4FA (soft blue) - Style: Dark, pastel, modern
catppuccin-latte
Light variant of Catppuccin. Clean and readable in bright environments.
- Background:
#EFF1F5 (warm white) - Accent:
#1E66F5 (vivid blue) - Style: Light, pastel, modern
dracula
Dark theme with vibrant colors. A classic among developers.
- Background:
#282A36 (dark gray-blue) - Accent:
#BD93F9 (purple) - Style: Dark, vibrant, bold
tokyo-night
Inspired by Tokyo’s night lights. Clean and modern with blue tones.
- Background:
#1A1B26 (deep blue-black) - Accent:
#7AA2F7 (bright blue) - Style: Dark, cool, modern
nord
Arctic, north-bluish color palette. Minimalist and calm.
- Background:
#2E3440 (dark blue-gray) - Accent:
#88C0D0 (frost blue) - Style: Dark, cool, minimalist
projectious
The projectious.work brand theme. Deep navy base with a vivid orange accent.
- Background:
#1d3352 (midnight navy) - Accent:
#E05232 (ember orange) - Midtone:
#546a82 (slate blue) - Style: Dark, professional
How It Works
Each theme is a coordinated set of config files applied to all tools when aibox apply, aibox up, or aibox set theme.* regenerates managed runtime files:
| Tool | Config file | What’s themed |
|---|
| tmux | .config/tmux/themes/<name>.conf | Pane borders, status bar, window colors |
| Vim | .vim/colors/<name>.vim | Syntax highlighting, UI elements |
| Yazi | .config/yazi/theme.toml | File colors, status bar, selection |
| lazygit | .config/lazygit/config.yml | Borders, selection, diff colors |
| Starship | .config/starship.toml | Prompt segment colors |
Claude Code inherits terminal colors automatically — no separate theme file needed.
Changing Themes
To switch light/dark mode in an existing project:
aibox set theme.mode auto
aibox set theme.mode light
aibox set theme.mode dark
aibox set theme.name tokyo-night
This updates [customization].mode in aibox.toml and regenerates the mounted runtime theme files under .aibox-home/. The running container is not stopped.
If the project tmux session is running, refresh and attach it without stopping the container:
aibox set theme.mode dark --restart-session
Theme files are force-updated by apply
aibox apply and aibox set theme.mode/name overwrite theme-dependent config files (tmux theme, Vim colorscheme, Yazi theme, lazygit config, Starship config) to match the selected theme. You do not need to rebuild or restart the container to change themes; running TUI processes may need to be restarted.
12 - Reference
12.1 - CLI Commands
CLI Commands
aibox uses a small verb/resource grammar. aibox.toml is desired state. The
established v0 runtime uses apply then up; v1 orchestration uses image,
deploy, up (apply-only), and an explicit connect.
Global Options
| Option | Environment Variable | Default | Description |
|---|
--config <PATH> | – | ./aibox.toml | Path to configuration file |
--log-level <LEVEL> | AIBOX_LOG_LEVEL | info | Log verbosity |
-y, --yes | – | – | Skip confirmation prompts |
Core Workflow
aibox init my-app --harness claude --addon python
aibox apply
aibox up --legacy-runtime
aibox down --legacy-runtime
aibox doctor
Command Grammar
aibox init [NAME] [OPTIONS]
aibox apply [RESOURCE] [NAME] [OPTIONS]
aibox up [OPTIONS]
aibox down [--legacy-runtime]
aibox image <build|inspect> [--output human|json]
aibox deploy <plan|apply|status|destroy|logs> [OPTIONS]
aibox connect <NAME> [-- COMMAND...]
aibox get <RESOURCE> [OPTIONS]
aibox describe <RESOURCE> [NAME] [OPTIONS]
aibox set <TARGET> [VALUE] [EXTRA...] [OPTIONS]
aibox edit <RESOURCE>
aibox reset <RESOURCE> [OPTIONS]
aibox delete <RESOURCE> [NAME] [OPTIONS]
aibox create <RESOURCE> [NAME] [OPTIONS]
aibox self <ACTION> [OPTIONS]
init
Create aibox.toml, generated devcontainer files, .aibox-home/, context scaffolding, and provider pointer files.
aibox init
aibox init my-app --harness claude
aibox init runner --profile headless-runner
aibox init my-app --addon python --addon infrastructure
aibox init my-app --harness claude --harness codex
aibox init my-app --context-mode harness-only --harness claude
aibox init my-app --theme catppuccin-mocha
| Option | Default | Description |
|---|
[NAME] | Current directory | Project/container name |
--base <BASE> | debian | Base image |
--profile <PROFILE> | human-dev | 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.
apply
Reconcile generated project state with aibox.toml.
aibox apply
aibox apply --no-cache
aibox apply --rebuild
aibox apply --config-only
aibox apply --standardize-config
aibox apply migration MIG-20260430_1200
aibox apply audio
aibox apply env research
| Option | Description |
|---|
--no-cache | 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 |
Runtime
aibox up # v1 deploy apply; does not attach
aibox down # v1 guarded deploy destroy
aibox up --legacy-runtime --layout focus
aibox up --legacy-runtime --apply
aibox down --legacy-runtime
aibox get runtime
aibox get runtime --resources
aibox get runtime --resources -o json
aibox describe runtime
aibox delete runtime
aibox up --legacy-runtime starts or creates the v0 workspace container and
attaches through tmux. aibox down --legacy-runtime stops that compose project.
This compatibility path is deprecated and will be removed on 2026-12-31;
migrate to the v1 workflow below. delete runtime removes the v0 container
while preserving project files and .aibox-home/.
V1 deployment workflow
V1 has no implicit attach step. up is an alias for a guarded deployment
apply; connect only after the deployment operation finishes. The alias requires
an enabled [orchestration] configuration.
# Inspect the immutable deployment input, or explicitly build its source contract.
aibox image inspect
aibox image build --output json
aibox image build --push --output json
# Plan without mutation, then reconcile and observe the deployment.
aibox deploy plan --output json
aibox deploy apply --output json
aibox deploy status
aibox deploy logs --service workspace --output json
# Open an interactive shell or run a noninteractive command with its exit code.
aibox connect shell
aibox connect shell -- sh -lc 'make test'
# Alias for deploy apply / guarded deploy destroy; neither attaches a terminal.
aibox up
aibox down
image build is an explicit source-backed operation. Configure it beneath the
deployment image with a build context and, when needed, a Dockerfile and named
stage:
[orchestration.image]
reference = "ghcr.io/acme/workspace:build"
digest = "sha256:<currently-selected-deployment-manifest-digest>"
platform = "linux-amd64"
[orchestration.image.build]
context = "image-source"
dockerfile = "Containerfile" # optional; relative to context
target = "runtime" # optional
The command passes this contract as typed Docker or Podman arguments; it does
not accept build arguments, environment values, or secrets. A normal build
returns its immutable local image ID and deliberately reports no deployable
reference. Use --push to publish the explicit tag and verify the runtime’s
registry RepoDigests; only then does the output include a pullable
reference@sha256:<manifest> value. Copy that digest into
orchestration.image.digest when you are ready to promote it for deployment.
Deploy operations always consume the configured immutable image and never build
or push implicitly.
Every v1 deploy command accepts -o, --output human|json. JSON is a single
machine-readable document on stdout; progress, warnings, and errors use stderr.
deploy apply, status, and destroy emit the deployment record in JSON.
deploy logs emits { deploymentId, service?, lines }. Human output is concise
for terminals. Backend failures preserve their nonzero exit status; connect
also forwards the remote command exit code. Kubernetes port-forward stays in
the foreground until it is interrupted, while Kubernetes exec uses TTY/stdin
only for connections configured as interactive.
down only destroys resources whose deployment record and ownership labels
prove that aibox created them. It refuses untracked, foreign, or
digest-mismatched resources.
These commands do not enable processkit production delegation. The published
processkit protocol remains a separate stable-v1 release gate; until it is
available, aibox retains its existing bounded/provisional integration behavior.
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.
Inspecting Resources
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.
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
Preview projections
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.
| Command | Schema | Contents |
|---|
describe addon-catalog | aibox.addon-catalog.v0 | Built-in addon metadata, profile intent, automation usage class, exported surfaces, dependencies, and tool versions |
describe workspace-manifest | aibox.workspace-manifest.v0 | Sorted projection of aibox.toml: project, context mode/packages, processkit source when enabled, AI harnesses, addons, and MCP server keys |
describe provider-backends | aibox.provider-backends.v0-preview | Supported AI harness backends, selected status, addon availability, MCP config targets, and permission targets |
describe image-provenance-policy | aibox.image-provenance-policy.v0-preview | GHCR image tag or tag template, generated file paths, runtime version/profile markers, selected addons, and release phase commands |
The preview projections do not create processkit entities and should not be
treated as canonical processkit Artifacts yet.
Mutating Resources
set changes config. Use --apply when you want to reconcile immediately.
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
Delete explicit resources:
aibox delete addon python
aibox delete addon python --apply
aibox delete skill pandas-polars
aibox delete env research --yes
aibox delete migration MIG-20260430_1200 --reason "Not applicable"
Reset And Backup
Project reset is intentionally scoped; there is no bare destructive reset.
aibox create backup
aibox create backup --dry-run
aibox create backup --output-dir /tmp/my-backup
aibox reset project
aibox reset project --dry-run
aibox reset project --no-backup --yes
aibox reset context --from-processkit v0.25.0 --dry-run
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.
Diagnostics
aibox doctor
aibox doctor --integrity
aibox doctor --integrity -o json
aibox doctor audio
aibox doctor security
doctor audio checks host PulseAudio readiness. doctor security runs available dependency/image scanners.
LaTeX container scripts
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.
aibox-latex-build # build all configured documents
aibox-latex-build overview # build one configured document
aibox-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.
Self Management
aibox self update --check
aibox self update --dry-run
aibox self update
aibox self completion bash
aibox self uninstall
aibox self uninstall --purge
Removed Old Grammar
The hard-break CLI redesign removed the old top-level command taxonomy.
| Removed | Use |
|---|
aibox sync | aibox apply |
aibox start | aibox up |
aibox stop | aibox down |
aibox status | aibox get runtime |
aibox remove / aibox rm | aibox delete runtime |
aibox theme ... | aibox set theme.mode ... or aibox set theme.name ... |
aibox addon ... | aibox get/describe/set/delete addon ... |
aibox kit ... | aibox get/describe/set/delete skill/process ... |
aibox migrate ... | aibox get/set/apply/delete migration ... |
aibox update | aibox self update |
aibox completions | aibox self completion |
aibox uninstall | aibox self uninstall |
aibox audio check/setup | aibox doctor audio / aibox apply audio |
12.2 - Configuration
Configuration
aibox.toml is the single source of truth for an aibox project. All generated files derive from it.
Full Specification
[aibox]
project_name = "my-app" # Human-readable project name
profile = "human-dev" # Usage profile: human-dev or headless-runner
[container]
name = "my-app" # Container name
hostname = "my-app" # Container hostname
user = "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 creation
keepalive = false # Periodic DNS keepalive for idle network timeouts
[container.resource_thresholds]
memory_mib_warn = 4096 # Optional warning limit for cgroup memory usage in MiB
process_count_warn = 400 # Optional warning limit for total live processes; 0 disables
processkit_mcp_python_warn = 50 # Optional warning limit for live Python MCP server processes; 0 disables
oom_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 path
read_only = true
[context]
mode = "processkit" # processkit | harness-only
packages = ["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 runtime
python = { version = "3.14" }
uv = { version = "0.12.0" }
[addons.rust.tools] # Addon: Rust toolchain
rustc = { version = "1.97.1" }
clippy = {}
rustfmt = {}
[addons.git-ui.tools] # Optional: GitHub CLI and lazygit
gh = {}
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 name
command = "npx" # Executable to run
args = ["-y", "@acme/team-server"] # Arguments
# [ai.mcp.servers.env] # Optional environment variables
# API_KEY = "..."
[customization]
theme = "gruvbox" # Theme family; concrete legacy names still parse
mode = "auto" # Theme mode: auto, light, dark
prompt = "default" # Starship preset (8 options)
layout = "dev" # tmux layout (4 options)
[customization.tmux.status]
mode = "extended" # extended | plain | disabled (legacy: powerline -> extended)
[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 off
line1-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 | none
style = "rounded"
# Edge separators may use a different style at status boundaries.
edge-style = "rounded"
# Spacing between elements. Options: false | true | both | windows | plugins
elements-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 = 15
aibox-metrics-cache-ttl-seconds = 30
netspeed-cache-ttl-seconds = 10
kubernetes-cache-ttl-seconds = 120
cloud-cache-ttl-seconds = 120
github-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 = false
cache-ttl-seconds = 300
timeout-seconds = 3
show-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 bridging
backend = "pulseaudio" # Audio bridge backend
install = true # Install container audio tools
pulse_server = "tcp:host.docker.internal:4714"
Section Reference
[aibox]
Top-level project metadata.
| Field | Type | Required | Default | Description |
|---|
project_name | String | No | container.name | Human-readable project name |
profile | String | No | "human-dev" | 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]
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.
[container.resource_thresholds]
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. |
Each entry in the extra_volumes array is an ExtraVolume with these fields:
| Field | Type | Required | Default | Description |
|---|
source | String | Yes | – | Host path (supports ~ expansion) |
target | String | Yes | – | Container path where the volume is mounted |
read_only | Boolean | No | false | Mount the volume read-only |
Example — mount a personal host configuration directory:
[[container.extra_volumes]]
source = "~/.aws"
target = "/home/aibox/.aws"
read_only = true
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
.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.
See the dedicated Local Config reference for a full example and merge-behavior details.
[context]
Selects the project context layer.
| Field | Type | Required | Default | Description |
|---|
mode | String | No | processkit | 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:
[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".
[latex]
Defines named LaTeX documents and their shared build/preview behavior. Add the
latex addon separately to install TeX Live in the container.
[latex]
engine = "lualatex"
cache_dir = ".latex-cache"
options = []
[[latex.documents]]
name = "overview"
source = "docs/overview.tex"
output_dir = ".latex-cache/overview"
[latex.preview]
enabled = true
engine = "embedpdf"
bind = "127.0.0.1"
port = 8765
document = "overview"
allow_public = false
| Key | Type | Required | Default | Description |
|---|
engine | String | No | lualatex | 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]
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.
[addons.python.tools]
python = { version = "3.14" }
uv = { version = "0.12.0" }
For interactive Git tooling:
[addons.git-ui.tools]
gh = {}
lazygit = {}
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.
[skills]
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.
[skills]
include = ["pk-doctor", "status-briefing"] # install only these plus core skills
exclude = ["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]
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. |
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:
harnesses = [
{ harness = "codex", enable = true, install = true },
# { harness = "claude", enable = true, install = true },
# { harness = "cursor", enable = true, install = false },
]
Provider env mapping:
| Provider | API key env | Base URL env |
|---|
anthropic | ANTHROPIC_API_KEY | ANTHROPIC_BASE_URL |
openai | OPENAI_API_KEY | OPENAI_BASE_URL |
google | GEMINI_API_KEY | GEMINI_BASE_URL |
mistral | MISTRAL_API_KEY | MISTRAL_BASE_URL |
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:
[container.environment]
OPENAI_API_KEY = "..."
OPENAI_BASE_URL = "https://api.openai.com/v1" # Optional override
GEMINI_API_KEY = "..."
GEMINI_BASE_URL = "https://generativelanguage.googleapis.com" # Optional override
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.
[processkit]
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.
| Field | Type | Required | Default | Description |
|---|
source | String | No | https://github.com/projectious-work/processkit.git | Git URL of the content source. |
version | String | No | unset | Semver tag to consume. The sentinel unset skips fetching until a real tag is set. |
src_path | String | No | src | Subdirectory inside the source repo containing the shippable payload. Auto-detected for flat release-asset tarballs. |
branch | String | No | (none) | Optional branch override for testing pre-release work. Discouraged but supported. |
release_asset_url_template | String | No | (GitHub-style default) | URL template for the release-asset tarball. Placeholders: {source} (.git stripped), {version}, {org}, {name}. Set this for non-GitHub hosts. |
[processkit.context]
Processkit-mode context-system metadata.
| Field | Type | Required | Default | Description |
|---|
schema_version | String (semver) | No | "1.0.0" | Context schema version. Canonical rendering keeps this under [processkit.context] for processkit-backed projects. |
Fetch strategy
The fetcher tries strategies in priority order:
- Branch override (if
branch is set) — git clone --branch <name>. - 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.
Example: consume a Gitea-hosted fork
[processkit]
source = "https://gitea.acme.com/platform/processkit-acme.git"
version = "v1.2.0"
release_asset_url_template = "https://gitea.acme.com/{org}/{name}/releases/download/{version}/{name}-{version}.tar.gz"
[ai.mcp]
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.
processkit Gateway: [ai.mcp.gateway]
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.
[ai.mcp.gateway]
mode = "auto" # auto | daemon | stdio | separate
lazy_catalog = true
host = "127.0.0.1"
port = 8765
path = "/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.
Server Definitions: [[ai.mcp.servers]]
Each [[ai.mcp.servers]] entry has these fields:
| Field | Type | Required | Default | Description |
|---|
name | String | Yes | – | Unique server name (used as the key in generated configs) |
command | String | Yes | – | Executable to run (e.g. npx, /usr/local/bin/my-server) |
args | Array of strings | No | [] | Arguments passed to command |
env | Map (String → String) | No | {} | Environment variables set when the server process starts |
Example:
[[ai.mcp.servers]]
name = "internal-docs"
command = "/usr/local/bin/internal-docs-mcp"
args = ["--stdio"]
[ai.mcp.servers.env]
LOG_LEVEL = "info"
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.
Permission Configuration: [ai.mcp.permissions]
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):
[ai.mcp.permissions.harness.claude-code]
default_mode = "allow" # Override global default if needed
allow_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:
[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-approve
default_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.
[ai.execution]
Controls the default execution policy intent for AI harnesses. aibox uses stable
cross-harness vocabulary here and maps it to each harness where supported.
[ai.execution]
filesystem = "workspace-write" # read-only | workspace-write | container-full
approval = "on-request" # ask | on-request | never
network = "ask" # deny | ask | allow
[ai.execution.codex]
filesystem = "container-full"
approval = "on-request"
network = "ask"
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.
[ai.agents]
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.
[customization]
Visual and layout configuration. See Themes and Layouts for details.
| Field | Type | Required | Default | Description |
|---|
theme | String | No | "gruvbox-dark" | Color theme. Supports the tmux-powerkit popular theme roster and variants, plus projectious; 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. |
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.status.separators.style | String | No | "rounded" | PowerKit separator style: normal, rounded, slant, slantup, trapezoid, flame, pixel, honeycomb, none. |
tmux.status.separators.edge-style | String | No | "rounded" | PowerKit edge separator style for status boundaries. Uses the same values as style. |
tmux.status.separators.elements-spacing | String | No | "both" | PowerKit spacing mode: false, true, both, windows, plugins. |
tmux.status.forge.github-hosts | Array of strings | No | ["github.com"] | Exact GitHub SSH hostnames and aliases recognized by the Forge status segment. Add aliases declared in SSH config, such as github-work. |
[audio]
Audio bridging configuration.
| Field | Type | Required | Default | Description |
|---|
enabled | Boolean | No | false | Enable PulseAudio environment setup |
backend | String | No | "pulseaudio" | Audio bridge backend. Only pulseaudio is currently supported. |
install | Boolean | No | true | Select the internal audio-voice recipe when audio is enabled |
pulse_server | String | No | "tcp:host.docker.internal:4714" | PulseAudio server address |
Legacy [container.audio] input is still accepted for compatibility. Fresh
scaffolding writes top-level [audio].
[integrations.github]
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.
Apply Behavior
| Field | Type | Required | Default | Description |
|---|
preserve_disabled_harness_state | Boolean | No | false | 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. |
Environment Variable Overrides
Some settings can be overridden via environment variables:
| Variable | Overrides | Description |
|---|
AIBOX_HOST_ROOT | .aibox-home/ path | Host directory for persistent config (default: .aibox-home/) |
AIBOX_WORKSPACE_DIR | Workspace mount source | Host directory mounted as /workspace |
AIBOX_LOG_LEVEL | --log-level | Log verbosity (trace, debug, info, warn, error) |
Example:
AIBOX_WORKSPACE_DIR=/home/user/projects/my-app aibox up
12.3 - Local Config (.aibox-local.toml)
Local Config (.aibox-local.toml)
.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.
Why it exists
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.
Location and gitignore
.aibox-local.toml lives in the project root, next to aibox.toml:
my-project/
├── aibox.toml ← committed, shared
├── .aibox-local.toml ← gitignored, personal
├── .devcontainer/
└── context/
aibox init and aibox apply automatically add .aibox-local.toml to .gitignore. You do not need to do this manually.
Supported sections
Three sections are supported. Everything else must remain in aibox.toml.
[container.environment]
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.
[container.environment]
GH_TOKEN = "github_pat_xxxxxxxxxxxx"
ANTHROPIC_API_KEY = "sk-ant-api03-..."
OPENAI_API_KEY = "sk-proj-..."
AWS_PROFILE = "my-dev-profile"
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.
[[container.extra_volumes]]
source = "~/.aws"
target = "/home/aibox/.aws"
read_only = true
[[container.extra_volumes]]
source = "~/.ssh/id_ed25519"
target = "/home/aibox/.ssh/id_ed25519"
read_only = true
[mcp]
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:
[[mcp.servers]]
name = "my-internal-tool"
command = "npx"
args = ["-y", "@acme/internal-mcp-server"]
[[mcp.servers]]
name = "local-notes"
command = "/home/user/bin/notes-mcp"
args = ["--db", "~/notes.db"]
[[mcp.servers]]
name = "stripe"
command = "npx"
args = ["-y", "@stripe/mcp"]
[mcp.servers.env]
STRIPE_SECRET_KEY = "sk_test_..."
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.
Merge behavior
| Section | Merge rule |
|---|
[container.environment] | Merged with aibox.toml; local values win on key conflicts |
[[container.extra_volumes]] | Appended after aibox.toml volumes; no deduplication |
[[mcp.servers]] | Appended after aibox.toml MCP servers; all sources merged into each generated config file |
GitHub authentication
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.
Recommended: least-privilege PATs
Put the token used for normal GitHub CLI commands in GH_TOKEN. GitHub CLI
reads it automatically:
[container.environment]
GH_TOKEN = "github_pat_default_project_token"
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:
[container.environment]
GH_TOKEN = "github_pat_default_project_token"
PROJECTXXX_ISSUES_TOKEN = "github_pat_upstream_issues_token"
Select the second credential only for the command that needs it:
GH_TOKEN="$PROJECTXXX_ISSUES_TOKEN" \
gh issue create --repo projectious-work/aibox
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.
Alternative: persistent GitHub CLI login
For a trusted personal workspace where broad account access is acceptable, log
in from inside the running container:
gh auth login --hostname github.com --web --git-protocol https --insecure-storage
--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:
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.
Full example
A typical .aibox-local.toml for a developer working with Claude, GitHub, and AWS, plus a personal MCP server:
[container.environment]
ANTHROPIC_API_KEY = "sk-ant-api03-..."
GH_TOKEN = "github_pat_xxxxxxxxxxxx"
AWS_PROFILE = "my-dev-profile"
AWS_REGION = "eu-west-1"
[[container.extra_volumes]]
source = "~/.aws"
target = "/home/aibox/.aws"
read_only = true
[[container.extra_volumes]]
source = "~/.ssh/id_ed25519"
target = "/home/aibox/.ssh/id_ed25519"
read_only = true
[[mcp.servers]]
name = "my-internal-tool"
command = "npx"
args = ["-y", "@acme/internal-mcp-server"]
What is NOT supported
Everything outside of [container.environment], [[container.extra_volumes]], and [[mcp.servers]] is ignored. The following must remain in aibox.toml:
- Container name, hostname, user, lifecycle, image, and generated paths
[context] — context mode and processkit package selection[addons] — addon configuration[processkit] — content source and version pin when processkit mode is enabled[skills] — enabled/disabled lists when processkit mode is enabled[ai] — harnesses, agents, and team MCP servers[customization] — theme, mode, prompt, layout[audio] — audio bridging
Applying changes
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.
12.4 - Cheatsheet
Keyboard Shortcuts
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 |
### 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 |
### 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 |
### 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.
12.5 -
V1 deployment boundaries and prerequisites
V1 is a deployment control plane for immutable workspace images; it is not a cluster, DNS-zone, ingress-controller, secret-manager, or processkit installer. It compiles typed desired state, records ownership, and asks an already-provisioned backend to reconcile only the resources it owns.
Infrastructure supplied by the operator
Before enabling a Kubernetes target, supply all of the following outside aibox:
- a reachable kube context with a namespace aibox is allowed to manage;
- an existing ingress class or gateway class when ingress is configured;
- an existing DNS zone when DNS reconciliation is configured;
- credential references that the selected backend can resolve, never secret values in
aibox.toml; - an immutable image reference and
sha256: digest; - a least-privilege identity limited to the target namespace and the selected DNS record scope.
Aibox refuses foreign, unlabeled, digest-mismatched, or missing-record resources during guarded destroy. These checks protect against accidental deletion; they are not a replacement for namespace policy, admission control, or credential rotation.
Operational limits
deploy plan and config compile are offline planning operations. deploy apply, status, logs, connect, and destroy use the selected backend. Only destroy removes resources, and it requires the matching local or verified remote deployment record plus all ownership labels/digests.
Processkit production delegation is a separate stable-v1 release gate. The current fixture protocol is not production authority. Likewise, fake-client Kubernetes tests are not evidence that a live disposable cluster behaves correctly.
The v1 processkit boundary has only two states:
- disabled — aibox performs no CLI discovery, creates no request file,
starts no subprocess, and changes no project or harness state;
- direct — aibox passes one versioned request file to
processkit execute --request ... and retains only the opaque structured result/provenance.
The boundary does not import aibox’s legacy processkit vocabulary, content
fetch/install machinery, template paths, skill names, migration layouts, or MCP
projection policy. Install, verify, unchanged update, recovery, and uninstall
tests exercise the same direct boundary against the exact pinned processkit
producer. Users may invoke that producer directly; aibox does not add a second
interpretation of its result.
Release evidence
Run the diagnostic before declaring a stable-v1 release:
aibox config release-readiness
aibox config release-readiness --output json
It exits non-zero while a blocking gate is incomplete, but JSON is still printed
for automation ingestion. Stable publication runs
scripts/test-v1-stable-readiness.sh first. That harness executes the real
migration/restore, ownership and secret canaries, dependency audit, and exact
processkit alpha.3 producer tests. It writes one typed, candidate-bound
ReleaseGateEvidence record per gate under
.aibox/release-evidence/v1-readiness/. A record is retained only after its
producer succeeds.
Stable readiness also runs scripts/test-v1-operational-readiness.sh for the
support/deprecation/retirement policy and the ainfra/aibox/processkit portfolio
boundary. The four-platform release and rollback gate is deliberately not
manufactured inside the Linux container: after both native release phases and
an exact-version rollback rehearsal, retain their artifacts with
scripts/record-v1-platform-rehearsal.sh.
Automated adoption journeys are necessary but not sufficient. Stable readiness
also requires all five external pilot feedback documents described in the
support and retirement policy, recorded by
scripts/record-v1-external-pilot-feedback.sh against the same candidate.
The readiness parser verifies the candidate commit, tested-binary digest, gate
identity, and SHA-256 digest of every referenced producer log. Missing,
candidate-mismatched, or modified logs block the release. M7c separately
requires complete live disposable-cluster evidence at
.aibox/release-evidence/m7c-live.json.
M7c passes only when the release workflow supplies both the exact candidate
commit and tested-binary digest. A standalone diagnostic intentionally treats
the artifact as unbound and remains blocked; use ./scripts/maintain.sh release <version> to evaluate it as release evidence.
The evidence artifact must be generated by the release suite and contain:
{
"apiVersion": "aibox.projectious.work/v1alpha1",
"kind": "DisposableClusterEvidence",
"status": "passed",
"candidateCommit": "<40-character-release-candidate-commit>",
"binarySha256": "sha256:<tested-candidate-binary-digest>",
"cluster": "<ephemeral-cluster-id>",
"command": "cargo test --features e2e --test e2e kubernetes_kind",
"scenarios": [
{ "id": "first-apply", "status": "passed" },
{ "id": "unchanged-apply", "status": "passed" },
{ "id": "changed-apply", "status": "passed" },
{ "id": "drift-recovery", "status": "passed" },
{ "id": "status-logs", "status": "passed" },
{ "id": "exec-port-forward", "status": "passed" },
{ "id": "ingress", "status": "passed" },
{ "id": "foreign-destroy-refusal", "status": "passed" }
],
"recordedAt": "<RFC3339 timestamp>"
}
The artifact is release evidence, not a configuration knob. The producer adds a
scenario only after it passed and validates the complete typed artifact with the
Rust readiness parser before the test harness retains it. Unknown, missing,
duplicate, or unexecuted scenarios are rejected. Do not add a hand-written
passing marker to bypass a failed or unrun cluster test.
12.6 - V1 support, deprecation, and retirement
V1 support, deprecation, and retirement
V1 prereleases are evaluation releases. Until a stable v1 release satisfies
every candidate-bound readiness gate, v0 remains supported as the stable line.
V1 and v0 may coexist while projects evaluate migration; neither line may
manage or destroy the other line’s deployment records or resources.
Product boundaries
- ainfra provisions accounts, hosts, networks, clusters, identities, DNS
zones, and other infrastructure, then exposes non-secret target references.
- aibox deploys immutable AI workspace images onto existing Compose or
Kubernetes targets. It does not provision infrastructure.
- processkit owns process distribution, installation, migrations, MCP,
skills, schemas, and harness projections. Aibox’s v1 integration is disabled
or delegates one opaque request to the processkit CLI.
These boundaries are release requirements. The portfolio audit fails if the v1
production path begins interpreting processkit policy or provisioning
infrastructure.
Support and deprecation
- Alpha and beta users should pin the exact prerelease and retain a known-good
v0 installer version.
- Corrective contract changes require compatibility review and an updated
contract-freeze manifest. Incompatible changes require a new API version.
- A deprecated v0 compatibility surface must identify its replacement and
removal criteria. A date alone is not sufficient retirement authority.
- Security reporting and response follow the repository
SECURITY.md.
Rollback and coexistence
Binary rollback does not delete v1 deployments. Before reinstalling v0, use the
matching v1 CLI to inspect and, when intended, destroy v1 resources through its
ownership-guarded lifecycle. Restoring a v0 configuration changes only the
configuration backup boundary; it does not delete v1 deployments or receipts.
Stable release rehearsal must retain checksummed archives for both Linux and
both macOS targets, container- and host-release logs, and an exact-version
rollback/reinstall log. scripts/record-v1-platform-rehearsal.sh validates and
records those artifacts against the exact candidate.
V0 retirement criteria
Retirement is evidence-based. V0 remains available until all of these are true:
- representative new, migrated, Kubernetes, and direct-processkit journeys
pass on candidate-bound technical evidence;
- external pilots have recorded migration friction, failures, recovery steps,
terminology problems, and documentation gaps;
- migration and coexistence documentation covers unresolved decisions and
manual v1 cleanup;
- supported projects have a reviewed migration outcome with no known data
loss or destructive ownership defect;
- all four native artifacts, release phases, and rollback have been rehearsed
from the final candidate;
- the ainfra/aibox/processkit portfolio-boundary audit passes.
Retirement requires a reviewed decision after this evidence exists. Automated
journeys cannot stand in for external operator feedback.
External pilot evidence
Stable readiness requires structured feedback for all five representative
journeys: aibox self-hosting, an existing v0 migration, a clean Compose project
without processkit, an existing Kubernetes target, and direct processkit use.
Each <journey>.json uses this shape:
{
"apiVersion": "aibox.projectious.work/pilot-feedback/v1alpha1",
"kind": "ExternalPilotFeedback",
"journey": "aibox-self-host",
"candidateCommit": "<40-character-commit>",
"status": "completed",
"operatorFeedback": "What the operator experienced",
"configurationFriction": [],
"recoverySteps": [],
"migrationDecisions": [],
"runtimeErrors": [],
"documentationGaps": [],
"terminologyConfusion": []
}
After review, retain the five files against the exact candidate:
RELEASE_CANDIDATE_SHA=<40-character-commit> \
AIBOX_RELEASE_BINARY_SHA256=sha256:<tested-binary-digest> \
./scripts/record-v1-external-pilot-feedback.sh \
dist/v1-pilot-feedback/<40-character-commit>
Empty finding arrays are honest; empty operator feedback, missing journeys, or
candidate-mismatched feedback block stable publication.
12.7 - Compatibility
Compatibility
aibox ↔ processkit Version Matrix
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 |
|---|
| 1.0.0-alpha.1 | v0.28.4 stable bridge; v1.0.0-alpha.3 installer exact pin | opt-in v1 orchestration alpha with signed opaque processkit installer delegation; the v0 bridge remains until parity, rollback, interruption, migration, and secret-safety gates pass |
| 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 |
| 0.28.2 | v0.27.5 | integrates derived-project doctor applicability fixes, Git-ignore-aware sensitive-data scanning, 30-day archive-age enforcement, generated schema foundations, migration drafting, repository portfolio review, and refreshed gateway metadata |
| 0.28.1 | v0.27.4 | 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 |
| 0.27.8 | v0.27.2 | integrates processkit derived-project remediation: project-local pk-commands preservation/schema validation, timestamped role-slot binding IDs, explicit doctor confirmation forwarding, archive remediation metadata, migration archive policy documentation, and refreshed gateway metadata |
| 0.27.7 | v0.27.1 | 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 |
| 0.26.1 | v0.26.9 | verifies GHCR release-host image pushes, fixes Yazi rich-preview API/cache behavior, suppresses recurring legitimate processkit template mirror repair warnings, emits migration affected files, and integrates processkit v0.26.9 |
| 0.26.0 | v0.26.7 | 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 |
| 0.23.10 | v0.25.7 | processkit v0.25.7 model-routing content, apply-time aibox.toml structure migration, self-documenting generated config comments, addon-backed image-slimming switches, and generated-runtime release finalization |
| 0.23.9 | v0.25.6 | 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 |
| 0.23.0 | v0.25.0 | processkit v0.25.0 gateway integration, daemon-proxy mode, runtime pressure diagnostics, init reaping, optional git UI tools, and profile-aware environment metadata |
| 0.22.0 | v0.24.0 | processkit v0.24.0: context archiving, richer model routing metadata, semantic task-router scoring, archive-aware index metadata |
| 0.21.2 | v0.23.1 | processkit v0.23.1 release-audit cleanup and skill metadata fixes |
| 0.21.1 | v0.23.0 | processkit v0.23.0 model governance and release-audit integration |
| 0.21.0 | v0.22.0 | multi-harness slash-command scaffolding and content-diff safety fixes |
| 0.20.0 | v0.22.0 | processkit install integrity, preauth merge, and no-container scaffold mode |
| 0.19.0 | v0.21.0 | MCP permission configuration and processkit v0.21 content integration |
| 0.17.16 | v0.13.0 | BREAKING: rename providers = ["codex"] → ["openai"]; fix zellij --layout flag; fix Rust x86_64 cross-compile target |
| 0.17.15 | v0.13.0 | MCP config model, zjstatus hints, Zellij Ctrl+q, processkit v0.13.0 |
| 0.17.5 | v0.8.0 | processkit v0.8.0 GrandLily src/ restructure |
| 0.17.4 | v0.6.0 | content migration documents (pending/in-progress/applied) |
| 0.17.3 | v0.6.0 | Claude Code slash-command adapters |
| 0.17.2 | v0.6.0 | core skill enforcement, processkit v0.6.0 compat |
| 0.17.0 | v0.5.0 | aibox.lock sectioned format |
| 0.16.1 | v0.4.0 | sync auto-install added |
| 0.16.0 | v0.4.0 | initial processkit integration |
How compatibility is enforced
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:
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".
Upgrading processkit
To upgrade processkit in an existing project:
Edit aibox.toml:
[processkit]
version = "v0.25.5"
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.
12.8 -
Security Reference
This page documents aibox’s security model and trust boundaries.
Support and vulnerability reporting
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.
Dependency and asset provenance review
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/package-lock.json and the Docsy submodule pin dependencies | clean npm ci, 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.
Data handling review
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.
MCP Gateway Trust Scope
How processkit skills are registered
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:
[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.
Implications
- A skill’s
mcp/server.py can read, write, and execute within the container
with the same permissions as the project user. - Skills can access mounted SSH keys (
~/.ssh), API key env vars, and
the full workspace at /workspace. - Skills are registered at the Codex/Claude
project scope — they
are active for every session in the container.
Third-party skill review checklist
Before installing a skill from a third party (outside the processkit core), verify:
- Source code is auditable: the skill’s
mcp/server.py (and any
imported modules) are readable and understandable. - No unexpected outbound network calls: the skill should not exfiltrate
data to external endpoints.
- No credential access beyond stated purpose: check for reads of
~/.ssh/, env vars (ANTHROPIC_API_KEY, etc.), or
~/.claude/~/.codex. - Tool list is minimal: the
allowed_tools set registered by the skill
should match only the capabilities the skill claims to need. - Dependency supply chain: if the skill uses
uv or pip to install
Python packages, review pyproject.toml / requirements.txt for
unexpected dependencies. - Immutable or pinned source: prefer skills pinned to a specific git SHA
or release tag over floating
main/latest references.
Opting out of a skill
To remove a skill and deregister its MCP server:
- Remove the skill from
context/skills/ or update [processkit] config. - Run
aibox apply — this rewrites the harness MCP configuration files
and removes the skill’s allowed_tools entries. - Recreate the container (
docker compose up -d --force-recreate) so the
new MCP configuration takes effect.
seccomp=unconfined Consent Gate
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:
[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.
13 - Roadmap
Roadmap
This page outlines planned features and improvements for aibox. The internal
source of truth is the processkit work item index under context/; this page is
the public-facing summary.
Current Focus
Current work is focused on making long-running AI workspaces cheaper and more
predictable:
- explicit Compose project and image names for each aibox project
- optional tool bundles so idle containers do not carry unnecessary CLIs
- suspended non-focused tmux panes
- runtime resource snapshots and doctor thresholds
- init-reaper support for orphaned helper processes
- processkit MCP gateway adoption and daemon validation in real projects
Planned — Near Term
processkit Gateway Follow-Through
Keep validating the gateway-mode MCP defaults in downstream projects and tune
daemon guidance as more host/container runtime combinations are exercised.
Runtime Diagnostics
Extend resource reporting with zombie process counts and clearer actionable
doctor output for memory and process pressure.
Documentation and Onboarding
Keep the public docs aligned with the current verb/resource CLI grammar,
processkit boundary, addon selection model, and runtime operations.
Planned — Medium Term
Remote Development Boundary
Clarify what belongs in aibox versus a dedicated infrastructure/deployer CLI
for remote and cloud-hosted workspaces.
External Addon and Skill Sources
Broaden source support while preserving pinned, reproducible installs.
Skill Evaluation Support
Support repeatable checks for installed processkit skills and project-specific
customizations.
Planned — Long Term
Multi-Service Workspaces
Improve first-class support for project sidecars and test companions without
turning aibox into a production orchestrator.
Signed Images and Supply Chain
Add stronger supply-chain verification for published images and release assets.
Richer Runtime UI
Move beyond shell status lines toward richer tmux-native status integration
when the additional runtime coupling is worth the complexity.