Skip to content

TUI ​

Documentation in progress

Some sections are still incomplete.

The same workspace, without the GUI:

bash
thinkterm tui [DOMAIN ...]

This is a subcommand of the thinkterm binary rather than a second program, so it costs nothing while it is not running.

It is a peer, not a mirror ​

The TUI is not a read-only view of the GUI. It is another client of the same authoritative server, and it holds itself to the same rules:

  • Space, Project and Thread data is accepted only from server snapshots
  • every change waits for the server to acknowledge it before the display updates

So having the GUI and the TUI open at once cannot leave the two disagreeing about what exists. A server that is offline cannot be changed from the TUI at all: nothing is queued to be sent later.

What it does ​

It covers the work you do inside a terminal: new tabs, splits, resizing, zooming, closing panes and tabs, copy mode with a scrollback search, and full mouse support.

On the sidebar it creates and renames Spaces, Projects and Threads, pins and unpins Threads, and deletes at every level — confirming each time, because a deletion can end the sessions inside. Dragging reorders Threads within their Project and Projects within their Space; Spaces themselves keep their order. It attaches and retries servers from the connections panel described below, and jumps to the next Thread that wants attention.

What it does not have ​

The TUI is narrower than the desktop app. It has no archive, no Thread references, no Files, Notes, Snippets or Agents panels, no plugins, no Live Overview and no tab icons. A Project it creates is not tied to a folder you pick: it is named by you and starts in your home directory. Those things are not lost by using the TUI — they stay as the desktop left them — but you need the desktop app to reach them.

Who drives the terminal ​

The data is shared, but a terminal has one driver at a time. The default is handoff — a client takes the terminal when you interact with it — and the TUI can switch the server to a shared, tmux-like mode where every attached client sees the same grid instead. The mode belongs to the server and is kept across its restarts, so it is a decision about that server rather than about this client. In the shared mode, the last client to interact with a tab decides its size. Remote describes the handoff side of it.

The switch is in the ⋮ menu on the tab bar, as A · Shared (tmux-like) and B · Handoff (exclusive), with a tick beside the current one. The bottom status bar, when it is on, names the state: A SHARED, B ACTIVE while this TUI holds the terminal, or B VIEW · example-host while another device does. In the shared mode, a tab whose size another client decides reads A SHARED · VIEW 120×30 instead, with the size the tab is held at.

A terminal another device is holding is covered by a note saying where it is in use, and Click or scroll to continue. In the TUI only a click or a scroll takes it over. The keyboard never does: there is no telling a keystroke meant to take control from one meant for the terminal underneath, so keys typed while the note is up go nowhere.

Exiting does not end anything ​

Quitting the TUI detaches from the server. Every session inside it keeps running, exactly as when a GUI client disconnects.

That is what makes the obvious use case work: SSH into a machine, run thinkterm tui, do some work, disconnect. Or skip the GUI entirely on a machine where you never wanted one.

Detach with Ctrl-b d or Ctrl-b q, the Detach entry in the ⋮ menu, or the Detach button on the status bar.

It will not open inside its own server ​

A TUI running in a pane of the very server it attaches to would be drawing that server's terminals inside one of them. ThinkTerm refuses: it lets go of every server it had attached to and exits with an error, leaving your terminal as it was. The error says to run thinkterm tui from another terminal application, or to pick a different domain.

Sameness is decided by the server's identity rather than by a domain's name: every ThinkTerm pane records which server hosts it, and a target that reports the same identity is refused. A pane old enough to carry no such record is refused too, since a different target cannot be proven from it.

The screen ​

The sidebar is a tree: each attached server, its Spaces, their Projects, and the Threads inside. ▾ and ▸ fold a level away. Every row carries a ⋯ button that opens its menu, and Space and Project rows a + that adds a Project or a Thread. Above the tree is ⊕ New Thread, which adds one to the Project you are in, and a WORKSPACES heading whose + adds a Project to the Space you are in. ⚙ Settings sits at the bottom. The ≡ at the top shows and hides the sidebar.

A Thread's row starts with a marker:

MarkerMeaning
*Something is running in it
!It needs attention, or it was marked unread
+Its work finished while you were not looking
★It is pinned

Opening a Thread clears its unread mark on the server, for every client. Ctrl-b o goes to the next Thread with a ! or a +, in tree order and wrapping round. When the TUI starts with no Thread remembered, it opens the one that most wants attention.

The tab bar holds the selected Thread's tabs, a ✕ on each to close it, + for a new tab and ⋮ for the main menu. When the tabs do not fit, < and > at the ends say how many are hidden. The wheel over the tab bar moves between tabs.

The pane nav bar is a strip along the top of each pane. On its left are the panes stacked in that pane's place — several terminals sharing one rectangle, reached as tabs of their own — each with a ✕. On its right are four buttons: ⤢ zoom (⤡ while zoomed), ◫ split right, ⊟ split down, and + for a new terminal stacked in the same place. A pane too narrow for all four drops the splits first and keeps zoom.

The status bar at the bottom is off by default. It shows the current mode's keys, messages, the access state, a ! N count of Threads wanting attention — click it to go to the next — and Detach. With it off, messages and mode hints appear as overlays and never take a row from the terminal.

Keys ​

Everything goes to the terminal except what follows the prefix, Ctrl-b. Press Ctrl-b, release, then the command key. Ctrl-b Ctrl-b sends a literal Ctrl-b to the program in the pane. Ctrl-b ? shows the key summary; Esc or ? closes it.

After the prefix ​

KeyAction
?Help
d or qDetach
b or sShow or hide the sidebar
g or wNavigate mode
CConnections panel
,Settings
cNew tab in the selected Thread
n / pNext / previous tab
1 … 9Tab 1 to 9
↑ / ↓Previous / next Thread
oNext Thread that wants attention
TabNext pane
h j k l, ← →Focus the pane to the left, below, above, right
vSplit right
-Split down
xClose the pane, after confirming
XClose the tab, after confirming
zZoom the pane, or unzoom it
rResize mode
[Copy mode

Any other key after the prefix does nothing but say so.

Opens the sidebar and keeps the keyboard there, so you can walk the tree without the prefix.

KeyAction
j / k, ↓ / ↑Next / previous Thread
h / l, ← / →Focus the pane to the left / right
n / pNext / previous tab
?Help
Enter or EscLeave navigate mode

Resize mode ​

KeyAction
h j k l, or the arrowsMove the focused pane's edge one cell that way
Enter or EscFinish

Copy mode ​

Copy mode puts a cursor in the focused pane that moves through the scrollback, independent of the program running there.

KeyAction
h j k l, or the arrowsMove the cursor
PgUp / PgDnScroll ten lines
EndBack to the bottom
SpaceStart a selection; press again to end it
y, Y or EnterCopy the selection
/Search forward
?Search backward
n / NNext / previous match
EscLeave copy mode

A search covers the whole scrollback and ignores case. A forward search jumps to the first match and a backward one to the last, moving the cursor there; No matches says when there is none.

WhereKeys
A menuj / k or the arrows to move, Enter to choose, Esc to close
A name promptType, Backspace to erase, Enter to accept, Esc to cancel
A confirmationEnter or y to confirm, Esc or n to cancel

A prompt left empty does nothing.

Mouse ​

With Application mouse on, which is the default, the mouse does most of what the keys do:

  • Click a Thread to open it, a tab to show it, a pane to focus it. A click or a wheel turn on a terminal also takes it over from another device.
  • Drag in a pane to select text. Near the top or bottom edge the selection scrolls the pane. A drag along one row has to cover three cells before it counts, so a tap that slips a cell or two is still a click.
  • Right-click anything for its menu. ⋯ on a sidebar row opens the same menu.
  • Drag a divider to resize the panes either side, the sidebar's right edge to resize the sidebar, and a pane's scrollbar to move through its scrollback. The sidebar width is saved.
  • Drag a Thread onto another Thread of the same Project, or a Project onto another Project of the same Space, to move it in front of it.

When a program in the pane has asked for the mouse — vim, htop, less with mouse support — clicks and drags go to that program instead. Hold Shift to select text yourself. Shift with the right button, and the middle button, are always passed to the program.

The wheel over a pane does one of three things. If the program asked for the mouse, it gets the wheel. If the pane is on the alternate screen — a full-screen program that did not ask for the mouse — each notch becomes arrow keys, which is what makes less and git log scroll from a touchscreen. Otherwise it scrolls the scrollback. Holding Shift, or being already scrolled back, always scrolls the scrollback. One notch is scroll_lines lines.

Right-click menus ​

OnOffers
A serverNew Space, Retry connection, Disconnect
A SpaceNew Project, Rename Space, Delete from server, End sessions and delete
A ProjectNew Thread, Rename Project, End sessions and remove
A ThreadOpen, New Thread, Rename Thread, Pin or Unpin, End session and delete
A tabOpen, New Tab, Rename Tab, Close Tab
A paneCopy, Paste, Split Right, Split Down, Zoom, Close Pane
⋮ on the tab barNew Tab, Split Right, Split Down, Copy Mode, Paste, Connections, A · Shared (tmux-like), B · Handoff (exclusive), TUI Settings, Toggle Sidebar, Help, Detach

Copy is available only when a finished selection is in that pane.

What creating and deleting do ​

New Space asks for a name and creates the Space with a Project called Home in your home directory and a Thread called main. New Project asks for a name and creates the Project, in your home directory, with a main Thread. New Thread asks for a name. Each opens what it made.

Deleting always asks first, and where it ends panes the dialog says how many:

  • Delete from server removes a Space from the server for every client and leaves its sessions running.
  • End sessions and delete removes the Space and ends every pane in it.
  • End sessions and remove removes a Project and ends its panes.
  • End session and delete removes a Thread and ends its panes.
  • Close Pane and Close Tab end those panes on the server, for every client.

Disconnect on a server is not a deletion: the TUI lets go of it, and its sessions keep running.

Copy and paste ​

With Copy on select on, the default, finishing a drag copies it, and copy mode copies with y. Turn it off and a finished selection stays on screen; Ctrl-C then copies it rather than interrupting the program. Once copied, the selection is dropped, so the next Ctrl-C reaches the program again.

The TUI writes the clipboard through the system's own tools:

SystemUsed
macOSpbcopy and pbpaste
Linuxwl-copy and wl-paste under Wayland, then xclip, then xsel
WindowsThe Windows clipboard

When none of these can write — typically over SSH to a Linux machine with no display — the TUI sends the text to the terminal it runs in as an OSC 52 sequence instead, and a terminal that honours OSC 52 puts it on the clipboard of the machine in front of you. Whether that works depends on that terminal, not on ThinkTerm.

Paste in a menu reads the clipboard through the same tools, so over SSH it reads the remote machine's clipboard, or fails. Your terminal's own paste shortcut always works: the TUI hands what it receives to the focused pane.

Copying and pasting are limited to 8 MiB at a time.

Narrow screens and phones ​

The TUI changes shape with the width of the terminal it runs in.

  • Wide — the sidebar sits beside the terminal at the width you gave it.
  • Compact — less than 24 columns wider than narrow_width, the sidebar is held to 18 columns.
  • Narrow — at narrow_width columns or fewer, 64 by default, the tree no longer shares the screen. It covers the terminal while it is open and gets out of the way once you pick a Thread; ≡ brings it back. A narrow TUI always starts on the terminal, and opening or closing the tree there is not saved, so a phone and a desktop sharing one tui.toml do not overwrite each other's choice.

Phones vary widely in how many columns they report, so narrow_width is the one number worth adjusting by hand.

Touch targets sizes the buttons for a fingertip: wider buttons, and a two-row bar at the top. Left at Auto, it follows the narrow layout, which is right most of the time and wrong when a phone held sideways reports enough columns to look like a desktop — hence the setting.

On a phone the pane nav bar is the only place a finger can reach zoom, split and a new terminal, since there is no Ctrl-b on a soft keyboard worth the name. Even a short pane keeps its bar.

Settings ​

Ctrl-b ,, ⚙ Settings at the foot of the sidebar, or TUI Settings in the ⋮ menu opens the settings screen. ↑ ↓ or j k move between rows; ← →, h l, Enter or Space change the value; Esc closes it. A click on a row changes it too. Every change applies at once and is saved.

The screen shows ten rows. Two more settings live only in the file: sidebar_width, which dragging the sidebar edge also sets, and narrow_width.

Key in tui.tomlOn screenDefaultValues
themeThememonochrome-darkOne of the ten themes below
sidebar_visibleSidebartruetrue, false
pane_nav_barPane nav bartruetrue, false
pane_bordersPane borderstruetrue, false
pane_scrollbarsPane scrollbarsfalsetrue, false
show_status_barBottom status barfalsetrue, false
mouseApplication mousetruetrue, false
copy_on_selectCopy on selecttruetrue, false
touch_targetsTouch targetsunset (Auto)unset, true, false
scroll_linesScroll lines31 to 20
sidebar_width—2618 to 36 columns
narrow_width—6420 to 200 columns

A value outside its range is pulled back into it. A border needs room to spare and a scrollbar takes a column, so both are drawn only on panes big enough for them; the scrollbar is off by default because the column it takes is one the server is not told about.

Application mouse off stops ordinary clicks, drags and wheel turns reaching programs as mouse events: clicks and drags then always select, and the wheel scrolls, or sends arrow keys on the alternate screen.

A minimal tui.toml:

toml
theme = "tokyo-night"
narrow_width = 80
touch_targets = true

Themes ​

themeOn screen
monochrome-darkMonochrome Dark
monochrome-lightMonochrome Light
terminalTerminal Default
catppuccinCatppuccin
tokyo-nightTokyo Night
draculaDracula
nordNord
gruvboxGruvbox
solarized-darkSolarized Dark
solarized-lightSolarized Light

The theme colours the TUI's own chrome, not the terminals: those keep the colours the server gives them. The dark themes draw on whatever background your terminal already has, so the sidebar and the panes never disagree about it. The two light themes paint a background of their own, since dark text on a dark terminal would be unreadable. Terminal Default uses the terminal's own colours for text as well.

NO_COLOR does not turn the named themes grey. To have no colour, choose one of the two Monochrome themes.

The connections panel ​

Ctrl-b C, or Connections in the ⋮ menu, lists every server the TUI can attach to:

  • this machine, as Local — the running ThinkTerm desktop app if there is one, otherwise the local session server
  • the multiplexer domains in your configuration
  • the hosts in Remote Hosts that use ThinkTerm Connect, by their label

Hosts that cannot be attached are listed but greyed out, with the reason: a plain SSH host says Enable ThinkTerm Connect in Remote Hosts, a Mosh host that its sessions are not mux servers.

MarkState
●Attached
…Connecting
!Failed
○Not attached
-Cannot be attached
KeyAction
j / k, ↓ / ↑Move
Enter or rAttach, or retry
dDisconnect — the server keeps its sessions
qDetach and quit the TUI
EscClose the panel

A click on a row attaches it too. A retry of Local looks for the desktop app again, so after the app has quit it reaches the session server instead.

Options ​

OptionEffect
[DOMAIN ...]Which servers to attach to, by domain name. Without one, the TUI attaches to this machine only; others can be attached later from the connections panel
--prefer-muxConnect to a background mux server rather than a running ThinkTerm GUI. The default prefers the GUI
--class <NAME>The window class used to discover a running ThinkTerm GUI socket
--tui-config <PATH>Use a different TUI settings file. The TUI's settings are independent of the GUI's

Where its settings live ​

The default file is ~/.config/thinkterm/tui.toml, in TOML, honouring $XDG_CONFIG_HOME; $THINKTERM_TUI_CONFIG names another one without the flag. It is editable from inside the TUI, and only settings that differ from the defaults are written back, so a default stays a default rather than being frozen at today's value.

Separately, ~/.local/state/thinkterm/tui.json, honouring $XDG_STATE_HOME, remembers which domain, Thread and tab you were last on.