# Codex Live Evidence Capture

## Status

Codex side of the v1 adapter-evidence gate: sufficient for the original
Codex CLI `0.122.0` capture and refreshed against Codex CLI `0.129.0` on
2026-05-09.

The committed fixture sets under `tests/fixtures/live_codex/` prove the Codex
hook surface Lifeloop depends on:

- `SessionStart` carries `session_id`, `transcript_path`, `cwd`,
  `hook_event_name`, `model`, `permission_mode`, and `source`.
- `UserPromptSubmit` carries the same session identity plus `turn_id` and
  `prompt`.
- `Stop` carries the same session and turn identity plus
  `stop_hook_active` and `last_assistant_message`.
- `Stop` output with `decision: "block"` continues the same Codex turn; the
  follow-up `Stop` input reports `stop_hook_active: true`.
- Lifeloop receipt synthesis for the captured Codex `frame.opening` shape
  validates as a `delivered` receipt.

The 0.129 refresh changes the lifecycle picture relative to 0.122:

- The canonical feature key is `[features].hooks = true`. Lifeloop does not
  treat the old `[features].codex_hooks = true` key as an installed-current
  config.
- User hooks are discovered but do not run until Codex hook state stores the
  current trusted hash. Managed hooks are trusted by Codex.
- `PreCompact` and `PostCompact` are now in Codex's hook registry. Lifeloop
  maps `PreCompact` to `context.pressure_observed` and `PostCompact` to
  `context.compacted`.
- `SessionEnd` remains unavailable in Codex's hook surface. `frame.opened`
  remains synthesized because Codex exposes prompt submission, not a separate
  post-open hook.

## Recapture Procedure

Use a disposable Codex home so no local credentials, logs, plugin state, or
operator paths are committed.

```bash
TMP="$(mktemp -d /tmp/lifeloop-codex-capture.XXXXXX)"
CODEX_HOME_CAPTURE="$TMP/codexhome"
WORK="$TMP/work"
mkdir -p "$CODEX_HOME_CAPTURE" "$WORK" "$TMP/hooks" "$TMP/capture"
git -C "$WORK" init -q
cp "$HOME/.codex/auth.json" "$CODEX_HOME_CAPTURE/auth.json"
```

Create `$CODEX_HOME_CAPTURE/config.toml`:

```toml
model = "gpt-5.4-mini"

[features]
hooks = true

[projects."<WORK>"]
trust_level = "trusted"
```

Replace `<WORK>` with the absolute `$WORK` path. Create
`$CODEX_HOME_CAPTURE/hooks.json` with `SessionStart`, `UserPromptSubmit`,
`PreCompact`, `PostCompact`, and `Stop` handlers. For Codex 0.129+, inspect
the hooks through the app-server `hooks/list` RPC or approve them in the TUI,
then persist each current hash under `[hooks.state]` before running
`codex exec`; otherwise user hooks are visible but skipped as untrusted. The
`Stop` handler should return `decision: "block"` once so the run captures
block-as-continuation.

Run:

```bash
CODEX_HOME="$CODEX_HOME_CAPTURE" \
  codex exec --json --cd "$WORK" --sandbox read-only --model gpt-5.4-mini \
  'Reply exactly: lifeloop first ok' \
  > "$TMP/codex-events.jsonl" \
  2> "$TMP/codex-stderr.txt"
```

Sanitize before committing:

- Replace `session_id` and `thread_id` with `codex-live-session-001`.
- Replace `turn_id` with `codex-live-turn-001`.
- Replace `transcript_path` and `cwd` with `/tmp/lifeloop-codex-live/...`.
- Replace token counts with `"sanitized"`.
- Do not commit `auth.json`, SQLite files, plugin cache, raw transcript logs,
  or stderr.
- Preserve hook field names, `hook_event_name`, `source`, `prompt`,
  `stop_hook_active`, `last_assistant_message`, and hook outputs.

After refreshing fixtures, run:

```bash
cargo test --test manifest_claims codex_
```
