Skip to content

TUI display toggles ​

The Ink CLI has two complementary toggle families: show (whether a row appears at all) and verbose (how much detail when it does). Both are TUI-side render state — the server keeps streaming everything either way.

Defaults from config ​

~/.somora/config.yaml:

yaml
tui:
  show:
    memory: true            # [memory · …] inject lines visible
    tools: true             # [tool call · …] / [tool result · …] visible
  verbose:
    tools: false            # full input/output payloads expanded
    memory: false           # full memory inject text expanded
    system: false           # /verbose system on flag at boot
    thinking: false         # model thinking text above each reply

The TUI fetches these from the server at startup (GET /tui-config) and uses them as initial values. Single config reader: server.

/show — line visibility ​

/show                       — list current state
/show memory on|off         — show/hide [memory · …] inject lines
/show tools on|off          — show/hide [tool call · …] / [tool result · …]
                              AND [◌ engine · …] meta lines

When a flag is off, the corresponding SSE event still arrives at the TUI but is dropped before the row is appended to the scrollback. New events are dropped going forward; rows that already rendered stay as-is.

The header surfaces the current state with mem ✓ tools ✗ badges.

Not gated by any flag: the warn line the TUI prints when a turn was answered by a fallback: model (⇄ model fallback: <primary> (<reason>) failed before producing anything — answering with <model>, every failed hop of a chain listed). It is a system line, always visible, and is replayed from history on reconnect.

/show tools is also the gate for engine_meta rows — codex-cli emits internal plan/checklist items (itemType: todo_list) that we persist alongside tool calls. They render with a dimmer ◌ codex · plan · 3 tasks · 2 done prefix and expand to a task list when /verbose tools on. Conceptually they belong to the same "agent internals" bucket as tool calls, hence the shared toggle. See setup.md for the mechanism.

/verbose — detail level ​

/verbose                    — list current state
/verbose tools on|off       — full input/output payload below each tool call/result
/verbose memory on|off      — full memory inject text below each [memory · …] line
/verbose system on          — print the agent's persona system prompt as a one-shot block
/verbose system off         — clear the system flag (no effect on previously printed blocks)
/verbose thinking on|off    — show the model's thinking text above each reply
                              (also in the web client, where it is on by default;
                              same switch as the ••• menu checkbox)

Verbose data is always on the wire — server pre-formats and includes it in every relevant SSE event:

eventalways sentverbose-only render trigger
tooltool, summarydetails (pretty-printed JSON payload)
memorycount, topScore, refsfullText (the inject block as it landed in the model's context)
thinkingtext (cumulative), truncatedthe whole event — nothing renders unless /verbose thinking on
——/verbose system on fetches GET /agents/:agent/system-prompt once and prints it

This means toggling /verbose tools on is instant for the next tool call — no reconnection needed. Already-rendered rows do not retroactively expand (consistent with /show).

Why details lives on the wire ​

A natural alternative is "client requests verbose payloads". We chose "server always sends, client always renders selectively" because:

  1. Bandwidth is local. Even a chunky JSON tool result is kilobytes on a localhost SSE — not worth the protocol round-trip to negotiate.
  2. No client-side schema knowledge. The server already pretty-prints payloads in src/server/tool-format.ts. Clients render strings, never inspect tool-specific structure. Same thin-client principle as the summary line.
  3. Future clients (Orbit, web). They consume the same SSE events and can implement the verbose toggle without a new endpoint.

Interaction with each other ​

/show memory off wins over /verbose memory on — if the line isn't shown at all, there's no place to attach the verbose details. Same for tools. Treat /show as the master switch, /verbose as the zoom level.

/verbose thinking — the model's reasoning text ​

Off by default. When on, the model's thinking content lands in the scrollback as a gray, indented 🧠 thinking block directly above the reply it produced ((truncated) is appended to the label when the server cut the text at its cap). While the model is still thinking and no reply text has arrived yet, the last six lines of the thinking text show live where the reply will appear; the first reply token replaces them. A finalized block renders at most 40 lines and ends with … (+N lines) for the rest, so a long reasoning dump cannot flood the terminal. Switching to a session replays stored thinking rows only when the toggle is on at that moment. The block only appears for engines and models that surface thinking at all — see thinking.md for the engine matrix. The 🧠 thinking… header badge and the reasoning token counter work regardless of this toggle.

/queue — what the session is doing ​

The status line carries the session's work counters — ⌛3 ▶1 🤖2 ↩1: waiting, running, started from here, arriving — and is empty when the session is idle. They count every kind of turn, not only what you typed: a question from another agent, a sub-agent brief, a sentinel fire, a question from a call.

/queue                      — the list: Running, Waiting (numbered), Arriving, From here (numbered on)
/queue rm <n>               — remove the n-th waiting entry; a running entry under From here is stopped

Removing works on any waiting entry, whoever queued it: a message of your own comes back into the input, another agent's question is reported to that agent as failed with the reason, a sub-agent brief as cancelled, a sentinel fire as skipped. An entry that started meanwhile says so — Esc aborts a running turn. The list reads GET /agents/:agent/sessions/:session/work (see api.md); the counters come from the same route, refetched on every queue event, on /queue rm and on a session switch — never polled while idle.

/export — the session as a file ​

/export                     — write the session as Markdown to ./<agent>-<session>.md
/export json [path]         — the raw event log as JSONL (one event per line)
/export markdown [path]     — readable transcript; path optional

The TUI fetches the session from the server (GET /agents/:agent/sessions/:session/export?format=…, see api.md) and writes the file locally; the notice names the absolute path and the size.