Every Playbook edit in the TUI is streamed to the daemon by handle_playbook_key, which snapshots the buffer before the key and flushes the resulting anchored diff afterwards:
let before = self.playbook_popup.as_ref().map(|popup| popup.buffer.clone());
// ... dispatch ...
if let Some(before) = before {
self.flush_playbook_live_edit(before).await;
}
(crates/cli/src/app/editor.rs ~lines 652 / 822 @ ad47152)
C-x u does not go through that path. It is a global KeyAction, and its handler calls the mutation directly:
UndoPlaybook => {
self.undo_playbook_edit();
}
(crates/cli/src/app.rs ~line 12705 @ ad47152)
So the undo mutates the local buffer and is never sent. The buffers diverge — and they stay diverged, because the next keystroke's anchored diff is computed against a before the daemon never received. Its old_string no longer exists server-side, playbook.edit fails with old_string not found in the current playbook, and the failure is swallowed (#1089). Every keystroke after that fails the same way.
Repro
- Open a Playbook in the TUI on a session whose document is in sync.
- Type
abc. Confirm the daemon has it (construct playbook get, or playbook.get over IPC).
- Press
C-x u.
- Type
Z.
Observed, against a daemon at v109:
| step |
daemon |
TUI |
type abc |
v109 - build the thing …abc |
…abc |
C-x u |
v109 …abc |
…ab |
type Z |
v109 …abc (unchanged) |
…abZ |
From step 3 on, the document the agent and the web UI see is frozen. The only indication is the * modified chip in the pane title. C-x C-s recovers correctly (playbook merged with agent edits (version 42)), but nothing points the user at it.
The web UI's C-x u does sync — this is TUI-only.
Expected
Undo is an edit like any other and must reach the daemon.
Acceptance criteria
Found during a hands-on UX audit of the Playbook in the TUI and web UI.
Every Playbook edit in the TUI is streamed to the daemon by
handle_playbook_key, which snapshots the buffer before the key and flushes the resulting anchored diff afterwards:(
crates/cli/src/app/editor.rs~lines 652 / 822 @ ad47152)C-x udoes not go through that path. It is a globalKeyAction, and its handler calls the mutation directly:(
crates/cli/src/app.rs~line 12705 @ ad47152)So the undo mutates the local buffer and is never sent. The buffers diverge — and they stay diverged, because the next keystroke's anchored diff is computed against a
beforethe daemon never received. Itsold_stringno longer exists server-side,playbook.editfails withold_string not found in the current playbook, and the failure is swallowed (#1089). Every keystroke after that fails the same way.Repro
abc. Confirm the daemon has it (construct playbook get, orplaybook.getover IPC).C-x u.Z.Observed, against a daemon at v109:
abc- build the thing …abc…abcC-x u…abc…abZ…abc(unchanged)…abZFrom step 3 on, the document the agent and the web UI see is frozen. The only indication is the
* modifiedchip in the pane title.C-x C-srecovers correctly (playbook merged with agent edits (version 42)), but nothing points the user at it.The web UI's
C-x udoes sync — this is TUI-only.Expected
Undo is an edit like any other and must reach the daemon.
Acceptance criteria
C-x uin the Playbook publishes the resulting document to the daemon, so agents and other clients see it.C-/(the in-editor alias,editor.rs~line 763) andC-x ubehave identically.Found during a hands-on UX audit of the Playbook in the TUI and web UI.