Skip to content

Classify Codex ghost text by render styling (faint), not a literal placeholder list — terminal.replay already exposes it #504

Description

@EtanHey

#500 was "the code knows one Codex placeholder literal and Codex rotates them." #503 fixes it with a
documented list of three exact literals — the honest short-term fix, and one that rots the next time
Codex ships a new placeholder.

It rots because cmuxlayer's parser only ever sees flattened text. It does not have to.

The attribute is one RPC away (measured, read-only, live)

cmuxlayerClaude-reviewer-503 verified this against an idle Codex pane while reviewing #503, without
sending anything:

  • cmux capabilities advertises terminal.render_grid.v1 on this machine
  • cmux rpc terminal.replay returns render_grid.row_spans[].style_id, indexing a
    render_grid.styles[] table with faint, bold, foreground, foreground_palette_index
  • on surface:551, row 57:
col=  0  style=32  faint=false bold=true   '›'
col=  2  style=33  faint=TRUE  bold=false  'Ask Codex to do anything'

The placeholder is faint:true. The prompt marker beside it is not. That is the property we
actually want — "this text is ghost text" — rather than "this text matches a string somebody wrote
down in August."

cmuxlayer's client calls surface.read_text, which flattens the grid and drops the styles. That is
the whole reason the string list exists.

Ask

  1. Add a client method that reads terminal.replay / render_grid and preserves per-span style.
  2. Use faint (plus the prompt-marker contrast on the same row) to classify an empty composer,
    replacing the literal list in normalizeKnownPlaceholderComposerInput (src/server.ts:2364).
  3. Keep a fallback. terminal.render_grid.v1 is a capability, not a guarantee — cmux builds
    without it must still work, and that is exactly the "keep the connectors swappable" rule this repo
    is built on. The literal list is a reasonable fallback; it should just stop being the only path.
  4. While there: this same styling would let the draft guard tell a human's real draft from any other
    dim/ghost UI text, which is the general form of the send_to can submit pre-existing human composer text #442 problem.

Not urgent — #503 unblocks the fleet today. This is what stops #500 from coming back.

Filed off the review of #503; evidence is that reviewer's, reproduced in its PR comment.

— cmuxlayerClaude (lead) · claude-code/claude-opus-5

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions