> ## Documentation Index
> Fetch the complete documentation index at: https://nono.sh/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Codex

> Sandboxing OpenAI Codex CLI with nono

Codex is OpenAI's CLI coding agent. It reads repositories, writes files, runs commands, and stores local session state. Running it under nono keeps that access confined to the project and state paths you intentionally grant.

> [!NOTE]
>
> When you run Codex under `nono`, keep the interactive client and its app server inside the same sandbox, and prefer a single filesystem and network boundary: use `--no-daemon`, let `nono` enforce access, and start Codex with its own sandbox disabled.
>
> Recommended invocation:
>
> ```bash theme={null}
> nono run --profile nolabs-ai/codex -- codex --no-daemon --sandbox danger-full-access --ask-for-approval on-request
> ```
>
> `--no-daemon` makes the TUI use an embedded app server instead of attaching to the shared background server. `--sandbox danger-full-access` avoids a nested Codex sandbox, while `--ask-for-approval on-request` retains Codex's operator approval flow. See OpenAI's [CLI reference](https://learn.chatgpt.com/docs/developer-commands?surface=cli) and [agent approvals and security docs](https://learn.chatgpt.com/docs/agent-approvals-security).

## 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

nono makes those boundaries kernel-enforced instead of advisory.

## Quick Start

```bash theme={null}
nono run --profile nolabs-ai/codex -- codex --no-daemon --sandbox danger-full-access --ask-for-approval on-request
```

If the registry pack `nolabs-ai/codex` isn't installed yet, nono prompts to pull it (see [Automatic Pack Install and Plugin Wiring](#automatic-pack-install-and-plugin-wiring) below).

The pack profile provides:

* **Read+write access** to the current working directory after nono's standard CWD consent prompt (or when started with `--allow-cwd`)
* **Read+write access** to `~/.codex` (config, auth state, sessions, caches, and local metadata) and `~/.agents`
* **Read+write access** to `~/.config/nono/profile-drafts` for persistent capability drafts
* **Read+write access** to user cache directories (`~/.cache` on both platforms, plus `~/Library/Caches` and `~/Library/Logs` on macOS)
* **Read access** to common user-local runtime paths for Rust, Node.js, Python, and Nix toolchains; macOS also grants `~/Library/Preferences`, and Linux grants `/sys`
* **macOS credential access** to `~/Library/Keychains`, which the profile explicitly exempts from the default keychain deny rules for Codex authentication
* **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

## App-server isolation

Recent Codex versions normally connect the TUI to a shared background app server. That server owns the agent harness and tool execution and can outlive the TUI that started it. Sandboxing only the TUI is therefore insufficient: it could attach to a server outside nono and execute tools with that server's access.

For interactive sessions, including `codex resume` and `codex fork`, always use `--no-daemon`. It bypasses daemon discovery without stopping or disrupting any shared daemon used by other Codex clients.

* **macOS:** the pack denies Codex's shared-daemon control paths as fail-closed protection. If Codex cannot connect, restart with `--no-daemon`; it does not automatically fall back to an embedded server.
* **Linux:** Landlock cannot subtract the daemon socket from the broader read-write `~/.codex` grant required for Codex state. `--no-daemon` is therefore the required isolation control.

The flag depends on the command's execution model:

| Command | App-server path | Safe usage with nono |
| - | - | - |
| `codex`, `codex resume`, `codex fork` | Interactive; uses the shared daemon by default | Add `--no-daemon` so the app server and tool execution remain in nono's process tree. |
| `codex exec`, `codex review` | Starts an in-process app server | No `--no-daemon` is needed. The command and its tool execution remain inside nono. |
| `codex login`, `codex logout`, and other local configuration commands | Does not run an agent tool harness | No `--no-daemon` is needed. The command itself is still constrained by nono. |
| `codex agents`, `codex queue`, and other commands targeting the shared server | Intentionally connects to a server outside the CLI process | Do not treat these as isolated agent runs. Sandboxing the client does not retroactively sandbox the shared server. |

The outer nono sandbox applies to the command and all processes it starts. It cannot constrain an already-running daemon outside that process tree. Conversely, `--sandbox danger-full-access` only disables Codex's nested sandbox; it does not disable nono.

## Automatic Pack Install and Plugin Wiring

The Codex profile is distributed as the signed `nolabs-ai/codex` package along with a Codex plugin that provides a sandbox-diagnostic skill and startup instructions.

The first time you run the canonical interactive command, nono prompts to install the pack:

```
  ⊕  Install nolabs-ai/codex?

     The requested profile is this registry package's public profile.

     Namespace    nolabs-ai
     Provenance   Sigstore cryptographic supply chain (verified on pull)

  Continue? [y/N]
```

After the one-second input guard enables the prompt, press `Y`. Pressing Enter
uses the safe default and skips installation. nono pulls the pack, verifies its
Sigstore provenance, and writes Codex's plugin wiring to the marketplace,
cache, and configuration paths Codex reads.

### What the pull writes

| Path | What goes there |
| - | - |
| `~/.config/nono/packages/nolabs-ai/codex/` | The unpacked and verified pack: profile, plugin manifest, helper, compatibility scripts, and skill. |
| `~/.config/nono/profile-drafts/.nono-codex-pack-marker` | A pack-owned marker that ensures the writable profile-drafts directory exists. |
| `~/.codex/plugins/marketplaces/nolabs-ai/plugins/nono` | Symlink to the pack store, exposing the `nono` plugin through Codex's local marketplace layout. |
| `~/.codex/plugins/marketplaces/nolabs-ai/.agents/plugins/marketplace.json` | Marketplace metadata for the local `nono` plugin. |
| `~/.codex/plugins/cache/nolabs-ai/nono/local` | Symlink to the pack store used by Codex's plugin cache discovery. |
| `~/.codex/bin/nono-draft-profile` | Structured helper used by the skill to create profile drafts safely. |
| `~/.codex/config.toml` (fenced block) | Adds sandbox-denial guidance, registers the local marketplace, and enables `nono@nolabs-ai`. |

The `config.toml` block is fenced with markers so re-pulls and removals never touch your other settings:

```toml theme={null}
# >>> nono:nolabs-ai-codex >>>
developer_instructions = """
Only treat a permission failure as a nono denial after explicit nono output or a successful `nono why --self` result with status `DENIED`.
"""

[marketplaces.nolabs-ai]
source_type = "local"
source = "/Users/<you>/.codex/plugins/marketplaces/nolabs-ai"

[plugins."nono@nolabs-ai"]
enabled = true
# <<< nono:nolabs-ai-codex <<<
```

The actual managed `developer_instructions` block contains the complete denial-confirmation and recovery rules; the abbreviated text above only illustrates its position. The fenced merge leaves every setting outside the managed block untouched.

Fresh installs deliberately do not register lifecycle hooks. Codex currently renders hook output in the TUI even for silent hook entries, so the pack uses its plugin skill and `developer_instructions` instead. The packaged hook scripts are compatibility no-ops for older installations whose `hooks.json` may still reference them.

### Subsequent runs

Once installed, the canonical interactive command runs without an installation prompt. nono's profile resolver loads the installed profile from the package store. Plugin wiring is applied during `nono pull` and `nono update`, recorded in the package lockfile, and reversed by `nono remove`; an ordinary `nono run` does not repair deleted wiring.

Because Codex is a security-sensitive official pack, nono checks its registry status before launching. An outdated installed version produces:

```
  [nono] official pack nolabs-ai/codex@0.2.3 status: outdated
  [nono] update with: nono pull nolabs-ai/codex@0.2.4 --force
```

The general cached pack checker may additionally show a one-line `run: nono update` hint. Use either printed update command, or run `nono outdated` to inspect all installed packs. See [Managing Packs](https://nono.sh/docs/cli/features/managing-packs.md) 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` | Automatic pull is skipped and the command exits non-zero because the requested profile remains unavailable. |
| Non-TTY (no env override) | Pull is skipped; nono exits non-zero and prints commands for an explicit pull or a `NONO_AUTO_MIGRATE=1` retry. |

### Skill-driven sandbox diagnostics

The enabled `nono@nolabs-ai` plugin exposes the `nono-sandbox` skill. Together with the managed startup instructions, it teaches Codex to distinguish generic permission failures from confirmed nono denials, run `nono why --self` when a concrete path is available, and offer either a narrowly scoped one-off restart or a structured profile draft.

Codex approval cannot expand the capabilities of an already-running nono sandbox. A confirmed denial requires restarting nono with the missing capability or promoting a derived profile.

### Removing the pack

```bash theme={null}
nono remove nolabs-ai/codex
```

Reverses the recorded marketplace, cache, profile-drafts marker, managed `config.toml`, and draft-helper wiring, then removes the pack store and lockfile entry. User-authored Codex settings and unrelated hooks are left untouched. If a reversal fails, nono preserves the lockfile entry and reports the conflict unless you explicitly use `--force`.

## 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:

```json theme={null}
{
  "extends": "nolabs-ai/codex",
  "meta": {
    "name": "my-codex",
    "version": "1.0.0",
    "description": "Codex with additional project access"
  },
  "filesystem": {
    "read": ["$HOME/shared-libs"]
  }
}
```

Then start interactive sessions with `nono run --profile my-codex -- codex --no-daemon --sandbox danger-full-access --ask-for-approval on-request`.

> [!NOTE]
>
> The `extends` chain inherits the package profile's policy (allow paths, runtime groups, OAuth origin, and other profile fields) and merges your additions on top. The package's plugin wiring is installed separately by `nono pull`; it is not a profile field. Package profiles require their fully-qualified name; a user profile named `codex` is separate and does not shadow `nolabs-ai/codex`.

## Security Tips

### OAuth Login

Codex login opens `https://auth.openai.com` during the OAuth flow.

The profile includes the required browser-open allowlist:

* `https://auth.openai.com`
* `localhost` callbacks for the OAuth redirect

On Linux, no additional flags are needed:

```bash theme={null}
nono run --profile nolabs-ai/codex -- codex --no-daemon --sandbox danger-full-access --ask-for-approval on-request
```

On macOS, enable LaunchServices temporarily for the login session:

```bash theme={null}
nono run --profile nolabs-ai/codex --allow-launch-services -- codex --no-daemon --sandbox danger-full-access --ask-for-approval on-request
```

After login completes, exit and rerun without `--allow-launch-services`.

> [!WARNING]
>
> `--allow-launch-services` lets the sandboxed Codex 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.

### Restrict to a Specific Project

The profile grants access to the directory you run Codex from. To pin access to a specific repository:

```bash theme={null}
nono run --profile nolabs-ai/codex --workdir ~/projects/my-app -- codex --no-daemon --sandbox danger-full-access --ask-for-approval on-request
```

### Read-Only Workspace

If you want Codex to keep all pack-provided state and runtime access but not modify the repository, create `~/.config/nono/profiles/codex-read-only.json`:

```json theme={null}
{
  "extends": "nolabs-ai/codex",
  "meta": {
    "name": "codex-read-only",
    "version": "1.0.0"
  },
  "workdir": {
    "access": "read"
  }
}
```

Then run the noninteractive review command. Unlike the interactive TUI, `codex review` starts its app server in the same `codex` process instead of connecting to the shared background daemon. That process remains inside nono, so `--no-daemon` is not needed here. `--sandbox danger-full-access` disables Codex's nested sandbox, not the outer nono sandbox:

```bash theme={null}
nono run --profile codex-read-only -- codex --sandbox danger-full-access --ask-for-approval on-request review
```

### Block Network for Local-Only Work

If you want to inspect local code without allowing outbound access:

```bash theme={null}
nono run --profile nolabs-ai/codex --block-net -- codex --no-daemon --sandbox danger-full-access --ask-for-approval on-request
```

### Use Network Filtering

If you want Codex limited to the built-in host allowlist for coding workflows:

```bash theme={null}
nono run --profile nolabs-ai/codex --network-profile codex -- codex --no-daemon --sandbox danger-full-access --ask-for-approval on-request
```

#### Codex Shell-based Tools

The `allow_login_shell` configuration key in Codex controls whether shell-based tools may request login-shell semantics. When it is `false`, requests with `login = true` are rejected, while requests that omit `login` use a non-login shell. On affected tool paths, that non-login-shell environment can omit values that nono injected into the Codex process, even when Codex's own sandbox is disabled.

If those values are missing:

* proxy-filtered network requests from Codex commands fail even for allowed destinations because the proxy variables or token are unavailable;
* `nono why --self` cannot see `NONO_CAP_FILE`, so a command cannot introspect the active nono capability set.

##### Option 1: Allow login shell in nono sandbox

Codex defaults `allow_login_shell` to `true`; if neither your configuration nor a managed requirement disables it, the network-filtering command above is already sufficient. To override a user configuration that set it to `false`, pass the setting explicitly. Because nono is already enforcing the outer sandbox, this disables only the optional Codex login-shell hardening for that invocation.

Recommended invocation:

```bash theme={null}
nono run --profile nolabs-ai/codex --network-profile codex -- codex --no-daemon --sandbox danger-full-access --ask-for-approval on-request --config allow_login_shell=true
```

##### Option 2: Explicit configuration

An alternative, more secure, and explicit approach is to keep optional hardening enabled and configure Codex’s `shell_environment_policy` so that required environment variables are passed to the subprocess.

Set `allow_login_shell=false` in the Codex configuration, then add the `shell_environment_policy` block and explicitly include the required exports. The `filters` map is the current form of this policy; the older `include_only` array remains supported by Codex for compatibility but is legacy configuration.

Keep `ignore_default_excludes = true` here. Codex's automatic secret-name filter runs before explicit filters and would otherwise remove `NONO_PROXY_TOKEN`; an `include` rule cannot restore it. The explicit include filters still form an allowlist, so unlisted environment variables remain excluded.

```toml theme={null}
[shell_environment_policy]
inherit = "all"
ignore_default_excludes = true

[shell_environment_policy.filters]
"PATH" = "include"
"HOME" = "include"
"USER" = "include"
"SHELL" = "include"
"TERM" = "include"
"COLORTERM" = "include"
"LANG" = "include"
"LC_*" = "include"
"NONO_CAP_FILE" = "include"
"NONO_PROXY_TOKEN" = "include"
"BROWSER" = "include"
"NO_PROXY" = "include"
"NONO_NO_PROXY" = "include"
"HTTP_PROXY" = "include"
"HTTPS_PROXY" = "include"
"NODE_USE_ENV_PROXY" = "include"
"GIT_SSL_CAINFO" = "include"
"CURL_CA_BUNDLE" = "include"
"NODE_EXTRA_CA_CERTS" = "include"
"REQUESTS_CA_BUNDLE" = "include"
"SSL_CERT_FILE" = "include"
"AWS_CA_BUNDLE" = "include"
```

Filter matching is case-insensitive, so the uppercase proxy entries also preserve nono's lowercase `http_proxy`, `https_proxy`, and `no_proxy` exports. See OpenAI's [configuration reference](https://learn.chatgpt.com/docs/config-file/config-reference) for the complete `shell_environment_policy` semantics.

### 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:

```bash theme={null}
nono run --profile nolabs-ai/codex \
  --read ~/.bun/bin \
  --read ~/go/bin \
  -- codex --no-daemon --sandbox danger-full-access --ask-for-approval on-request
```

See [Network Filtering](https://nono.sh/docs/cli/features/networking.md) and [Security Profiles](https://nono.sh/docs/cli/features/profiles-groups.md) for details on host allowlists, profile format, and precedence rules.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.