Codex
OpenAI's CLI coding agent with an external launcher boundary and kernel sandbox enforcement.
Last updated
Cloud API TypeScript1. Installation
Prerequisites
- A platform supported by the current Codex release
- ChatGPT sign-in or an OpenAI API key
- A project directory you are comfortable granting to the agent
Install Codex
brew install --cask codex
Install the preferred stack
brew tap nvk/tap
brew install nvk/tap/agent-bondage
brew install nono
# Optional, for explicitly scoped API-key launches:
brew install nvk/tap/envchain-xtra
Observed on 2026-10-26: Codex 0.164.0, agent-bondage 0.3.1, envchain-xtra 1.4.1, and upstream nono 0.80.0. The last public end-to-end stack test used Nono 0.61.1, so validate the current profile schema and effective policy before promoting a 0.80 profile to daily use. Pull registry packs without copying an old version suffix from this guide.
Verify
codex --version
bondage --version
nono --version
envchain --help # prints the version header, if installed
2. nono Profile
Codex has its own internal sandbox, but nono adds kernel-level enforcement that the tool itself cannot bypass. In the preferred setup, bondage chooses the exact target and the selected external Codex profile before Codex starts.
What the sandbox allows
| Resource | Access | Why |
|---|---|---|
| Current working directory | Read + Write | Project files |
| Required OpenAI/sign-in endpoints | Network | Model calls and the selected authentication flow |
CODEX_HOME (normally ~/.codex/) | Bounded Read + Write | Config, authentication state, sessions, and installed plugin state |
/dev/tty, /dev/null | Read + Write | Terminal I/O |
/dev/urandom | Read | Crypto randomness |
3. Optional envchain-xtra
Codex supports ChatGPT sign-in and API-key operation. The preferred launcher path is still bondage + nono either way. Use envchain-xtra when you want an API key released from the OS secret store only for the launched process.
Store your API key
envchain --set codex OPENAI_API_KEY
API key vs OAuth
| Method | Credential storage | Recommendation |
|---|---|---|
| envchain + API key | macOS Keychain (encrypted) | Useful for explicit API-key launches and scoped secret release |
| ChatGPT sign-in | Codex-managed authentication state under CODEX_HOME |
Normal interactive account path; protect the state directory and grant only what the launcher needs |
4. bondage Wrapper
Add this thin wrapper to your shell config:
codex() {
bondage exec codex ~/.config/bondage/bondage.conf -- "$@"
}
Sample stack snippets
Assuming your shared [global] block already exists in ~/.config/bondage/bondage.conf, this is a minimal Codex shape to adapt:
# ~/.config/bondage/bondage.conf
[profile "codex"]
use_envchain = false
use_nono = true
nono_profile = codex-local
touch_policy = none
target_kind = native
target = /absolute/path/to/codex
target_fp = sha256:replace-me
nono_allow_cwd = true
nono_allow_file = /dev/tty
nono_allow_file = /dev/null
nono_read_file = /dev/urandom
env_set = GIT_TERMINAL_PROMPT=0
{
"extends": "codex",
"meta": {
"name": "codex-local",
"description": "Codex with project-only access"
},
"filesystem": {
"deny": ["/Volumes"]
},
"workdir": {
"access": "readwrite"
}
}
If you prefer an explicitly scoped API-key launch instead of ChatGPT sign-in, switch the profile to use_envchain = true and add namespace = codex.
How it works
- The shell wrapper passes only the profile name and your arguments
bondageverifies the exact Codex targetbondageapplies the externalnonoprofile- If configured for API-key mode,
bondagealso launches throughenvchain-xtra
Reload your shell:
source ~/.zshrc
5. Operational resilience
The most common failure is not “Codex broke.” It is that the launcher path quietly stopped being the thing your shell actually runs.
Keep home-shell bootstrap stable
Do not point ~/.zshrc straight at a repo symlink and hope it stays readable forever. Keep a tiny stable bootstrap file in $HOME and let it source the real repo-backed config if available.
# ~/.zshrc
if [ -r "$HOME/src-repo/.dotfiles/zsh/.zshrc" ]; then
. "$HOME/src-repo/.dotfiles/zsh/.zshrc"
elif [ -r "$HOME/src-repo/.dotfiles/ai/shell.zsh" ]; then
. "$HOME/src-repo/.dotfiles/ai/shell.zsh"
fi
Treat upgrades as launcher changes
If Homebrew or your package manager upgrades nono or Codex, re-verify the launcher stack. A stale pinned path is enough to strand the whole wrapper chain.
export BONDAGE_CONF="${BONDAGE_CONF:-$HOME/.config/bondage/bondage.conf}"
brew upgrade nono
brew cleanup nono
bondage --config "$BONDAGE_CONF" repin-globals
nono pull always-further/codex --force
nono list --installed
nono profile show "${NONO_PROFILE:-codex-local}" >/dev/null
bondage --config "$BONDAGE_CONF" verify codex
bondage --config "$BONDAGE_CONF" chain codex -- --help
After a Nono upgrade, pull the current signed pack, inspect its provenance and files, and validate your child profile before launching. Keep agent-created policy suggestions in the Nono draft-and-promote flow; do not let a sandboxed Codex session write active profile policy directly.
Keep repair access explicit
If you maintain several profiles, keep a named repair tier such as codex-fix. It should still be sandboxed, but broad enough to repair shell startup files, launcher config, hooks, and profile trees without dropping straight to rawdog.
Keep sandbox recovery out of Codex hooks
Codex hooks can be useful for deterministic checks, but hook output is model input. Do not inject nono recovery workflows through SessionStart or PostToolUse hooks. A hook that tells the agent to offer choices, wait, stop, or create a profile can derail the real task. Put normal path grants in the managed nono profile or bondage config, then restart Codex.
6. Verification
Test the full chain
# Should launch Codex normally
bondage verify codex ~/.config/bondage/bondage.conf
bondage chain codex ~/.config/bondage/bondage.conf -- --help
codex --help
Confirm the sandbox shape
export NONO_PROFILE="${NONO_PROFILE:-codex-local}"
for path in \
"$HOME/.ssh" \
"$HOME/.npmrc" \
"$HOME/.aws" \
"$HOME/Library/Keychains"
do
nono why --profile "$NONO_PROFILE" --path "$path" --op read
done
nono why --profile "$NONO_PROFILE" --path "$HOME/.config/nono/profiles" --op write
nono why --profile "$NONO_PROFILE" --path "$HOME/.config/nono/profile-drafts" --op write
Expected shape: credentials are denied, active profile writes are denied, and profile-drafts is writable only if your selected profile intentionally supports draft-and-promote profile edits.
Confirm no plaintext keys
# Should return nothing
grep -r "sk-proj\|sk-live" ~/.codex/ ~/.zshrc 2>/dev/null
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| "Invalid API key" | API-key mode selected but envchain namespace empty | envchain --set codex OPENAI_API_KEY |
| Codex starts without the expected profile | Running outside the wrapper | Launch through bondage exec codex ..., not the bare binary |
| Wrapper commands disappeared after a shell restart | Home shell startup depends on an unreadable sourced path | Use a tiny stable ~/.zshrc bootstrap and keep the real logic below it |
"Permission denied" on ~/.codex/ |
nono profile too restrictive | Add ~/.codex to the managed nono profile or bondage nono grants, rerun bondage verify/bondage chain, then restart Codex |
Wrapped launch broke after upgrading nono |
Launcher still pins an old package-manager path, or the Codex pack is stale | Run brew cleanup nono, bondage repin-globals, update always-further/codex, then rerun bondage verify |