Repository navigation
Conversation
Draft-only prep. Propose surfacing in-conversation Task subagents (context-keeper,
code-reviewer, etc.) as nested sub-rows under their parent session's card, sourced
from ~/.claude/projects/<cwd>/<parentSessionId>/subagents/agent-<id>.jsonl (model,
tokens, type/desc, running-vs-done). No PID/session file, so still never a
top-level card. Also scopes correcting RFC 0003's now-inaccurate known-gap note
("only inline in parent transcript" -> separate subagents/ file on Claude Code 2.1.x).
Not implemented; left as a starting point to continue later.
Co-Authored-By: Claude <noreply@anthropic.com>
…we were parsing away Three layers the adapter could already reach and didn't: - Layer 0: sessions/<pid>.json carries name/nameSource/jobId/parkedJobId/ agent/entrypoint/version/startedAt. The jobId <-> parkedJobId pair is a file-backed lineage edge, stronger than RFC 0003's PPID walk. - Layer 1 (RFC 0004): projects/<cwd>/<sid>/subagents/agent-*.jsonl plus the .meta.json sidecar, which is where type/description actually live. - Layer 2 (RFC 0005): subagents/workflows/wf_*/ with journal.jsonl — the only source that makes running vs done a reading instead of an mtime guess — and the workflow script's own `export const meta`. Per agent: model, effort, real cumulative burn (input+output, the only additive figure), cwd, branch, last action, and the span from the transcript's first/last timestamp. The opening timestamp is persisted in the tracker because the reader tails by offset and would otherwise lose the head on the second pass. Honesty guards that cost real findings to get right: an interrupted agent is its own state (the harness writes the turn, so it is read, not inferred); a dead owner degrades to "" rather than to an invented "done"; a symlinked wf_* dir belongs to the session that owns the bytes, which dedups the parked pair and closes a symlink escape past the segment guard; and hostile sessionId/cwd now route through one path choke point. Co-Authored-By: Claude <noreply@anthropic.com>
… means something The card grows a block below its footer: one ◇ row per subagent, one ⧉ row per workflow with its description and phases, and one row per workflow agent with model, context, burn, span and state. Cards became variable-height in LIST, so CardHeightOf() is now the source of truth and model.go sums it instead of multiplying by CardHeight. A bg card whose own transcript is empty no longer reads as an empty card: it shows the burn aggregated from the tree hanging under it, in its own labelled block, never merged into the own-transcript reading. TreeLinked names the session the tree belongs to, including in GRID where there are no sub-rows to carry the attribution. The border animates a purple gradient while — and only while — a workflow agent is genuinely running per its journal. Liveness outranks selection, which moved to a marker in the header, because making the card under the cursor the one card that can never animate hid the effect exactly where it was wanted. Truecolor ramp with an ANSI-256 fallback, frame passed in so the render stays pure and testable. A settled workflow folds to its headline and description at rest, with any interruption promoted onto that line so a fold can never lose bad news; selecting the card still opens everything. J/K scroll inside a selected card, because a card taller than the viewport had an unreachable tail. Co-Authored-By: Claude <noreply@anthropic.com>
…nce claims Records what the three implementation rounds found on disk, including the parts that must stay "—" and why: the agent label and the per-phase progress are runtime-only (every .meta.json of every recent run, one of them mid-flight, carries nothing but agentType/spawnDepth, and journal.key is a one-way hash), and using the prompt's opening line as a label was tried and rejected because agents of one workflow share the preamble. Also corrects the claim in ADAPTER.md that a sidechain "exists only as isSidechain:true lines inside the parent's transcript". On 2.1.220 the parent transcript holds zero such lines — the data lives in separate files. Kept as a recorded lesson rather than a silent edit, same as the 0/204 fix in 0003. Co-Authored-By: Claude <noreply@anthropic.com>
Merges the unmerged browser branch, which forked from the same base as this one. No file overlaps: the web view lives entirely in internal/webserver/, plus the --serve/--addr flags in main.go. The RFC it shipped as 0004 collides with 0004-subagent-activity, which is already cross-referenced from ADAPTER.md, the README and code comments — so the web view is renumbered to 0006 in the following commit. The frontend is still a hand-written JS port of the pre-0004 BuildCards, so it renders none of the activity this branch added. Serving the Go-built cards is the next step. Co-Authored-By: Claude <noreply@anthropic.com>
Both branches independently claimed 0004. The subagent-activity RFC keeps the number: it is already cross-referenced from the README, ADAPTER.md, RFC 0005 and code comments, so moving it would break more links than it fixes. Co-Authored-By: Claude <noreply@anthropic.com>
The browser view had its own buildCards/sortCards in JavaScript, a second implementation of the Go join that had already drifted from the original. internal/webserver now calls cards.BuildCards / cards.Sort / cards.NestByParent - the exact pipeline ui.Model.orderedCards runs - and emits sorted, parent-before-child cards. The frontend became a paint layer, so it inherits delegated activity (subagent and workflow sub-rows, tree burn) for free. Card's JSON tags are now a public contract encoding the honesty invariant: a field whose zero means "nothing was read" is absent so the renderer paints a dash, and a field whose zero is a real reading (gates, token and cost figures, proc counts, depth) is always present. TestCardJSONContract pins both halves next to the struct. tool and sort moved to the query string because both have to be resolved server-side: the representative session that absorbs a tool's unattributable processes is picked among the filtered sessions, and NestByParent requires parent-before-child ordering. The raw Sessions and Usage arrays left the payload - they only fed the client-side join. Co-Authored-By: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Two things that turned out to be one thing.
Delegated activity (RFC 0004 + RFC 0005). The Claude adapter was parsing away session fields it already had on disk: subagents spawned via Task, multi-agent workflows, session lineage, entrypoint, agent type. Those now reach the cards, which render delegated work as sub-rows under the session that spawned it, with aggregated tree burn and a border that means something.
A browser view over the same board (RFC 0006).
aitop --serveexposes a read-only SPA. It shipped with its ownbuildCards/sortCardsin JavaScript, a second implementation of the Go join, and the copy had already drifted.internal/webservernow callscards.BuildCards/cards.Sort/cards.NestByParent, the exact pipelineui.Model.orderedCardsruns, and the frontend became a paint layer. Whatever the TUI gains, the browser gains with it, structurally, which is how the delegated sub-rows above showed up in the browser without being written twice.Contract
cards.Card's JSON tags are now public API, and they encode the honesty invariant:TestCardJSONContractpins both halves, and lives next to the struct so an edit that never runs the webserver's tests still trips it.toolandsortmoved to the query string, because both have to be resolved server-side: the representative session that absorbs a tool's unattributable processes is picked among the filtered sessions, andNestByParentneeds parent-before-child ordering. RawSessionsandUsageleft the payload; they only fed the join that no longer happens.Invariants held
Read-only, GET only, default bind 127.0.0.1. No new dependencies and no cgo:
internal/ui/panes/cardspulls lipgloss, already a dependency, and not the Bubble Tea program tree.Test
go build ./...andgo test ./...green on macOS.