Files
clide/docs/spikes/cc-team-internals-2.1.148.md
T
jpmschweitzerandClaude 3f2e5ad9a9
test / unit + widget + golden + a11y (push) Failing after 31s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 31s
spike T-134: Claude Code team/transcript internals (pinned to 2.1.148)
Findings note for the tmux agent-team work (epic T-132), validated from
real on-disk artifacts (42 past team configs, real team + subagent
transcripts, current-version .meta.json) plus a synthetic control-mode
test and the tmux manual — no live team run / quota needed.

Key results: teammates get tmux panes (config tmuxPaneId) and write
transcripts at <munged>/<sid>/subagents/agent-<hex>.jsonl + .meta.json;
tmux 3.6a has no %pane-died (use %window-close/%layout-change), and
polling list-panes -a is the reliable lifecycle baseline; the real risk
is identity linkage — pane/teammate (config: name@team, agentType,
%pane) joins to the transcript only via agentType (config <-> .meta.json),
ambiguous for same-type teammates, so T-139 needs a joinedAt/mtime or
lead-transcript tiebreaker.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-05-22 19:52:00 +02:00

5.3 KiB
Raw Blame History

Spike: Claude Code team / transcript internals (T-134)

Pinned to: claude 2.1.148, tmux 3.6a. These are undocumented, version-drifting internal contracts (per D-75) — re-validate on a CC bump.

Method: validated from real on-disk artifacts (42 past team config.jsons, real team + Task-tool subagent transcripts, .meta.json written by the current version) plus a synthetic tmux -L clide control-mode test and the tmux manual. No live team run was needed to answer the questions — the existing artifacts are conclusive and cost no quota.


Findings

1. Teammates get tmux panes; transcripts live under subagents/

  • Confirmed: across real teams, 42 teammate members carry a populated tmuxPaneId (e.g. %5, %120); the lead's tmuxPaneId is "". So teammates spawn as panes and the config records the pane id.
  • Teammate transcript location: ~/.claude/projects/<munged-cwd>/<session-id>/subagents/agent-<hex>.jsonl, with a sibling agent-<hex>.meta.json. <munged-cwd> = absolutePath.replaceAll('/','-') (leading - kept). Note: a team's <session-id> dir held 0 top-level *.jsonl and 44 subagents/agent-*.jsonl — teammate content is the subagent files, not top-level sessions.
  • Each subagent record carries agentId (the hex, e.g. a2a3530 — matches the filename), sessionId (the dir), isSidechain: true, slug (a random codename), type (user/assistant/…). This is the same JSONL schema TranscriptReader (T-136) already parses.

2. Lifecycle signal — control mode vs. polling

  • tmux 3.6a control-mode notifications (from man tmux): %window-add, %window-close, %window-pane-changed, %layout-change, %unlinked-window-add, %unlinked-window-close, %session-changed, %sessions-changed, %pane-mode-changed, %exit, %output/%extended-output, … There is NO %pane-died (an-idea.md assumed one). Pane/teammate exit surfaces via %window-close / %layout-change / %window-pane-changed.
  • Driving control mode from code is finicky: a tmux -L clide -C attach captured %session-changed/%exit but the attach exited early under non-interactive Bash; reliably consuming the stream needs a long-lived managed client.
  • Polling tmux -L clide list-panes -a -F '...' works and is reliable (validated: it enumerated panes with pane-id/pid/title). Recommendation for T-139: use polling as the baseline lifecycle source; treat control mode as a later optimization.

3. Team config schema (~/.claude/teams/<team>/config.json)

  • Top keys: name, description, createdAt, leadAgentId, leadSessionId, members[].
  • Member keys: name, agentId (=<name>@<team>), agentType, model, cwd, joinedAt, subscriptions, tmuxPaneId. (Some runs also carry backendType/isActive/mode — optional, version-varying.) The lead member has empty tmuxPaneId.

4. ⚠️ Identity linkage — the real risk for T-139

The pane/teammate identity in config does NOT share a key with the transcript file:

  • Config: {name: gestalt, agentId: gestalt@control-interaction, agentType: gestalt, tmuxPaneId: %120}.
  • Transcript: agent-<hex>.jsonl (records agentId = <hex>, slug = <random>) + agent-<hex>.meta.json = {agentType, description}.
  • The only join key is agentType (config.member.agentType ↔ .meta.json.agentType). This is unambiguous only when teammates have distinct agentTypes (e.g. control-interaction: gestalt/ozzie/tyre/…). For same-type teammates (e.g. art-requirements: 3× general-purpose) agentType is ambiguous → need a disambiguator: spawn order / joinedAt timestamp vs. file mtime, or parse the lead transcript's teammate-spawn records (likely carry both ids). T-139 must handle this; recommend: join on agentType, fall back to ordering by joinedAt/mtime, and investigate the lead transcript's spawn events for an explicit hex↔name link.

5. Resolved elsewhere

  • Session-id discovery (check 5): Claude doesn't expose its session id; pick newest *.jsonl by mtime — already implemented in TranscriptReader (T-136).
  • Paste (check 4): scope to @path file references over send-keys (text channel). Clipboard image paste needs an interactive display ($DISPLAY) and is out of scope for headless validation; decide the composer's image handling in T-138/T-006.

Recommendations for the team tickets

  • T-139 (observer): poll list-panes -a for lifecycle; read team config.json for the roster
    • pane ids; tail teammate transcripts at <munged>/<sid>/subagents/agent-<hex>.jsonl; resolve pane→transcript via agentType join with a joinedAt/mtime tiebreaker (and confirm whether the lead transcript gives an explicit link). Isolate all of this behind the one module (D-75).
  • Re-validate on any CC version bump — key off the transcript version field.

Not done

  • A live, real-time team run (watching a pane + transcript appear live) was not executed — the static artifacts answer every question and a live run costs quota without adding certainty. The one item a fresh run would pin precisely: whether the lead transcript records an explicit teammate hex↔name mapping (would remove the same-type ambiguity). Worth a short observed run when T-139 is implemented.