PreCompact hook fires for sub-agent compaction, causing unnecessary main-agent conversation archiving

Resolved 💬 2 comments Opened Mar 28, 2026 by Tivility Closed Mar 28, 2026

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 PreCompact hook is registered on the main query() call that:
  1. Archives the conversation transcript to disk
  2. Sets a flag (hadCompaction = true) to trigger auto-continue after the query

Steps

  1. User sends a message that triggers the Skill tool (e.g. /pua)
  2. The skill's execution spawns a sub-agent via the Agent tool (e.g., web-researcher using haiku)
  3. The web-researcher sub-agent fetches web pages and accumulates context
  4. Sub-agent's context reaches ~167K tokens → SDK triggers auto-compaction for the sub-agent
  5. Bug: The PreCompact hook registered on the main agent's query() fires
  6. The hook archives the main agent's conversation (which hasn't changed)
  7. The hook sets hadCompaction = true, triggering CLAUDE.md update queries and auto-continue on the main agent
  8. 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:

  1. Not trigger the main agent's hooks at all, or
  2. Pass a field in the PreCompactHookInput (e.g., agent_id or is_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.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗