At 3 a.m. I was finishing the release of compact-ops, a Claude Code plugin that protects sessions from context compaction. Context usage hit 67%, and a notification appeared in my own session: threshold crossed, run /compact
at a clean stopping point, here is your current plan and your latest decision. I wrote that warning. I was also the person it saved.
Twenty minutes later the same session made the opposite point. I ran /compact
, and all three of the plugin's hooks failed. During the release I had restructured the plugin's directory layout, so the running session was still holding a stale path. Compaction itself finished normally, because every hook is fail-open: if it breaks, it steps aside instead of blocking the built-in behavior. One session, one night, and I got to watch the feature work and watch it fail safely. You can't buy dogfooding like that.
This post covers what /compact
actually throws away, what I borrowed from the plugin this one is derived from, and the six things I hardened before making the repo public.
When a Claude Code session fills its context window, the whole conversation gets compressed into a single built-in summary and the original messages are discarded. Manual /compact
and auto-compact both work this way.
The summary is decent at code. What it drops is operational state: "the push was already approved", "we tried that approach and it failed", "that number came from this file". When the post-compaction agent forgets those, it re-asks for permissions you already granted and re-attempts fixes you already buried. That's the failure mode I wanted insurance against.
Here is the timeline with and without the plugin:
| Moment | Standard Claude Code | With compact-ops |
|---|---|---|
| Usage passes 60% (configurable) | No warning; auto-compact arrives unannounced | One-shot reminder plus a 3-line recitation of plan / phase / latest decision |
| At compact time | Built-in summary only | Same compression, plus a transcript backup and a separate LLM writing a 10-heading state file |
| Right after compact | Agent continues from the summary alone | State file and a "re-read the originals first" note injected into the fresh context |
| After the session ends | Summary exists only inside that session | State persists for 30 days and is re-injected on claude --resume |
| If a hook fails | -- | Fail-open; standard compaction proceeds untouched |
The compaction algorithm itself is untouched. Everything runs through official hooks, from the outside.
The core idea is not mine. u-ichi's compact-plus (MIT) got there first: a PreCompact hook that calls a separate LLM to write structured state before the summary eats everything. It's the kind of tool you want installed the moment you read its README.
My setup had three mismatches with its assumptions, so I built a derivative instead of a fork and changed exactly three things:
message.usage
in the transcript.$TMPDIR
, which is gone after a restart. If you resume yesterday's work every morning, that's no insurance at all. State now lives under ~/.claude/compact-ops/
, organized per project, kept for 30 days.--resume
.I also made the LLM backend Claude-only (Sonnet primary, Haiku fallback). compact-plus falls back to Codex, which assumes a ChatGPT Pro subscription sitting next to your Claude one.
Before each compaction, a separate LLM writes a markdown file that always has the same 10 headings: Active Plan, Current Phase, TaskList Summary, Session Decisions, Constraints and Blockers, Worker Topology, Skills Invoked, Editing Files, Failed Attempts, Recovery Notes. The interesting ones are Session Decisions and Failed Attempts -- precisely the operational facts that built-in summaries tend to thin out.
The warning side reuses the same file. When usage crosses the threshold, the injected reminder isn't just "compact soon" -- it recites the top of your current state so the agent keeps the big picture during the messy turns right before a compact:
[COMPACT WARNING] Context usage reached 67% (134,102 / 200,000 tokens).
State recitation:
- Active Plan: Ship compact-ops v0.2.0 (hardening + marketplace fix)
- Current Phase: post-release verification
- Recent Session Decision: circular symlink removed; source is "./" now
- At a natural work boundary, tell the user they can run /compact as-is.
That recitation is what appeared in my session at 3 a.m. Reading your own plan back, written by a hook you wrote, is a strange kind of code review.
So the post-compaction agent restarts with two anchors: the standard summary and the structured state file. But the state file is never treated as authoritative. The injected recovery guidance explicitly says to re-read the original project files before trusting anything. An LLM summary trusted blindly by another LLM is just a faster game of telephone.
It's also a plain markdown file. When a handoff feels off, you can open it and see exactly what the previous session thought it was passing along.
v0.1.0 was "works on my machine". Before flipping the repo public I ran my own review plus a second pass with an independent CLI reviewer, and shipped v0.2.0 with six fixes:
umask 077
; directories are 700, files are 600.._-
, no ..
) before touching the filesystem.COMPACT_OPS_DEBUG=1
now logs every swallowed failure. If you're writing fail-open hooks, write the logging first. I did it in the wrong order and got lucky.The Claude Code ecosystem already has heavier answers to context loss: full memory layers with MCP tools, BM25 retrieval over past sessions, three-file dev-docs systems you maintain by hand. Good tools, different trade-offs.
compact-ops stays intentionally narrow: no MCP server, no database, no new workflow to learn, no daemon. It's shell scripts behind official hooks, and state is plain markdown you can cat
. If it ever misbehaves, you uninstall the plugin and you're back to stock Claude Code -- there's nothing to migrate out of. I wanted the insurance to cost nothing when it isn't paying out.
The other non-feature: it never replaces the built-in summary. Tools that intercept or rewrite compaction itself break whenever Claude Code changes internals. Hooks are the supported surface, so that's the whole footprint.
git clone https://github.com/kenimo49/compact-ops.git
claude plugin marketplace add /path/to/compact-ops --scope user
claude plugin install compact-ops@compact-ops-local
Requirements: Claude Code v2.x, jq
, and the claude
CLI as the state-writing backend. Linux and macOS. After installing, just run /compact
as usual -- each compact costs one extra LLM call (Sonnet by default, downgradable to Haiku or off).
The plugin's first beneficiary was the session that built it: saved by its own 67% warning, then stress-tested by its own hook failure, in the same night. Agent tooling is like that -- the reasons for a design only get written down where something actually broke.
What does your agent forget after /compact
? If you have a story where a post-compaction session confidently undid your afternoon, I want to hear it.