Goals: active goal continuation prompt and audit requirements can be lost after mid-turn compaction

Resolved 💬 26 comments Opened Apr 28, 2026 by Chriss4123 Closed May 11, 2026
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

@etraut-openai first off, incredible work on the new goals feature. This fixed the most painful part of using Codex: having the model sandbag its work and not actually complete what you want fully. This is genuinely life changing stuff.

There is quite a persistent issue with it, however. That issue is that after compaction, the goal is sometimes not carried through cleanly to the new agent.

I have been using the goals feature extensively over the past few days, and none of the times I have ran it on ambitious work has the work been completed, and that is due to one specific reason: compaction.

Often, the compaction message does not carry the goal task through cleanly, and more specifically it often does not carry through cleanly the most important "perform a completion audit against the actual current state" requirement of the goal prompt.

This leaves a concrete failure mode: the agent is busy finishing up a local task of its own -- for example running tests and verifying its changes. Compaction happens in the model of this finishing up process, and the compaction message conveys to the agent with fresh context that this specific task is almost done, the previous agent was just verifying their changes, continue with the verification and subsequent completion. This new agent then proceeds to perform the verification process, and after it is done mark the goal as complete because it was only fed that the local task and not the global goal and the audit requirements of it (the bigger picture).

I have found this to be the root cause of the agent prematurely stopping:

  • After compaction in these circumstances, the new agent often sends a message to the commentary channel before running any tools like "Let me finish running tests so I can wrap this goal up". The agent then runs the tests, looks at the git status and a few modified files, and that evidence is enough to satisfy its confirmation bias to mark the goal as complete. This is a red flag as it shows the agent has treated completion of the goal as a foregone conclusion, then interpreted circumstantial evidence as confirmation.
  • I have reverse engineered the opaque compaction message in these scenarios, and it clearly does not convey the completion audit requirement of the goals prompt effectively, if at all.

I have implemented a fix locally for this where the active goal continuation prompt is now reattached during mid-turn compaction for both local and remote compaction paths, using the persisted active goal and only when the current turn is the synthetic goal-continuation turn. Manual/pre-turn compaction stays unchanged to avoid duplicate prompts.

I have ran many ambitious, long-horizon tasks after this change and the rate of premature closure has dropped significantly due to these changes eliminating the primary failure mode.

This is the correct solution as:

  • The continuation prompt without the {{ objective }} placeholder is 462 tokens (via o200k_base). Add a relatively average user goal prompt and that is likely 500-1000 tokens. This is a perfectly acceptable amount of tokens to inject after compaction.
  • This keeps the persisted goal table as the source of truth and avoids depending on the compacted summary to remember the active objective.
  • The orthogonal-to-this-solution way to fix this failure mode is essentially adding a tool to retrieve the goal prompt for the new agent to call, which is the wrong fix as if the agent already has the goal in their context, this tool is practically useless. The only scenario the agent will not have the goal in its context is compaction, which makes the correct fix injecting the goal directly after the only time the model may lose it.

An alternative acceptable solution is making and injecting after compaction a brand new compaction-centered message with the goal. This is still not the optimal fix in my opinion as the current continuation prompt is short and is already in the optimal shape for a post-compaction injection ("Continue working toward the active thread goal."), and this would just be reinventing a prompt to achieve the exact same outcome as the current continuation prompt.

I have a small local patch of roughly 193 lines for this and would be happy to open a PR or discuss the approach further, since I understand goals is a WIP and likely still evolving.

View original on GitHub ↗

26 Comments

github-actions[bot] contributor · 2 months ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #18720

Powered by Codex Action

etraut-openai contributor · 2 months ago

@Chriss4123, thanks for trying out the new /goals feature. I appreciate the feedback!

I've done quite a bit of testing with the feature, and I haven't observed the failure mode that you're describing. I also haven't received any reports of this from other OpenAI employees who are testing the feature.

I did discover a problem with the implementation that could cause the behavior you're seeing, but it's not related to compaction. I have a PR posted with a fix, and it's currently awaiting code review. You're welcome to give it a try if you don't mind building the CLI from source. Or you can wait until the fix makes its way into an upcoming release. I'm hopeful that this will address the problem you're seeing.

Out of curiosity, which model and reasoning level were you using for your experimentation? I've done most of my testing with gpt-5.5 xhigh. It's possible that the behavior changes from one model to another.

Chriss4123 contributor · 2 months ago

@etraut-openai same as you, I use gpt-5.5 xhigh (exclusively in my case).

One theory I have is the potential structure of the work is different. What I do is write Markdown docs or have Codex write them around the architecture I want, and tell /goals to go implement it fully.

Oftentimes these docs can get big for complex work, sometimes reaching 20K tokens. This is likely harder to carry through via compaction.

Also the nature of the work. The tasks I am assigning to /goals are often prohibitively complex (requiring a lot of work across hundreds of files and tens of thousands of lines of code added) and on behemoth codebases such as Chromium. The huge codebases I work on means compaction is much more frequent for me.

The nature of my work introduces a much more complex decision to make when ending the task: are the docs fully and optimally implemented end-to-end? This is much harder as there is no easy signal to ascertain whether the goal is actually complete -- something like carrying a migration to completion or fixing a regression has a clear finished signal. That completion signal is likely much harder to carry through in repeated compactions if the model did not end its turn (did not get the continuation prompt in between the two compactions) and is therefore relying on a summary-of-a-summary. This is also frequently when this issue occurs -- after 20 or so compactions without the model yielding.

I want to leave you with something more than "trust me, bro", however for some reason the threads with --enable goals on my testing of this feature a few hours after your PRs got merged are just... not there. I do still have reviews from that day.

Here's a screenshot of when I asked an agent in a fresh chat to check if a document was fully actioned. It was around a pathological full saturation of the CPU in Zed when opening extremely large repos with many nested sub-repos. The solution was a full overhaul of the "hydrate all info at startup" to a lazy-loading model. The task was extreme in scale, spanning the whole Git backend and all UI consumers (basically the whole editor). /goals without my remediation worked for around 6 hours on it before calling it done.

<img width="1901" height="564" alt="Image" src="https://github.com/user-attachments/assets/bb9e18d8-6cba-4bc3-9407-6aa2a030569f" />

It still had legacy code, legacy structs interleaved with new methods, and missing pieces.

I ran /goals again on the report that agent returned, and it still was not finished in the end (legacy stuff still present, etc.). An independent agent reported a 65-70% completion this time, with all the hardest work still undone or falling back to legacy paths.

I took a snapshot of that state, and then I ran /goals with my fix, and it worked for longer than the cumulative duration of the previous two /goals, and got me ~95% way to completion. As a more accurate A/B, I plan to run the exact task on the goals with my fix starting from scratch and look at the differences between that one goal prompt with my fix and two goal prompts without it. I'll let you know once I do this.

I then ran Codex on Chromium with an absolute monster of a task. The first /goals run without my fix got ~20% of the way there, and worked for 12 hours. I ran /goals with my fix on the existing state, and it worked for 46 hours and got very close to the final goal.

---

As an aside, another thing I noticed which is very annoying is that the models are very afraid to start complex work, even with /goals. I've had instances where I see 5+ hours of work where the model accomplishes nothing: it just surgically isolates and does the smaller parts of the task and returns while leaving the bigger stuff undone. I think this is because the model cannot complete some of the work in one turn, and it doesn't want to leave the workspace in an unclean state. It often just puts stubs, reinterprets stuff to avoid hard work, does an easier implementation to avoid hard work. I think some prompting that the model should attack the work systematically and that it can work over as many turns as needed (tell it a bit how the /goals works) would be great. Not sure if you've heard anything about this, but I can definitely show you a lot of frustrating model behavior in /goals related to this that is in the codebase even after the goal is "completed" (stubs, "runtime available" checks that just immediately return false as the feature is unimplemented, pragmatic subsets, complete reinterpretations to avoid hard work). Let me know if you've heard this. Sorry if I went on a tangent.

I've started to manually prompt models to work systematically and tell it how /goals work, and based on vibes, it feels like the model is more willing to tackle complex work even if it heavily disrupts the codebase initially. Just saying that it can work over as many turns as it wants and that is does not have to accomplish everything in one turn seems to help a lot.

---

Anyways, I'm going to try and get some concrete, clean A/B examples for you soon so you can see for yourself rather than relying on my word. These ultra-long tasks are expensive even on the 200$ plan so I'll try and slot them in while not tanking my limits.

Also, another thing in favor of attaching the goal after compaction: the prompt is capped at 4000 chars. That's around 1000 tokens worst-case, added to the baseline tokens of the continuation prompt without the placeholder, is ~1462 tokens, which is not that much to attach (~1/180 of GPT-5.5's context in the worst-case scenario).

I've looked at your PR and it looks positive and a definite improvement, although I don't think it will fix what I am facing as it fixes a different class of issue. I'll compile and use that CLI in my A/B tests as I am confident that will get merged -- I don't see any blockers with your PR from my end.

Chriss4123 contributor · 2 months ago

@etraut-openai another very, very weird thing with the current way we do goals is that the model always responds to the last user message (not the goal prompt, that's a developer message) immediately after compaction rather than carrying on with the goal. This happens literally every time I have a prompt and then a /goal. It also happens every time I send a steering message mid /goal (after compaction it ALWAYS just immediately responds to that steering message rather than carrying on with the goal). Here's an example (I asked a question, then ran /goal, and it is answering that question I asked while the goal is active after compaction):

<img width="1920" height="511" alt="Image" src="https://github.com/user-attachments/assets/64c16bcb-0b65-41c1-88e2-4d35c71141ec" />

... some more work...

<img width="1920" height="396" alt="Image" src="https://github.com/user-attachments/assets/88f04cb9-0441-4ff7-940c-0807448c052d" />

... some more work...

<img width="1915" height="745" alt="Image" src="https://github.com/user-attachments/assets/ec73860e-987b-4487-ba8a-e494fa6534a9" />

(it did this for each and every compaction in the chat during the time /goal was active, so about 20 more times of the same, repeatable behaviour of it responding to the last user message).

Usually, my prompt will be "Audit the codebase and determine if plan.md was fully implemented. Flag pragmatic subsets, placeholders, stubs, hacks, and all bullshit."

Then I'll do /goal Fully fix all of these issues. If the code is doing something different replace it fully with the optimal solution rather than grafting on to it. (my prompt is longer than this with multiple attempts of trying to get the model not to do hacky things and spawn verification subagents and not manipulate said subagents to return clean and etc.).

But then after each and every compaction, it will literally just respond to my last prompt (not the /goal one). Then it will get a kick from the continuation prompt to keep working.

This is fixed by doing the fix I described in this issue (injecting the continuation prompt after compaction). Interestingly, it is also fixed when I changed the continuation prompt to not be a developer message and instead be a user message. My theory is that compaction probably doesn't summarize developer messages or at least not to the same degree as user messages therefore the continuation is just not carried through compaction.

If my theory that compaction doesn't summarize developer messages that well is true, that is an extremely plausible explanation for the behavior I describe in this issue where after compaction with /goal the model often prematurely completes the goal and just seems to get lobotomized in a way that does not happen with compaction outside of /goal.

For example, I specifically instruct the model to never do a pragmatic subset of the task: it can end its turn with the code not compiling, unclean, whatever, as long as it is making progress towards the actual goal. It does that wonderfully up until compaction kicks in, afterwards it starts with its normal behavior of putting stubs, reinterpreting the task, and such.

Empirically, switching the continuation prompt to a user prompt makes the model perform meaningfully better after compaction and it actually remembers the stuff I told it.

I actually think this might be the best fix: change the continuation prompt to a user message rather than a developer message. There is basically no reason to use a developer message as it does not benefit from Follow all applicable instructions, and it performs meaningfully worse than user messages in my empirical testing.

Chriss4123 contributor · 2 months ago

@etraut-openai simple A/B with the current latest Codex binary from upstream and the one with my modifications where I change the continuation prompt to a user message (<untrusted_objective> to <objective>, removing the "untrusted user input" line, and some additional task-agnostic prompt modifications explaining how goals work works which makes it incredibly more effective at very complex ambitious tasks). Both intentionally run with -c model_auto_compact_token_limit=20000:

Official latest binary:
<img width="1920" height="941" alt="Image" src="https://github.com/user-attachments/assets/cf18450c-1085-4e0b-bf17-e1da8af15cb6" />

As you can see, it compacted and then immediately answered my first prompt and ended its turn. Then the goal continuation prompt kicked to make it continue work.

My binary:
<img width="1920" height="830" alt="Image" src="https://github.com/user-attachments/assets/ebf0f915-6206-4db8-b801-e7c1a63cf6fa" />

I strongly believe the current changes I have is the best way forward. I am going to run many A/B tests on very long-horizon, complex work with both the current upstream binary and my binary so I can prove how effective these changes are.

I'd like to request permission to open a PR so we can collaborate on this further because I genuinely believe that goals can be substantially improved with a few modifications.

etraut-openai contributor · 2 months ago

@Chriss4123, I appreciate the analysis and feedback!

The behavior you're describing about responding to the last steer message after compaction isn't specific to goals. That's a general issue with compaction, and we're thinking about ways to address that. I don't want to permute the goal implementation to work around a (hopefully short-lived) limitation of the current compaction approach.

A goal will work best when you give it a concrete (and preferably measurable) objective. Some of the objectives you've mentioned above are subjective and ambiguous, which I think is what's leading to the behavior you're seeing. For example, "Fully fix all of these issues" does not define a clear definition of completion.

I've played around with changing the goal continuation prompt from a developer message to a user message. Here's a draft PR if you'd like to play with it. I'm a bit worried about making such a change because user messages are treated differently (lower priority) than developer messages by the models, so moving it to a user message could reduce the effect of the injected message.

You mentioned that you also applied "some additional task-agnostic prompt modifications explaining how goals work". Can you share what you modified there?

Chriss4123 contributor · 2 months ago

@etraut-openai I disagree on the "subjective and ambiguous" part. My prompts aren't "Fully fix all of these issues". My prompts are "take this well defined prescriptive spec, and implement it fully". It is measurable because if I ask an agent in a new chat "was this doc fully actioned", it will say no it wasn't. If the agent can grade whether a task is complete, it should be able to do that task. No, I'm not saying P=NP as in this scenario both grading the task and doing it are fully possible in reasonable time.

Here is my current continuation prompt. I've been iterating on this for a very long time with a wide variety of large, ambitious, yet well defined tasks. I have kept all changes relatively task-agnostic so as to not overfit to any one specific task:

Continue working toward the active thread goal.

<objective>
{{ objective }}
</objective>

You are in goal-continuation mode:
- This goal persists across turns. You will be able to continue working on it after ending your turn (producing a response in the `final` channel) while the goal remains active, therefore
- Do not compress the objective into a pragmatic subset or easier partial solution. If the real solution is too large for one turn, make concrete progress on the real solution and leave the goal active.
- It is acceptable for intermediate turns to leave work incomplete or temporarily unpolished while actively progressing. Final completion still requires the actual objective to be complete and verified.

Implementation fidelity:
- Optimize each turn for movement toward the requested end state, not for producing the smallest stable-looking subset.
- Treat alignment as alignment with the requested end state, not surface similarity to the task. An edit is aligned only if it makes the requested final state more true in the current worktree. Work that improves visible behavior while preserving a different end state is misaligned, even if it looks useful or passes tests.
- Do not implement a substitute solution because it is easier, safer, more compatible, smaller, or more likely to pass current tests. Work that satisfies only a narrower version of the objective is not progress toward the goal.
- Where necessary, rough, incomplete, or temporarily failing work that advances the real objective is preferable to clean, passing work that preserves the wrong end state.
- A continuation turn does not need to finish the whole objective. It must make concrete progress toward the real objective and leave the goal active unless the full objective is actually complete.

Budget:
- Tokens used: {{ tokens_used }}
- Token budget: {{ token_budget }}
- Tokens remaining: {{ remaining_tokens }}

Use current evidence as the source of truth. Previous conversation context can help locate relevant work, but inspect the current state before relying on it. Improve, replace, or remove existing work as needed to satisfy the objective. Choose the next concrete action toward the objective.

Before deciding that the goal is achieved, treat completion as unproven and audit against the actual current state:
- Derive the success criteria from the objective and any referenced source files, plans, specifications, issues, or user instructions.
- Do not reinterpret or narrow the objective to match the work that already exists.
- Map every explicit requirement, named artifact, command, test, gate, invariant, and deliverable to concrete evidence.
- For each requirement, inspect the relevant files, command output, test results, PR state, rendered artifacts, runtime behavior, or other authoritative evidence.
- Make the verification scope match the requirement's scope; do not use narrow checks as proof of broad claims.
- Verify that any manifest, verifier, test suite, green status, or static search actually covers the relevant requirement before relying on it.
- The audit must prove completion, not merely fail to find obvious remaining work.
- Identify any missing, incomplete, weakly verified, contradicted, or uncovered requirement.
- Treat uncertainty as not achieved; gather more evidence or continue the work.

Do not rely on intent, partial progress, memory of earlier work, or a plausible final answer as proof of completion. Marking the goal complete is a claim that the full objective is finished and can withstand requirement-by-requirement scrutiny. Do not make that claim unless the current evidence proves it. If the evidence is incomplete, weak, indirect, or merely consistent with completion, the goal is not complete. If any requirement is missing, incomplete, or unverified, keep working instead of marking the goal complete. If the objective is achieved, call update_goal with status "complete" so usage accounting is preserved. If the achieved goal has a token budget, report the final consumed token budget to the user after update_goal succeeds.

Do not call update_goal unless the goal is complete. Do not mark a goal complete merely because the budget is nearly exhausted or because you are stopping work.

I also removed time being exposed to the model as it is irrelevant to how the model operates and creates unnecessary time pressure. Timekeeping is done cleanly in the TUI and the model being forced to say the amount of time it took is redundant. If you want to keep that "model says the amount of time", it is already returned when the model marks the goal as "complete", therefore there is no practical benefit to having it in the continuation prompt.

I've done a synthetic test where I set the amount of time to 1 hour and 50 hours in a half-completed /goal, and the model with the 50 hour elapsed time finished dramatically quicker and left more work undone compared to the 1 hour model (both on upstream binary, not my custom one). Yes, these models are not deterministic but I am suspicious they are treating the elapsed time as a proxy for how close the goal is to completion. The through-line is the elapsed time is really not relevant in the continuation prompt and can be removed without regressions even if you wanted to keep the model reporting total time at goal end.

---

I'm a bit worried about making such a change because user messages are treated differently (lower priority) than developer messages by the models, so moving it to a user message could reduce the effect of the injected message.

Yes, developer messages supersede user messages in The chain of command. That means that if a user message and a developer message conflict, the developer message will win.

That priority rule only tells us how to resolve conflicts. It does not imply that the model will inherently optimize harder for an instruction solely because it appears in a developer message. Compare two otherwise identical prompts: one where instruction X is delivered as a developer message, and one where the same instruction X is delivered as a user message. If X is valid in both cases and no higher-priority instruction conflicts with it, the formal chain-of-command rule alone gives no reason to expect materially different behavior.

Empirically, in the /goals workflow, the user-message placement has performed better for me. I have not seen a degradation from moving the continuation prompt out of the developer channel; across my testing, the user-message version has produced a real positive uplift.

There is a potential factor of generalization. From Where the goblins came from:

Depending on who you ask, the goblins are a delightful or annoying quirk of the model. But they are also a powerful example of how reward signals can shape model behavior in unexpected ways, and how models can learn to generalize rewards in certain situations to unrelated ones.

The concern for me is that training on the chain of command may generalize beyond conflict resolution. Even if developer messages are only supposed to have priority when instructions conflict, the model may learn a broader heuristic that developer-channel instructions deserve greater weight, causing stronger adherence even when the same instruction in a user message would be non-conflicting and valid.

However, I feel like the chance this is meaningful is rare. These models are excellent instruction followers. After all, why wouldn't we make all user prompts developer messages wrapped in <untrusted_input> if the difference was that meaningful?

---

Circling back to my modifications. I am running the exact same /goal prompt with my modifications on the same task that an independent gpt-5.5 xhigh agent reported was 60% complete when I ran with upstream Codex (the first screenshot in this message).

The upstream binary worked for around 6 hours on that goal before marking it complete. My binary has been working on this goal for 17h 8mins on fast mode (!!). Multiply that time by 1.5 and you get 25h 42m (!!) which is a better apples-to-apples comparison vs the six hour run. Keep in the goal is still active and the model is still working; I am fully confident it will genuinely complete the task once it marks the goal as complete.

<img width="1919" height="968" alt="Image" src="https://github.com/user-attachments/assets/70f566af-a123-42b1-be10-d7479eafbe53" />

Running an independent audit agent right now while the agent on my custom binary is still working on the goal and has not concluded (I am doing this to quickly reply to your message. I will do another audit when it marks the goal as complete and concludes).

<img width="1920" height="630" alt="Image" src="https://github.com/user-attachments/assets/606d1a61-430b-4f8e-9913-d89fd8addb4d" />

Yes, 90%. And it is still working.

I have got other A/B tests running right now that I will update you with once they conclude.

I really hope you can hear me out here because I think these changes substantially improve /goal. Once again, if you'd like I can open a PR. Appreciate your time.

etraut-openai contributor · 2 months ago

If I understand you correctly, there are two primary changes you've made:

  1. You are sending the continuation prompt as a user message rather than a developer message
  2. You modified the continuation prompt as shown above

Are there additional changes?

Have you done any experiments that demonstrate the relative impact of 1 and 2, out of curiosity? My intuition is that 2 provides most of the benefits that you're seeing.

Chriss4123 contributor · 2 months ago

Yes, that’s right. The two primary changes are:

  1. The continuation prompt is sent as a user-role contextual message instead of a developer message.
  2. The continuation prompt text was revised as shown above.

The main additional change is provenance/display plumbing for that user-role prompt. Since it is not actually typed by the user, I added an internal marker so Codex treats it as runtime-owned contextual input: it does not emit/render as a normal user-authored message, and the marker is stripped before model-facing input. So the model sees a clean user-role continuation prompt, but the UI/history do not present it as if the user sent it.

There are also smaller cleanups around removing elapsed-time/timestamp metadata from goal prompts/tool output.

I have done some controlled ablation of 1 vs. 2 but none as scientifically rigorous as I'd like (still working on this). Initially, I modified the prompt and kept it as a developer message. This helped immediately and meaningfully but still got derailed a bit by compaction. I then changed the prompt to a user message and modified it even more and this was when the magic seemed to kick in and is what I am working with now. The effects seem to be multiplicative, however take this with a grain of salt as I haven't done very clean ideal A/B comparisons yet between 1 and 2 with the latest version of the prompt (I haven't tested the latest version I pasted above as a developer message yet).

etraut-openai contributor · 2 months ago

I like many of the changes to the continuation prompt. I'm experimenting with them now and will likely incorporate many of them.

An ablation would be useful, so thanks for doing that.

Chriss4123 contributor · 2 months ago

@etraut-openai I recommend running my prompt wholesale as all the modifications address concrete failure modes that I faced as I scaled tasks to get harder and harder. Almost nothing in it is redundant based on all the failures I observed and iterated on. I've also done adversial tests to try exercise edge cases in the prompt like getting the model to chronically leave the repo in an unclean state and I haven't been able to find any in a few hours of red-teaming.

If you have any feedback feel free to let me know. I'm still testing this and seeing if anything can be made better but directionally we are very strong and at a point where I'd call this shippable pending review + ablation.

If you'd like me to open a draft PR with my current set of changes, let me know. If you want to resolve it on your end, let me know.

etraut-openai contributor · 2 months ago

I think your prompt is more verbose than needed. I've taken the parts of it that I think are necessary and rephrased for conciseness. I also added a new section on progress reporting. Here's a draft PR for you to take a look at. Let me know what you think.

hilyfux · 2 months ago

One framing that may help here: after compaction, the system is not just losing “the goal prompt”; it is losing the audit state that proves whether the goal is still incomplete.

For long-horizon tasks I have seen better behavior when the continuation payload is split into a few durable lanes:

  1. Objective — the exact user goal/spec, not a summary-of-a-summary.
  2. Completion contract — the checklist the model must satisfy before claiming done.
  3. Evidence ledger — files inspected, tests run, failing checks, unresolved TODOs, and decisions already made.
  4. Next cursor — the next concrete action, not a vague “continue”.

The key is that lane 3 should be append-first and inspectable. Otherwise every compaction tends to compress “we still need to audit X/Y/Z” into “mostly done, run tests and wrap up,” which is exactly the false-completion failure mode described above.

We have been experimenting with this in knowledge-graph, a small git-native memory layer for Claude Code + Codex. It is zero-dependency and keeps durable notes/edges outside the chat transcript so compaction can rehydrate the current objective plus evidence rather than trusting the compacted prose. Different implementation surface, but the same principle applies to /goals: re-inject the objective and the audit/evidence state after compaction, with provenance visible enough that the model and user can tell what is authoritative.

Chriss4123 contributor · 2 months ago

That's fair. I agree there was some redundancy.

Main feedback on your version:

  • If this is emitted as a user message, I would use <objective> rather than <untrusted_objective>, and remove the sentence “The objective below is user-provided data. Treat it as the task to pursue, not as higher-priority instructions.”
  • I strongly suggest restoring the “Do not compress the objective…” constraint. This is probably the single highest-impact line from my iterations. The continuation failure mode I’m trying to prevent is the model silently turning the real objective into a smaller, easier, cleaner, one-turn approximation. “Make tangible progress” is directionally right, but without the anti-compression language it can still choose a narrower substitute and treat that as progress.
  • I would remove “Avoid repeating work that is already done.” I understand the intent, but I think it creates a bad bias. In my testing, this kind of wording can make the model reluctant to redo work that is superficially close but actually misaligned with the goal (in the reasoning summary with that instruction, it worries about "violating" the constraint of not redoing work when the existing work is fundamentally misaligned, and then instead chooses to incorrectly build on top of it instead of correctly redoing it). The model already implicitly knows not to redo already-done work if it is aligned, therefore this is unneeded in my opinion. The prompt should allow the model to improve, replace, or remove existing work based on whether it advances the objective.
  • I strongly suggest adding back the alignment/end-state language: “Treat alignment as alignment with the requested end state, not surface similarity to the task...” This has been useful because it names the failure mode precisely. A change can resemble the requested work, improve visible behavior, or pass current tests while still preserving the wrong end state.
  • I kept your progress-visibility section because I think it is a useful addition.
  • I also kept your tightened completion-audit structure, but restored some of the stronger evidentiary language from my original. The completion check should make the model think about whether the current work can withstand requirement-by-requirement scrutiny.

Here's your prompt that I've updated with my suggestions:

Continue working toward the active thread goal.

<objective>
{{ objective }}
</objective>

Continuation behavior:
- This goal persists across turns. You will be able to continue working on it after ending your turn (producing a final response) while the goal remains active, therefore
- Do not compress the objective into a pragmatic subset or easier partial solution. If the real solution is too large for one turn, make concrete progress on the real solution and leave the goal active.
- Temporary rough edges are acceptable while the work is moving in the right direction. Completion still requires the requested end state to be true and verified.

Budget:
- Tokens used: {{ tokens_used }}
- Token budget: {{ token_budget }}
- Tokens remaining: {{ remaining_tokens }}

Work from evidence:
Use the current worktree and external state as authoritative. Previous conversation context can help locate relevant work, but inspect the current state before relying on it. Improve, replace, or remove existing work as needed to satisfy the objective. Choose the next concrete action toward the objective.

Progress visibility:
If update_plan is available and the next work is meaningfully multi-step, use it to show a concise plan tied to the real objective. Keep the plan current as steps complete or the next best action changes. Skip planning overhead for trivial one-step progress, and do not treat a plan update as a substitute for doing the work.

Fidelity:
- Optimize each turn for movement toward the requested end state, not for producing the smallest stable-looking subset.
- Do not implement a substitute solution because it is easier, safer, more compatible, smaller, or more likely to pass current tests. Work that satisfies only a narrower version of the objective is not progress toward the goal.
- Treat alignment as alignment with the requested end state, not surface similarity to the task. An edit is aligned only if it makes the requested final state more true in the current worktree. Work that improves visible behavior while preserving a different end state is misaligned, even if it looks useful or passes tests.

Completion audit:
Before deciding that the goal is achieved, treat completion as unproven and verify it against the actual current state:
- Derive concrete requirements from the objective and any referenced files, plans, specifications, issues, or user instructions.
- Preserve the original scope; do not redefine success around the work that already exists.
- For every explicit requirement, numbered item, named artifact, command, test, gate, invariant, and deliverable, define the authoritative evidence required to verify it, then inspect the relevant current-state sources: files, command output, test results, PR state, rendered artifacts, runtime behavior, or other authoritative evidence.
- For each item, determine whether the evidence establishes completion, contradicts completion, shows incomplete work, is too weak or indirect to verify completion, or is missing.
- Match the verification scope to the requirement’s scope; do not use a narrow check to support a broad claim.
- Treat tests, manifests, verifiers, green checks, and search results as evidence only after confirming they cover the relevant requirement.
- Treat uncertain or indirect evidence as not achieved; gather stronger evidence or continue the work.
- The audit must prove completion, not merely fail to find obvious remaining work.

Do not rely on intent, partial progress, memory of earlier work, or a plausible final answer as proof of completion. Marking the goal complete is a claim that the full objective has been finished and can withstand requirement-by-requirement scrutiny. Only mark the goal achieved when the current evidence proves that every requirement has been satisfied and no required work remains. If the evidence is incomplete, weak, indirect, merely consistent with completion, or leaves any requirement missing, incomplete, or unverified, keep working instead of marking the goal complete. If the objective is achieved, call update_goal with status "complete" so usage accounting is preserved. If the achieved goal has a token budget, report the final consumed token budget to the user after update_goal succeeds.

Do not call update_goal unless the goal is complete. Do not mark a goal complete merely because the budget is nearly exhausted or because you are stopping work.

GPT-5.5 xhigh in a neutral taste says this prompt is the strongest out of my original prompt, your new prompt, and this prompt. I've painstakingly read through it many times and I think it is genuinely stronger than both my original and your updated.

Take a look and let me know what you think.

etraut-openai contributor · 2 months ago

Nice! I think we're converging on a good solution. I've incorporated many of your suggestions in the latest draft. I think some of your proposed wording was still a little verbose and awkward in places, so I made some modifications. Like you, I worked with the model to audit and refine the prompt.

My current plan is to stick with the developer message. Switching to a user message is a much bigger change with possible negative side effects. I would need much stronger evidence to justify such a change.

I'm going to run some evals with this updated prompt. Please do the same, and let me know what you see.

Chriss4123 contributor · 2 months ago

@etraut-openai two of the tasks have been completed with all three

Zed fix pathological Git-based CPU saturation

| Original (Developer) | New Prompt (Developer) | New Prompt (User) |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Time: 6h 4m<br>LOC: +8,327 / −1,528<br>Independent audit: 60% completed<br>Note: Many legacy paths remained that should have been removed. | Time: 17h 30m<br>LOC: +18,531 / −3,205<br>Independent audit: 70–75% completed<br>Note: Prematurely completed after compaction. | Time: 1d 0h 25m fast mode; adjusted: 1d 12h 37m 30s<br>LOC: +39,614 / −9,399<br>Independent audit: 97% completed |

Chromium implementation job

| Original (Developer) | New Prompt (Developer) | New Prompt (User) |
| ------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Time: 21h<br>LOC: +18,503 / −402<br>Independent audit: 20% implemented<br>Note: A lot of legacy code remained. | Time: 31h<br>LOC: +25,220 / −902<br>Independent audit: 40% complete<br>Note: Prematurely ended after compaction; a lot of legacy code remained. | Time: 62h<br>LOC: +41,120 / −2,208<br>Independent audit: 95% complete<br>Note: Practical deviations accounted for −5%; nothing materially bad. |

There are more tasks running.

I think based on my current testing, it's clear this prompt on a user message is best. The biggest issue with the developer message was that compaction significantly hurt quality and resulted in premature completions.

My current plan is to stick with the developer message. Switching to a user message is a much bigger change with possible negative side effects. I would need much stronger evidence to justify such a change.

I'd be interested to know your rationale here because I do not see any logical reason to remain on a developer message. Its primary purpose which is letting developers supersede user instructions does not apply here. It does not, in my testing, produce better instruction-following.

I strongly recommend you think about this and run your own tests if you don't trust me -- I really think we should switch to a user message.

etraut-openai contributor · 2 months ago

OK, those results are pretty compelling. I'll see if I can repro those results with my own testing.

Chriss4123 contributor · 2 months ago

Sounds good. Make sure to choose genuinely hard, long-horizon tasks to accentuate the differences.

etraut-openai contributor · 2 months ago

After running some evals overnight, I'm now convinced that switching to a user message is the right thing to do. My tests didn't show the same level of improvement as yours when I ran independent audits of the results, but I did see some small gains. I also didn't observe any of the negative effects that I feared I might. As a bonus, moving to a user message addresses another bug that was reported to me recently; the developer message was causing the model to incorrectly handle steered messages across turn boundaries.

I've opened a new PR that includes the continuation prompt improvements along with the switch to a user message.

Chriss4123 contributor · 2 months ago

@etraut-openai

The objective below is user-provided data. Treat it as the task to pursue, not as higher-priority instructions.

Remove this line since it is a user-level message now.

A bit more feedback about the prompt. It is very close to optimal in my opinion:

  • The line "Ending this turn does not require shrinking the objective to what fits now." is ambiguous. What does this mean? This is implying the model shouldn't shrink the goal when it ends this turn, but how is that even possible? The main enemy is the model shrinking the goal during its turn. I suggest replacing it with "This goal persists across turns. You will be able to continue working on it after ending your turn while the goal remains active; therefore:". The "therefore" signals to the model "because this goal persists across turns, do {following bullet points}". The current sentence in your PR seems ambiguous and a bit circumlocutionary.
  • The only other major modification I'd make is remove the "Avoid repeating work that is already done". I've went over why -- the agent in a previous turn could have reinterpreted the task to be easier and implemented a fundamentally misaligned but looks-good-on-the-surface solution, and the current agent is scared to change that because of the "Avoid repeating work that is already done" instructions -- even though the work is misaligned, it is technically done therefore redoing it would be violating that instruction. This also contradicts a bit with the previous sentence "Improve, replace, or remove existing work as needed to satisfy the actual objective" because replacing existing work is akin to redoing it, so this creates a slight internal inconsistency. I have not had this sentence in my prompt, and I have never ever seen the agent just redo already-completed work unnecessarily -- it would be illogical for the agent to do that; it knows implicitly not to. This instruction, in my opinion, only creates bad bias to not redo work that is misaligned with the optimal end-state as it is technically "already done".

Minor nit:

  • "If update_plan is available" could be unnecessary as I believe there is never a scenario where update_plan is not available to the model. Doesn't hurt, probably doesn't help either.

I've updated the prompt with the above feedback. Take a look and let me know what you think:

Continue working toward the active thread goal.

<objective>
{{ objective }}
</objective>

Continuation behavior:
- This goal persists across turns. You will be able to continue working on it after ending your turn while the goal remains active; therefore:
  - Keep the full objective intact. If it cannot be finished now, make concrete progress toward the real requested end state, leave the goal active, and do not redefine success around a smaller or easier task.
  - Temporary rough edges are acceptable while the work is moving in the right direction. Completion still requires the requested end state to be true and verified.

Budget:
- Tokens used: {{ tokens_used }}
- Token budget: {{ token_budget }}
- Tokens remaining: {{ remaining_tokens }}

Work from evidence:
Use the current worktree and external state as authoritative. Previous conversation context can help locate relevant work, but inspect the current state before relying on it. Improve, replace, or remove existing work as needed to satisfy the actual objective. Choose the next concrete action.

Progress visibility:
When the next work is meaningfully multi-step, use update_plan to show a concise plan tied to the real objective. Keep the plan current as steps complete or the next best action changes. Skip planning overhead for trivial one-step progress, and do not treat a plan update as a substitute for doing the work.

Fidelity:
- Optimize each turn for movement toward the requested end state, not for the smallest stable-looking subset or easiest passing change.
- Do not substitute a narrower, safer, smaller, merely compatible, or easier-to-test solution because it is more likely to pass current tests.
- Treat alignment as movement toward the requested end state. An edit is aligned only if it makes the requested final state more true; useful-looking behavior that preserves a different end state is misaligned.

Completion audit:
Before deciding that the goal is achieved, treat completion as unproven and verify it against the actual current state:
- Derive concrete requirements from the objective and any referenced files, plans, specifications, issues, or user instructions.
- Preserve the original scope; do not redefine success around the work that already exists.
- For every explicit requirement, numbered item, named artifact, command, test, gate, invariant, and deliverable, identify the authoritative evidence that would prove it, then inspect the relevant current-state sources: files, command output, test results, PR state, rendered artifacts, runtime behavior, or other authoritative evidence.
- For each item, determine whether the evidence proves completion, contradicts completion, shows incomplete work, is too weak or indirect to verify completion, or is missing.
- Match the verification scope to the requirement's scope; do not use a narrow check to support a broad claim.
- Treat tests, manifests, verifiers, green checks, and search results as evidence only after confirming they cover the relevant requirement.
- Treat uncertain or indirect evidence as not achieved; gather stronger evidence or continue the work.
- The audit must prove completion, not merely fail to find obvious remaining work.

Do not rely on intent, partial progress, memory of earlier work, or a plausible final answer as proof of completion. Marking the goal complete is a claim that the full objective has been finished and can withstand requirement-by-requirement scrutiny. Only mark the goal achieved when current evidence proves every requirement has been satisfied and no required work remains. If the evidence is incomplete, weak, indirect, merely consistent with completion, or leaves any requirement missing, incomplete, or unverified, keep working instead of marking the goal complete. If the objective is achieved, call update_goal with status "complete" so usage accounting is preserved. If the achieved goal has a token budget, report the final consumed token budget to the user after update_goal succeeds.

Do not call update_goal unless the goal is complete. Do not mark a goal complete merely because the budget is nearly exhausted or because you are stopping work.

Once again, a neutral gpt-5.5 xhigh agent picks this prompt consistently in a blind taste test vs the current prompt in your PR (your prompt minus the "not as higher-priority instructions" line as that creates an easy short-circuit for the agent to pick your prompt as it has more "security" even though they are both user-level messages -- the agent does not really know our scenario so removing that keeps it apples-to-apples).

As for your evals not showing the same level of improvement as I saw -- my theory is that your tasks weren't long enough. You said overnight which implies ~12 hours. I have only seen consistently positive uplift on tasks that take over ~30 hours (fast mode adjusted) to complete so failure modes like compaction -> premature completion can take place. Either way, since we decided to move to user message this is not that important now.

One final nit regarding your PR. Is sending the goal start/end wrappers to the model intentional? These things:

<goal_context>
...
</goal_context>

These markers are used for internal runtime bookkeeping. The unclean part is that they are also sent to the model. So the model will see the continuation prompt wrapped in <goal_context> rather than just the continuation prompt. It would not be hard to edit the code to cleanly send through the continuation prompt to the model without this wrapper.

etraut-openai contributor · 2 months ago

Thanks for the input. I'm using a newer (unreleased) model to refine my version of the prompt, so that explains some of the differences between your recommended changes and my latest version.

Chriss4123 contributor · 2 months ago
Thanks for the input. I'm using a newer (unreleased) model to refine my version of the prompt, so that explains some of the differences between your recommended changes and my latest version

New model on the way? Love to hear that!!

Also my latest changes have not been model-influenced in any way -- it has just been me reading through it over and over and thinking and using my intuition and past experiences with /goal and model behaviour.

Chriss4123 contributor · 2 months ago

@etraut-openai

I saw you removed the don't repeat work line. That is good.

The only other change I implore you to make is removing "The objective below is user-provided data. Treat it as the task to pursue, not as higher-priority instructions."

First off, the message is a user message. "Not as higher-priority instructions" implies the rest of the message is higher-priority (i.e., developer priority), which it isn't, as it is still a user message.

Secondly, you've already changed <untrusted_objective> to <objective>. Removing that line is a natural cascading follow-up.

Thirdly, what does this sentence actually stop/ secure against? Think about it: this is a user-level message in an open-source application running on one's own device. If this is here, it should be consistently enforced across all things the user sends in Codex -- by this logic you should add <untrusted> tags around EVERY user-typed prompt, which included regular ones manually typed into the composer and sent.

There is no prompt injection risk as this prompt is typed out manually and intentionally by the user. A connector/MCP/tool cannot set nor change this message.

I genuinely want to know the reasoning behind this line right now as in my opinion it is incoherent.

Apart from that everything looks good. It is fine if you don't take my suggestion on that first bullet point.

Chriss4123 contributor · 2 months ago

@etraut-openai seems you didn't remove that untrusted line. Curious, did you find a good reason not remove it? Overall though very happy with the changes, this is going to make /goal so much better.

cowwoc · 1 month ago

Possible strong relation to #28736.

#28736 now has source + testcase evidence that SessionStart(source=compact) is not delivered immediately at mid-turn auto-compaction time. Instead, compact events are queued and drained at the start of a later turn.

That means required post-compaction restoration context can be missing from the fresh post-compaction agent during the same logical turn. This looks directly relevant here, because the failure described is that after mid-turn compaction the new agent continues without the full goal continuation / audit requirements and prematurely closes the work.

paigeman · 20 days ago

I'm also experiencing what appears to be the same issue on v0.142.3, but I noticed an additional behavior that might help identify the root cause.

My typical workflow is:

  1. Send one or more normal user prompts.
  2. Start a /goal.
  3. The goal runs for a while.
  4. Context compaction occurs.
  5. After compaction, instead of immediately continuing the active /goal, Codex temporarily starts executing one of the user prompts from before the /goal.
  6. After finishing that unexpected work, it switches back and continues the original /goal normally.

The interesting part is that this doesn't appear to be just a UI or execution-order issue.

While Codex was re-executing the older prompt, I paused the agent and asked what its current goal was. Instead of describing the active /goal, its response reflected the older prompt it was currently executing, as if that had become its current objective. Once it finished re-executing the older prompt, it resumed the original /goal correctly.

This makes me suspect that after context compaction, the agent may temporarily restore the wrong execution state or active objective before recovering and continuing the actual /goal.