Skip to main content

sessions-view

The read side of session mission control: see every concurrent Claude session on this machine without window-hopping. It reads the registry the session-safety hooks already write โ€” it never mutates it.

This is the companion to the write-side hooks from session-safety: session-register (creates the entry + heartbeat), session-guard (records touched files + collisions), session-drift-check (heartbeat on each prompt + clears wait_state), and notify-attention (sets wait_state when a session blocks on the developer).

Registry shapeโ€‹

Each live session is a JSON file at <repo>/.claude/session/sessions/<session_id>.json:

session_id, surface, cwd, repo_root, branch,
started_at / started_epoch, last_heartbeat / last_heartbeat_epoch,
baseline_head, baseline_origin_master, last_fetch_epoch,
files_touched: [...],
wait_state: { type, reason, since, since_epoch } # present only while blocked

The registry is gitignored, per-repo, machine-local. archive/ holds reaped stale entries โ€” ignore it.

Stepsโ€‹

  1. Run the reader. The single source of derivations (age, live/stale, collision, waiting) is the script โ€” do not re-implement the logic in chat:

    node scripts/sessions-view.mjs --json

    It returns one row per session with live, collision, files_touched, age_secs, and a resolved wait_state (or null). Live/stale uses SESSION_TTL_SECS (default 900s), matching the hooks.

  2. Machine-wide (optional). The registry is per-repo. To include sessions in other repos, pass each root โ€” node scripts/sessions-view.mjs --json --root /path/a --root /path/b โ€” or set SESSIONS_REGISTRY_ROOTS=/path/a:/path/b. Default is the current repo.

  3. Render the table, ordered so what needs the developer comes first:

    • Waiting on me โ€” wait_state set (a permission or idle prompt the session can't clear itself). Show the reason and the claude --resume <id> hint.
    • Collisions โ€” two live sessions on the same branch+dir (session-guard blocks the later one). Name both.
    • Live โ€” heartbeat within the TTL.
    • Stale โ€” past the TTL; likely closed. The hooks reap these on the next SessionStart.

    Columns: surface ยท branch ยท dir (basename of cwd) ยท files ยท age ยท state ยท flags ยท claude --resume <id>.

  4. HTML dashboard (on request / --ui). For a richer, self-refreshing window:

    node scripts/sessions-view.mjs # writes + opens file://$TMPDIR/bewith-sessions.html (macOS)
    node scripts/sessions-view.mjs --watch # regenerates every 10s for a live wall-display

    Zero backend, machine-local. The page auto-refreshes; --watch keeps the data fresh underneath it.

Boundariesโ€‹

  • Read-only. This skill and script never write the registry. Reaping, heartbeats, and wait_state are owned by the hooks.
  • If the registry dir doesn't exist, the session hooks aren't wired in this repo โ€” say so and point at install-bewith-plugin.md rather than fabricating a list.
  • A stale entry is not proof a session died (the heartbeat only advances on SessionStart, each prompt, and edits) โ€” report it as "stale (likely closed)", not "closed".

โญ Favoritesโ€‹

Alongside live sessions, the dashboard and the SwiftBar menu show a โญ Favorites section โ€” sessions the developer pinned with /favorite (owned by the favorite-session skill). They are read from the local cache ~/.bewith/favorites.json (no network), so they render instantly and survive the registry's reaping. In the menu, clicking a favorite re-attaches it in a terminal (claude --resume).

When rendering the chat view of /sessions, also run node scripts/session-favorites.mjs list and show the favorites under the live-sessions table.