Skip to content

session-onboard.sh compact-restart output can exceed SessionStart's undocumented size limit #64

Description

@jsirish

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingpriority/highImportant, address soon

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions