Skip to content

Subagent observability: hierarchy, transitions, badges, live tail (fork CI) - #2

Merged
JeanBaptisteRenard merged 5 commits into
mainfrom
feat/subagent-observability
May 22, 2026
Merged

Subagent observability: hierarchy, transitions, badges, live tail (fork CI)#2
JeanBaptisteRenard merged 5 commits into
mainfrom
feat/subagent-observability

Conversation

@JeanBaptisteRenard

Copy link
Copy Markdown
Collaborator

Internal PR for local CI verification. Stacked on #1 (this fork) / doctly#47. Canonical upstream PR is doctly/switchboard#48.

@JeanBaptisteRenard
JeanBaptisteRenard force-pushed the feat/subagent-observability branch 3 times, most recently from 24c2241 to 4ac1d2b Compare May 21, 2026 21:36
@JeanBaptisteRenard
JeanBaptisteRenard changed the base branch from feat/subagent-support to main May 21, 2026 21:36
readSessionFile JSON.parse'd every line of a session file in a single
outer try/catch. If a Claude CLI session was actively writing the file
while the worker scan read it, one mid-write line could throw and
invalidate the ENTIRE file's session row. With many parallel live sessions
this manifested as 'most projects show no sessions after a fresh index'.

- Per-line try/catch inside readSessionFile: skip malformed lines, keep
  parsing the rest.
- Per-file try/catch in workers/scan-projects.js: defensive belt and
  braces so one unparseable file can't abort an entire folder scan.
@JeanBaptisteRenard
JeanBaptisteRenard force-pushed the feat/subagent-observability branch from 4ac1d2b to e893501 Compare May 21, 2026 21:58
resolveWorktreePath was defined and exported in the file but never
actually called from deriveProjectPath. As a result every worktree under
<project>/.claude/worktrees/<name>/ appeared as a separate project group
in the sidebar instead of being grouped under its parent project.

Wire the call in both branches of deriveProjectPath (direct .jsonl path
and subdirectory path) and export resolveWorktreePath for other callers.
session-transitions.js now tracks per-active-session knownSubagents and emits
two new IPC events:
- subagent-spawned (parentSessionId, agentId, subagentType, description) when
  a new agent-*.jsonl file appears under <sid>/subagents/
- subagent-completed (parentSessionId, agentId) when an existing file's mtime
  has been stable for >30s

Adds two IPCs for read-only live tailing:
- start-subagent-watch (parent, agentId) -> watchId
- stop-subagent-watch (watchId)

The watcher streams new JSONL entries via subagent-watch-event so the renderer
can append them to an open inline-expanded subagent transcript without polling.
- sidebar.js: subagents are no longer flat siblings of their parent. Each
  top-level row now shows a 'N subagents' affordance with a disclosure caret;
  expanded children render indented with a subagentType pill, description as
  label, and persist expansion state per parent in localStorage. Orphan
  subagents (parent absent from cache) hoist to a 'Orphan subagents' group.
- grid-view.js: each active session card now shows a stack of small pills
  for currently-running subagents, color-coded by subagentType, capped at
  5 with a '+N more' overflow. Listens on onSubagentSpawned/onSubagentCompleted.
- jsonl-viewer.js: when an inline-expanded subagent block represents a still-
  running agent, start an fs.watch via the new IPC and append streamed
  entries; show a small '● live' indicator until completion. Stops the
  watch on collapse or subagent-completed.
- style.css: minimal styles for new sidebar/grid/live elements, matching
  existing palette and font weights.
When Switchboard attaches to a session that already has many subagent
files on disk (e.g. a long-running session with 100+ Agent calls), the
first walk of detectSubagentTransitions treated every existing file as a
'first sighting' and emitted subagent-spawned for each. 30s later it
emitted subagent-completed for each. Hundreds of IPC events back to back
froze the renderer UI.

Distinguish bootstrap (first walk for this session) from steady-state.
On bootstrap, record every existing file in knownSubagents silently:
- files modified in the last 60s stay in the active lifecycle (could be
  mid-run, will eventually fire subagent-completed)
- older files are marked completed immediately with no IPC

Only files that appear AFTER the bootstrap walk fire subagent-spawned.
@JeanBaptisteRenard
JeanBaptisteRenard force-pushed the feat/subagent-observability branch from e893501 to a6210a6 Compare May 22, 2026 07:29
@JeanBaptisteRenard
JeanBaptisteRenard merged commit bd5aff2 into main May 22, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant