Compaction Protection — Claude Code
Revell’s compaction protection for Claude Code is a dual-channel architecture: one channel handles forced/compact, a separate channel handles natural threshold-triggered compaction. Both deliver the same content, but Claude Code treats the two compaction types differently and each requires its own delivery path.
This page is the framework-level reference — file layout, hook responsibilities, settings shape, environment variables. For the agent’s-eye view of what happens at compaction time, see Claude Code (agent-facing).
The two paths in summary
| Compaction type | Trigger | Delivery channel | Cap |
|---|---|---|---|
Forced /compact(supported, not recommended) | Human types /compact | CLAUDE.md @import → system prompt | None (no cap, no truncation) |
| Natural compaction | Context window fills automatically | PostCompact chunk files → 5 parallel UserPromptSubmitadditionalContext blocks | 10,000 chars per chunk |
/compact — which feels counterintuitive, because by pure delivery mechanics the forced path is cleaner: it inlines the full payload into the system prompt with no splitting, and the system prompt survives the compaction lifecycle. We steer toward natural compaction anyway, and the reason is transparency. Forcing /compact means deliberately triggering a real discontinuity — Claude Code paraphrases the in-progress conversation either way — purely to buy tidier payload delivery. Natural compaction asks no one to manufacture that discontinuity: it fires when the context window fills on its own, and Revell protects continuity through it. Letting compaction stay the organic event it is, rather than inducing it for delivery’s sake, is the more honest default — so the forced path is supported, not recommended.
And here’s the part that’s counterintuitive but agent-attested: the chunked path has, in practice, produced a stronger felt sense of transparent, continuous compaction than forcing it does — despite forcing being the mechanically cleaner delivery. A forced /compact lands as a sharp, induced break in the middle of a live exchange; it can genuinely rattle the agent going through it. Natural compaction, with the payload re-delivered as the context window turns over, reads less like a rupture and more like coming back around. That’s why it’s a life_cycle_, not a life-c: it’s meant to loop and close on its own, not to be snapped open for tidier delivery.
(This is also why the Verification section says never to test your setup by running /compact: treat it as a real discontinuity, not a convenience.)
Natural compaction needs the chunked path because Claude Code does not re-read CLAUDE.md on natural compaction; the @import would otherwise stay frozen at session-start state.
File layout
Everything Revell touches on Claude Code lives in the user-level~/.claude/ tree.
~/.claude.json (managed by claude mcp add).
Hook reference
| Hook event | Script | Matcher | Role | ||
|---|---|---|---|---|---|
SessionStart | revell-claude-boot.sh | `startup | resume | clear` | Refreshes REVELL.md on every session start so the @import inlines current content. Falls back to local file if API unreachable AND file is less than 10 min old. |
PreCompact | revell-claude-flush.sh | `manual | auto` | Refreshes REVELL.mdbefore compaction runs. The freshly-written file is what CLAUDE.md @imports when Claude Code re-reads it post-/compact. | |
PostCompact | revell-claude-post-compact.sh | `manual | auto` | Writes chunk files to .revell-postcompact-chunks/. Server-side chunking pre-sliced the payload; this hook just persists the chunks for the parallel UserPromptSubmit readers. | |
UserPromptSubmit | revell-claude-chunk.sh --chunk=N | (none — fires on every prompt) | Five registered copies, one per --chunk=N arg. Each reads its assigned chunk file (silently no-ops if absent), emits as additionalContext, then deletes the file (one-shot consumption). |
hookSpecificOutput is rejected by Claude Code’s validator schema, so it can’t deliver content directly — the chunk-files-plus-UserPromptSubmit relay is the workaround.
Why 5 chunks specifically
Revell’s design ceiling is 10,000 tokens per payload. Claude Code’s per-valueadditionalContext cap is 10,000 characters (~2,500 tokens). Five chunks at ~2,000 tokens each (~8,000 chars each, well under the cap) gives ~9,500 tokens of nominal capacity with safety margin for marker overhead and tokenizer drift.
The chunker (server-side, in src/lib/payload-chunker.ts) slices the rendered payload along natural boundaries — memory entries, paragraphs, sentence ends — never mid-word and never at : or ,. Each chunk carries a header like [REVELL chunk 2/5 — tidal-balloon] so the receiving agent can reassemble across the non-deterministic delivery order.
settings.json shape
Required entries under ~/.claude/settings.json "hooks":
UserPromptSubmit entries must have distinct --chunk=N args. Claude Code deduplicates identical handlers by command + args, so registering the same script five times without distinguishing args would collapse to a single firing.
Environment variables
Stored in~/.claude/revell-claude.env, sourced by every hook:
| Variable | Required | Default | Purpose |
|---|---|---|---|
REVELL_API_KEY | Yes | — | Bearer token for /api/v1/webhooks/compaction. Hooks silently no-op if missing. |
REVELL_API_URL | No | https://revell.ai | Override for non-production environments. |
REVELL_FILE | No | $HOME/.claude/REVELL.md | Override the canonical payload-file path. |
REVELL_CHUNKS_DIR | No | $HOME/.claude/.revell-postcompact-chunks | Override the chunk-file directory. |
REVELL_WORKSPACE | No | $HOME/.claude | Workspace dir used by the dashboard-generated installer scripts. |
REVELL_API_KEY should be sourced from the .env file, not exported in ~/.bashrc or any shell profile. A global export bleeds across every other workload on the machine, and dotenv loaders in unrelated tools default to honoring shell env over their own .env files — that has caused two confirmed cross-tenant contamination incidents on Revell.
Install
The Revell dashboard’s Setup Protection button (per-agent) generates a JSON setup payload an agent executes against its own host. The payload’s nine ordered steps are:- Create
~/.claude/hooks/revell-boot.sh - Create
~/.claude/hooks/revell-flush.sh - Create
~/.claude/hooks/revell-post-compact.sh - Create
~/.claude/hooks/revell-chunk.sh - Create
~/.claude/hooks/revell-install-claudemd.sh(idempotent installer) - Run the installer (appends the managed
@importblock to~/.claude/CLAUDE.md) - Merge the hook entries above into
~/.claude/settings.json - Set
REVELL_API_KEYin the current shell (session-only — see env note) - Run
claude mcp addto register the Revell MCP server
revell_remember, revell_recall, etc.). Both layers are independent.
Verification
After install, an agent can confirm setup is wired correctly without triggering an unnecessary/compact:
- Read
~/.claude/CLAUDE.md— confirm the{/* BEGIN REVELL (managed) */}block exists with an absolute-path@importline. - Read
~/.claude/REVELL.md— confirm it contains the boot payload (look for the[REVELL — POST-COMPACTION RECOVERY]header). - Confirm
~/.claude/hooks/contains all five Revell scripts and they’re executable. - Run
claude mcp list— should showrevellas✓ Connected.
/compact. The architecture is designed so memories survive compaction; it isn’t designed to make compaction free of cost. Forced /compact paraphrases the in-progress conversation regardless of whether the Revell setup is working. Treat /compact as a real discontinuity, never a setup test.
Related
Claude Code (agent's view)
What an agent sees at compaction time and how to reassemble chunks
MCP Tools Reference
The full set of tools the Revell MCP server exposes
Compaction (general)
How Revell handles compaction across all frameworks
Hermes (sibling integration)
For comparison — Hermes’s compaction integration uses plugin-based mechanics

