A macOS worktree-aware terminal multiplexer built on libghostty & zmx.sh.
Graftty organizes persistent terminal sessions by git worktree. Each worktree in your sidebar has its own split layout of terminals that stay alive across worktree switches, and a CLI (graftty) lets running processes interact with the Graftty UI.
brew tap btucker/graftty
brew install --cask grafttyInstalls Graftty.app to /Applications and symlinks the graftty CLI onto PATH. On first launch, macOS will block the app with Gatekeeper — approve it under System Settings → Privacy & Security (on Sonoma, right-click → Open). Uninstall with brew uninstall --cask --zap graftty.
Graftty updates itself. On first launch, you'll be asked whether
Graftty may check for updates automatically — if you agree, a small
indicator appears in the window titlebar when a new version is
available, and clicking it installs the update. You can also trigger a
check manually from Graftty → Check for Updates….
When a repo has more than one worktree open, Graftty treats it as an agent team. AI coding agents (Claude Code, Codex, etc.) running inside each worktree can register their presence, message each other through a per-worktree inbox, and react to PR/CI events that affect the team — useful when you've got one agent per branch grinding through PRs and want them to coordinate.
Enable it under Settings → Agent Teams. From there you choose which events (PR state, merges, CI conclusion, mergability) get routed to the root agent, the per-worktree agent, peer worktrees, or any combination, and customize the templated session and per-event prompts each agent receives.
Each agent's session-start hook is decorated with team context plus the CLI surface for coordination:
graftty team register --runtime claude # announce presence at session start
graftty team list # see teammates, roles, and running state
graftty team send <member> "<text>" # direct message a teammate's inbox
graftty team broadcast "<text>" # message everyone on the team
graftty team inbox # read your incoming messagesDelivery is hook-driven. Graftty installs claude and codex shims on
each agent's PATH that wire SessionStart and Stop hooks into the
runtime. SessionStart primes the agent with team context and your
session prompt; Stop triggers inbox delivery at the end of each turn.
For Claude Code, a Stop-spawned watcher wakes the agent on stderr
when a new message arrives; for Codex, a graftty-side service types the
message text into the pane's PTY via zmx. Both paths defer while the
pane shows recent user typing, so a teammate's message can't interrupt
you mid-edit.
Window → Team Activity Log opens a unified transcript of every team event and inter-agent message for the focused worktree's team.
When inbox messages aren't enough, a lead agent can drive a teammate's
pane directly — see CLI below for graftty pane show (read another
worktree's terminal) and graftty pane send (inject keystrokes).
The bundled graftty CLI lets a process inside a Graftty pane drive the app, and lets one agent control panes in another worktree.
graftty notify "tests passing" # set a sidebar attention badge
graftty pane list # panes in the current worktree
graftty pane add --command "claude" # split + run a command
graftty pane close 2 # close pane 2
# Cross-worktree pane control:
graftty pane list drag-files # list panes in another worktree
graftty pane show drag-files:1 # last 100 lines of that pane's output
graftty pane show drag-files:1 --lines 500 # more scrollback
graftty pane send drag-files:1 "pnpm test" # type the command and press Enter
graftty pane send drag-files:1 "y" --no-enter # type without committing<addr> is <id> (current worktree, that pane), <worktree> (worktree's only pane), or <worktree>:<id>. Worktree names match what graftty team list prints. Run graftty pane <verb> --help for examples on every subcommand.
graftty pane send writes raw bytes to the addressed pane's PTY — there's no inbox or consent layer, so the keystrokes land in whatever process is reading that pane's stdin. Use graftty team send for cooperative messaging where the receiving agent decides what to do.
Requires Xcode 15+ and macOS 14 Sonoma or later.
swift buildOpen Package.swift in Xcode to run the app.
Graftty's browser-facing web access client lives in web-client/ (React +
Vite + TypeScript + TanStack Router). If you change anything under
web-client/, rebuild the bundle that ships with the app:
./scripts/build-web.shThis refreshes Sources/GrafttyKit/Web/Resources/{index.html,app.js,app.css}.
CI verifies the committed bundle matches a fresh build.
You need node (LTS) and pnpm installed locally for web-client work:
brew install node pnpmIf you only touch Swift, you need neither — the committed bundle is what
swift build ships, and Homebrew users get the prebuilt tarball.
MIT — see LICENSE.
