Mission control for your coding agents.
Run Claude Code, Codex, Cursor and Pi across every project and git WORKTREE you own — from one terminal, one keyboard, one tree. They keep working when you close it.
Keys · Commands · Sessions · Configuration · How it works
curl -fsSL https://raw.githubusercontent.com/AgentSystemLabs/nebula/main/install.sh | sh
You start three agents in three terminal tabs. Five minutes later you don't know which one is waiting on a permission prompt, which one finished, and which one is still thinking — so you tab through all three, every time, and read the screens. Start a fourth and you aren't running more agents, you're doing a worse job of watching the ones you have.
nebula replaces the reading with a tree and a color. Every PROJECT, WORKTREE and SESSION is a row; every SESSION carries a STATUS DOT that says what it's doing; and every parent ROLLS UP its children, so a red dot on a collapsed PROJECT tells you exactly where to look without opening anything.
No Electron, no browser, no server, no MCP. One ~4 MB Rust binary and a unix socket.
| One tree, up to four PANELS | PROJECTS → WORKTREES → SESSIONS → TERMINAL PANE. h/j/k/l moves, Enter drills in, and landing on a live pane hands it the keyboard — so Tab all the way right and start typing at the agent. |
| A DAEMON that owns the PTYs | Quit the TUI, shut the laptop, come back tomorrow. The agents never stopped, and the SCROLLBACK RING is replayed on ATTACH. |
| STATUS DOTS you read instead of screens | ● yellow mid-turn, ● violet finished and UNSEEN, ● green finished and read, ● red waiting on you — plus a violet n done DONE BADGE counting the terminals you still owe a look. |
| Lists that order themselves | PROJECTS, WORKTREES and SESSIONS all sit most-recent-first in RECENCY ORDER, with a dim 23m ago after the name saying why the row is where it is. The one fixed seat is the ROOT WORKTREE, always the first WORKTREES PANEL row; nothing else is pinned or dragged into place by hand. |
| Real git WORKTREES, one keystroke | n in the WORKTREES PANEL branches off into an actual git worktree. Two agents in two directories never collide. A WORKTREE HOOK in git config lets a project claim a port or a route when a checkout is created and release it when it is deleted. |
| Agents that drive nebula back | Tell a Claude SESSION "do this in a worktree" and it runs nebula worktree, then restarts itself resumed inside the new checkout. Say "show me the file" and nebula open puts it in front of you in a tabbed modal. Say "start a new nebula session that…" and nebula spawn has a second agent working beside it before you look. |
| Every open pull request, in place | nebula asks gh what's still open on the repo. Rest on a PR ROW and the PR PREVIEW reads it to you — description, stats, the whole conversation. g for its diff, Enter for the browser, n for a SESSION on any harness, scoped to that PR. |
| Every open issue, one key from an agent | i lists the project's open GitHub issues, newest first, and reads the one under the cursor — description, labels, comments. Enter opens a QUICK PROMPT for it, e launches one of your AGENT PRESETS on it; the issue's URL travels with the session as context on every spawn, so the harness knows what it is fixing. |
| Diff, find, grep, browse | g opens the DIFF VIEWER with REVIEWED MARKS, f the FILE FINDER, F a git grep, b the TREE BROWSER — all scoped to the selected WORKTREE, all one key from anywhere. |
/ finds anything, anywhere |
The PALETTE spans every WORKSPACE, not just the open one. Before you type it sorts by attention: NEEDS FEEDBACK first, then RUNNING, then UNSEEN — so / Enter is the fastest way back to whatever needs you, and ] / [ cycle that same attention order with no modal at all, one session per press, workspaces included. Open pull requests are rows too: Enter on one lands on its PR ROW with the PR PREVIEW reading it, Ctrl+o hands it to the browser. |
| It follows you to other machines | nebula ssh <host> opens nebula there, installing it if missing. nebula tunnel <host> puts that machine's TUI in a browser tab over a single ssh tunnel. |
macOS or Linux — the same command installs and updates:
curl -fsSL https://raw.githubusercontent.com/AgentSystemLabs/nebula/main/install.sh | shIt downloads the prebuilt binary for your platform from the latest GitHub release into ~/.local/bin
(override with NEBULA_INSTALL_DIR), falling back to cargo install --git when no release matches.
Afterwards, nebula upgrade runs that same script for you; it refuses to clobber a local cargo build
(pass --force if you mean it). Upgrading with a DAEMON running is safe: an idle one — nothing live in
it — is shut down for you, so the next launch comes up on the new binary. A DAEMON with live SESSIONS is
left alone and they keep running the old binary until you nebula kill and relaunch. nebula --version
(-V) says which binary you are on.
Prerequisite: at least one agent CLI on your
PATH—claude,codex,cursor-agent, orpi. nebula spawns them; it doesn't ship them.Three commands each want one more binary, and only those commands:
nebula sshandnebula tunnelexit if there is no OpenSSH client (ssh), andnebula browserneedsttydon yourPATH— fornebula tunnelit is the remote host that needs it. The TUI itself needs neither.
1. Add a repo. nebula is project-first, and a PROJECT is just a git checkout:
nebula add ~/code/my-app # or, from inside the repo: nebula add .2. Open the TUI. A bare nebula launches it and auto-starts the DAEMON:
nebulaTab / Shift+Tab (or h / l) move FOCUS between PANELS, j / k move the selection inside one, and
Enter drills in. With no PROJECTS yet you get the SPLASH — press n to add one without leaving the TUI.
3. Pick where the agent runs. Every PROJECT starts with one WORKTREE: the checkout itself. Press n
in the WORKTREES PANEL to branch off into a real git worktree. That's the whole point of the column —
two agents in two WORKTREES edit two directories and never collide.
4. Start the agent. n in the SESSIONS PANEL opens the NEW SESSION PICKER — Claude, Codex,
Cursor or Pi, → for MODEL and EFFORT, Enter for your defaults. Or skip the picker entirely: p from any
PANEL opens the QUICK PROMPT, you type the task, and an agent starts working on it in the selected
WORKTREE — or, from the WORKTREES PANEL or with Ctrl+N inside the box, in a fresh worktree cut for the
job, the box turning green to say so. Save a framing you keep retyping as an AGENT PRESET (e) and it
becomes one keystroke.
5. Walk away. Ctrl+q leaves the TERMINAL PANE for the panels; q asks first — a CONFIRM DIALOG
reading Leave the TUI? Sessions keep running in the daemon. that Enter accepts and a second Ctrl+C
walks straight through. The DAEMON still owns every PTY — come back with nebula an hour later and each
SESSION is exactly where you left it, scrollback replayed.
Leave a new SESSION on its default name and AUTO-TITLE renames it from your first prompt — Fix Login Redirect, not agent-3. Type a name yourself and nebula never touches it. A Claude SESSION's own name
is the same name: /rename inside Claude Code retitles the row, and a name set in nebula reaches
Claude's prompt box and /resume picker on your next prompt.
| Dot | AGENT STATUS |
|---|---|
| ● gray | FRESH — agent never run |
| ● yellow | RUNNING — turn in progress (the STOP GATE holds it open while subagents are live) |
| ● violet | UNSEEN — turn complete and nobody has looked at it yet |
| ● green | FINISHED — the same finished turn, once the cursor has been on the SESSION |
| ● red | NEEDS FEEDBACK — permission prompt or question waiting on you |
| ● magenta | terminated — process died mid-run |
| ○ | disconnected — the DAEMON restarted while the agent was live |
A Cursor SESSION never goes red: nebula runs cursor-agent --force and Cursor reports no permission
event, so waiting-on-you is not detectable there.
WORKTREE and PROJECT rows ROLL UP their children: red beats yellow beats done, and a parent's dot is violet whenever anything UNSEEN finished under it — so the violet walks up the tree and turns green as you read your way down it.
A dot going violet while you were looking elsewhere is easy to miss, so nebula counts those for you. When
a turn finishes in a pane that isn't on screen, its WORKTREE and PROJECT rows grow a violet n done
DONE BADGE — the number of terminals you have left to go read — and the SESSION row says done where its
HARNESS BADGE normally sits. Walking the cursor onto a SESSION previews it, which reads it: the badges
count down as you go and disappear at zero — ] walks you onto the next one owed a look without hunting
for it. The flag lives in the DAEMON, so it survives closing the TUI
and is shared by every client; a turn that finishes in the pane you're already looking at never counts.
A dot going red is the one you can't afford to miss — a blocked agent burns the clock while you're in
another window — so that one reaches you: the FEEDBACK SOUND rings (Sosumi by default, distinct from
the Glass DONE SOUND a finish gets), and when the terminal window is in the background a desktop
notification names the session and its worktree. Neither fires for the pane you're locked into typing
at with the window focused — that prompt is already under your hands. One setting, feedback_sound,
owns both; off silences the pair. See Configuration.
nebula doesn't poll the agents and it doesn't guess from the screen. At spawn it merges MANAGED HOOKS
into the WORKTREE's .claude/settings.local.json, .cursor/hooks.json or ~/.codex/hooks.json — tagged
_nebulaManaged, your own hooks preserved, rebuilt every spawn — and each one is a fail-soft curl to
the DAEMON's loopback HOOK RECEIVER, authenticated with a per-boot BEARER TOKEN. Pi has no shell hooks,
so it gets one managed extension at ~/.pi/agent/extensions/nebula.ts that posts the same events. For the one event no CLI
reports — a turn you cancelled with Esc — the PROGRESS SCANNER reads the CLI's own OSC 9;4 progress
escapes straight off the PTY, a signal that survives the cancel and stays busy while a permission prompt
is open.
| Keys | Every default binding, the WORKTREE views (g f F b), and the mouse. All of it rebindable. |
| Commands | The nebula CLI: add, rename, worktree, spawn, workspace, ssh, tunnel, browser, daemon, kill, upgrade. |
| Sessions | The NEW SESSION PICKER, MODEL / EFFORT, Claude Cloud and the CLOUD MIRROR, AGENT PRESETS, the PROJECT OPEN PRS group, the ISSUES MODAL. |
| Configuration | config.json, the SETTINGS OVERLAY, the HOTKEYS TAB, logs and environment overrides. |
| How it works | The DAEMON, the hook dialects, AUTO-TITLE, WORKTREE RELOCATION, prewarm and reaping, persistence. |
| Architecture | Process model, the IPC CODEC and the crate layout. |
cargo build --release # → target/release/nebula (~4 MB)
cargo test # unit + end-to-end suite (spawns real daemons/PTYs)nebula-core (shared protocol/entities), nebula-daemon (PTYs, SQLite, HOOK RECEIVER, STATUS MACHINE),
nebula-tui (ratatui client), nebula (the binary). vendor/vt100 is a patched copy of the terminal
parser wired in through [patch.crates-io]: rows scrolled out of a top-anchored scroll region go to the
SCROLLBACK RING instead of being discarded, so wheel-up over a codex SESSION has something to show.
Releases: push a v* tag (git tag v0.1.0 && git push --tags) and CI builds mac (arm/intel) and linux (x64/arm64, static musl) binaries and
attaches them to a GitHub release — which is what install.sh downloads.
MIT — see LICENSE.
If nebula saves you a tab, a ⭐ helps other people find it.