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 and
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.dstarts a delete; a seconddon 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.rrefreshes. 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.
ltoggles Local Inference, with a note that the toggle takes effect at the next model selection because the running backend is not swapped.rrefreshes.
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.
/thinkingis TUI-only and not advertised over ACP, the same precedent as/resume. - Restored sessions re-split think blocks on entry, so
/resumeand 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.