Skip to content

Latest commit

 

History

History
195 lines (174 loc) · 71 KB

File metadata and controls

195 lines (174 loc) · 71 KB

Keys

← README · Keys · Commands · Sessions · Configuration · How it works

Every binding below is a default, and every one of them is rebindable in the SETTINGS OVERLAY's HOTKEYS TAB (s) — see Configuration.

Worktree views

The grid isn't the only view. With a session selected:

Key View
g Git diff. Changed files down the left, the diff on the right, with a live fuzzy filter. With the pane reading a pull request (after a / jump onto one) it shows that pull request's diff instead, fetched whole with gh pr diff. Ctrl+r marks a file reviewed ✓ and sinks it to the bottom — nebula-side bookkeeping only, no git state is touched — and every mark clears itself when HEAD moves or the file changes again, so what's left unticked is genuinely what you haven't read. Ctrl+t folds the file list into a directory tree and back — every directory open, a chain of directories that hold only each other shown as one row (crates/nebula-tui/src) — and the choice is remembered; in the tree →/← open and fold a directory, Enter or a click flips it, a directory's row lists what changed under it, and a directory wears the ✓ once every file under it has one.
f Find file. Fuzzy finder over the worktree. Enter opens the file in an editor modal (vim by default; the editor setting or NEBULA_EDITOR picks another) — except a markdown file, which is read first: it opens as the rendered page in the file tabs below, where Enter is the editor and m shows the source — and Ctrl+y copies the path — ready to paste into an agent. The editor modal sits above every OVERLAY and is handed every key raw — vim owns Esc — so Ctrl+q is the only way out of it: one press kills the editor process and closes the modal, and the mouse is inert the whole time it is up.
F Find in files. git grep into the same modal; Enter opens the hit at its line.
i GitHub issues. The selected project's open issues, newest first down the left, the one under the cursor read on the right — number, title, author, labels, the description, and its comments once the cursor has rested on it for a moment (the gh issue list runs in the background once the cursor rests on the project, and again every couple of minutes while it stays selected, so the modal opens on rows already there; one gh issue view per issue you stop on). The list filters as you type, from the moment the modal is up: letters narrow the rows to the fuzzy matches of #15 title, best first with the cursor on the best and the matched letters lit (the count reads 2/14), ↑/↓ (or Ctrl+n/Ctrl+p) walk the matches, and Esc clears the filter before a second Esc closes. So the verbs are chords, as in the diff viewer. PgUp/PgDn, Ctrl+d/Ctrl+u and Shift+↑/Shift+↓ read (Ctrl+u kills the typed filter first, as in any line editor), Ctrl+o — or a click on the ↗ open in browser button pinned right on the reading pane's frame — opens the issue in the browser, the footer saying where it went; Ctrl+r asks GitHub again. Ctrl+c (or Ctrl+y, the grid's y as a chord) leaves a comment on the issue: a multi-row box (Shift+Enter for a newline) whose Enter posts the text as you with gh issue comment and lands back on the row, the pane saying the comment is on its way until GitHub answers and the conversation is read again; Esc, or an empty box, lands back without posting, and a post gh refused brings the box back with your text. Ctrl+e edits the issue itself, in place: the reading pane becomes a form on its title and description (Tab, ↑/↓ or a click move between the two, Shift+Enter breaks a line in the description), Enter sends both to GitHub as one gh issue edit and puts the pane back reading the new text, Esc drops the draft; a save GitHub refuses keeps the form up with gh's reason on it and your text intact. Enter opens the QUICK PROMPT for that issue and Shift+Tab picks one of your AGENT PRESETS for it — the box's own keys, and the same box either way, titled Quick prompt · issue #15 …, with Tab / Shift+Tab / Ctrl+N working as they do in any quick prompt. What that launch starts is an ISSUE SESSION: the issue's URL travels with the create and reaches the harness as context on every spawn and resume — Claude and Pi in the appended system prompt, Grok Build in its --rules, Codex, Cursor, Muse and OpenCode at the top of their first prompt — so the agent knows which issue the session is for before it reads a word of your task. Send the box empty and the task is Fix GitHub issue #15: <title>; it launches on the project's root branch, and Ctrl+N inside it cuts a fresh worktree named issue-15-<title-slug> instead (the box starts on that fresh worktree with New worktree on under Quick prompt in Settings → Agents).
v GitHub pull requests. The selected project's open pull requests down the left, newest first with the drafts below — the one under the cursor read on the right as the pane reads it: state, checks, branches, the description, then the conversation once the cursor has rested on it (the rows are the list the OPEN PRS beat already keeps warm, so the modal opens on them at once; one older than thirty seconds is re-asked underneath). The list filters as you type, as the ISSUES MODAL's does: letters narrow the rows to the fuzzy matches of #42 title, ↑/↓ (or Ctrl+n/Ctrl+p) walk the matches, Esc clears the filter before a second Esc closes, and the verbs are chords. PgUp/PgDn, Ctrl+d/Ctrl+u and Shift+↑/Shift+↓ read, Ctrl+r asks GitHub again. Enter opens the QUICK PROMPT for a PR SESSION on that pull request, Shift+Tab launches one of your AGENT PRESETS on it and Tab picks a harness and starts one bare — the box's own three keys, and in the project's checkout of the PR's head branch. Ctrl+c (or Ctrl+y) comments on it and lands back on the row, Ctrl+g opens its diff, Ctrl+o — or a click on the ↗ open in browser button pinned right on the reading pane's frame, or a double-click on the row — opens it in the browser and marks it read on the way out, as Shift+V does from a card; Esc closes.
(none — an agent opens it) File tabs. What nebula open <file>… raises when a session runs it — ask an agent to "open it" or "show me the file"; it never opens one unasked, and only text files — an image or any other binary is refused at the CLI, so the agent names the path instead. A modal with a tab strip like the SETTINGS OVERLAY's, one tab per file: ←/→, Tab/⇧Tab and 1-9 switch tabs, the focused tab's file is previewed underneath with the TREE BROWSER's highlighting — a markdown file as a rendered page (headings, lists, fenced code, tables, links; m flips it to the source and back, and the choice holds across tabs) — and Enter runs the editor in that pane (the tabs stay put; :q lands back on the strip with the file re-read). ↓/j from the strip drops into the preview, where j/k, Ctrl+d/Ctrl+u, PgUp/PgDn and Home/End scroll and ↑ off the top returns to the strip. This is the one OVERLAY where Ctrl+q is staged: from the editor or the preview it steps back to the tab strip, and only from the strip does it close; Esc backs out the same way.
b File tree browser. Tree on the left, syntax-highlighted preview on the right (a markdown file as a rendered page; Ctrl+r flips it to the source and back), and an always-live filter that narrows the tree to matching files and the directories holding them. → expands a directory and ← collapses it; Enter folds or unfolds a directory, and on a file it loads the file into the preview pane rather than the floating editor modal that f and F open — the tree stays where it is. The preview takes the DIFF VIEWER's scroll keys: Ctrl+d/Ctrl+u half pages (Ctrl+u only while the filter is empty — with text typed it is the LINE EDITOR's kill-to-start), Shift+↑/Shift+↓ a line, PgUp/PgDn a page, Home/End the ends. Ctrl+y copies the selected path, and dragging the tree/preview border resizes the tree side.

Full keymap

Context Key Action
The grid / fuzzy jump across every live project, worktree and session on the machine (Ctrl+n/p move, Ctrl+o opens the hit, Ctrl+f just lands the selection on it). Archived sessions are never rows here, whatever the grid's A toggle shows and however exactly you type the name: an archived session's PTY is released, so there is nothing to jump to — . / , skip them for the same reason. The list is flat — one row per thing, nothing folded under anything: each reads project/name, the project it lives in dim, then its own name (a session's title, a worktree's branch, a pull request's #42 title), with a dim 23m ago pinned right. Until you type it is a recent sessions list: the sessions and nothing else — no project or worktree rows in the way — in attention order, the ones waiting on you first, then the running ones, then the unread finishes, then the rest by last interaction, with the cursor on the top row, so / Enter is the fastest way back to what needs you or to what you last ran. Enter on a session that NEEDS FEEDBACK — the red row — attaches and focuses the TERMINAL PANE whatever palette_enter_attaches says, since the only thing to do with a jump to a question is answer it; Ctrl+f is still the way to only land on it. Typing reaches every row, projects and worktrees too, on lines of their own in that same order; the query runs over each row's full project/branch/session path, so a project's or branch's name narrows to what is under it, even the parts the row does not draw, and every visible row counts toward the (hits/total). Every open pull request nebula has listed is a row too, ↗ project/#42 title, searchable by number or title (# lists them all), and badged draft or ready for review after the title — the same states the PULL REQUESTS MODAL's rows wear, spelled out here where there is room (ready for review is an open pull request that is not a draft; it says nothing about approvals, checks or mergeability), or merge conflicts / checks failing in red, the row red with it, when GitHub says the pull request cannot merge as it stands — so a draft is told from a finished one, and a blocked one from either, before it is picked, by the word and not only by its color; the badge follows the next open-list answer, so a draft marked ready flips under an open palette. Enter on one selects its project and reads the pull request in the pane — no checkout or session of its own needed. Ctrl+o on it is the explicit way out to the browser, as is Enter on the row once landed
The grid . / , next / previous session in that same attention order, with no modal: one press lands on the next session waiting on you (then the running ones, then the unread finishes, then the rest by last interaction), wrapping at both ends. It is / Enter without the typing — a session in another project selects that project, its worktree and its row, and palette_enter_attaches decides whether the pane is attached and focused or only selected and previewed — a session that NEEDS FEEDBACK is attached and focused either way, as it is under / Enter. Landing on an UNSEEN finish reads it, so the DONE BADGE counts down as you cycle. With nothing red or blue it still walks the running sessions, then everything else; with no sessions anywhere the footer says so
The grid o open a project: a folder with a git repository in it, from any focus. The prompt starts on the folder nebula was started in — its parent listed, the folder itself highlighted — so Enter opens it; started anywhere else it starts at ~/. A folder that already is a project (its root, a checkout of it, or a folder inside either) opens that project rather than adding it twice. A folder in no git repository is never added as it stands: a confirm asks to git init it first (y inits and opens it, n backs out), and a path that doesn't exist yet asks to create it, then inits it. On the first-run splash n opens the same prompt, and Enter opens the folder nebula was started in outright
Open project type + Tab, ↓↑ / → / ← browse for the repo: type to filter (bash-style Tab completion), arrows pick a directory, → steps in, ← steps up, Enter opens the highlighted (or typed) path; ● marks git repos
The grid, on a root-branch card c the BRANCH SWITCHER: move the project's ROOT WORKTREE onto another branch — the checkout the card under the cursor runs in (a linked worktree only says why not: a worktree stays on the branch it was cut for), or the project's root with no card selected. It lists the current branch first, then the other local branches newest commit first, then the remote branches no local branch shadows, newest first — each with its last commit's subject and age — and Enter switches (a remote branch becomes a local branch tracking it). Type to filter, fuzzily, as in /; ↑/↓ or Ctrl+n/Ctrl+p move. Opening it starts one background git fetch --all (at most once a minute per checkout; Ctrl+r fetches again now) and the list follows when it lands. With nothing matching, Enter creates the typed branch off the current one and switches to it, changes and all (a name that starts with a remote's, like origin/x, is refused — it would shadow the remote branch). A checkout with uncommitted changes stops and asks how they travel: s stashes them under an entry named nebula: <from> before switching to <to> (if git refuses the switch, or stops part-way — a missing git-lfs does that — the files it wrote are undone and that entry is applied straight back), b brings them along (git's own switch, refused when they collide with the target), c commits everything first — untracked files too — after asking for the message (refused on a detached HEAD, where the commit would belong to no branch), and d discards changes to tracked files on a second d, unstaging first so untracked and newly added files stay; if the changes moved since the prompt opened — a new change, or another edit to a file already listed — it asks again. Esc backs out one step at a time. Nothing switches mid-merge, mid-rebase or with unresolved conflicts, and a git repository nested in the checkout (a .claude/worktrees/… checkout) is neither counted as a change nor committed. A branch another worktree has checked out is listed but refused, since git keeps a branch in one checkout. One switch runs per checkout: Esc while git works hides the modal and c brings it back, and an answer that lands while it is hidden is said in the footer. A switch that stops part-way puts back only files byte-identical to the target branch's, so nothing anyone wrote is touched; whatever it could not undo, it names. Sessions running in the checkout keep running and see its files change. A root-branch card's right-click menu has it as Switch branch…; rebindable as switch_branch
The grid Shift+Enter / Shift+O / Alt+Enter open the selected checkout outside nebula, usually in your editor (o's shift pair: o opens a folder as a project in nebula): fires its OPEN COMMAND once — Open command on the SETTINGS OVERLAY's Project tab (s) when it is set, else the open command from the checkout's .nebula.json — open http://localhost:3000, say — through $SHELL -c in that checkout, from the TUI, so it opens things on the machine you are sitting at; its output is discarded. Neither set, and the footer names both places. The worktree is the one whose band the cursor is on. Shift+Enter needs the KITTY PROTOCOL to arrive as a key of its own: Ghostty and kitty send it; Terminal.app sends a plain Enter, which steps into the pane instead, and tmux flattens a shifted Enter to a plain one on its way to the pane whatever extended-keys says. So two keys are bound beside it: Shift+O, which every terminal delivers, and Alt+Enter — the ESC CR that Claude Code's /terminal-setup makes VS Code's terminal send for Shift+Enter, and that Option+Enter sends on a Mac whose terminal treats Option as Meta — which tmux passes through untouched. Terminal.app can be taught the real key instead: Settings → Profiles → Keyboard, add ⇧↩ with the action Send Text and the text \033[13;2u. The project menu (a right-click on its tab) has Open too
The grid Shift+R reload from GitHub now: the project's OPEN PRS list and its open issues, the selected worktree's own pull request, and the description and conversation of the pull request the pane is reading are all asked of gh again at once — past the 15-second beat and the few-second floor a focus event respects — with the reader's scroll kept. reloading pull requests and issues from GitHub… in the footer says it was heard; the rows repaint as the answers land. Its own key, not a meaning r takes on: it acts on the selected project and worktree, so it works from any card — r stays rename; the run command is the project menu's Run
The grid i GitHub issues: the ISSUES MODAL for the selected project (above) — read an issue, type to filter the list by #15 title, Enter prompts an agent on it, Shift+Tab launches an AGENT PRESET on it, Ctrl+c leaves a comment on it, Ctrl+e edits its title and description, Ctrl+o or the pane's ↗ open in browser button opens it in the browser, Ctrl+r refreshes
The grid v GitHub pull requests: the PULL REQUESTS MODAL for the selected project (above) — read a pull request, type to filter the list by #42 title, Enter prompts a PR SESSION on it, Shift+Tab launches an AGENT PRESET on it, Tab picks a harness, Ctrl+c comments, Ctrl+g opens its diff, Ctrl+o, the pane's ↗ open in browser button or a double-click on the row opens it in the browser, Ctrl+r refreshes; a list GitHub could not be asked for says couldn't refresh (^r retries) under the filter, over the last rows that worked
New worktree type a sentence, or Enter on the empty prompt the branch name is slugified (fix login redirect → fix-login-redirect); empty takes a random <adj>-<noun>-<verb>. The branch starts at the freshly fetched origin/HEAD (normally origin/main), untracked — never at the root checkout's HEAD; with no origin, or a fetch that fails, it falls back to HEAD. Worktree base branch (Settings → General; worktree_base_branch in CONFIG.JSON) names another start — master, develop — resolved the same way: origin's fetched copy first, the local branch of that name otherwise, and origin/HEAD again in a repo that has neither
The grid n new session, harness first: the NEW SESSION PICKER lists the enabled harnesses (→ drills into a harness's model and effort, Enter takes your defaults for whatever you did not drill into), and the pick opens the QUICK PROMPT set to it — the same box p opens (below), aimed at the same checkout, with your harness on its title instead of the Settings → Agents one. The cursor starts on that Settings → Agents harness, so Enter at once is p. Type the task and Enter launches; Enter on the box empty starts the session bare, and you type the first prompt in the CLI. Esc on the picker closes it and opens nothing; text parked by an earlier box comes back into the picked box, the pick kept. A shell terminal is t
The grid (a card) Ctrl+d / Ctrl+u jump two rows of cards down / up, stopping at the first and last row, with the grid scrolling after the cursor so the card landed on is in view and the pane previewing it. Same rebindable actions, half_page_down / half_page_up
New session picker (Claude) Tab toggle Claude Cloud; Enter then opens the QUICK PROMPT as a cloud box — harness claude · cloud — whose Enter launches claude --cloud=<task> on what you typed (Shift+Enter or Ctrl+J inserts a line); sent empty it closes instead, a cloud session being nothing without its task
Quick prompt's harness picker (Claude) Tab the same Claude Cloud toggle, in the picker Tab opens from the quick prompt: Enter hands the box back as a cloud one — harness claude · cloud, Claude Cloud in its title — with your text kept, and the box's Enter launches claude --cloud=<task> on what you typed. Not offered in a box for an issue or a pull request, which Claude Cloud cannot take
Claude model / effort list Tab the same Claude Cloud toggle, from the list itself — reached with → on a picker's Claude row or opened by the box's ^O. It is the launch's, not one row's: the rows keep their names, the title reads Claude model · cloud, the footer says Tab: cloud on, a typed filter keeps it, and ← backs out to a Claude row that agrees. Offered wherever the picker's Claude row offers it
New session picker (any row) ? or s open Settings → Agents parked on the highlighted harness's section, where its Enabled switch and default model and effort live (s types in the model/effort submenus instead, where the filter owns letters)
The grid (a cloud card) Enter, right-click Enter — or a click on the link in the CLOUD SESSION PANEL — opens the session's page in the browser; the right-click menu offers Open in browser and Send to cloud session, which queues a message on it. No Attach or Restart: the agent runs in the cloud, not in a terminal here
The grid (a card) Space follow-up prompt. A small modal opens over the grid and what you type there goes to the agent already running in the selected session as its next turn: Enter sends it, Shift+Enter / Option+Enter / Ctrl+J break a line, Esc closes without sending. The right-click menu's Follow-up prompt row does the same. Only a live local agent has one: an archived session, a Claude Cloud card (whose right-click menu queues a message instead) and a terminal have nothing to follow up on. A session whose CLI is not up is booted first and the box kept as it is, so nothing is typed into a process that is still starting — press Enter again once it is. Rebindable as follow_up
The grid r, a, u, d, A rename, archive, unarchive, delete, toggle archived. Delete and Backspace are bound alongside d and do the same thing, here and everywhere else d deletes something — and a and the row menu's Archive ask first, in the CONFIRM DIALOG d goes behind (Enter or y archives, Esc or n keeps the session), so typing aimed at an agent that lands on the grid archives nothing; the dialog says what makes saying yes cheap: u brings the session back. Confirm on archive (Settings → Sessions, on by default) off archives at once. In the nested layout, d and a on a thread's root that has children take the whole thread: d deletes every prompt and terminal nested under it, a archives every prompt and closes its terminals — each behind a confirm that counts and lists them, a's asking even with the setting off; the root checkout's thread included, and a project left with nothing is the welcome. d on the last live card of a linked worktree asks about the checkout in the same confirm, before anything is deleted — Nothing else is left in worktree 'feature': delete it from disk too? — with three answers: y deletes the card and then the checkout as d on its band would, n deletes the card and keeps the empty checkout, Esc keeps the card alive; Delete emptied worktree (Settings → Sessions, off by default) skips that question and Enter deletes both, except when archived sessions are still filed under the checkout. With Show all worktrees on (Settings → Sessions, off by default) the question is never asked: the card goes alone, its checkout stays as an EMPTY BAND, and d on that band — a checkout with nothing running — asks to delete the worktree itself (Delete worktree 'feature' from disk?), as Delete worktree in the band's right-click menu does. Shift+R refreshes the pull requests (above). A held a opens one dialog and archives nothing by itself: its repeats land on the dialog, where a is nothing — with the confirm off, it archives one card, as u unarchives one. A held u unarchives one card, however long it is held: on a terminal with the kitty keyboard protocol (Ghostty, kitty, WezTerm, foot) nebula watches the key until it comes up, swallowing the repeats the terminal sends meanwhile, and the next card needs the key pressed again; a terminal without it (Terminal.app, nebula browser, tmux) reports a held key as one press after another, and there a long hold still walks the row
The grid (a card) e agent presets: saved launch definitions (harness, model, effort, text on the side of the task the form's Text row names — a prefix, a postfix or both; a new preset starts on prefix alone unless Preset text in Settings → Sessions says otherwise — and whether to ask for a task). The launch lands in the checkout under the cursor — or, with Tab (or a click on the list's bottom [ ] new worktree row), in a fresh worktree of the project cut first, the row turning into a green NEW WORKTREE chip naming the branch; Tab again flips back. The same toggle is on the list wherever it opens: in the ISSUES MODAL it flips between the root checkout and a fresh issue-15-<title-slug> worktree, and a PR SESSION's row just names the pull request's own checkout, there being nothing to flip. Enter asks for an optional task and starts the agent with prefix + task + postfix as its first prompt — sent empty, the prefix and postfix go alone — or, for a preset whose Task row is skip, launches at once without asking. Type to find a preset by name — letters narrow the rows to the fuzzy matches, the cursor on the best, the query in the title (Agent presets ⌕ rev); ↑/↓ (or Ctrl+n/Ctrl+p) move, Backspace widens, and Esc clears the letters before it closes. Because letters type, the verbs are chords: Ctrl+a / Ctrl+e / Ctrl+d create, edit, delete (Delete deletes too). In the PULL REQUESTS MODAL, Shift+Tab on a pull request is the same picker, launching the preset as a PR SESSION on it
The grid p quick prompt: a wrapped, multi-row task box (Shift+Enter, Option+Enter or Ctrl+J inserts a line and ↑/↓ walk the rows as they wrap, as in Claude Code's own prompt — the keys for getting around a long prompt are under Any multi-row box below; Esc closes the box, Enter launches) that starts a new agent in the checkout under the cursor — the worktree whose band the cursor is on — with what you typed as its first prompt — no picker. Which CLI it launches is the Agent row under Quick prompt in Settings → Agents, run with that harness's own default model and effort; the session titles itself from the prompt. For one launch only, Tab picks a different harness (→ drills into its model and effort, same as the new-session picker) and Shift+Tab picks one of your saved agent presets — adopting its harness, model, effort and prefix/postfix wrapping; sent empty with a preset on, the box launches on the prefix and postfix alone, and a skip-task preset picked over an empty box launches right away. Either picker hands the box back with your text intact, on Esc too. The launch lands the cursor on the new session's card as it goes up in its band, the grid scrolling to it (shown in the pane, the keys still on the grid) — turn off Follow new under Quick prompt in Settings → Agents to stay out of its way instead, the cursor and the pane staying on the card you were on and the footer naming the branch it went to, or turn on Focus there to drop straight into its terminal. The box launches in the checkout under the cursor by default — the worktree whose band the cursor is on, open or collapsed, the new session starting beside the ones already running there (more work in one session's own conversation is its follow-up, Space) — and on the project's root branch once Esc has let the aim go; turn on New worktree under Quick prompt in Settings → Agents to have every new box cut a fresh worktree first — a random branch off the fetched origin/HEAD, or the Worktree base branch setting — its band going up beside the rest, the cursor moving onto it unless Follow new is off. Ctrl+N inside the box flips between the two for this one launch only — the next box starts from the setting again: the row under the title says which — a quiet worktree: main with [ ] new worktree unticked, or a filled NEW WORKTREE chip naming the branch to be cut with [✓] new worktree ticked and the whole frame turned green — and the text and caret stay put across the flip. Enter on the box empty starts the session all the same — the harness, model and effort the title names, with no first prompt: you type it in the CLI (a Claude Cloud box, which needs its task, closes instead). Closing the box does not throw the prompt away: Esc, a click outside it and ^q park what you typed, and the next p opens on it — aimed the same way, the box comes back whole, the Tab harness or Shift+Tab preset you had picked included; aimed somewhere else, your text comes back into that box's own launch. One draft is kept, in memory only, and the box that takes it back is the last place it can be lost from: clear it there and close it and it is gone
The grid Shift+D delete every session listed for the checkout under the cursor (the confirm lists the casualties)
The grid g git diff for the selected worktree: filter, ↑↓ files, Ctrl+d/u half the file list down / up (flat or tree, as in vim), Shift+↑↓/PgUp/PgDn/Home/End scroll the diff, the wheel walks the files over the list and scrolls the diff over the diff, Ctrl+r marks a file reviewed ✓, Ctrl+t flips the file list between flat paths and a directory tree (←/→ fold, Enter flips a directory). Ctrl+u moves only while the filter is empty — with something typed it is the LINE EDITOR's kill-to-start
The grid Shift+G open the selected repo's page on its git host — the origin remote (git@github.com:o/r.git, ssh://, https://) turned into a browsable URL, credentials stripped
The grid (a card) Shift+V open the card's pull request in the browser — the #42 title line under its name, the pull request on the branch its session runs in — without stepping into the session or opening the PULL REQUESTS MODAL. v lists the project's pull requests in nebula; Shift+V goes to GitHub. It is marked read on the way out, as when it opens from anywhere else. A card with no pull request yet says so and names its branch (Shift+R asks GitHub again); with no card selected (after Esc) nothing opens. A click on that #42 title line, on any card, does the same — the cursor lands on the card first — and the line is underlined while the pointer rests on it, the way the header's tabs are. The card's right-click menu has it as Open pull request; rebindable as open_pull_request
The grid (a card) Shift+I open the GitHub issue the card's session was started from — an ISSUE SESSION, launched out of the ISSUES MODAL — in the browser. i lists the project's issues in nebula; Shift+I goes to GitHub. A card that was not started from an issue says so; with no card selected (after Esc) nothing opens. The card's right-click menu has it as Open issue; with Card issue number on (Settings → Appearance, off by default) the card shows the issue's #15 at the right of its second row, and a click on it does the same; rebindable as open_issue
The grid (a card) Shift+P open the QUICK PROMPT set to launch what the card runs — the same harness, model and effort, into the same checkout, for the same issue when the card is an ISSUE SESSION — so the task is all there is to type: Enter there sends it with those settings, exactly as a spec picked through the box's Tab / ^O would, and every picker of the box still works on it. p opens the box on the Agents tab defaults, in the checkout under the cursor; Shift+P opens it on the card. The card's conversation is not copied (the new session is a fresh CLI). A cloud card comes up as a cloud box on its model and effort. With no card selected (after Esc) nothing opens. The card's right-click menu has it as Duplicate; rebindable as duplicate_session
The grid Shift+T t's terminal outside nebula: a new Ghostty tab in the selected worktree's directory (the project's clone when it has no worktrees yet): nebula hands the directory to Ghostty.app with open -a, which Ghostty takes like a folder dropped on its Dock icon — a tab in the front window, or a new window if macos-dock-drop-behavior = new-window is set. Without Ghostty.app in /Applications or ~/Applications, off macOS, or over ssh, the key does nothing at all, not even a footer message. Rebindable as open_ghostty_tab in Settings → Hotkeys
The grid f / F / b find file / find in files (git grep) / file tree browser, all scoped to the selected worktree — Enter opens the file in an editor modal (at the matched line, for F; a .md from f opens read-first in the file tabs instead); in f and b, Ctrl+y copies the path
PALETTE, FILE FINDER (and its grep view), TREE BROWSER, BRANCH SWITCHER ↑/↓ or Ctrl+n/Ctrl+p move the selection inside a fuzzy overlay. j/k deliberately do not — they are typed into the query, so a branch or filename with a j in it stays reachable — which makes these five the one place the app-wide j/k convention above stops at the modal's edge. Esc is two-staged here as well: the first press clears what you typed, and only the second closes
The grid (a card) y the COMMENT BOX on the card's pull request — its checkout's, the #42 title on its band's rule and the one Shift+V opens — posted with gh pr comment on Enter. With no card selected, or no pull request on the checkout yet, it says so and opens nothing
The pane reading a pull request (after a / jump onto one) g, y, Shift+R, PgUp/PgDn, Home/End g shows its diff, y opens the COMMENT BOX on it, Shift+R fetches it afresh, PgUp/PgDn scroll it and Home/End jump to its ends
The grid t new shell terminal inside nebula, in the cursor's checkout (Shift+T opens one outside it, in Ghostty) — the band under the cursor — which comes up as a chip on the grid with the pane on it and the keys in it; with nothing selected (after Esc) it opens on the project's root checkout, and the footer says so. The grid has no + for it: the key is the way
The grid 1–9 open that PROJECT TAB, counting from the left of the header — the click on it, through the same code; one past the last tab says so. ⌘1–⌘9 are bound behind the digits as silent aliases, since Terminal.app, nebula browser and most other emulators never encode ⌘ into pty bytes — the bare digit is the one that always arrives. Rebindable per slot in Settings → Hotkeys, as project_tab_1 … project_tab_9
The grid Shift+H ssh hosts: every nebula ssh / nebula tunnel destination, newest first. Enter/click reconnects (quits this TUI and execs a fresh nebula ssh — local sessions keep running), a types a new user@host [dir], and d (or x, Delete, Backspace) forgets one — alone among nebula's destructive keys it asks nothing first, because the next nebula ssh to that host just re-adds it
The grid right-click context menu: a card's, or a project tab's
The grid s settings overlay (theme, editor, which agents to offer and their defaults, timeouts) — its Hotkeys tab rebinds every key in this table; R inside it resets everything to the defaults (with a confirmation). A first open lands on the tab strip; reopening within a minute of closing lands back on the tab and row you left, and after that it opens fresh again. Tab/Shift+Tab, [/] and the digits 1–9 move between tabs, j/k (or ↑/↓) move down the rows — ↑ off the top row steps back onto the strip — and h/l cycle the selected row's value. On a HOTKEYS TAB row the grammar changes: Enter or Space starts a capture, a or + captures a second chord beside the one already there, Backspace/Delete puts the default back, x unbinds it outright, and Esc cancels a capture in progress. Pressing a chord that some other action already owns does not take it — the row warns you who has it (… is already “Git diff” — Enter to move it here, Esc to keep it there) and a second Enter is what actually steals it
The grid Shift+M memory usage: RAM per agent/terminal process tree, nebula itself, and the machine-wide share; ↑/↓ + Enter opens the selected session. A click on the footer's memory readout opens it too
The grid ? help overlay
The grid q / Ctrl+c quit the TUI — behind a CONFIRM DIALOG ("Leave the TUI? Sessions keep running in the daemon."), because q sits one finger away from every other grid hotkey and a stray letter aimed at an agent used to end the client outright. y/Enter goes, Esc/n stays, and a second Ctrl+C while the dialog is up leaves without asking again — that shortcut is wired to the quit confirm alone, no other CONFIRM DIALOG takes it. Nothing is killed either way: the DAEMON keeps every session running
Terminal anything forwarded raw to the PTY — until the session's process exits, when nothing is forwarded any more: Esc, Enter and q leave the lock and every other key falls through to the grid, so an exited pane never swallows a keystroke it cannot use
Terminal / any OVERLAY Ctrl+q the HARDWIRED UNLOCK, and the one binding that is more than a hotkey. From a locked TERMINAL PANE it goes back to the card. With any OVERLAY open it force-closes that overlay in a single press from any nesting depth — a typed filter, an open submenu, a live hotkey capture, the preset editor stacked over its list, the editor modal — landing you on the grid every time. The one staged exception is the file tabs an agent opens with nebula open: there it steps back to the tab strip first, and closes from the strip. It stays wired in on top of whatever the KEYMAP says, so no rebind, nested modal or half-typed field can ever trap you. Ctrl+] and Ctrl+Shift+H (KITTY PROTOCOL only) are the other two defaults for leaving the pane — but those two are ordinary rebindable bindings, and only Ctrl+q closes an OVERLAY
Terminal mouse wheel three cases, tried in this order. A child that has asked for the mouse — Claude Code's alt-screen UI does, as do vim with mouse=a and htop — gets the notch forwarded as a real mouse-wheel report (SGR, or legacy X10 bytes when that is the encoding it negotiated), because synthesized arrows would land in its input box, cycle its prompt history and trip its "Scroll wheel is sending arrow keys" warning. An alternate-screen app that wants no mouse (plain vim, less) gets ↑/↓ instead, one per line the notch would have scrolled. Anything else scrolls nebula's own scrollback, a line a notch, stopping at the top of what it holds — a notch past the top is not a debt the way back down pays off first — and the header counts how far back you are as scroll N
Any typed field ←→/⌥←→, Ctrl+a/Ctrl+e, ⌥⌫, Ctrl+u/Ctrl+k every prompt, filter and query is the same line editor: move by character / word, jump to ends, delete word, kill line
Any multi-row box ↑/↓, ⌥↑/⌥↓, Ctrl+Home/Ctrl+End, PgUp/PgDn, wheel, click the quick prompt, the task and comment boxes, a preset's prefix and postfix, an issue's description: a long prompt is walked by the rows the box shows, not only by its line breaks — one typed without a single Shift+Enter too. ↑/↓ move a row and keep the column through a shorter one; past the top or bottom row a form steps to its next field, and a box with no other field goes to the very start or end of the text. ⌥↑/⌥↓ jump to the start or end of the paragraph, then the one before or after, as a Mac text field does; Ctrl+Home/Ctrl+End (Cmd+↑/Cmd+↓, where the terminal passes Cmd on — Ghostty keeps it for its own prompt jumps) to the start or end of the whole text; PgUp/PgDn a boxful. The box scrolls only when the caret would leave it, with ↑ 3 more / ↓ 5 more on its border for what is out of sight; in the quick prompt and the task and comment boxes the wheel scrolls it and a click puts the caret where it points

The grid

nebula's whole screen is a GRID of cards (see Sessions): the sessions and terminals of the project whose PROJECT TAB is lit in the header, grouped into a BAND per checkout — a titled rule over one row of cards — with a pane down the right of them that reads the card under the cursor. j/k walk the bands, Tab opens one in place (its cards, walked with h/l) and Tab or Esc folds it back. There is no level above it — the tabs, the + in front of them, a digit and a / jump are how you get to another project, and each of them lands on that project's sessions. These are the keys of the grid itself:

Where Key Action
The box ^P the PROJECT PICKER, drawn over the box rather than in place of it — the box stays on screen under the list, with the task in it, as every one of the box's pickers does: type to narrow every project on the machine, ↑/↓ (or ^N/^P) move, Enter aims the box there with the text kept, Esc clears the query and then hands the box back. Aiming the box never moves the screen: a launch into another project runs in the background, and the footer names where it went
The box ^T the WORKTREE PICKER, over the box and dropped down from the branch it names: a fresh worktree first (the branch it would be cut on named), then every checkout of the project the box is aimed at, the root first and the rest most recently worked in first, the one the box is aimed at ticked and under the cursor; type to narrow, Enter aims this one launch there with the text kept, Esc hands the box back unchanged. It picks where the session runs and never switches a checkout's branch. A PR SESSION's box has nothing to pick — it runs in the pull request's own checkout — and says so
The box ^O the harness's model list, straight away and over the box; → on a model reaches its efforts, Enter sets it, Esc hands the box back unchanged; in Claude's list Tab toggles Claude Cloud (above)
The box ^N flip between a fresh worktree and the root branch of the project the box is aimed at; the next box starts from the New worktree setting again
The box a click on project …, worktree …, harness … or model … the same picker the chord printed beside it opens, over the box, with what you typed kept. The four details along the top of the box are buttons — the word, the value and the chord together, so a click anywhere on harness claude Tab is Tab and one on worktree main ^T is ^T — as the [ ] new worktree ^N toggle across from the question is ^N. A click in the air between two of them is not either one: it lands in the box, as any other miss does
The box Enter / Esc launch the session / leave the box for the grid — what you typed is kept, and the next p opens on it (Tab, ⇧Tab and ^J are the QUICK PROMPT's). Enter puts the new session in front of you without handing it the keys: the pane under the grid opens on it — unfolded if ^~ had folded it away, and off any terminal tab it was on — while the keys stay on the cards, so the next p is one key away
The grid h/l, ←/→ walk the cards of the band under the cursor — its sessions, then its terminals, as its row draws them — one at a time, stopping at either end, the pane following onto each while the grid stays on the bands (Enter still goes in, on the card the walk stopped on). The card under the cursor is raised under the lit rule: a heavy accent frame over a gray fill. The row scrolls under the cursor to keep its card on it, and a ❮ before the row or a ❯ after its last card says the rest went that way — each a button: a click on it is the same one-card step. In the nested layout h/l do not walk a row: l/→ expands a collapsed thread, h/← collapses an expanded thread's root, and h/← on a child moves to that thread's root.
The grid j/k, ↑/↓ walk the BANDS — one checkout at a time, the rule of the one under the cursor in the accent and the pane swapping onto that checkout's remembered card (the session it was last left on, else its first) as you pass; on the band opened with Tab (below), walk the rows of its cards — the sessions' rows, then the terminals' under them — a row at a time, and off its last row on to the next band, off its first back to the one above. Ctrl+d/Ctrl+u jump two. On the first band — the top row of its cards when it is the open one — k has nowhere to go: one press stays put and says so, and a second within 400 ms walks up into the PROJECT TABS (below). Walking reads what the pane lands on — a done badge comes down as you arrive. The pane is the selected card, so it is there whenever one is selected and collapses when none is. The wheel does not walk the grid: a notch scrolls the bands under a cursor that stays put (below), so a trackpad cannot swap the pane out from under the card you are reading; the next j/k brings the cursor's card back on screen
The grid mouse wheel scrolls the grid three rows a notch, the way a terminal scrolls its screen — every band, and the open band's cards with them: the cursor and the pane stay on the card they were on, a band or a card the window's edge cuts is drawn to the edge rather than left out, and the scroll holds at the grid's ends. ↑ 2 more above on the row of air under the PROJECT TABS and ↓ 3 more below on the row under the cards say which way the rest went — ↓ 3 more worktrees below while every band is collapsed and whole checkouts are what is missing (the header's ↑↓ 5 hidden counts them too). The next key that walks the cursor — or j/k against the grid's edge — scrolls just far enough to bring the cursor's card whole back on screen, and a click on a cut card does the same. A grid that fits the screen has nothing to scroll
The grid a click on a card aim at it: the pane opens beside the cards reading that session — always, even with the pane folded away (^~), which a click on a card brings back — and the keys stay on the cards. The band stays as it is, open or collapsed: a click aims its band and the card — raised under the rule — so the pointer's second click finds it where the first left it. A right-click lands the same way before its menu opens. A click shows a session; it does not step into one
The grid Tab on a band, or a second click on its rule open the worktree in place. The band unfolds like an accordion: every one of its cards wrapped into rows under its rule — the sessions first, its terminals under a terminals rule — pushing the bands under it down, with the cursor still on the card the pane was reading and the keys still on the grid. Only one band is open at a time: Tab on another closes it first, and Tab on the open band — from its rule or any of its cards — folds it back to its one row, the cursor where it was. A band's rule says as much while the grid holds the keys — ❯ at its left where the other bands have ──, Tab: see all 8 (Tab: expand when its row showed every card, Tab: collapse on the open one) at its right. A click on a band's rule aims the band as j/k do. Which band is open is remembered per project — switch to another project's tab and back and it is still open, whatever you opened there — and across restarts. In the compact list (Settings → Appearance → Worktree layout → list) a collapsed band lists its 3 most recent sessions and Tab lists them all; on a band that already lists everything it only says so. In the nested layout (Worktree layout → nested) each worktree is a thread of one-line rows — the first prompt its root, later prompts and terminals its children — starting collapsed except the thread that holds the selection. l/→ expands a collapsed root, h/← collapses an expanded one, and h/← on a child moves to the root; Tab and a click on the ▾ / ▸ caret toggle the same fold, any number of threads open at once, remembered across restarts. j/k walk only the rows on screen, and Enter opens the selected row, root or child. A click on a root's #141 opens the PULL REQUESTS MODAL on it, as v does for the thread under the cursor. With Settings → Appearance → Expand all worktrees on, every band is open at once and stays open: Tab and the second click open and fold nothing (the footer says so), no rule shows a Tab: verb, and j/k walk every band's rows, off one band's last row onto the next band's first in the same column
The grid Enter, a double-click down into the pane beside the cards on the card under the cursor, its input locked — open band or collapsed, the grid stays up over it and ^` hands the keys back to the cards. A terminal's chip attaches its shell the same way. On a band aimed at rather than any one card, its remembered card. Tab is the accordion's (above), never the pane's. On a terminal too short to draw the pane the session takes the whole screen instead, and ^q, or a click on ‹ sessions, comes back to the grid. ^F gives any session the whole screen on purpose
The grid Space the FOLLOW-UP MODAL for the card under the cursor: a small box over the grid — Follow-up · <session> on its border — for that session's next turn. Enter sends what you typed straight down its PTY and closes the box, with sent to <session> in the footer; Shift+Enter / Option+Enter / Ctrl+J break a line, Esc closes it without sending. Nothing about the pane moves: it is not unfolded, not swapped onto the card, not attached to and not focused — prompting a card is not opening it, so you can click a card, Space, type a line, Enter, move to the next card and do it again without ever stepping into a session. It works with the pane folded away entirely (^~). A session whose CLI is not up is started first and the box kept with your text in it — press Enter again once it is. Only a live local agent takes one; an archived row, a Claude Cloud row, a terminal and a pull request each say what they take instead. The card's right-click menu's Follow-up prompt opens the same box. Rebindable as follow_up
The grid Esc close the open band first, the cursor on it and the pane still on your card; with every band collapsed, let the band under the cursor go — no band is drawn selected any more and the pane collapses. A further Esc does nothing: the bands are the top of the view. What is under the cursor is only let go of, not forgotten: j steps from where the eye last saw the cursor and takes the aim back. With Expand all worktrees on there is no band to close, so the first Esc lets the card go
The grid a click on the air between the cards nothing but the focus: a click that misses every card is a miss. It leaves the card under the cursor selected and the pane under the grid open on the session it was reading — the gutter between two cards and the blank rows under a short last row are the easiest thing in the view to hit by accident, and neither one should shut what you were reading. Letting the card go is Esc's, and ^~ folds the pane outright
The grid's header a click on 3 prs or 2 issues the PULL REQUESTS MODAL or the ISSUES MODAL for the project in front of you — the list v or i opens, through the same code. Each count is its own button, underlined while the pointer rests on it; the · between them is neither
The pane under the grid a click in it type into the session it is showing, where it stands, with the grid still up; the wheel scrolls its scrollback
The pane under the grid ^` (then ^` again) hand the keys back to the cards, the cursor on the card the pane reads and the pane still up; the same chord again, now from the cards, folds the pane away. ^~ does the same, and ^q still hands the keys back too
The pane under the grid ` the next TERMINAL chip of the cursor's checkout, and round to the first — the checkout's shells as a loop the key walks without passing through its sessions. Its header names what the pane reads — the card under the cursor with its STATUS DOT, or its ❯ / ▶ for a terminal — and the checkout it runs in (↳ feat, ⌂ main, in the band's own scope colors); opening a terminal there is t. Enter and a click in the pane step into and type at whatever the cursor is on, terminal or session alike. Where ^~ is whether the pane is drawn at all
A terminal's chip d done with a terminal: close it and kill its shell, behind a confirm (Close terminal 'shell-1'? Its shell is killed.), so y is what actually kills it. The cursor then lands on the chip beside the one that went — the next card of the band, else the one before it — so the pane is never left blank on a card that no longer exists. When that chip is the last card in a linked worktree, the same confirm asks about the checkout too (Nothing else is left in worktree 'feature': delete it from disk too?) — y closes the terminal and deletes the checkout, n closes the terminal only, Esc keeps both; the Delete emptied worktree setting skips the question and y does both
The grid ^`, ^~, ~ fold the pane beside the cards away and give the grid the whole body, or bring it back. The × at the right end of the pane's header is the same fold in one click; the button just before it moves the pane instead — ⬓ along the bottom, under the cards, ◨ back down the right of them — and saves that as Settings → Appearance → Session pane. Folding it lets the card under the cursor go with it — nothing is selected and nothing is being read, exactly as after an Esc. Bringing the pane back selects the card it reads again. The fold lasts only while the keys walk the cards: a click on a card — either button — always brings the pane back open on it, as Enter on a card does. The choice is remembered across restarts, with the pane's size. ^` is the chord to reach for, and ^~ the same key for terminals that report it shifted with Ctrl held, but only the KITTY PROTOCOL carries either (Ghostty, kitty) — a stock terminal has no encoding for Ctrl and this key and sends the same NUL it sends for ^Space. So the bare ~ is bound beside them, which every terminal delivers. The two Ctrl chords work from inside the pane too, in two presses: with its input locked they are not typed into the session — the first hands the keys back to the card the pane reads, and the second, from the cards, folds the pane away. The bare ~ stays the session's to type
The pane's edge drag it how the body is shared between the cards and the pane: drag the edge facing the cards toward them and the pane takes columns off the grid, away and the cards get them back, its grip a short ┃ down the middle lighting up under the pointer. With the pane along the bottom (Settings → Appearance → Session pane: bottom, or the ⬓ button on its header) it is the top edge, dragged up and down, and the height is remembered apart from the width; the blank row the pane opens with, and the grid row over it, are the grab zone there — a short ━ grip across the middle of it says so. It stops against the pane's own minimum at one end and against a column of cards — the header plus one row of them, under a pane along the bottom — at the other, so neither side is ever dragged away. A double-click on the edge snaps it to the middle of the body, the cards and the pane sharing it evenly, whichever way a drag had taken it. The size is remembered across restarts and re-fitted to the window, so one dragged on a wide or tall screen never squeezes the cards out on a small one
The pane under the grid, or the grid ^F, or a click on ⤢ full-screen the session: the grid and its header give way to the session in the pane, its input locked — the chord is nebula's, never forwarded to the agent. From the cards it full-screens the card under the cursor. The ⤢ sits before the side button at the right of the pane's header. Rebindable as toggle_full_screen
A full-screen session ^F, ^q, ^`, or a click on ⤡ or ‹ sessions back down to normal size: the session goes back into the pane beside the cards with the keys still in it, the cursor on its card — ^q or ^` once more hands the keys to the cards. ⤡ holds the right end of the full-screen header. A session full-screened for want of a pane (a terminal too short to draw one) comes back to the grid instead. The crumb underlines under the pointer, as the grid header's tabs do
The grid's header a click on a project tab, or [ / ] switch project from where you are. The header is the PROJECT TABS: one tab per project you have opened, the one you last worked in at the far left, the one the grid is on lit, each with its STATUS DOTS right of the name — ●2 red waiting on you, blue finished unread, yellow running — and its name sweeps in the loudest of those colors (red, then yellow, then blue once nothing is live). A click on a tab opens that project's sessions; [ and ] open the tab to the left and right, stopping at the first and the last rather than wrapping round. Working in a project — launching a session there, a ^P launch into it from another project's grid included, a shell or worktree opened there, a follow-up sent, a key typed into one of its sessions — moves its tab to the far left; switching never reorders the tabs, and a / jump into a project with no tab puts one at the far left. Tabs the row has no room for fold into 2 more ▾ after the last one drawn, which carries their dots; a click on it lists them. The tabs are remembered across restarts. Rebindable as prev_project_tab / next_project_tab; the digits open a tab by its place (above)
The grid's header k,k (↑,↑) on the top row of cards the PROJECT TABS take the keys. A cursor of its own lands on the lit tab, drawn as an accent block, and the card you left stays selected — its heavy accent frame kept, its fill a shade darker with the keys gone — with the pane still on it, and the band you left keeps its bold branch while its rule goes gray, so the header's cursor is the one lit thing. h/l (←/→, or [/]) walk the cursor along the tabs, stopping at either end, and the grid switches with it — each project comes up on the card you last left it on, its session in the pane, with no Enter needed; Enter — or j,j (↓,↓), the double tap back down — hands the keys back to the cards of the project on screen; x closes the tab under the cursor, and d, Delete or Backspace asks first, then closes it. Esc goes back down too, a click anywhere hands the keys back (a click on a tab is Enter on it), and any other key does the same and then means what it means on the grid
The grid's header a click on the + in front of the tabs, or + the PROJECT DROPDOWN: switch to any project by name. Every project on the machine drops under the + — the ones waiting on you first, the one on screen ticked — with a last row that opens a folder that is not a project yet. Type to narrow it (fuzzy, best first), ↑/↓ to move, Enter or a click to open the project on the card you last left it on (its first card on a first visit), Esc to clear the text and then close. The key + is the button's own glyph and arrives in every terminal and in nebula browser, from the cards (in the pane it is text, and the agent's — Ctrl+q out first). ⌘P is bound behind it for terminals that send ⌘ (the KITTY PROTOCOL: Ghostty and kitty do, Terminal.app and the browser never do — Chrome takes ⌘P as print): it works from the cards and from inside the pane under them — a ⌘ chord is never text, so the agent loses nothing, and Esc hands the keys straight back to it — and pressed again puts the list away; a full-screen session has no header, so there it is the agent's. A tab's name and the + underline while the pointer rests on them, and a tab's × turns red — the sign that they are buttons. Rebindable as project_dropdown
The grid's header a click on a tab's ×, or x; d, Delete or Backspace with the header holding the keys close a project tab. Only the tab goes — the project and its sessions are untouched, and the + opens it again. The × and x close it at once; the three delete keys ask first (Close the tab for 'web'? Its sessions run on — + opens it again.), as every delete key in nebula does, and Enter or y on the dialog is the same close, Esc keeps the tab with the cursor still on it. Closing the tab the grid is on moves the grid to the tab that slides into its place. Closing the last tab goes back to the splash nebula opens on with no project, where + lists every project again. Rebindable as close_project_tab
The grid's header a right-click on a project tab the project's own menu: New worktree, Run / Stop run and Open for the checkout the grid would launch into (Delete worktree too, for a linked one), Rename — a label; the folder on disk keeps its name, and an empty name goes back to it — and Remove from list, behind a confirm, which leaves the clone on disk alone. A right-click opens the tab first, so the menu is always the project on screen's
The grid p / n the box again (n after its harness pick), aimed at the project under the cursor and at the checkout the cursor is on — the worktree whose band the cursor is on; its ROOT BRANCH with nothing selected — or at a fresh worktree with New worktree on under Quick prompt in Settings → Agents. Which of the worktree's cards is selected does not matter, only the worktree: more work in one session's own conversation is its follow-up (Space). ^P in the box re-aims it at any project on the machine
The grid Shift+A the ARCHIVED VIEW. The same grid, of the project's archived sessions instead of its live ones — the header counts them under their own word — so u unarchives the card under the cursor where it stands and d deletes it. Shift+A again comes back to the live sessions. The two lists never mix: there is no ARCHIVED group to fold, only the other grid. Enter on an archived card says to unarchive it first — its session was reaped when it was archived, so there is nothing to read. An archived card is drawn as the live card put away: square frame (┌ against a live ╭), a square ▪ where the STATUS DOT was, the name muted and unbolded, the SCOPE COLOR and the PR's own colors off, and the badge counting from when it was archived (2h ago) rather than from its last turn — so which grid is up reads without the header, and without color at all

Every other key in the table above acts on the card under the cursor — the card the pane reads (a, d, g, /, s, ?, q). ^P in the box is the way to another project without leaving this one: it aims the box at any project on the machine without taking you there, so Enter starts that session in the background and leaves the screen on the work in front of you.

Chips and readouts

Two strips report state without being asked. The TERMINAL PANE's header shows one chip at a time — the first of these that applies, so a scrolled-back exited session reads exited:

Chip What it is telling you
exited (red) the session's process is gone. Keys stop reaching it — Esc, Enter and q leave the lock and everything else falls through to the grid — and the next attach is what respawns it
scroll N (yellow) you are N lines back in the scrollback rather than at the live edge. Typing anything, or scrolling back down to the bottom, clears it
starting… (dim) nothing has come off the PTY yet: the session was reaped while you were elsewhere and its CLI is booting now. The blank grid on its own reads as a hang, so the chip says otherwise
INPUT (accent) the pane is locked and every key is going to the PTY — where Enter leaves you; the pane keeps that corner for its close button, and its accent rule says the keys are in there

The FOOTER carries the rest, left to right:

Readout What it is telling you
nebula vX.Y.Z at the far left which nebula this is — the same string nebula --version prints, and the one thing on the bar that never moves with the cursor. It costs the key hints ~18 columns and steps aside only for a flash message that would not otherwise fit
⇡ v0.22.0 right after it, in the warning color a newer nebula is published on GitHub — the nudge to run nebula upgrade. Checked once at start and hourly after with one curl to the release page's redirect (no gh token, no API quota); it says nothing while it can't ask, and NEBULA_UPDATE_CHECK_SECS=0 turns the check off
✗ disconnected this client has lost the DAEMON. It is the client-to-daemon link and nothing else — a session's own health is its ● STATUS DOT, and a hollow ○ is an agent the daemon restarted out from under. A healthy connection says nothing at all: the bar reports the link only when something is wrong
2 agents · 1 term · 3 warm · 412 MB at the right edge live counts and nebula's whole memory footprint — this TUI, the DAEMON and every session's process subtree summed — re-read every 5 seconds while no modal is up. Prewarm spares are counted apart as warm so the agent figure matches the cards, and the whole readout is blank until the first reading lands. It is a button: the pointer on it underlines it, and a click opens the memory modal, the same one Shift+M opens
j - Move down on the blank row above the bar, far left the KEY COMBO DISPLAY, always on: the key you just pressed in a keycap and what it did, for anyone watching a screen share — vim's showcmd. A double tap reads as one combo (k k - Project tabs), an unbound key bare, and it clears itself three seconds after the press. Keys typed into a LOCKED PANE never show (only the hatch out and the pane fold do), nor does anything typed into a modal's text field — in a modal only Esc, Enter, Tab, the arrows and ^/⌥ chords show, bare

Mouse

The mouse is another way to press the keys, never a second set of behaviors: a click on a row is the arrow keys landing there, a click on a row of a picking list (a menu, the / palette, the file finder, the agent presets, the ssh hosts) is Enter on that row, a second click on a row you are already on — a session, a checkout, a pull request, a settings row — is Enter on it, a right-click is a click that then opens that row's context menu, and a click into the terminal pane is Enter on the pane. So a markdown file clicked in the file finder opens read-first in the file tabs as Enter opens it, a preset clicked in a pull request's preset picker starts the PR SESSION Enter starts, and a right-click on another checkout brings its session into the pane as ↑/↓ onto it would. Double-click in the terminal selects a word, ⌥-click opens the URL or file:line under the cursor (browser / editor modal; a .md opens read-first in the file tabs, Enter there for the editor), and dragging the pane's edge resizes it. A click on the pull request on a band's rule (↗ #42 title) is Shift+V on that checkout: the cursor lands on the band (unless the grid is already on that checkout) and the pull request opens in the browser; the link is underlined while the pointer rests on it, and a right-click on it is the band's right-click. A click outside any modal (help, settings, a confirm, a prompt, the pickers) dismisses it, and lands on the card it hit — only lands: the click was spent closing the modal, so it moves no cursor, previews no session and switches no project. Landing in the terminal pane takes the input lock the way a click there always does. That is not always the same thing as Esc: the DIFF VIEWER, the PALETTE, the FILE FINDER, its grep view, the TREE BROWSER and the BRANCH SWITCHER all stage Esc — the first press clears the typed filter and only a second one closes — where a click outside closes them outright, first press. The CONTEXT MENU splits the same way: Esc backs out one submenu level at a time, a click outside takes the whole menu. The rest (a CONFIRM DIALOG, a prompt, the agent presets list, the preset editor) really do run their own Esc, side effects and landing included. The wheel scrolls whatever the pointer is over — the GRID included, whose cards the keys walk and the wheel only moves under them: it moves their lists without touching the selection, and the PR PREVIEW scrolls three lines a notch while a cursor is resting on a pull request. Text selection: hold Shift while dragging (mouse capture bypass — same as tmux).

A program that asked for the mouse itself — Claude Code's fullscreen renderer, vim with mouse=a, htop, tmux with its mouse on — gets the left button the way a plain terminal hands it over: the press, the drag and the release all reach it, and its own selection does the copying. Claude Code's knows that its /diff panel sits beside the conversation; a screen-row copy of nebula's took the panel along with the reply. nebula's own drag-select is for everything that never asked — a shell, Claude Code's classic renderer — and Shift-drag selects through the terminal either way. A copy the program sends its terminal as an OSC 52 write (Claude Code over nebula ssh, vim's OSC 52 clipboard, tmux with set-clipboard on) is passed on to the terminal you are sitting at, the route nebula's own copy takes on a remote host.

A drag-select ends when the button comes up and not before: the wheel, the agent printing on, a resize, even a replay that rebuilds the screen all leave a drag in progress where it is, since the selection is pinned to the text rather than to screen rows. Drag past the pane's top or bottom edge — onto the rule above it or the footer below — and the history scrolls under the pointer until it comes back inside, a line per tick for each row past the edge, so a copy can run longer than the pane is tall; the release copies every row the drag crossed, on screen or not.

A host terminal can forget that it was asked for the mouse — iTerm2's Session ▸ Reset (⌘R) does, and so does a stray full reset — after which every click goes to the terminal and the wheel scrolls its own scrollback instead of the pane. nebula asks for the mouse (and bracketed paste, focus reports and the kitty keyboard flags) again every two seconds — never in the middle of a drag — so the mouse comes back on its own; resizing the window also re-enters the alternate screen and repaints every cell.