Skip to main content

claude-recents

Quick — you have seven Claude sessions running. What is each one doing right now? …Exactly. Stop keeping that in your head. That's what this app is for.

The only ADHD cure you'll ever need.

A macOS menu bar app that shows what every one of your Claude Code sessions is doing — right now, across all your machines.

If you run more than a couple of Claude Code sessions at once (a few locally, a few on remote GPU boxes over SSH), you know the feeling: which session was doing what again? claude-recents puts a ✳ icon in your menu bar with a live count of working sessions, and one click opens a panel where every session shows its latest request, the latest reply, and what it is doing at this exact moment.

한국어 문서 (Korean)

claude-recents panel (dark mode)

Features

  • Live session list — every running Claude Code session on this Mac, plus any remote servers you add. Sessions are grouped by machine, sorted by your most recent request.
  • Chat-style cards — each session shows your latest request and Claude's latest reply as chat bubbles, with line breaks preserved. Click a card to expand the full text. If replies piled up while you were away (autonomous loops, long goals), a small "⋯ N earlier replies" marker tells you so without flooding the card.
  • What it's doing right now — working sessions show a live activity line ("Running command · pytest tests/auth -x", "Editing file · …") and a status: 🟢 working, 🟠 waiting for your approval, ⚪ idle.
  • Remote servers over SSH — add any host from your ~/.ssh/config in two clicks. Nothing is installed on the server: each poll pipes a small script through ssh and parses your Claude sessions there. Per-server connection status (connected / connecting / failed) is always visible.
  • Multi-account aware — sessions from other Claude accounts (separate CLAUDE_CONFIG_DIR profiles, claude-swap profiles) are picked up automatically and badged with their account.
  • Stays out of your way — flat, native-feeling UI with light/dark themes, drag-to-reorder server sections, collapsible groups for stale sessions ("Last week", "Older"). Menu bar icon shows ✳ working/total at a glance.
  • Private by design — everything is read locally (or over your own SSH connections). Nothing is sent anywhere.

Install

Requires macOS 12+ and Python 3.12+.

uv tool install claude-recents      # recommended
# or: pipx install claude-recents
# or: pip install claude-recents

claude-recents                       # ✳ appears in your menu bar

Updating

uv tool upgrade claude-recents      # or: pipx upgrade claude-recents
# plain pip: pip install -U claude-recents

The app also checks PyPI once a day (and via right-click → Check for Updates) and shows an Update & Restart banner in the panel when a new version is out — one click upgrades and relaunches. Set "update_check": false in the config file to disable the daily check.

Start at login (optional)

Right-click the ✳ menu bar icon → Start at Login. That's it — the app writes its own LaunchAgent (~/Library/LaunchAgents/com.kiddj.claude-recents.plist) and starts automatically from your next login. Toggle it again to turn it off.

Tip: if you launch the app from a tmux daemon or SSH shell, the process will run but the icon won't appear — menu bar items require the GUI login session. Launching normally (or via Start at Login) guarantees the right context.

Usage

  • Click the ✳ icon → the panel opens. Click again (or click outside) to close.
  • Click a card → expands the full request/reply and the session's working directory.
  • Click a server header → collapse/expand that machine's sessions.
  • Drag a server header → reorder machines (a blue insertion line shows where it will land).
  • Add Server (bottom of the panel) → pick a host from your ~/.ssh/config and press Add.
  • Unlink icon on a server header → "Disconnect / Cancel" to remove that server.
  • ↻ Refresh (header) → re-poll every server immediately, even mid-connection.
  • ☀ / ☾ → light/dark theme (defaults to following the system).
  • Right-click the menu bar icon → quit.

Adding remote servers

Remote monitoring needs passwordless (key-based) SSH — the app polls with ssh -o BatchMode=yes, so password prompts cannot work. Set it up once per server:

ssh-copy-id my-server

The server needs python3 on its PATH (any modern Linux does) and, of course, Claude Code sessions running on it. If authentication fails, the panel shows exactly that with the fix inline.

Session states

Marker State Meaning
🟢 solid green, pulsing working Claude is thinking, running tools, or writing a reply right now
🟠 solid orange, pulsing waiting Claude is waiting for your decision (e.g. a permission prompt)
🟠 hollow orange ring, static + stalled badge stalled the status flag says "working", but nothing has happened for hours — see below
⚪ gray idle the reply is finished; Claude is waiting for your next message

The menu bar count (✳ 3) counts working + waiting sessions only.

About "stalled" (a heuristic, explained honestly)

Status flags come from Claude Code itself, and they can get stuck: if a session loses its connection mid-turn (dropped SSH, a killed remote-control link during a shell call), the claude process stays perfectly healthy — event loop running, shell child alive — but it waits forever for an event that will never arrive, and never writes the "back to idle" transition. From the outside, every process-level signal (state, CPU, TTY, child processes) looks identical to a genuinely working session; we tested them all. The only observable difference is that a stuck session stops producing transcript output.

So claude-recents marks a session as stalled when its flag claims active but there has been no observable activity for 3+ hours. In measured practice the two populations are far apart — really-working sessions emit events every few seconds-to-minutes (even day-long autonomous loops), while stuck ones sit silent for days — so misclassification is unlikely. A quiet foreground command running longer than 3 hours would be the one false-positive case.

Stalled sessions consume no tokens (no API calls — their transcripts prove it) but do hold server memory. Killing the process is safe: the conversation stays on disk and claude --resume picks it up again.

How it works

Claude Code keeps per-session state on disk. claude-recents reads it — nothing more:

What you see Where it comes from
Live sessions, working/idle/waiting ~/.claude/sessions/*.json (+ process liveness check)
Your latest request, latest reply, current tool activity session transcripts in ~/.claude/projects/…
Account badges ~/.claude.json
Remote sessions the same files on the server, fetched via ssh <host> python3 - (a self-contained script; parsing happens server-side, only compact results travel back)

Refresh is every 2 seconds locally; remote hosts are polled every 10s while the panel is open and every 60s in the background. If a server becomes unreachable, the panel keeps the last received data, shows the connection error inline, and marks the section with how old the data is (e.g. · 5m old) — it catches up automatically (or instantly via the refresh button) once the network is back.

Note: the per-session state files are an undocumented Claude Code internal (verified against v2.1.x). A future Claude Code update could change them; the parser is written defensively, but if things break, please open an issue with your Claude Code version.

Configuration

Everything you change in the UI (servers, section order, collapsed state, theme) is persisted to ~/.config/claude-recents/config.json. You can also edit it directly:

{
  "ssh_hosts": ["gpu-server", "staging-box"],   // remote machines to monitor
  "host_order": ["gpu-server", ""],             // section order ("" = This Mac)
  "host_collapsed": [],                          // collapsed sections
  "theme": "auto",                               // "auto" | "light" | "dark"
  "extra_config_dirs": ["~/.claude-work"],       // extra CLAUDE_CONFIG_DIR profiles
  "panel_width": 460,                            // optional, defaults shown
  "panel_height": 900                            // optional, defaults to screen height
}

Privacy

  • All data is read from your local disk or over SSH connections you configured.
  • The app's only outbound request is an optional once-daily version check against PyPI ("update_check": false disables it) — no telemetry, no accounts, no cloud.
  • Requests/replies are displayed, never stored anywhere new.

Limitations

  • macOS only (menu bar app built on PyObjC).
  • Shows sessions on machines you can reach — there is no public Anthropic API for listing a Claude account's cloud/web sessions, so those can't appear.
  • Session titles come from Claude Code's local session name, which can differ from the title shown in the Claude mobile/desktop apps (that one is generated server-side and not available locally).

Development

git clone https://github.com/kiddj/claude-recents
cd claude-recents
python3 -m venv .venv && .venv/bin/pip install pyobjc-framework-Cocoa pyobjc-framework-WebKit
PYTHONPATH=src .venv/bin/python -m claude_recents.app

To build the standalone .app bundle (no Python required on the target machine), see README.ko.md for the py2app recipe and the post-build privacy scrub steps.

License

MIT © 2026 kiddj

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

claude_recents-0.1.9.tar.gz (34.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

claude_recents-0.1.9-py3-none-any.whl (39.4 kB view details)

Uploaded Python 3

File details

Details for the file claude_recents-0.1.9.tar.gz.

File metadata

  • Download URL: claude_recents-0.1.9.tar.gz
  • Upload date:
  • Size: 34.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.1

File hashes

Hashes for claude_recents-0.1.9.tar.gz
Algorithm Hash digest
SHA256 8da65dd48d1e773890ea3562235aa008fa0912d615cbb54432931240c04b58bb
MD5 6de6ae11d1ea830b95d5ee0c4482d286
BLAKE2b-256 d20f352eef7335b0625bcfea0ac2be33854abc704b1d5926aa20eb552d1f7717

See more details on using hashes here.

File details

Details for the file claude_recents-0.1.9-py3-none-any.whl.

File metadata

  • Download URL: claude_recents-0.1.9-py3-none-any.whl
  • Upload date:
  • Size: 39.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/7.0.0 CPython/3.13.1

File hashes

Hashes for claude_recents-0.1.9-py3-none-any.whl
Algorithm Hash digest
SHA256 705f11552f6ad4d621f69c0b715ba7059b5b21b2ce21254b799d60a3ce353479
MD5 3461fd4974222f79ad210a11679fefd1
BLAKE2b-256 5e86f992a90fcb17a0f8435b8ffa0a5392ba32ea6f39628280cebcdf78206b27

See more details on using hashes here.

Release history Release notifications | RSS feed

0.1.10

2 files

This release

0.1.9 This release

2 files

0.1.8

2 files

0.1.7

2 files

0.1.6

2 files

0.1.5

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page