titah with no arguments spawns a local server on a random port and attaches
the TUI to it. It takes over the alternate screen buffer, the way nvim does:
whatever was in your terminal stays hidden while Titah runs, and is restored
intact on exit.
Layout
The opening screen centres the prompt beneath the ASCII logo. After your first prompt the layout switches:
- an info panel on top — model, agent, session, token and cost counters
- history in the middle
- the prompt pinned to the bottom, with a spinner above it while work runs
The header panel carries the Titah mark beside the session information. On terminals under 26 rows the mark is dropped — conversation history is worth more than decoration when space is scarce.
Markdown rendering
Assistant answers are rendered as markdown: headings, bold, italics, inline code, fenced code blocks, lists, quotes and rules.
Hasil
• Item satu
• Item dua
┌ ts
const a = 1
└
Two deliberate choices:
- Your own prompts are never rendered. What you typed is not markdown, and rendering it would hide characters you meant to write — for instance when asking about markdown syntax itself.
- Underscores are never emphasis. Coding-agent answers are full of
snake_case_nameand__init__; treating_as emphasis turns identifiers into wrong-looking italics.*italic*and**bold**still work.
Code blocks are not parsed as markdown either — * and _ inside code are
code.
Command palette
Ctrl+P opens the palette without typing anything — the same key as opencode:
│ Commands · 10 · ↑↓ move · tab/enter select · esc close │
│ › /model Switch the model for this session │
│ /agent Switch the agent for this session │
│ /skill Insert a skill into your prompt │
│ /consensus Fan one question out to every agent │
Commands that need no arguments run immediately when selected. Those with
sub-options drill into a second menu — picking /model opens the list of models
from your config, and picking one switches the model for this session right
away:
│ Switch model · 6 · ↑↓ move · tab/enter select · esc close │
│ › 9router/ocode nemotron-3-ultra (via ocode) │
│ 9router/gapis gemini-3-flash (via gapis) │
│ ollama/qwen3.5:27b Qwen3.5 27B │
Commands that take arguments — /consensus, your own custom commands — are
inserted into the prompt instead, so you can type the argument.
Popups while typing
| Trigger | Shows |
|---|---|
@ | External agents, internal agents, and files in the working directory |
/ | Every command, built-in and custom |
↑↓ moves, Tab or Enter selects, Esc closes. Triggers only fire at the
start of a word, so [email protected] and /etc/hosts never open a popup
nobody asked for.
Keys
Keybindings follow opencode’s defaults, with Ctrl+X as the leader.
| Key | Action |
|---|---|
Enter | Send the prompt |
Ctrl+J | Newline inside the prompt |
Esc | Cancel the running turn |
Ctrl+P | Open the command palette |
Ctrl+R / Ctrl+X R | Cycle effort: default → low → medium → high → default |
Tab / Shift+Tab | Switch agent forwards / backwards (or select inside a popup) |
↑ / ↓ | Recall the previous / next prompt — on a draft that spans more than one row these move the cursor between rows first, wrapped rows included |
Ctrl+← / Ctrl+→ | Move the cursor a word at a time. Alt+← / Alt+→ and Alt+B / Alt+F do the same, because no single sequence reaches every terminal |
Shift+↑ / Shift+↓ | Scroll the history one line |
Ctrl+X N | New session |
Ctrl+X L | List sessions |
Ctrl+X U | Undo the last turn’s changes |
Ctrl+X D | Collapse every tool block, and again to bring them back — works mid-turn, and a running tool shows its arguments |
Ctrl+X B / End | Jump to the newest message |
Ctrl+X M | Toggle mouse capture |
Ctrl+X ↓ | Toggle the sub-agent panel — Enter on a row opens that sub-agent’s transcript |
Ctrl+X S | Open a sub-agent’s transcript — every sub-agent this session has run, finished turns included |
Ctrl+X ← / → | Toggle the left / right side panel |
Ctrl+X E | Refresh both side panels |
Ctrl+X F | Cycle the keyboard through the side-panel boxes — Esc returns it without closing anything |
Ctrl+X Z | Fold or unfold the focused box. Clicking its title row does the same |
Ctrl+X X | Extensions — search the registry, install with Enter |
Ctrl+X ? | Short help |
| Click a tool line | Collapse/expand just that block |
| Mouse wheel | Scroll the history |
Ctrl+Alt+U / Ctrl+Alt+D | Scroll half a page |
PageUp / PageDown | Scroll a page |
Ctrl+G / Home | Jump to the start |
Ctrl+D | Quit |
Ctrl+C | Clear the input; twice on an empty input quits |
y / a / n | Answer a permission dialog: once / always / deny |
Inside the prompt, the usual readline keys work: Ctrl+A / Ctrl+E for the
start and end of the current line — not of the whole draft — Ctrl+B /
Ctrl+F to move a character, Ctrl+U to delete to the start of the line.
The cursor walks visual rows, not just \n. A long sentence the terminal
wrapped is no longer skipped in one press, and the editor box is measured from
those same visual rows, so a long single-line draft stops eating the bottom row
of history.
!!! note “There is no <leader>q”
Four ways to quit — Ctrl+C twice, Ctrl+D, <leader>q, /exit — meant
three of them had to be remembered without ever being used, and each was a
key that could be hit by accident. What is left: Ctrl+D for fingers,
/exit for people who type, Ctrl+C twice for reflex.
Selecting text to copy
While Titah tracks the mouse, the terminal stops using clicks to highlight text
— the two cannot both be on. Ctrl+X M turns tracking off so normal selection
works, and the footer keeps saying ✂ mouse off until you turn it back on. Most
terminals also let you hold Shift while dragging to bypass tracking without
toggling anything.
Configuring keys
{ "keybinds": { "session_interrupt": "ctrl+g", "tool_details": "none" } }
"none" disables an action.
Two honest notes about “1:1 with opencode”:
- opencode defines 184 actions; Titah implements the subset that matters here, with identical keys.
tool_detailsis left unbound by opencode. Titah binds it toCtrl+XD, because a collapsible tool block with no key to collapse it is a feature nobody can find.- Tool blocks are open by default — the work you just asked for should not sit behind one more keypress. Reasoning blocks stay folded, because they are usually far longer than the answer they lead to; both use the same mechanism, only the default differs.
input_newline in opencode is shift+return,ctrl+return,alt+return,ctrl+j.
Most terminals cannot tell Shift+Enter from Enter, so the one that actually
works is Ctrl+J.
The sub-agent panel
Ctrl+X then ↓ toggles a panel listing every sub-agent of the current
turn, with each row’s status. While it is open it owns the keyboard — ↑ /
↓ select, Enter (or a click) opens that sub-agent’s transcript, x x
cancels the selected sub-agent, Esc closes, and everything else is swallowed
rather than typed into your prompt behind it.
Full behaviour in Sub-agents.
Reading what a sub-agent did
A sub-agent runs in its own session, so its transcript is a real one. Enter on
a panel row opens it as a full page, streaming along live while the work is
still going; Ctrl+X S opens the same page for any sub-agent this session has
run, including turns already finished — the panel itself is cleared on every new
prompt, so without that list yesterday’s work had no way in from the screen.
The page is read-only and Esc returns. A prompt box there would promise
messages you could send into a session the coordinator is already driving.
Super agents are the exception: they run a CLI outside Titah and only send their final answer back, so their page says so rather than drawing an empty screen.
Side panels are stacks
Extensions listed for the same side are drawn as separate boxes, top to
bottom in config order. Height runs out faster than width does, so a box folds
to a single title line with ▸ — Ctrl+X Z, a click on its title, or
"collapsed": true in config. A folded box is not rendered at all, so folding a
git panel also stops it running git status on every refresh, and below
panel.boxFloor rows the bottom box folds itself and says so.
Ctrl+X F cycles the keyboard through the drawn boxes; while a box has it,
+ / - / = widen, narrow, or reset that side. Full behaviour, including the
config block, in Extensions.
Sessions in the TUI
/session lists your saved sessions newest first, with the current one marked.
Picking one loads its history and points the stream at it; /new starts a fresh
session in the same directory. Both clear whatever you had half-typed —
carrying a draft into a different conversation is never what you meant.