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

Return to the regular view of this page.

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

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]

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.

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.