Summary
On macOS, Codex Desktop 26.623.61825 / embedded codex-cli 0.142.3 still persists high-frequency TRACE logs into the local SQLite feedback log database (~/.codex/logs_2.sqlite) and its WAL during normal use, even though the app-server process has RUST_LOG=warn.
This is not a cosmetic/UI issue. The concern is persistent diagnostic logging causing unnecessary local disk I/O, SQLite/WAL churn, and possible retention of detailed runtime data.
Related reports include #17320, #28224, #29532, #29814, and #30405. I am opening this as a fresh current-version macOS data point.
Environment
- OS: macOS 26.5.1, arm64
- Codex.app:
26.623.61825, build 4548
- Embedded CLI:
codex-cli 0.142.3
codex doctor: reports 0.142.4 available, current 0.142.3
- App-server command:
/Applications/Codex.app/Contents/Resources/codex app-server --analytics-default-enabled
- App-server environment includes:
RUST_LOG=warn
- Log database:
~/.codex/logs_2.sqlite
- SQLite journal mode:
wal
Observed behavior before workaround
The active log database was already large:
logs_2.sqlite ~406 MiB
logs_2.sqlite-wal ~4.5 MiB
A live SQLite inspection showed a large TRACE share:
MAX(id): 41,863,047
retained rows: 381,734
TRACE rows: 289,408
non-TRACE rows: 92,326
Recent rows were dominated by TRACE logs:
Recent 5000 rows by level:
TRACE 4070
INFO 464
DEBUG 416
WARN 50
Representative recent TRACE targets were low-level protocol/dependency logs, for example:
h2::proto::streams::flow_control
h2::proto::streams::recv
h2::proto::connection
h2::codec::framed_read
log
A later aggregate over recent TRACE rows showed these targets as the largest groups:
TRACE codex_api::sse::responses 2431
TRACE log 1439
TRACE codex_mcp::connection_manager 432
TRACE h2::codec::framed_read 137
TRACE h2::proto::streams::recv 73
TRACE h2::proto::streams::prioritize 65
TRACE h2::proto::connection 61
TRACE codex_core::session::turn 59
TRACE codex_api::endpoint::responses_websocket 59
TRACE codex_core::client 55
During inspection, MAX(id) and the latest row ids continued advancing, which indicates ongoing insert churn rather than a static old database. I am not pasting raw feedback_log_body values because they may contain private session, tool, path, or protocol data.
Temporary workaround used locally
I first installed a TRACE-only trigger to confirm the source of churn:
CREATE TRIGGER ignore_trace_logs_insert
BEFORE INSERT ON logs
WHEN upper(NEW.level) = 'TRACE'
BEGIN
SELECT RAISE(IGNORE);
END;
After that, TRACE stopped growing:
max_trace_id: 41,880,082 -> 41,880,082
WAL bytes: 4,684,472 -> 4,684,472
sample gap: ~8 seconds
However, MAX(id) still advanced slightly from non-TRACE DEBUG/INFO inserts:
MAX(id): 41,880,426 -> 41,880,432
To stop all persistent log-table writes temporarily, I then used an all-insert trigger:
CREATE TRIGGER ignore_logs_insert
BEFORE INSERT ON logs
BEGIN
SELECT RAISE(IGNORE);
END;
That fully stopped growth over the verification window:
MAX(id): 41,880,471 -> 41,880,471
rows: 382,004 -> 382,004
TRACE rows: 289,271 -> 289,271
max TRACE id: 41,880,082 -> 41,880,082
sqlite_seq: 41,880,471 -> 41,880,471
WAL bytes: 4,684,472 -> 4,684,472
sample gap: ~12 seconds
This workaround is not a product fix and it disables useful local diagnostics. It only demonstrates that the persistent logs table is the write path causing the observed churn.
Expected behavior
Production Codex Desktop builds should not persist high-frequency frame-level/dependency-level TRACE logs into logs_2.sqlite by default, especially when the app-server process has RUST_LOG=warn.
Expected improvements:
- The SQLite feedback log sink should honor the effective runtime log-level filter, or expose a separate documented persisted-log-level setting.
- Low-value
TRACE targets such as log, h2::*, websocket/SSE frame logs, and dependency internals should be suppressed, sampled, summarized, or bounded by default.
- Local diagnostic logs should have clear size/write caps, retention/rotation, and WAL checkpoint/truncation behavior.
- Users should have a documented way to reduce or disable persistent diagnostic logs without disabling durable Codex state.
Reproduction sketch
- Start Codex Desktop on macOS.
- Confirm the app-server process has
RUST_LOG=warn.
- Use Codex normally in an active thread.
- Inspect
~/.codex/logs_2.sqlite and ~/.codex/logs_2.sqlite-wal.
- Sample
MAX(id), row counts by level, recent targets, and WAL size/mtime over a short interval.
- Observe continuing TRACE-heavy inserts into the persistent SQLite log table during normal use.
Privacy note
I am intentionally not attaching logs_2.sqlite or raw log bodies. They may contain private conversation text, local paths, tool output, or protocol payload fragments.
Summary
On macOS, Codex Desktop
26.623.61825/ embeddedcodex-cli 0.142.3still persists high-frequencyTRACElogs into the local SQLite feedback log database (~/.codex/logs_2.sqlite) and its WAL during normal use, even though the app-server process hasRUST_LOG=warn.This is not a cosmetic/UI issue. The concern is persistent diagnostic logging causing unnecessary local disk I/O, SQLite/WAL churn, and possible retention of detailed runtime data.
Related reports include #17320, #28224, #29532, #29814, and #30405. I am opening this as a fresh current-version macOS data point.
Environment
26.623.61825, build4548codex-cli 0.142.3codex doctor: reports0.142.4available, current0.142.3/Applications/Codex.app/Contents/Resources/codex app-server --analytics-default-enabledRUST_LOG=warn~/.codex/logs_2.sqlitewalObserved behavior before workaround
The active log database was already large:
A live SQLite inspection showed a large TRACE share:
Recent rows were dominated by TRACE logs:
Representative recent TRACE targets were low-level protocol/dependency logs, for example:
A later aggregate over recent TRACE rows showed these targets as the largest groups:
During inspection,
MAX(id)and the latest row ids continued advancing, which indicates ongoing insert churn rather than a static old database. I am not pasting rawfeedback_log_bodyvalues because they may contain private session, tool, path, or protocol data.Temporary workaround used locally
I first installed a TRACE-only trigger to confirm the source of churn:
After that, TRACE stopped growing:
However,
MAX(id)still advanced slightly from non-TRACE DEBUG/INFO inserts:To stop all persistent log-table writes temporarily, I then used an all-insert trigger:
That fully stopped growth over the verification window:
This workaround is not a product fix and it disables useful local diagnostics. It only demonstrates that the persistent
logstable is the write path causing the observed churn.Expected behavior
Production Codex Desktop builds should not persist high-frequency frame-level/dependency-level
TRACElogs intologs_2.sqliteby default, especially when the app-server process hasRUST_LOG=warn.Expected improvements:
TRACEtargets such aslog,h2::*, websocket/SSE frame logs, and dependency internals should be suppressed, sampled, summarized, or bounded by default.Reproduction sketch
RUST_LOG=warn.~/.codex/logs_2.sqliteand~/.codex/logs_2.sqlite-wal.MAX(id), row counts bylevel, recent targets, and WAL size/mtime over a short interval.Privacy note
I am intentionally not attaching
logs_2.sqliteor raw log bodies. They may contain private conversation text, local paths, tool output, or protocol payload fragments.