[FEATURE] Mods: pass images and hidden context rows to session.compact so a hook does not drop them
Preflight Checklist
- [x] I have searched existing requests and this feature hasn't been requested yet. The closest, #16592, asks for raw pasted image data in UserPromptSubmit hooks. This request is about what a
session.compacthook receives and can keep. - [x] This is a single feature request (not multiple features)
Problem Statement
A session.compact function hook (Claude Code 2.1.289, macOS arm64, CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1, mod loaded from a plugin) receives messages: SessionMessage[] with text and tool blocks only. Part of what the model saw is not in that list, so any hook that returns { messages } removes it from context:
| Lost when a hook compacts | In the transcript | Lost in 66 real compactions |
|---|---|---|
| Pasted images | image blocks on user rows | 76 of 76 |
| Images inside tool results | image blocks in tool_result | 424 of 424 |
| Prompts typed while a turn runs | attachment rows, queued_command | 144 of 150 |
| Subagent hand-backs, other sessions | isMeta user rows, origin.kind: peer | 441 of 441 |
| Scheduled prompts | isMeta user rows | 76 of 76 |
These are 66 compactions by one session.compact mod, 28-09 to 07-10-2026, counted from the transcripts before and after each compact_boundary.
After the compaction the model works without the screenshot the user just pasted, or the instruction they typed mid-turn, and nothing tells it that these are gone.
Proposed Solution
Let session.compact see and keep everything the model saw, with additive, optional fields, so existing hooks behave exactly as today:
type SessionMessage = {
role: Role; text: string; toolUses: ToolUseSummary[];
toolResults?: ToolResultSummary[]; handle?: string;
// new, optional
content?: ContentBlock[]; // image and document blocks in order (base64, or a durable file ref)
meta?: { kind: 'attachment' | 'meta'; origin?: PromptOrigin; attachmentType?: string };
};
event.messagescarries non-text blocks incontent, and includes hidden rows (attachments, isMeta rows) in transcript order withmetaset.- A message a hook returns with
contentis written back with those blocks. A hidden row returned with itsmetakeeps its kind and origin framing.
Acceptance:
- Paste an image, then compact with a hook that returns
event.messageswith old tool output trimmed. After--resume, the model still sees the image. - Type a prompt while a long Bash call runs, then compact the same way. The prompt is still in context, with its origin.
- A subagent hand-back from before the compaction is still in context after it.
- Hooks that ignore the new fields behave as today.
Alternative Solutions
What a mod can do today, and where it falls short:
- Record deliveries in
prompt.submitandsession.receive, then write them back as plain text at compaction. Images and the engine's origin framing are lost, and the mod has to dedupe, anchor and retire its own records. - Keep the engine
handleon plain user prompts that carried an image. A handle on atool_resultrow undoes the compaction on--resume(#95328, #96485), so images inside tool results can only become a text pointer to a file, and pasted-image files under/private/tmpare gone after a reboot.
Priority
High - Significant impact on productivity
Feature Category
Developer tools/SDK
Use Case Example
- I paste a screenshot of a broken layout and ask Claude to fix it.
- Context passes 60%. My
session.compactmod compacts early: it trims old tool output and keeps every message word for word. - On the next turn the screenshot is gone. Claude asks for it again, or guesses.
The same happens to "stop, use the other config" typed during a long build, and to a background agent's report that arrived just before the compaction.
Additional Context
- Measured on Claude Code 2.1.274 to 2.1.289, macOS arm64, in the desktop app and in
claude -p. - Live probe: keeping
handleon the image prompt keeps the image through two rounds of compact plus--resume. Keeping it on atool_resultrow brings back the uncompacted history (the same bug as #95328). - Related, not duplicates: #16592 (raw pasted image data for UserPromptSubmit hooks; a different event and need), #95328 and #96485 (resume bugs that force hooks to drop handles).