feat: machine-readable export surface for sessions and checkpoints#1144
Merged
alishakawaguchi merged 8 commits intomainfrom May 7, 2026
Merged
feat: machine-readable export surface for sessions and checkpoints#1144alishakawaguchi merged 8 commits intomainfrom
alishakawaguchi merged 8 commits intomainfrom
Conversation
Expose the rich data Entire already captures as a stable, supported CLI contract for external consumers (Baton, eval pipelines, the session-handoff skill) so they no longer parse internal storage: - entire session info <id> --transcript / session current --transcript stream the live raw agent transcript bytes to stdout. JSON envelopes remain metadata-only. - entire checkpoint explain --json emits a metadata-only envelope: list view when no target is given, single-checkpoint envelope (with per-session metadata read via V2 ReadSessionMetadata) when targeted. Transcript bytes are never embedded. - entire checkpoint explain <id> --transcript streams the normalized compact transcript (V2 transcript.jsonl on /main); --raw-transcript keeps the per-agent raw bytes. - --session-index N selects a session within a multi-session checkpoint for --transcript / --raw-transcript (default: latest). The legacy raw-transcript dispatch silently ignored the index, so the cobra fork now routes --raw-transcript through the export path whenever --session-index is explicit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Entire-Checkpoint: db502c03f98b
Codex/Claude reviews of the prior commit flagged correctness gaps in the new machine-readable export modes. Fix them: - Positional commit-SHA fallback. `explain --json <sha>` and `--transcript <sha>` failed when the positional didn't match a checkpoint prefix; now falls through to commit-ref resolution like the prose `runExplainAuto` does, and the prefix lookup also retries after a remote metadata fetch on miss. - JSON envelope is lossless. Per-session metadata read failures now surface an explicit `error` field rather than silently producing a stub entry, and the v1 fallback uses `GitStore.ReadSessionMetadata` (metadata-only) instead of `ReadSessionContent`, which used to fail on v1 checkpoints whose raw transcript had been pruned. List-view JSON now propagates non-context errors (`fetch failed` is no longer indistinguishable from `[]`). - Cancellation actually works. `streamTranscriptToStdout` wires `<-ctx.Done()` to a goroutine that closes the file, so Ctrl-C on a multi-MB transcript unblocks the read promptly instead of running to EOF. - Live-transcript snapshot is shape-clean. The trailing partial line (from an agent mid-write) is trimmed so consumers never see a truncated JSONL record. - User-visible errors. `session info|current --transcript` now prints the cause to stderr before returning SilentError; previously the silent path exited with no message. - Distinct sentinel for empty checkpoint. `resolveSessionIndex` returns a new `errCheckpointHasNoSessions` for the empty-Sessions case so callers using `errors.Is(err, ErrCheckpointNotFound)` for UX no longer give the wrong diagnosis. - Internal cleanup. Extracted `matchCheckpointPrefixWithRemoteFallback` shared by the prose and export paths. Replaced the `(jsonOutput, transcriptOutput bool)` pair with a `sessionOutputMode` enum so the trichotomy is total. The error message for `--raw-transcript` without a target now references `--raw-transcript` instead of `--transcript`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 4103be403127
Adds the metadata-only JSON envelope to the session list view, sharing the exact same per-entry shape that `session info --json` and `session current --json` already emit. Always emits a valid array (`[]` for empty) so consumers can pipe through `jq` without special-casing "no sessions". Closes the last gap from #1125: external tools (Baton, eval pipelines, the session-handoff skill) can now enumerate sessions across worktrees without globbing `.git/entire-sessions/*.json` directly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 3f985842651a
Contributor
There was a problem hiding this comment.
Pull request overview
Adds an additive, machine-readable CLI surface for exporting session and checkpoint metadata and streaming transcript bytes, enabling downstream tooling (handoff/eval pipelines) to consume Entire data without parsing internal storage.
Changes:
- Introduces
--jsonlist output forentire session list, and--transcriptstreaming forentire session info/entire session current. - Adds
entire checkpoint explain --json(metadata-only envelope) and--transcript/--raw-transcript --session-indextranscript streaming paths via a new export implementation. - Refactors checkpoint-prefix matching into a shared
matchCheckpointPrefixWithRemoteFallbackhelper and exportsstrategy.ResolveTranscriptPathfor non-strategy callers.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| cmd/entire/cli/strategy/resolve_transcript.go | Exposes an exported wrapper for transcript-path re-resolution so CLI commands can safely follow agent transcript relocations. |
| cmd/entire/cli/sessions.go | Adds transcript streaming helper, session list JSON output, and a total sessionOutputMode for info/current. |
| cmd/entire/cli/sessions_test.go | Adds unit tests for session list --json and session info --transcript (including trimming + mutual exclusion). |
| cmd/entire/cli/session_current.go | Adds --transcript mode and routes output via the new sessionOutputMode. |
| cmd/entire/cli/explain.go | Adds export flags (--json, --transcript, --session-index) and dispatches to export pipeline. |
| cmd/entire/cli/explain_export.go | Implements the export pipeline: checkpoint/commit resolution, JSON envelopes, transcript streaming, and shared remote-fallback prefix matching. |
| cmd/entire/cli/explain_export_test.go | Adds coverage for export JSON invariants, transcript streaming, session-index behavior, and commit-SHA fallback. |
PR #1144 review feedback. Three real issues + one rename: 1. Whole-document JSON transcripts (Gemini's session-*.json) were being silently dropped: the trim-to-last-newline logic stripped the closing brace, leaving malformed output. Now `shapeTranscriptSnapshot` checks `json.Valid` first and emits the document intact when the buffer is a single JSON document; only JSONL streams (Claude/Cursor/Codex) get the trailing partial-line trim. 2. Snapshot semantics were inaccurate: io.ReadAll reads to current EOF, so bytes the agent appends after command start would be included silently. Now bound the read with io.LimitReader anchored to f.Stat().Size() at open. Help text updated to match. 3. `explainExportOptions` doc comment claimed "exactly one of json or transcript" but rawTranscript is also a valid mode. Reworded. 4. Renamed `bytes` local in runExplainStreamTranscript to `compact` so it doesn't shadow the stdlib package. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Entire-Checkpoint: c0c9dd5b48db
Contributor
Author
|
bugbot run |
Two real low-severity issues caught by cursor[bot]:
1. Unused `json` field in explainExportOptions: the JSON path was being
reached by elimination ("not transcript, not raw-transcript") instead
of by checking opts.json explicitly. A future caller invoking
runExplainExport with all three mode flags false would silently
produce JSON output. Replace the implicit dispatch with an explicit
switch and a defensive default branch that errors out. Regression
test: TestRunExplainExport_NoModeFlagFailsLoudly.
2. Double-close on context cancellation in streamTranscriptToStdout: the
cancel goroutine and the defer both called f.Close() unconditionally.
os.File.Close handles repeated calls gracefully today but it can trip
the race detector under heavy fd reuse. Funnel both paths through a
sync.Once so close happens exactly once.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: 11908a40a40c
Three findings from /codex:adversarial-review:
[high] --session JSON filter dropped archived sessions in multi-session
checkpoints. runExplainListJSON only matched against p.SessionID (the
latest contributor), so any checkpoint where the searched session had
been archived to an older slot was silently omitted — exactly the
concurrent-session case the metadata model exists to support. New
checkpointMatchesSessionFilter helper now matches against both
SessionID and every entry in SessionIDs. Regression test:
TestCheckpointMatchesSessionFilter.
[medium] Transcript export buffered the entire session file before
writing. io.ReadAll on a multi-hour Claude Code transcript would spike
memory to O(file size); the help text positioned this as a streaming
export, so falling over on the largest transcripts is a real
regression. Now agent-aware:
- JSONL agents (Claude Code/Cursor/Codex/etc.): line-buffered copy
via bufio.Reader.ReadBytes('\n'). Only one line is held in memory
at a time. Trailing partial line at EOF is dropped (existing
contract). New writeJSONLTranscript.
- Whole-document JSON agents (Gemini): buffer + json.Valid as before
— these transcripts are bounded by conversation size and rarely
exceed a few MB. Trim-to-last-newline would corrupt them.
[medium] Checkpoint JSON export silently produced partial data on
per-session read failures. Added a top-level `partial` flag to
checkpointExportJSON that's set when any session metadata fails to
read; the command also returns SilentError so the exit code is
non-zero. Per-session error fields stay so consumers can pinpoint the
failure. Contract test: TestCheckpointExportJSON_PartialContract.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Entire-Checkpoint: c774f18acf9a
Working through the in-flight code review on the export surface: [H1] streamTranscriptToStdout silently disabled the snapshot bound when f.Stat() failed: snapshotSize stayed at -1, the io.LimitReader was skipped, and the help text's "snapshot bounded at command start" promise was a lie. Now Stat failure returns an error rather than emitting an unbounded read with a misleading guarantee. [H2] The previous --raw-transcript --session-index test wrote one session, so it could only catch a regression where the flag was rejected outright — not one where it was silently ignored (which is exactly the bug we fixed earlier in the branch). New TestExplainCmd_RawTranscriptMultiSessionDistinctContent uses a v2 fixture with two byte-distinct sessions and asserts that index 0 and index 1 return different content. [H3] The partial-failure JSON path was only contract-tested (struct shape via direct marshal). To exercise the actual readSessionMetadataForExport → envelope.Partial → SilentError flow without corrupting a real v2 git tree (the splice helper is unexported), extracted buildCheckpointJSONEnvelope into a unit-testable helper and added TestBuildCheckpointJSONEnvelope_PartialFailureFromMockReader using a stubCommittedReader that hits the default branch in readSessionMetadataForExport. [M1] entire checkpoint explain --json was capped at 100 checkpoints with no indication. Added a --limit flag and a stderr note when the cap is hit (we probe limit+1 to detect overflow, trim, and tell the user how to see more). The JSON shape stays a flat array so existing jq pipelines don't break. [M2] --commit <ref> skipped the remote-fetch retry that --checkpoint / positional already used. Now resolveCheckpointFromCommitRef calls matchCheckpointPrefixWithRemoteFallback when the trailer points at an unknown checkpoint, so commit-SHA targets work the same as prefix targets. [M4] --transcript on a v1-only checkpoint used to error with "compact transcript is only available for v2 (try --raw-transcript)". The user's intent is "give me transcript bytes" and we have a way to satisfy it, so transparently fall through to the raw transcript with a one-line stderr note instead of forcing a re-run. [L2] resolveExplainCheckpointID docstring updated to mention that --commit also has remote-fetch retry now, matching the implementation. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 67e4b2cf7534
Contributor
Author
|
bugbot run |
Cursor bugbot finding: writeWholeDocumentJSONTranscript returned nil (success) with no output when json.Valid was false. For machine consumers, exit-code 0 + empty stdout was indistinguishable from "transcript is empty" — a Baton-style script would silently proceed with no data. - Empty buffer (agent hasn't written anything yet) still succeeds cleanly, since that's a real "no data" case. - Non-empty + invalid (agent mid-write or genuinely corrupt) now returns an error suggesting a retry. The non-zero exit lets consumers branch on stdout-vs-data. - writeSessionTranscript sets cmd.SilenceUsage so the runtime error doesn't trigger cobra's usage block on top of any partial output. Regression test: TestInfoCmd_TranscriptInvalidJSONErrorsLoudly. The other two cursor[bot] comments on this PR are stale — both were posted before commit 786b84b (which added the sync.Once close and the explicit opts.json switch case). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> Entire-Checkpoint: 3fe20a6a7b12
Contributor
Author
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 8eedead. Configure here.
peyton-alt
approved these changes
May 7, 2026
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.
https://entire.io/gh/entireio/cli/trails/320
Summary
Adds a thin, additive CLI surface that exposes session and checkpoint data
as a stable contract for external consumers (Baton, eval pipelines, the
session-handoffskill). Closes #1125.No new top-level commands, no schema invention. JSON envelopes are
metadata-only; transcript bytes always stream to stdout from a flag.
New flags:
entire session info <id> --transcript/entire session current --transcript— stream the live raw agent transcript to stdout (snapshot semantics:
trailing partial JSONL line is trimmed;
<-ctx.Done()cancels the read).entire session list --json— same per-entry envelope assession info --json, emitted as an array ([]for empty).entire checkpoint explain --json— metadata-only envelope. List viewif no target, single-checkpoint object if a target is given. Per-session
read failures surface an explicit
errorfield (no silent stub entries);list-view non-context errors propagate (no swallowed
[]).entire checkpoint explain <id> --transcript— stream the normalizedcompact transcript (V2
transcript.jsonlon/main).entire checkpoint explain <id> --raw-transcript --session-index N—pick a specific session in a multi-session checkpoint (default: latest).
--session-indexalso works with--transcript.Internal:
matchCheckpointPrefixWithRemoteFallbackhelper used by both theprose
runExplainCheckpointWithLookupand the new export resolver.sessionOutputModeenum replaces(jsonOutput, transcriptOutput bool)so the trichotomy is total in code.
strategy.ResolveTranscriptPathfor live-transcript callersoutside the strategy package.
errCheckpointHasNoSessionssentinel — distinguishes empty vsmissing checkpoints for callers using
errors.Is.Test plan
mise run test:ci)mise run lint)--jsonenvelope verified to never embed transcript bytes(
TestRunExplainExport_JSONNeverEmbedsTranscript)--session-indexdistinct content per session verified end-to-end(264KB session 0 vs 1.4MB session 1, distinct sessionIds)
<-ctx.Done()cancellation contract verified via close-on-done pattern(
TestInfoCmd_TranscriptTrimsPartialTrailingLine)🤖 Generated with Claude Code
Note
Medium Risk
Adds new machine-readable CLI output modes that stream transcript bytes and emit JSON envelopes, which could affect scripting/automation and output/exit-code behavior if edge cases are missed.
Overview
Adds a machine-readable export surface to existing CLI commands.
entire checkpoint explaingains--json(metadata-only list or single-checkpoint envelope withpartial+ per-sessionerrorreporting),--transcript(stream v2 compact transcript),--session-index(select session in multi-session checkpoints), and--limit(cap JSON list output with truncation note). Export resolution now retries missing checkpoint prefixes via a shared remote-metadata fetch helper, and supports positional fallback to commit-trailer resolution.entire session infoandentire session currentgain--transcriptto stream the live on-disk agent transcript with snapshot/cancellation semantics and agent-aware shaping (JSONL line streaming vs whole-JSON validation), whileentire session listgains--jsonto emit the same per-session JSON envelopes assession info --json. Also exportsstrategy.ResolveTranscriptPathfor non-strategy callers and adds comprehensive tests for the new flags and edge cases.Reviewed by Cursor Bugbot for commit 8eedead. Configure here.