[FEATURE] Model-callable, permission-gated Compact tool for persist → compact → re-read workflows
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
/compactcan't be invoked by the model. Scheduled prompts (/loop,CronCreate) deliver them as plain text, per the scheduled-tasks docs. PreCompactandPostCompacthooks are informational only. They can't trigger compaction.- The model can't change its own auto-compact window.
/autocompactis a built-in command, and the auto mode classifier denies editingautoCompactWindowas self-modification. - A helper that types
/compactinto the session's own tmux pane is denied by the classifier ("Tmux Self Drive"). - A helper that starts a fresh headless successor session,
claude -pwith 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)
focusworks 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.
PreCompactfires withtrigger: "model"(or"tool"), thenPostCompact, thenSessionStartwith thecompactmatcher, 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 (
Compactin allow/ask/deny) and visible to the auto mode classifier. Users choose whether the agent may compact on its own. The default could beaskin manual mode andallowin 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 100kon 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):
- The owner hands Claude a TODO list with four independent units and leaves for several hours.
- Claude ships units 1–2 as PRs. They account for about 30% of context: diffs, test output, review back-and-forth.
- Units 3–4 touch unrelated code. Claude writes
.delegator/NEXT_SESSION.md(done, in flight, next step, decisions), commits it, then callsCompact(focus: "keep: PR stack #20–#22, budget left, next = unit 3"). - 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
/goalruns as context fills), #28559 (native/compacttool 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).
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
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:/compactto itself.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.
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.
compacttool with afocussuch 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.<compact-now>focus</compact-now>next to a tool call. That's because an agent with atools:allowlist can't see a plugin's tool.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.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