[BUG] `/branch` creates session from pre-compact state, resulting in larger branch than parent

Resolved 💬 2 comments Opened Mar 28, 2026 by Skydev0h Closed Mar 28, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

Running /branch after a previous /compact creates a branch session that is larger than the parent session. The branch contains both the pre-compact conversation history (that /compact logically collapsed) AND the compact summary AND the post-compact content — effectively undoing the compaction.

In my case:

  • Parent session after compact: 8,804 lines, 33 MB
  • Branch created from it: 12,056 lines, 42 MB (27% larger)

The extra ~3,500 lines in the branch are the pre-compact conversation content that should have been collapsed by the earlier /compact.

What Should Happen?

/branch should fork from the session's current logical state — meaning the branch should contain the compact summary + post-compact content only. The branch should be approximately the same size or smaller than the parent, not larger.

Error Messages/Logs

# No error message — the command succeeds silently with wrong content.
# The only indication is the file size:

$ ls -lh ~/.claude/projects/<project>/*.jsonl
-rw------- 1 user user  33M  dedb4e26-....jsonl    # parent (after compact)
-rw------- 1 user user  42M  212d1504-....jsonl    # branch (should be ≤33M)

# Line counts:
# Parent: 8,804 lines (compact summary at line 4,456 + 4,348 post-compact)
# Branch: 12,056 lines (compact summary at line 4,206 + 7,850 after — includes pre-compact content)

Steps to Reproduce

  1. Start a Claude Code session and work until it accumulates significant conversation history (>5,000 lines)
  2. Run /compact — the session logically collapses older content into a summary
  3. Continue working for a while (add more conversation after the compact)
  4. Run /branch <name>
  5. Compare the file sizes of the parent and branch session JSONLs in ~/.claude/projects/<project>/
  6. Observe: the branch file is larger than the parent

Root cause in source (minified function Yf9 in the compiled binary):

// The branch function reads the RAW file:
z = await TSH.readFile(f)    // reads ALL lines including pre-compact content

// Parses every line:
A = np(z)                     // does NOT apply content-replacement transforms

// Copies content-replacement entries separately:
O = A.filter(j => j.type === "content-replacement" ...)

// Writes ALL parsed messages to branch:
for (let j of Y) { w.push(gH({...j, sessionId: $})) }
await TSH.writeFile(_, w.join('\n'))

The /compact operation adds a content-replacement entry that tells the runtime to substitute old messages with the summary, but does not physically remove old messages from the JSONL. /branch reads the raw file and copies everything — both the old content and the replacement.

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.86

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

Windows Terminal

Additional Information

Suggested fix (either approach works):

Option A — Fix in /branch: After parsing the JSONL, apply content-replacement transforms before copying messages to the branch:

let replacements = A.filter(j => j.type === "content-replacement" && j.sessionId === q)
    .flatMap(j => j.replacements);
if (replacements.length > 0) {
    A = applyContentReplacements(A, replacements);
}

Option B — Fix in /compact: Physically truncate the JSONL during compaction — remove pre-compact lines and write only the summary + post-compact content, so readFile() in /branch naturally gets the compacted state.

The root cause was identified by extracting and deobfuscating the branch function from the compiled binary at ~/.local/share/claude/versions/2.1.86.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗