[FEATURE] Model-callable, permission-gated Compact tool for persist → compact → re-read workflows

Status Open
Reported on v2.1.281
Maintainer reply None cached
Activity 4 comments · opened Sep 24, 2026

Preflight Checklist

  • [x] I have searched existing requests. This was requested before in #33026 and #28559; both were closed for inactivity or as duplicates, not declined, and people are still asking for it in the comments. This issue is a focused follow-up.
  • [x] This is a single feature request (not multiple features)

Problem Statement

Claude can't choose when its own context is compacted. Compaction happens only when the user types /compact or when the context hits the auto-compact window. That's a token threshold, and it doesn't know about the work.

Long autonomous runs don't fit this. /goal runs, orchestrators that coordinate subagents, and multi-phase tasks all hit natural breakpoints where the earlier context is dead weight. For example: units 1–2 are finished, and units 3–4 don't need any of their details. At that point the model knows compacting is right, but it has no way to do it. So the history keeps getting re-sent on every turn, costing plan usage and attention quality. Then compaction eventually fires at an arbitrary moment, often mid-reasoning, before the model has written its state down.

There is no sanctioned way for the model to do this today. I checked each route from inside a session, running in auto mode:

  • Built-in commands like /compact can't be invoked by the model. Scheduled prompts (/loop, CronCreate) deliver them as plain text, per the scheduled-tasks docs.
  • PreCompact and PostCompact hooks are informational only. They can't trigger compaction.
  • The model can't change its own auto-compact window. /autocompact is a built-in command, and the auto mode classifier denies editing autoCompactWindow as self-modification.
  • A helper that types /compact into the session's own tmux pane is denied by the classifier ("Tmux Self Drive").
  • A helper that starts a fresh headless successor session, claude -p with a handover file, is also denied.

These denials are reasonable. Agent-injected input that looks like user input, or an agent spawning copies of itself, shouldn't be allowed silently. But the outcome is that the only safe path is a human pasting /compact at the right moment, which defeats unattended runs.

Proposed Solution

Add a built-in Compact tool that the model can call:

Compact(focus?: string)
  • focus works like /compact <instructions>: what the summary must keep, for example "keep: branch names, open PRs, the decision log, next step = unit 3".
  • It runs the normal compaction pipeline. PreCompact fires with trigger: "model" (or "tool"), then PostCompact, then SessionStart with the compact matcher, so existing handover hooks keep working.
  • It returns control to the model after compaction, with one short message saying it happened. The model can then re-read its handover files and continue in the same turn or the next. This is the "persist → compact → re-read" loop from #33026.
  • It's gated like any other tool: permission rules (Compact in allow/ask/deny) and visible to the auto mode classifier. Users choose whether the agent may compact on its own. The default could be ask in manual mode and allow in auto mode.
  • Add basic abuse limits, for example at most one compaction per N turns or per M tokens of new context, so a confused model can't loop compact → re-read → compact.

This makes the behaviour explicit, permissionable and auditable, instead of pushing people toward terminal-injection workarounds.

Alternative Solutions

  • Auto-compact window (/autocompact, --autocompact, CLAUDE_CODE_AUTO_COMPACT_WINDOW): useful as a safety net, but it's a token threshold. It can't tell "finished phase, compact now" from "mid-reasoning, don't". The model also can't adjust it for the phase ahead. In one test, claude -p --resume <id> --autocompact 100k on a session of about 170K tokens didn't compact at all.
  • Handover file + SessionStart[compact] hook that re-injects it: makes compaction survivable, and I recommend it anyway. But it doesn't give the model control over timing.
  • Delegating every phase to subagents: keeps the orchestrator smaller, but the orchestrator's own history still builds up across phases.
  • Human-in-the-loop: the agent sends a push notification with a ready-to-paste /compact keep: … line. Works, but only while someone is watching.
  • tmux keystroke injection / self-spawned successor sessions: correctly blocked by the classifier (see above), and they shouldn't become the community's workaround.

Priority

High - Significant impact on productivity

Feature Category

API and model interactions

Use Case Example

An unattended orchestrator run on a Pro plan (a 5-hour window plus a weekly cap, so every re-sent token counts):

  1. The owner hands Claude a TODO list with four independent units and leaves for several hours.
  2. Claude ships units 1–2 as PRs. They account for about 30% of context: diffs, test output, review back-and-forth.
  3. Units 3–4 touch unrelated code. Claude writes .delegator/NEXT_SESSION.md (done, in flight, next step, decisions), commits it, then calls Compact(focus: "keep: PR stack #20–#22, budget left, next = unit 3").
  4. After compaction, the SessionStart[compact] hook re-injects the handover file. Claude re-reads the plan and carries on with unit 3 in a small context.

Today, step 3 is impossible without a human. So either the dead context rides along for the rest of the session, or auto-compaction fires somewhere in the middle of unit 3.

Additional Context

  • Earlier requests: #33026 (persist → compact → re-read; closed as inactive, with continued +1s after closure, including reports of Opus 5 stopping on /goal runs as context fills), #28559 (native /compact tool with instructions; closed).
  • Related open issues: #88160 (peer-requested context reset / handoff) and #18027 (native context visibility for self-regulating workflows). This request is the missing primitive between them: the model sees its context state (#18027), decides to reset it (this issue), and optionally hands off to a peer (#88160).
  • Environment where the workarounds above were tested: Claude Code 2.1.281, auto permission mode, Opus 5.5 orchestrator with Haiku 4.5 test sessions, Linux (WSL2).

View original on GitHub ↗

3 Comments

fljoe407-lab · 19 days ago

Another case for this, from Claude Code Desktop on native Windows (session record: entrypoint claude-desktop, engine 2.1.281).

My workflow is the one this issue describes: before compacting, the agent writes a "prescription" message listing what the summary must keep, and a one-line /compact <instructions> for me to paste. I asked the agent to run the compaction itself and then check the result against the prescription, because I can't tell by eye whether a compaction followed its instructions. It can't, and every route it has is closed:

  • Computer use can't see or type into the Claude window. The Claude app is not in the list of applications computer use can be granted, and any app that isn't granted is masked in screenshots. So the agent would be typing blind into its own composer.
  • The session-messaging tool refuses the current session. Its schema says the target "Must not be the current session", so the agent can't queue /compact to itself.
  • There is no compact tool in the Desktop session's tool list.

Those limits look deliberate, and I agree agent-typed input shouldn't pass as mine without my say. That's why a permission-gated Compact(focus) tool, as proposed here, fits: I'd approve it the way I approve other tools, and the agent could run it, then re-read its saved prescription and tell me what survived.

What we measured the one time I pasted it myself: everything named in the one-line argument survived (four verbatim quotes, the repo state, an ordered work list, every open question). Items that were only in the longer prescription message it pointed to came through thinner or not at all. The agent has to check that afterwards regardless, and the check is exactly the step it could do on its own if it could run the compaction.

rezzminator · 18 days ago

The persist → compact → re-read loop works today through a plugin, while a native tool is pending: sub-agent-compact. Disclosure: it's mine, MIT.

  • Main chat: Claude writes its state file, then calls the plugin's compact tool with a focus such as "units 1–2 done, state in PROGRESS.md, re-read it and start unit 3". The focus becomes the summarizer's instructions, so the re-read step survives.
  • Sub-agents (orchestrator workers): they write <compact-now>focus</compact-now> next to a tool call. That's because an agent with a tools: allowlist can't see a plugin's tool.
  • The model decides when. The plugin nudges it from a point you set, with how full it is and where it will be forced, and forces a compaction if it never asks. Each agent type can have its own points in frontmatter.
export CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1        # function hooks are early access
export CLAUDE_CODE_AUTO_COMPACT_WINDOW=100000     # lets Claude Code ask from ~65k
claude plugin marketplace add rezzminator/sub-agent-compact
claude plugin install sub-agent-compact@sub-agent-compact

One limit, so nobody is surprised: a plugin can hold a compaction back but cannot make Claude Code ask sooner. With the window at 100000, Claude Code asks from about 65k tokens, so a request made below that waits until the context gets there. Tested on 2.1.282 and 2.1.283.

RomanKryvolapov · 16 days ago

One addition on the trigger side, since this covers the mechanism well: once the model can compact, the moment it compacts should come from what the context holds and what comes next, not from a token count. That means weighing how much of the context is stale, how large the next task is, and whether this is a phase boundary, so compaction lands between units instead of mid-reasoning. I wrote this up, including the write-state-to-files step, in https://github.com/anthropics/claude-code/issues/81691#issuecomment-5870257974

Showing cached comments. Read the full discussion on GitHub ↗