
AI Jail in practice — the sandbox that learned with us
The first time the sandbox saved us
The previous post told how ai-jail entered Hermes — the Rust sandbox that isolates every terminal execution with bubblewrap, Landlock and Seccomp. That was the story of the installation.
This is the story of the usage. Because installing a sandbox is easy; living with it is another thing.
The first time it truly saved me was on a pip install of an unknown package. Before the jail, that command would have access to everything: .env, Stripe keys, database credentials. Inside the jail, sensitive paths are masked — the process doesn’t even see they exist.
The feeling is strange at first: you realize every Hermes execution could leak your life — and that there’s now a safety net.
The context: from installing to coexisting
The initial config (~/.ai-jail) defines the rules:
| Category | What it does |
|---|---|
| Mask (empty) | .env, credentials.json, secrets.yml, *token*.json, *.pem, id_ed25519*, id_rsa* |
| Deny (error) | secrets/, *.key, .gnupg/ |
| GPU | Active (Ollama needs it) |
| Docker | Active |
| Worker mode | GPU/Docker/Display off |
Real usage revealed 3 lessons the docs don’t tell you:
Lesson 1: Landlock is expensive — so we turned it off
First benchmark: with Landlock active, the jail took 5.2s; without it, 3.8s. Almost 40% slower on quick operations.
On WSL (where Hermes runs), the modern kernel supports Landlock — but the latency wasn’t worth it for trivial commands like python3 script.py. The pragmatic decision: no_landlock = true by default on WSL, keeping bubblewrap + Seccomp as the safety net.
# ~/.ai-jail — pragmatic decision
no_landlock = true # 5.2s → 3.8s on WSL
The lesson: security is a trade-off. A sandbox nobody uses because of latency protects less than a fast one that becomes routine.
Lesson 2: every command has its own needs
At first, jail npm install failed because npm couldn’t find its cache. The solution: command-specific mounts:
| Command | Extra RW mounts |
|---|---|
python |
~/.cache/huggingface, ~/.cache/torch |
npm |
~/.npm, ~/.cache/pnpm |
pip |
~/.cache/pip |
uv |
~/.cache/uv |
cargo |
~/.cargo/registry, ~/.cargo/git |
Each one mounts only what it needs — least privilege applied to caches. The process runs isolated, but with access to what legitimately belongs to it.
Lesson 3: worker mode is Hermes’ default mode
When Hermes spawns a worker (delegate_task / Kanban), it automatically detects HERMES_KANBAN_TASK and enters worker mode: GPU, Docker and Display off.
Why? Because a disposable worker doesn’t need GPU (Ollama), Docker or display — and each one is one less attack surface.
jail --worker python3 analyze.py # no GPU, no Docker, no display
The practical result: every command Hermes runs in production is isolated — normal for common tasks, lockdown for critical operations (deploy, DB restore), worker for disposable processes.
The Arachne integration
Arachne took the concept further: app/sandbox.py uses ai-jail as a backend to isolate:
- Browser (Playwright) — Chrome with OS sandbox (no
--no-sandbox) - Pipeline
eval()(math,jsonata) — execution in an isolated subprocess (anti-RCE) - Custom Python (
codestage) —sandboxed_handler()writes handler + input into a tempdir and runs inside the jail
# app/sandbox.py — the essence
def run_sandboxed(cmd, ro_maps=[], rw_maps=[], no_net=False, timeout=60):
# mounts paths, runs inside the jail, returns stdout/stderr
And the MCP tool arachne_sandbox_status shows active protections in real time — transparency about what’s protected.
Real usage metrics
| Item | Value |
|---|---|
| Landlock active | (5.2s vs 3.8s — off on WSL) |
| Commands with custom mounts | 5 (python, npm, pip, uv, cargo) |
| Execution modes | 3 (normal, lockdown, worker) |
| Worker mode | Auto via HERMES_KANBAN_TASK |
| Arachne sandboxable | Browser + eval + code stage |
Lessons learned
- Security is a trade-off — slow sandbox = nobody uses it; fast = becomes routine
- Least privilege applied to caches — each command mounts only what it needs
- Worker mode is default — GPU/Docker/Display off by default for disposable processes
- Transparency —
arachne_sandbox_statusshows what’s protected - Daily usage is the real test — docs teach you to install; usage teaches you to live
The sandbox isn’t a feature you install and forget. It’s a discipline you live — and the more you use it, the more you realize what it’s protecting.