--- id: NVIM-PLAN-LAJ8PGRK type: plan title: Deliver pivi transcript presentation and navigation spec: NVIM-SPEC-GMWDCMJZ status: approved depends_on: - NVIM-PLAN-CEJPO_XF --- # Deliver pivi transcript presentation and navigation ## Intent Deliver the transcript presentation and navigation behavior of [NVIM-SPEC-GMWDCMJZ](../../specs/NVIM-SPEC-GMWDCMJZ-pivi-native-neovim-integration/index.md). [NVIM-PLAN-CEJPO_XF](../NVIM-PLAN-CEJPO_XF-deliver-pivi-native-neovim-integration/index.md) delivered a working transcript that appends plain text and mixes pivi's own framing into the content. This plan makes the transcript the conversation document it already is: addressable entries, message text as authored, rendered formatting, and ordinary motion. Placement continues from the earlier plan: `lua/bugabinga/pivi/`, with module-level testing rules in that directory's `AGENTS.md`. Measured constraint, not assumption: a transcript that reparses on every streamed delta costs roughly five hundred times a transcript that lets redraw drive parsing. Presentation must therefore never force parsing per delta. ## Module map ```mermaid flowchart TB session["bugabinga.pivi.session"] --> entry["bugabinga.pivi.entry"] entry --> transcript["bugabinga.pivi.transcript"] transcript --> render["bugabinga.pivi.render"] entry --> fold["bugabinga.pivi.fold"] entry --> navigate["bugabinga.pivi.navigate"] navigate --> follow["bugabinga.pivi.follow"] navigate --> detail["bugabinga.pivi.detail"] command["bugabinga.pivi.command"] --> navigate command --> fold ``` | Module | Responsibility | | --- | --- | | `bugabinga.pivi.entry` | Entry identity, kind, bounds, metadata, and lifecycle over a transcript buffer | | `bugabinga.pivi.transcript` | Buffer ownership; message text only, with framing delegated to presentation | | `bugabinga.pivi.render` | Formatting, embedded language presentation, and framing decoration | | `bugabinga.pivi.fold` | Collapsed and expanded presentation of an entry | | `bugabinga.pivi.navigate` | Motion between entries and tool calls, and reaching a referenced location | | `bugabinga.pivi.detail` | Detailed inspection of one entry without leaving the transcript | | `bugabinga.pivi.session` | Emits entries instead of writing framing text | | `bugabinga.pivi.command` | `:Pi` subcommands and `` mappings for the new behavior | ## Slice order ```mermaid flowchart LR s1["1 Addressable entries"] --> s2["2 Pure message text"] s1 --> s3["3 Collapse and expand"] s2 --> s4["4 Rendered formatting"] s1 --> s5["5 Motion between entries"] s5 --> s6["6 Reach a referenced location"] s3 --> s7["7 Detailed inspection"] ``` | # | Observable behavior | Modules touched | Verified by | | --- | --- | --- | --- | | 1 | Every appended submission, answer, tool call, result, and error is an addressable entry with stable bounds that survive later appends | `bugabinga.pivi.entry`, `bugabinga.pivi.transcript`, `bugabinga.pivi.session` | Entry bounds spec under streaming appends and buffer growth | | 2 | Transcript text is the message as authored; copying an answer yields the original text without framing | `bugabinga.pivi.transcript`, `bugabinga.pivi.render`, `bugabinga.pivi.session` | Copy spec comparing buffer text with recorded message content | | 3 | A tool result arrives collapsed to one readable line and expands on request; entry state never alters session history | `bugabinga.pivi.fold`, `bugabinga.pivi.entry`, `bugabinga.pivi.command` | Collapse spec asserting unchanged session entries and message state | | 4 | Message formatting renders rather than showing markup, embedded code appears in its own language, and unknown formats stay plain | `bugabinga.pivi.render` | Rendering spec plus a streaming budget assertion over a recorded answer | | 5 | Ordinary motions move between entries and between tool calls in both directions | `bugabinga.pivi.navigate`, `bugabinga.pivi.command` | Motion spec over a replayed recorded run | | 6 | An entry that names a location navigates there, reusing the existing follow surfaces | `bugabinga.pivi.navigate`, `bugabinga.pivi.follow` | Navigation spec asserting the working window is preserved | | 7 | An entry can be inspected in full, including tool arguments and results, without leaving the transcript | `bugabinga.pivi.detail`, `bugabinga.pivi.entry` | Inspection spec asserting the transcript window and cursor are unchanged | Slice 1 is the walking skeleton; every later slice keeps the whole suite green before the next begins. ## Critical paths - Entry bounds must be extmark-backed, because text appended later shifts every fixed line number. - Presentation is driven by redraw, never by a forced parse per streamed delta. - Framing lives in decoration, so the buffer stays copyable message text. - Collapsing is presentation only; the session transcript and Pi history are untouched. - Location navigation reuses follow-mode surfaces rather than introducing a second window policy. ## Risks | Risk | Slice | Mitigation | | --- | --- | --- | | Entry bounds drift as the transcript grows | 1 | Extmark-backed ranges, asserted after appends and after edits to earlier entries | | Moving framing out of the text loses scannability | 2 | Replace it with decoration in the same slice, and assert both text purity and visible framing | | Rendering cost grows with a long answer | 4 | Assert a streaming budget over a recorded answer; keep parsing redraw-driven | | Collapsed entries hide errors the user needs | 3 | Collapse voluminous results only; keep errors expanded | | New mappings collide with user keys | 3, 5, 7 | Buffer-local mappings in pivi buffers plus `` mappings; no global keys |