Skip to content

Repository files navigation

aibox

CI License: MIT Bash

Run AI coding agents in a lightweight Bubblewrap sandbox, with project tooling managed by direnv and Nix devShells.

aibox is the lightweight successor to aidock: no container image, no image commits on exit, no per-session agent binary drift, and no runtime configuration file.

aibox codex
aibox claude
aibox copilot
aibox hermes
aibox omp
aibox opencode
aibox pi
aibox ori codex
aibox -- bash

Supported agent state/config policy is maintained for Codex, Claude Code, GitHub Copilot CLI, Hermes, OMP, OpenCode, and Pi. OpenRouter support uses Ori. Other commands can be useful for debugging, but they are best-effort and do not get dedicated persistent state/config mounts.

Install

Nix is the recommended installation method:

nix profile install github:ruifm/aibox/v0.3.0

Run without installing:

nix run github:ruifm/aibox/v0.3.0 -- codex

From a clone:

nix profile install .

Secondary direct-script install:

mkdir -p ~/.local/bin
curl -fsSL https://raw.githubusercontent.com/ruifm/aibox/v0.3.0/aibox -o ~/.local/bin/aibox
chmod +x ~/.local/bin/aibox

After installing, run an end-to-end smoke check:

aibox -- true && echo "aibox smoke check passed"

This also creates the known persistent agent state paths when they are missing.

Updates

Select a tested version from GitHub Releases. Each release includes compatibility notes for mounts, environment handling, and command-line changes. Published version tags are not moved.

For a host or project flake, pin the selected tag:

inputs.aibox.url = "github:ruifm/aibox/v0.3.0";

Commit the flake lock with its exact revision and NAR hash. To update, change the tag, run nix flake update aibox, and test the locked result before deployment. Release automation can select a GitHub release and retain that same exact lock. main remains the development branch. Sandbox startup does not check for or install updates. See the 0.3.0 compatibility notes.

Quick Start

Use direnv and a Nix devShell per project. The agent can edit flake.nix, refresh the devShell, and install project-specific tools declaratively.

Example .envrc:

use flake

If flake.nix exists but .envrc does not, an interactive aibox launch offers to create the .envrc above. If neither file exists, add a minimal flake.nix devShell first. Aibox does not create a devShell for you.

Then launch the agent from the repository root:

cd my-project
aibox codex

When .envrc is present, Aibox loads it before it starts the agent. If it is not approved, Aibox shows its content and asks before it runs direnv allow. Approval persists in host direnv state: a later host shell can run the file outside Aibox. Review it and any files it loads before you approve it. With no terminal, Aibox stops and shows the manual approval command. If direnv is not installed, Aibox continues with the inherited environment and warns.

In a Git repository, Nix does not see an untracked flake.nix. Aibox asks before git add -N -- flake.nix; this records intent to add but does not stage the file content. It never runs git init, force-adds ignored files, or adds other untracked files. If Nix reports another missing project file, review that file and add it to the Git index yourself. Non-interactive launches stop when Git approval is needed. A local flake outside a Git repository needs no Git setup.

The agent inherits the loaded environment, so routine commands need no direnv exec . prefix. This also works when your host shell has already loaded direnv; aibox -p remains available inside the sandbox. If you change .envrc or the devShell during a session, the running agent's environment does not update. Use direnv exec . for the next command, or restart Aibox after any needed approval.

aibox mounts the current directory, not its parent directories. If you start it from a directory below the repository root, parent files such as .git, AGENTS.md, CLAUDE.md, and agent settings are not visible.

Read-Only Host Mode

Use --host-ro when a command needs to inspect host files or run an installed host tool that the default sandbox cannot see:

aibox --host-ro -- codex

This flag is available on main. The v0.3.0 install commands above predate it; use a checkout or a locked main revision until the next release.

This opt-in mode exposes host files, including other projects, home files, SSH keys, and credentials, read-only with your normal user permissions. The current directory, the usual persistent agent and direnv state, and explicit --rw-mount paths remain writable. Host /tmp, /var/tmp, /run, /proc, /dev, and /sys remain private. The Nix daemon and selected desktop services work as in the default mode. Aibox prints a notice before the Bubblewrap command. AIBOX_MODE=host-ro identifies the active mode inside the box; it is not proof of isolation.

This mode helps prevent direct edits and deletion outside the project. Readable credentials, host services, and the shared network can still permit changes elsewhere. A read-only mount of a Unix socket does not make service requests read-only. The mode does not expose the host D-Bus or systemd sockets. Use the separate service flags only when needed.

Package queries such as pacman -Qi and apt-cache policy can read available host metadata. Package updates and installs cannot write the host package database. journalctl can read journals under /var/log/journal and, when present, /run/log/journal, subject to normal file permissions. Live host systemctl status is unavailable because it needs access to the host service manager. Some tools will still fail if they need writes outside the selected paths or access to hidden runtime services.

Generic home cache and config paths are readable but not writable in this mode. Agent state symlinks to / or other protected paths are rejected. Start Aibox from the repository root when you need to edit project files; files above that root remain read-only. aibox --host-ro -p shows the agent prompt for this mode. Inside a running box, aibox -p shows the active mode.

Additional Mounts

Use --ro-mount PATH or --rw-mount PATH to expose an existing file, directory, or Unix socket. Each option can be repeated. Relative paths and symlinks resolve to their absolute host paths; the same resolved paths appear inside the sandbox. The default mounts remain unchanged. Missing paths and mounts that overlap existing mounts or Aibox's internal paths fail at startup. These options never create a host path.

A socket is a connection to a service. A read-only socket mount still permits service requests. Share a dedicated directory when a server needs to create a socket inside Aibox, then give clients the socket path alone:

shared=$(mktemp -d "${XDG_RUNTIME_DIR}/aibox-session.XXXXXX")
aibox --rw-mount "$shared" -- server-command "$shared/session.sock"
# In another terminal, with the same value of shared:
aibox --rw-mount "$shared/session.sock" -- client-command "$shared/session.sock"

The directory must be private to your account; mktemp -d creates it with mode 0700. A client bound to one socket must restart if the server replaces the socket. Share the dedicated directory in both processes if clients must follow socket replacement. Remove the directory after both processes stop.

Optional Podman Example

The Podman devShell example runs a limited Podman engine inside Aibox. It uses another Bubblewrap namespace to provide a private /sys/fs/cgroup path and masks host subordinate ID maps. It works in both default and --host-ro modes. It does not connect to a host container service.

For a new project, put the example flake.nix, flake.lock, .envrc, .gitignore, .containerignore, .dockerignore, aibox-podman.sh, containers.conf, and policy.json in its root. Add them to Git before using use flake, so Nix includes the source files. In a project that already has a flake or ignore files, merge the package and ignore rules instead of replacing those files. Keep the project's own pinned Nix inputs. Both container ignore files exclude .aibox-podman/ from image build contexts. Activate the devShell with direnv allow or nix develop, then run from the project root:

aibox -- aibox-podman run --rm docker.io/library/alpine:3.22 echo hello
aibox -- aibox-podman build --network=host --isolation=rootless -t localhost/demo .

The example keeps images in .aibox-podman/storage in the project and ignores that directory in Git. Live sockets and process state use Aibox's private XDG_RUNTIME_DIR and end with the box. Registry login data stored there is also temporary; use a separate, private credential path if it must persist. Do not use the image store from concurrent boxes. The example uses VFS storage, disables container cgroups, shares the host network, and maps only one user and group. An image that runs as another UID, such as 1234:1234, can fail. Cgroup resource limits and container network isolation are unavailable. The private cgroup path can cause a Podman cgroups-v1 warning; this setup is version-sensitive and is pinned by the example lock file. The example accepts unsigned images in policy.json; TLS certificate checks still apply. Edit that policy if the project needs signature rules.

The Docker CLI can use a Podman API socket created inside the box. Add pkgs.docker-client to the devShell, then start the API and set DOCKER_HOST inside the box:

aibox -- bash
aibox-podman system service --time=0 "unix://$XDG_RUNTIME_DIR/podman.sock" &
DOCKER_HOST="unix://$XDG_RUNTIME_DIR/podman.sock" docker ps

Stop the API process when done. This socket grants its clients control of the Podman engine in that box. It is not a host Docker daemon. Nested dockerd, LXD, Docker Compose, and images that need multiple user IDs are not covered by this example.

Desktop Access

On a Wayland desktop, select the host services an agent needs:

aibox --keyring --wayland --browser -- copilot

--keyring connects to the host Secret Service through a filtered D-Bus proxy. Copilot can then use a token that it stored in the host keyring. This permission also lets sandboxed programs read or change other secrets that the service allows the same account to access. Aibox does not copy or migrate tokens. If Copilot has already stored a plaintext token in ~/.copilot/config.json, that file remains until you remove it through Copilot's account controls or after you verify another login method.

--wayland exposes one host Wayland socket. Programs such as wl-copy and wl-paste can then copy or paste text and images. This socket also permits other Wayland operations; it is not a clipboard-only permission. A clipboard selection can disappear when the process that supplies it stops. This option does not support X11.

--browser makes xdg-open and BROWSER use the host OpenURI portal. Browser login can use the host's existing SSO session and a local callback because Aibox shares the host network. The proxy permits OpenURI and introspection on the portal object. It does not permit file-opening methods, and OpenURI does not accept file:// URLs. The portal reports the final result asynchronously. A successful xdg-open exit means the request was sent, not that a browser opened. Remote SSH sessions can need separate loopback forwarding. Browser profiles are not mounted.

The Nix package includes the proxy and client tools. A direct-script install needs xdg-dbus-proxy and gdbus for --keyring or --browser, and wl-clipboard for wl-copy and wl-paste. The host must have a working D-Bus session and Secret Service for --keyring, a desktop portal for --browser, and a Wayland socket for --wayland. Missing services stop startup with a named error. Without these flags, Aibox does not mount desktop sockets.

Display Name and Detection

Use aibox --hostname project-agent -- codex to set a display name. The default is aibox. Names contain 1-64 ASCII letters, digits, dots, or hyphens, with a letter or digit at each end. --hostname=project-agent also works.

Scripts can use [ "${AIBOX:-}" = 1 ] to select sandbox behavior. The marker is set inside every sandbox, including when the hostname changes. It does not prove isolation or grant authority. Replace hostname checks with this marker and remove source patches for --hostname aibox. The option changes no mounts or credential policy.

OpenRouter

Install Ori and the agent in a project devShell or Nix profile. Sign in without trying to start a host browser from the sandbox, then run the agent through Ori:

aibox ori login --no-browser
aibox ori codex

You can also set OPENROUTER_API_KEY before you start aibox. The sandbox keeps inherited environment variables.

Ori keeps shared login and settings in ~/.ori, which aibox mounts read/write. Ori also writes logs and session transcripts to .ori/ in the project. Add .ori/ to the project .gitignore because these files can contain repository content and prompts.

Agent Prompt

Before starting a session, paste the generated prompt into the agent. Inside an active agent session, aibox is available on PATH, so you can also run !aibox -p and ask the agent to follow it. The prompt names common sandbox limits and the flags or devShell steps that address them.

aibox -p

Prerequisites

To start the sandbox:

  • Linux.
  • Bash 4+.
  • Bubblewrap.
  • Unprivileged user namespaces available to Bubblewrap.
  • Core commands such as realpath, mktemp, and tee on PATH. The Nix package supplies these commands and Bubblewrap.
  • An existing $HOME with writable agent state paths, and a writable host /tmp. Start from a project directory, not / or $HOME.

For the recommended devShell workflow, install Nix with a multi-user daemon and direnv. Check nix store info on the host. Aibox can start without either tool. If the project has a Nix shell file or .envrc, Aibox warns when the needed tool is not visible inside the sandbox. A missing Nix daemon socket also gets a warning. Warnings do not stop a command that does not need these tools.

For an agent session, install the supported agent command you intend to run (codex, claude, copilot, hermes, omp, opencode, pi, or ori) somewhere the sandbox can see it: the project Nix devShell, a Nix profile, or the host system paths mounted read-only at /usr and /bin. Ori also needs the target agent command.

How It Works

In its default mode, aibox builds a Bubblewrap command that:

  • binds the current directory read/write at the same absolute path;
  • keeps host networking available;
  • allows nested user namespaces so programs can create their own sandboxes;
  • starts $HOME as a private tmpfs skeleton at the same absolute path;
  • mounts selected real agent state/config directories back into that home;
  • exposes /nix/store read-only;
  • binds the Nix daemon socket so nix develop, nix build, and direnv exec . can work;
  • mounts aibox itself read-only at /run/aibox/bin/aibox and prepends that directory to PATH;
  • leaves the inherited PATH visible, but does not discover or bind-mount arbitrary agent binaries from host-only paths such as ~/.local/bin or ~/.opencode/bin;
  • remounts the synthetic root read-only after setup;
  • prints the final bwrap command to stderr before execution.

aibox does not try to bind a single resolved agent executable into the sandbox. Many agent commands are scripts or wrappers that need interpreters, dynamic libraries, Node package trees, plugin files, or a Nix closure. Keeping agent CLIs in a project devShell or Nix profile makes the executable and its runtime closure available through the already-mounted Nix paths without adding an arbitrary host-path mount interface.

Persistent agent state/config mounts:

  • ~/.agents/skills
  • ~/.agents/plugins
  • ~/.codex
  • ~/.claude
  • ~/.claude.json
  • ~/.config/anthropic
  • ~/.copilot
  • ~/.cache/copilot
  • ~/.hermes
  • ~/.omp
  • ~/.pi
  • ~/.cache/opencode
  • ~/.config/opencode
  • ~/.local/share/opencode
  • ~/.local/state/opencode
  • ~/.ori

These writable state paths are created on the host before launch when missing. ~/.claude.json is initialized as {}. If one of the expected directories is a file, or ~/.claude.json is not a file, aibox fails before starting the sandbox.

~/.agents/skills is shared by Codex and Copilot CLI. Codex uses ~/.agents/plugins for personal plugin records. Claude Code can use Anthropic CLI profiles and credentials from ~/.config/anthropic. A selected Anthropic API profile can use API billing instead of Claude subscription billing. ~/.cache/copilot is persistent to prevent repeated downloads.

OpenCode uses ~/.config/opencode for user settings, instructions, agents, commands, skills, and plugins. It uses ~/.local/share/opencode for login, MCP, session, and log data. It uses ~/.local/state/opencode for state and ~/.cache/opencode for downloaded tools and plugin packages. Project .opencode files are available through the project mount.

Hermes keeps its config, credentials, sessions, memories, skills, plugins, and managed tools in ~/.hermes. OMP keeps its config and default state in ~/.omp. Pi keeps its config, credentials, sessions, packages, skills, and extensions in ~/.pi.

OMP can move data, state, and cache to ~/.local/share/omp, ~/.local/state/omp, and ~/.cache/omp. aibox mounts these paths when they already exist. It does not create them because OMP uses their existence to decide if XDG migration is complete. Run omp config init-xdg outside aibox if you want to migrate an existing OMP profile.

System agent config mounts are read-only and are added only when they exist:

  • /etc/codex
  • /etc/claude-code
  • /etc/github-copilot
  • /etc/hermes
  • /etc/opencode

On NixOS, the matching /etc/static subdirectories are also mounted read-only. This includes the existing Nix and certificate directories. The complete host /etc/static directory is not mounted. Links to arbitrary host targets are not followed to add mounts. Nix store contents remain readable through /nix/store.

To require system policy files before a command starts:

aibox --require-config /etc/codex/managed_config.toml \
  --require-config=/etc/codex/requirements.toml -- codex

Each path must be an absolute file path below one of the five system agent directories above, without . or .. components. The check runs inside the sandbox and stops startup if a file is missing or unreadable. The option does not add mounts or check whether the agent obeys the policy. Without the option, missing system configuration remains optional. NixOS packages can remove their source patches for /etc/static/codex.

For required configuration and certificate files, startup errors name the requirement and its path. Aibox keeps Bubblewrap's original error and adds a short hint when it detects a namespace, hostname, or mount setup failure. These hints name possible systemd restrictions; they do not identify a unit setting with certainty. Application errors keep their status and terminal stderr without a sandbox startup hint.

aibox uses the default agent state paths. It removes CODEX_HOME, CODEX_SQLITE_HOME, CLAUDE_CONFIG_DIR, ANTHROPIC_CONFIG_DIR, COPILOT_HOME, COPILOT_CACHE_HOME, HERMES_HOME, HERMES_MANAGED_DIR, PI_CONFIG_DIR, PI_CODING_AGENT_DIR, PI_CODING_AGENT_SESSION_DIR, PI_SERVER_DIR, and OPENCODE_CONFIG_DIR inside the sandbox. It does not use environment variables to add mounts. Profile variables such as ANTHROPIC_PROFILE, HERMES_PROFILE, and OMP_PROFILE still pass through.

OPENCODE_CONFIG and OPENCODE_TUI_CONFIG also pass through. The file must be in the project or another path that the sandbox can read.

Other inherited agent variables also pass through. This includes API tokens, model settings, provider settings, and profile selectors. A new variable does not need a change in aibox unless it contains a file path that must be visible inside the sandbox.

aibox does not mount GitHub CLI config, Git config, SSH or GPG agents, Docker, Kubernetes config, or browser profiles. The host D-Bus socket stays hidden even when the filtered desktop proxy is active. Inherited token environment variables remain another sign-in method. In --host-ro mode, host files such as Git and GitHub config, SSH and GPG keys, and browser profiles are readable with normal user permissions. Host agent and D-Bus sockets under the private runtime paths stay hidden unless explicitly selected.

Security Model

This is an accident-safety tool, not hostile-code containment.

The sandbox is intended to prevent routine agent/tool mistakes from writing outside the project or reading broad host state. It still gives the agent full network access, and it mounts real agent auth/session/config directories. Any readable mounted data can be exfiltrated by code running in the sandbox. --host-ro intentionally permits broad host reads, so it does not provide the default mode's read boundary. Neither mode prevents use of readable credentials or services over the network.

aibox does not clear the ordinary process environment. API keys, cloud credentials, package tokens, and other variables inherited by aibox are visible to processes inside the sandbox. The printed bwrap command also contains the command arguments you passed to aibox, so do not pass secrets as CLI arguments.

Nix builds are performed by the host Nix daemon, outside Bubblewrap. Use host Nix sandboxing if build isolation matters.

Nested sandboxes inherit Aibox's filesystem limits. They can change their own mount layout, but cannot make inherited host read-only mounts writable or remove individual inherited mounts to reveal hidden files. Allowing nested user namespaces exposes more kernel operations; Aibox does not block these as an extra hardening measure. This behavior is available on main, after v0.3.0.

This does not configure nested container runtimes or expose host container services. A host Docker, Podman, or LXD service runs outside Aibox's filesystem boundary, even if its client runs inside Aibox.

State Lifetime

Paths Access and lifetime
Workspace, including .direnv Read/write; persists on the host
Agent state/config paths listed above Read/write; persists on the host
Explicit --rw-mount and --ro-mount paths Selected host access; persists on the host
~/.local/share/direnv, ~/.cache/direnv Read/write; persists on the host
Other files below ~/.cache, ~/.config, ~/.local Private temporary storage, except listed read-only mounts
/tmp, /var/tmp, /run/aibox/runtime Private temporary storage; each new sandbox starts empty
Home skeleton outside writable mounts Read-only; not the host home contents
Nix store, system configuration, Nix profiles, direnv configuration Read-only host mounts

With --host-ro, other host files are visible read-only. The workspace, selected agent and direnv state, and explicit writable mounts still persist. Temporary paths and the private runtime directory have the same lifetime as in the default mode.

XDG_RUNTIME_DIR is /run/aibox/runtime, a separate tmpfs mount owned by the invoking user with mode 0700. The inherited runtime path is replaced. Concurrent sandboxes do not share it. Use it for sockets and active GPG state that must not survive a restart. Storage is released when the sandbox processes end.

aibox removes SSH_AUTH_SOCK, GPG_AGENT_INFO, GNUPGHOME, DBUS_SESSION_BUS_ADDRESS, DOCKER_HOST, and KUBECONFIG, plus the agent path variables listed above. It replaces HOME, the XDG base directories, and TMPDIR, and selects NIX_REMOTE=daemon when the daemon socket exists. It clears inherited direnv tracking before it loads the project environment. With --keyring or --browser, it sets DBUS_SESSION_BUS_ADDRESS to the private proxy. With --wayland, it sets the private Wayland socket name and removes inherited X11 display settings. Other variables remain visible, including credentials. No host SSH or GPG agent is forwarded automatically.

Sending SIGHUP, SIGINT, or SIGTERM to the launcher stops the sandbox. The launcher returns exit status 129, 130, or 143, respectively. Commands keep their standard input and normal interrupt handling.

Persistent agent directories can contain credentials, live databases, locks, and sockets. Do not synchronize complete live state directories without checking the application's backup requirements. Exclude sockets, locks, temporary runtime files, and credential bundles from ordinary source synchronization.

Explicit Credentials

Use a dedicated credential bundle inside the workspace when a command needs it. Create it outside the sandbox, restrict its directory to mode 0700 and private files to mode 0600, and exclude it from Git and synchronization. Do not put secret keys in Nix expressions or the Nix store.

For SSH, select the dedicated key and known-hosts file explicitly:

aibox -- ssh -F /dev/null -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes \
  -o UserKnownHostsFile="$PWD/.credentials/known_hosts" \
  -i "$PWD/.credentials/id_ed25519" operator@server.example

For GPG and a dedicated password store, set paths after sandbox entry:

aibox -- bash -c '
  export GNUPGHOME="$XDG_RUNTIME_DIR/gnupg"
  export PASSWORD_STORE_DIR="$PWD/.credentials/password-store"
  install -d -m 0700 "$GNUPGHOME"
  gpg --batch --import "$PWD/.credentials/gpg-secret.asc" || exit
  exec pass show service/account
'

Install these commands in the project devShell. An authorized self-SSH key can permit commands on the host through the shared network, outside the filesystem boundary. Credential access is an explicit operator choice, not an ordinary account default.

Systemd Services

The NixOS service example runs a project command as the dedicated aibox account. The VM test imports this same example. For a NixOS flake with an aibox input, include it in the host configuration:

imports = [
  (import "${inputs.aibox}/examples/systemd.nix" {
    aibox = inputs.aibox.packages.${pkgs.stdenv.hostPlatform.system}.default;
    workspace = "/srv/project";
    command = [ "${pkgs.nix}/bin/nix" "develop" "--command" "project-task" ];
    hostname = "project-agent";
    requiredConfig = [
      "/etc/codex/managed_config.toml"
      "/etc/codex/requirements.toml"
    ];
  })
];

Provision the checkout and its devShell outside the sandbox. The aibox account must own the workspace. Enable Nix flakes for this command, and provision the required policy files through environment.etc. Omit requiredConfig for a command that does not need these files. Start or inspect the service with systemctl start aibox and journalctl -u aibox, outside the sandbox. If a service workspace has .envrc, approve it as the service account before starting the service; a non-interactive launch cannot answer Aibox prompts.

The service supplies explicit command paths and a clean environment, including both certificate variables. Persistent agent state lives in /var/lib/aibox, with mode 0700. ProtectSystem=strict restricts persistent filesystem writes, with writable exceptions for the workspace and the systemd state directory. PrivateTmp supplies separate temporary directories. Bubblewrap limits access within those paths to its normal mount policy. The complete host state directory is not bound into the sandbox.

The tested service uses ProtectHostname=private, ProtectKernelLogs=no, and ProtectKernelTunables=no. It retains ProtectKernelModules=yes, PrivateTmp=yes, ProtectClock=yes, ProtectControlGroups=yes, and ProtectProc=invisible. These settings were tested together with the locked nixpkgs. The service manages process lifetime; aibox does not manage sessions.

Troubleshooting

Service Restrictions

Bubblewrap prints its original startup error. Check the unit's journal and restrictions before changing host-wide settings:

Error Check
Can't set hostname ProtectHostname=yes prohibits the syscall; the example uses private
Can't mount proc ProtectKernelLogs and ProtectKernelTunables each caused this failure in the VM test
No permissions to create a new namespace Check RestrictNamespaces, syscall filters, and host user-namespace restrictions
Mount permission error A filter such as SystemCallFilter=~@mount prevents Bubblewrap setup
Writable state creation fails Check ownership, StateDirectory, ReadWritePaths, and any ProtectHome setting

The same EPERM can have several causes. These messages do not identify one specific unit setting on every host. A syscall filter can also terminate the process with SIGSYS before Bubblewrap can print an error. Do not remove the whole service restriction set to repair a single conflict. See the systemd execution reference for the scope of each setting.

Certificate Bundles

aibox preserves SSL_CERT_FILE and NIX_SSL_CERT_FILE. When either is set, it must name a readable regular file inside the sandbox. An empty value is an error. Relative paths refer to the workspace. The variables can name different files. Unset variables leave the client's default certificate selection intact.

For NixOS or a service with a minimal environment, set both variables to the Nix store bundle:

SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
NIX_SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";

The check runs before the command starts and names an invalid variable without printing its value. It adds no mounts and does not parse certificates or prove that a TLS connection will succeed. TLS verification remains the client's job. Other client-specific certificate variables are inherited without this check.

Ubuntu AppArmor User Namespaces

On Ubuntu 24.04+, AppArmor may restrict unprivileged user namespaces. If aibox -- true fails with a Bubblewrap namespace permission error, add a targeted profile for Bubblewrap instead of disabling the restriction globally:

cat <<'EOF' | sudo tee /etc/apparmor.d/local-aibox-bwrap >/dev/null
abi <abi/4.0>,
include <tunables/global>

profile local-aibox-bwrap /usr/bin/bwrap flags=(unconfined) {
  userns,

  include if exists <local/aibox-bwrap>
}

profile local-aibox-bwrap-nix /nix/store/*-bubblewrap-*/bin/bwrap flags=(unconfined) {
  userns,

  include if exists <local/aibox-bwrap-nix>
}
EOF

sudo apparmor_parser -r /etc/apparmor.d/local-aibox-bwrap
aibox -- true

If bwrap is installed somewhere else, add another profile stanza for the absolute path printed by readlink -f "$(command -v bwrap)".

Contributing

Development setup and test commands live in CONTRIBUTING.md.

License

MIT

About

bubblewrap + nix devShell AI sandbox

Topics

Resources

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Contributors

Languages