When you run Codex under This keeps Codex’s approval flow while avoiding nested sandboxes that can make denials harder to diagnose. See OpenAI’s agent approvals and security docs.
nono, prefer a single sandbox layer: let nono enforce filesystem and network boundaries, and start Codex with its own sandbox disabled.Recommended invocation:Why Sandbox Codex?
Codex is designed to inspect code, execute tools, and persist local state. Without isolation:- It could read files outside the repository you meant to expose
- A prompt injection or tool mistake could modify unrelated files on the same machine
- Long-lived local state could become a path for broader access than the current task needs
Quick Start
always-further/codex isn’t installed yet, nono prompts to pull it (see Automatic Pack Install and Plugin Wiring below).
The pack profile provides:
- Read+write access to the current working directory
- Read+write access to
~/.codex(config, auth state, sessions, caches, and local metadata) and~/.agents - Read access to common user-local runtime paths for Rust, Node.js, Python, and Nix toolchains, plus
~/Library/Preferences(Codex queries CFPreferences on startup) - OAuth login support via supervised URL opening on Linux and a temporary LaunchServices flag on macOS
- Network access enabled
- Interactive mode enabled for the terminal UI
Automatic Pack Install and Plugin Wiring
Thecodex profile is distributed as a signed registry pack at always-further/codex along with a Codex plugin that provides sandbox-aware diagnostic hooks and a skill for guiding the user through denial-recovery.
The first time you run nono run --profile codex -- codex, nono prompts to install the pack:
Y. nono pulls the pack, verifies its Sigstore provenance, and writes Codex’s plugin wiring directly to the files Codex actually reads (verified against openai/codex source — not the ~/.agents/plugins/marketplace.json that some external docs hint at).
What the pull writes
| Path | What goes there |
|---|---|
~/.config/nono/packages/always-further/codex/ | The unpacked pack: profile, plugin manifest, hooks, skill. Single source of truth — every Codex-side path below is a symlink or registry entry pointing at this dir. |
~/.codex/plugins/cache/always-further/codex/local | Symlink → pack store. Codex’s PluginStore (codex-rs/core-plugins/src/store.rs) walks this dir to discover installed plugin versions. |
~/.codex/config.toml (fenced block) | [marketplaces.always-further] registers the marketplace; [plugins."nono@always-further"] enabled = true enables the plugin. |
~/.codex/hooks.json | Hook entries pointing at <pack store>/bin/nono-hook*.sh for PostToolUse, PermissionRequest, SessionStart. |
config.toml block is fenced with markers so re-pulls and removals never touch your other settings:
Activating the hooks
Codex requires an opt-in feature flag for hooks. Add the following to~/.codex/config.toml (the section header and the key must be on separate lines — this is TOML, not a single-line declaration):
nono pull you’ll see a one-line reminder if the flag isn’t set:
Subsequent runs
Once installed,nono run --profile codex -- codex runs silently — no prompt. nono’s profile resolver finds codex in the pack store and re-asserts the marketplace + cache wiring on every run, so deleting any of the entries above is recovered transparently on the next nono run.
If a newer version of the pack is available, nono prints a one-line hint after the capabilities block:
nono update to apply it, or nono outdated to check all installed packs at once. See Managing Packs for pinning and other options.
Skipping or automating the prompt
| Environment | Behaviour |
|---|---|
| Interactive TTY | Prompt fires; press Enter or Y to install. |
NONO_AUTO_MIGRATE=1 | Prompt skipped; pull runs immediately. Useful for CI/scripted setup. |
NONO_NO_MIGRATE=1 | Pull blocked; nono exits cleanly with a hint pointing at nono pull always-further/codex. |
| Non-TTY (no env override) | Same as NONO_NO_MIGRATE=1. |
Hook-driven sandbox diagnostics
The pack’s hooks wire into three Codex events:PostToolUseforBash,apply_patch, and MCP file tools — when the tool’s output matches a sandbox-denial signature (Operation not permitted,EACCES,EPERM,landlock), the hook returnsdecision: blockwith areasonstring. Codex pauses the agent loop and shows the reason to the user verbatim — no LLM paraphrasing, no “Want me to run nono why?” dangler. Thereasonincludes the diagnostic, the allowed paths, and an inline JSON template for the Option B persistent-fix profile (extendscodexand adds the blocked path).PermissionRequest— when Codex’s approval flow asks the user to escalate, the hook denies upstream with a message explaining that approval can’t grant access the OS sandbox already blocks. The user is told to restart with--allow <path>.SessionStart— pre-loads the sandbox boundary into the conversation asadditionalContext, so the model understands the limits from turn 1 and won’t reach for “macOS TCC” or “chmod” diagnoses on the first denial.
permission_mode = "bypassPermissions" (Codex’s yolo mode), all three hooks stay silent — the user has explicitly opted into running without approval.
Removing the pack
config.toml, the hook entries from hooks.json, and the lockfile entry. [features] codex_hooks = true is left alone — it’s a user-set Codex preference, not something nono installed.
Custom Profile
Create~/.config/nono/profiles/my-codex.json if you want different permissions. Extend the pack profile so you keep all its grants (groups, OAuth origin, etc.) and just add what you need:
nono run --profile my-codex -- codex.
The
extends chain pulls in everything the pack profile declares (allow paths, runtime groups, OAuth origin, hook plugin) and merges your additions on top. If you instead create a profile literally named codex in ~/.config/nono/profiles/, it shadows the pack profile entirely — you take responsibility for the full configuration.Security Tips
OAuth Login
Codex login openshttps://auth.openai.com during the OAuth flow.
The profile includes the required browser-open allowlist:
https://auth.openai.comlocalhostcallbacks for the OAuth redirect
--allow-launch-services.
Restrict to a Specific Project
The profile grants access to the directory you run Codex from. To pin access to a specific repository:Read-Only Workspace
If you want Codex to keep its local state but not modify the repository:Block Network for Local-Only Work
If you want to inspect local code without allowing outbound access:Use Network Filtering
If you want Codex limited to the built-in host allowlist for coding workflows:Additional Home-Directory Tools
The profile covers common Rust, Node.js, Python, and Nix runtime locations under~/, but some developer tools still install into other home-directory paths such as ~/go/bin or ~/.bun/bin.
If a tool exists on your PATH but Codex cannot launch it inside the sandbox, grant read access to the specific path entry: