openai / openai/codex

CLI /goal persists pasted text as inline file instructions that /goal edit does not reconstruct

Open
#44,075 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug CLI session TUI windows-os
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

Version and environment

Codex CLI 0.153.4 on native Windows x64 (OS build 10.0.26200), originally observed in an Orca embedded terminal. The Goal persistence code also remains present in main snapshot 3d3df0a0cad5d3d8d3340b633787e9dd304ea463. Model/subscription are not material to this TUI persistence path; no inference result is used as evidence here. A doctor report is not included.

Actual behavior

When a /goal draft contains long pasted text, the saved objective replaces each paste placeholder with an inline instruction:

pasted text file: <CODEX_HOME>/attachments/<id>/pasted-text-1.txt. Read this file before continuing.

Surrounding typed text stays inline. If a paste occurs in the middle of a sentence, the reference is embedded directly in that sentence. Source inspection shows that /goal edit does not restore these individual files into the original text; this edit behavior has not been independently reproduced interactively. The internal file-reference representation therefore becomes the user-editable goal.

This is not a claim that the payload files are missing or the original bytes have been deleted. In the observed case, all three files existed and contained 4,660, 2,885, and 3,130 characters. A read-only inspection confirmed that the saved objective itself contained three reference instructions; it was not merely a terminal rendering artifact. Private goal contents, attachment paths, and session identifiers are omitted.

Proposed minimal reproduction
  1. In the CLI composer, type /goal Prefix .
  2. Paste more than 1,000 characters, for example "sample paragraph " repeated 100 times, so the composer creates a paste placeholder.
  3. Type suffix, submit the goal, and then open /goal edit.
  4. The saved/editable objective contains Prefix pasted text file: ... Read this file before continuing. suffix rather than the original paragraph.

The sequence above follows the current code path; it has not been rerun as a complete interactive acceptance test on a newly built CLI. The persisted real-world example and the existing upstream test establish the storage transformation independently of that proposed manual reproduction.

Source-level cause
  • ChatComposer::handle_paste keeps pastes over 1,000 characters in pending_pastes and inserts display placeholders.
  • materialize_goal_draft computes expanded text for an emptiness check but then materializes each pending paste separately and replaces its placeholder with the reference instruction.
  • In the same file, objective_text_for_edit recognizes only the whole-objective goal-objective.md reference. It does not reassemble inline pasted-text-N.txt references, even after loading a whole-objective file.
  • The upstream test set_thread_goal_draft_materializes_long_objective_and_confirms_before_paste explicitly expects Use pasted text file: ... for a Use <placeholder> draft. The existing test explicitly expects this transformation; the reported defect is the failure to preserve the editable prose across save/edit.

Windows timing-based paste detection can make one physical paste become multiple placeholders, but that is not required to trigger this Goal bug. Even one pending paste is sufficient. Windows paste latency is tracked in #14099; this report concerns Goal persistence, rather than the desktop-app attachment UX in #25144 or #25346.

Expected behavior and suggested fix

Saving and reopening a Goal should preserve the objective text, apart from documented normalization. Internal input chunk boundaries should not determine how many files or inline instructions appear in the editable goal.

Expand the active pending-paste placeholders into the complete objective first, then apply the existing 4,000-character inline-objective limit. If externalization is needed, write the complete objective to the existing single goal-objective.md format, which the editor already knows how to read. Preserve/remap non-paste text-element spans for images using the existing expansion helper.

Suggested regression cases: mixed Korean text and multiple paste placeholders; one oversized objective saved and reopened as a single document; image placeholders after pasted spans; stale/deleted placeholders; whitespace-only pasted text.

For pre-existing goals, avoid blindly interpreting reference-looking prose as metadata or making one missing attachment prevent the entire goal from being edited. A legacy recovery design should be considered separately.

Validation limits

Source inspection, the existing upstream test, saved-state/file inspection, and independent code review support the diagnosis. Regression tests for the suggested change and full CLI integration remain outstanding. The full build was stopped because of local resource pressure. No fixed binary, complete test-suite pass, or user acceptance is claimed.

Submitting the analysis as an issue in accordance with the current contributing policy, which does not accept external PRs.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with codex-rs/tui/src/goal_files.rs, especially materialize_goal_draft and objective_text_for_edit, then inspect paste handling in codex-rs/tui/src/bottom_pane/chat_composer.rs. Run the existing set_thread_goal_draft_materializes_long_objective_and_confirms_before_paste test in codex-rs/tui/src/app/tests.rs. Done means saving and reopening a goal preserves mixed prose and paste content, with regression coverage for the listed placeholder cases.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cli
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.