The leader key and the command palette
You’ve shipped a fix to feedmill and you’re settling into the TUI for real now — and within an hour something nags at you. You keep flicking your hand toward a trackpad to do the obvious things: switch back to yesterday’s session, change the model for a heavier parse job, get out of this dark theme that’s wrong for the room. There’s nothing to click. The TUI supports a mouse — mouse defaults to true, so scroll and select work — 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 action 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. Press ctrl+p and the command palette opens — a searchable list of every command OpenCode has registered. Type a few letters and it filters:
> (ctrl+p)
┌─ command palette ───────────────────────────┐ │ sess▏ │ ├─────────────────────────────────────────────┤ │ Session: list / switch <leader>l │ │ Session: new <leader>n │ │ Session: share │ └─────────────────────────────────────────────┘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. The reason for a leader at all is conflict avoidance: a TUI lives inside your terminal, and binding bare ctrl-combos would collide with the terminal’s own shortcuts and your shell’s. Routing actions through a leader keeps OpenCode’s 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 pickerPress 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. 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. 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. You’ve already been typing slash commands — /sessions, /themes, /models — into the prompt. Those 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. Under the hood they converge on the same actions — the keybinds you’ll configure as session_list, theme_list, and so on. 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). 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.
A couple of changes you might actually make on day one. 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+a", "command_list": "ctrl+p", "session_list": "<leader>s" }}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. 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.
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 feedmill you’re constantly context-switching: jump to the session where you were debugging the JSON 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 even if it existed.
You can now reach every action in the TUI two ways without leaving the keyboard, 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 across days. Next: juggle and resume sessions.