DaddyNote

UK, Irish and EU money and travel rules, worked through step by step, with the date each figure was checked.

AI how-to notes · 2026-09-17 · last run 2026-09-17 · 한국어 원문

Writing codex exec results to a file — -o and --json measured on Windows (Codex CLI)

One line summary

If you only need the final answer from codex exec, use -o FILE; if you want the whole run in machine-readable form, use --json > FILE. The two work together. In this round, pointing -o at a directory that did not exist made the file write fail while the exit code was still 0 — so check the result separately.

Who this is for

Test environment

ItemValue
OSWindows 11 Home (10.0.26200)
ShellsGit Bash, PowerShell 7.6.6
codexcodex-cli 0.153.4
Model (as shown in the run banner)gpt-6-astra
PromptReply with the single word OK. (identical in every round)
Shared options-s read-only --skip-git-repo-check (Git Bash rounds 1–4 closed stdin with < /dev/null)

This note has no comparison for the case where stdin is left open. The runs where codex exec never finished because stdin was attached to a pipe, the way an agent shell leaves it, are written up separately in codex exec hangs waiting on stdin.

The options in the help text

Two lines from codex exec --help matter here.

      --json
          Print events to stdout as JSONL

  -o, --output-last-message <FILE>
          Specifies file where the last message from the agent should be written

--json is not a file option. It goes to standard output, so redirect it with > if you want it in a file.

1. Getting only the final answer with -o

codex exec -s read-only --skip-git-repo-check -o last.txt "Reply with the single word OK." < /dev/null

Exit code 0, 8.4 seconds. The output splits in two: standard output carried only the answer OK, and the banner and the progress log all went to standard error.

Reading additional input from stdin...
OpenAI Codex v0.153.4
--------
workdir: C:\Users\User\AppData\Local\Temp\longtail_A\exec
model: gpt-6-astra
provider: openai
approval: never
sandbox: read-only
...
codex
OK
tokens used
6,707

last.txt was 2 bytes. There is no trailing newline, so wc -l counts it as 0 lines.

0 2 last.txt
--- cat -A ---
OK

cat -A shows no end-of-line marker ($) either. Worth knowing if your script concatenates this file onto another one, or judges success by line count.

2. Getting every event with --json

codex exec -s read-only --skip-git-repo-check --json "Reply with the single word OK." < /dev/null > events.jsonl

Exit code 0, 6.1 seconds. Standard error held only the one Reading additional input from stdin... line; no banner. The file was 4 lines, 345 bytes.

{"type":"thread.started","thread_id":"01a0ae78-dd26-7ce2-8b79-6da03f94ac20"}
{"type":"turn.started"}
{"type":"item.completed","item":{"id":"item_0","type":"agent_message","text":"OK"}}
{"type":"turn.completed","usage":{"input_tokens":18453,"cached_input_tokens":12416,"cache_write_input_tokens":0,"output_tokens":5,"reasoning_output_tokens":0}}

The answer lives in text on the line whose type is item.completed and whose item.type is agent_message. Token usage sits in usage on the final turn.completed line.

command -v jq printed no path in the shell we ran this from, so we pulled the answer out with Node.

node -e 'const fs=require("fs");for(const l of fs.readFileSync("events.jsonl","utf8").split(/\r?\n/)){if(!l)continue;const e=JSON.parse(l);if(e.type==="item.completed"&&e.item.type==="agent_message")console.log(e.item.text)}'
OK

3. Using both at once

codex exec -s read-only --skip-git-repo-check --json -o both_last.txt "Reply with the single word OK." < /dev/null > both_events.jsonl

Exit code 0. both_last.txt was 2 bytes of OK and both_events.jsonl was 4 lines and 345 bytes — the same shapes as sections 1 and 2, produced in a single run.

4. In PowerShell 7

codex exec -s read-only --skip-git-repo-check --json -o ps_last.txt "Reply with the single word OK." > ps_events.jsonl
"codex exit=$LASTEXITCODE"
Get-Content ps_events.jsonl | ForEach-Object { $_ | ConvertFrom-Json } |
  Where-Object { $_.type -eq 'item.completed' } | ForEach-Object { $_.item.text }

We ran this script with pwsh -NoProfile -File. We did not record what state stdin was in outside it. We got codex exit=0, a 2-byte ps_last.txt, and OK extracted from a 4-line ps_events.jsonl. The first 3 bytes of the file were 7B 22 74 ({"t), so no BOM.

The sizes differed. Same 4 lines, but the PowerShell file was 349 bytes. We counted CR characters.

CR count:
events.jsonl 0
ps_events.jsonl 4

Only the PowerShell round's file had CR characters — 4 of them — and it was 4 bytes larger than the Git Bash one. This record alone can't settle whether PowerShell's > changed the line endings. Either way, anything reading the JSONL that splits on \n alone will be left with a trailing \r, so splitting on /\r?\n/ like the Node example above is the safer habit. The -o file was 2 bytes in both shells.

Results

RoundShellOptionsExit codeTimeFiles produced
1Git Bash-o last.txt08.4slast.txt 2 bytes, 0 lines (no newline)
2Git Bash--json > events.jsonl06.1s4 lines, 345 bytes
3Git Bash--json -o together08.4s2 bytes + 4 lines, 345 bytes
4Git Bash-o nodir/last.txt (directory does not exist)06.1snone
5PowerShell 7--json -o together08.3s2 bytes + 4 lines, 349 bytes (4 CRs)

What failed

Round 4 is the part of this note to be careful about. We gave -o a directory that did not exist; the answer still came out on standard output as OK, but the file write failed. This line appeared on standard error only (this PC runs Korean-locale Windows, so the OS error text is in Korean — it reads "the specified path could not be found").

Failed to write last message file "nodir/last.txt": 지정된 경로를 찾을 수 없습니다. (os error 3)

And codex's exit code was still 0 (codex exit=0). That status alone cannot establish a successful save. The earlier suggestion, test -s ... || echo ..., can also print an error and still exit 0; an old file can make it pass incorrectly.

Newly checked — 2026-09-28

Save the complete Bash example verify-new-output.sh in the current directory, then run it. It requires Bash, mktemp, cmp, and an installed, authenticated Codex CLI.

bash verify-new-output.sh output

The script creates a new directory with mktemp -d ./codex-check.XXXXXXXX, enters it, and requests OK with -o last.txt. It preserves any nonzero Codex exit code. Even after exit 0, it requires a new regular last.txt (not a symbolic link) and uses cmp to check exactly two bytes, OK, with no newline; failure exits 1. Only success prints verified: <new directory>/last.txt. The directory is left for inspection; existing files are neither overwritten nor deleted. For a real prompt, replace the fixed OK check with the expected content or format for that task.

The new verification tested the shell guard with a mock producer, not Codex. On Linux with Bash 5.2.21, correct contents returned 0; missing, empty, wrong, newline-suffixed, and symbolic-link outputs each returned 1. A producer that wrote a correct file but exited 37 propagated 37. A stale OK file in the parent directory did not make the missing-output case pass, and every run used a different new directory. This environment has no Codex binary, login, or Windows, so actual -o behavior was not retested. The 2026-09-17 measurements above are preserved.

What we did not test

Related notes

Corrected 2026-09-28: The extraction code in section 2 was reading both_events.jsonl, a file that is not created until section 3. Fixed it to read events.jsonl, the file section 2 actually creates.