Codex App: Goal compaction resurrects completed manual steer before goal continuation resumes
What version of the Codex App are you using (From “About Codex” dialog)?
26.616.51431
What subscription do you have?
Pro 20x
What platform is your computer?
Darwin 25.4.0 arm64 arm
What issue are you seeing?
In a long-running active /goal, a completed manual steering instruction is repeatedly resurrected after compaction and executed again before the active goal continuation is re-injected.
This appears to be the same failure mode as, or a regression/continuation of:
- #21291
- #27894
- #19910
- #28874
- #25900
- #28925
- #21269
It also appears related to the goal-continuation fixes discussed in:
- #22045
- #22174
I am intentionally omitting thread IDs, local paths, and exact project/conversation text. The example below is anonymized but preserves the observed control-flow shape.
Observed pattern:
- Start a long-running
/goal, e.g. “migrate a large project with full parity and keep working until complete.” - During the goal, send a normal user steering message, e.g. “please implement the cache boundary using backend X and keep it extensible.”
- The agent implements that steer and finishes the turn.
- Because the goal is still active, Codex starts the next turn by injecting an internal goal-continuation user message like:
``text``
<codex_internal_context source="goal">
Continue working toward the active thread goal.
...
- The agent correctly resumes the broader goal and works on unrelated next parity/evidence tasks.
- After a later compaction, the replacement history appears to preserve the original goal, app/developer context, AGENTS/project instructions, and the last ordinary user steering message. The visible replacement history does not appear to preserve enough of the later goal-continuation/checkpoint state that proves the steering task was already completed.
- The next model turn treats the old steering message as the current unresolved user instruction and performs the same steering task again.
- When that repeated steering turn completes, the goal-continuation message is injected again, so the agent briefly returns to the broader goal.
- At the next compaction, the same stale steering message regains salience again.
In the anonymized run I inspected, there were five compactions after the manual steer. All five replacement histories had the same high-level shape:
1. original /goal message
2. developer/app instructions
3. AGENTS/project instructions
4. latest ordinary user steer message
5. encrypted compaction summary
The observed behavior after those compactions was:
- Compaction 1: continued/cache-related follow-up work; arguably still close to the just-completed steering task.
- Compaction 2: re-checked the already-implemented cache backend and documentation, then eventually returned to the broader goal.
- Compaction 3: clearly re-executed the cache steer, introducing/rewiring a neutral cache interface and backend export again, then returned to broader parity work.
- Compaction 4: briefly summarized/re-verified the cache again, then resumed broader parity work.
- Compaction 5: clearly re-entered the cache steer again, including documentation lookup and additional cache interface expansion, despite the broader goal having moved on.
This creates a positive feedback loop: stale steer is replayed after compaction, which increases the amount of steer-related context, which makes the next compaction even more likely to preserve and emphasize that stale steer, which consumes more context and time.
What steps can reproduce the bug?
A minimal reproduction should be possible with a long-running goal and one mid-goal manual steer:
- Start a Codex App thread with a long-running goal:
``text``
/goal Perform a large migration/refactor. Keep working until all implementation and verification work is complete.
- Let Codex complete at least one goal-continuation turn.
- Send a normal user steering message that is concrete and easy to recognize later:
``text``
Please implement subsystem A using backend X. Keep the design extensible so backend Y can be added later.
- Let Codex implement that steering instruction and finish the turn.
- Let the active goal continue automatically. It should move on to unrelated broader-goal work.
- Wait for or force a compaction.
- Observe whether the next turn repeats the already-completed steering instruction before the goal-continuation context is re-injected.
- Let that repeated turn complete and then continue to another compaction. The same steer may repeat again.
I cannot include the original session/thread ID because the session contains private workspace details, but the local event log showed this control flow explicitly:
task_complete: completed steer work
new task_started
response_item role=user: <codex_internal_context source="goal"> Continue working...
agent resumes broader goal
...
compacted
replacement_history: original /goal + instructions + old ordinary steer + encrypted summary
agent starts by acting on old steer again
What is the expected behavior?
Once a manual steer inside an active goal has been completed, later compaction should not resurrect it as the current unresolved user task.
Compaction should preserve enough goal state/checkpoint metadata to distinguish:
completed manual steering instruction
from:
current active goal-continuation task
After compaction, the next turn should continue from the latest active goal checkpoint, e.g.:
The cache/backend steering instruction was completed earlier. Continue the broader migration goal from the current audit/checkpoint.
It should not re-run the completed steer unless the user explicitly asks for it again.
Additional information
This is particularly dangerous for destructive or expensive steer messages. In my case it caused repeated cache/backend work and repeated verification/documentation passes. With a different steer, the same mechanism could re-run deletion, rollback, large refactor, or external-service operations.
This looks like a state restoration issue rather than a model reasoning issue: after normal task_complete, the app does inject a hidden goal-continuation user message and the model resumes correctly. The failure appears specifically after compaction, where the older ordinary user steer becomes the latest visible user instruction again.
A robust fix likely needs one or more of:
- Preserve active
GoalContext/ goal-continuation state through compaction. - Mark manual steer messages as completed once a following
task_completehas handled them. - Include a compact checkpoint such as “last manual steer X was completed; current active work is Y.”
- Ensure replacement history after compaction does not make an old completed steer the latest actionable user message.
This seems closely aligned with the concerns in #21291 and #27894 and with the unmerged/draft direction in #22174.
9 Comments
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action
codex generated analysis:
This still reproduces in the Codex App with GPT-5.6 Sol Max.
Feedback ID:
019f48b9-86a4-74e3-abda-5a45bb45f6d2Second affected task:
019f48b9-7824-7d72-a756-1e0034bd9601App:
26.707.62119(5211)CLI:
0.144.1Platform: macOS
In the first task, the affected
/goalremained oneinProgressturn across several later user messages. It underwent three context compactions and emitted afinal_answerwithout the turn completing. After compaction, a completed earlier manual steer was repeatedly treated as the current request, even after newer steering messages.The second task shows the same lifecycle failure independently. A user prompt was answered once. A later automatic goal continuation crossed
contextCompactionand answered that consumed prompt again. The next automatic continuation repeated it once more without a new user message.This looks like goal/turn lifecycle state being restored incorrectly during compaction, rather than a model-attention failure: a consumed steer regains actionable status while the current goal checkpoint and consumed-steer state do not.
feedback ID 1:
<img width="822" height="497" alt="Image" src="https://github.com/user-attachments/assets/1749d488-b38d-499e-a58d-9425e55b7757" />
<img width="758" height="241" alt="Image" src="https://github.com/user-attachments/assets/b43b5b78-7fb5-4eca-b765-9ff86c78c498" />
<img width="781" height="270" alt="Image" src="https://github.com/user-attachments/assets/a89ebcf2-88bf-47eb-81d2-24908af72734" />
feedback ID 2:
<img width="785" height="490" alt="Image" src="https://github.com/user-attachments/assets/62ee5798-5402-4b36-be6c-681bf708fb85" />
I'm also affected by this in Windows.
Feedback ID 019f7d4d-3161-7ce3-bb2e-2d0b8155f671
Version 26.715.31925
Wastes tokens and causes the steering command to be given more weight than it should.
One workaround I've come up to stop it re-handling old steering messages is to give a follow-up message with something like this:
"This steering command is an empty command to deal with a codex compacting bug that re-sends previous steering messages. Ignore this message."
Further info:
I am seeing the same failure mode in the Codex App's active Goal workflow with GPT-5.6 Thinking.
A concrete instance:
This is not merely repeated wording: it can repeat commands, file edits, Git checks, reviews, or other side-effecting work. The issue appears to be that compaction preserves the old user steer but loses or underweights the state proving that the steer was already consumed/completed.
Expected behavior: a one-off user steer handled by a completed turn should remain marked as completed after compaction. The resumed turn should restore the latest Goal phase/checkpoint and next action, and should not treat the historical steer as the current actionable request unless the user sends it again.
A useful regression case would distinguish at least:
This report matches the positive-feedback-loop behavior described in the issue: replaying the stale steer adds more related context, making it increasingly likely to be replayed after later compactions.
Adding a current Windows reproduction with a slightly different—and especially damaging—variant: the resurrected message was the last ordinary user message from before the Goal was created, not a manual steer sent during the Goal.
Environment:
019fae90-5dd8-7721-860c-dc6b27d04fc026.727.6591.00.146.0-alpha.9.2I inspected the local Goal database and rollout JSONL read-only. The Goal was persisted as active in
goals_1.sqlite; the session log then showed this sanitized control flow:task_complete.thread_goal_updated→task_started→ hidden user context<codex_internal_context source="goal">....replacement_historyended with the same pre-Goal ordinary user message followed by the compaction item. The retained tail did not contain the current hidden Goal continuation context.phase: "final_answer"returned to answering that already-completed pre-Goal message.task_complete; only then did the next automatic Goal turn inject fresh hidden Goal context and resume the real objective.Sanitized timestamps from one run (UTC):
This confirms two important points:
This looks deterministic at the history/lifecycle layer rather than ordinary model drift: compaction repeatedly preserves the exact old user message while the state proving it was completed and the current Goal checkpoint are compressed or absent;
task_completethen causes Goal context to be reattached only for the next cycle.A focused regression should cover:
Please treat this as an instruction-lifecycle / final-response-ownership issue in addition to compaction salience. Replaying a completed prompt can repeat edits, commands, or external actions, and in this reproduction it repeatedly displaced the Goal's own conclusive response.
Adding a current Linux reproduction from a very large, long-running Goal thread.
Affected thread ID:
019f43ac-20b8-7ad1-965b-3b2e6460255dClient: Codex CLI
0.146.0Platform: Linux x86_64
Model: GPT-5.6 Sol
I inspected the canonical root rollout read-only. No session content, local paths, repository names, hostnames, or account details are included below.
48-hour evidence
From
2026-08-03T12:20Zthrough2026-08-05T12:20Z:task_completeevents occurred.Several
final_answerevents stated that all non-gated work was complete. Later Goal continuations reopened and re-reviewed the same acceptance surfaces, then produced another completion statement. Completed one-off steering instructions also regained salience after later compactions.Latest native compaction structure
The latest inspected native compaction was
window_number: 702. Itsreplacement_historycontained 495 items:messageitems withrole: usermessageitem withrole: developercompactionitemThe serialized replacement history was approximately 1.27 MB. The retained user messages contained about 63,500 text characters. This means hundreds of historical user instructions remained visible after compaction, while the responses and lifecycle state proving that they were completed were represented only indirectly by the encrypted compaction item.
This matches the instruction-lifecycle failure described in this issue: old consumed prompts remain structurally prominent, while the current Goal checkpoint and completion ownership lose salience.
Control observations
The Goal was removed after the repeated review loop. No further hidden Goal continuation messages appeared after removal, which confirms that the Goal lifecycle was one part of the loop.
A later ordinary user turn still inherited the same long native history and reached 244,251 input tokens against a 258,400-token context window. Removing the Goal therefore stops automatic continuation, but it does not repair the already contaminated compacted history.
A local context handoff hook was also enabled. Its delivery was one-shot: 59 compactions produced 59 unique generations with no duplicate injection. The hook had a separate stale-tail selection problem that amplified old-request salience. However, the native
compacted.replacement_historyindependently showed the 493-user / 0-assistant structure above.Expected behavior
After
task_complete, a handled steering message must remain historical and non-actionable across compaction. The compacted state should preserve:A completed prompt must not become actionable again merely because later history was compacted.
@tibo-openai This. This is the easy stuff that you're missing. Bugs that affect every desktop user, are obvious, chew tokens for no reason, are easy to fix, and haven't been addressed for several months. I don't want new features - I just want to use Codex without every single update introducing new and exciting bugs.
Additional Windows reproduction on a later build.
Environment:
During a long running goal task:
just checking if the replay bug has been fixed. Say "ding!" and continue.2026-08-20T07:18:54Z, 13:53:38Z, 14:38:13Z, 16:23:37Z, 17:38:24Z, 19:01:56Z, 23:51:53Z, and 2026-08-21T01:18:54Z.
This is a later Windows reproduction than the existing Windows report in this issue and provides a concrete replay sequence across eight compaction windows.
Expected behavior: once a one-off instruction has been consumed, it must remain historical across compaction and continuation. The next turn should resume the current checkpoint and must not re-play steering commands.
Minimal reproduction: start a long-running task, send a harmless distinctive instruction such as Say "ding!" once and continue, let it complete and continue into unrelated work, allow multiple compactions, and do not resend the instruction. Repeated "ding!" output after compaction reproduces the issue.
This is a closely related variant in the Codex desktop app on macOS.
Summary
An earlier question was resolved through a revised goal. The user then activated that replacement goal, and Codex began executing it. Automatic context compaction occurred. Immediately afterward, Codex answered the earlier question as though it were still pending.
This suggests compaction retained the question but lost its disposition: resolved, superseded, and incorporated into the active goal.
Cleaned transcript
User:
Assistant:
User:
Assistant:
Assistant:
System/UI:
Assistant:
Actual behavior
After compaction, Codex answered the first user message even though that question had already been resolved by the revised goal, which had subsequently been activated and was already being executed.
Expected behavior
Codex should continue the active
/goal. The earlier question should remain marked resolved or superseded and should not be answered again.Impact
No destructive action resulted in this instance, but losing request disposition after compaction could:
Privacy cleanup
Repository names, paths, commit hashes, database identifiers, project data, agent names, and unrelated transcript content have been removed.
This differs slightly from a mid-goal manual steer: the resurrected question was resolved before the replacement
/goalwas activated.