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