What
hooks/session-onboard.sh assembles the SessionStart hook output unconditionally: version
header, worktree pointer, capture-failure warning, HANDOFF pointer, gitignore nudge, the
post-compaction buffer-tail inline (TL_COMPACT_TAIL_LINES=30 × TL_COMPACT_TAIL_LINE_CHARS=300
≈ 9,030 chars), the unconsumed-buffer scan, and git status -s | head -20 — with no total-size
budget across the whole thing.
Claude Code's hook docs (code.claude.com/docs/en/hooks) document no character limit for
SessionStart additionalContext/stdout at all. A competing plugin
(adrrr/persistent-handoff, docs/REFERENCE.md)
claims a 10,000-character cap past which Claude Code truncates to a preview + path, sourced from
reading the 2.1.251 binary rather than any doc — so treat the exact number as unverified, but the
underlying risk (unbounded output) is real and worth designing against regardless of where the
line actually is.
Reproduction
Built a fixture: a 30-line buffer where each line is near TL_COMPACT_TAIL_LINE_CHARS (270
padding chars), plus a repo with 20 untracked files with moderately long names (not pathological
— a real refactor session), plus a normal HANDOFF.md header. Invoked the real hook with
source: "compact":
=== TOTAL CHARS ===
11026
11KB from a realistic scenario, not a contrived one. The tail end of the output — the live git
state block, which is often exactly what's needed to reorient after a compact — is what gets
pushed off first if truncation does occur.
Fix shape
Measure the assembled block before emitting and budget it: if the total would exceed a safe
threshold (e.g. 8,000 chars, leaving headroom), trim the buffer-tail inline first (it has a
stated fallback — "full history is at <path>" — the git-status block does not), rather than
letting whichever section renders last silently lose the tail.
Prior art
adrrr/persistent-handoff's hook documents this constraint explicitly and keeps its own output
well under it (259–407 chars per preamble). Worth reading docs/REFERENCE.md#the-10000-character-cap
in that repo for the framing, even if the exact number needs independent confirmation.
What
hooks/session-onboard.shassembles the SessionStart hook output unconditionally: versionheader, worktree pointer, capture-failure warning, HANDOFF pointer, gitignore nudge, the
post-compaction buffer-tail inline (
TL_COMPACT_TAIL_LINES=30×TL_COMPACT_TAIL_LINE_CHARS=300≈ 9,030 chars), the unconsumed-buffer scan, and
git status -s | head -20— with no total-sizebudget across the whole thing.
Claude Code's hook docs (
code.claude.com/docs/en/hooks) document no character limit forSessionStartadditionalContext/stdout at all. A competing plugin(adrrr/persistent-handoff,
docs/REFERENCE.md)claims a 10,000-character cap past which Claude Code truncates to a preview + path, sourced from
reading the 2.1.251 binary rather than any doc — so treat the exact number as unverified, but the
underlying risk (unbounded output) is real and worth designing against regardless of where the
line actually is.
Reproduction
Built a fixture: a 30-line buffer where each line is near
TL_COMPACT_TAIL_LINE_CHARS(270padding chars), plus a repo with 20 untracked files with moderately long names (not pathological
— a real refactor session), plus a normal
HANDOFF.mdheader. Invoked the real hook withsource: "compact":11KB from a realistic scenario, not a contrived one. The tail end of the output — the live git
state block, which is often exactly what's needed to reorient after a compact — is what gets
pushed off first if truncation does occur.
Fix shape
Measure the assembled block before emitting and budget it: if the total would exceed a safe
threshold (e.g. 8,000 chars, leaving headroom), trim the buffer-tail inline first (it has a
stated fallback — "full history is at
<path>" — the git-status block does not), rather thanletting whichever section renders last silently lose the tail.
Prior art
adrrr/persistent-handoff's hook documents this constraint explicitly and keeps its own outputwell under it (259–407 chars per preamble). Worth reading
docs/REFERENCE.md#the-10000-character-capin that repo for the framing, even if the exact number needs independent confirmation.