Skip to content

Workspaces & panes

τ-mux organizes work into workspaces containing a binary-tree of panes.

Each pane hosts a surface. There are seven kinds:

KindBacked byNotes
terminala real PTY (Bun.spawn, terminal: true)the default; the only kind with a shell
browseran embedded webviewbrowser panes
agentthe pi coding agent (pi --mode rpc)pi integration
claudea Claude Code session (Agent SDK)Claude Code pane
telegramthe Telegram bot serviceTelegram bridge
editorCodeMirrorfile explorer & editor
extensiona Bun backend + Vite frontend iframeextension apps

Only terminal panes own a PTY. Everything else is a DOM (or webview) surface that happens to live in the same pane tree — which is why they never appear in the process tree and why the metadata poller has nothing to report for them.

Workspace
└── PaneTree (binary tree of splits)
└── PaneLeaf
└── Surface (terminal | browser | agent | claude | telegram | editor | extension)
  • Workspace — independent layout. Switch with ⌘⇧] / ⌘⇧[ or jump directly with ⌘1…9.
  • Pane tree — a binary tree. Every internal node is a horizontal or vertical split with a draggable divider; every leaf is a single surface.
  • Surface — the actual content. A surface has a stable id (surface:N) referenced by every CLI command and RPC call.

A pane is the visual rectangle. The surface is the content inside it. Most of the time the distinction doesn’t matter — but when you drag a terminal into another pane, the surface moves while the pane stays. The CLI and RPC speak in surface ids because they care about content, not geometry.

ActionShortcutCLI
Split right⌘Dht new-split right
Split down⌘⇧Dht new-split down
Split left / up(drag-and-drop)ht new-split left / up
Close pane⌘Wht close-surface
Focus neighbor⌘⌥←↑→↓ht focus-surface --surface surface:N

Splits commit on dragging a pane onto a drop zone, or on ht new-split <direction>. The default split ratio is 50%; resize by dragging the divider.

Drag a pane header into another pane to:

  • swap two panes
  • merge two panes (close the source)
  • create a new split in any of four edge zones

The drop overlay shows the target zone before you release. See src/views/terminal/pane-drag.ts for the state machine.

Each workspace has its own:

  • Pane tree
  • Sidebar status pills
  • Process Manager view (the global view aggregates across workspaces)
  • Workspace color (a left-border accent)

Closing a workspace (⌘⇧W) also kills every shell inside it. The metadata poller drains the dead surfaces on the next tick.

Workspace and pane layout is saved to ~/Library/Application Support/hyperterm-canvas/layout.json (settings live separately in settings.json). On restart, terminal surfaces re-spawn shells with the saved cwd and shellPath; non-PTY surfaces re-mount with their saved state — a browser pane restores its URL, an editor its file, an extension pane its extension id. Agent and Claude panes re-mount as fresh sessions (the old subprocess died with the app); a Claude pane offers resume from its Sessions picker. If an extension has since been uninstalled, that slot degrades to a terminal.