Skip to content

fix(hooks): bound pre_tool transcript reads to a tail window - #110

Merged
mahmoudimus merged 1 commit into
mainfrom
fix/pre-tool-bounded-tail
Jul 20, 2026
Merged

mahmoudimus merged 1 commit into
mainfrom
fix/pre-tool-bounded-tail

Conversation

@mahmoudimus

Copy link
Copy Markdown
Owner

What

Root cause of the recurring multi-GB daemon balloons: src/simba/hooks/pre_tool_use.py performed two unbounded whole-file transcript reads on the highest-frequency hook (PreToolUse fires on every tool call, and the same code runs daemon-side via /hook/pre_tool concurrently across sessions):

  • _extract_thinking: read_text().strip().split("\n") of the entire transcript — to find the last thinking block, which lives at the end of the file. On multi-GB rollouts this read gigabytes per tool call (and on non-Claude-format transcripts, read them to return "").
  • _post_compaction_tail_bytes: read_bytes() of the entire file to rfind the last compaction marker. Its caller's "cheap path" skips the read only for small files — inverted for exactly the files that hurt.

A malloc_history capture of a live 30.9GB balloon attributed ~29.7GB to five concurrent in-flight reads of ~2GB transcripts through this path. No config cap governed it.

Changes

  • New hooks.pre_tool_tail_mb (default 16.0): maximum transcript bytes read from the END of the file by pre_tool inspectors.
  • New _read_tail_bytes(path, cap) helper: stat → seek(size−cap) → read to EOF, discarding a partial leading line; cap<=0 degrades to uncapped (matching sibling cap idioms).
  • _extract_thinking scans only the tail (documented tradeoff: a thinking block older than the window is not found — the block of interest is the most recent one).
  • _post_compaction_tail_bytes scans only the tail; marker-not-in-window degrades to the never-compacted (total, 0) case, and the context-low warning still fires correctly there since tail ≥ cap ≥ threshold. Absolute offsets preserved exactly when the marker is in the window.
  • Red-first tests for both paths, including a memory-bound proxy (thinking block placed before the window is not found — proving no whole-file read) and a partial-line-discard absolute-offset case.

Notes

Follow-up (separate PR): the same bounded-tail treatment for tailor/hook.py's Stop-hook transcript read and usage_signals.py, sharing this helper.

PreToolUse is the highest-frequency hook (fires on every tool call, and
the same code runs daemon-side via /hook/pre_tool across sessions).
_extract_thinking and _post_compaction_tail_bytes both read the ENTIRE
transcript to find something that always lives near EOF, so five
concurrent requests against ~2.1GB Codex rollouts produced ~30GB of
in-flight allocations.

Both now share a bounded-tail helper (hooks.pre_tool_tail_mb, default
16MB): stat the file, seek to size-cap, read to EOF, discard a partial
leading line. A thinking block or compaction marker older than the tail
window degrades to not-found, which is the correct behavior for both
callers (most-recent-only, and warn-once-at-offset-0 respectively).
@mahmoudimus
mahmoudimus merged commit b8b4fb4 into main Jul 20, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant