Expand description
Offline session scanners - stateless filesystem helpers that read
transcripts from <config_dir>/projects/<project_key>/*.jsonl.
list_sessions- lists sessions, either for one project or all.get_session_messages- reads the full transcript for one session.
Session metadata (list_sessions) comes from an internal head +
tail lite read, so the fields it parses cost two 64 KiB reads
whatever the transcriptโs size. The worker tag is the exception and
is read in full: it can sit anywhere in the file and the last one
wins, so there is no window that settles it.
Re-exportsยง
use std::collections::HashMap;๐use std::collections::HashSet;๐use std::fs;๐use std::io::BufRead;๐use std::io::BufReader;๐use std::io::Read;๐use std::io::Seek;๐use std::io::SeekFrom;๐use std::path::Path;๐use std::path::PathBuf;๐use serde_json::Value;๐use unicode_normalization::UnicodeNormalization;๐use uuid::Uuid;๐use forge_primitives::FORGE_WORKER_TAG_PREFIX;๐use forge_primitives::SDKSessionInfo;๐use forge_primitives::SessionHistory;๐use forge_primitives::SessionMessage;๐use forge_primitives::SessionMessageKind;๐use forge_primitives::worker_tag;๐use forge_sdk::projects_dir_for;๐
Structsยง
- Block ๐
- One sidecarโs frames and the dispatch it ran as.
- Lite
Session ๐File - Head / tail snapshot of a session file - enough to recover all
SDKSessionInfofields without a full scan. Thetagfield is populated by a separate streaming line-scan because tag rows can appear anywhere in the file (start-of-file at spawn, mid-file via/newre-tag) and the head + tail windows miss both cases on large transcripts. - Session
TagCache - Carries the previous runโs tag scans into this one and collects what changed, so the whole catalog costs one store read up front and one store write at the end rather than a transaction per transcript.
- Session
TagScan - What a tag scan learned about one transcript, and how far into it the answer is known to hold.
- Sidecar
Link ๐ - A sidecarโs own meta: the dispatch its agent ran as, and the agent whose sidecar fired that dispatch.
- Window ๐
- One window of a transcript file: the bytes read and the byte they start at.
Enumsยง
- Workers
- Which worker sessions a listing may carry.
Constantsยง
- LIST_
SESSIONS_ ๐MAX_ CONCURRENT - Bounded-concurrency cap for
list_sessionsper-file lite reads. - LITE_
READ_ ๐BUF_ SIZE - Size of the head / tail byte buffer for lite metadata reads. The CLI constant - match exactly so the two implementations slice transcripts at the same boundary.
- MAX_
SANITIZED_ ๐LENGTH - ROWS_
PAST_ ๐CUT - How many rows past a pageโs own count a cut may step back over, so that it does not open on a result without its call.
- SIDECAR_
BUDGET_ ๐BYTES - How many bytes of sidecar frames one resume reads in total. A session can hold hundreds of sidecars and most of them are older than the window the conversation is cut to, so the read is bounded rather than whole (#1763).
- SPAN_
CAP_ BYTES - SPAN_
ROWS_ PER_ TURN - How many rows a pageโs own turn count may ask for.
- SPAN_
STEP_ BYTES - How many bytes of a transcript one paging pass reads before growing, and how wide a single window it takes may be.
- START_
REASONS ๐ - The removal reasons that mean the CLI TOOK the prompt, read off this
machineโs transcripts:
absorbed_mid_turn(pressed into the running turn),delivered_to_agent(handed over at its boundary), and the empty reason on rows written before the field existed. Any other reason did not start the prompt and draws no row. - SYSTEM_
ROWS_ ๐DRAWN_ ELSEWHERE - The
systemsubtypes whose row is not the conversationโs: the task lifecycle lands on its callโs row, the background-task and command lists feed their own surfaces, the handshake is not content, and a hook run draws from its attachment row. The client filters the same list (its ownSYSTEM_DRAWN_ELSEWHERE), because the read and the live path are one obligation - a subtype added here belongs there, and the other way round. - UNREAD_
TRANSCRIPT_ ๐COUNT_ NOTE - Tail shared by every
get_session_messagesbail. The compaction count these paths return is unknown rather than zero, and the Projects-pane row hides at zero, so โcount says 0 on a session I know compactedโ has no triage path unless each bail is greppable. - UNSERVED_
ROWS ๐ - Top-level rows the read does not serve, of two kinds: the transcriptโs own bookkeeping, which the CLI writes to disk and never streams, and the wire types that live only on the stream and have no durable row.
Functionsยง
- already_
kept ๐ - Whether this read has already kept a row under
uuid. - answered_
dispatches ๐ - The calls
rowanswers. - answers_
dispatch ๐ - Whether
rowis the tool result answeringdispatch. - block_
field ๐ - The
fieldof every content block ofkindinrow. - canonicalize_
path ๐ - Resolve a directory to its realpath and apply NFC normalisation.
Wraps the CLIโs
_canonicalize_path(falls back to the input, NFC-normalised, when the path canโt be canonicalised: most commonly because it doesnโt exist). NFC is essential on filesystems that donโt auto-normalise (Linux ext4, Windows NTFS) so decomposed inputs still hash to the CLIโs on-disk project-key layout. - carries_
a_ ๐result - Whether a row carries a tool result: the kind of row a cut may not land on, because the call it answers sits just above it in the page below.
- compact_
boundary_ ๐frame - The boundary row in the shape the wire sends.
- emit_
block ๐ - Append one block, with each child block inserted after the row that carries its dispatch.
- emit_
sidecar_ ๐tree - One ownerโs blocks, flattened in the order the work ran: a block emits at the row naming its dispatch, and a block no other names - its parent body was past the budget - follows the roots.
- extract_
command_ ๐name - Extract
<command-name>CMD</command-name>when present. - extract_
first_ ๐prompt_ from_ head - Extract the first meaningful user prompt from a JSONL head chunk.
Skips
tool_result,isMeta,isCompactSummary, slash-command messages (with command-name fallback), and the fixed-prefix skip patterns the CLIโs_SKIP_FIRST_PROMPT_PATTERNmatches. Truncates to 200 chars with an ellipsis. - extract_
json_ ๐string_ field - Extract the first occurrence of a JSON string field (
"key":"value"or"key": "value"). Scans bytes directly to survive partial tail reads; unescapes viaserde_jsononly when the value contains a backslash. ReturnsNonewhen the field is absent or unterminated. - extract_
last_ ๐json_ string_ field - Like
extract_json_string_fieldbut returns the LAST occurrence. - find_
bytes ๐ - Find the first byte offset where
needlebegins inhaystack. - fold_
subagent_ ๐sidecars - Insert each dispatchโs sidecar frames under the first row its chain answers. Appending them at the end would put them at the newest edge of the resumed window, ahead of the main rows.
- get_
session_ messages - Read the full transcript for one session.
- has_
a_ transcript_ row - Whether a transcript row carries this frame.
- hook_
outcome ๐ - The outcome the live frame reports for one persisted run record.
- hook_
output ๐ - What one persisted hook run printed, as a
hook_responseframe carries it. - is_
hook_ ๐attachment - Whether an attachment row records a hook run the live stream forwards.
- is_
queued_ ๐attachment_ row - Whether a transcript line is the attachment the CLI writes for a prompt queued mid-turn.
- is_
valid_ ๐uuid - True if
sis a canonical 8-4-4-4-12 hyphenated UUID. The length guard rejects the hyphenless / braced / URN forms thatUuid::try_parseotherwise accepts - session ids on disk are always the hyphenated form the CLI emits. - list_
sessions - List sessions. When
directoryisSome, scans that project dir; whenNone, scans every project directory underconfig_dirโsprojects/tree. A capped listing stats each candidate for its mtime, reads newest first on the tokio blocking pool (at most 16 at once), and stops once the rows the cap serves are in hand - a short batch is filled by the next, so the cap bounds the reads without shortening the listing. An uncapped listing (the boot scan) reads every candidate.workersdecides which worker-tagged rows may appear, and it lands before the cap: a listing is never shortened by rows it would not have carried. - live_
hook_ ๐event - The hook events whose runs the live stream forwards, and therefore the only ones a read serves as rows.
- messages_
from_ ๐rows - The rows a transcriptโs messages convert to, typed as the wire sends them
and stamped with
session_id. - missing_
boundary_ ๐facts - Which of the facts the kept boundary frame reads the row did not yield - the trigger, and the counts either side of the cut.
- owning_
dispatch ๐ - The dispatch whose row a sidecarโs frames belong under: the first dispatch in its chain the transcript answers.
- parse_
rfc3339_ ๐ms - Parse the CLIโs RFC-3339 timestamp (e.g.
2026-04-22T04:15:27.123Z) into Unix epoch milliseconds. Sub-millisecond precision is truncated. - parse_
session_ ๐info_ from_ lite - Build an
SDKSessionInfofrom a lite head/tail read. Skips sidechain transcripts and metadata-only sessions (no summary after all fallbacks). - parse_
session_ ๐messages - project_
dir_ ๐for - project_
key_ for_ directory - Map a directory path to the CLIโs on-disk project key. Canonicalises
the path first and then applies the CLIโs JS-style sanitisation
hash.
Nonedefaults to"."(the processโs current working directory). - queue_
remove_ ๐row - The
queue-operation removeline as the queued promptโs row, orNonefor any other line. - queue_
row_ ๐id - The rowโs id, minted from the one line an anchored read can reproduce.
- queued_
prompt_ ๐text - The prompt words an attachment rowโs synthesised message carries.
- queued_
start_ ๐row - The row a remove line draws, taking the attachment that named the press if one is waiting.
- read_
rows - Read the rows of
session_idโs transcript that sit strictly beforebelow, newest first, up torows_wantedof them. - read_
rows_ ๐with read_rowswith the pageโs own budget in the callerโs hands, so the growth, the cap and the search bound can be driven by a test without a transcript of the size the production budget is written for.- read_
session_ ๐info - read_
session_ info_ at - The one transcript at
path, read for its title and clock. - read_
session_ ๐info_ with - read_
session_ ๐lite - Open a session file, stat it, read at most
LITE_READ_BUF_SIZEbytes from the head and the same from the tail. For files smaller than the buffer,tail == head(single read). ReturnsNoneon any I/O error or for empty files. - read_
session_ ๐messages - read_
session_ ๐messages_ main_ thread get_session_messagesover the sessionโs own rows only: no sub-agent sidecars are opened or folded. The handoff brief takes this one, so it neither pays for the sidecar parse nor carries frames it does not read. A page read does not: a dispatch row draws its sidecar frames (#1763).- resolve_
anchor ๐ - Where a readโs window ends for a named anchor: the byte its row starts at, seeking when the cursor carries a byte and searching from the fileโs end when it does not.
- row_at ๐
- The row that starts at
at, for the anchored readโs verify. - sanitize_
path ๐ - Sanitise a path the same way the
claudeCLI does - non-alphanumerics become hyphens, and overlong paths are truncated with a base-36 hash suffix (matching JSโsString.prototype.hashCodetrick). - sanitize_
path_ ๐public - Crate-internal re-export of the path sanitiser - other modules need
it to derive the same on-disk project-key layout the CLI uses. Not
part of the public API; downstream consumers should call
project_key_for_directoryinstead. - scan_
tag_ ๐from - Return the value of the LAST
{"type":"tag"}rowโs"tag"field. Empty strings are filtered.Nonewhen no tag row is present or any read errors out. - session_
in_ ๐row - The session a transcript row belongs to. The wire spells it
session_id; a row the CLI wrote spells itsessionId. - session_
row ๐ - One line of a transcript as its row, or
Nonefor a line that is not one. - session_
transcript ๐ - The file a session id reads from: its projectโs directory when the caller places it, the first copy named after it otherwise.
- should_
exclude_ worker_ tag - True when
inforepresents a worker session: one whose transcript carries aforge:worker:<label>tag. - should_
skip_ ๐first_ prompt - Fixed-prefix counterpart to the CLIโs
_SKIP_FIRST_PROMPT_PATTERN. - simple_
hash ๐ - 32-bit integer hash to base-36, matching the CLIโs directory naming.
- subagent_
sidecars ๐ - The frames a sessionโs sub-agent sidecars hold, with each sidecarโs own dispatch and every metaโs chain link. The links are read for all sidecars, not only the ones inside the budget; the fold stamps the rows themselves.
- subagent_
sidecars_ ๐with_ budget subagent_sidecarswith the read budget given, so the cap is drivable at a size a test can build.- synthesize_
hook_ ๐frame - One persisted hook run as the live frame the chat folds.
- synthesize_
queued_ ๐command_ message - Build a
{"role":"user","content":[{queued_command}]}envelope from a JSONL attachment rowโsattachmentfield. Used during session replay to surface mid-turn queued inputs that claude persisted astype:"attachment"rows (which the scanner would otherwise skip). - tag_
and_ ๐project_ of - The last tag AND the project its row names, with the same cache and
read-error behaviour as
tag_of. A worker resume uses the project to tell this projectโs session from another projectโs in a directory both compose to. - tag_of ๐
- The last tag
pathโs transcript carries, with the read errorread_session_liteturns into โuntaggedโ handed back as one: a caller that has to tell an unreadable transcript from an untagged one cannot use the lite read. - tool_
use_ ๐ids - The calls made in
row. - transcript_
row ๐ - One transcript row as the sessionโs message, or
Nonefor a row that is not one. The flag says the row is a compaction boundary, which the read counts. - try_
read_ ๐dir - Open
dirfor directory iteration. NotFound is the expected case for the catalogโs projects/ tree on a fresh forge install and is silent; real I/O failures (perm denied, broken FS) log at warn so the user gets a triage signal rather than silently empty catalog reads. - unescape_
json_ ๐string - Unescape a JSON string value. No-op when there are no backslashes.
- window_
ending ๐ - Read up to
takebytes ending atend, and the byte before the window as well. - window_
rows ๐ - The rows a window holds, each with the byte it starts at.
- wire_
session_ ๐frame - A kept row carrying the session under the spelling the live frame sends.
Type Aliasesยง
- Sidecar
Read ๐ - The sidecar bodies the budget admitted, and every metaโs chain link.