Profiles
Why Profiles?
Manually specifying capabilities for every tool is tedious and error-prone:Profile Sources
Profiles can come from three sources, in order of precedence:| Source | Location | Trust Level |
|---|---|---|
| CLI flags | Command line | Highest - explicit user intent |
| User profiles | ~/.config/nono/profiles/ | Medium - user-defined |
| Built-in profiles | Compiled into binary | Base - audited defaults |
Profile Format
Profiles use JSON format:Working Directory
Theworkdir section controls whether and how the current working directory is automatically shared with the sandboxed process.
| Value | Meaning |
|---|---|
"none" | No automatic CWD access (default if section omitted) |
"read" | Read-only access to CWD |
"write" | Write-only access to CWD |
"readwrite" | Full read+write access to CWD |
--allow-cwd is used to skip the prompt).
Secrets
Thesecrets section maps keystore account names to environment variable names. Secrets are loaded from the system keystore (macOS Keychain / Linux Secret Service) before the sandbox is applied, then injected as environment variables.
Hooks
Thehooks section defines hooks that nono will automatically install for specific applications.
Interactive Mode
Theinteractive field (default: false) indicates whether the application has an interactive terminal UI that requires TTY preservation:
true, nono uses direct exec mode (equivalent to --exec flag), which preserves the terminal for apps like Claude Code, vim, or htop.
Undo Exclusions
Theundo section controls which files are excluded from atomic rollback snapshots:
Environment Variables
Profiles support these environment variables in path values:| Variable | Expands To |
|---|---|
$WORKDIR | Current working directory (from --workdir or cwd) |
$HOME | User’s home directory |
$XDG_CONFIG_HOME | XDG config directory (default: ~/.config) |
$XDG_DATA_HOME | XDG data directory (default: ~/.local/share) |
$TMPDIR | System temporary directory |
$UID | Current user ID |
Creating User Profiles
-
Create the profiles directory:
-
Create a JSON file:
-
Use the profile:
Overriding Built-in Profiles
CLI flags always take precedence over profile settings:Groups
Groups are named, composable collections of security rules. Profiles reference groups by name in theirsecurity.groups field.
How Groups Compose
Every profile’s effective capability set is built through composition:- base_groups are always applied (deny rules, system paths, dangerous commands)
- trust_groups are per-profile exclusions from base (e.g., removing
deny_credentialsfor an infrastructure agent that legitimately needs credential access) - profile.security.groups add additional groups on top
- profile.filesystem entries are additive
- CLI overrides (
--allow,--read, etc.) are applied last
Group Taxonomy
Groups use a structured allow/deny taxonomy:Allow Operations
| Field | Meaning |
|---|---|
allow.read | Read-only access to listed paths |
allow.write | Write-only access (no read) |
allow.readwrite | Both read and write access |
Deny Operations
| Field | Meaning |
|---|---|
deny.access | Block both read and write content (metadata like stat still allowed) |
deny.unlink | Block file deletion globally |
deny.commands | Block execution of listed commands |
Other
| Field | Meaning |
|---|---|
symlink_pairs | macOS symlink-to-target path mappings (e.g., /etc to /private/etc) |
platform | Restrict group to "macos" or "linux" only |
Built-in Groups
nono ships with 22 built-in groups: Deny groups (block sensitive content):deny_credentials- SSH keys, cloud credentials, GPG keysdeny_keychains_macos- macOS Keychain databasesdeny_browser_data_macos- Browser data (Chrome, Firefox, Safari, etc.)deny_shell_history- Shell history filesdeny_shell_configs- Shell config files (may contain API keys)
system_read_macos- macOS system libraries, frameworks, dyld cachesystem_read_linux- Linux system libraries, locale datasystem_write_macos- macOS temp directories, cache pathssystem_write_linux- Linux temp directories
node_runtime- nvm, fnm, npm, voltarust_runtime- rustup, cargopython_runtime- pyenv, conda, pipuser_tools- Homebrew, local bins
unlink_protection- Prevents file deletion, with override for user-writable pathsdangerous_commands- Blocksrm,dd,chmod,sudo,mkfs, etc.
Platform-Specific Groups
Groups with aplatform field only apply on that OS:
platform field (like deny_credentials) apply on all platforms.
Platform-specific groups use _macos or _linux suffixes by convention.
never_grant
Thenever_grant list in policy.json defines paths that can never be granted access through the supervisor, even with explicit user approval:
/etc/shadow,/etc/sudoers,/etc/passwd/boot,/boot/grub- macOS launch daemons
~/.ssh/authorized_keys, SSH private keys,~/.gnupg
Platform Differences
macOS (Seatbelt) supports full deny-within-allow semantics. A group can allow/Users but deny /Users/luke/.ssh and the deny takes precedence.
Linux (Landlock) is strictly allow-list. Deny groups are implemented as exclusion filters - broad allow groups that overlap deny paths will generate warnings. Avoid granting access to parent directories of deny paths on Linux.
Built-in Profiles
claude-code
user_caches_macos, node_runtime, rust_runtime, python_runtime, vscode, unlink_protection (plus all base_groups)
Filesystem: ~/.claude (read+write), ~/.claude.json (read+write)
Network: Allowed
Special: interactive = true (preserves TTY), auto-installs Claude Code hooks
opencode
~/.config/opencode, ~/.cache/opencode, ~/.local/share/opencode (all read+write)
Network: Allowed
openclaw
~/.openclaw, ~/.config/openclaw, ~/.local, $TMPDIR/openclaw-$UID (all read+write)
CWD: Read-only
Network: Allowed
Requesting New Built-in Profiles
If you’d like a built-in profile for a tool not listed here:- Open an issue on the nono GitHub repository
- Include:
- Tool name and repository URL
- Required filesystem access patterns
- Network requirements
- Any special considerations