PreCompact hook fires for sub-agent compaction, causing unnecessary main-agent conversation archiving
Problem
When using the Claude Agent SDK with query() and registering a PreCompact hook, the hook fires not only when the main agent triggers auto-compaction, but also when any sub-agent (spawned via the Agent tool or in-process runner) triggers its own compaction. This causes unintended side effects in the main agent's session.
Reproduction
Setup
- Main agent model:
opus[1m](1M context, auto-compact threshold ~967K tokens) - Sub-agent model:
haiku(200K context, auto-compact threshold ~167K tokens) - A
PreCompacthook is registered on the mainquery()call that:
- Archives the conversation transcript to disk
- Sets a flag (
hadCompaction = true) to trigger auto-continue after the query
Steps
- User sends a message that triggers the
Skilltool (e.g./pua) - The skill's execution spawns a sub-agent via the
Agenttool (e.g.,web-researcherusing haiku) - The
web-researchersub-agent fetches web pages and accumulates context - Sub-agent's context reaches ~167K tokens → SDK triggers auto-compaction for the sub-agent
- Bug: The
PreCompacthook registered on the main agent'squery()fires - The hook archives the main agent's conversation (which hasn't changed)
- The hook sets
hadCompaction = true, triggering CLAUDE.md update queries and auto-continue on the main agent - Sub-agent continues working, hits 167K again → cycle repeats
Observed behavior
In one session, the sub-agent compacted 17 times in 9 minutes. Each compaction triggered the main agent's PreCompact hook, resulting in:
- 9 identical conversation archives (same content, different timestamps)
- Unnecessary CLAUDE.md update queries consuming API tokens
- Auto-continue queries that produced no useful output
Evidence from SDK debug log
The autocompact: debug lines show two interleaved threshold groups:
# Main agent — never exceeds threshold, never needs compaction
05:42:30 autocompact: tokens=24123 threshold=967000 effectiveWindow=980000
05:43:29 autocompact: tokens=33016 threshold=967000 effectiveWindow=980000
# Sub-agent (haiku) — repeatedly exceeds threshold
05:42:19 autocompact: tokens=168279 threshold=167000 effectiveWindow=180000 ← triggers compact
05:42:19 PreCompact:auto [callback] completed ← main agent's hook fires 2ms later!
05:42:37 autocompact: tokens=168378 threshold=167000 effectiveWindow=180000 ← triggers compact
05:42:37 PreCompact:auto [callback] completed ← fires again
The PreCompact hook fires within 2-3ms of each sub-agent compaction, confirming the causal relationship.
Expected behavior
The PreCompact hook registered on the main query() call should only fire when the main agent itself triggers compaction. Sub-agent compactions should either:
- Not trigger the main agent's hooks at all, or
- Pass a field in the
PreCompactHookInput(e.g.,agent_idoris_subagent: boolean) so the hook callback can distinguish the source and skip if needed.
Impact
- Wasted API tokens: Each spurious PreCompact triggers follow-up queries (CLAUDE.md updates, auto-continue) that produce no useful output
- Confusing UX: Users see repeated "context compression" messages even though the main agent's context is well within limits
- Disk spam: Identical conversation archives are written repeatedly
Environment
- Claude Agent SDK: latest (installed via
"*"in package.json) - Main model:
claude-opus-4-6[1m](1M context) - Sub-agent model:
claude-haiku-4-5(200K context) - Host mode (non-containerized)
Workaround
Currently considering checking PreCompactHookInput fields to detect sub-agent compaction, but the input doesn't appear to include an agent identifier. A field like agent_id or is_root_agent in the hook input would enable a clean workaround.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗