387 lines
7.8 KiB
Markdown
387 lines
7.8 KiB
Markdown
# Codex CLI
|
|
|
|
Automate code, bash scripting, web research with clean output.
|
|
|
|
## Install
|
|
|
|
```bash
|
|
npm install -g @openai/codex
|
|
codex --version
|
|
```
|
|
|
|
## Config
|
|
|
|
`~/.codex/config.toml`:
|
|
```toml
|
|
model = "gpt-5-codex"
|
|
model_reasoning_effort = "high"
|
|
approval_policy = "never"
|
|
sandbox_mode = "workspace-write"
|
|
web_search = true
|
|
```
|
|
|
|
## Commands
|
|
|
|
**Interactive:** Real-time development
|
|
```bash
|
|
codex "Create a Python REST API"
|
|
```
|
|
|
|
**Exec:** Automation
|
|
```bash
|
|
codex exec "Task" --full-auto
|
|
```
|
|
|
|
---
|
|
|
|
## Bash Scripting
|
|
|
|
### Basic
|
|
```bash
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
cd /tmp/project
|
|
git init && git config user.email "bot@example.com" && git config user.name "Bot"
|
|
|
|
codex exec "Your task" --full-auto
|
|
```
|
|
|
|
### With Clean Output
|
|
```bash
|
|
codex exec "Your task" --full-auto --output-last-message /tmp/result.txt
|
|
cat /tmp/result.txt
|
|
```
|
|
|
|
### Idempotent
|
|
```bash
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
log() { printf '[%s] %s\n' "$(date +%H:%M:%S)" "$*"; }
|
|
ensure_tool() { command -v "$1" >/dev/null || { log "install $1"; exit 1; }; }
|
|
|
|
case "${1:-help}" in
|
|
bootstrap)
|
|
ensure_tool jq
|
|
[[ -f .ready ]] || { ./setup.sh && touch .ready; }
|
|
;;
|
|
ci)
|
|
for step in lint test build; do
|
|
log "running $step"
|
|
./scripts/$step.sh || exit 1
|
|
done
|
|
;;
|
|
watch)
|
|
ensure_tool entr
|
|
find src -type f | entr -r bash -lc './scripts/test.sh'
|
|
;;
|
|
*)
|
|
printf 'usage: %s {bootstrap|ci|watch}\n' "$0" >&2; exit 64
|
|
;;
|
|
esac
|
|
```
|
|
|
|
### Git Checkpoint
|
|
```bash
|
|
#!/bin/bash
|
|
set -euo pipefail
|
|
|
|
git add . && git commit -m "Before Codex" || true
|
|
|
|
codex exec "Run tests and fix failures" --full-auto || {
|
|
git reset --hard HEAD~1
|
|
exit 1
|
|
}
|
|
|
|
git add . && git commit -m "Codex: Fixed" || true
|
|
```
|
|
|
|
### Batch
|
|
```bash
|
|
#!/bin/bash
|
|
for project in project1 project2 project3; do
|
|
(
|
|
cd "$project"
|
|
git init && git config user.email "bot@example.com" && git config user.name "Bot" || true
|
|
|
|
if codex exec "Update dependencies" --full-auto; then
|
|
git add . && git commit -m "Updated" --allow-empty || true
|
|
echo "✓ $project"
|
|
else
|
|
git reset --hard HEAD~1
|
|
echo "✗ $project"
|
|
fi
|
|
)
|
|
done
|
|
```
|
|
|
|
---
|
|
|
|
## Web Search
|
|
|
|
Enable with `-c web_search=true`.
|
|
|
|
### Research with JSON
|
|
```bash
|
|
#!/bin/bash
|
|
cd /tmp/research
|
|
git init && git config user.email "bot@example.com"
|
|
|
|
task="Find top 3 bash patterns. Return ONLY valid JSON with: pattern, description, code_example."
|
|
|
|
codex exec "$task" \
|
|
-c web_search=true \
|
|
--full-auto \
|
|
--output-last-message /tmp/result.json
|
|
|
|
cat /tmp/result.json | jq .
|
|
```
|
|
|
|
### View Searches
|
|
```bash
|
|
codex exec "Research bash best practices" \
|
|
-c web_search=true \
|
|
--full-auto \
|
|
--json 2>/dev/null | \
|
|
jq -r 'select(.type=="web_search") | .item.query'
|
|
```
|
|
|
|
### View Reasoning
|
|
```bash
|
|
codex exec "Research X" \
|
|
-c web_search=true \
|
|
--full-auto \
|
|
--json 2>/dev/null | \
|
|
jq -r 'select(.type=="reasoning") | .item.text'
|
|
```
|
|
|
|
---
|
|
|
|
## Output Control
|
|
|
|
**`--output-last-message FILE`** - Writes final answer to FILE only.
|
|
|
|
```bash
|
|
codex exec "Task" --full-auto --output-last-message /tmp/answer.txt
|
|
cat /tmp/answer.txt
|
|
```
|
|
|
|
Result:
|
|
- FILE: Clean plaintext answer
|
|
- STDOUT: 5 lines metadata
|
|
- STDERR: Empty
|
|
|
|
**`--json`** - JSONL events: thread.started, turn.started, reasoning, web_search, agent_message, turn.completed.
|
|
|
|
```bash
|
|
codex exec "Task" --full-auto --json 2>/dev/null | jq '.type' | sort | uniq -c
|
|
```
|
|
|
|
**Suppress console:** Redirect to /dev/null
|
|
```bash
|
|
codex exec "Task" --full-auto --output-last-message /tmp/answer.txt >/dev/null 2>&1
|
|
cat /tmp/answer.txt
|
|
```
|
|
|
|
**Save audit log + clean output:**
|
|
```bash
|
|
codex exec "Task" --full-auto \
|
|
--output-last-message /tmp/answer.txt \
|
|
--json >/tmp/audit.jsonl 2>&1
|
|
cat /tmp/answer.txt
|
|
```
|
|
|
|
---
|
|
|
|
## Python
|
|
|
|
### Simple
|
|
```python
|
|
import subprocess
|
|
|
|
result = subprocess.run(
|
|
['codex', 'exec', 'Create test module', '--full-auto'],
|
|
cwd='/tmp/project',
|
|
capture_output=True,
|
|
text=True
|
|
)
|
|
|
|
print(result.stdout)
|
|
```
|
|
|
|
### Wrapper
|
|
```python
|
|
from dataclasses import dataclass
|
|
from typing import Optional
|
|
import subprocess
|
|
import os
|
|
|
|
@dataclass
|
|
class CodexResult:
|
|
returncode: int
|
|
stdout: str
|
|
stderr: str
|
|
task: str
|
|
|
|
@property
|
|
def success(self) -> bool:
|
|
return self.returncode == 0
|
|
|
|
class CodexCLI:
|
|
def __init__(self, model="gpt-5-codex", web_search=False):
|
|
self.model = model
|
|
self.web_search = web_search
|
|
|
|
def execute(self, task: str, cwd: Optional[str] = None) -> CodexResult:
|
|
output_file = f"/tmp/codex-{os.urandom(4).hex()}.txt"
|
|
|
|
cmd = [
|
|
'codex', 'exec', task,
|
|
'--full-auto',
|
|
'-m', self.model,
|
|
'--output-last-message', output_file
|
|
]
|
|
|
|
if self.web_search:
|
|
cmd.extend(['-c', 'web_search=true'])
|
|
|
|
result = subprocess.run(
|
|
cmd,
|
|
cwd=cwd or os.getcwd(),
|
|
capture_output=True,
|
|
text=True
|
|
)
|
|
|
|
try:
|
|
with open(output_file) as f:
|
|
output = f.read()
|
|
os.unlink(output_file)
|
|
except:
|
|
output = result.stdout
|
|
|
|
return CodexResult(
|
|
returncode=result.returncode,
|
|
stdout=output,
|
|
stderr=result.stderr,
|
|
task=task
|
|
)
|
|
|
|
# Usage
|
|
codex = CodexCLI(web_search=True)
|
|
result = codex.execute("Research X")
|
|
print(result.stdout)
|
|
```
|
|
|
|
---
|
|
|
|
## Flags
|
|
|
|
| Flag | Purpose |
|
|
|------|---------|
|
|
| `--full-auto` | Auto-approve, workspace-write sandbox |
|
|
| `-c web_search=true` | Enable web search |
|
|
| `--output-last-message FILE` | Write final answer to FILE |
|
|
| `--json` | Stream JSONL events |
|
|
| `-m, --model` | gpt-5 (fast), gpt-5-codex (code), o3 (powerful) |
|
|
| `-C, --cd` | Working directory |
|
|
|
|
---
|
|
|
|
## Patterns
|
|
|
|
**Research + JSON**
|
|
```bash
|
|
codex exec "Find X. Return JSON with: pattern, description, code." \
|
|
-c web_search=true --full-auto --output-last-message /tmp/result.json
|
|
```
|
|
|
|
**Batch docs**
|
|
```bash
|
|
for module in auth utils data; do
|
|
codex exec "Generate API docs for $module.py" \
|
|
--full-auto --output-last-message "/tmp/${module}_docs.md"
|
|
done
|
|
```
|
|
|
|
**Research → Generate → Commit**
|
|
```bash
|
|
codex exec "Research Python testing best practices 2025" \
|
|
-c web_search=true --full-auto --output-last-message /tmp/research.txt
|
|
|
|
codex exec "Using this research, generate test suite for module.py" --full-auto
|
|
|
|
git add . && git commit -m "Generated tests from latest best practices"
|
|
```
|
|
|
|
---
|
|
|
|
## Performance
|
|
|
|
| Task | Time | Success |
|
|
|------|------|---------|
|
|
| Simple | 30-60s | 99%+ |
|
|
| Web search | 60-120s | 95%+ |
|
|
| Complex | 120+s | 90%+ |
|
|
|
|
**Models:**
|
|
- `gpt-5`: Fast, cheap
|
|
- `gpt-5-codex`: Default, code-optimized
|
|
- `o3`: Powerful, slow
|
|
|
|
---
|
|
|
|
## Security
|
|
|
|
**Safe:**
|
|
- `workspace-write` sandbox (default)
|
|
- Git checkpoints before Codex
|
|
- Validate generated code
|
|
|
|
**Avoid:**
|
|
- `danger-full-access` without external sandboxing
|
|
- Running without git checkpoints
|
|
- Web search on untrusted domains
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
| Problem | Solution |
|
|
|---------|----------|
|
|
| `codex not found` | `npm install -g @openai/codex` |
|
|
| Not in trusted directory | `git init` in working directory |
|
|
| Web search returns nothing | Rephrase as task ("Find X"), not question |
|
|
| Too much output | Use `--output-last-message FILE` |
|
|
| Can't parse output | Use `--json` with `jq` |
|
|
| Auth failed | `codex login` or set `OPENAI_API_KEY` |
|
|
|
|
---
|
|
|
|
## Quick Reference
|
|
|
|
```bash
|
|
# Basic
|
|
codex exec "Task" --full-auto
|
|
|
|
# Web search
|
|
codex exec "Research X" -c web_search=true --full-auto
|
|
|
|
# Clean output
|
|
codex exec "Task" --full-auto --output-last-message /tmp/out.txt
|
|
|
|
# View searches
|
|
codex exec "Task" -c web_search=true --full-auto --json 2>/dev/null | \
|
|
jq -r 'select(.type=="web_search") | .item.query'
|
|
|
|
# Token usage
|
|
codex exec "Task" --full-auto --json 2>/dev/null | \
|
|
jq 'select(.type=="turn.completed") | .usage'
|
|
|
|
# Different model
|
|
codex exec "Task" -m o3 --full-auto
|
|
|
|
# Specific directory
|
|
codex exec "Task" -C /path/to/project --full-auto
|
|
```
|