A macOS menu bar app that monitors Claude Code sessions running in Ghostty in real time.
- Menu bar: braille spinner + live
processing/totalcount (e.g.⠋ 2/19) - Dashboard window: Processing / Idle sections, per-session title · project · last-input time ("12m ago")
- Click a card → jump to its Ghostty tab
- Launch-at-login toggle
🧪 Beta (v0.1.1) ·
⚠️ Ghostty only — iTerm2, Terminal.app, kitty, WezTerm, etc. are not supported (see "How it works").
- macOS 13 (Ventura) or later
- Ghostty terminal
- Claude Code sessions running in Ghostty tabs
Download the latest ClaudeBar-x.y.z.dmg from Releases and drag ClaudeBar.app into Applications.
It is signed & notarized, so it opens without a Gatekeeper warning. If it ever gets blocked, right-click → Open, or:
xattr -dr com.apple.quarantine /Applications/ClaudeBar.appgit clone https://github.com/wonsss/ClaudeBar.git
cd ClaudeBar
./build.sh # build + sign + install to /ApplicationsOn first run you'll get a "ClaudeBar wants to control Ghostty" automation prompt → Allow.
If denied: System Settings > Privacy & Security > Automation > ClaudeBar → Ghostty.
Reset if it gets stuck: tccutil reset AppleEvents io.github.wonsss.claudebar
Screen Recording permission is not needed. ClaudeBar only reads tab titles & working directories — never terminal contents/scrollback (Ghostty doesn't expose them) — and makes no network calls.
| Data | Source |
|---|---|
| Session list · title · state · tab location (for jump) | Ghostty tabs (AppleScript). Title = Claude's generated summary |
| Processing vs idle | Tab-title glyph — braille spinner ⠋⠙⠹… (U+2800–U+28FF) = processing, ✳ (U+2733) = idle |
| Last-input time | ~/.claude/history.jsonl (last input per sessionId) |
| Live-session enrichment | ~/.claude/sessions/<pid>.json + pgrep -x claude |
- Jump: focuses the tab by its windowID/tabIndex, then brings Ghostty forward via AppKit
NSRunningApplication.activate(a reliable path for an accessory app to foreground another app). - Time matching: there is no stable key linking a session to a tab, so the last-input time is matched best-effort by keyword overlap between the tab title and the session's first prompt (omitted when no confident match).
- AppleScript enumeration runs on a dedicated background thread with its own run loop, so the menu bar UI never blocks.
ClaudeBar relies on undocumented, internal behavior of Claude Code and Ghostty:
- Claude Code: the file formats of
~/.claude/sessions/<pid>.jsonand~/.claude/history.jsonl, and the status glyphs Claude writes into the tab title (braille spinner /✳). - Ghostty: its AppleScript dictionary (
window/tab/terminal,focus) andtab-group-…window IDs.
These are not public APIs, so an update to either app may change the format/glyphs and break ClaudeBar.
Verified against: Claude Code 2.1.x, Ghostty (latest as of 2026-06). If the list goes empty or jumping stops working after an upgrade, ClaudeBar may need an update — please open an issue.
| Item | Status |
|---|---|
| Network | None — zero networking code. All data stays in local memory |
| File writes | None — no disk writes other than osascript stdin |
| Permissions | Automation (→ Ghostty) only. No screen recording / accessibility / full-disk |
| Subprocesses | /usr/bin/pgrep, /usr/bin/osascript — absolute paths, fixed args |
| AppleScript injection | windowID validated against ^[A-Za-z0-9-]+$; tabIndex is a positive integer |
| Code signing | Developer ID signed + notarized (Release DMG) |
Note: prompt text from history.jsonl is read and shown in the dashboard (your own data, local only, never transmitted) — it may be visible during screen sharing/recording.
- Ghostty only — other terminals show an empty list.
- Last-input time is best-effort; when several same-state sessions share a project, times may be attributed to a sibling session.
| File | Role |
|---|---|
Session.swift |
Session model |
GhosttyScanner.swift |
Tab enumeration (title/state/cwd/windowID) + jump |
SessionRegistry.swift · HistoryIndex.swift |
Read ~/.claude registry & history (time enrichment) |
Matcher.swift |
Attach time by keyword-matching tabs ↔ history |
AppleScriptRunner.swift |
Run NSAppleScript on a dedicated run-loop thread |
SpinnerClock.swift · RelativeTime.swift |
Menu bar spinner · relative time |
SessionStore.swift |
Polling + @Published state |
DashboardView.swift |
Popover + dashboard window UI |
LoginItem.swift · ClaudeBarApp.swift |
Login item · app entry point |
swift build # debug build
./build.sh # release build + sign + install
./notarize.sh --store-credentials # one-time: store notarization credentials (TTY)
./create-dmg.sh # build a notarized DMGReleases are cut manually:
./create-dmg.sh
gh release create vX.Y.Z ClaudeBar-X.Y.Z.dmg --title "ClaudeBar X.Y.Z" --prerelease -F CHANGELOG.mdMIT © 2026 Wonseok Jang
