Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

yeonsh/termy

Repository files navigation

termy icon

termy

Mission control for Claude Code and Codex CLI.

A native macOS terminal built for running many coding agents at once —
so you always know which one is blocked, working, or waiting on you.

Four Claude Code agents grouped by project, with a live status dashboard at the bottom (dark theme)

Press G to jump straight to the next WAIT agent.


Why termy

Running N coding agents — Claude Code, Codex CLI, or a mix — in a stock terminal turns into tab roulette: which session is blocked on a permission prompt, which is mid-tool, which already finished? You end up Cmd-Tabbing through windows, scanning panes, and missing the one that was waiting on you five minutes ago.

termy pulls that state out of the panes and into a glanceable dashboard. Every running agent — Claude Code or Codex CLI — gets a chip at the bottom of the window with its live status: IDLE, THINK, or WAIT. When something goes WAIT, macOS notifies you — even if termy isn't focused. One keystroke takes you there.

Projects, not tabs

Other terminals give you tabs. termy gives you projects.

Every pane belongs to a project (its cwd), and the top filter bar shows one pill per project. Click termy to see only the termy panes. Click ALL to see everything. Same project → same pastel accent everywhere — pane header, dashboard chip, filter pill — so a four-agent window stops looking like a soup of identical black rectangles.

Filter bar with numbered project pills visible while holding ⌘

Hold and a number appears on every filter pill. Press the number — you're there. 0 is always All; 19 jump straight to that project's pane grid. No tab order to memorize, no cycling through things you don't care about.

Prefer names? K opens a fuzzy project switcher over every project termy has seen, with pane counts and "last used" timestamps. Picking one restores that project's saved pane grid.

⌘K fuzzy project switcher

A dashboard for every agent

The strip along the bottom of the window is one chip per running agent — Claude Code or Codex CLI, mixed freely. Each chip shows project / branch and a live state:

Dashboard row showing WAIT, WAIT, THINK, and IDLE states

  • IDLE — agent is at the prompt, nothing running.
  • THINK — tool call in flight.
  • WAIT — blocked on a permission prompt. Your attention needed.

G jumps to the next WAIT pane, wherever it is — across splits, across project filters. The single most useful keystroke in the app.

Hold and a number appears on each dashboard chip; press the number to focus that pane directly, even if it's in a different project filter.

See it in action

Pane borders colored by state
State shows up everywhere. Pane border, dashboard chip, and a macOS notification — all driven by Claude Code's Notification and Stop hooks. Three-pane split layout on a single project
Splits, not tabs. Nested NSSplitViews. Drag to resize. D for a row split, D for a column.
Keyboard shortcut overlay
/ reveals everything. The full shortcut map — focus, projects, splits, window. No hidden bindings. Dark side-by-side with an editor
Lives next to your editor. Light, Dark, or Match System — View → Appearance switches terminal, chrome, and dashboard together.

What else you get

  • Permission-prompt notifications. Claude goes WAIT → macOS pings you, even if termy isn't focused.
  • Workspace that survives. Splits, project grouping, and cwd are all persisted per project. K a project and termy rebuilds the pane grid you left it in.
  • Real splits. D row split, D column. Drag dividers. toggles maximize.
  • Native, not Electron. AppKit + SwiftTerm. 2 MB signed DMG, ~3.6 MB installed. Real UserNotifications, Full Disk Access, titlebar chrome.

Claude Code hooks

First launch asks once — "Install termy hooks into Claude Code?" — and the app merges its entries into ~/.claude/settings.json, preserving any hooks you already have. Every entry is tagged _termy_managed: true so uninstall is surgical, and the previous file is backed up to settings.json.backup-<ts> before any write.

  • If you move the app, the next launch detects the stale path and silently re-registers against the new location.
  • To uninstall, use the termy menu → Claude Code Hooks...Uninstall. Your own hooks are untouched.
  • termy-hook always exits 0 and write-timeouts after 100 ms — it cannot stall Claude Code even if termy isn't running.

Codex CLI hooks

Codex CLI is supported via the same termy-hook binary and an analogous TOML installer that writes to ~/.codex/config.toml. If termy detects a Codex install (it probes ~/.codex and the common Homebrew / npm / cargo / mise / asdf install paths), it will offer to install the integration on first launch; otherwise opt in any time via termy menu → Codex Hooks...

Mappings (per developers.openai.com/codex/hooks):

Codex event Pane state
SessionStart hard reset to IDLE
PreToolUse / PostToolUse THINK
PermissionRequest WAIT + macOS notification
Stop IDLE after 30 s

Codex has no native SessionEnd hook; termy synthesizes one by watching the foreground process group of each pane's PTY (tcgetpgrp + libproc). Once codex leaves the foreground (/exit, Ctrl-C), the chip resets to neutral INIT automatically — even though no hook fired.

Caveat: Codex hooks don't cover every state transition

Claude Code exposes a complete state-tracking surface: Notification fires the moment Claude stops to ask for input, and Stop fires when the agent finishes a turn. Codex's hook surface is narrower. There's no Notification-equivalent — PermissionRequest fires only for explicit permission asks, not the general "I'm waiting on you" pauses that reasoning models (GPT-5, o-series) lean on. Result: a Codex pane can sit silent at a > prompt with no hook ever firing.

termy fills the gap with a two-stage silence detector: ~8 s of PTY quiet moves the chip to a silent POSSIBLY_WAITING (visual only, no sound), and ~12 s of further quiet promotes it to WAITING (chip + macOS notification). Any byte from the PTY reverts the silent state instantly. The trade-off: Codex WAIT lands ~20 s after the agent actually paused rather than instantly, and the false-positive rate isn't zero. If Codex ships a Notification-equivalent in future, termy will switch to it and drop the heuristic.

Keyboard cheatsheet

G Jump to next WAIT pane
0 Show all projects
19 Jump to project filter N (hold to see numbers)
19 Jump to dashboard chip N (hold to see numbers)
K Fuzzy project switcher
[ / ] Previous / next pane
←↑↓→ Focus pane in direction
D / D Split row / column
Toggle maximize focused pane
W Close focused pane
/ Full shortcut overlay

How it works

Claude Code ──hook──▶ termy-hook (CLI) ──unix socket──▶ HookDaemon (in-app actor)
 Codex CLI ──hook──▶ termy-hook --agent codex ──┘ │
 │
 ┌────────┴────────┐
 ▼ ▼
 PaneStateMachine fg-process watcher
 │ (synthetic
 ▼ SessionStart/End)
 MissionControlView + Notifier
  • SwiftTerm renders the PTY and owns the child shell lifecycle.
  • termy-hook is a tiny Swift CLI that Claude Code invokes per hook event. It slims the payload and sends one JSON line over /tmp/termy-$UID.sock.
  • HookDaemon is an actor that receives those events and runs them through PaneStateMachine, the pure reducer covered by 74 unit tests.
  • Synthetic PtyExit fills the gap Claude Code's hooks can't: hard crashes (Ctrl+C mid-response, SIGKILL) fire no hook, so termy emits a synthetic event on PTY EOF. Details in docs/project-overview.md.

Status

The core loop is working end-to-end:

  • SwiftTerm panes with OSC 7 cwd tracking, splits, and -click URL open
  • Hook daemon + termy-hook end-to-end
  • XCTest coverage over the state machine, fuzzy match, persistence, and filter layout
  • Workspace autosave + restore with project-scoped pane grids
  • Developer ID-signed, notarized DMG pipeline (scripts/dist.sh)

Not in v1

See TODOS.md for deferred work — screen-scraping fallback for non-hook agents, separate LaunchAgent daemon, user-editable hook config, per-project settings UI.

Internals

  • docs/project-overview.md — architecture, runtime, hook system constraints
  • TODOS.md — scoped-out work with reasoning
  • apps/termy/Sources/ — the app (25 files)
  • apps/termy-hook/Sources/ — the hook helper CLI
  • apps/termy-tests/Sources/ — 74 tests across 8 suites

About

Native macOS terminal for running multiple Claude Code & Codex CLI agents in parallel — glanceable per-agent state so you stop juggling tabs.

Resources

License

Stars

Watchers

Forks

Packages

Contributors

AltStyle によって変換されたページ (->オリジナル) /