Codex CLI
← Back to labs index

Codex CLI

Lab Exercise Codex capability
0 Setup Foundry provider and auth
1 Constrained baseline Built-in loop (not a bare call)
2A Tool loop Built-in shell tool
2B Hooks and policy Command rules and policy limits
3 Sessions Resume
4 Planning Plan-then-execute
5 File memory Files and session scope
6 Approval Sandbox and human approval
7 Observability JSON events and usage
8 Skills and MCP Skills and MCP registration
9 Delegation Child agents
10 Compaction Built-in context management
11 Loops Explicit bounded validation
12 Graphs Manual routing (no native graph claim)
13 Capstone Planner / generator / evaluator
14 Comparison Control and provenance

The exercises use a separate CODEX_HOME and do not change your usual Codex configuration. Use a Foundry GPT deployment that supports the Responses API. Each lab can be run independently: use that lab’s own configuration example and workspace; never import or copy material from another lab folder. Instructions were checked against Codex CLI 0.159.3. Recheck codex --help and codex exec --help on your installed version. Live runs cost money and require learner-provisioned credentials; no live Foundry assertions are made by this repository.

Workspace and preflight

Every lab includes workspace/ with only a tracked .gitkeep; generated contents are gitignored. Comparison labs also include workspace-b/. These folders make paths predictable, not an OS isolation boundary. Codex can inherit parent AGENTS.md, discover skills, and access other readable files. Run write drills only on synthetic data; use an isolated account/container when real host files must be protected.

Start each lab’s commands in that lab’s directory, not the track root or a previous workspace. Run the following preflight in your chosen shell for every lab (and before a completely fresh attempt):

$labdir = (Get-Location).Path
$workdir = Join-Path $labdir 'workspace'
$env:CODEX_HOME = Join-Path ([IO.Path]::GetTempPath()) ("codex-lab-" + [guid]::NewGuid())
New-Item -ItemType Directory -Path $env:CODEX_HOME | Out-Null
Copy-Item .\config.toml.example (Join-Path $env:CODEX_HOME 'config.toml')
labdir="$PWD"
workdir="$labdir/workspace"
export CODEX_HOME="$(mktemp -d)"
chmod 700 "$CODEX_HOME"
cp ./config.toml.example "$CODEX_HOME/config.toml"

Edit this temporary config, setting your deployment and endpoint (/openai/v1). Keep credentials out of it. Use a fresh CODEX_HOME for each lab; keep the same home for that lab’s resume exercise. Resetting a workspace does not erase session history in CODEX_HOME.

Load your own resource API key into AZURE_OPENAI_API_KEY via a secret manager; env_key in the config names that variable. The Microsoft Foundry Codex guide currently says Entra ID is not supported for Codex; do not pass an Entra token in place of a key. Never write the key to a lab file, terminal transcript, or commit. For noninteractive runs use --sandbox read-only unless a lab explicitly requires disposable local writes. A read-only sandbox restricts writes; it does not disable tools, network access, the model’s built-in agent loop, or all connectors. It is not a confidentiality boundary for other readable host files or environment variables. Use a separate disposable account/container for sensitive environments, and do not give Codex access to real customer data.

Use only synthetic data and disposable directories. Do not grant access to real customer data, live Azure resources, or privileged credentials. After each lab, reset the disposable workspace, remove CODEX_HOME and unset the credential. Record unsupported metrics as unavailable, not zero.

On Windows, enter the key without putting its literal value in history:

$secureKey = Read-Host 'Azure OpenAI API key' -AsSecureString
$env:AZURE_OPENAI_API_KEY = [Net.NetworkCredential]::new('', $secureKey).Password
$secureKey.Dispose()
Remove-Variable secureKey

In bash, use a secret manager or a hidden prompt:

read -r -s -p 'Azure OpenAI API key: ' AZURE_OPENAI_API_KEY
printf '\n'
export AZURE_OPENAI_API_KEY

The key is available to processes launched from this shell, not other already-running terminals. Never print it. In the temporary config, add the following to keep the key out of model-launched shell tools (Codex itself still needs the environment variable for provider authentication):

[shell_environment_policy]
exclude = ["AZURE_OPENAI_API_KEY"]

Native Windows prerequisite

Native Windows learners need a functioning Windows sandbox before the file/tool exercises. A successful model reply alone does not verify that shell tools can read the fixtures. Follow the official Windows sandbox guide. In each temporary Windows config, select the preferred implementation:

[windows]
sandbox = "elevated"

Launch interactive codex -C "$workdir" --sandbox read-only. Complete the offered sandbox setup. Newer versions expose /setup-default-sandbox inside Codex, not PowerShell; check the / menu rather than assuming that command exists (it is not available in 0.157.0). Administrator approval may be required to create the low-privilege sandbox users and configure firewall/local policy. Normal lab sessions do not need to run the terminal as administrator. Check setup whenever you create a new private CODEX_HOME; the CLI may need to provision sandbox state for that home again.

If your organization disallows elevated setup, ask IT or use WSL with its Linux prerequisites. The documented unelevated Windows fallback has weaker isolation and should be an explicit learner/administrator decision, not an automatic downgrade. Do not fix blocked by policy errors by disabling the sandbox or blanket-allowing commands. Follow Lab 0’s file-read check before progressing. macOS/Linux/WSL learners do not need this Windows-specific setup.

If an embedded terminal reports host Job Object prevents daemon detachment, rerun the interactive command with --no-daemon, as the CLI error instructs, for example codex --no-daemon -C "$workdir" --sandbox read-only. This keeps the app server attached to the session; it does not disable the sandbox. Check your installed version’s help/error before using this compatibility option.

Reset and cleanup

Exit Codex first. From existing-harnesses/codex-cli/, reset only the lab you are about to rerun. These scripts prompt before deleting contents:

.\scripts\reset-workspace.ps1 -Lab lab08-skills-tools
.\scripts\reset-workspace.ps1 -Lab lab08-skills-tools -Second
bash ./scripts/reset-workspace.sh lab08-skills-tools
bash ./scripts/reset-workspace.sh lab08-skills-tools --second

They preserve .gitkeep, reject unknown lab names and linked workspaces, and do not modify other labs or your usual Codex home. Reset both folders before a comparison; use a new codex exec invocation for a fresh context, not resume. Where a lab asks for no project instructions, also pass -c project_doc_max_bytes=0 to disable inherited AGENTS.md loading.

At the end of a lab, unset the credential and remove only the private home created by the preflight above (check the printed path before deleting):

Remove-Item Env:\AZURE_OPENAI_API_KEY -ErrorAction SilentlyContinue
$env:CODEX_HOME
# Only after verifying this is the temporary codex-lab-<guid> directory:
Remove-Item -LiteralPath $env:CODEX_HOME -Recurse -Force
Remove-Item Env:\CODEX_HOME
unset AZURE_OPENAI_API_KEY
printf '%s\n' "$CODEX_HOME"
# Only after verifying this is the temporary directory created above:
rm -r -- "$CODEX_HOME"
unset CODEX_HOME

Clear generated fixtures and handoffs with the reset helper. Do not delete the lab folder or repository. Re-run preflight for the next lab.