Skip to content

Review commands start ephemeral threads, so Codex usage from them is unattributable #675

Description

@Summit240

Plugin version: 1.0.6 (db52e28, tag v1.0.6)
Codex CLI: 0.147.0
Platform: Windows 11

Summary

/codex:review and /codex:adversarial-review start their app-server threads with
ephemeral: true. Ephemeral threads are never written to ~/.codex/sessions/**/*.jsonl and never
registered in ~/.codex/state_5.sqlite, so a review leaves no durable record that it ran — no
rollout to resume from, nothing in codex resume, and nothing for usage/cost tooling to attribute.

/codex:rescue (task) is unaffected: it is the only caller that opts into persistence.

Entry point Path Thread Durable record
/codex:rescue, task runAppServerTurn + persistThread: true persisted yes
/codex:review runAppServerReview ephemeral no
/codex:adversarial-review runAppServerTurn, no persistThread ephemeral no

Where it comes from

plugins/codex/scripts/lib/codex.mjs:

  • L70 — buildThreadParams: ephemeral: options.ephemeral ?? true (default for every thread/start)
  • L1013 — runAppServerReview: ephemeral: true, hardcoded, no way to override
  • L1109 — thread/resume: ephemeral: false
  • L1117 — runAppServerTurn: ephemeral: options.persistThread ? false : true

plugins/codex/scripts/codex-companion.mjs:

  • L493 — executeTaskRun passes persistThread: true (the only opt-in in the codebase)
  • L411 — executeReviewRun, adversarial branch, calls runAppServerTurn without
    persistThread, so it inherits the ephemeral default

There is no environment variable, CLI flag, or plugin setting that changes this. ephemeral occurs
at exactly those four lines and nowhere else in the plugin.

Reproduce

  1. In a git repo, run /codex:adversarial-review (or /codex:review) and let it finish.
  2. ls ~/.codex/sessions/**/*.jsonl — no new rollout.
  3. Query ~/.codex/state_5.sqlite: select id, cwd, created_at from threads order by created_at desc limit 5;
    — the review's thread id is absent.
  4. Grep ~/.codex/logs_2.sqlite for the thread id — the run is there, including
    token usage turn_id=... total_usage_tokens=.... Trace logs are the only surviving evidence.

Observed here: an adversarial review ran 2026-08-22 03:51–03:53 (thread
01a0272a-d8c5-73e0-a8fd-bc1e1fefbfa8, gpt-5.6-sol, ~18k tokens and climbing). Nothing in
sessions/, nothing in threads. A task run on 2026-08-14 in the same ~/.codex persisted
normally, which is what isolated the difference.

Why it matters

  1. Usage attribution. Anything that reconciles Codex spend by reading rollouts — internal
    chargeback, per-repo cost reporting, seat justification — silently undercounts, and reviews are
    a large share of real plugin usage. The failure is invisible: no error, no partial record.
  2. No resume or audit trail. A long adversarial review that produces a finding you want to
    revisit cannot be resumed or re-read; only the rendered output in the Claude Code transcript
    survives.
  3. Asymmetry is surprising. task persists, review does not, and nothing in the docs or command
    help says so.

Suggested fix

Either of:

  • Persist by default. Drop ephemeral: true at L1013 and pass persistThread: true from
    executeReviewRun (L411). Reviews are user-initiated, named, and scoped to a repo — the same
    things that justify persisting task threads.
  • Expose an opt-in. Add --persist to the review commands (and/or honour a
    CODEX_PLUGIN_PERSIST_THREADS=1 env var) threaded through to buildThreadParams.

The first is preferable — an opt-in that defaults off leaves the accounting gap in place for
everyone who does not know to look for it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions