Tools to monitor and sandbox processes on Linux and macOS. While primarily developed to supervise AI coding agents, all tools work with any process.
- Monitoring — bpftrace scripts that trace what a process and all its descendants are doing (exec, file, network, suspicious ops) using kernel tracepoints, kprobes, and uprobes. Requires Linux with BTF support (
CONFIG_DEBUG_INFO_BTF=y), bpftrace >= 0.25 (see 8aacaf8 for bpftrace < 0.25). - Sandboxing — a multi-backend jailing script that sandboxes processes with configurable filesystem, command, and network restrictions. Requires Python 3.11+ (or Python 3.6+ with the
tomlipackage). Backend-specific requirements: bubblewrap (bwrap) on Linux,sandbox-execon macOS (available by default), or Linux kernel 5.13+ for Landlock (no extra dependencies).
Example configuration files for popular AI coding agents are provided in the confs/ directory.
- Key tools
- monitor-process.sh — all-in-one bpftrace monitoring wrapper
- jail-process.py — multi-backend process sandboxing / jailing
- Individual bpftrace scripts
- Configuration files
- Sandbox profiles
The main entry point for monitoring. Launches or attaches to any process and runs all bpftrace scripts in parallel. Traces are written to a log file (not the terminal). Supports selective tracer disabling and file-tracer output filtering.
# Run mode — launch a command and trace it
./monitor-process.sh -- <COMMAND> [ARGS...]
# Attach mode — trace an already-running process
./monitor-process.sh -p <PID>
# With a config file (e.g. for Claude Code)
./monitor-process.sh -c confs/monitor-claude.conf -- claude --resume
# Disable specific tracers
./monitor-process.sh -EN -- my-program run
# Follow traces in real time from another terminal
tail -f <log-file>
See ./monitor-process.sh -h for all options.
Sandboxes any process using one of three backends, selected automatically based on the platform or overridden with a flag. Uses TOML profiles to configure what the process can access.
Backends (mutually exclusive):
| Flag | Backend | Platform | Isolation strength |
|---|---|---|---|
--bwrap |
bubblewrap | Linux | Strongest — full namespace isolation (PID, mount, network, user, IPC, UTS) |
--sandbox-exec |
macOS Seatbelt (sandbox-exec) |
macOS | SBPL-based filesystem + network + exec control |
--landlock |
Linux Landlock LSM | Linux 5.13+ | Kernel-enforced filesystem allowlist; no namespace isolation |
The default is the first available backend in the order above. On Linux, bwrap is preferred; if absent, Landlock is used. On macOS, sandbox-exec is used. A profile can set bwrap: false to skip bwrap and prefer Landlock instead.
What it restricts (bwrap, strongest):
- Filesystem — only explicitly listed paths are mounted (read-only or read-write)
- Commands — only allowlisted binaries are available;
/usr/binis NOT mounted wholesale - Namespaces —
--unshare-allby default (PID, mount, network, user, IPC, UTS, cgroup) - Network — denied by default, must be explicitly enabled per profile
- Environment — cleared and rebuilt from config only
Landlock and sandbox-exec enforce filesystem and exec restrictions but do not provide namespace or network isolation (Landlock) or mount/UTS namespaces (both). Warnings are printed when a profile option is unsupported by the selected backend.
# Dry-run — inspect what the sandbox would do (output depends on backend)
./jail-process.py -c confs/jail.toml -p claude --dry-run -- claude
# Run a process inside the sandbox (auto-selects backend)
./jail-process.py -c confs/jail.toml -p claude -- claude
# Add extra mounts from the command line
./jail-process.py -c confs/jail.toml -p claude --rw ~/myproject --ro /opt/data -- claude
# Explicitly select a backend
./jail-process.py -c confs/jail.toml -p claude --bwrap -- claude
./jail-process.py -c confs/jail.toml -p claude --landlock -- claude
./jail-process.py -c confs/jail.toml -p claude --sandbox-exec -- claude
See ./jail-process.py -h for all options.
Features:
- Profiles defined in TOML (
confs/jail.toml), one per process/agent ~expansion in all path fields for portable configs- Automatic script dependency scanning — shell wrapper shebangs and
exectargets are resolved and bound - Binaries are bound at all their paths (canonical,
which, and realpath) so they work regardless of how they're referenced --dry-runprints a readable summary of what would be sandboxed (bwrap command, Landlock path list, or SBPL profile)--ro/--rwCLI flags to add extra mounts without editing the config
Monitors sub-processes spawned by the target process. Logs every execve call with the full command line.
sudo bpftrace trace-execs.bt <PID>
Monitors outbound network activity: TCP connects, DNS lookups (UDP port 53), data transfer (TX/RX for TCP and UDP), and hostname resolution via getaddrinfo. When a hostname is resolved before a connection, subsequent TCP events display the hostname alongside the IP address. Consecutive TCP send/receive events for the same connection are aggregated into a single line showing total bytes and call count.
sudo bpftrace trace-netcalls.bt <PID>
Monitors file operations: opens (read/write/create), reads, writes, directory creation, deletes, renames, chmod, and chown. Tracks fd-to-filename mappings so that read/write syscalls display the file path and byte count.
sudo bpftrace trace-files.bt <PID>
Monitors suspicious or potentially dangerous operations:
- Credential/secret access — opening SSH keys, GPG keyrings, Cloud credentials,
.env, token/secret files, etc. - Privilege escalation —
setuid/setgid/setresuid/setresgid,capset - Persistence mechanisms — writing to crontabs, systemd unit files, shell startup files (
.bashrc,.zshrc, etc.) - System manipulation —
ptrace(process injection),mount/umount, kernel module loading, hostname changes - Covert execution —
memfd_create(fileless execution), raw socket creation - Listening sockets / reverse shells —
bind,listen,accept/accept4 - Cross-process memory access —
process_vm_readv/process_vm_writev - Namespace / sandbox escape —
unshare,chroot,pivot_root - Code injection / anti-forensics —
mprotectwith PROT_EXEC,prctlPR_SET_DUMPABLE=0,seccomp,personality,userfaultfd - Symlink / hardlink attacks —
symlinkat,linkat - Credential keyring access —
keyctl - Destructive actions —
reboot,killoutside watched process tree - Permission manipulation —
chmodwith setuid/setgid bits
sudo bpftrace trace-suspicious.bt <PID>
monitor-process.sh options can be set via CLI flags, environment variables, or a config file sourced with -c. Example config files for popular AI coding agents are provided in the confs/ directory:
| Config file | Tool |
|---|---|
confs/monitor-claude.conf |
Claude Code |
confs/monitor-codex.conf |
OpenAI Codex CLI |
confs/monitor-aider.conf |
Aider |
confs/monitor-cline.conf |
Cline |
confs/monitor-goose.conf |
Goose |
confs/monitor-continue.conf |
Continue |
confs/monitor-openhands.conf |
OpenHands |
Precedence: defaults < env vars < config file < CLI options.
Pre-configured profiles for popular AI coding agents are provided in confs/jail.toml. Any process can be jailed by adding a new profile to this file.
| Profile | Tool | Agent state directory |
|---|---|---|
claude |
Claude Code | ~/.claude, ~/.claude.json |
codex |
OpenAI Codex CLI | ~/.codex |
aider |
Aider | ~/.config/aider, ~/.aider.conf.yml |
cline |
Cline | ~/.cline |
goose |
Goose | ~/.config/goose |
continue |
Continue | ~/.continue |
openhands |
OpenHands | ~/.openhands |
Each profile mounts shared libraries (/usr/lib, /lib, /lib64) read-only, the agent's state directory read-write, and whitelists a minimal set of commands. Edit ~/project in the config to point at your working directory.