Push compact transcript.jsonl without pointing metadata at it · Entire

Push compact transcript.jsonl without pointing metadata at it

2b5c661→main·

computermode·3w ago·4 files·+34 added/-31 removed

The compact transcript (transcript.jsonl) is still generated on every committed write and during finalization, and written into the checkpoint tree so it is pushed alongside full.jsonl. The metadata.json sessions[].transcript pointer now stays on full.jsonl; pointing it at the compact transcript is deferred to a later change.

Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com

Sessions

029ccd754882View transcript

Changes

4

488 unmodified lines

489
490
491
492
492
493
494
495

488 unmodified lines

- **Worktree-specific branches** - each git worktree gets its own shadow branch namespace, preventing conflicts  
- **Supports multiple concurrent sessions** - checkpoints from different sessions in the same directory interleave on the same shadow branch  
- Condenses session logs to permanent `entire/checkpoints/v1` branch on user commits  
- Each committed session stores the raw transcript (`full.jsonl`, read by CLI rewind/resume/explain) plus a best-effort compact transcript (`transcript.jsonl`, generated via `transcript/compact` and pre-sliced to the checkpoint's `checkpoint_transcript_start`). The root `metadata.json` `sessions[].transcript` pointer targets `transcript.jsonl` when generated, falling back to `full.jsonl`. Both are pushed with the v1 branch.  
- Each committed session stores the raw transcript (`full.jsonl`, read by CLI rewind/resume/explain) plus a best-effort compact transcript (`transcript.jsonl`, generated via `transcript/compact` and pre-sliced to the checkpoint's `checkpoint_transcript_start`). Both are pushed with the v1 branch. The root `metadata.json` `sessions[].transcript` pointer still targets `full.jsonl`; pointing it at `transcript.jsonl` is deferred to a later change.  
- Uses the `post-rewrite` Git hook to keep local session linkage aligned after amend/rebase rewrites  
- Builds git trees in-memory using go-git plumbing APIs  
- Rewind restores files from shadow branch commit tree (does not use `git reset`)

MCLAUDE.md+1/-1

293 unmodified lines

294
295
296
297
297
298
299
300
103 unmodified lines

404
405
406
407
408
409
407
408
409
410
411
412
309 unmodified lines

722
723
724
725
726
727
728
725
726
727
728
729
730
731
732
72 unmodified lines

805
806
807
808
809
810
811
812
813
808
809
810
814
815
816
23 unmodified lines

840
841
842
840
841
843
844
845
846
847
8 unmodified lines

856
857
858
856
859
860
861
862
863
864
862
865
866
867
868
869
870
871
869
872
873
874
875
2 unmodified lines

878
879
880
878
881
882
883
884
1 unmodified line

886
887
888
886
889
890
891
875 unmodified lines

1767
1768
1769
1768
1769
1770
1770
1771
1772
1773
1774
1775

293 unmodified lines

// ├── 1/                    # First session
// │   ├── metadata.json     # CommittedMetadata (session-specific, includes initial_attribution)
// │   ├── full.jsonl        # Raw agent transcript (CLI rewind/resume/explain)
// │   ├── transcript.jsonl  # Compact transcript scoped to this checkpoint (referenced by metadata.json)
// │   ├── transcript.jsonl  # Compact transcript scoped to this checkpoint (pushed; not yet referenced by metadata.json)
// │   ├── prompt.txt
// │   └── content_hash.txt
// ├── 2/                    # Second session
103 unmodified lines

}
}

// Write transcript. The pointer targets the compact transcript.jsonl when
// available; full.jsonl stays in the tree for CLI rewind/resume/explain,
// which read it by filename rather than through these paths.
// Write transcript. The pointer targets full.jsonl, which CLI
// rewind/resume/explain read by filename. The compact transcript.jsonl is
// also written into the tree (so it is pushed) but is not yet pointed at.
transcriptPointer, err := s.writeTranscript(ctx, opts, sessionPath, entries)
if err != nil {
    return filePaths, err
}
309 unmodified lines

}

// writeTranscript writes the transcript, compact transcript, and content hash
// to the checkpoint entries. Returns the session-relative filename the
// metadata transcript pointer should target: transcript.jsonl when the
// compact transcript was generated (best-effort), full.jsonl otherwise, or ""
// when the transcript was empty and nothing was written.
// to the checkpoint entries. The compact transcript.jsonl is written into the
// tree (so it is pushed alongside full.jsonl) but is not yet referenced by
// metadata. Returns the session-relative filename the metadata transcript
// pointer should target: full.jsonl, or "" when the transcript was empty and
// nothing was written.
func (s *GitStore) writeTranscript(ctx context.Context, opts WriteCommittedOptions, basePath string, entries map[string]object.TreeEntry) (string, error) {
logCtx := logging.WithComponent(ctx, "checkpoint")
transcriptBytes := opts.Transcript.Bytes()
72 unmodified lines

}

contentHashSpan.End()

// Write the compact transcript (transcript.jsonl) into the tree so it is
// pushed alongside full.jsonl. The metadata pointer intentionally stays on
// full.jsonl for now — pointing it at the compact transcript is deferred to
// a later change.
s.writeCompactTranscript(logCtx, opts.Agent, opts.CheckpointTranscriptStart, transcriptBytes, basePath, entries)
pointerFile := paths.TranscriptFileName
if s.writeCompactTranscript(logCtx, opts.Agent, opts.CheckpointTranscriptStart, transcriptBytes, basePath, entries) {
    pointerFile = paths.CompactTranscriptFileName
}

logging.Debug(logCtx, "write transcript timings",
    slog.String("session_id", opts.SessionID),
23 unmodified lines

// compact transcript.jsonl format, scoped to this checkpoint via startLine,
// and records it at sessionPath in the tree. Best-effort: the compact
// transcript is derived data, so failures are logged and never fail the
// checkpoint write. Returns true when transcript.jsonl was recorded.
func (s *GitStore) writeCompactTranscript(ctx context.Context, agentType types.AgentType, startLine int, transcriptBytes []byte, sessionPath string, entries map[string]object.TreeEntry) bool {
// checkpoint write.
func (s *GitStore) writeCompactTranscript(ctx context.Context, agentType types.AgentType, startLine int, transcriptBytes []byte, sessionPath string, entries map[string]object.TreeEntry) {
    compactCtx, compactSpan := perf.Start(ctx, "write_compact_transcript")
defers
compactSpan.End()

8 unmodified lines

slog.String("agent", string(agentType)),
        slog.String("error", err.Error()),
    )
    return false
    return
}
if len(bytes.TrimSpace(compacted)) == 0 {
    logging.Debug(compactCtx, "compact transcript empty, skipping transcript.jsonl",
        slog.String("agent", string(agentType)),
    )
    return false
}
if len(compacted) > agent.MaxChunkSize {
    logging.Warn(compactCtx, "compact transcript exceeds max blob size, skipping transcript.jsonl",
        slog.String("agent", string(agentType)),
        slog.Int("compact_bytes", len(compacted)),
    )
    return false
}

blobHash, err := CreateBlobFromContent(s.repo, compacted)
2 unmodified lines

logging.Warn(compactCtx, "failed to create compact transcript blob, skipping transcript.jsonl",
        slog.String("error", err.Error()),
    )
    return false
}
compactPath := sessionPath + paths.CompactTranscriptFileName
entries[compactPath] = object.TreeEntry{
1 unmodified line

Mode: filemode.Regular,
        Hash: blobHash,
    }
return true
}

// mergeFilesTouched combines two file lists, removing duplicates.
875 unmodified lines

Hash: hashBlob,

// Regenerate the compact transcript from the new content. Best-effort: on
    // generation failure the previous transcript.jsonl entry (if any) is left
    // in place so the metadata.json transcript pointer never dangles.
    // Regenerate the compact transcript from the new content so the pushed
    // transcript.jsonl stays current. Best-effort: on generation failure the
    // previous transcript.jsonl entry (if any) is left in place.
s.writeCompactTranscript(ctx, agentType, startLine, transcript.Bytes(), sessionPath, entries)

return nil

Mcmd/entire/cli/checkpoint/committed.go+23/-21

119 unmodified lines

120
121
122
123
123
124
125
126
127
128
128
129
130
131
132

119 unmodified lines

t.Error("compact transcript missing assistant content")

// Root metadata.json points at the compact transcript.
    // Root metadata.json still points at full.jsonl; the compact transcript is
    // written into the tree (and pushed) but not yet referenced by metadata.
summary := readSummaryFromBranch(t, repo, cpID)
if len(summary.Sessions) != 1 {
    t.Fatalf("session count = %d, want 1", len(summary.Sessions))
}
wantTranscript := "/" + sessionPath + paths.CompactTranscriptFileName
wantTranscript := "/" + sessionPath + paths.TranscriptFileName
if summary.Sessions[0].Transcript != wantTranscript {
            t.Errorf("sessions[0].transcript = %q, want %q", summary.Sessions[0].Transcript, wantTranscript)
}

Mcmd/entire/cli/checkpoint/committed_compact_transcript_test.go+3/-2

216 unmodified lines

217
218
219
220
221
222
223
224
225
226
220
221
222
223
224
225
226
227
228
229

216 unmodified lines

`checkpoint_transcript_start`), `transcript.jsonl` is pre-sliced to the checkpoint's own portion (`compact.Compact` is called with `StartLine = checkpoint_transcript_start`), so it needs no offset to consume.
The root `metadata.json` `sessions[].transcript` pointer targets `transcript.jsonl` when it was generated and falls back to `full.jsonl` otherwise (e.g. unparseable/external-agent transcripts, or checkpoints written by older CLI versions). CLI read paths (rewind/resume/explain) ignore the pointer and read `full.jsonl` by filename. Generation failures are logged but never fail the checkpoint write; during finalization a failed regeneration keeps the previous `transcript.jsonl` so the pointer never dangles.
It is written into the checkpoint tree and pushed alongside `full.jsonl`, but the root `metadata.json` `sessions[].transcript` pointer still targets `full.jsonl`; pointing it at `transcript.jsonl` is deferred to a later change.
CLI read paths (rewind/resume/explain) read `full.jsonl` by filename. Compact generation is best-effort: failures are logged but never fail the checkpoint write, and during finalization a failed regeneration keeps the previous `transcript.jsonl`.

**Root-level metadata.json (`CheckpointSummary`):**
```json
```

Mdocs/architecture/sessions-and-checkpoints.md+7/-7