Native goal is silently deleted from thread_goals on thread resume / after Voice Live ends
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.5k
- PR merge metrics
- PR metrics pending
Description
Bug description
A native goal that is created and correctly persisted gets silently deleted when the thread is resumed/rehydrated. After resuming a thread (or after a Voice Live session ends, which triggers the same rehydration path via transcript_tail_flush), get_goal returns null and update_goal(status="complete") fails with:
cannot update goal because this thread has no goal
The app-server emits thread/goal/cleared during the resume, and the row is physically removed from the thread_goals table in ~/.codex/goals_1.sqlite.
Reproduction steps (headless, no voice needed)
-
Create a thread and a goal:
codex exec "Call create_goal with objective 'canary goal', then call get_goal and print the raw result."get_goalreturnsstatus: "active".- Confirmed in
goals_1.sqlite: a row for the newthread_idexists inthread_goals(statusactive).
-
Resume the same thread:
codex exec resume <session-id> "Call get_goal and print the raw result." -
While the resumed session is running (before any model turn even completes), the runtime emits:
app-server event: thread/goal/cleared targeted_connections=0and the row for that
thread_idis deleted fromthread_goals. The six pre-existing rows for older threads were untouched. -
get_goalon the resumed thread returnsnull.
Observed timeline (2026-08-16, local time)
- 10:51:34 — goal row present in
thread_goals(snapshot of the sqlite db). - 10:52 —
codex exec resumestarted. - 11:03:37 and 11:08:37 — two
thread/goal/clearedevents in the runtime logs during the resume. - 11:14 — goal row gone from
thread_goals(second snapshot).
Voice Live variant (original sighting)
When a Voice (realtime) conversation ends, the injected transcript_tail_flush message ("Realtime conversation ended...") is followed by the same goal clearing: goal active before the voice session, get_goal = null right after. This makes goal mode unusable across any voice session boundary.
Additional inconsistency
On the affected thread, create_goal is refused with:
cannot create a new goal because this thread has an unfinished goal; complete the existing goal first
while get_goal returns null — so the "unfinished goal" check used by create_goal reads different state than get_goal/update_goal.
Environment
- codex-cli 0.145.0 (darwin arm64)
- VS Code extension + CLI (
codex exec) - macOS
Expected behavior
Resuming a thread (or ending a Voice Live session) should preserve the thread's active goal, or at minimum surface why it was cleared. Silent deletion makes native goals unusable for any multi-session or voice-interleaved workflow.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Trace the resume/rehydration path and the transcript_tail_flush flow, then compare the state used by create_goal, get_goal, and update_goal with the thread_goals row in goals_1.sqlite. Reproduce the issue with codex exec and resume, observing thread/goal/cleared and the database row. Done means an active goal survives resume and Voice Live termination, with consistent behavior across the goal operations.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust, sqlite
- Domain
- backend, databases
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100