The CLAUDE.md splitter
What happens when a memory file grows past 2,000 characters, and how to watch it.
CLAUDE.md is loaded into context at the start of every session and stays there
for all of it. A long one is a fixed tax on every turn, paid whether or not any
of it was relevant.
When CULP sees a CLAUDE.md over 2,000 characters, it splits it into a compact
root plus on-demand documents under .claude/md/, and the root points at them.
It never runs in the hook
Claude Code has no asynchronous command hook, so a SessionStart hook delays
the session for exactly as long as it runs. Measured: a 12-second hook turned a
2-second claude -p into a 20-second one. Running an inference there would
freeze the session for the whole split.
So the hook only claims the file and starts a background worker. The split runs in its own process, and your session continues immediately.
On Windows the worker takes a console window, so you can watch it. On macOS and
Linux the same transcript goes to a log file under ~/.culp/claude-md-splits/,
and the session start message tells you which one.
Your original is never destroyed
The source is backed up before anything replaces it, and the replacement is atomic. A failed split leaves the file byte-identical.
A generated root carries a marker comment, which is how a second session knows not to split it again.
Reporting
The split is dispatched at session start and its outcome is reported once, on your next prompt. Ending a session cancels the workers it started.
If a split fails, that counts against the exact content it failed on, so a file that cannot be split is not retried for ever in every future session. Fix the file, or change it, and the count resets.