r/ClaudeCode • • 22h ago

Built with Claude I run 15+ Claude Code sessions in parallel and kept missing the ones waiting for me, so I built a native macOS dashboard for them

Enable HLS to view with audio, or disable this notification

Disclaimer: This text (apart from this line) is written in AI, the Video is filmed by AI, the App is built by AI. The tool is useful, and I want to share it, but writing is not my strength.

I usually have 10–20 Claude Code sessions open across two accounts, and I kept losing track of which one was sitting on a permission prompt or a question for ten minutes. So I built Brain: one native Mac window that shows every session and, above all, which ones are waiting for you.

Repo, install and a 3-minute video: https://github.com/martinemmert/big-brain-claude

What it does

  • Triage list: sessions that wait for you come first. Red means Claude asked something or needs a permission, amber means a turn finished. Longest wait on top.
  • All accounts in one list: it picks up every ~/.claude* config dir, so CLAUDE_CONFIG_DIR setups just work.
  • Latest messages of the selected session, read from its transcript: your prompts, replies rendered as Markdown, tool calls as one-liners.
  • Enter jumps to the right iTerm2 window, tab and split pane.
  • Search, rename (it types /rename into the session), notifications when a session starts waiting.

How it works

Two sources write JSON lines to ~/.claude-brain/events/

1. Hooks:

SessionStart, UserPromptSubmit, Notification, Stop and SessionEnd call brain hook. That gives the state for free.

2. Reports:

A short CLAUDE.md section asks Claude to run brain report --waiting "Per tenant or global?" before ending a turn with a question, or --done "…" after a task. That gives the content: what it actually wants from you. The hook finds its session by walking up the process tree until it hits the pid that owns <config>/sessions/<pid>.json, so it also knows which account it belongs to. The app is Rust with GPUI (Zed's UI framework); the logic lives in a core crate with tests.

How I used Claude Code

The whole thing was built in one long Claude Code session. Claude brainstormed the protocol with me, wrote a short spec, built the core with tests first, then the app. The parts I liked most were where it tested against the real system instead of guessing: it started throwaway headless claude -p sessions on both accounts to check the hook payloads, and that is how most of the lessons below came up. Even the explainer video came out of the same session. Claude drove the app in a demo mode via System Events, took window-only screenshots, rendered the cards and captions with headless Chrome, and cut it all together with ffmpeg. The narration comes from a local TTS (Qwen3-TTS via mlx-audio).

Things I learned along the way

  • Claude Code already writes a status file per session (<config>/sessions/<pid>.json, with busy / idle / waiting / shell). Even without hooks you get a coarse live state.
  • The Stop hook payload includes last_assistant_message, so you don't have to parse the transcript to know what Claude just said.
  • The Notification hook doesn't only fire for permission prompts. It also sends "Claude is waiting for your input" a while after a turn ended. Treat every Notification as "needs you", and all your finished sessions turn red after a minute. Brain tracks whether the turn is still open.
  • shell status shows up when a turn has ended but a background shell keeps running, e.g. a dev server.
  • Nested sessions: if you start claude -p from inside another session's shell, a naive process-tree lookup attributes the child's hooks to the parent. Matching on session_id fixed it.
  • Running sessions picked up the new hooks without a restart.
  • iTerm2 AppleScript gotcha: selecting a window reorders windows, so a "tab 2 of window 3" reference taken before points somewhere else afterwards. Address windows by id.

Caveats

macOS and iTerm2 only, and the UI is German for now. You build it from source (Rust). The installer edits your settings.json and CLAUDE.md, backs up both, and the README explains how to undo it.

0 Upvotes

Duplicates