This is the multi-page printable view of this section. Click here to print.

Return to the regular view of this page.

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

  1. Fork and clone the repository:

    git clone https://github.com/projectious-work/aibox.git
    cd aibox
    
  2. 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.

  3. Build the CLI:

    cd cli
    cargo build
    
  4. Run the tests:

    cargo test
    cargo clippy -- -D warnings
    cargo fmt -- --check
    

Project Structure

  • cli/ — Rust CLI source code
  • images/ — Published container image Dockerfiles
  • addons/ — 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

  1. Make your changes in cli/src/
  2. Run cargo test to verify all tests pass
  3. Run cargo clippy -- -D warnings for lint checks
  4. Run cargo fmt to format code

Image Changes

  1. Edit the relevant Dockerfile in images/
  2. Build locally to verify: docker build -t aibox-test images/<flavor>/
  3. Test that derived images still build if you changed the base

Documentation Changes

  1. Edit or add pages in docs-site/docs/
  2. Update docs-site/sidebars.js if adding new pages
  3. 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:

PhaseWhereCommandPurpose
Container sideaibox devcontainer./scripts/maintain.sh release X.Y.Zcheck dependency/harness state, sync processkit default, bump CLI version, test, audit, build Linux binaries, tag, create GitHub release, deploy docs
Host sidemacOS host./scripts/maintain.sh release-host X.Y.Zbuild 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.

LineDevelopmentRelease authorityPurpose
v0 maintenancev0.x-devv0.x-releaseStable v0 releases and hotfixes
v1 prereleasev1.x-devv1.x-pre-releaseAlpha, beta, and release-candidate tags
v1 GAv1.x-devv1.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 audit
  • cargo update --dry-run review for lockfile-resolvable crate updates
  • Linux release builds for aarch64-unknown-linux-gnu and x86_64-unknown-linux-gnu
  • binary version smoke check
  • annotated git tag push
  • GitHub release creation with Linux binaries
  • Hugo/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

TierWhere it runsWhat it needs
Tier 1Local temp directoryThe compiled aibox binary only
Tier 1 + MockLocal temp directoryBinary + mock docker/podman scripts on PATH
Tier 2Remote SSH companionaibox-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:

CommandCovers
./scripts/maintain.sh test-e2e-visual-statusall generated layouts across all themes, tmux status/key rows, and theme RGB signatures
./scripts/maintain.sh test-e2e-visual-tabstmux window traversal, Yazi surface, Vim, shell, lazygit, and every enabled AI harness
./scripts/maintain.sh test-e2e-visual-yaziYazi preview plugins, optional preview tools, git symbols, and preview modes
./scripts/maintain.sh test-e2e-visualall visual tiers
./scripts/maintain.sh test-e2e-doc-capturesall 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:

  1. a new Compose workspace can compile and render a deterministic plan;
  2. a representative v0 project can preview, apply, and roll back a reviewed v1 intent without exposing secrets or touching v1 deployment records;
  3. an existing Kubernetes target passes the complete live M7c lifecycle;
  4. 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

AreaOutput
Project contractaibox.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
Addonstool and runtime selection from addons/ YAML definitions
Harness wiringprovider entry files, MCP registration, permissions, and runtime tabs
Diagnosticsaibox 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.

# 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 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:

PlatformFile
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 ARM64aibox-vX.Y.Z-aarch64-unknown-linux-gnu.tar.gz
Linux x86_64aibox-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:

OptionDefaultDescription
--basedebianBase image
<NAME>Current directory nameContainer and hostname
--profilehuman-devUsage profile: human-dev or warning-mode headless-runner
--harnessclaudeAI harnesses (can be repeated): claude, codex, gemini, aider, etc.
--addonAddon names (can be repeated): python, rust, node, go, latex, etc.
--themegruvboxTheme family
--context-modeprocesskitContext layer: processkit or harness-only
--processkit-versionlatest stable tagprocesskit 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.

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:

aibox apply

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:

  1. Open the project folder in VS Code
  2. When prompted, click “Reopen in Container”
  3. 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

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.

Apply Devcontainer Files

Run apply to create the .devcontainer/ directory from your config:

aibox apply

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

  1. Back up your existing files:
    cp -r .devcontainer .devcontainer.bak
    
  2. Run aibox apply – it will overwrite the existing files
  3. 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)
  4. 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:

aibox doctor

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:

mv .root .aibox-home

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.

Installed Tools

ToolVersion / SourcePurpose
tmuxDebian packageTerminal multiplexer
Yazi25.4.8 (prebuilt binary from GitHub releases)Terminal file manager
VimDebian package (vim + vim-runtime)Editor
GitDebian packageVersion control
Claude CLIOfficial install scriptAI assistant
ripgrep (rg)Debian packageFast recursive search (grep replacement)
fdDebian packageFast file finder (find replacement)
batDebian packageSyntax-highlighting cat replacement
ezaDebian packageModern ls replacement with git integration
zoxideDebian packageSmarter cd that learns your habits
fzfDebian packageFuzzy finder for files, history, and more
deltaDebian packageSyntax-highlighting diff viewer (used by git)
starshipPrebuilt binaryMinimal, fast shell prompt with context
curlDebian packageHTTP client
jqDebian packageJSON processor
lessDebian packagePager
unzipDebian packageArchive extraction
iproute2Debian packageNetwork route/interface inspection for status segments
iputils-pingDebian packageICMP latency checks for status segments
bash-completionDebian packageShell completions
ca-certificatesDebian packageTLS root certificates
localesDebian packageLocale support (en_US.UTF-8)
tzdataDebian packageTimezone 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.

KeyAction
Ctrl+g then h/j/k/lNavigate panes (vim-style)
Ctrl+g then nNew pane
Ctrl+g then dSplit down
Ctrl+g then rSplit right
Ctrl+g then xClose focused pane
Ctrl+g then fToggle fullscreen
Ctrl+g then zToggle pane frames
Ctrl+g then eToggle embed/floating
Ctrl+g then = / -Resize pane (increase / decrease)
Ctrl+g then tNew window
Ctrl+g then wClose window
Ctrl+g then [ / ]Previous / next window
Ctrl+g then 1-5Jump to window N
Ctrl+g then i / oMove window left / right
Ctrl+g then sSession chooser
Ctrl+g then mSession manager
Ctrl+g then uEnter scroll mode
Ctrl+g then /Search scrollback
Ctrl+qQuit 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.

focus – one tool per window, fullscreen

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.

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 PathContainer PathContents
.aibox-home/.ssh//home/aibox/.ssh (read-only)SSH keys
.aibox-home/.vim//home/aibox/.vimVim config and undo history
.aibox-home/.config//home/aibox/.configGit, tmux, Yazi, prompt, and tool config
.aibox-home/.cache//home/aibox/.cacheRuntime caches
.aibox-home/.local//home/aibox/.localHelper scripts, state, and local data
.aibox-home/.tmux//home/aibox/.tmuxtmux 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.

Extra Packages — Dockerfile.local

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

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"
FieldDefaultDescription
enabledfalseWhether to set up audio environment variables in the container
backendpulseaudioAudio bridge backend. Only PulseAudio is currently supported
installtrueWhether to install the internal audio-voice tool recipe when audio is enabled
pulse_servertcp:host.docker.internal:4714PulseAudio 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

  1. Install PulseAudio:

    brew install pulseaudio
    
  2. Enable the TCP module. Add to ~/.config/pulse/default.pa:

    load-module module-native-protocol-tcp port=4714 auth-anonymous=1
    
  3. Start PulseAudio:

    pulseaudio --start
    
  4. Verify it is listening:

    lsof -i :4714
    

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

  1. 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
    
  2. Use host.docker.internal (Docker 20.10+) or the Docker bridge IP:

    [audio]
    enabled = true
    pulse_server = "tcp:host.docker.internal:4714"
    

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.

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

  1. Verify PulseAudio is running on the host:

    pulseaudio --check && echo "running" || echo "not running"
    
  2. Verify the TCP module is loaded:

    pactl list modules | grep module-native-protocol-tcp
    
  3. 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:

[audio]
enabled = false

This removes the PULSE_SERVER environment variable from the container. The audio packages (sox, pulseaudio-utils) remain installed in the base image but are inert without a server to connect to.

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:

MechanismWhen to use
Yazi file previewBrowsing files — preview appears automatically in the right panel as you navigate
Standalone TUI viewersViewing 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.

Supported formats

FormatExtensionsPreviewerRequirement
JPEG / PNG.jpg .jpeg .pngimage (built-in)chafa
GIF (incl. animated).gifimage (built-in)chafa
WebP.webpimage (built-in)chafa
BMP.bmpimage (built-in)chafa
TIFF.tiff .tifimage (built-in)chafa
SVG.svgsvg.yazi pluginresvg or rsvg-convert
EPS.epseps.yazi pluginghostscript (addon)
PDF.pdfpdf (built-in)poppler-utils
Markdown.md .markdownrich-preview.yazi pluginpreview-enhanced addon
SQLite.sqlite .sqlite3 .dbsqlite-preview.yazi plugindata-preview addon
CSV / TSV.csv .tsvtabular-preview.yazi plugindata-preview addon
Excel.xls .xlsxtabular-preview.yazi plugindata-preview addon
Video.mp4 .mkv .webm .avivideo (built-in)ffmpeg (addon)
Text / codemost text formatscode (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.

Format notes

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.

SQLitesqlite-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 / Exceltabular-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.


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 output.pdf

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'
PartRole
entrWatches output.pdf for changes (inotify, near-zero CPU at idle)
mutool drawMuPDF rasteriser — renders a PDF page to PNG (fast, no X11 needed)
-o /tmp/p.png output.pdf 1Output file, input file, page number
timg --clearRenders 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 formatRasteriser command
PDF (page 1)mutool draw -o /tmp/p.png file.pdf 1
SVGresvg file.svg /tmp/p.png
EPSgs -dBATCH -dNOPAUSE -sDEVICE=png16m -r150 -sOutputFile=/tmp/p.png file.eps

Format Coverage Summary

FormatYazi previewchafatimgWatch-mode
JPEG / PNG
GIF (animated)
WebP
BMP
TIFF
SVG✓ (resvg)✓ (librsvg)✓ (resvg)
EPS✓ (ghostscript)✓ (ghostscript)
PDF✓ (poppler)✓ (mutool)
Video✓ (ffmpeg)
.excalidrawtext 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:

FieldWhat it tells you
memory_current_bytescurrent cgroup memory usage
memory_maxmemory limit or unlimited
oom_kill_countwhether the kernel has killed a process in the cgroup
total_process_counttotal visible processes
processkit_mcp_python_process_countlive 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].name
  • init: 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

SymptomFirst checks
AI process disappearsaibox get runtime --resources, then inspect oom_kill_count
OrbStack groups projects oddlyrerun aibox apply, then recreate the container
Network drops after idle timeset [container] keepalive = true
Build keeps using stale layersrun aibox apply --no-cache
Runtime starts but tools are missingcheck 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

AddonDefault ToolsOptional Tools
pythonpython (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)
rustrustc (1.90/1.91/1.92/1.93/1.94/1.94.1/1.96.0/1.96.1/1.97.1), clippy, rustfmt
nodenode (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)
gogo (1.25/1.26/1.26.3/1.26.4/1.26.5)
typsttypst (0.13.1/0.14.2/0.15.0)
latextexlive-core, texlive-recommended, texlive-fonts, biber, texlive-code, texlive-diagrams, texlive-mathtexlive-music, texlive-chemistry

Tool Bundles

AddonDefault ToolsOptional Tools
infrastructureopentofu, ansible, packer
git-uigh, lazygit
preview-archivechafa, librsvg, poppler, timg, mupdf, entr, p7zip, resvg
preview-enhancedrich, ffmpeg, ghostscript
data-previewsqlite3, csvkit
audio-voicesox, pulseaudio-utils, ALSA PulseAudio plugins
kuberneteskubectl, helm, kustomizek9s
cloud-awsaws-cli
cloud-gcpgcloud-cli
cloud-azureazure-cli

Documentation Frameworks

AddonTools
docs-mkdocsmkdocs + mkdocs-material
docs-zensicalzensical
docs-docusaurusdocusaurus
docs-starlightstarlight
docs-mdbookmdbook
docs-hugohugo

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:

AddonNaturally relevant skills
pythonpython-best-practices, fastapi-patterns, pandas-polars
rustrust-conventions, concurrency-patterns
goconcurrency-patterns and the Go-flavoured patterns shipped upstream
nodetypescript-patterns, tailwind
latex / typstdocumentation
git-uigit-workflow
kubernetescontainer-orchestration
cloudflareCloudflare Tunnel workflows
infrastructureterraform-flavoured patterns shipped upstream

See Skills (via processkit) for the full split.

How Addons Work

When you run aibox apply, the CLI:

  1. Reads [addons] from aibox.toml
  2. Looks up each addon definition from YAML files in ~/.config/aibox/addons/
  3. Merges your tool selections with addon defaults
  4. Generates Dockerfile builder stages (for heavy builds like Rust, LaTeX)
  5. Generates runtime RUN/COPY commands
  6. 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 Definition Format

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.

Extra Packages

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 Bundle Addons

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.

Preview and Archive Tools

[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]
enabled = true

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.

AddonToolInstall Method
docs-mkdocsMkDocs + Material themeuv
docs-zensicalZensicaluv
docs-docusaurusDocusaurusnpm
docs-starlightStarlight (Astro)npm
docs-mdbookmdBookBinary download
docs-hugoHugo ExtendedBinary 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.

Configure documents

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:

[audio]
enabled = true

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)

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.

How Version Tracking Works

Two pieces track the version:

  1. 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"
    
  2. 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

aibox 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.

  1. Run aibox doctor to identify gaps and queue migration artifacts
  2. Run aibox set migration <id> in-progress to begin the next pending migration
  3. Open the migration document from context/migrations/in-progress/
  4. Paste its contents into a Claude Code session (or let the agent find it via AGENTS.md)
  5. Review the changes the agent makes
  6. Run aibox apply migration <id> to mark the migration complete

Manually

  1. Run aibox doctor to generate migration artifacts
  2. Run aibox set migration <id> in-progress to move the migration to context/migrations/in-progress/
  3. Follow the migration document’s checklist
  4. Run aibox apply migration <id> to archive the migration to context/migrations/applied/

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 Document Format

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

  1. Edit aibox.toml:

    [customization]
    prompt = "arrow"
    
  2. Run apply:

    aibox apply
    

The Starship config is regenerated at .aibox-home/.config/starship.toml. Colors are derived from the active theme.

Font Requirements

PresetFont requirement
defaultNerd Font recommended (for symbol)
plainAny font — ASCII only
minimalNerd Font recommended (for symbol)
nerd-fontNerd Font required
pastelNerd Font or Powerline font required
powerline-pastelNerd Font or Powerline font required
bracketedAny font — no special glyphs
arrowNerd 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:

ToolConfig LocationFormat
tmux.config/tmux/themes/<name>.conftmux style settings
Vim.vim/colors/<name>.vimVim colorscheme
Yazi.config/yazi/theme.tomlTOML with hex colors
lazygit.config/lazygit/config.ymlYAML gui.theme section
Starship.config/starship.tomlTOML with palette

Color Mapping

A theme needs these terminal color slots for tmux:

SlotPurpose
fgDefault foreground text
bgBackground
blackDark background variant
redErrors, unstaged changes
greenSuccess, staged changes
yellowWarnings, search highlights
bluePrimary accent
magentaSecondary accent
cyanTertiary accent, links
whiteBright foreground
orangeSpecial 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

WindowContents
1 · workleft 50%: yazi · right 50%: 1st harness
2 · aiall further harnesses, split as full-height even horizontal panes
3 · lazygitlazygit, when git-ui selects lazygit
3/4 · shellbash

dev

WindowContents
1 · workleft 50%: yazi top 50% / 1st harness bottom 50% · right 50%: shell
2 · lazygitlazygit, when git-ui selects lazygit
2/3 · aiall further harnesses, split as full-height even horizontal panes
final · shellbash

focus

WindowContents
1 · filesyazi
2..n · harness nameone fullscreen window per harness in harness_order
next · lazygitlazygit, when git-ui selects lazygit
final · shellbash

cowork

WindowContents
1 · workleft 50%: yazi · right 50%: shell
2 · aiall harnesses, split as full-height even horizontal panes
3 · lazygitlazygit, when git-ui selects lazygit

Setting The Default Layout

[customization]
layout = "dev"

Options: dev, focus, cowork, ai.

Per-Session Override

aibox up --layout focus

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.

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-day
  • catppuccin-mocha, catppuccin-macchiato, catppuccin-frappe, catppuccin-latte
  • dracula, dracula-soft, nord, gruvbox-dark, gruvbox-light
  • rose-pine, rose-pine-moon, rose-pine-dawn
  • material, material-ocean, material-palenight, material-lighter, material-darker
  • solarized-dark, solarized-light
  • github-dark, github-dark-dimmed, github-dark-high-contrast, github-light, github-light-high-contrast
  • ayu-dark, ayu-mirage, ayu-light, night-owl, night-owl-light, moonlight
  • everforest-dark, everforest-light, kanagawa-wave, kanagawa-dragon, kanagawa-lotus
  • min-dark, min-light, one-dark-pro, one-light, slack-dark, slack-ochin
  • vitesse-dark, vitesse-light, vitesse-black, vscode-dark-plus, vscode-light-plus
  • andromeeda, aurora-x, houston, laserwave, monokai, plastic, poimandres, red, snazzy-light, synthwave-84, vesper
  • projectious

Light/Dark Partners

FamilyDark variantsLight variant
Tokyo Nighttokyo-night, tokyo-night-stormtokyo-night-day
Catppuccincatppuccin-mocha, catppuccin-macchiato, catppuccin-frappecatppuccin-latte
Gruvboxgruvbox-darkgruvbox-light
Rose Pinerose-pine, rose-pine-moonrose-pine-dawn
Materialmaterial, material-ocean, material-palenightmaterial-lighter
Solarizedsolarized-darksolarized-light
GitHubgithub-darkgithub-light
Ayuayu-dark, ayu-mirageayu-light
Night Owlnight-owlnight-owl-light
Everforesteverforest-darkeverforest-light
Kanagawakanagawa-wave, kanagawa-dragonkanagawa-lotus
Minmin-darkmin-light
One Darkone-dark-proone-light
Slackslack-darkslack-ochin
Vitessevitesse-dark, vitesse-blackvitesse-light
VS Codevscode-dark-plusvscode-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:

ToolConfig fileWhat’s themed
tmux.config/tmux/themes/<name>.confPane borders, status bar, window colors
Vim.vim/colors/<name>.vimSyntax highlighting, UI elements
Yazi.config/yazi/theme.tomlFile colors, status bar, selection
lazygit.config/lazygit/config.ymlBorders, selection, diff colors
Starship.config/starship.tomlPrompt 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

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

OptionEnvironment VariableDefaultDescription
--config <PATH>./aibox.tomlPath to configuration file
--log-level <LEVEL>AIBOX_LOG_LEVELinfoLog verbosity
-y, --yesSkip 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
OptionDefaultDescription
[NAME]Current directoryProject/container name
--base <BASE>debianBase image
--profile <PROFILE>human-devUsage profile: human-dev or warning-mode headless-runner
--context-mode <MODE>processkitContext layer: processkit or harness-only
--harness <NAME>claudeAI harness, repeatable
--addon <NAME>Addon name, repeatable
--theme <THEME>gruvboxRuntime UI theme family
--processkit-version <TAG>latest prompt/defaultPin processkit
--include-prereleaseoffInclude 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
OptionDescription
--no-cacheForce a full image rebuild without using cached layers
--rebuildVisible alias for --no-cache
--config-onlyRegenerate files without building the image
--standardize-configRewrite aibox.toml through the current canonical grouped template after compatibility migrations. Recognized schema fields are preserved; unknown keys block the rewrite.
--fix-compliance-contractRewrite the processkit compliance block in AGENTS.md
--no-containerSkip 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:

FieldSourceMeaning
memory_current_bytes/sys/fs/cgroup/memory.currentCurrent cgroup memory usage in bytes
memory_max/sys/fs/cgroup/memory.maxCgroup memory limit, or unlimited when the kernel reports max
oom_kill_count/sys/fs/cgroup/memory.eventsCumulative oom_kill counter for the cgroup
total_process_countnumeric entries under /procTotal visible process count
processkit_mcp_python_process_count/proc/*/cmdlinePython 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.

CommandSchemaContents
describe addon-catalogaibox.addon-catalog.v0Built-in addon metadata, profile intent, automation usage class, exported surfaces, dependencies, and tool versions
describe workspace-manifestaibox.workspace-manifest.v0Sorted projection of aibox.toml: project, context mode/packages, processkit source when enabled, AI harnesses, addons, and MCP server keys
describe provider-backendsaibox.provider-backends.v0-previewSupported AI harness backends, selected status, addon availability, MCP config targets, and permission targets
describe image-provenance-policyaibox.image-provenance-policy.v0-previewGHCR 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.

RemovedUse
aibox syncaibox apply
aibox startaibox up
aibox stopaibox down
aibox statusaibox get runtime
aibox remove / aibox rmaibox 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 updateaibox self update
aibox completionsaibox self completion
aibox uninstallaibox self uninstall
aibox audio check/setupaibox 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.

FieldTypeRequiredDefaultDescription
project_nameStringNocontainer.nameHuman-readable project name
profileStringNo"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.

FieldTypeRequiredDefaultDescription
nameStringYesContainer name (used by compose and runtime inspect)
hostnameStringNo"aibox"Container hostname
userStringNo"aibox"Container user
post_create_commandStringNoCommand to run after container creation
keepaliveBooleanNofalsePeriodic DNS keepalive for development environments with idle network timeouts.
environmentMap (String → String)No{}Environment variables injected into the container. Suitable for non-secret project-wide values; use .aibox-local.toml for secrets.
extra_volumesArray of ExtraVolumeNo[]Additional bind mounts. Each entry has source, target, and optional read_only.
resource_thresholdsTableNosee belowWarning 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.

FieldTypeDefaultDescription
memory_mib_warnIntegerunsetWarn when cgroup memory.current exceeds this many MiB.
process_count_warnInteger400Warn when /proc contains more processes than this. Set to 0 to disable.
processkit_mcp_python_warnInteger50Warn when many Python processkit MCP server processes are live. Only rendered and used in processkit mode. Set to 0 to disable.
oom_kill_warnInteger0Warn when cgroup memory.events reports more OOM kills than this.

[[container.extra_volumes]]

Each entry in the extra_volumes array is an ExtraVolume with these fields:

FieldTypeRequiredDefaultDescription
sourceStringYesHost path (supports ~ expansion)
targetStringYesContainer path where the volume is mounted
read_onlyBooleanNofalseMount 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.

.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.

FieldTypeRequiredDefaultDescription
modeStringNoprocesskitprocesskit installs the processkit-backed project context layer. harness-only skips processkit content and uses only generated container/harness configuration.
packagesArray of stringsNo["product"] in processkit mode, [] in harness-only modeprocesskit package selection. Required to be non-empty in processkit mode. Ignored in harness-only mode.
schema_versionString (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
KeyTypeRequiredDefaultDescription
engineStringNolualatexlualatex, pdflatex, xelatex, or tectonic. Tectonic supports build but not watch.
cache_dirRelative pathNo.latex-cacheRoot for project-local TEXMFVAR and TEXMFCONFIG. Parent traversal is rejected.
optionsArrayNo[]Additional single-line engine arguments.
documents[].nameStringYesUnique command-safe document name.
documents[].sourceRelative pathYesMain TeX source.
documents[].output_dirRelative pathNo.latex-cache/outputPDF, log, and auxiliary output directory.
preview.enabledBooleanNofalseGenerates one shared read-only Compose preview sidecar; host-side aibox up starts it and it serves every configured document.
preview.engineStringNoembedpdfViewer implementation; currently only embedpdf is supported.
preview.bindIP addressNo127.0.0.1Compose host-publish address. Loopback is accessible only from that host; use 0.0.0.0 only for other machines.
preview.portIntegerNo8765Host-published port for the document index and all viewers. It maps to sidecar port 8765.
preview.documentStringNofirst configured documentDefault for legacy /document.pdf and /events routes. All configured documents are served.
preview.allow_publicBooleanNofalseRequired 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.

FieldTypeRequiredDefaultDescription
harnesses[].harnessStringYes for each entrynoneHarness id. Supported values: claude, codex, gemini, aider, continue, cursor, copilot, opencode, hermes.
harnesses[].enableBooleanNofalseInclude this harness in generated runtime, agent, and MCP config. Alias: enabled.
harnesses[].installBooleanNofalseInstall the matching in-container CLI recipe when available. Cursor has no container CLI, so keep this false for cursor.
harnesses[].versionStringNoaddon’s defaultOptional CLI version pin.
model_providersArray of stringsNo[]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:

ProviderAPI key envBase URL env
anthropicANTHROPIC_API_KEYANTHROPIC_BASE_URL
openaiOPENAI_API_KEYOPENAI_BASE_URL
googleGEMINI_API_KEYGEMINI_BASE_URL
mistralMISTRAL_API_KEYMISTRAL_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.

FieldTypeRequiredDefaultDescription
sourceStringNohttps://github.com/projectious-work/processkit.gitGit URL of the content source.
versionStringNounsetSemver tag to consume. The sentinel unset skips fetching until a real tag is set.
src_pathStringNosrcSubdirectory inside the source repo containing the shippable payload. Auto-detected for flat release-asset tarballs.
branchStringNo(none)Optional branch override for testing pre-release work. Discouraged but supported.
release_asset_url_templateStringNo(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.

FieldTypeRequiredDefaultDescription
schema_versionString (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:

  1. Branch override (if branch is set) — git clone --branch <name>.
  2. 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.
  3. Host auto-tarball — falls back to GitHub / GitLab’s auto-generated archive/refs/tags/<version>.tar.gz when no release asset is available.
  4. 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:

  1. Built-in processkit servers — only in context.mode = "processkit", either the processkit gateway or separate per-skill servers, depending on [ai.mcp.gateway]
  2. aibox.toml [[ai.mcp.servers]] — team-shared servers committed to version control
  3. .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"
ModeBehavior
autoRegister a self-starting processkit gateway daemon when the installed processkit version ships it; otherwise fall back to separate per-skill servers
daemonUse one localhost processkit gateway daemon plus one stdio proxy per harness
stdioRegister processkit-gateway directly as a stdio MCP server
separateAlways 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:

FieldTypeRequiredDefaultDescription
nameStringYesUnique server name (used as the key in generated configs)
commandStringYesExecutable to run (e.g. npx, /usr/local/bin/my-server)
argsArray of stringsNo[]Arguments passed to command
envMap (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:

FieldTypeRequiredDefaultDescription
default_modeStringNo"ask"Default permission when no explicit pattern matches. Use "allow" only when every configured MCP server is trusted.
allow_patternsArray of stringsNo[]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_patternsArray of stringsNo[]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"

[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.).

FieldTypeRequiredDefaultDescription
canonicalStringNo"AGENTS.md"Filename of the canonical agent entry document. Almost no one should override this — the default matches the agents.md ecosystem convention.
provider_modeStringNo"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.

FieldTypeRequiredDefaultDescription
themeStringNo"gruvbox-dark"Color theme. Supports the tmux-powerkit popular theme roster and variants, plus projectious; see Themes.
modeStringNo"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.
promptStringNo"default"Starship preset: default, plain, arrow, minimal, nerd-font, pastel, powerline-pastel, bracketed. Legacy pastel-powerline is accepted as an alias.
layoutStringNo"dev"tmux layout: dev, focus, cowork, ai
tmux.status.modeStringNo"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.styleStringNo"rounded"PowerKit separator style: normal, rounded, slant, slantup, trapezoid, flame, pixel, honeycomb, none.
tmux.status.separators.edge-styleStringNo"rounded"PowerKit edge separator style for status boundaries. Uses the same values as style.
tmux.status.separators.elements-spacingStringNo"both"PowerKit spacing mode: false, true, both, windows, plugins.
tmux.status.forge.github-hostsArray of stringsNo["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.

FieldTypeRequiredDefaultDescription
enabledBooleanNofalseEnable PulseAudio environment setup
backendStringNo"pulseaudio"Audio bridge backend. Only pulseaudio is currently supported.
installBooleanNotrueSelect the internal audio-voice recipe when audio is enabled
pulse_serverStringNo"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.

FieldTypeRequiredDefaultDescription
credential_helperStringNo"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

FieldTypeRequiredDefaultDescription
preserve_disabled_harness_stateBooleanNofalseRecords 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_stateBooleanNofalseExplicitly removes retained state for disabled AI harnesses on the next aibox apply.

Environment Variable Overrides

Some settings can be overridden via environment variables:

VariableOverridesDescription
AIBOX_HOST_ROOT.aibox-home/ pathHost directory for persistent config (default: .aibox-home/)
AIBOX_WORKSPACE_DIRWorkspace mount sourceHost directory mounted as /workspace
AIBOX_LOG_LEVEL--log-levelLog 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.

[[container.extra_volumes]]

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

SectionMerge 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.

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.

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

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&#123;char&#125;` | Jump to next &#123;char&#125; 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 `&#123;N&#125;j`/`&#123;N&#125;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:

  1. representative new, migrated, Kubernetes, and direct-processkit journeys pass on candidate-bound technical evidence;
  2. external pilots have recorded migration friction, failures, recovery steps, terminology problems, and documentation gaps;
  3. migration and coexistence documentation covers unresolved decisions and manual v1 cleanup;
  4. supported projects have a reviewed migration outcome with no known data loss or destructive ownership defect;
  5. all four native artifacts, release phases, and rollback have been rehearsed from the final candidate;
  6. 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 versionMin. processkitNotes
1.0.0-alpha.1v0.28.4 stable bridge; v1.0.0-alpha.3 installer exact pinopt-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.14v0.28.4ensures pk-reconcile and pk-repo-reconcile install their project-reconciliation and repo-management skill dependencies
0.28.15v0.28.4refreshes bundled maintenance tools, locks cargo-audit installation for Rust compatibility, and publishes the Hugo/Docsy documentation site
0.28.13v0.28.4adds open GitHub Discussion counts to the tmux Forge status segment and restores the complete generated Codex command projection set
0.28.12v0.28.4integrates processkit v0.28.4 and makes companion E2E validation work from linked release worktrees
0.28.11v0.28.3adds the cloudflare addon, which installs cloudflared from Cloudflare’s signed package repository rather than Debian’s archive
0.28.10v0.28.3reconciles standard processkit skills, recommends tooling-linked skills interactively, upgrades prerelease processkit surfaces, and serializes release Tier 2 E2E validation
0.28.6v0.28.3fixes 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.5v0.28.1fixes 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.4v0.28.1integrates processkit v0.28.1 and refreshes the maintained v0.x processkit compatibility baseline
0.28.3v0.27.6integrates 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.2v0.27.5integrates 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.1v0.27.4restores 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.0v0.27.4adds 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.8v0.27.2integrates 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.7v0.27.1fixes the TeX Live historic installer mirror, resolves pk-doctor false positives, preserves disabled harness state, and accepts context mode in schema validation
0.27.6v0.27.1refreshes tool and harness pins, updates generated runtime/docs references, and adds the GitHub CLI credential-helper integration for HTTPS Git operations
0.27.5v0.27.1refreshes 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.4v0.27.1refreshes 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.3v0.27.1integrates 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.2v0.27.0fixes 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.1v0.27.0refreshes 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.0v0.27.0integrates 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.8v0.26.16integrates 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.7v0.26.15integrates 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.6v0.26.14integrates processkit v0.26.14; updates processkit metadata to the new release and preserves tmux/Vim/cheatsheet and clipboard behavior consistency
0.26.5v0.26.13re-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.4v0.26.10integrates 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.3v0.26.9fixes 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.2v0.26.9fixes 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.1v0.26.9verifies 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.0v0.26.7refreshes 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.14v0.26.5integrates 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.13v0.26.2fixes 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.12v0.26.2fixes 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.11v0.26.2fixes 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.10v0.26.2integrates 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.9v0.26.1integrates 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.8v0.26.0improves 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.7v0.25.8introduces 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.6v0.25.8expands tmux/PowerKit theme coverage with light/dark partner handling, generated theme comments, Docusaurus theme documentation, and runtime border/status color improvements
0.25.5v0.25.8refreshes 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.4v0.25.8repairs 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.3v0.25.8fixes 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.2v0.25.8adds 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.0v0.25.8replaces 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.1v0.25.8fixes 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.0v0.25.8adds 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.21v0.25.8repairs 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.20v0.25.8makes 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.19v0.25.8hardens 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.18v0.25.8updates 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.17v0.25.8installs 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.16v0.25.8moves 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.15v0.25.8fixes 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.14v0.25.8canonical 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.13v0.25.8fixes 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.12v0.25.8processkit 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.11v0.25.7grouped 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.10v0.25.7processkit 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.9v0.25.6restores 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.8v0.25.5native 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.7v0.25.5host-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.6v0.25.5processkit 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.5v0.25.4generated Dockerfile lazygit disablement cleanup no longer aborts when lazygit is absent as an apt package, while still removing inherited lazygit binaries
0.23.4v0.25.4processkit 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.3v0.25.3processkit v0.25.3 model-spec/model-profile migrations and Codex seccomp fallback for bubblewrap
0.23.2v0.25.1processkit v0.25.1 model-recommender lifecycle metadata, task suitability classes, task-class-aware routing, and refreshed model roster
0.23.1v0.25.0stale runtime cleanup for old Compose project names, lazygit disablement fixes, and procps runtime diagnostics
0.23.0v0.25.0processkit v0.25.0 gateway integration, daemon-proxy mode, runtime pressure diagnostics, init reaping, optional git UI tools, and profile-aware environment metadata
0.22.0v0.24.0processkit v0.24.0: context archiving, richer model routing metadata, semantic task-router scoring, archive-aware index metadata
0.21.2v0.23.1processkit v0.23.1 release-audit cleanup and skill metadata fixes
0.21.1v0.23.0processkit v0.23.0 model governance and release-audit integration
0.21.0v0.22.0multi-harness slash-command scaffolding and content-diff safety fixes
0.20.0v0.22.0processkit install integrity, preauth merge, and no-container scaffold mode
0.19.0v0.21.0MCP permission configuration and processkit v0.21 content integration
0.17.16v0.13.0BREAKING: rename providers = ["codex"]["openai"]; fix zellij --layout flag; fix Rust x86_64 cross-compile target
0.17.15v0.13.0MCP config model, zjstatus hints, Zellij Ctrl+q, processkit v0.13.0
0.17.5v0.8.0processkit v0.8.0 GrandLily src/ restructure
0.17.4v0.6.0content migration documents (pending/in-progress/applied)
0.17.3v0.6.0Claude Code slash-command adapters
0.17.2v0.6.0core skill enforcement, processkit v0.6.0 compat
0.17.0v0.5.0aibox.lock sectioned format
0.16.1v0.4.0sync auto-install added
0.16.0v0.4.0initial 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:

  1. Edit aibox.toml:

    [processkit]
    version = "v0.25.5"
    
  2. Run aibox apply on the host — the 3-way diff will show changed content and generate processkit content migration documents in context/migrations/pending/.

  3. 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:

SurfaceProvenance controlRelease validation
Rust CLIcli/Cargo.lock pins the complete dependency graphcargo test, Clippy with warnings denied, and cargo audit
Documentationdocs-site/package-lock.json and the Docsy submodule pin dependenciesclean npm ci, production Hugo build, and npm audit
processkitsource, version, and release-asset SHA-256 are recorded in aibox.lock and live provenanceinstaller hash verification, three-way content comparison, and pk-doctor integrity checks
Base imagesrelease-specific image tags, OCI source/profile labels, and generated version markerscross-platform build, GHCR publication verification, and downstream runtime smoke
Addon downloadspinned versions plus SHA-256, signed checksum, or upstream sidecar verification where availablerelease-state inventory and real container lifecycle tests
Release binarieslocally cross-compiled artifacts attached to a signed release tagversion 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:

  1. Source code is auditable: the skill’s mcp/server.py (and any imported modules) are readable and understandable.
  2. No unexpected outbound network calls: the skill should not exfiltrate data to external endpoints.
  3. No credential access beyond stated purpose: check for reads of ~/.ssh/, env vars (ANTHROPIC_API_KEY, etc.), or ~/.claude/~/.codex.
  4. Tool list is minimal: the allowed_tools set registered by the skill should match only the capabilities the skill claims to need.
  5. Dependency supply chain: if the skill uses uv or pip to install Python packages, review pyproject.toml / requirements.txt for unexpected dependencies.
  6. 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:

  1. Remove the skill from context/skills/ or update [processkit] config.
  2. Run aibox apply — this rewrites the harness MCP configuration files and removes the skill’s allowed_tools entries.
  3. Recreate the container (docker compose up -d --force-recreate) so the new MCP configuration takes effect.

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.