Skip to content

feat(claude): session lineage (kind badge + spawned-by nesting) - #2

Merged
grippado merged 3 commits into
mainfrom
feat/session-lineage-spawned-by
Jul 10, 2026
Merged

grippado merged 3 commits into
mainfrom
feat/session-lineage-spawned-by

Conversation

@grippado

Copy link
Copy Markdown
Owner

What

Surface where a spawned Claude Code session came from. When one session launches
others as real background processes (worktree mutirões, detached claude -p
runs), they used to land as unrelated cards. This adds honest lineage:

  • SessionInfo.Kind (bg / interactive): verbatim from the kind key already
    present in ~/.claude/sessions/<pid>.json, previously read and discarded.
  • SessionInfo.ParentPID: the on-board session that spawned this one, resolved by
    a bounded gopsutil PPID walk (cap 40 hops) to the first ancestor that is itself
    a tracked session. A root or orphan stays 0. Never fabricated.
  • UI: a [bg] / [interactive] badge, a spawned by <parent> line (only when the
    parent is actually a card on the board, otherwise an honest fallback), and
    children indented under their parent in list view, at unchanged card height.
    --demo gains a real root plus two children so the lineage renders.

Implements RFC 0003.

Why it stays honest

  • No new file I/O: kind parses an already read field; the PPID walk uses the
    same gopsutil category as the existing daemon scan. No new dependency, no new
    credential surface.
  • In-process Task subagents (sidechains) still never surface as cards: they have
    no sessions/<pid>.json of their own. Documented as a structural known gap in
    the adapter's ADAPTER.md, stated without any fragile transcript count.

How it was built

Driven through the repo's own /aitop-enhance flow, with the specialized agents
in hand off: audit gate, pattern scout, adapter engineer, test engineer, UI
integrator, blocking re audit, docs scribe. The run is recorded as
Case study 0001, including the moment
the honesty gate caught a fabricated statistic written into the RFC prose itself,
and the fix that stated the guarantee structurally instead.

Tests and verification

Faked Reader plus faked ppid hook cover: kind parse, kind absent to empty, walk
through untracked ancestor to the tracked parent, orphan to 0, self reference
guard, and the hop cap (cycle run in a goroutine so a non terminating walk would
hang rather than pass). go build, go vet, and CGO_ENABLED=1 go test -race ./...
all green. --json --demo confirms the fields serialize.

Follow up (out of scope here)

The plain --once text snapshot does not yet show kind / parent_pid (only the
JSON snapshot and the TUI cards do). A short /aitop-enhance can close that parity
later.

🤖 Generated with Claude Code

grippado and others added 3 commits July 9, 2026 22:31
Propose showing where a spawned (kind:bg) Claude Code session came from:
add SessionInfo.Kind + ParentPID (both already observable on disk), and a
UI that badges kind and prints "▸ spawned by <parent>" under the parent.

Honest naming (not "subagent"): an in-process Task subagent has no
sessions/<pid>.json of its own — it exists only as isSidechain:true lines
inside its parent's transcript — so it can never surface as a card. Stated
structurally (aitop's cards come exclusively from sessions/<pid>.json, none
ever a sidechain), with no fragile transcript count.

Co-Authored-By: Claude <noreply@anthropic.com>
Surface where a spawned Claude Code session came from, using signals already
on disk. Adds two honest SessionInfo fields:

- Kind ("bg" | "interactive"): verbatim from the session file's `kind` key,
  previously read-and-discarded. Empty for adapters with no equivalent.
- ParentPID: the on-board session that spawned this one, resolved by a bounded
  gopsutil PPID walk (maxParentWalkHops=40) to the first ancestor that is
  itself a tracked session; 0 = a root / no visible parent. Never fabricated.

UI: a [bg]/[interactive] badge, a "▸ spawned by <parent>" line (only when the
parent is actually a card on the board, else an honest fallback), and children
indented under their parent in list view — at unchanged card height. --demo
gains a real root + two children so the lineage renders.

No new file I/O (kind parses an already-read field; the walk uses the same
gopsutil category as the existing daemon scan), no new dependency, no new
credential surface. In-process Task subagents (sidechains) still never surface
as cards — they have no sessions/<pid>.json of their own — documented as a
structural known gap in the adapter's ADAPTER.md.

Implements RFC 0003. Faked-Reader + faked-ppidOf tests cover kind parse,
kind-absent, walk-through-untracked-ancestor, orphan→0, self-reference, and
the hop cap. go build / go vet / go test -race all green.

Co-Authored-By: Claude <noreply@anthropic.com>
…ture

First worked record of /aitop-enhance driving a full feature end to end
through the specialized agents (audit → scout → engineer/test → re-audit →
docs). Captures the moment the honesty gate caught a fabricated statistic the
author had written into the RFC prose ("0/204 transcripts"), and how the fix
was to state the guarantee structurally instead of with a fragile count.

Links the case study from agentic-orchestration.md.

Co-Authored-By: Claude <noreply@anthropic.com>
@grippado
grippado marked this pull request as ready for review July 10, 2026 01:52
@grippado
grippado merged commit 22f4f3f into main Jul 10, 2026
1 check 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