Observed since 20 Oct, 22:45 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
A lightweight bwrap sandbox for AI agents
A lightweight sandbox for AI agents using bubblewrap (bwrap) to isolate the agent from the host system.
Lightweight. Fast. No special privileges. Easy to install.
A simple sandbox for AI agents, built on top of bubblewrap — the low-level sandboxing tool at the core of Flatpak.
Unlike full container systems (podman, docker, apptainer), this is:
This project has similarities and shares many goal with the following projects, which you can consider as alternative is you wish:
While the main driver for writing this project is the sandboxing / isolation of AI agents, it can be used to sandobox pretty much anything.
AI Agents usually run with the same UID / GID as your daily user. This means that discretionary access control (DAC) has no way to distinguish it from the human behind the screen. You might not want to share all of your data with the AI Agent, or let it change files in your home directory. As we all know sometimes AI makes mistakes, like in this case, which happened during the development of this very project:
the agent tried to rm -rf ~/.config that would have wiped a lot of important files in my personal home directory. Luckily opencode stopped the execution and asked as it detected this was not within the project directory. However, there are easy bypass for the AI agent, and I might not be so lucky next time. However, I still want to share data with the agent, for example the git repo itself so it can help me coding. This tool is meant to give you the possibility of decide how to isolate the agent and what to share with it. You can even force it to be unable to use the network, if you like. However, I would discourage considering this tool a bulletproof security tool. The main objective is to control what the AI agent can do / access, but it assume the agent itself is trust-able software, that might make, unintentional, mistakes.
This is a project I do during my spare time. It may contain errors or security bugs, so use it at your own risk and don't run untrusted / malicious code within the sandbox. It might find a way out and eat your hamster.
This project is being developed with the assistance of AI open weight models and a lot of free and open software. With all of the following (plus more) this would not have been possible. A big thank you to everybody!
git clone https://github.com/enricotagliavini/agent-nook
cd agent-nook
pip install -e .
agent-nook run --command "echo hello from sandbox"
| Concern | Choice | Why |
|---|---|---|
| Sandboxing | Bubblewrap | Low-level, no root, no daemon, Flatpak-proven |
| Images | Optional | Keep it simple; the sandbox can use host filesystem, or, if desired, also a custom image |
| Runtime | None | bwrap has no background service |
| Config format | YAML | Human-readable, standard for config files |
| Logging | logging module + XDG | Standard library, no dependencies |
| Language | Python 3.10+ | Type hints, dataclasses, modern features |
Agent → bwrap sandbox → isolated filesystem + capabilities → agent runs safely
Bubblewrap applies filesystem isolation, network isolation, and capability restrictions in userspace — no kernel namespaces or privileged containers needed.
Bubblewrap creates a userspace sandbox by:
--new-session) to prevent TIOCSTI attacks--die-with-parent)Seven mount types are supported:
| Type | Syntax | Description |
|---|---|---|
bind | --bind SRC DEST | Read-write bind mount |
ro-bind | --ro-bind SRC DEST | Read-only bind mount |
dev-bind | --dev-bind SRC DEST | Device bind mount |
tmpfs | --tmpfs TARGET [SIZE] | Temporary filesystem in memory |
proc | --proc TARGET | Proc filesystem |
dev | --dev TARGET | Dev filesystem |
dir | --dir TARGET | Directory without content check |
Six namespace types can be unshared (isolated):
| Namespace | Flag | Description |
|---|---|---|
| PID | --unshare-pid | Isolate process tree |
| UTS | --unshare-uts | Isolate hostname/domainname |
| IPC | --unshare-ipc | Isolate inter-process communication |
| cgroup | --unshare-cgroup | Isolate cgroup hierarchy |
| user | --unshare-user | Isolate user IDs |
| network | --unshare-net | Isolate network stack (also implies UTS and IPC) |
Note: Specifying --unshare-net automatically enables --unshare-uts and --unshare-ipc.
bwrap \
--die-with-parent \
--new-session \
--bind /host/data /sandbox/data \
--ro-bind /host/config /sandbox/config \
--cap-drop ALL --cap-add CAP_CHOWN CAP_DAC_OVERRIDE \
--unshare-pid --unshare-uts --unshare-ipc --unshare-cgroup --unshare-user --unshare-net \
--chdir /sandbox \
python3 agent.py
Mounts are applied in topological order (parents before children). For example:
mounts:
- target: /home
type: tmpfs
- source: /home/user/project
target: /home/project
type: bind
The sandbox will correctly mount /home first, then /home/project as a subdirectory, irrespective of the order in which they are specified in the configuration file.
It is recommended to use the bubblewrap version that comes from the OS. If you OS supports flatpak bubblewrap should be already installed. If there is bubblewrap available, install adding the optional [bubblewrap] dependencies to pull a binary build from PyPi.
git clone https://github.com/enricotagliavini/agent-nook
cd agent-nook
pip install -e ".[dev]" # with dev dependencies
pip install -e ".[bubblewrap]" # with bubblewrap dependency in case it's not already installed and available by the OS
pip install agent-nook
agent-nook run --command "echo hello"
pipx install agent-nook
agent-nook run --command "echo hello"
| Command | Description |
|---|---|
run | Run a command in a sandbox |
status | Show agent-nook status |
logs | Show recent logs (live follow with -f) |
list | List available sandboxes |
# Basic usage
agent-nook run python3 my_script.py
# With a Python inline script
agent-nook run python3 -c "print('hello')"
# With bind mounts
agent-nook run --bind /host/data:/sandbox/data python3 script.py
# Read-only bind mount
agent-nook run --ro-bind /host/config:/sandbox/config python3 script.py
# Custom config file
agent-nook run --config /path/to/config.yaml python3 script.py
# Override capabilities
agent-nook run --cap-add NET_BIND_SERVICE --cap-add SYS_PTRACE python3 net_script.py
# Drop capabilities
agent-nook run --cap-drop SYS_ADMIN --cap-drop SYS_PTRACE python3 safe_script.py
# Unshare namespaces (space-separated)
agent-nook run --unshare pid uts ipc python3 script.py
# Environment variables
agent-nook run --env PATH=/usr/bin --env HOME=/root python3 script.py
# Unset environment variables
agent-nook run --unset-env PATH --unset-env HOME python3 script.py
# Custom hostname
agent-nook run --hostname my-agent python3 script.py
# Work in specific directory
agent-nook run --chdir /home/enrico python3 my_script.py
# Work directory from config
agent-nook run python3 my_script.py
# Quiet mode (suppress non-error output)
agent-nook run --quiet python3 my_script.py
# Show the last 50 lines
agent-nook logs
# Show the last 100 lines
agent-nook logs -n 100
# Follow the log live (like `tail -F`); stop with Ctrl+C
agent-nook logs -f
# Follow, starting from the last 100 lines (`-F` / `--follow` work too)
agent-nook logs -F -n 100
| Flag | Description |
|---|---|
CMD [ARGS...] | Command to execute in the sandbox (e.g. python3 agent.py) |
--config CONFIG | Override config file path (default: ~/.config/agent-nook/sandbox.yaml) |
--chdir DIR | Change working directory in sandbox (overrides config) |
--cap-add CAP | Add capability (e.g. CAP_NET_BIND_SERVICE, repeat for multiple) |
--cap-drop CAP | Drop capability (e.g. CAP_SYS_ADMIN, repeat for multiple) |
--unshare NS | Unshare namespace (e.g. pid uts ipc, repeat for multiple) |
--bind SRC:DEST | Bind mount host SRC to sandbox DEST (repeat for multiple) |
--ro-bind SRC:DEST | Read-only bind mount host SRC to sandbox DEST (repeat for multiple) |
--env KEY=VALUE | Set environment variable (repeat for multiple) |
--unset-env KEY | Unset environment variable (repeat for multiple) |
--hostname HOSTNAME | Set sandbox hostname |
--new-session | Create new session (prevents TIOCSTI attacks, default: on) |
--no-new-session | Don't create new session (allows TIOCSTI) |
--quiet | Suppress non-error output |
--die-with-parent | Kill sandbox child when parent dies (default: on) |
--no-die-with-parent | Keep sandbox alive after parent exits |
Configuration follows XDG Base Directory Specification.
~/.config/agent-nook/sandbox.yaml — Main sandbox configuration~/.config/agent-nook/logging.yaml — Logger configuration~/.local/state/agent-nook/ — Log files; lines are tagged with the active sandbox name (e.g., agent_nook[mybox])To create or edit the configuration, edit ~/.config/agent-nook/sandbox.yaml directly.
The config uses YAML format with these top-level keys:
name: agent-sandbox
chdir: /home/enrico
mounts:
- source: /home/enrico/project
target: /workspace
type: bind
capabilities:
drop: ["ALL"]
keep: ["CAP_CHOWN", "CAP_DAC_OVERRIDE"]
unshare:
pid: true
ipc: true
uts: false
user: true
You can override any config option at runtime via CLI flags:
agent-nook run --chdir /tmp --cap-add NET_BIND_SERVICE python3 agent.py
See sandbox.yaml
Edit ~/.config/agent-nook/sandbox.yaml to customize:
name: Sandbox identifier (used in logs)chdir: Working directory inside the sandboxmounts: Mounts from host to sandbox. At least one mount is required — a config with no mounts is rejected, because the sandbox root would be completely empty (you can also add one at runtime via --bind). See below for supported types.capabilities: Linux capabilities to drop (drop: ["ALL"]) or keep (keep: ["CAP_CHOWN"])unshare: Which namespaces to unshare (isolate) — pid, uts, ipc, cgroup, user, networkhostname: Sandbox hostname (implies UTS namespace unshare)die_with_parent: Kill sandbox children when parent exits (default: true)new_session: Create a new session (prevents TIOCSTI attacks, default: true)timeout: Maximum execution time in seconds (null = no timeout)env_vars: Environment variables to set (YAML map: KEY: value)unset_vars: Environment variables to unset (YAML array: ["PATH", "HOME"])Seven mount types are supported:
# Read-write bind mount
mounts:
- source: /host/path
target: /sandbox/path
type: bind
# Read-only bind mount
- source: /host/config
target: /sandbox/config
type: ro-bind
# Device bind mount
- source: /dev/sda
target: /sandbox/dev
type: dev-bind
# Temporary filesystem (in memory)
- target: /tmp
type: tmpfs
# with optional size
- target: /sandbox/cache
type: tmpfs
size: "100M"
# Proc filesystem
- target: /sandbox/proc
type: proc
# Dev filesystem
- target: /sandbox/dev
type: dev
# Directory without content check
- target: /sandbox/workspace
type: dir
CLI equivalents:
--bind SRC:DEST → type: bind--ro-bind SRC:DEST → type: ro-bind--dev-bind SRC:DEST → type: dev-bind--tmpfs TARGET [SIZE] → type: tmpfs with optional size--proc TARGET → type: proc--dev TARGET → type: dev--dir TARGET → type: dirSix namespaces can be unshared (isolated):
unshare:
pid: true # Isolate process tree
uts: true # Isolate hostname/domainname
ipc: true # Isolate inter-process communication
cgroup: true # Isolate cgroup hierarchy
user: true # Isolate user IDs
network: true # Isolate network stack (implies UTS and IPC)
CLI equivalents:
--unshare-pid--unshare-uts--unshare-ipc--unshare-cgroup--unshare-user--unshare-net (also enables --unshare-uts and --unshare-ipc)# Allow the agent to read from host directories but restrict system access
agent-nook run \
--bind /home/enrico/data:/data \
--ro-bind /var/lib/docker:/docker-data \
--env DOCKER_DATA=/docker-data \
--env HOME=/data/home \
python3 my_agent.py
agent-nook run --cap-drop ALL --chdir /workspace python3 agent.py
agent-nook run \
--cap-drop ALL \
--unshare pid,ipc,uts,user \
--chdir /sandbox \
--env HOME=/sandbox/home \
--env PATH=/usr/bin:/bin \
python3 safe_agent.py
SYS_ADMIN, SYS_PTRACE).--unshare-pid, --unshare-uts, --unshare-ipc, --unshare-cgroup, --unshare-user, --unshare-net and --die-with-parent.Bubblewrap is the same technology behind Flatpak. It's a single binary that applies sandbox rules without requiring a container runtime. It's available out of the box on any distribution supporting Flatpak packages.
dnf install bubblewrap, apt install bubblewrap, pip install bubblewrap-bin or download from the bubblewrap github releases)git clone https://github.com/enricotagliavini/agent-nook
cd agent-nook
pip install -e ".[dev]"
# Run tests
./run_tests.sh
# Lint and format (run with --check to verify without fixing, as CI does)
./run_lint.sh
A GitHub Actions workflow (.github/workflows/tests.yml) runs on every push and pull request:
test — full test suite (./run_tests.sh) across a Python 3.10–3.14 matrix on ubuntu-latest runners. Integration tests launch real sandboxes, so the job installs bubblewrap and lifts Ubuntu 24.04's default AppArmor restriction on unprivileged user namespaces (kernel.apparmor_restrict_unprivileged_userns=0).lint — ./run_lint.sh --check (ruff lint + format verification).GPLv3 — see LICENSE for details.
Contributions are welcome! Feel free to open an issue or a pull request.
Download counts and popularity will appear here as the collector receives them.
| Version | Published | Direct dependencies | Open version |
|---|---|---|---|
| 0.1.2 | 22 Sept 2026 | 6 |
This describes our collected data; it is not a security assessment.
Observed since 20 Oct, 22:45 UTC
No superseded metadata states collected. Unchanged observations do not create new revisions.
package:b4d86e71163ec58986cd3f9a4b572f3a99482a570403e23938f29c9dbd25d2b5