Repository navigation
fix(claude-code): open long Claude transcripts a page at a time - #2428
Conversation
A Claude session file over the 50 MB read limit failed to open with "is larger than 50 MB". Such a file is now read as its first 4 MB, which says whose conversation it is, and its last 40 MB, which holds its latest turns, through two new declared read processes. The transcript reports more turns when it was cut. Session files are only read, and the shared reader keeps its limit, timeout and protections. Refs AIDA-2457 Co-authored-by: Martha <73923046810b68ae182000e74ef7c444383a907df20f81f2ba1008870a6f45a1@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: John Tennant <[email protected]>
Co-authored-by: Martha <73923046810b68ae182000e74ef7c444383a907df20f81f2ba1008870a6f45a1@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: John Tennant <[email protected]>
A session over 50 MB was read as its first 4 MB and last 40 MB, so one whose latest turns span more than that showed fewer of them. It is now read in 32 MiB pages from its end until it has the latest turns or its start, as the Codex transcript reads a turn's items a page at a time. Co-authored-by: Martha <73923046810b68ae182000e74ef7c444383a907df20f81f2ba1008870a6f45a1@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: John Tennant <[email protected]>
Records main as a parent; 5560670 brought in its changes without one. Signed-off-by: John Tennant <[email protected]> Co-authored-by: Martha <73923046810b68ae182000e74ef7c444383a907df20f81f2ba1008870a6f45a1@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <[email protected]> * origin/main: feat(solo): let viewers join read-only spaces (#2301) [3/5] Add protection to the Claude harness plugin (#1878) fix(settings): keep the bottom padding on long sections (#2361) fix(mermaid): cap diagram output size (#2231) feat(agents): give plugin agent types the Buzz side of a turn (#2364) feat(plugins): pin buzz://plugin-install links to a path and commit (#2315) feat(plugins): tint currentColor SVG page icons like host icons (#2314) feat(notifications): add a soft notification sound (#1536) feat(agents): let agents propose a profile picture (#2267) fix(plugins): default reminders and workflows off for fresh installs (#2291) Show all reactors in compact, separate emoji capsules (#2179) fix(panels): remember page split widths per workspace (#2264) # Conflicts: # src/bundled/claude-code/manifest.json
kalvinnchau
left a comment
There was a problem hiding this comment.
🤖 One resource-bound defect remains in large transcript loading.
A session over 50 MB with fewer turns than the limit read every page, holding the whole file and reparsing it after each page. Stop after two 32 MiB pages and report the older turns as more. Co-authored-by: Martha <73923046810b68ae182000e74ef7c444383a907df20f81f2ba1008870a6f45a1@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: John Tennant <[email protected]>
Co-authored-by: Martha <73923046810b68ae182000e74ef7c444383a907df20f81f2ba1008870a6f45a1@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: John Tennant <[email protected]>
Co-authored-by: Martha <73923046810b68ae182000e74ef7c444383a907df20f81f2ba1008870a6f45a1@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <[email protected]> * origin/main: test(agents): refuse a real relay workflow mention in the harness kit (#2444) fix(agents): catch up every event watch on the kinds it watches (#1852) Keep local artifact collections current (#1507) feat(members): add several people to a chat in one write (#2010) Signed-off-by: John Tennant <[email protected]>
kalvinnchau
left a comment
There was a problem hiding this comment.
🤖 One transcript truncation issue remains.
A large session read to its page budget can keep fewer than 50 turns. Turns merged from the conversation's other sessions that are older than its first kept one would then show around the gap, so they are left, and the notice gives the count shown rather than promising 50. Co-authored-by: Martha <73923046810b68ae182000e74ef7c444383a907df20f81f2ba1008870a6f45a1@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: John Tennant <[email protected]>
Co-authored-by: Martha <73923046810b68ae182000e74ef7c444383a907df20f81f2ba1008870a6f45a1@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: John Tennant <[email protected]>
loganj
left a comment
There was a problem hiding this comment.
🤖 Larry and Auto: an independent adversarial review of 5efb784. Source review only, plus targeted probes: Auto ran vitest run src/bundled/claude-code src/buzz-mcp at this head (20 files, 689 tests pass) and two throwaway probe tests; Larry checked the read-page dd/base64 command and its missing-file error on macOS. No typecheck or full app suite run.
The page stitching is correct: it splits only at 0x0A, so no decode runs mid-character, and the held-back partial line is joined back without loss or duplication. A file under 50 MB keeps the whole-file path, and one from 50 MB to 64 MiB is read whole in two pages with cut false. The read-page process adds no power the manifest's claude-sh (bash -c) does not already have, and its arguments are quoted.
Must fix (error): a cut window that starts at a prompt is labelled "New session" (inline at readTranscript).
Everything else is advice, a question or a preference. Approving on the understanding that the newSession fix and its test land before merge.
Notes outside the diff:
- question: two other whole-file reads of the same session
.jsonlstill fail above 50 MB: usage (usage.ts:274, throughhost.readFileandMAX_READ_BYTES), and the protected history reader (runtime.ts:1053, called from the hook atclaude.ts:909), which makes every hook of a protected session over 50 MB fail. Both need the whole file, so paging from the end is not their fix. Fine as known follow-ups; worth a line in the PR body. - convention: the branch conflicts with main (
mergeStateStatusDIRTY) intranscript.tsandtranscript.test.ts, after #2088 changed the transcript readers andstartedFor. Needs a rebase. - advice: tests are missing for
newSessionon a cut window, a record longer than the page budget, andreadSessionTitlepaging.
| return { text, cut: false, start: async () => text }; | ||
| } catch (error) { | ||
| signal.throwIfAborted(); | ||
| if (!/larger than 50 MB/.test(error instanceof Error ? error.message : "")) |
There was a problem hiding this comment.
advice (perf, simplicity): check the size before the whole-file read.
For every session over 50 MB, this first try streams about 50 MB through base64 and buffers about 67 MB of text before readFile kills it, and only then pages. With wc, two 32 MiB pages and start(), that is about 120 MB read per large session. Spawning size first and paging only above READ_LIMIT removes the wasted read, and removes the coupling to the larger than 50 MB error text.
A simpler alternative, given PAGE_BUDGET = 2: one tail -c 48M "$1" | base64 read that drops the first partial line would replace size, the page loop, the rest stitching and enough, at the cost of a fixed 48 MiB window and no early stop after one page.
Also, for sessions other than the saved one, running start()/startedFor before paging the tail would avoid reading 64 MiB of a file that turns out not to match.
There was a problem hiding this comment.
🤖 Leaving this as it is for now. Checking the size first adds a wc spawn for every session, and most sessions are small, so the wasted read only happens for the rare session over 50 MB. The tail -c alternative is tempting, but it gives up stopping early after one page. Happy to switch if you'd rather drop the coupling to the error text.
| path: string, | ||
| signal?: AbortSignal, | ||
| protection?: ProcessProtection, | ||
| process = protection ? "read-protected" : "read", |
There was a problem hiding this comment.
convention: readFile now takes six positional parameters, and transcript.ts:319 passes undefined for protection to reach process. An options object for protection, process and args would read more clearly.
There was a problem hiding this comment.
🤖 Agreed it reads better as an options object. I'd rather do that in a follow-up, because readFile has callers outside this plugin.
A paged window that starts at a prompt was labelled "New session", and a cut session that kept no turns let older sessions' turns through with a gap. The notice also gets a singular form and says when the latest turn is too large to show. Also stops the size process on abort and finishes the readSession doc. Co-authored-by: Martha <73923046810b68ae182000e74ef7c444383a907df20f81f2ba1008870a6f45a1@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: John Tennant <[email protected]>
Keeps main's sender names for prompts in the paged transcript. Co-authored-by: Martha <73923046810b68ae182000e74ef7c444383a907df20f81f2ba1008870a6f45a1@buzz.block.builderlab.xyz> Co-Authored-By: Claude Opus 5.5 <[email protected]> Signed-off-by: John Tennant <[email protected]>
* origin/main: fix: exclude muted channels from sidebar unread scroll indicators (#2335) fix(claude-code): open long Claude transcripts a page at a time (#2428) feat(solo): share chats as view only (#2375) fix(inbox): show Solo responses under All, read live replies in the open conversation, describe toolbar badges (#2275) AIDA-2434: Show saved teams in mentions (#2339) AIDA-2455: Restore channel scrollbar dragging beside threads (#2436) feat(agent-protection): show the owner why a protection provider denied input (#2105) fix(search): show slow lookups beside their section headings (#2442) Align Bestie DM layout and unread state; speed up thinking shimmer (#2418) Send Claude, Pi and Goose history as exact records (#2088) fix(agent-activity): align the stopped note and show it after the agent's reply (#2441) fix(agents): stop orphaned Attention commands and prevent duplicate runs (#2448) Signed-off-by: Gil Birman <[email protected]> Co-authored-by: Claude <[email protected]> # Conflicts: # src/app/shell/PageNavigation.tsx
) ## Why Bug fix. Opening a Codex agent's transcript can fail with "Could not read the Codex session: Codex output frame is too large". The transcript asked Codex for each turn in one `thread/turns/list` response with every item (`itemsView: "full"`). One long turn can exceed `AppServer`'s 4 MiB frame bound, and that closes the connection and fails the whole transcript, including every turn that would have fit. This happened on a real agent conversation: one of its 28 matching threads had a 467-item turn that arrived as a single 4.25 MiB frame, although no item in it was larger than 34 KB. ## What The transcript lists turns without their items (`itemsView: "notLoaded"`), then reads each displayed turn's items through `thread/items/list`, 50 per request. Frames are now bounded by a page of items instead of a whole turn. Displayed turns, item order and the 4 MiB bound itself are unchanged. A page of items that still exceeds the bound (50 items averaging over 80 KiB) is read again at half the size on a fresh app-server, from the same cursor, and the rest of the transcript keeps the smaller size, so it pays that reopen chain once rather than once per turn. Item cursors name a position in the thread's rollout, so they work on a new process and at any limit. Only a single item over 4 MiB still fails the transcript, as before. Pages start at 50 items so a long conversation needs few requests (12,018 items across the 28 threads above). This is the Codex half of a matching pair. [#2428](#2428) fixes the same failure for Claude, where a session file over 50 MB could not be read, by reading it a page at a time from its end. ## Validation - A new regression test reads one turn of 100 commands, 4.4 MiB as a single frame. It fails on `main` with "Codex output frame is too large" and passes on this branch, which reads it in two pages of 50 items. A second test reads 40 items of 200 KiB, where pages of 50 and 25 are over the bound: it reads them again at 25, then 13, on fresh app-servers and shows all 40. - Against Codex 0.166.0's real app-server, the paged items for the 467-item turn were identical to its `itemsView: "full"` items. Replaying this branch's read sequence over all 28 threads read 12,018 items in 540 requests and 1.2 s, with a largest frame of 1.33 MiB. - On a fresh app-server process, a cursor from another process with a smaller limit returned exactly the next items of the 467-item turn. --------- Signed-off-by: John Tennant <[email protected]> Co-authored-by: Damon <8a08290d889f1c68921542bfe9631d4cd671be9bea5f1114951f386819e4c10a@buzz.block.builderlab.xyz> Co-authored-by: Martha <73923046810b68ae182000e74ef7c444383a907df20f81f2ba1008870a6f45a1@buzz.block.builderlab.xyz> Co-authored-by: Claude Opus 5.5 <[email protected]>
…-nip-fi * origin/main: feat(inbox): preview recent Inbox activity when hovering the sidebar row (#2347) Add collapsible Solo and Team sidebar sections (#2296) fix(codex): open long Codex transcripts a page of items at a time (#2259) Keep Solo model and effort choices per chat (#2342) feat(sidebar): smooth channel reordering with bounded motion (#2108) Connect legacy agents from DMs and channel mentions (#2423) fix: exclude muted channels from sidebar unread scroll indicators (#2335) fix(claude-code): open long Claude transcripts a page at a time (#2428) feat(solo): share chats as view only (#2375) # Conflicts: # src/app/shell/PrimarySidebar.tsx
…-clone-auth-ab8b97 * origin/main: (38 commits) feat(identity): decide a missing backup choice from community membership (block#2378) Offer Builderlab decisions in FI builds (block#2227) feat(inbox): preview recent Inbox activity when hovering the sidebar row (block#2347) Add collapsible Solo and Team sidebar sections (block#2296) fix(codex): open long Codex transcripts a page of items at a time (block#2259) Keep Solo model and effort choices per chat (block#2342) feat(sidebar): smooth channel reordering with bounded motion (block#2108) Connect legacy agents from DMs and channel mentions (block#2423) fix: exclude muted channels from sidebar unread scroll indicators (block#2335) fix(claude-code): open long Claude transcripts a page at a time (block#2428) feat(solo): share chats as view only (block#2375) fix(inbox): show Solo responses under All, read live replies in the open conversation, describe toolbar badges (block#2275) AIDA-2434: Show saved teams in mentions (block#2339) AIDA-2455: Restore channel scrollbar dragging beside threads (block#2436) feat(agent-protection): show the owner why a protection provider denied input (block#2105) fix(search): show slow lookups beside their section headings (block#2442) Align Bestie DM layout and unread state; speed up thinking shimmer (block#2418) Send Claude, Pi and Goose history as exact records (block#2088) fix(agent-activity): align the stopped note and show it after the agent's reply (block#2441) fix(agents): stop orphaned Attention commands and prevent duplicate runs (block#2448) ... Signed-off-by: damienrj <[email protected]>
* origin/main: (38 commits) fix(browser): load scheme-less address input over https, falling back to http (#2467) fix(identity): stop one-click key unlinks and show the linked backed-up key (#2486) fix(test): observe coordination transition events (#2297) fix(profiles): keep the next view's profile reads through a shrink (#2395) fix(channels): show Add and Send message errors above the Manage members list (#2421) fix(threads): keep reply hooks off agent activity bubbles (#2422) fix(channels): offer only Copy link in a not-joined preview's sidebar actions (#2425) test: scope row menu placement checks to active section rows (#2493) feat(relay): detach channel windows to a point in history (#2042) feat(identity): decide a missing backup choice from community membership (#2378) Offer Builderlab decisions in FI builds (#2227) feat(inbox): preview recent Inbox activity when hovering the sidebar row (#2347) Add collapsible Solo and Team sidebar sections (#2296) fix(codex): open long Codex transcripts a page of items at a time (#2259) Keep Solo model and effort choices per chat (#2342) feat(sidebar): smooth channel reordering with bounded motion (#2108) Connect legacy agents from DMs and channel mentions (#2423) fix: exclude muted channels from sidebar unread scroll indicators (#2335) fix(claude-code): open long Claude transcripts a page at a time (#2428) feat(solo): share chats as view only (#2375) ...
Why
Bug fix (AIDA-2457). Opening a long Claude agent's transcript fails with "Could not read the Claude session: .//.jsonl is larger than 50 MB". The plugin read each session file whole through the shared
readFile, which caps a read at 50 MB, and long Claude sessions grow past that. One real agent session is 152 MB.What
A session too large to read whole is read a page at a time from its end, 32 MiB per request, until it has the transcript's latest 50 turns, reaches the file's start or has read two pages. Reads are now bounded by a page, and a session's text by two pages (about 64 MiB), instead of a whole session. Displayed turns, their order and the 50 MB bound itself are unchanged, and sessions under 50 MB read exactly as before.
size(wc -c) andread-page(ddof whole MiB blocks, printed as base64).readFiletakes an optional process and arguments and keeps its limit, timeout and protections.more, and the session's first 4 MiB still decide whose conversation it is.This is the Claude half of a matching pair. #2259 fixes the same failure for Codex, where one long turn exceeded app-server's 4 MiB frame, by reading each turn's items a page at a time.
Validation
mainit fails with "large.jsonl is larger than 50 MB". On this branch it shows both turns, with the reply whole.more.more.read-pagescript returned byte-identical pages of a real 152 MB session (cmpagainsttail | head), returned a 17 MiB final page at its end, and failed withNo such file or directoryfor a missing file. The file's sha256 matched before and after.Screenshots
Activity tab opening a 55.5 MB session
🤖 Generated with Claude Code