Add specs for the siGit Code TUI tabs and thinking display

The tabbed TUI (sigit #25) and the thinking display with /thinking (sigit #26) were built from direct requests rather than the parity roadmaps, so their behavior had no source of truth here. This records both as after-the-fact specs alongside the parity docs: tab bar and navigation rules, History and Cloud tab contents and keys, the approval auto-switch, the live reasoning tail, the collapsed indicator, and the display-only boundaries. Ends with follow-ups, including an Issues and PRs tab once the client consumes the new MCP repo tools.

Seto Elkahfi committed Jul 5, 2026 at 08:44 UTC 6a879f65c26539457da2a711bff15f2c07ce49bd
1 file changed +108
docs/product/sigit-code-tui-features.md new
+108
@@ -0,0 +1,108 @@
1 +# siGit Code TUI features: tabs and thinking display
2 +
3 +Status: shipped, pending merge (sigit #25 and #26, 2026-07-05). Owner: product/eng.
4 +Audience: internal (private repo). Scope: the **siGit Code** interactive terminal
5 +UI (`src/chat.rs`, Unix-only). These two features were built from direct requests
6 +rather than the parity roadmaps; this document records their specs after the
7 +fact so the behavior has a source of truth alongside
8 +[sigit-code-parity-roadmap.md](sigit-code-parity-roadmap.md) and
9 +[sigit-code-copilot-cli-parity.md](sigit-code-copilot-cli-parity.md).
10 +
11 +---
12 +
13 +## 1. Spec: tabbed TUI (sigit #25)
14 +
15 +Inspired by GitHub Copilot CLI's June 2026 terminal redesign (Session, Gists,
16 +Issues, and PR tabs switched with the Tab key).
17 +
18 +### Behavior
19 +
20 +Three tabs, rendered as a bar at the top of the screen on every view:
21 +
22 +- **Session** (default): the chat exactly as before, messages, input, footer.
23 +- **History**: the saved sessions from the session store
24 + (`$SIGIT_CONFIG_DIR/sessions/*.jsonl`), listed newest first with id, coarse
25 + age ("2m ago"), and message count. Up/Down selects. Enter restores the
26 + selected session into the live backend, pushes a system message saying how
27 + many messages were restored, and returns to the Session tab. `d` starts a
28 + delete; a second `d` on the same selection confirms, any other key cancels.
29 + The pending delete is keyed by session id, not list index, so a refresh can
30 + never redirect the confirmation. `r` refreshes. An empty store shows "No
31 + saved sessions yet."
32 +- **Cloud**: siGit Code Cloud status and settings. Shows the signed-in account,
33 + on-device vs remote inference, current model and engine state, the Local
34 + Inference setting, the permission policy summary, and the config dir. `l`
35 + toggles Local Inference, with a note that the toggle takes effect at the next
36 + model selection because the running backend is not swapped. `r` refreshes.
37 +
38 +### Interaction rules
39 +
40 +- Tab cycles Session, History, Cloud. It only cycles when the input buffer is
41 + empty, so pasted text containing tabs cannot hijack navigation; on non-Session
42 + tabs the input is inactive so Tab always cycles. Esc on a non-Session tab
43 + returns to Session.
44 +- Inference keeps streaming while the user is on another tab. Restoring history
45 + sits behind the busy gate so the conversation cannot be swapped mid-turn.
46 +- A tool approval prompt arriving while on another tab auto-switches to the
47 + Session tab: a y/a/n prompt must never be invisible.
48 +- The Cloud status fetch runs as a spawned task feeding the render loop over a
49 + oneshot, because `account::status_line()` can hit the network and must not
50 + freeze rendering. A dead fetch degrades to "press r to retry".
51 +
52 +### Implementation notes
53 +
54 +Pure logic (the tab cycle, age and row formatting, `session_store::list`) lives
55 +outside the Unix-only `mod tui` behind the same cfg-gate pattern as
56 +`permissions::TUI_SESSION`, so all four CI targets compile and unit-test it.
57 +
58 +---
59 +
60 +## 2. Spec: thinking display with `/thinking` (sigit #26)
61 +
62 +Reasoning models (Qwen 3, DeepSeek-R1 distills) emit their thought process in
63 +`<think>` tags. Before this feature the TUI hid reasoning behind the spinner
64 +while streaming and then rendered it as an unconditional box on every finished
65 +message. Both extremes were wrong: watching the model reason is useful, reading
66 +every past thought is noise.
67 +
68 +### Behavior
69 +
70 +- **While streaming**, if the turn is still inside its think block, the TUI
71 + shows the last three wrapped lines of the reasoning live, dim italic, under
72 + the thinking spinner. Once visible (non-think) text arrives, the reply
73 + streams as before.
74 +- **Finished replies** collapse the reasoning to a one-line dim indicator with
75 + the line count, e.g. `· thought for a bit (12 lines), /thinking to show`.
76 +- **`/thinking [on|off]`** (bare flips) expands the full reasoning block, dim
77 + and visually separated, above each reply across the whole transcript, and
78 + collapses it again when turned off.
79 +
80 +### Boundaries
81 +
82 +- Display only. Nothing changes in what is sent to the model, what is saved to
83 + the session store, or what goes over ACP, where reasoning stays stripped and
84 + editors render their own thought UI. `/thinking` is TUI-only and not
85 + advertised over ACP, the same precedent as `/resume`.
86 +- Restored sessions re-split think blocks on entry, so `/resume` and the
87 + History tab keep the indicator behavior.
88 +- The TUI streams only when no tools are offered (on-device tool turns buffer
89 + to detect tool calls), so the live tail appears exactly on the turns that can
90 + stream, which are also the turns where think deltas exist.
91 +
92 +### Implementation notes
93 +
94 +The live-tail extraction is a pure, width-aware function with its own greedy
95 +word wrap (hard-splitting over-wide words), unit-tested without ratatui.
96 +
97 +---
98 +
99 +## 3. Follow-ups worth considering
100 +
101 +- Copilot CLI's Issues and Pull requests tabs have a natural sigit equivalent
102 + once the MCP repo workflow tools (sigit-si #3) are consumed by the client: a
103 + fourth tab listing issues and PRs for the current repo when its origin points
104 + at sigit.si.
105 +- A persistent setting for the thinking toggle (settings.toml) if the
106 + per-session default proves annoying.
107 +- Coarse ages in the History tab could show absolute timestamps on a keypress
108 + if precision is ever needed.