Skip to content
Menu
Do I need it?What an agent can reach on your machineHow it worksThe layers between the agent and your systemCompareBuilt-in sandboxes, Docker and VMsConfigureOpen only what a task needsSecurityThe threat model and its limitsDownloadBinaries, checksums and release notesInstall
Install

Install it, look inside, run your agent

ai-jail is one program with no daemon and no root. You install it, put its name in front of the command you already type, and the agent starts inside a sandbox.

For the person at the keyboard.

Install

Choose the way you already install command line tools. Every method gives you the same single ai-jail program.

terminal
brew tap akitaonrails/tap && brew install ai-jail

Works on macOS and on Linux.

What your system needs

Linux

Install bubblewrap, the small program ai-jail uses to build the sandbox. Most distributions package it as bubblewrap.

terminal
pacman -S bubblewrapapt install bubblewrapdnf install bubblewrap

macOS

Nothing to install. ai-jail uses sandbox-exec, which ships with macOS. Apple marks that interface as deprecated. Package registries are not reachable by default on macOS: add one with --allow-host, or open the network with --network.

Windows

Not supported. Use WSL2 and follow the Linux steps inside it.

Your first run

Three commands: a plan, a look inside, a working agent. The login is already inside, and ai-jail opens the route to the agent's API host for you.

↔ Swipe sideways to see the full diagram

Your home directory stays outside at every step, and the agent's login is inside from the start. In the last step ai-jail opens the agent's own API host; on Linux, toolchains can also reach their package registries. Everything else stays shut.
  1. See the plan without running anything

    Go to your project and ask for a dry run. ai-jail prints the sandbox command it would use and exits. A dry run never writes a file.

    dry run
    cd ~/Projects/my-appai-jail --dry-run claude
  2. Look around inside

    Start a plain shell in the jail. Your project is there at its real path and you can edit it. Your home directory is a fresh one, and your shell's tokens are gone. Type exit to leave.

    a shell in the jail
    ai-jail bash
  3. Run the agent

    ai-jail mounts the agent's own state folder by default, so it is already signed in. When it knows the agent, it also lets the agent's own API host through its filtered proxy: api.anthropic.com for Claude Code, api.openai.com and chatgpt.com for Codex, generativelanguage.googleapis.com for Gemini, api.x.ai for Grok, server.codeium.com for Devin, on Linux and on macOS. Telemetry hosts stay shut. On Linux, toolchains reach package registries such as crates.io, npm and PyPI by default, so builds work. --network opens the whole network instead.

    the real run
    ai-jail claude# or, with the whole network open:ai-jail --network claude
  4. When you need more

    Put a host list in ~/.ai-jail, your own config file, under the agent's name. The list adds to the agent's own API host, which stays allowed, and on Linux github.com and the package registries are already in. Or use --network for the whole network. For a logged-out run, pass --no-agent-state. A .ai-jail file inside the project can only tighten the jail: it can shrink the host list or the forward_ports list and turn the login off, never the opposite, so a repository you clone cannot open the jail for itself.

    ~/.ai-jail
    [commands.claude]allow_hosts = ["api.example.com"]# added to the API host and the registries ai-jail already allows # or, for one run:# ai-jail --network claude

What you will see inside

The prompt changes to (jail) and the project is where it always was. Your toolchains are there too, read only. The things worth stealing are missing, except the agent's own login, which is there on purpose.

ai-jail bash, on Linux
$ ai-jail bash# the project is at its real path(jail) ~/Projects/my-app $ pwd/home/you/Projects/my-app# a token exported in your shell did not come along(jail) ~/Projects/my-app $ echo $GITHUB_TOKEN # your keys are not in this home(jail) ~/Projects/my-app $ cat ~/.ssh/id_ed25519cat: /home/you/.ssh/id_ed25519: No such file or directory# the jail has its own hostname(jail) ~/Projects/my-app $ hostnameai-sandbox

This is a Linux session. macOS has no way to build a separate file tree, so there the same paths exist and reading them is refused.

↔ Swipe sideways to see the full diagram

From inside, the project is the only thing of yours that you can change. Your toolchains (mise, cargo, npm and others) are there, read only, with a dependency cache the jail owns. The network stays outside, apart from a known agent's own API host and, on Linux, the package registries those toolchains fetch from, until you open a host with --allow-host, one local port with --forward-port, or all of it with --network. How toolchains are mapped.

When the jail blocks something

Everything the agent starts runs inside with it, so a blocked thing fails, and nothing asks you. This is what that looks like, and how to see it.

  • A file outside the project is not there. On Linux the path does not exist, on macOS it exists and reading it is refused.
  • A host outside the list cannot be reached: the connection fails. --allow-host HOST adds it for the next run.
  • A variable from your shell is empty inside, unless you pass it with --env NAME or --env-from-file.
  • To see what was refused, add --audit-log: it records each launch and every connection the proxy allowed or denied. ai-jail --audit-show prints it.
  • To look around yourself, ai-jail bash opens a shell inside the same jail.

What you will open on day one

Installs

Work on Linux as they are: the registries and github.com are in the default list. On macOS add one, --allow-host registry.npmjs.org, or open everything with --network.

Local services

A database, a local MCP server or an editor socket on your machine's loopback: --forward-port 5432 relays that one port on Linux. On macOS, --network.

Git push

Clone and pull from GitHub work on Linux. A push needs a credential: --github for your gh token over HTTPS (on macOS add --allow-host github.com), or --network --ssh for your SSH key.

MCP servers

They start inside the jail with the agent. One that reads a token from your shell gets nothing until you pass it, --env GITHUB_TOKEN or --env-from-file. A remote one over HTTP needs its host in --allow-host.

If it does not start

These are the cases the README's troubleshooting covers, plus the two setup rules people trip on.

bwrap: setting up uid map: Permission denied

Ubuntu 24.04 and later and Debian 13 and later ship an AppArmor policy that stops programs from creating user namespaces without root, which is how bubblewrap isolates the jail. It affects every rootless tool of this kind. Relax it for the whole system:

terminal
echo 'kernel.apparmor_restrict_unprivileged_userns=0' \  | sudo tee /etc/sysctl.d/60-userns.confsudo sysctl --system

Or keep the policy and exempt only bwrap. Save this as /etc/apparmor.d/bwrap, then run sudo apparmor_parser -r /etc/apparmor.d/bwrap.

/etc/apparmor.d/bwrap
abi <abi/4.0>,include <tunables/global>profile bwrap /usr/bin/bwrap flags=(unconfined) {  userns,}

Your BWRAP_BIN is refused

You can point ai-jail at a specific bubblewrap with BWRAP_BIN. ai-jail accepts it only when it resolves to a program owned by root that other users cannot write, or to one in a standard multi-user /nix/store. It refuses a copy in your own home, because anyone who can replace that file controls the jail.

opencode hangs at Starting background server

opencode 2.x talks to a shared background server. The jail is a one-shot wrapper with a fresh home, so that server does not survive between runs. Start opencode self-contained with --standalone, and pin it in your config so you do not type it each time. ai-jail warns at launch when opencode starts without it:

~/.ai-jail
[commands.opencode]command = ["opencode", "--standalone"]

Failed to create stream fd at startup

This comes from a login script on Ubuntu desktop during mise setup. It is harmless and mise still works. Pass --no-mise to skip mise setup and the message with it.

terminal
ai-jail --no-mise claude

Per agent

ai-jail knows where each agent keeps its login and mounts it by default: only the folders of the agent you start, and only if they exist. --no-agent-state turns it off. When set in your shell, that agent's API key variable comes along too: ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY or GOOGLE_API_KEY, XAI_API_KEY, MOONSHOT_API_KEY.

Show the per-agent table
You runMounted by defaultGood to know
ai-jail claude~/.claude
~/.claude.json
For a second Claude profile, point --claude-dir at its directory.
ai-jail codex~/.codexAfter you resize the window, ai-jail sends Codex a redraw key so the screen repaints. On macOS, non-lockdown Codex gets a private ps shim; with agent state on, it also gets the scoped system services its app server needs. --no-agent-state removes those service grants, not the shim.
ai-jail gemini~/.gemini
ai-jail opencode~/.config/opencode
~/.local/share/opencode
Needs --standalone. See the troubleshooting item above.
ai-jail antigravity~/.geminiShares its Google login with Gemini, so one sign in serves both.
ai-jail kimi~/.kimi~/.kimi-code, the older location, is mounted too when it exists.
ai-jail kiro-cli~/.kiro
~/.local/share/kiro-cli
On macOS the second folder is ~/Library/Application Support/kiro-cli instead.
ai-jail prime-agent~/.prime/agentOnly the agent's own folder, never the whole ~/.prime.
ai-jail devin~/.local/share/devin
~/.config/devin
The CLI's own installation under devin/cli/_versions stays read only. Update Devin on the host, then start a new session.
ai-jail ai-memory run claudeThe launched agent's foldersai-jail recognizes the agent that ai-memory launches and applies that agent's settings, with both programs in one jail.

The same works for crush, grok, jcode, pi, aider, soulforge and omp. Any other command runs too, with the same jail and no login folder. ai-jail opens the API host by default for the five agents in step 03; other agents need --allow-host or --network.

Put your agent behind bars

ai-jail is a single binary that needs no daemon and no root. You add one word in front of the command you already run.

terminal
brew tap akitaonrails/tap && brew install ai-jailai-jail claude