Terminals routinely deliver the line breaks inside a bracketed paste as \r, not \n — that is what a tty expects for Enter, and it is what tmux's own paste-buffer sends unless given -r. The Playbook's paste path inserts the payload verbatim (crates/cli/src/app.rs ~line 6786 @ ad47152); nothing in the client, the protocol, or the daemon normalizes \r / \r\n to \n.
The result is a pasted block that renders as one long line, because the TUI's renderer paints \r as nothing.
Repro
Paste this into a Playbook from a terminal that sends CR for newlines (e.g. tmux paste-buffer -p, no -r):
## Plan
- alpha
- beta
- gamma
```sh
echo tab-indented
Plan- alpha - beta - gammashecho tab-indented- [ ] task one- [x] task two
Saved document (after `C-x C-s`):
'## Plan\r\r- alpha\r - beta\r - gamma\r\rsh\r\techo tab-indented\r\r\r- [ ] task one\r- [x] task two\r'
The same paste with real `\n` (`paste-buffer -p -r`) renders perfectly — nested list, fence, and checklists all intact — so the payload is the only difference.
## Why it matters beyond rendering
Block splitting is newline-based, so a CR document is **one block**:
stored: '# Title\r\r- one\r- two\r'
block b0:27 '# Title\r\r- one\r- two\r'
That single block is the whole shimmer/selection-Run granularity for the document, and the agent receives the CR text verbatim on Run.
The web UI is unaffected: its paste goes through `document.execCommand("insertText", …)`, which normalizes CRLF to LF. Pasting `- one\r\n- two\r\n - nested\r\n` there produces the correct `- one\n- two\n - nested\n`.
## Expected
Normalize `\r\n` and lone `\r` to `\n` when a paste enters the Playbook (and ideally defensively on the daemon write path, so no client can store lone CRs in a Markdown document).
## Acceptance criteria
- [ ] A multi-line paste whose newlines arrive as CR produces the same document as one whose newlines arrive as LF.
- [ ] Documents stored by the daemon contain no lone `\r`.
- [ ] Regression test over a CR and a CRLF paste payload.
Found during a hands-on UX audit of the Playbook in the TUI and web UI.
Terminals routinely deliver the line breaks inside a bracketed paste as
\r, not\n— that is what a tty expects for Enter, and it is what tmux's ownpaste-buffersends unless given-r. The Playbook's paste path inserts the payload verbatim (crates/cli/src/app.rs~line 6786 @ ad47152); nothing in the client, the protocol, or the daemon normalizes\r/\r\nto\n.The result is a pasted block that renders as one long line, because the TUI's renderer paints
\ras nothing.Repro
Paste this into a Playbook from a terminal that sends CR for newlines (e.g.
tmux paste-buffer -p, no-r):Plan- alpha - beta - gamma
shecho tab-indented- [ ] task one- [x] task two'## Plan\r\r- alpha\r - beta\r - gamma\r\r
sh\r\techo tab-indented\r\r\r- [ ] task one\r- [x] task two\r'stored: '# Title\r\r- one\r- two\r'
block b0:27 '# Title\r\r- one\r- two\r'