Skip to main content
When you run Claude Code under nono, prefer using nono as the only sandbox layer. Leave Claude Code’s built-in sandbox disabled so all filesystem and network boundaries come from the kernel-enforced nono policy.If you keep Claude Code’s sandbox enabled, Anthropic documents an intentional escape hatch: when a command fails because of sandbox restrictions, Claude may retry it with dangerouslyDisableSandbox after going through Claude Code’s normal permissions flow. To disable that fallback, set "allowUnsandboxedCommands": false in Claude Code’s sandbox settings. See Anthropic’s sandboxing docs.

Why Sandbox Claude Code?

Claude Code includes its own sandboxing, but Anthropic documents an intentional escape hatch: when a command fails because of sandbox restrictions, Claude may retry it with dangerouslyDisableSandbox after approval. Running Claude inside nono gives you a single kernel-enforced boundary that is easier to reason about and audit.

Quick Start

nono run --profile claude-code -- claude
macOS users: Claude Code needs to open a browser on first use (e.g., for claude /login), you must add the --allow-launch-services flag:
nono run --profile claude-code --allow-launch-services -- claude
After this initial login, you can exit and rerun without --allow-launch-services for better security. See OAuth2 Login for details.
The built-in profile provides:
  • Read+write access to the current working directory
  • Read+write access to ~/.claude (agent state, debug logs, project config)
  • Read+write access to ~/.claude.json (settings file)
  • Read+write access to ~/.vscode (VS Code extensions directory)
  • Read+write access to the OS-specific VS Code app data directory: ~/Library/Application Support/Code on macOS, ~/.config/Code on Linux
  • Read access to the OS-specific Claude Code state path: ~/Library/Keychains/login.keychain-db on macOS, ~/.local/share/claude on Linux
  • Network access enabled (required for Anthropic API)
  • Interactive mode enabled (preserves TTY for Claude’s terminal UI)
  • Automatic hook installation for sandbox-aware error handling
  • OAuth2 login support via supervised URL opening (allows claude /login to work)

Custom Profile

If you need different permissions, create a custom profile at ~/.config/nono/profiles/claude-code.json:
{
  "meta": {
    "name": "claude-code",
    "version": "1.0.0",
    "description": "Claude Code with additional project access"
  },
  "security": {
    "groups": ["git_config"]
  },
  "filesystem": {
    "allow": ["$WORKDIR", "$HOME/.claude"],
    "read": ["$HOME/shared-libs"],
    "allow_file": ["$HOME/.claude.json"]
  },
  "network": {
    "block": false
  },
  "env_credentials": {
    "anthropic_api_key": "ANTHROPIC_API_KEY"
  }
}
If you want to inherit the built-in Claude Code profile but remove its network filtering, create a separate extending profile and explicitly clear the inherited network profile:
{
  "meta": { "name": "claude-code-netopen" },
  "extends": "claude-code",
  "network": { "network_profile": null }
}
Then run:
nono run --profile claude-code-netopen -- claude
Usage:
nono run --profile claude-code -- claude
Custom profiles with the same name override the built-in. Remove or rename the file to revert to the built-in profile.

Security Tips

Use Secrets Management

Instead of keeping your API key in environment variable exports or shell config files, load it from the system keystore: macOS:
security add-generic-password -s "nono" -a "anthropic_api_key" -w
Linux:
secret-tool store --label="nono: anthropic_api_key" service nono username anthropic_api_key
Then run with secrets:
nono run --profile claude-code --env-credential anthropic_api_key -- claude
See Credential Injection for full documentation.

Restrict to Specific Projects

The built-in profile grants access to the current working directory (wherever you run the command). To limit access to a specific directory regardless of where you invoke it:
nono run --allow ~/projects/my-app --read ~/.claude -- claude

Read-Only Mode

For code review or exploration where Claude shouldn’t modify files:
nono run --read . --read ~/.claude --allow-file ~/.claude.json -- claude

Block Network for Offline Work

If you want to prevent any outbound connections (e.g., for reviewing local code without API calls):
nono run --profile claude-code --block-net -- claude

Add Extra Domains

If Claude Code needs to reach a domain not in the built-in network profile:
nono run --profile claude-code --allow-domain my-internal-api.example.com -- claude

OAuth2 Login

Running claude /login inside a sandbox requires the browser to open outside the sandboxed process. On Linux (Landlock), nono can delegate approved URLs to the unsandboxed parent process. On macOS (Seatbelt), Claude’s login flow needs a temporary LaunchServices permission to open the browser. The built-in claude-code profile includes an origin allowlist that controls which URLs may be opened during supervised login flows:
  • https://claude.ai (OAuth2 authorize endpoint)
  • localhost callbacks (for the OAuth2 redirect)
On Linux, no additional flags are needed:
nono run --profile claude-code -- claude
On macOS, enable LaunchServices temporarily for the login session:
nono run --profile claude-code --allow-launch-services -- claude
After login completes, exit and rerun without --allow-launch-services.
--allow-launch-services lets the sandboxed Claude process ask macOS LaunchServices to open URLs, files, or apps for that session. Use it only for temporary login or setup flows, and prefer running it from a trusted directory.

Adding Custom OAuth2 Origins

If your organization uses a custom identity provider for Claude Code authentication, add its origin to your profile:
{
  "meta": { "name": "claude-code-custom-auth" },
  "extends": "claude-code",
  "open_urls": {
    "allow_origins": [
      "https://claude.ai",
      "https://sso.example.com"
    ],
    "allow_localhost": true
  }
}
When a derived profile specifies open_urls, it replaces the base profile’s config entirely. Include all origins you need, including https://claude.ai if you still want the standard OAuth2 flow. Omit open_urls to inherit the base profile’s settings unchanged.
The origin allowlist is enforced by the supervisor when nono delegates browser opening itself. On macOS, --allow-launch-services bypasses that supervisor path for the duration of the session in exchange for login compatibility.

Enabling LSPs, Linters, and Dev Tools

Claude Code’s LSP plugins (pyright, rust-analyzer, etc.) spawn language servers as child processes. These spawns use posix_spawnp() which searches your PATH for the binary. If any PATH directory is unreadable to the sandbox, posix_spawnp() receives EPERM from the kernel and stops searching immediately (unlike ENOENT, which continues to the next entry). nono’s built-in system paths cover standard directories (/usr/bin, /opt, etc.), but version managers and dev tools install binaries under ~/ which requires explicit read access. Common home-directory PATH entries that need read access:
ToolPath
Rust / cargo~/.cargo/bin
Go~/go/bin
Python / pyenv~/.pyenv/shims, ~/.pyenv/bin
Node / fnm~/.local/share/fnm, ~/.local/state/fnm_multishells
Node / nvm~/.nvm
Node / pnpm~/Library/pnpm, ~/.local/share/pnpm
Haskell / ghcup~/.ghcup/bin
Ruby / rbenv~/.rbenv/shims, ~/.rbenv/bin
Local binaries~/.local/bin
Diagnose which paths are needed by listing your PATH:
echo "$PATH" | tr ':' '\n'
Grant read access to any ~/ entry that appears before the directory containing your LSP binary:
nono run --profile claude-code \
  --read ~/.cargo/bin \
  --read ~/.local/bin \
  -- claude
You only need --read (not --allow) for these directories. This permits PATH lookup without granting write access.

VS Code Extension

Claude Code installs a VS Code extension on startup. The built-in profile already grants write access to ~/.vscode plus the OS-specific VS Code data directory: ~/Library/Application Support/Code on macOS or ~/.config/Code on Linux. No additional flags are needed for VS Code extension installation.

Git Configuration

Claude Code reads git configuration for repository operations. The built-in profile includes the git_config group, which grants read access to ~/.gitconfig, ~/.gitignore_global, and ~/.config/git/ignore. No additional flags are needed for git operations.

Secretive (SSH Keys in Secure Enclave)

If you use Secretive to store SSH keys in the macOS Secure Enclave, git commit signing (git commit -S) needs access to the Secretive agent socket. Create a custom profile that extends the built-in Claude Code profile: Save as ~/.config/nono/profiles/claude-code-secretive.json:
{
  "meta": {
    "name": "claude-code-secretive",
    "version": "1.0.0",
    "description": "Claude Code with Secretive SSH agent support"
  },
  "extends": "claude-code",
  "filesystem": {
    "read": [
      "$HOME/.ssh/config",
      "$HOME/Library/Containers/com.maxgoedjen.Secretive.SecretAgent/Data/socket.ssh"
    ],
    "allow_file": ["$HOME/.ssh/known_hosts"]
  },
  "policy": {
    "add_allow_readwrite": ["$HOME/.ssh/known_hosts"]
  }
}
Usage:
nono run --profile claude-code-secretive --allow-cwd -- claude
The profile extends the standard Claude Code profile with:
  • Read access to ~/.ssh/config (git signing configuration)
  • Read access to the Secretive agent socket (~/Library/Containers/com.maxgoedjen.Secretive.SecretAgent/Data/socket.ssh)
  • Read+write access to ~/.ssh/known_hosts (SSH may append new host keys)
The Secretive socket is a Unix domain socket, not a regular file. nono supports granting capabilities on sockets directly, so only the socket itself is exposed — not the entire container directory.

Overriding Profile Settings

CLI flags always take precedence over profile settings:
# Use profile but add extra directory access
nono run --profile claude-code --allow ~/other-project -- claude

# Use profile but block network
nono run --profile claude-code --block-net -- claude

# Use profile but add a custom domain
nono run --profile claude-code --allow-domain custom-api.example.com -- claude
See Security Profiles for details on profile format and precedence rules.

Automatic Hook Integration

When you first run nono run --profile claude-code, nono automatically installs a hook that helps Claude understand sandbox restrictions. You’ll see:
Installing claude-code hook to ~/.claude/hooks/nono-hook.sh
This hook:
  1. Detects sandbox errors - When Claude’s file operations fail due to sandbox restrictions
  2. Injects context - Tells Claude exactly which paths are allowed and blocked
  3. Provides guidance - Instructs Claude to suggest restarting with --allow flags instead of attempting workarounds
nono also adds a section to ~/.claude/CLAUDE.md with upfront sandbox instructions, so Claude understands the security boundaries before encountering errors.
The hook installation is idempotent - it only installs once and updates automatically when nono is upgraded. The hook only activates when running inside a nono sandbox (detected via $NONO_CAP_FILE).

What Claude Sees on Errors

When Claude attempts to access a blocked path, instead of just seeing “Operation not permitted”, the hook injects:
[NONO SANDBOX - PERMISSION DENIED]

STOP. Do not try alternative approaches. This is a hard security boundary.

You are running inside the nono security sandbox. The operation you just
attempted is PERMANENTLY BLOCKED for this session.

ALLOWED PATHS (everything else is blocked):
  /Users/you/project (readwrite)
  /Users/you/.claude (readwrite)
Network: allowed

REQUIRED ACTION:
Tell the user they must EXIT this Claude session and restart with:
  nono run --allow /path/to/needed -- claude
This prevents Claude from wasting time on workarounds that cannot succeed.