--- id: NVIM-RESEARCH-T3BL4TK4 type: research title: Pi tool result formats for presentation --- # Pi tool result formats for presentation Read from real Pi session logs on disk (`$PI_CODING_AGENT_SESSION_DIR`), not from prose. Each tool result is a `toolResult` message: `{ role, toolCallId, toolName, content, isError, timestamp, details? }`. `content` is always a text block list `[{ type:"text", text }]`; the rich, per-tool structure lives in `details`. This closes the evidence gap that blocked grep file-grouping and the bash full-output surface. ## Per-tool shapes | Tool | `details` keys | `content` text shape | | --- | --- | --- | | edit | `diff`, `firstChangedLine` | a short sentence, e.g. `Successfully replaced 4 block(s) in .` | | grep | none | ripgrep context output, or `No matches found` | | find | none | newline-separated names, no line numbers | | ls | none | newline-separated entries, directories suffixed `/` | | bash | `truncation`, `fullOutputPath` | the captured output, possibly truncated | | read | `truncation` | file content | | write | none | a short sentence | ### edit `details.diff` is a display diff with a line-number gutter and change markers, for example: ``` 9 * ... + 11 * The tools use ... + 12 * a system prompt section ... ``` A removed line is marked `-`, an added line `+`, and a context line has no marker. `details.firstChangedLine` is the first changed line number. This matches what pivi already consumes; no change needed for the edit diff. ### grep No `details`. The match structure is only in `content.text`, in ripgrep's context format: - a match line is `PATH:LINE:TEXT` - a context line is `PATH-LINE-TEXT` - distinct match groups may be separated by a `--` line - an empty search is exactly `No matches found` The path repeats on every line, so grouping by file means reading the `PATH` prefix and collecting consecutive lines that share it; the match lines are the ones joined by `:` rather than `-`. There is no column offset in this format, so an exact in-line match span is not available; only the whole match line can be distinguished without re-searching the text client-side. ### find and ls `content.text` is a newline-separated list. `find` returns names or paths with no line numbers, so a find result groups trivially as a flat list. `ls` suffixes directories with `/`. ### bash `details.truncation` carries `{ truncated: bool, ... }`; `details.fullOutputPath` is a filesystem path to the complete output when the kept result was trimmed. A full-output detail surface opens that path. ### read `details.truncation` only; the subject path is the file itself, so a preview leads back to the file that was read. ## Conclusions - grep and find file-grouping is implementable now: parse the ripgrep context format, grouping consecutive lines by their `PATH` prefix and marking the `:` match lines; `find` is a flat list. - Exact in-line match highlighting is not supported by the data; distinguish the match line, or re-find the term client-side, rather than relying on an offset. - The bash full-output surface opens `details.fullOutputPath`; truncation is `details.truncation.truncated`. - Edit diff and first-changed-line are already correct against the real shape; no rework there. ## Unresolved - Whether ripgrep emits `--` separators and heading lines under every Pi configuration, or only with certain flags; the parser must tolerate both. - Whether a stable match column is ever present in any grep mode; none seen in the sampled logs. - Whether `details.truncation` ever includes a kept/total count useful to show beyond the boolean.