A useful layer, with known edges
ai-jail keeps an AI coding agent away from your keys, your home directory and the rest of your machine. It is a process sandbox, so it shares your kernel. It does not replace a disposable virtual machine when the code is hostile.
What it is built to stop
An agent can be talked into bad behavior by a web page, a package or a file in the repository. These are the things it then reaches for, and does not find.

Out of reach
- Your home directory and the credentials in it. The agent gets a fresh, empty home, so
~/.sshand~/.awsdo not exist in there. - Secrets in your shell. Environment variables are cut down to a small allowlist, so exported tokens stay outside.
- The network. It is off, so nothing the agent reads can be sent anywhere.
- Host shared memory, your display server and your clipboard. Agent output passes through a filter that drops terminal clipboard and query sequences.
- Typing into your terminal. Linux blocks the
TIOCSTIcall that fakes keystrokes, and macOS limits terminal control to the one terminal ai-jail created for the run. - Its own rules. A
.ai-jailfile inside a repository is untrusted: it can tighten the sandbox and never open it.
Where the wall ends
The jail and your system stand on the same kernel. A bug in that kernel, in a driver or in the sandbox backend is a way around the wall, and ai-jail cannot do anything about it. A virtual machine brings its own kernel, which is why it is the stronger boundary.

What stays at risk
- Kernel and driver vulnerabilities. Every sandboxed process talks to the same kernel as the rest of your machine.
- Bugs in your terminal emulator, above all with
--terminal-passthrough, which turns the output filter off. - Defects in the sandbox backend itself: bubblewrap, Landlock and seccomp on Linux,
sandbox-execon macOS. - Secrets inside the project. A
.envfile in the repository is readable unless you mask it. See how to mask files. - Masks cover only paths that exist when the sandbox starts. A secret file created later, during the session, is not hidden.
- Side channels and some classes of inter-process communication.
- On macOS,
sandbox-execis deprecated by Apple and is not equivalent to the Linux isolation. See the macOS differences.
Switches that open the wall
Everything below is off until you turn it on, and each one gives the agent real access. How to set them is on the Configure page.
| Switch | What anything in the sandbox can then do |
|---|---|
--network | Send anywhere everything it can read. Traffic is unrestricted and there is no per-domain filter. |
--docker | Act as root on your machine through the Docker daemon. |
--x11 | Log keystrokes and take screenshots of other X11 windows. |
--systemd-user | Ask your systemd user manager to run services on the host. |
--inherit-env | Read your whole shell environment, secrets included. |
--agent-state | Use the agent's saved login, for example Claude's ~/.claude. |
--audio | Record and play audio while it is on. |
--no-private-home | See your real home directory. This is a broad exception; prefer a map of the one path you need. |
When in doubt, it refuses to start
A sandbox that silently starts weaker than you asked is worse than one that stops with an error. In these cases ai-jail stops.
- A config file that exists and is invalid or unreadable.
- A project
.ai-jailthat is a symlink. A symlinked global~/.ai-jailis followed only to a regular file you own, that no one else can write, outside the project. --lockdownwhen Landlock, the kernel's own filesystem rules, is missing, partial or fails to apply.--lockdown --no-landlockis rejected too.--allow-tcp-port. That interface cannot constrain UDP, so the flag is accepted for compatibility and the launch fails.- A
BWRAP_BINthat points at a bubblewrap binary someone other than root could have replaced. It is ignored with a warning, and with no trusted bubblewrap the launch fails.
How the project is checked
One maintainer runs the project in the open. Below is what gets checked and what does not.
- 19
- sandbox-escape integration tests that try to write to
/usr, read~/.ssh, callptraceandbpf, and expect to fail - 720
- unit tests in the source tree at version 1.22.0
- 0
- network requests at launch. The update check is opt-in with
--update-check
How a release is made
- Release tags are signed, and CI verifies each one against a key fingerprint pinned in the repository.
- Every GitHub Action is pinned to a commit SHA, and actions are restricted to an allowlist.
- Builds use a pinned Rust toolchain and
--lockeddependencies. - macOS binaries are signed and notarized by Apple.
- Each archive ships with a SHA-256 checksum, and the publish job checks them again.
What the release document says is still missing
- Signing and publishing secrets are still stored at repository level and should move into the release environments.
- No ruleset yet forces every
v*tag to be signed. - Immutable releases are not enabled.
- crates.io publishing still uses a token. Trusted publishing is planned.
- With a single maintainer there is no second reviewer on changes or releases.
Report a vulnerability
Do not open a public issue. Use GitHub's private vulnerability reporting, include the steps to reproduce and the affected versions, and allow time to coordinate a fix.
Common questions
Can the agent break out?
Is it safe to run with the network on?
Has it been audited?
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.
brew tap akitaonrails/tap && brew install ai-jailai-jail claude