- Shell 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
- Translate entire README from German to English - Expand Portability section to mention Linux support (Landlock) - Mention Seatbelt as macOS's sandboxing mechanism |
||
| .gitignore | ||
| nonoblock | ||
| nonoblock_permissions | ||
| README.md | ||
| setup.sh | ||
nonoblock
Runs AI agents (claude, aider, opencode, cline) inside the
nono sandbox.
nonoblock claude
nonoblock aider -m gpt-4o
nonoblock opencode
nonoblock cline
nonoblock extends nono's built-in claude-code profile (which already
contains deny-rules for credentials, browser data, keychains, and shell
history) with additional grants for the tools we actually use. The goal
is "allow most things, block the dangerous ones" – not full
isolation.
On Linux, nono sandboxes via Landlock; on macOS via Seatbelt.
The script only builds the nono wrap argument list, so it covers both
platforms with a single script.
Prerequisites
| Dependency | Required for |
|---|---|
| nono (≥ 0.41) | Sandbox execution |
| jq | Only for cmd-default / cmd-allow / cmd-deny lines |
| bash | Runs on macOS's stock /bin/bash (3.2) |
Installation
Quick start (recommended)
./setup.sh
Installs nonoblock to ~/.local/bin/nonoblock, creates the shared
permissions file, and installs missing agent binaries (sandboxed via
nono).
Manual
install -m755 nonoblock ~/.local/bin/nonoblock
Make sure ~/.local/bin is on your $PATH:
# ~/.zshrc or ~/.bashrc
export PATH="$HOME/.local/bin:$PATH"
Permissions file
nonoblock expects one shared permissions file for all agents (no per-agent split). Default path:
| Platform | Path |
|---|---|
| Linux | ~/.local/etc/nonoblock_permissions |
| macOS | ~/Library/Application Support/nonoblock/nonoblock_permissions |
Alternatively, via environment variables:
export NONOBLOCK_PERMISSIONS_FILE=/path/to/file # canonical
export AGENT_PERMISSIONS_FILE=/path/to/file # legacy, also accepted
Upgrade
Update the repository
git pull
Reinstall the script
install -m755 nonoblock ~/.local/bin/nonoblock
Everything at once (incl. agent updates)
./setup.sh update
This:
- Runs
git pull --ff-onlyin the repository. - Reinstalls
nonoblock. - Updates the permissions file from the template.
- Runs each agent's own update mechanism sandboxed:
claude→claude updateaider→uv tool upgrade/pipx upgrade/pip install --user --upgradeopencode→go install github.com/opencode-ai/opencode@latestcline→npm install -g @anthropic-ai/cline
Only specific agents
./setup.sh claude aider update
Usage
Basic invocations
nonoblock claude
nonoblock aider -m gpt-4o
nonoblock opencode
nonoblock cline
All arguments after the agent name are passed through to the agent unchanged.
Starting from $HOME
Landlock/Seatbelt cannot sandbox $HOME with --allow-cwd. nonoblock
detects this case automatically, switches to a temporary directory, and
cleans it up on exit:
Running from $HOME; using tmpdir /tmp/tmp.XXXXXX (Landlock/Seatbelt can't sandbox $HOME with --allow-cwd)
Manually specifying the agent binary
If the agent is not found by name on $PATH:
AGENT_REAL_BIN=/path/to/binary nonoblock myagent
Configuration
Permissions file – format
Each line: <type> <path>. Comments (#) and blank lines are skipped.
Paths are evaluated, so ~ and brace expansion ({a,b}) work.
| Type | Meaning |
|---|---|
rw |
Read-write access to directory |
ro |
Read-only access to directory |
ro-file |
Read-only access to file |
bypass-ro-file |
Bypass protection + read-only on file |
bypass-rw-file |
Bypass protection + read/write on file |
cmd-default |
Default policy: <exe> <allow|deny> |
cmd-allow |
Allow argv prefix: <exe> <argv-prefix...> |
cmd-deny |
Deny argv prefix: <exe> <argv-prefix...> |
Example
# Directories
rw ~/projects
ro ~/.cache/{pnpm,gh,deno}
ro ~/.config
# Files
ro-file ~/.gitconfig
bypass-rw-file ~/.aws/credentials
# Command Policies (requires jq)
cmd-default kubectl deny
cmd-allow kubectl get
cmd-allow kubectl describe
cmd-deny kubectl apply
cmd-deny kubectl delete
Environment variables
| Variable | Purpose |
|---|---|
NONOBLOCK_PERMISSIONS_FILE |
Path to the permissions file (canonical) |
AGENT_PERMISSIONS_FILE |
Legacy name, also accepted |
AGENT_REAL_BIN |
Explicit path to the agent binary (overrides $PATH lookup) |
NONOBLOCK_BIN |
Install path for nonoblock (default: ~/.local/bin/nonoblock) |
XDG_RUNTIME_DIR |
Runtime directory (Linux); fallback: $TMPDIR or /tmp |
XDG_CONFIG_HOME |
Base for generated nono profiles (default: ~/.config) |
Auto-detected tools
nonoblock adds grants when certain tools are found on the system:
- Docker:
~/.dockeris allowed, the Unix socket is exposed, credential files (config.json,daemon.json) receive--bypass-protection. - Go:
GOPATH/bin(read),GOPATH/pkgandGOCACHE(rw). - just: A private tmpdir under the runtime directory is allowed.
Agent-specific behavior
-
cline: The
clinebinary is a Node.js resolver that spawns a hidden.clinebinary. nonoblock detects this and launches.clinedirectly so nono only has to sandbox a single process.CLINE_WRAPPER_PATHis set so cline resolves its package-manager detection and webview search correctly. -
claude: Uses nono's built-in
claude-codeprofile directly. -
other agents (e.g.
aider,opencode): nonoblock checks whether a per-agent generated profile<agent>-codeexists and uses it if present.
Shebang interpreters
If the agent binary is a script (e.g. a uv-managed Python tool),
nonoblock follows the #! line (including symlink resolution) and
grants read access to the interpreter's directory. Without this grant,
execve() of the interpreter would be blocked by Landlock/Seatbelt.
Generated profiles
If cmd-default / cmd-allow / cmd-deny lines are present in the
permissions file, nonoblock generates a profile
<agent>-nono-cmdpolicy.json under
$XDG_CONFIG_HOME/nono/profiles/ (default: ~/.config/nono/profiles/).
This profile is regenerated on every invocation – treat the file as a build artifact and do not edit it manually. Changes belong in the permissions file.
Debugging
# Shows what the base profile allows:
nono profile show claude-code
# Shows resolved caps without actually launching:
nono wrap --dry-run ... -- /bin/true
# Explains a denial (from inside the sandbox):
nono why --self --path <path> --op read
Full schema and patterns: nono profile guide
Portability
The script runs on both Linux and macOS – each with the tools
standardly installed on that platform. On macOS that means stock
/bin/bash (Bash 3.2, the last GPLv2 release) and the Apple toolchain.
The following constraints are therefore observed:
- No
array+=(...)syntax (Bash 4.0+) – arrays are rebuilt instead:arr=("${arr[@]}" new) - No
/run/user/<uid>(systemd-only) – fallback via$TMPDIR - No dependency on GNU
readlink -forrealpath
On Linux, nonoblock uses the kernel's Landlock mechanism
(kernel ≥ 5.13) for file-access sandboxing – no additional tooling
required. nono ≥ 0.41 wraps the Landlock rules; nonoblock itself
installs nothing extra. The constraints above primarily concern macOS,
where the stock toolchain (Bash 3.2, BSD tools) is older or different
from typical Linux distributions.
On macOS, Seatbelt (XNU's sandbox implementation) handles the same role – also with no additional tooling.