feat(terminal): Log view — transcript live tail (main + subagent transcripts) - #5
Open
thanhsmind wants to merge 2 commits into
Open
thanhsmind wants to merge 2 commits into
thanhsmind wants to merge 2 commits into
Conversation
A second, semantic observation source for Claude Code panes: tail the agent's own on-disk session transcript (~/.claude/projects/<encoded-cwd>/ *.jsonl) with a client-held byte cursor, so every command, output, thinking line and subagent action appended between polls arrives — nothing scrolls away unseen between 1.5s ticks, unlike the pane.read pixel path. - src/transcript/: resolve (cwd -> project dir -> newest session file), gap-free tail (complete lines only, partial appends wait), defensive per-record rendering (unknown shapes pass through raw), cursor validated against path escape. Open = EOF: no retroactive history by design. - GET /api/panes/:pane/activity: stateless like every route; cursor round-trips through the client; gateway stores nothing (never-store rule untouched). available:false when a pane has no transcript. - web: "Log" footer toggle swaps the xterm screen for an append-only <pre> with a client-owned 200-line ring and stick-to-bottom; screen view, PageUp history and input sheets untouched. - drive-by: demo_config() now builds JSON via serde_json — the Windows temp dir's backslashes made --demo panic on invalid JSON escapes. Plan: plans/260805-1500-transcript-as-history-source/plan.md (executed directly at user request, outside the bee flow). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Field feedback on the first Log view build: opening to an empty pane read as "still limited", and subagent work never showed up. - Open now backfills: render the last 512 KiB of the session tail and land with the client's 200-line ring already full, cursor at the end of the last complete line so the next poll continues seamlessly. - Subagents: Claude Code ≥2.1.x writes Task/teammate activity to <session-id>/subagents/agent-*.jsonl — the main file's isSidechain is always false (verified against 2.1.222) — so the watch set is now the main file plus every subagent transcript, merged by record timestamp, subagent lines prefixed with ⑂, files born mid-watch tailed from byte 0. Cursor becomes a ;-joined multi-entry set; v1 cursors still parse. - Caps loosened: tool output 20→40 lines, text blocks 40→80. Co-Authored-By: Claude Fable 5 <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
A second, additive observation surface for Claude Code panes: a Log toggle in the terminal view that tails the agent's own on-disk session transcript instead of screenshotting the terminal grid.
The existing screen view polls
pane.read— an 80-line ANSI snapshot every 1.5s — so anything that scrolls past between ticks is unrecoverable, and there is no concept of a tool call, command output, or subagent. The transcript (~/.claude/projects/<encoded-cwd>/…) is append-only and written by Claude Code itself, so a byte cursor over it is gap-free by construction: every command with its full output, thinking, edits, and subagent activity between two polls arrives, regardless of poll interval. This is thetranscript-as-history-sourcecandidate from the distillery (collie,docs/distillery/porting-log.md:104), finally built.How
src/transcript/(new): resolve pane → transcript via the snapshot'sforeground_cwd ?? cwd(D5 precedence) and Claude Code's project-dir encoding; gap-free tail reading complete lines only (a mid-append partial line waits for the next poll); defensive per-record rendering — unknown record shapes pass through raw, nothing is silently dropped; cursor validated against path escape.<session-id>/subagents/agent-*.jsonl, not asisSidechainrecords in the main file (verified live against 2.1.222). The watch set is therefore multi-file: main session + every subagent transcript, merged by record timestamp, subagent lines prefixed⑂, files born mid-watch tailed from byte 0.GET /api/panes/:pane/activity(new route): stateless per request like every existing route — the (opaque, multi-entry) cursor round-trips through the client; the gateway stores nothing, keeping the never-store rule (src/store/mod.rs) intact. Panes without a transcript answeravailable:false(data, not an error).<pre>with a client-owned 200-line ring and stick-to-bottom (release on scroll-up). Opening backfills the tail so the ring lands full. Screen view, PageUp history, keys/reply sheets are untouched.demo_config()now builds its JSON via serde_json — the Windows temp dir's backslashes made--demopanic on invalid JSON escapes.Scope & limits
… (+K lines)), never silent.plans/260805-1500-transcript-as-history-source/plan.md.Testing
available:false).doctor::checks::agent_presets_fix_seeds…, fails on a clean checkout ofmaintoo — pre-existing, unrelated).🤖 Generated with Claude Code