app-server: feedback log sqlite (logs_N.sqlite) grows unbounded — ~0.75 GB/day, no retention/rotation
Summary
The app-server's internal feedback/telemetry log database ($CODEX_HOME/logs_<N>.sqlite) grows without bound — no retention, no rotation, no size cap. On a long-running headless deployment (app-server driven 24/7) it reached 9.8 GB in ~10 days (~0.75 GB/day) before we noticed and manually cleared it.
This is distinct from state_<N>.sqlite (actual thread/session state), which stays small and healthy (~106 MB).
Environment
codex-cli0.132.0 (codex app-server --listen stdio://)- Linux x86_64 (musl vendor build), driven continuously by an automation host (frequent short sessions: heartbeats, scheduled jobs, chat).
CODEX_HOMEset to a persistent dir.
Evidence
logs_<N>.sqlite has a single dominant table logs:
1,420,123 rows, ~9.4 GB used (10.47 GB file, 1.08 GB freelist)
schema: id, ts, ts_nanos, level, target, feedback_log_body, module_path, file, line, thread_id, process_uuid, estimated_bytes
Bytes by column — feedback_log_body dominates at 7.3 GB. By target:
5.88 GB n=314,237 codex_api::endpoint::responses_websocket (TRACE)
0.44 GB n=329,301 codex_otel.log_only
0.39 GB n=324,112 codex_otel.trace_safe
0.21 GB n=215,142 codex_api::sse::responses
0.21 GB n= 453 codex_core::client
Level mix: 675,801 INFO + 614,236 TRACE + 73,883 WARN + 23,110 DEBUG + 7 ERROR.
The largest single rows are ~800 KB each — full op.dispatch.compact / op.dispatch.user_input_with_turn_context request/response payloads serialised verbatim into feedback_log_body.
Steady-state growth (one row of the per-day breakdown):
2026-05-26 140,239 rows 0.71 GB
2026-05-27 136,379 rows 0.72 GB
...
2026-06-03 139,209 rows 0.75 GB
The logs_<N> suffix appears to be a schema version, not a size-based rotation — within a version the table grows indefinitely. RUST_LOG does not appear to gate these sqlite writes (no EnvFilter hook found for the feedback-log layer), and the only "bounded" reference in the binary (bounded_feedback_logs AS (...)) is a read-side CTE used when assembling a feedback bundle, not a write-side cap.
Impact
- ~0.75 GB/day ≈ 22 GB/month, ~270 GB/year of pure telemetry on disk for any long-lived app-server deployment.
- Full prompt/response payloads (including large compaction turns) are persisted indefinitely on the local disk — also a data-retention concern.
Expected behaviour
The feedback log should be bounded by default — e.g. a max age and/or max size with automatic pruning/rotation (à la a rolling window), or an explicit CODEX_HOME/config setting to cap or disable it. Ideally TRACE-level full-payload dumps should not be persisted to the on-disk feedback DB by default.
Workaround
logs_<N>.sqlite* is safe to delete while the app-server is stopped — it is recreated empty on next start and only debug/feedback-bundle history is lost. But this requires manual intervention and downtime since the file is held open continuously.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗