Features

Sessions #

Heads up: The session list display is not yet perfect and will keep improving — what it can show is heavily dependent on the signals each agent CLI exposes.

Creating a session with Ctrl+N : pick a repo, name it, choose an agent.

Run multiple coding-agent CLIs side-by-side, each in its own tmux pane. A session runs one agent (Claude Code, Codex, Antigravity, opencode, aider, GitHub Copilot CLI, Vibe, pi, Oh My Pi, or your own), each with its own default config. Sessions persist across crashes, restarts, and even multiple concurrent Thurbox instances — tmux keeps them alive in the background.

  • Create a session with Ctrl+N : repo picker → session name → agent picker. The agent picker is skipped when only one agent is defined.
  • Restart a session with Ctrl+R to preserve conversation history when the agent supports resume (e.g. Claude's --resume ).
  • Each session row shows the agent's live activity when the CLI reports one (via its terminal title), next to a colored status dot
  • Open URLs in terminal output with Ctrl+Click
  • Select text with mouse drag, copy with Ctrl+C , paste with Ctrl+V . With no selection, Ctrl+C sends SIGINT to the active session.
  • Toggle a shell pane alongside the agent session with Ctrl+T
  • Reorder the list by hand: with the session list focused, Shift+J / Shift+K move the selected session (and its nested children) down/up, and Shift+S sorts sessions alphabetically by name within each repo group. Manual order wins — a status change only recolors the dot, never moves a row — and it survives restarts.
  • Recover sessions externally at any time with tmux -L thurbox attach

Agent Definitions #

The set of available agents is data, not code. On first run Thurbox seeds ~/.config/thurbox/agents.toml with built-ins (claude, codex, antigravity, opencode, aider, copilot, vibe, pi, omp). Edit the file to tweak an agent or add a new one — no recompile required. See Built-in agents for each one's recommended config and behavior.

  • Each [[agents]] entry has a command , args (always passed — bake in flags like a model here if you want), and argument-template groups ( resume_args , fork_args , new_session_args ).
  • A group is appended only when its driving value is present, with {id} substituted. Selection precedence is fork > resume > new-session id.
  • A session is fully described by its repos and agent. There is no per-session model selection, permissions, prompt, tool, or skill configuration — those belong to the agent CLI itself, which runs with its own default config.

Automations #

Note: Automations are stable and good enough for daily use today, but the feature may still evolve.

Named, scheduled agent runs. An automation fires on a schedule and either sends a prompt to a running session or spawns a fresh session (optionally on a new git worktree) and prompts it. Press Ctrl+P for the full list, or use the always-present Automations pane beneath the session list.

  • Schedules are one-shot (a relative delay) or recurring cron, with friendly hourly / daily / weekdays / weekly presets and an optional timezone. The editor needs no cron knowledge: the trigger is a selector, the time is set with steppers, and a live preview shows the next fire.
  • The Automations pane joins the Ctrl+H / Ctrl+L focus cycle; once focused, Ctrl+N creates and j / k / Space / r / e / d select / toggle / run / edit / delete.
  • Automations fire even when the TUI is closed — a detached tmux heartbeat keeper runs them every minute (and keeps the tmux server alive), with opt-in systemd/launchd units for reboot-proof firing. Concurrent firers are de-duplicated by an atomic claim, so nothing double-fires.
  • Everything is persisted in SQLite ( automations + automation_runs history) and scriptable headlessly via thurbox-cli automation create/list/edit/run/runs/tick .

Tasks #

Heads up: Tasks are a new feature — expect the UX and UI to keep evolving in upcoming releases.

Building a todo list and wiring items to an agent with Ctrl+W .

A built-in todo list whose items can be connected to a coding agent with the same Send/Spawn model as automations: Send pastes the task title into an existing session, Spawn creates a fresh session (optionally on a new worktree) seeded with the title, and an unconnected task is a plain local todo. Triggering a task runs its action and advances it to in progress .

  • Tasks render in a toggleable right-side column ( Ctrl+W / F5 ) that behaves like the file viewer and joins the Ctrl+H / Ctrl+L focus cycle. Once focused, n creates, e / Enter opens an in-pane editor (no popup), Space cycles status (☐ todo · ◐ in progress · ☑ done), r runs the action, and d deletes.
  • Persisted in SQLite and scriptable headlessly via thurbox-cli task (alias todo ): create/list/show/edit/remove/run . External issue-tracker sync (Jira, GitHub Issues) is scaffolded for a later release.

Git Worktrees #

Optionally spawn sessions inside git worktrees for branch isolation.

  • When creating a session ( Ctrl+N ), choose "Worktree" mode to select a base branch and name a new branch
  • Thurbox creates the worktree and launches the agent inside it
  • Press Ctrl+S to sync all worktree sessions with origin/main
  • On rebase conflicts, Thurbox automatically sends a resolution prompt to the agent
  • Closing a session automatically removes the worktree
  • Worktree sessions show the branch name in the terminal title and session list

Worktree storage

Worktrees are created at <repo>/.git/thurbox-worktrees/<sanitized-branch> , where / in branch names is replaced by - .

Multi-repo sessions

A session can span several repositories. The repo picker lets you select more than one, and headless callers pass --add-repo PATH[@BASE] (each gets its own isolated worktree on the session's branch) or --add-dir PATH (attached as-is, no branch). Because agent CLIs differ wildly in how they accept extra directories, Thurbox launches a multi-repo session in a per-session symlink workspace ( ~/.local/share/thurbox/workspaces/<id>/ , one symlink per repo) and starts the agent there, so every agent sees each repo as a subdirectory — fully agent-neutral. Single-repo sessions are unchanged.

Remote SSH Sessions #

Run an agent on a remote machine over SSH while the TUI stays local. The agent process, its tmux window, and any git worktrees all live on the remote host.

  • Declare hosts in ~/.config/thurbox/hosts.toml (seeded commented-out, so a fresh install has none); each entry registers a selectable backend named ssh:<name>
  • The new-session flow ( Ctrl+N ) shows a host picker first; remote sessions are marked with a glyph in the session list
  • Thurbox shells out to your system ssh , so authentication, keys, and connection multiplexing come from ~/.ssh/config — thurbox never handles credentials
  • Remote sessions get the same persistence, multi-instance sharing, and restore-on-startup as local ones
  • The remote host needs tmux ≥ 3.2 and git
~/.config/thurbox/hosts.toml
[[hosts]]
name = "devbox"            # backend "ssh:devbox"; what --host expects
destination = "me@devbox"  # ssh target or a ~/.ssh/config alias
ssh_opts = ["-o", "ControlMaster=auto", "-o", "ControlPersist=10m"]
# socket / session  — optional remote tmux -L / session-name overrides
# worktrees_dir      — optional absolute remote worktrees dir

Spawn remotely from the CLI with thurbox-cli session create --host devbox … .

Worktree Sync #

Ctrl+S synchronizes all worktree sessions with their upstream default branch.

  • Sessions are grouped by repository to avoid git lock contention. Different repos sync in parallel.
  • Per-worktree: stash uncommitted changes, fetch, rebase origin/main , stash pop.
  • Stale .git/index.lock files from crashed git processes are automatically cleaned up before syncing.
  • Runs on background threads — the TUI remains fully responsive.
  • Results shown per-session: synced, conflict (sent to Claude for resolution), or error.

Session Forking #

Forking with Ctrl+F : children nest under their parent session.

Press Ctrl+F to fork the active session. This creates a new session that resumes from the same conversation history, allowing you to explore alternative approaches without losing the original session's context. The fork records the source session as its parent : the session list nests children under their parent with a tree prefix, and the info panel shows a Parent: row.

Parent Sessions (Lead / Worker) #

Every session carries an optional parent , so orchestration scripts can model a lead session that spawns workers . A Ctrl+F fork records its source as the parent automatically; headless, thurbox-cli session create --parent <uuid> sets it explicitly, and session list --parent <uuid> lists a lead's direct children.

  • In the session list, children nest under their parent within the same repo group (muted tree prefix; a child whose parent lives in another group keeps its place with a mark instead). Ctrl+J / Ctrl+K navigation walks the tree exactly as rendered.
  • The link is informational only — deleting a lead never deletes or orphans its workers (they routinely outlive the lead). A dangling parent just renders the child as a top-level session again.

Inter-Session Messages #

A general, agent-neutral message queue lets one session hand another a structured payload — addressed to a session, with a free-form --kind tag, a --body , and optional sender/task provenance — instead of scraping its rendered terminal. It is the channel extensions use for agent↔agent coordination (the flow extension 's clarify→plan→build relay is the first consumer).

  • Push, not poll. A worker pushes a clean payload with thurbox-cli message send ; a wake nudge types a short inbox token into the recipient's pane so it drains immediately. The payload always travels through the durable database, never the pane.
  • Exactly-once drain. message inbox --claim is a single atomic UPDATE … RETURNING , so the TUI, a cron tick, and a wake nudge can drain the same inbox concurrently without ever double-processing or dropping a message.
  • Self-knowable identity. Thurbox injects a stable THURBOX_SESSION (and, for task-spawned sessions, THURBOX_TASK ) into each agent, so a CLI call inside a session proves its own identity: an agent sends and reads its own mail passing no ids, and message reply <id> routes back to a message's original sender without ever mapping a peer to a session id.
One strip, Ctrl+/ , searching every scope at once.

Press Ctrl+/ to open a non-modal search strip that searches every scope at once — sessions, tasks, automations, and the active session's file tree. It is the one search: the old per-pane / filters were folded into it.

  • Sessions match on name, agent, and worktree branch and on live terminal-buffer content; tasks match on title, automations on name, and files on path.
  • Matches highlight live in the panels themselves — matching rows are accented, the rest dimmed — with per-scope match counts and a grouped result list.
  • / move the selection (previewing the owning panel), Enter jumps to the result and focuses its pane, and Esc restores exactly what you had before searching.

Code Review #

A native, GitHub-style review pane — Ctrl+X , no external tool.

Every session is a git worktree on a branch forked from a base, so “review what this agent built” maps cleanly onto the session model. Press Ctrl+X (or F7) to open a native diff reviewer in the central pane — rendered by Thurbox itself, with no external binary.

  • What to review. The whole branch (<base>..HEAD), a single commit, or the uncommitted working changes — switch targets with t .
  • Changed-files tree. The file-viewer column lists changes as a folder tree with colored status glyphs (M/A/D/R) and per-file +/- counts; the diff body is syntax-highlighted, unified or side-by-side (v).
  • Comments. Leave line, file, or review-summary comments classified as issue / suggestion / note / praise , composed inline at the line.
  • Mark reviewed & fold. Mark a file (or hunk) reviewed with r / R ; a reviewed file folds to just its header, tree-style (Enter expands/collapses any file).
  • Persistent per session. An open review stays open as you switch sessions and come back — exactly like the shell view.
  • Feedback loop. y copies the review as markdown; e sends the whole review back into the agent as a prompt to address it. (Submitting to GitHub/GitLab is intentionally out of scope.)

Comments and reviewed-marks persist in SQLite, keyed per session. The review command is native; gate the whole feature with [features] code_review .

Responsive UI #

Three layout tiers adapt to your terminal width:

Width Layout
< 80 cols Terminal only
>= 80 cols Session sidebar + terminal
>= 120 cols Sidebar + terminal + info panel
  • Scrollback with Shift+arrows / PageUp / PageDown / mouse wheel
  • Non-modal error messages in the status bar
  • Vim-inspired keybindings throughout
  • Tri-state focus system (Focused, Active, Inactive) with visual border feedback
The info panel ( Ctrl+B ) — session details plus live CPU/RAM and agent metrics.
The file viewer ( Ctrl+E ) — browse the worktree tree with fuzzy search.

Themes #

Nine built-in palettes (five dark, four light) switch live with Ctrl+Y and persist across restarts.

Cycling palettes with the theme picker ( Ctrl+Y ).

OS Notifications #

When a session crosses into a needs-you state — the agent rang the terminal bell or emitted an OSC 9 / OSC 777 notification (usually because it is waiting on an answer or has finished a task) — Thurbox fires an OS desktop notification, so you can react without watching the TUI. The notification body is the agent's last OSC message, or Waiting for input otherwise.

  • Linux dispatches over dbus and supports click-to-focus : clicking the banner switches the TUI to that session on its next tick. macOS shows the banner but ignores clicks (the modern notification API requires a signed app bundle, which Thurbox is not).
  • It fires only while the TUI is open — the terminal parser that watches for the bell does not run headless — and is deduplicated per session, with the session you are currently viewing skipped by default.
  • Tune it in the [notifications] block of settings.toml ( see Configuration ): opt into the timing-only Busy → Waiting edge for agents that never ring a bell, toggle the sound, or change the dedup floor. Turn the whole feature off with [features] notifications = false .

Mouse Navigation #

The whole TUI is clickable (on by default; disable with the mouse feature flag below):

  • Click a row in the session list, tasks panel, automations pane, or file viewer to select it and focus that pane. File rows also open the file or toggle the directory.
  • Click a picker row (theme, agent, host, branch, …) to select and confirm in one click. Open modals swallow stray clicks, so a misclick never discards typed input.
  • Hover underlines the row under the pointer; the mouse wheel scrolls the focused terminal and steps the selection while a modal is open (with a draggable scrollbar on long lists).
  • Drag selects terminal text ( Ctrl+C copies); Ctrl+Click opens a URL.

Feature Flags #

Whole TUI features can be switched off in ~/.config/thurbox/settings.toml under [features] (seeded commented-out; everything defaults to true except version_check and auto_update , which are opt-in because they reach the network). A disabled feature hides its pane and turns its keybinding into an explanatory toast, but its data and the thurbox-cli surface keep working — so flipping a flag back on is lossless.

settings.toml
[features]
tasks = true          # F5/Ctrl+W tasks panel
automations = true    # automations pane, Ctrl+P, schedule firing
file_viewer = true    # F3/Ctrl+E file viewer
global_search = true  # Ctrl+/ search strip
info_panel = true     # F2/Ctrl+B info panel
shell_pane = true     # Ctrl+T per-session shell
mouse = true          # mouse capture: clicks, wheel, drag-select, hover
notifications = true  # OS desktop alerts when a session needs attention
soft_delete = true    # Ctrl+D soft-deletes (Ctrl+Z undo); false = hard-delete behind a confirm
version_check = false # opt-in GitHub update check (makes a network call)
auto_update = false   # opt-in: silently download+verify+replace binaries on startup

automations = false is the one flag with teeth beyond the UI: it also stops the TUI from firing due schedules and arming the tmux heartbeat at startup (explicit thurbox-cli automation commands still work).

You don't have to hand-edit the file: press Ctrl+, (or F6 ) to open the Settings panel — a modal that views and edits all of settings.toml (the [features] toggles, the [notifications] knobs, and the scalars). Edits apply on Ctrl+S ( Esc discards); the file is also live-reloaded, so feature flags and notification knobs take effect immediately.

Session Persistence #

Sessions run inside a dedicated tmux server ( tmux -L thurbox ) and survive crashes, restarts, and multiple concurrent instances.

How it works

  • Sessions spawn as tmux windows. The tmux pane keeps running regardless of Thurbox's lifecycle.
  • On shutdown ( Ctrl+Q ), session metadata is saved to SQLite. Thurbox detaches without killing sessions.
  • On restart, Thurbox discovers existing sessions from tmux, matches them to persisted metadata, and adopts them with terminal content intact.
  • External recovery is always possible via tmux -L thurbox attach .

Close vs Quit

Action Behavior
Ctrl+Q (Quit) Detaches all sessions, saves metadata. Sessions resume on next launch.
Ctrl+D (Close) Permanently kills the tmux pane. Worktree (if any) is removed immediately.

Headless CLI #

The thurbox-cli binary drives the same sessions, automations, and editor settings without the TUI — ideal for scripting. It shares the TUI's SQLite database and tmux -L thurbox server, so changes made by either show up live in the other. Output is human-readable by default and switches to JSON automatically when stdout is piped (so … | jq keeps working); force a format with --json (compact), --pretty (indented), or --text (human even when piped).

bash
thurbox-cli session list
thurbox-cli session create --name reviewer --repo-path /path/to/repo --agent codex
thurbox-cli session send <uuid> "run the test suite"
thurbox-cli session capture <uuid> --lines 500
thurbox-cli message send --to flow --kind questions --task 5 --body "scope?"
thurbox-cli message inbox --for flow --claim
  • sessionlist , get , create (synchronous — the tmux window is live on return; supports --worktree-branch / --base-branch ), send , capture , restart , delete , restore .
  • automation (alias auto ) — create / list / show / edit / remove / run / runs , plus tick (the headless entry point that fires all due automations — what the tmux heartbeat keeper and any systemd/cron timer call).
  • message (alias msg ) — send / inbox / prune : a general, agent-neutral inter-session message queue so one session hands another a structured payload (a free-form --kind , a body, optional task/sender provenance) instead of scraping its terminal. send enqueues and, by default, wakes the recipient; inbox --claim drains it exactly once. The flow extension is its first consumer.
  • task (alias todo ) — create / list / show / edit / remove / run the todo list : create with neither --session nor --repo is a plain local todo, and run triggers its Send/Spawn agent action headlessly.
  • extension (alias ext ) — install / uninstall / reinstall / list / available / update / activate / deactivate / status manage the opt-in extensions .
  • editorget / set the command Ctrl+O runs (the worktree path is appended as the final argument).
  • configvalidate strict-parses every config file (exit 1 on a problem — handy in dotfiles CI), and show prints the effective resolved configuration.
  • version — prints the running version; --check queries GitHub's latest release (gated on the version_check feature).
  • update — downloads, verifies, and replaces the installed binaries with the latest release ( --force bypasses the up-to-date / dev-build guards; gated on the auto_update feature).
  • notify — diagnoses OS desktop notifications: prints the detected delivery backend and last error; --test fires a sample.

How session delete is handled

session delete <uuid> is a soft-delete by default: it only marks the database row deleted. The tmux window, git worktrees, and any pending scheduled commands are left untouched — the running TUI cleans those up on its next sync, and the session stays recoverable with session restore <uuid> (the TUI's Ctrl+U / Ctrl+Z undo). Restore revives the metadata; the TUI re-spawns a fresh window for it.

Pass --force to tear down the session's runtime resources in the same call — for headless cleanup when no TUI is running to observe the deletion. A forced delete also:

  • kills the tmux window,
  • removes the session's git worktrees (the underlying repos are left intact),
  • removes the multi-repo symlink workspace, if any (only the symlinks — never the linked repos), and
  • disables any send automations that target the session.

Teardown is best-effort : individual tmux/worktree failures are recorded in the JSON report ( killed_window , removed_worktrees , worktree_errors , disabled_automations ) but never abort the delete. The DB row is always soft-deleted last, so even a forced delete stays restorable — it just re-spawns from a clean slate.