Course · OpenCode · Living in the TUI
The leader key and the command palette
Spend any real stretch of work in the TUI (OpenCode’s full-screen terminal interface) and something nags at you: you keep flicking your hand toward a trackpad to do the obvious things. Switch to the session (one running conversation with the agent) you had open before this one. Change the model for a heavier parse job. Get out of a theme that’s wrong for the room. The TUI supports a mouse - mouse (mouse capture) defaults to true, so the TUI handles scroll and select itself (as of October 2026; TUI documentation) - but it was built to be driven from the keyboard, and you can feel the friction of fighting that grain. The fix isn’t to find the mouse. It’s to learn the two entry points that put every command within reach of the keyboard, and the ones you use most two keystrokes away.
The discoverable door: ctrl+p
Section titled “The discoverable door: ctrl+p”Start with the one you can’t get wrong, because it requires remembering nothing. With the TUI open (run opencode in your repo if you haven’t launched it yet), press ctrl+p and the command palette opens - a searchable list of every command OpenCode has registered. Type a few letters and it filters - an illustrative rendering:
> (ctrl+p)
┌─ command palette ───────────────────────────┐ │ sess▏ │ ├─────────────────────────────────────────────┤ │ Session: list / switch <leader>l │ │ Session: new <leader>n │ └─────────────────────────────────────────────┘Two things to notice in that little box, because they’re the whole lesson. First, you found “switch session” without knowing its name - you typed sess and it surfaced. The palette is how you discover what the TUI can do, which means you never have to memorize the full command set up front; you reach for ctrl+p, describe what you want, and run it. Second, look at the right-hand column: the palette shows you the keybind for each command right next to it. Session: list is <leader>l. The palette isn’t just a runner - it’s how you learn the chords, one at a time, in the flow of actually using them.
So the honest path to fluency is: use ctrl+p for everything at first, and let it teach you the chords for the three or four things you do constantly.
The fast door: the leader key
Section titled “The fast door: the leader key”Once you know a chord, you skip the palette. OpenCode uses a leader key for most of its keybinds - a prefix you press first, then release, then press the action key. The default leader is ctrl+x, and the palette stays on a bare ctrl+p (as of October 2026; keybinds documentation). The reason for a leader at all is conflict avoidance: a TUI lives inside your terminal, and binding every action to a bare ctrl-combo would collide with the terminal’s own shortcuts and your shell’s. OpenCode keeps a few hot actions on bare keys (the palette on ctrl+p, for one) and routes most of the rest through the leader, which keeps its keymap out of everyone else’s way.
So switching sessions, the thing you reached for the mouse to do, is:
ctrl+x then l → open the session list ctrl+x then n → start a new session ctrl+x then t → open the theme picker ctrl+x then m → open the model listPress ctrl+x, let go, press l. The session switcher opens - same dialog the palette would have run, reached in two keystrokes instead of a search. That’s the move you were missing. Change the theme that’s wrong for the room with ctrl+x t, or open the model list for a heavier job with ctrl+x m. Spin up a clean session for a tangent with ctrl+x n. The command palette stays bound to a bare ctrl+p rather than a leader chord, on purpose - it’s the one thing you want reachable in a single stroke, since it’s the door to everything else.
There’s a timing detail worth knowing before it trips you. After you press the leader, OpenCode waits a fixed window for the action key. That window is leader_timeout, and it defaults to 2000 milliseconds (as of October 2026; keybinds documentation). Press ctrl+x, get distracted for three seconds, and the chord lapses - your next keypress is just a keypress, not the second half of a binding. If two seconds feels long or short for your hands, it’s a number you can change, which brings us to the real point of the lesson.
Slash commands and chords are the same commands
Section titled “Slash commands and chords are the same commands”Before the config, one unification that makes the whole system click. Slash commands - /sessions, /themes, /models - typed at the prompt are not a separate feature from the leader chords. They’re a third way to trigger the same registered commands:
/sessions ≈ ctrl+x l ≈ (ctrl+p → "session list") /themes ≈ ctrl+x t ≈ (ctrl+p → "theme list")One command, three doors: type its slash name when your hands are already in the prompt, fire its leader chord when you know it cold, or find it in the palette when you don’t. OpenCode documents these as related TUI commands and keybind actions; exact aliases and bindings can vary by release. Knowing this means you stop thinking of slash commands and keybinds as two things to learn. They’re one set of capabilities with three ways in, and you pick the door that’s closest to your hands at that moment.
Make the keys yours: tui.json
Section titled “Make the keys yours: tui.json”The defaults are sensible, but they’re defaults - every binding here is remappable. TUI behavior, including the full keymap and the leader settings, lives in tui.json (it also accepts tui.jsonc if you want comments; as of October 2026, TUI documentation). It’s a separate file from opencode.json, which is worth keeping straight: model and provider config lives in opencode.json, while the TUI’s keys and timing live in tui.json. Put it at ~/.config/opencode/tui.json to remap the keys in every repo on your machine, or beside a project’s opencode.json to scope it to that repo; a personal keymap usually belongs in the global file (config documentation, as of October 2026).
A couple of changes you might make right away. Two seconds after the leader is too patient for your taste? Tighten it. And if ctrl+x itself clashes with something you’ve trained your fingers on elsewhere - it’s a common terminal binding - move the leader:
{ "$schema": "https://opencode.ai/tui.json", "leader_timeout": 800, "keybinds": { "leader": "ctrl+o", "session_list": "<leader>j" }}Two rules keep this painless. First, keybinds is merged with the built-in defaults, not a replacement - you only list the bindings you want to change, and everything you leave out keeps its default (“keybinds is merged with built-in defaults, so you only need to configure the shortcuts you want to change” - TUI documentation, as of October 2026). Second, you can disable a binding by setting it to "none" or false, which is the clean way to silence a chord you keep firing by accident rather than leaving it live. Note that the leader itself is set inside keybinds (as "leader"), while leader_timeout sits at the top level alongside $schema. A new leader moves every <leader> chord with it, so with this file each ctrl+x chord listed above starts with ctrl+o instead.
One habit on top of the two rules: whatever key you bind, pick one no default already uses. That holds for a new leader too. ctrl+a looks like an obvious leader, but by default it already moves the cursor to the start of the input line (input_line_home) and is the default for model_provider_list too, which is why the example above uses ctrl+o, a key no default claims (as of October 2026; keybinds documentation). For leader chords, plenty are already claimed by defaults - status_view sits on <leader>s, for instance - and OpenCode documents no rule for what happens when your binding takes a chord another action still holds, so sidestep the question rather than test it in your config. That’s why the example above, which moves session_list only to show a remap, puts it on <leader>j; the palette’s right-hand column is your quick check for which chords are already spoken for, and the full default list in the keybinds documentation is the check for bare keys.
Notice what you’ve actually bought yourself here. The reason a keyboard-first TUI beats a mouse for this kind of work isn’t purism - it’s that on a project like feedmill (the course’s illustrative feed aggregator, where you might have several parser threads on the go at once) you’re constantly context-switching: jump to the session where you were debugging the JSON feed parser, swap to a cheaper model for a throwaway question, flip themes when you move from desk to couch. Each of those is now a chord, not a hunt. The mouse you kept reaching for would have been the slow path.
You can now reach every command in the TUI without leaving the keyboard, most of them up to three ways, and bend the keymap to your hands. The next thing that keymap unlocks is continuity - because the sessions you’ve been switching to are OpenCode’s memory, and they outlive any single sitting. Next: juggle and resume sessions.