feat(checkpoint): flag compact transcript via has_compact_transcript · Entire

feat(checkpoint): flag compact transcript via has_compact_transcript

278addd→main·

computermode·3w ago·5 files·+33 added/-11 removed

Add a has_compact_transcript boolean to the root metadata.json sessions[]
entries instead of repointing sessions[].transcript at transcript.jsonl.
The transcript pointer keeps targeting full.jsonl; the flag (omitted when
false) signals to external readers that a compact transcript.jsonl was
written alongside it. Derived from the actual tree entry so it can't drift
from what was written.

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

Sessions

9c9ee0f533ffView transcript

?\
Add Compact Transcript Metadata FieldClaude Code·Opus 4.8·4 steps

Changes

5

494 unmodified lines

495
496
497
498
498
499
500
501

494 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`). 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

379 unmodified lines

380
381
382
383
384
385
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398

379 unmodified lines

// Used in CheckpointSummary.Sessions to map session IDs to their file locations.
type SessionFilePaths struct {
    Metadata string `json:"metadata"`
    // Transcript points at the compact transcript.jsonl when one was
    // generated, otherwise at the raw full.jsonl. Checkpoints written by
    // older CLI versions always point at full.jsonl.
    // Transcript points at the raw full.jsonl, which CLI read paths
    // (rewind/resume/explain) resolve by filename. When a compact
    // transcript.jsonl is also generated it is written into the same session
    // directory alongside full.jsonl and signalled by HasCompactTranscript.
    Transcript  string `json:"transcript,omitempty"`
    ContentHash string `json:"content_hash,omitempty"`
    Prompt      string `json:"prompt"`
    // HasCompactTranscript is true when a compact transcript.jsonl was
    // generated and written into this session's directory alongside full.jsonl.
    // Omitted (false) for non-compactable, empty, or oversized transcripts and
    // for checkpoints written by older CLI versions. When set, the compact file
    // lives next to Transcript, named transcript.jsonl.
    HasCompactTranscript bool `json:"has_compact_transcript,omitempty"`
}

// CheckpointSummary is the root-level metadata.json for a checkpoint.

Mapi/checkpoint/metadata.go+10/-3

405 unmodified lines

406
407
408
409
409
410
411
412
413
1 unmodified line

415
416
417
418
419
420
421
422
423
424
425

405 unmodified lines

// 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.
    // also written into the tree (so it is pushed) and signalled to external
    // readers via the HasCompactTranscript flag below.
    wroteTranscript, err := s.writeTranscript(ctx, opts, sessionPath, entries)
    if err != nil {
        return filePaths, err
    }
1 unmodified line

if wroteTranscript {
        filePaths.Transcript = "/" + sessionPath + paths.TranscriptFileName
        filePaths.ContentHash = "/" + sessionPath + paths.ContentHashFileName
        // Signal the compact transcript.jsonl when writeTranscript wrote one
        // into the tree (best-effort; skipped for non-compactable, empty, or
        // oversized transcripts). Derived from the actual tree entry so the
        // flag can never drift from what was written.
        _, filePaths.HasCompactTranscript = entries[sessionPath+paths.CompactTranscriptFileName]
    }

// Write prompts via the 7-layer pipeline. OPF runs only in the

Mcmd/entire/cli/checkpoint/persistent.go+7/-1

80 unmodified lines

81
82
83
84
84
85
86
87
6 unmodified lines

94
95
96
97
98
99
100
101
102
57 unmodified lines

160
161
162
163
164
165
166
167
168

80 unmodified lines

}

// Root metadata.json still points at full.jsonl; the compact transcript is
    // written into the tree (and pushed) but not yet referenced by metadata.
    // written into the tree (and pushed) and flagged via has_compact_transcript.
    summary := readSummaryFromBranch(t, repo, cpID)
    if len(summary.Sessions) != 1 {
        t.Fatalf("session count = %d, want 1", len(summary.Sessions))
6 unmodified lines

if summary.Sessions[0].ContentHash != wantHash {
        t.Errorf("sessions[0].content_hash = %q, want %q", summary.Sessions[0].ContentHash, wantHash)
    }
    if !summary.Sessions[0].HasCompactTranscript {
        t.Error("sessions[0].has_compact_transcript = false, want true")
    }
}

func TestWriteCommitted_CompactTranscriptScopedToCheckpointStart(t *testing.T) {
57 unmodified lines

if summary.Sessions[0].Transcript != wantTranscript {
        t.Errorf("sessions[0].transcript = %q, want %q", summary.Sessions[0].Transcript, wantTranscript)
    }
    if summary.Sessions[0].HasCompactTranscript {
        t.Error("sessions[0].has_compact_transcript = true for non-compactable transcript, want false")
    }
}

// codexTranscriptWithCompactionBeforeStart returns a Codex-format JSONL

Mcmd/entire/cli/checkpoint/persistent_compact_transcript_test.go+7/-1

212 unmodified lines

213
214
215
216
217
218
216
217
218
219
220
221
222
223
12 unmodified lines

236
237
238
237
239
240
239
241
242
243
244
245

212 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.
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.
It is written into the checkpoint tree and pushed alongside `full.jsonl`. The
root `metadata.json` `sessions[].transcript` pointer keeps targeting
`full.jsonl`; when a compact transcript was generated the session entry also
carries `has_compact_transcript: true` (omitted otherwise) so external readers
can find `transcript.jsonl` next to it.
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
12 unmodified lines

"sessions": [\
    {\
      "metadata": "/ab/c123def456/0/metadata.json",\
      "transcript": "/ab/c123def456/0/transcript.jsonl",\
      "transcript": "/ab/c123def456/0/full.jsonl",\
      "content_hash": "/ab/c123def456/0/content_hash.txt",\
      "prompt": "/ab/c123def456/0/prompt.txt"\
      "prompt": "/ab/c123def456/0/prompt.txt",\
      "has_compact_transcript": true\
    }\
  ],\
  "token_usage": {