crowsnest
One session that watches your other Claude Code sessions.
A machine running many Claude Code sessions has a question nobody answers: what are they all doing, and which of them needs me? Each session knows only itself, the terminal tabs are silent until you click them, and the answer lives in forty scrollbacks.
crowsnest reads what Claude Code already writes, the registry it keeps for every running session and the transcript each one appends to, and answers in three tiers, cheapest first. It never sends, spawns, kills or writes into another session.
Start here
pip install crowsnest # Python 3.10+. Puts a `crowsnest` command on your PATH.
crowsnest install-skills # link the skill and the scout subagent into ~/.claude
Then open a session, name it, and ask in whatever words you would have used anyway:
claude -n lookout
what are my sessions doing, and is anything waiting on me?
## Waiting on you
- xa_needed_or_not (xa, 25m) — input needed
## Just finished
- monitor (proj, 10m) — "The sweep landed. It's the repo-side view, and it's complementary…"
## Working
- openloops: one session, mid-turn on the one-command test.
## Headline
1 waiting on you, 1 just finished, 1 working, 29 idle.
That answer is a synthesis. Every row behind it is one the crowsnest command printed, and the skill tells the session how to go deeper when a row is not enough: read a session's earlier turns, ask the session itself, or arm the event stream and be told.
The three tiers
| Tier | What | Costs the watched session |
|---|---|---|
| 1. read | crowsnest, crowsnest show X, crowsnest turns X — the registry and the transcript tail |
nothing |
| 2. ask | message a running session (Claude Code's SendMessage) and get an answer from its own context |
one turn of its context |
| 3. be told | crowsnest watch, one line per change, fed to the watching session's Monitor tool |
nothing |
The skill's rule is to never spend a costlier tier when a cheaper one answers, and never to ask a session that is busy or waiting.
The command
crowsnest who is alive: waiting on you first, then busy, then idle
crowsnest show <session> one session: last asked, last said, running now, pending question
crowsnest turns <session> -n 5 the last five turns, oldest first; --before N pages back
crowsnest watch one line per change, forever (started, exited, idle, busy, waiting, error)
crowsnest install-skills link the skill and the scout subagent into ~/.claude
<session> is the name you gave the session with claude -n <name>, a unique prefix of one, a session-id prefix, or a pid.
waiting 25m xa_needed_or_not xa input needed · Let me split that into smaller steps.
busy 14m session_monitor openloops → Bash: Run the one-command test
idle 10m monitor proj "The sweep landed. It's the repo-side view…"
-- 32 live: 1 waiting, 1 busy, 30 idle
What it reads
~/.claude/sessions/<pid>.json: written while a session runs. Name, session id, working directory,busy/idle/waiting, and when waiting, what for. Checked against a live process before it is reported, because a crash leaves the file behind.~/.claude/projects/<slug>/<session-id>.jsonl: the transcript. Read from the end, widening until one human prompt is in view;turnsreads the whole file on request.
What a transcript's content means is openloops' business, and crowsnest calls it rather than re-implementing it. openloops deliberately never looks at whether a process is running; crowsnest is that other half.
From Python
from crowsnest import roster, show, turns, events, live_sessions
roster()["counts"] # {'waiting': 1, 'busy': 1, 'idle': 30, 'other': 0}
show("monitor")["activity"]["last_assistant_text"]
for event in events(interval=5): # forever
...
Every function takes home= (the Claude Code config directory; a synced copy of another machine's works the same way) and the readers take is_alive= (how a registry pid is confirmed running).
Not in crowsnest
Starting a session, in some directory, from a phone, is xa's job (xa spawn). Asking a session a question is Claude Code's own SendMessage; the skill says when.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file crowsnest-0.0.3.tar.gz.
File metadata
- Download URL: crowsnest-0.0.3.tar.gz
- Upload date:
- Size: 28.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e301191d4b5f694470871bd2e5de9a0704b362473f6a4da632859b27ac21c084
|
|
| MD5 |
82f757d4a3f3fd3988e844630b9b050b
|
|
| BLAKE2b-256 |
d25bbc5cfa7502d00352d8b780b790e680e410c92b19414463723141bfe8748a
|
File details
Details for the file crowsnest-0.0.3-py3-none-any.whl.
File metadata
- Download URL: crowsnest-0.0.3-py3-none-any.whl
- Upload date:
- Size: 27.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.12.10 {"installer":{"name":"uv","version":"0.12.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
963e38e0b1b6cc85cb91e4ad3b4b1af822993a2f55d34da4a755903e3c5c2477
|
|
| MD5 |
7523522279bbf8bfa87a135f36d61b34
|
|
| BLAKE2b-256 |
9df79447785182f15fc96ea654ac29c6dcf690a92765ac2c0ebb40fdee61bd73
|