Skip to content

Latest commit

 

History

3,066 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

term-mesh logo

term-mesh

AI Agent Control Plane for macOS

Run a team of AI coding agents in parallel — each in its own sandboxed worktree, on this Mac or on any machine you can SSH into — from one native, GPU-accelerated terminal.

Website · Download · Features · Quick Start

Download for macOS


term-mesh screenshot

Features

Sandbox Worktree Orchestration

Agents get physically isolated git worktree environments. Each agent session runs in its own directory, preventing accidental modifications to the main repository. Worktrees are automatically cleaned up when tabs close.

Multi-Agent Native Terminal

Built on Ghostty (libghostty) for Metal GPU-accelerated terminal rendering. Vertical sidebar tabs show git branch, working directory, and notification status for each agent session.

Vertical tabs and split panes

Agent Panes

An agent does not have to be a terminal you read. A native pane renders the conversation itself: streaming answers, tool calls you can fold away, file edits drawn as a coloured diff, and the cost and elapsed time of each finished turn. Claude speaks the protocol directly; codex, kiro, cursor and agy go through a bridge. Prefer the raw terminal? Settings → Agent Teams → Agent Panes switches back.

Agent Teams

One leader, several workers, and a task board they share. The leader delegates, the workers reply with a fixed five-field header (STATUS / FILES / VERIFY / NEXT / FULL_REPORT), and the app files each reply where the leader can collect it. Workers can sit on different machines than the leader.

tm-agent create 3 --adopt          # this pane becomes the leader, three workers join
tm-agent add reviewer --cli codex  # add one more, on a different CLI
tm-agent add builder --host jw-server --dir /root/build   # …or a different machine
tm-agent delegate executor 'implement T1'
tm-agent wait --timeout 120 --mode any

Projects

Point at a repository and a machine, and term-mesh does the rest: clone (or reuse a folder), lay out one worktree per agent, start the leader, and open the team in a workspace. The destination field browses the remote machine's folders, and the branch field completes with Tab.

A Project created on a peer belongs to that host, not to the Mac window that created it. As long as the host's term-meshd and its sessions are running, you can quit the local app, connect again from this or another Mac, select the Project in the sidebar, and reattach its exact leader and member panes. Closing a viewer only detaches that Mac; deleting the Project from its owner ends the remote resources.

Notification Rings

Visual notification rings on sidebar tabs alert you when agents need attention — completed tasks, errors, or prompts waiting for input.

Notification rings on sidebar tabs

Built-in Browser

Open web pages, documentation, or dashboards directly in a split panel without leaving the terminal.

Built-in browser panel

Budget Guard & Resource Monitoring

  • CPU/Memory monitoring with automatic process discovery
  • SIGSTOP/SIGCONT process control when thresholds are exceeded
  • Real API cost tracking by parsing Claude Code's JSONL logs with incremental reads
  • Model-specific pricing: Opus $5/$25, Sonnet $3/$15, Haiku $1/$5 per MTok

File Access Heatmap

FSEvents-based file watcher tracks create/modify/remove events across watched directories. The dashboard renders a heatmap with top-10 hot files, recent events, and per-minute timeline buckets.

Real-time Dashboard

Monitoring dashboard available as a split panel in-app (Cmd+Shift+D) or standalone browser at http://localhost:9876.

Socket API

Full control via Unix socket and HTTP REST API — automate tab creation, pane management, notifications, and more from scripts or other tools.

Peer hosts (Mac and Linux)

Attach another machine from your menu bar — its split layout opens in a relay window on your laptop, with live PTY streams in every pane. Drive remote panes with the usual keybindings (Cmd+D split, Cmd+T new tab, Cmd+W close, divider drag, click-to-focus, tab strip switching). ssh -L tunnels the wire, so any host you can SSH into works; Bonjour discovery and a recent-hosts list make reconnecting one keystroke, and auto-reconnect covers sleep/wake and network blips.

A Mac peer serves from the app itself. A Linux peer runs term-meshd, installed by one command:

curl -fsSL https://raw.githubusercontent.com/x-mesh/term-mesh/main/scripts/install-linux.sh | bash

That also installs tm-agent and the agent bridge, so the machine can host agents and not just terminals. Edit Peer Host runs a health check that reports what it found — which binaries, which versions, whether a pane's PATH can reach them — instead of leaving a silent failure to guess at. See docs/peer-linux-host.md and the peer federation primer.

Remote agents

An agent can run on a peer while its pane lives here. The far machine owns both the process and the Project manifest that maps it back to the right leader and member panes. Quitting term-mesh does not end the work — reconnect to the host, select the Project, and the app reattaches to the sessions still running there. Environment values an agent needs (API keys, for instance) travel as a file that the launcher sources and deletes, never as ssh command-line arguments, which every other process on that machine can read.

Architecture

┌──────────────────────────────────────────────────────────┐
│                   term-mesh (macOS App)                   │
│                                                          │
│  ┌─────────────────┐  ┌──────────────────────────────┐  │
│  │  Native Shell   │  │     Dashboard (WKWebView)    │  │
│  │  Swift + AppKit  │  │     Chart.js + HTTP Poll     │  │
│  │                 │  │     http://localhost:9876     │  │
│  │  Vertical Tabs  │  │                              │  │
│  │  Split Panes    │  │  ┌────────┐ ┌────────────┐  │  │
│  │  Notifications  │  │  │CPU/Mem │ │ File       │  │  │
│  │                 │  │  │Monitor │ │ Heatmap    │  │  │
│  ├─────────────────┤  │  ├────────┤ ├────────────┤  │  │
│  │ Terminal Engine  │  │  │API Cost│ │ Agent      │  │  │
│  │ libghostty      │  │  │Tracker │ │ Status     │  │  │
│  │ (Metal GPU)     │  │  └────────┘ └────────────┘  │  │
│  └─────────────────┘  └──────────────────────────────┘  │
│          │                         │                     │
│          │    Unix Socket / HTTP   │                     │
│          └───────────┬─────────────┘                     │
│                      ▼                                   │
│  ┌──────────────────────────────────────────────────┐   │
│  │              term-meshd (Rust Daemon)             │   │
│  │                                                    │   │
│  │  Worktree (git2)  │  Monitor (sysinfo)            │   │
│  │  Watcher (notify)  │  Usage (JSONL parsing)        │   │
│  │  Budget Guard (SIGSTOP/SIGCONT)                    │   │
│  └──────────────────────────────────────────────────┘   │
└──────────────────────────────────────────────────────────┘

A peer is the same picture with the terminal on the other end of an SSH tunnel. The pane is local; the shell, the agent, and the files are not:

   this Mac                                    peer host
┌──────────────┐                        ┌────────────────────┐
│  pane / UI   │                        │  Mac: the app      │
│  agent panel │◀── ssh -L ── peer ────▶│  Linux: term-meshd │
│              │      protocol          │                    │
│  leader ─────┼── delegate / collect ─▶│  shell · agent CLI │
└──────────────┘                        │  worktrees         │
                                        └────────────────────┘

The far side owns the process. Quitting here does not end the work there.

Install

Homebrew (recommended)

brew install --cask x-mesh/tap/term-mesh

The cask downloads the latest DMG from GitHub Releases, copies term-mesh.app into /Applications, and strips the Gatekeeper quarantine attribute automatically — so the unsigned build launches without a manual xattr step.

Bundled CLI helpers (tm-agent, term-mesh-run) are symlinked to $(brew --prefix)/bin.

Upgrade / uninstall:

brew upgrade --cask term-mesh
brew uninstall --cask term-mesh           # remove the app
brew uninstall --cask --zap term-mesh     # also remove ~/Library data and ~/.term-mesh

"App already exists" on first install

If you previously installed term-mesh manually (e.g. by dragging the DMG) and then run brew install --cask, Homebrew refuses to overwrite the existing bundle:

Error: It seems there is already an App at '/Applications/term-mesh.app'.

Either pass --force to let Homebrew take over the existing app:

brew install --cask --force x-mesh/tap/term-mesh

…or move the existing app out of the way first:

mv /Applications/term-mesh.app ~/Downloads/term-mesh.app.manual-backup
brew install --cask x-mesh/tap/term-mesh

Quit any running term-mesh instance before either command.

DMG (manual)

Grab term-mesh-macos-<version>.dmg from the latest release, open it, and drag term-mesh.app into /Applications. Because the build is not notarized, run once after copying:

xattr -dr com.apple.quarantine /Applications/term-mesh.app

Auto-updates (Sparkle) handle subsequent versions.

Prerequisites

Component Version Notes
macOS 14 Sonoma+ Metal 2 required
Xcode 15+ Swift 5.9+
Rust stable 1.88+ edition 2021
Zig 0.15+ For libghostty build

A peer host needs none of the above — see Peer hosts.

Quick Start

# 1. Clone and setup
git clone https://github.com/x-mesh/term-mesh.git && cd term-mesh

# 2. Build libghostty + native app
./scripts/setup.sh
./scripts/reload.sh --tag dev

# 3. Run daemon only (for development)
cd daemon && cargo run --bin term-meshd

CLI Usage

The term-mesh CLI controls the app via Unix socket. Install location: ~/bin/term-mesh

Two more ship beside it: tm-agent drives agent teams (see Agent Teams), and term-mesh-run wraps a command in a PTY. Homebrew symlinks all three into $(brew --prefix)/bin.

Running Commands (PTY Wrapper)

term-mesh run claude code                    # Run Claude Code in PTY wrapper
term-mesh run -- kiro-cli chat "fix this"    # Run any command
term-mesh run --sandbox claude code          # Run in isolated git worktree

Window & Workspace Management

term-mesh list-windows                       # List all windows
term-mesh new-window                         # Open a new window
term-mesh list-workspaces                    # List workspace tabs
term-mesh new-workspace                      # Create a new workspace tab
term-mesh new-workspace --command "htop"     # New workspace running a command
term-mesh select-workspace --workspace 2     # Switch to workspace by index
term-mesh rename-workspace "My Project"      # Rename current workspace
term-mesh close-workspace --workspace 3      # Close a workspace tab
term-mesh current-workspace                  # Show active workspace info

Panes & Splits

term-mesh new-split right                    # Split right (terminal)
term-mesh new-split down                     # Split down
term-mesh new-split right --type browser --url https://example.com
                                             # Split with browser panel
term-mesh list-panes                         # List panes in current workspace
term-mesh focus-pane --pane 2                # Focus a specific pane
term-mesh new-pane --type browser --url https://docs.dev
                                             # Add browser tab to current pane
term-mesh close-surface --surface surface:5  # Close a surface (tab in pane)
term-mesh close-surface --surface surface:5 --close-pane
                                             # Close surface and collapse pane

Terminal Input & Output

term-mesh send "ls -la"                      # Send text to terminal
term-mesh send-key Enter                     # Send a key press
term-mesh read-screen                        # Read visible terminal content
term-mesh read-screen --scrollback --lines 500
                                             # Read scrollback buffer
term-mesh capture-pane                       # tmux-compatible capture

Built-in Browser

term-mesh browser open https://github.com   # Open browser in new split
term-mesh browser navigate https://docs.dev  # Navigate existing browser
term-mesh browser eval 'document.title'      # Execute JavaScript
term-mesh browser snapshot                   # Get DOM snapshot
term-mesh browser snapshot --interactive     # Interactive DOM with selectors
term-mesh browser click '#submit-btn'        # Click an element
term-mesh browser type '#search' "query"     # Type into an input
term-mesh browser wait --selector '.loaded'  # Wait for element
term-mesh browser get title                  # Get page title
term-mesh browser get text '#content'        # Get element text
term-mesh browser back                       # Navigate back
term-mesh browser reload                     # Reload page
term-mesh browser cookies get                # Get all cookies
term-mesh browser console list               # List console messages

Notifications & Sidebar Metadata

term-mesh notify --title "Done" --body "Build complete"
term-mesh set-status build "passing" --icon checkmark --color "#00ff00"
term-mesh clear-status build
term-mesh set-progress 0.75 --label "Building..."
term-mesh log --level info --source agent "Task completed"
term-mesh sidebar-state                      # Full sidebar state dump

tmux Compatibility

term-mesh resize-pane --pane 2 -R --amount 10  # Resize pane right
term-mesh swap-pane --pane 2 --target-pane 3    # Swap two panes
term-mesh break-pane                             # Break pane to new workspace
term-mesh join-pane --target-pane 2              # Join pane into another
term-mesh pipe-pane --command "tee log.txt"      # Pipe pane output
term-mesh last-pane                              # Focus previous pane
term-mesh next-window                            # Next workspace
term-mesh find-window --content "error"          # Search across workspaces

Handle Format

Commands accept UUIDs, short refs (window:1, workspace:2, pane:3, surface:4), or indexes. Output defaults to refs; use --id-format uuids or --id-format both for UUIDs.

term-mesh --json list-workspaces             # JSON output
term-mesh --id-format both list-panes        # Include UUIDs in output
term-mesh identify                           # Show caller's workspace/surface

Environment Variables

Variable Description
TERMMESH_WORKSPACE_ID Auto-set in term-mesh terminals; default --workspace
TERMMESH_SURFACE_ID Auto-set in term-mesh terminals; default --surface
TERMMESH_SOCKET_PATH Override socket path (default: /tmp/term-mesh.sock)
TERMMESH_SOCKET_PASSWORD Socket authentication password

Run term-mesh help or term-mesh <command> --help for full details.

API Reference

HTTP REST API (port 9876)

Method Endpoint Description
GET /api/monitor System + process snapshots, budget config, usage summary
GET /api/sessions Terminal sessions from the Swift app
GET /api/watcher File heatmap snapshot (top files, events, timeline)
GET /api/usage Per-session API cost and token usage
POST /api/process/stop SIGSTOP a process {"pid": 1234}
POST /api/process/resume SIGCONT a process {"pid": 1234}
POST /api/budget/auto-stop Toggle auto-stop {"enabled": true}
POST /api/watcher/watch Start watching a path {"path": "/..."}
POST /api/watcher/unwatch Stop watching a path {"path": "/..."}

JSON-RPC 2.0 (Unix Socket)

Socket path: $TMPDIR/term-meshd.sock

Method Description
ping Health check (returns "pong")
worktree.create Create a sandboxed worktree
worktree.remove Remove a worktree by name
worktree.list List all term-mesh worktrees
monitor.snapshot Get system/process resource snapshot
monitor.track Track a PID for monitoring
monitor.untrack Stop tracking a PID
process.stop Send SIGSTOP to a process
process.resume Send SIGCONT to a process
budget.auto_stop Enable/disable auto-stop
watcher.watch Watch a filesystem path
watcher.unwatch Unwatch a filesystem path
watcher.snapshot Get heatmap snapshot
usage.snapshot Get API cost/token snapshot
session.sync Push session list from Swift app
session.list List terminal sessions

Project Structure

Sources/                 # the macOS app (Swift + AppKit + SwiftUI)
  TeamOrchestrator*.swift    # teams, delegation, remote leaders and agents
  Peer*.swift                # peer hosts: discovery, tunnels, health, panes
  Panels/                    # agent panes, terminal panes, browser panes
  GhosttyTerminalView.swift  # libghostty surface hosting
  TerminalController*.swift  # the socket API the CLI talks to

daemon/                  # Rust
  term-meshd/            # the daemon: monitoring, worktrees, peer serving
  term-mesh-cli/         # `term-mesh` and `tm-agent`
  term-mesh-peer-relay/  # the helper a remote pane runs
  tm-agent-bridge/       # agent CLIs that do not speak the protocol natively
  peer-proto/            # wire types, shared with Swift

swift/PeerProto/         # the peer protocol, Swift side
vendor/bonsplit/         # the split/tab layout engine (vendored, not a submodule)
ghostty/                 # libghostty (submodule, JINWOO-J/ghostty fork)
scripts/                 # setup.sh, reload*.sh, install-linux.sh, release tooling
docs/                    # peer federation, Linux hosts, protocol notes

Build & Test

# Run all Rust tests
cd daemon && cargo test

# Run daemon in development mode
cd daemon && cargo run --bin term-meshd

# Performance benchmarks (requires running daemon + socat)
bash daemon/scripts/bench.sh

License

This project is licensed under the GNU Affero General Public License v3.0 or later (AGPL-3.0-or-later).

Built on Ghostty by Mitchell Hashimoto.

About

No description, website, or topics provided.

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages