Which of my Claude Code sessions is waiting for me?
I keep one Mac desktop per project, and most of them have a terminal running Claude Code. With ten sessions going, the slow part of my day was no longer the code. It was walking through desktops to find the one that had stopped twenty minutes ago to ask for permission to run a command. This is how Spacepal now tells me, and what I got wrong on the first day.
Claude Code already says when it stops
Claude Code has hooks: commands it runs at points in a session. Three of them are enough here:
- Notification runs when Claude needs something from you, such as permission to use a tool.
- Stop runs when it finishes its turn.
- UserPromptSubmit runs when you send it a message, which means you have answered.
Each hook gets a small JSON object on stdin with the session's working folder and, for notifications, the message Claude would show, like "Claude needs your permission to use Bash".
From a folder to a desktop
The hook runs the Spacepal binary with a flag: Spacepal --agent-event waiting. That short-lived process reads the JSON, finds the terminal it was started from by walking up its parent processes until one has a tty (ttys002), and passes folder, message and tty to the running app with a distributed notification. Then it exits. Nothing leaves the Mac.
The app then has to decide which desktop the folder belongs to. Spacepal already records the terminals on each desktop and the folders they run in, because it puts them back after a restart. So the rules are:
- A desktop with a terminal in exactly this folder.
- Otherwise a desktop whose note names the folder.
- Otherwise the deepest parent folder, but only if a single desktop has it.
The third rule exists because of my own setup: several desktops have a terminal sitting in ~/workspace, the parent of every project. "Longest matching folder" picked the first of those for a project that had no desktop of its own, which was wrong. Now a tie means "don't know", and nothing is marked.
What you see
The overview tile gets an orange Waiting or green Done, the menu says the same next to the desktop's name, and the menu bar shows how many are waiting. If you are on another desktop when Claude asks, a short notice shows its message. ⌃⌥J goes to the session that has waited longest; Spacepal switches desktops and then asks iTerm or Terminal, over AppleScript, to select the window and tab on that tty. The mark clears when you visit the desktop or answer.
While I was at it, the tiles of project desktops now show the git branch, how many files changed, and local servers started from the project folder, found with lsof and each process's working folder. The first version also listed the Android emulator's ports as "dev servers", so tooling from the Android SDK, databases and ephemeral ports are left out.
What I got wrong
A few hours after release I opened the menu and seven desktops said "Claude is waiting". They were not. Claude Code also sends a Notification when a session has sat idle at its prompt for about a minute, with the message "Claude is waiting for your input". I had counted that as a question. Every finished session turned orange a minute later, and the real permission request was lost among them. Version 1.2.13 treats the idle notice as finished, using the hook's notification type where Claude Code provides it and the message text otherwise.
Limits
- It needs the hooks, which Spacepal adds to
~/.claude/settings.jsonwhen you click Add to Claude Code (with a backup). Sessions started before that do not report. - Bringing the tab forward works in iTerm and Terminal. Other terminals still get the desktop switch.
- It only knows the desktop if Spacepal has seen that project's terminal there, or a note names the folder.
- It is in the direct version of Spacepal, not the Mac App Store one.
Setup and details: Spacepal for Claude Code. The MCP server exposes the same state to agents through agent_sessions, so one session can check whether another has finished.
Written by Dan Bayer, developer of Spacepal. Last updated 2026-11-13.