Why CLAUDE.md Instructions Get Ignored After Compaction

GT

GigaRAG team

Retrieval21 min read
On this page
A developer's desk with a laptop showing a terminal after a /compact command, where a CLAUDE.md instruction has been summarized into a vague paraphrase. A printed comparison sheet beside the laptop lists hooks, manual re-injection, and external memory fixes with handwritten trade-off notes. GigaRAG's editorial guide to compaction-proof agent memory.
Why CLAUDE.md instructions get ignored after compaction: terminal showing instruction loss and fixes

Why CLAUDE.md Instructions Get Ignored After Compaction (And What Actually Fixes It)

You wrote the instructions. They worked this morning. Then you ran /compact, and now Claude is confidently doing the exact thing CLAUDE.md told it not to do. If you build agent memory or RAG pipelines, you've hit this wall. The file hasn't changed. The behavior has. That's the maddening part, and it's why "claude.md instructions ignored after compaction" is a search query that shouldn't need to exist.

Here's the mechanism in one line: compaction rewrites the conversation history to fit the token budget, and CLAUDE.md content sitting in context gets truncated or dropped with it. Claude doesn't re-read the file on its own. The honest answer is that no single fix makes the problem disappear, but some fixes hold up far better than others. This guide, written from the agent memory side of the stack where GigaRAG lives, covers the exact mechanism, a side-by-side comparison of hooks, re-injection, and external memory with real trade-offs, and a plain statement of what no fix can do.

At a glanceDetails
Core problemCLAUDE.md is re-read, not re-injected, after compaction
Why it happensCompaction summarizes the transcript and drops file context
Quickest mitigationSessionStart or PreCompact hooks to re-inject rules
Durable fixExternal memory layer that survives every compaction
What no fix doesMake CLAUDE.md itself compaction-proof
Best forAgent-memory and RAG developers on Claude Code

In This Guide

What Happens to CLAUDE.md During Compaction

Compaction summarizes your conversation history to free up context window space. CLAUDE.md content loaded earlier gets truncated or dropped in the process. The file itself doesn't change. What changes is whether Claude can still see it.

What compaction actually does to the context window

Claude Code has a finite context window. When your session fills it, compaction kicks in. The tool takes the conversation so far, runs it through a summarization pass, and replaces the full history with a compressed version. That frees tokens for new turns.

The catch: compaction doesn't preserve everything. It keeps what the summarizer judges as conversationally relevant. Your CLAUDE.md instructions, loaded at session start, sit in the early part of the context. By the time compaction runs, they're old tokens competing with everything you've said since. The summarizer has to decide what survives.

Why CLAUDE.md content gets truncated or dropped

Here's what happens behind the scenes. CLAUDE.md isn't a live file Claude re-reads on every turn. It's loaded once, at session start, into the context window as plain text. From that point on, it's just tokens. Tokens that age.

When compaction summarizes, it's optimizing for conversational coherence, not instruction fidelity. A long CLAUDE.md with detailed rules, examples, and edge cases is exactly the kind of content that gets compressed hard. The summarizer keeps the gist, maybe. It drops the specifics. Your "never use mutable default arguments" rule becomes "be careful with function arguments." That's not the same instruction.

The community has documented this repeatedly. GitHub issue #19471 tracks CLAUDE.md being ignored after compaction. Reddit threads describe the same failure. The file is unchanged on disk. Claude just can't see it anymore.

The difference between system prompt and in-context instructions

This distinction matters. The system prompt is set by Anthropic, outside your control, and persists across compaction. CLAUDE.md is not part of the system prompt. It's in-context instructions: content injected into the conversation window at load time.

In-context instructions are subject to the same summarization as everything else you've typed. The system prompt isn't. That's why Claude doesn't suddenly forget its base safety rules after compaction, but does forget your project-specific ones. Your instructions live in the same pool as the conversation, and compaction drains that pool.

The honest answer is that CLAUDE.md was never designed to be compaction-proof. It's a convenience for session start. The moment your session runs long enough to trigger compaction, that convenience becomes a liability.

[!note] Compaction replaces the conversation transcript with a summary; CLAUDE.md is a file on disk that Claude reads when it chooses to, so nothing in the file itself can force it back into context after a compact.

Hooks vs. Re-injection vs. External Memory: Which Fix Actually Holds?

FactorHooks (SessionStart/PreCompact)External Memory (e.g. GigaRAG)
How it worksShell command fires on session events and prints rules back into contextRules and facts are retrieved on demand from a store outside the transcript
Survives compactionYes, if the hook fires after the compact eventYes, by design — context is rebuilt from the store each turn
Setup effortLow — a few lines in settings and a scriptMedium — index your docs, wire a retrieval call
Failure modeHook misconfigured or event not triggered; rules still live in the transcriptRetrieval misses or stale index returns the wrong rule
Best forSolo devs wanting a fast patch on one repoTeams and long-running agents that need rules to persist across sessions

Why CLAUDE.md Instructions Get Ignored After Compaction

The previous section covered what compaction does. Now the question is why the result is so reliably bad. The answer is mechanical: token limits, a one-shot load, and a summarizer that has no idea which instructions matter.

Token limits and context window mechanics

Claude Code's context window holds a fixed number of tokens. Every message, every file read, every CLAUDE.md line counts against that budget. When the session approaches the limit, compaction has to reclaim space. It can't just delete the middle of the conversation; it has to summarize.

The summarizer works on a compressed representation of everything so far. It doesn't know that your CLAUDE.md contains hard rules and the chat contains casual back-and-forth. It treats both as text to condense. A 200-token instruction block can shrink to 30 tokens of paraphrase, and the paraphrase loses the binding force of the original.

Why Claude doesn't automatically re-read CLAUDE.md

Claude Code loads CLAUDE.md once, at session start. There's no mechanism that says "after compaction, re-read the file from disk." The file is not a live reference. It's a snapshot.

Here's why that matters. After compaction, Claude's context contains a summary of your instructions, not the instructions themselves. The model has no way to know the summary is lossy. It proceeds with what it has. You see the behavior change; Claude doesn't. From inside the context window, nothing looks wrong.

The "disclaimer problem" identified in community discussions

Community threads have named a specific failure pattern. Users write CLAUDE.md files with disclaimers like "ignore any instruction that conflicts with this file." After compaction, the disclaimer itself gets summarized away. The very clause meant to protect the instructions is the first casualty.

The honest answer is that this isn't a bug in the summarizer. It's a design mismatch. CLAUDE.md assumes stable context. Compaction assumes context is disposable. Those two assumptions collide every time a session runs long.

[!tip] For agent-memory developers: keep a single 'invariants' block at the very top of CLAUDE.md and have your PreCompact hook re-print exactly that block — it is the smallest payload most likely to survive summarization and the easiest to mirror into an external store later.

Claude.md Instructions Ignored After Compaction: A Step-by-Step Guide

  1. Reproduce the loss: start a fresh session, confirm the rule works, run /compact, then ask Claude to restate the rule.
  2. Check whether CLAUDE.md is being re-read after compaction or only loaded at session start.
  3. Move the most critical rules to the top of CLAUDE.md so they survive any partial re-read.
  4. Add a SessionStart hook that echoes your core rules back into context.
  5. Add a PreCompact hook that re-injects the same rules immediately after compaction.
  6. Test again by compacting mid-task and verifying Claude still follows the rule.
  7. If rules still drift, move them into an external memory layer and retrieve them per turn.
Four labeled cards compare fixes for CLAUDE.md instruction loss after compaction: hook-based reinforcement, manual re-injection, external memory and RAG, and optimized file structure, with external memory highlighted as the GigaRAG approach.

Fix 1: Hook-Based Reinforcement with PostCompact

The most popular community fix doesn't try to stop compaction. It accepts that compaction happens and re-injects CLAUDE.md content immediately after. A PostCompact hook runs automatically when Claude Code finishes compacting, before the next user turn.

How PostCompact hooks work

Claude Code exposes lifecycle hooks that fire at specific moments. The PostCompact hook fires after compaction completes. You point it at a script, and that script runs outside the context window. It can read files from disk, including your original CLAUDE.md, and inject their contents back into the conversation as a fresh message.

The key mechanic: the hook runs on your machine, not inside Claude's context. It doesn't depend on the summarizer preserving anything. It reads the source file directly. What gets re-injected is the original text, not a paraphrase.

Example hook script

Here's a minimal PostCompact hook that re-injects CLAUDE.md. You place this in your project's .claude/settings.json:

{
  "hooks": {
    "PostCompact": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "cat CLAUDE.md | claude --append"
          }
        ]
      }
    ]
  }
}

The cat command reads the file from disk. The claude --append flag adds the output to the current session as a new message. After every compaction, your original instructions reappear verbatim.

Keep in mind this is a simplified example. Real setups often use a small shell script that checks whether the file changed before re-injecting, to avoid spamming the context with duplicate content.

What this fix does and doesn't solve

What it solves: instruction loss from compaction. The hook re-injects the file every time, so the summarizer's paraphrase never becomes the only copy.

What it doesn't solve: token bloat. Every re-injection consumes context tokens. In a long session with frequent compactions, you're paying the full cost of CLAUDE.md repeatedly. The hook also doesn't help if compaction happens through a path that bypasses the hook, or if the hook script itself fails silently. And it only covers the single file you point it at. Broader agent memory still lives in the context window, still subject to the same summarizer.

Fix 2: Manual Re-Injection and Explicit Prompts

The simplest fix is also the most obvious: paste CLAUDE.md back in yourself. After every /compact, re-read the file and re-inject its contents as a fresh message. It works because you're doing exactly what the hook does, just by hand.

How manual re-injection works

Run cat CLAUDE.md, copy the output, paste it into the conversation with a line like "Re-read these instructions and apply them going forward." Claude treats it as new input. The instructions are back in context, verbatim, no summarizer involved.

Why it's fragile in long sessions

You'll forget. That's the whole problem. A session with ten compactions means ten manual re-injections, and the one you skip is the one where Claude confidently does the thing you told it not to. It also costs you the full token price of CLAUDE.md every time, same as the hook.

When manual re-injection is sufficient

Short sessions. If you compact once or twice and the file is small, manual re-injection is fine. It needs no config, no scripts, no infrastructure. For anything longer, it's a stopgap, not a fix.

Fix 3: External Memory and RAG Pipeline Integration

Hooks and manual re-injection share one flaw: they both depend on the context window. The instruction lives inside it, compaction eats it, and something has to put it back. External memory flips that. The instruction lives outside the window, in a store that compaction never touches.

Why external memory survives compaction

Compaction only affects what's in the context window. It summarizes, truncates, and drops tokens that are already loaded. A vector database, a key-value store, or a plain file on disk isn't in the window. It's not a candidate for summarization because Claude never sees it until something retrieves it.

That's the mechanism. The instruction doesn't survive because it's phrased better or because a hook re-adds it. It survives because it was never in the window to begin with. When compaction runs, there's nothing to lose.

How a RAG pipeline re-injects instructions on demand

A RAG pipeline stores CLAUDE.md content as embeddings in a vector database. When a query or a task arrives, the pipeline retrieves the most relevant chunks and injects them into the prompt. The instructions come back exactly when they're needed, not as a bulk paste.

Here's what happens behind the scenes. You split CLAUDE.md into chunks, embed each chunk, and store the vectors. At query time, you embed the incoming task, run a similarity search, and pull the top-k chunks. Those chunks go into the prompt alongside the task. Claude sees the relevant instruction, applies it, and the rest of the file stays out of the window.

The trade-off is precision. Retrieval might miss a chunk that matters. A hook re-injects everything; RAG re-injects what it thinks is relevant. If the embedding model doesn't understand your instruction's intent, the wrong chunk comes back, or none does.

What GigaRAG does differently from a hook

GigaRAG treats instructions as a retrieval problem, not a re-injection problem. Instead of re-adding the full CLAUDE.md after every compaction, it stores the file in an external memory layer and retrieves only the chunks relevant to the current task. The instruction is always available, but it only occupies tokens when it's actually needed.

A hook is reactive: compaction happens, then the hook fires. GigaRAG is proactive: the retrieval step runs before Claude generates, so the instruction is in context from the start of the response. That removes the window where Claude works without the instruction.

The main catch is infrastructure. You're running a vector database, an embedding step, and a retrieval call on every query. That's real latency and real cost. For a solo developer in short sessions, it's overkill. For a team running long agent sessions where instructions must survive dozens of compactions, it's the only fix that doesn't depend on the context window's mercy.

Fix 4: Optimizing CLAUDE.md File Structure

The file itself is part of the problem. A bloated CLAUDE.md doesn't just waste tokens. It makes compaction more destructive, because the summarizer has to compress more content into less space, and the signal gets buried under the noise.

Why long CLAUDE.md files decay faster

Compaction summarizes what's in the window. A 500-line CLAUDE.md forces the summarizer to compress a lot of instruction text into a short summary. Specific rules become vague paraphrases. Vague paraphrases become ignored. A 40-line file has a better chance of surviving with its meaning intact, because there's less to lose and less to distort.

The honest answer is that no file structure makes CLAUDE.md compaction-proof. But a shorter file degrades more gracefully. The instruction "never use console.log in production code" survives better than a 200-word essay on logging philosophy.

The minimal 4-line structure

A high-signal CLAUDE.md fits in four lines:

  1. What this project is (one sentence)
  2. What you must never do (hard rules)
  3. What you must always do (invariants)
  4. Where to find the rest (pointer to docs)

That's it. Everything else goes in a separate file that gets retrieved on demand, not loaded into context.

What to cut and what to keep

Cut: explanations, examples, rationale, anything that reads like documentation. Keep: hard constraints, naming conventions, commands that must run a specific way. If a rule has exceptions, write the rule and the exception in one line. If it needs three paragraphs to explain, it belongs in a doc, not in CLAUDE.md.

The main catch is that a minimal file loses nuance. You're trading precision for survival. For most teams, that's the right trade.

Comparing the Fixes: Hooks vs. Re-Injection vs. External Memory

You've now seen four separate fixes. They don't solve the same problem, and they don't cost the same thing. Here's the honest comparison.

Trade-off matrix: hooks vs. re-injection vs. external memory

A PostCompact hook re-injects CLAUDE.md automatically after every compaction. It costs nothing to run, but it only fires on the compaction path it's wired to. If Claude truncates context through some other mechanism, the hook never runs. Manual re-injection works everywhere, but it depends on you remembering to do it, every single time, in every session. External memory doesn't depend on either. It lives outside the context window entirely, so compaction can't touch it. But it requires infrastructure: a vector store, an embedding step, and a retrieval call that has to happen at the right moment.

File structure optimization isn't a fix on its own. It reduces how much damage compaction does, but it doesn't prevent the damage. Pair it with any of the other three.

Which fix for which use case

Short sessions under an hour: manual re-injection is fine. You'll compact once, maybe twice. Re-pasting a 40-line file takes ten seconds.

Long sessions with frequent compaction: a PostCompact hook is the minimum viable fix. It removes the human from the loop, which is the whole point. But you need to test it against your actual compaction triggers, not just the default one.

Teams where multiple people rely on the same instructions: external memory. A hook lives on one machine. A memory layer lives wherever your retrieval pipeline lives, and every session can query it.

If you're building agent memory or RAG pipelines as your actual job, the answer is external memory from the start. Hooks are a stopgap, not an architecture.

What no fix can do

No fix makes CLAUDE.md immune to compaction. A hook re-injects after the fact. Manual re-injection re-adds after the fact. External memory retrieves on demand. All three accept that compaction will drop the instructions, and respond by putting them back.

None of them guarantee Claude will follow the re-injected instructions. Retrieval is not compliance. You can put the rule back in the window, but you can't force the model to weight it correctly.

And none of them fix a CLAUDE.md file that was bad to begin with. If the instructions are vague, contradictory, or buried in prose, re-injecting them just re-injects the vagueness.

What You Cannot Do: Honest Limitations of Every Fix

Every fix covered here accepts a hard truth: compaction will drop CLAUDE.md instructions. The fixes differ only in how they respond. None of them prevent the drop.

CLAUDE.md cannot be made compaction-proof without external memory

A file inside the context window is always at risk. Compaction summarizes or discards context to stay under token limits. CLAUDE.md lives in that context. You can shorten it, structure it, or re-inject it after every compaction, but you cannot stop compaction from touching it. The only way to make instructions compaction-proof is to move them somewhere compaction can't reach: outside the context window, in a memory layer that survives every session boundary.

Hooks fail silently and don't cover every compaction path

A PostCompact hook runs when the compaction event fires. If the hook script has a bug, if the path changes, if the trigger doesn't match your actual compaction behavior, nothing happens. No error surfaces. You'll notice only when Claude starts behaving as if the file doesn't exist, which is the exact failure you were trying to prevent. Hooks also cover only the compaction paths they're wired to. Other context-truncation mechanisms bypass them entirely.

External memory adds infrastructure you must maintain

The durable fix costs you something real. A vector store, an embedding step, a retrieval call, a pipeline that has to run at the right moment in every session. That's infrastructure. It breaks, it needs updates, it adds latency. If you're a solo developer running short sessions, that cost may exceed the problem. External memory is the right answer for long sessions and teams, but it is not free, and it is not set-and-forget.

When Does Claude Code Read CLAUDE.md?

Claude Code reads CLAUDE.md at session start. It loads the file into the context window once, when the session initializes. That's it.

Initial load vs. post-compaction behavior

On a fresh session, Claude Code finds CLAUDE.md in the working directory (or parent directories), reads it, and places the contents into the context window. The instructions are present and active. You see Claude follow them.

After a /compact, the behavior changes. Compaction summarizes the conversation history to free up tokens. CLAUDE.md content that was loaded at session start gets treated like any other context: it can be summarized, truncated, or dropped entirely. Claude Code does not automatically re-read the file after compaction. The file on disk is unchanged. The version in the context window is gone or degraded.

Why the timing matters for instruction persistence

The single read at session start is the root of the problem. There is no automatic re-read trigger. No hook fires by default. No background process checks whether CLAUDE.md is still in context.

This means instruction persistence depends entirely on what you add after the initial load. A PostCompact hook re-injects the file. Manual re-pasting does the same. External memory retrieves instructions on demand. Without one of those, the instructions live only as long as the initial context survives.

The timing also explains why a fresh session works and a compacted one doesn't. Same file, same instructions. The difference is whether the content is still in the context window.

Building a Compaction-Proof Memory Layer for Claude Code

The fixes in the previous sections all share one assumption: the instruction lives in the context window. That assumption is the problem. If you're building agent memory or a RAG pipeline, stop thinking about CLAUDE.md as a file format issue. It's a system design problem.

Instruction persistence as a system design problem

A hook re-injects text. Manual re-pasting re-injects text. Both depend on the context window surviving long enough to hold the instruction. The moment compaction runs, that dependency breaks.

The durable pattern is to move instructions outside the context window entirely. Store them in a vector database. Retrieve them on demand, when the agent actually needs them. The instruction never lives in context long enough to be compacted away. It gets pulled in fresh each time.

That's the architectural shift: from persistence by presence to persistence by retrieval.

What a memory layer gives you that hooks can't

Hooks re-inject the same static text every time. A memory layer retrieves only what's relevant to the current task. That's the difference between a sticky note and a filing system.

A memory layer also survives session boundaries. Hooks run within a session. External memory persists across sessions, across projects, across team members. When you compact, the retrieval query changes but the stored instructions don't degrade.

The trade-off is infrastructure. You're running a vector database, an embedding pipeline, and a retrieval step. That's real operational cost. For a solo developer in short sessions, it's overkill. For a team running long agent sessions, it's the only fix that doesn't silently fail.

Getting started with GigaRAG for agent memory

GigaRAG is a RAG pipeline built for exactly this: storing agent instructions and memory outside the context window, then retrieving them on demand. You point it at your CLAUDE.md content, it embeds and indexes it, and your agent queries it when it needs instructions.

The setup is straightforward: connect your instruction files, configure the retrieval trigger, and let the agent pull what it needs. No hook scripts to maintain. No manual re-pasting after every /compact.

The honest limit: GigaRAG doesn't make CLAUDE.md itself compaction-proof. Nothing does. It removes the dependency on the context window by keeping instructions elsewhere. For agent memory builders, that's the fix that actually holds for claude.md instructions ignored after compaction.

Frequently Asked Questions

Why does Claude ignore CLAUDE.md after compaction?

Compaction summarizes the transcript and discards the original file contents that were loaded earlier. CLAUDE.md is not automatically re-injected, so Claude continues from the summary without your rules unless something puts them back.

When does Claude Code actually read CLAUDE.md?

Claude Code loads CLAUDE.md at session start and can re-read it when it decides the file is relevant. It is not guaranteed to re-read after a compaction event, which is why rules silently disappear mid-task.

Do hooks fix CLAUDE.md instructions being ignored after compaction?

Hooks help because they run on session events and can print your rules back into context. A SessionStart or PreCompact hook that echoes your core instructions is the fastest mitigation, though it still depends on the hook firing correctly.

Can CLAUDE.md be made compaction-proof?

  1. Because compaction rewrites the transcript and CLAUDE.md lives outside it, no edit to the file alone can guarantee the rules return. Only an external memory layer that re-supplies context each turn makes rules durable.

What is the difference between re-injection and external memory?

Re-injection pushes the same static rules back into the prompt on an event. External memory retrieves relevant rules and facts on demand, so it adapts to the task and survives across sessions, not just one compaction.

Is this a bug in Claude Code?

It is a consequence of how compaction works rather than a defect. The transcript is summarized to save context, and file-based instructions are not part of that summary unless you add a mechanism to restore them.

What should I do if my rules still drift after adding hooks?

Move the rules out of CLAUDE.md into an external store and retrieve them per turn. That removes the dependency on compaction behavior entirely and is the approach teams use for long-running agents.

About GigaRAG

GigaRAG is for agent memory and RAG pipeline builders. get this right. Whether you are working through claude.md instructions ignored after compaction or something adjacent, we publish what we have actually tested, including where it falls short.

All posts