● A native macOS workspace for coding agents
A repo is a tab. A git worktree is a card. A split pane is one agent. Seahelm renders every one of them on the Ghostty engine, watches what they are doing, and keeps their sessions alive across a reboot. Twelve agent CLIs work out of the box.
Example fleet. Every status above is one the app really reports.
▶ Forty-seven seconds of it working
A real session, not a mock-up: worktrees down the sidebar, an agent working in one of them, and a suggestion card asking which way to go.
Deck one · on deck
Seahelm has no editor and no diff-review ceremony. The whole surface is about placing agents — which repo, which worktree, which pane — and then showing you which of them needs a human.
git worktree list --porcelain; a pane is a leaf of that worktree's split tree, and
holds exactly one agent. AgentRegistry.shared knows the status of every leaf in the picture.
Space as a which-key leader. h j k l moves focus, Cmd+P is the quick switcher, Cmd+N opens a new branch.sea ; replies go back stamped helm , which is also what stops the bridge from answering itself.A pill at the top of the screen that stays shut until a worktree needs you. It opens for one of three things: something is running, something is waiting, something broke. Agent suggestions arrive in it as clickable cards.
An autonomous supervisor on status transitions. Green-zone actions it just takes — watch, inspect, auto-commit. Red-zone actions — broadcast an order, return a worktree to port — queue up for your approval first.
cwd, so Seahelm matches the longest worktree prefix and moves that one pane —
keeping its Ghostty surface and its zmx session — instead of standing up a stranger beside it.
Two gates keep it honest: the destination must belong to the same repo, and after any move auto-follow
holds for ten minutes, because an agent's cwd bounces while it works.
| Agent | Status | Event hooks | Suggestion cards |
|---|---|---|---|
| Claude Code | ✓ manifest + hooks | ✓ native | ✓ |
| Codex | ✓ manifest + hooks | ✓ native | ✓ |
| opencode | ✓ manifest + hooks | ✓ plugin | model-volunteered |
| Nine more | ✓ screen scan | — | — |
agent · aider · amp · claude · cline · codex · cursor · gemini · goose · kiro · opencode · pi
Deck two · below deck
247 Swift files in four layers, over the Ghostty terminal engine. No Combine, no SwiftUI — AppKit and delegates, because the thing on screen is a Metal surface with a PTY behind it.
| Layer | Path | Files | What lives there |
|---|---|---|---|
| Coordinators | Sources/App/ | 15 | Window, tabs, split operations, side panels, the modal keyboard machine. |
| UI | Sources/UI/ | 75 | Dashboard layouts, the Island, split container, worktree sidebar, diff viewer, settings, onboarding. |
| Core services | Sources/Core/ · Status/ | 133 | AgentRegistry, the detection pipeline, the manifest engine, First Mate, the control socket, hook installers. |
| Terminal & git | Sources/Terminal/ · Git/ | 19 | The Ghostty C API bridge, Station surface lifecycle, the split tree, worktree discovery. |
NormalizedEvent, so the reducer stays a pure function and the UI never learns which lane
a status came from. Ask any pane which rule decided it: seahelm pane explain <pane>.
The same five states drive the dot, the card, the Island and the rollup. There is no sixth.
$SEAHELM_PANE_ID, can
call back and split a pane, run a command in a sibling, read its scrollback, or block until
another pane goes idle.
A python3 wrapper on PATH, newline-delimited JSON-RPC over a 0600 socket. Nothing to authenticate to, nothing on the network.
$ seahelm pane list $ seahelm pane read <pane> --lines 50 $ seahelm pane split <pane> --direction right $ seahelm pane run <pane> "npm test" $ seahelm wait agent-status <pane> --status Idle $ seahelm pane explain <pane> # which rule? $ seahelm layout export
Hook shims install non-destructively into each tool's own config — and stay out of the way. CwdChanged is deliberately not registered: taking it made Claude Code hand worktree creation to us and broke --worktree.
The status poll runs on a background queue while you type on the main one, and both call into the same C library. A single lock serializes them — except key input, which deliberately takes no lock: Ghostty is thread-safe for keys, and holding it there would deadlock on a synchronous callback.
The poll is not uniform either. The worktree you are looking at is read every cycle; the rest every third, so a fleet of twenty panes costs about what three do.
Ghostty for the terminal engine, linked as a C xcframework — zmx for session persistence — Sparkle 2 for updates, rendered into an inline banner instead of its own modals.