# Keep your agent's rules after /compact (Claude Code, Cursor, Codex)

> Compaction keeps what each tool reloads from disk and summarizes the rest: rules given in chat, path-scoped rules and nested rule files get lost. What survives in each tool (checked 2026-10-25), plus free hooks that re-add must-keep rules and task notes after every compaction.

Source: https://agentpromptsatoz.com/guides/survive-compact/ · License: free to use and adapt · Publisher: Agent Prompts A to Z

## What survives compaction (checked 2026-10-25)

- **Claude Code**. Kept: Project-root CLAUDE.md, unscoped .claude/rules, auto memory, the plan-mode plan, skill descriptions. Invoked skills come back capped at 5,000 tokens each (25,000 total). Lost or at risk: Rules you typed in chat, rules with paths: frontmatter, nested CLAUDE.md files (they come back only when Claude reads a file in that folder), and context earlier hooks added. Only up to five recently edited files are re-read. Source: https://code.claude.com/docs/en/context-window
- **Cursor**. Kept: Root AGENTS.md and rules with alwaysApply: true stay in context after a chat is summarized. Lost or at risk: Nested AGENTS.md files and file-scoped (globs) rules are attached once per conversation. After a summary they can drop out and later reads don't re-attach them (Cursor staff, Oct 19 2026). Source: https://forum.cursor.com/t/nested-agents-md-rules-vanish-after-summarization-and-cursor-thinks-theyre-still-there/175331
- **OpenAI Codex**. Kept: Current versions re-insert the initial context (including AGENTS.md instructions) into the history after compaction. An old bug where auto-compact didn't re-read AGENTS.md (issue #5772) is closed. Lost or at risk: Anything you only said in chat is at the mercy of the summary. You can replace the summary prompt with compact_prompt in config.toml. Source: https://developers.openai.com/codex/config-reference

## The 3-part fix

1. Move rules out of chat into the root CLAUDE.md or AGENTS.md; mark the must-keep ones with a keep-after-compact block.
2. Re-add them after every compaction with a Claude Code SessionStart hook (matcher compact), plus a .claude/NOW.md task file.
3. Check what still drops with compact_risk.sh and log each summary with a PostCompact hook.

## 1. Keep-after-compact block (AGENTS.md or CLAUDE.md)

````markdown
## How to work here
- Run pnpm test before saying done.

<!-- keep-after-compact -->
- Never edit files in migrations/. Ask first.
- Run pnpm test and paste the result before saying done.
- Work only on the task in .claude/NOW.md.
<!-- /keep-after-compact -->
````

.claude/NOW.md:

````markdown
# NOW (the agent updates this file after each step)
Task: auth refactor, step 3 of 5
Done: 1 token model, 2 login route
Next: fix the token refresh test, then step 4 (logout)
Decisions: keep JWT in httpOnly cookie; no new dependencies
````

## 2. .claude/settings.json

````json
{
  "hooks": {
    "SessionStart": [
      {
        "matcher": "compact",
        "hooks": [
          { "type": "command", "command": "sh", "args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/after_compact.sh"] }
        ]
      }
    ],
    "PostCompact": [
      {
        "hooks": [
          { "type": "command", "command": "python3", "args": ["${CLAUDE_PROJECT_DIR}/.claude/hooks/log_compact.py"] }
        ]
      }
    ]
  }
}
````

## 3. .claude/hooks/after_compact.sh

````sh
#!/bin/sh
# after_compact.sh - Claude Code SessionStart hook (matcher "compact").
# Free from https://agentpromptsatoz.com/guides/survive-compact/ (MIT-style: use and adapt).
# Prints plain text; Claude Code adds a SessionStart hook's stdout to the
# compacted context. Read-only: it never writes or deletes anything.
# It re-adds: 1) the lines between <!-- keep-after-compact --> markers in
# AGENTS.md / CLAUDE.md, 2) .claude/NOW.md (your current task notes),
# 3) the git branch and short status. Output is capped under Claude Code's
# 10,000-character hook-output limit.
cd "${CLAUDE_PROJECT_DIR:-.}" 2>/dev/null || exit 0
MAX=9000
out=$(
  for f in AGENTS.md CLAUDE.md; do
    [ -f "$f" ] || continue
    block=$(sed -n '/<!-- keep-after-compact -->/,/<!-- \/keep-after-compact -->/p' "$f" | grep -v 'keep-after-compact -->')
    [ -n "$block" ] && printf '## Project rules from %s (kept after compaction)\n%s\n\n' "$f" "$block"
  done
  if [ -f .claude/NOW.md ]; then
    printf '## Current task notes (.claude/NOW.md)\n'; cat .claude/NOW.md; printf '\n\n'
  fi
  if command -v git >/dev/null 2>&1 && git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
    printf '## Git state after compaction\nBranch: %s\n' "$(git branch --show-current 2>/dev/null)"
    git status --short 2>/dev/null | head -n 20
  fi
)
[ -z "$out" ] && exit 0
printf 'This session was just compacted. The notes below come from files in the repo and are current.\n\n%s\n' "$out" | head -c "$MAX"
exit 0
````

## 4. .claude/hooks/log_compact.py

````python
#!/usr/bin/env python3
"""log_compact.py - Claude Code PostCompact hook. Saves each compaction summary
to .claude/compact-log/ so you can read what the summary kept and what it lost.
Free from https://agentpromptsatoz.com/guides/survive-compact/ . Writes only
inside .claude/compact-log/. Never blocks: always exits 0."""
import json, os, sys, time
try:
    data = json.load(sys.stdin)
    root = os.environ.get("CLAUDE_PROJECT_DIR") or data.get("cwd") or "."
    d = os.path.join(root, ".claude", "compact-log")
    os.makedirs(d, exist_ok=True)
    name = time.strftime("%Y%m%d-%H%M%S") + "-" + str(data.get("trigger", "unknown")) + ".md"
    with open(os.path.join(d, name), "w", encoding="utf-8") as f:
        f.write(data.get("compact_summary") or "(no compact_summary in hook input)")
except Exception as e:  # never break the session
    print(f"log_compact: {e}", file=sys.stderr)
sys.exit(0)
````

## 5. compact_risk.sh

````sh
#!/bin/sh
# compact_risk.sh - read-only check: which agent rules in this repo are likely
# to drop out of context after /compact (Claude Code) or summarization (Cursor).
# Free from https://agentpromptsatoz.com/guides/survive-compact/
# Usage: sh compact_risk.sh [--strict]   (--strict exits 1 if any RISK is found)
# Based on the Claude Code docs "What survives compaction" (checked 2026-10-25)
# and Cursor staff guidance on the Cursor forum (2026-10-19).
risk=0; warn=0
say(){ printf '%s %s\n' "$1" "$2"; }
r(){ say "RISK" "$1"; risk=$((risk+1)); }
w(){ say "WARN" "$1"; warn=$((warn+1)); }
ok(){ say "OK  " "$1"; }
# 1. Root instructions exist (these are re-injected / stay in context)
if [ -f CLAUDE.md ] || [ -f AGENTS.md ]; then ok "root CLAUDE.md/AGENTS.md found (re-injected after compaction)"
else r "no root CLAUDE.md or AGENTS.md: rules you typed in chat are summarized away"; fi
# 2. Root file length (Anthropic suggests under 200 lines)
for f in CLAUDE.md AGENTS.md; do
  [ -f "$f" ] || continue
  n=$(wc -l < "$f" | tr -d ' ')
  [ "$n" -gt 200 ] && w "$f has $n lines (docs suggest under 200; long files get followed less reliably)"
done
# 3. Path-scoped Claude rules (.claude/rules/*.md with paths:) drop after compaction
if [ -d .claude/rules ]; then
  for f in $(find .claude/rules -name '*.md' 2>/dev/null); do
    sed -n '1,/^---$/{p}' "$f" | sed '1d' | grep -q '^paths:' && \
      w "$f has paths: frontmatter -> summarized away after compaction until a matching file is read again"
  done
fi
# 4. Nested CLAUDE.md / AGENTS.md (reload only on demand in Claude Code; Cursor may not re-attach them)
for f in $(find . -mindepth 2 \( -name CLAUDE.md -o -name AGENTS.md \) -not -path '*/node_modules/*' -not -path './.git/*' 2>/dev/null); do
  w "nested $f -> lost after compaction until the agent reads a file there (Cursor: ask it to read this file again)"
done
# 5. Cursor file-scoped rules (globs, not alwaysApply)
if [ -d .cursor/rules ]; then
  for f in $(find .cursor/rules -name '*.mdc' 2>/dev/null); do
    grep -q '^alwaysApply: *true' "$f" || w "$f is not alwaysApply -> may drop after Cursor summarizes the chat"
  done
fi
# 6. Big skills: Claude Code re-injects invoked skills capped at ~5,000 tokens each (rough: 20,000 bytes)
for f in $(find .claude/skills .agents/skills -name SKILL.md 2>/dev/null); do
  b=$(wc -c < "$f" | tr -d ' ')
  [ "$b" -gt 20000 ] && w "$f is $b bytes (~$((b/4)) tokens) -> truncated after compaction; keep key rules at the top"
done
# 7. A post-compaction hook is configured
if grep -qs '"compact"' .claude/settings.json .claude/settings.local.json; then ok "SessionStart compact hook configured"
else r "no SessionStart hook with matcher \"compact\" in .claude/settings.json"; fi
# 8. Keep-after-compact markers
if grep -qs 'keep-after-compact -->' AGENTS.md CLAUDE.md; then ok "keep-after-compact block found"
else w "no <!-- keep-after-compact --> block in AGENTS.md/CLAUDE.md (after_compact.sh re-adds only that block)"; fi
printf '\n%s risk(s), %s warning(s)\n' "$risk" "$warn"
[ "$1" = "--strict" ] && [ "$risk" -gt 0 ] && exit 1
exit 0
````

Test log:

````text
VERIFY-LOG for the survive-compact scripts, run 2026-10-25 on Linux (sh = /usr/bin/dash, dash). Scripts tested on their own with sample hook input, not inside a live Claude Code or Cursor session.

== Case 1: empty git repo, no rules ==
$ sh compact_risk.sh
RISK no root CLAUDE.md or AGENTS.md: rules you typed in chat are summarized away
RISK no SessionStart hook with matcher "compact" in .claude/settings.json
WARN no <!-- keep-after-compact --> block in AGENTS.md/CLAUDE.md (after_compact.sh re-adds only that block)

2 risk(s), 1 warning(s)
[exit 0]

$ dash compact_risk.sh
RISK no root CLAUDE.md or AGENTS.md: rules you typed in chat are summarized away
RISK no SessionStart hook with matcher "compact" in .claude/settings.json
WARN no <!-- keep-after-compact --> block in AGENTS.md/CLAUDE.md (after_compact.sh re-adds only that block)

2 risk(s), 1 warning(s)
[exit 0]

$ sh compact_risk.sh --strict
RISK no root CLAUDE.md or AGENTS.md: rules you typed in chat are summarized away
RISK no SessionStart hook with matcher "compact" in .claude/settings.json
WARN no <!-- keep-after-compact --> block in AGENTS.md/CLAUDE.md (after_compact.sh re-adds only that block)

2 risk(s), 1 warning(s)
[exit 1]

== Case 1b: after_compact.sh on empty repo (expect git state only) ==
$ env CLAUDE_PROJECT_DIR=/tmp/test/c1 sh after_compact.sh
This session was just compacted. The notes below come from files in the repo and are current.

## Git state after compaction
Branch: master
[exit 0]

== Case 2: full setup (markers, NOW.md, hook, path rule, nested AGENTS.md, file-scoped .mdc, 25 KB skill) ==
$ sh compact_risk.sh
OK   root CLAUDE.md/AGENTS.md found (re-injected after compaction)
WARN .claude/rules/api.md has paths: frontmatter -> summarized away after compaction until a matching file is read again
WARN nested ./pkg/api/AGENTS.md -> lost after compaction until the agent reads a file there (Cursor: ask it to read this file again)
WARN .cursor/rules/testing.mdc is not alwaysApply -> may drop after Cursor summarizes the chat
WARN .claude/skills/big/SKILL.md is 25000 bytes (~6250 tokens) -> truncated after compaction; keep key rules at the top
OK   SessionStart compact hook configured
OK   keep-after-compact block found

0 risk(s), 4 warning(s)
[exit 0]

$ dash compact_risk.sh
OK   root CLAUDE.md/AGENTS.md found (re-injected after compaction)
WARN .claude/rules/api.md has paths: frontmatter -> summarized away after compaction until a matching file is read again
WARN nested ./pkg/api/AGENTS.md -> lost after compaction until the agent reads a file there (Cursor: ask it to read this file again)
WARN .cursor/rules/testing.mdc is not alwaysApply -> may drop after Cursor summarizes the chat
WARN .claude/skills/big/SKILL.md is 25000 bytes (~6250 tokens) -> truncated after compaction; keep key rules at the top
OK   SessionStart compact hook configured
OK   keep-after-compact block found

0 risk(s), 4 warning(s)
[exit 0]

$ sh compact_risk.sh --strict
OK   root CLAUDE.md/AGENTS.md found (re-injected after compaction)
WARN .claude/rules/api.md has paths: frontmatter -> summarized away after compaction until a matching file is read again
WARN nested ./pkg/api/AGENTS.md -> lost after compaction until the agent reads a file there (Cursor: ask it to read this file again)
WARN .cursor/rules/testing.mdc is not alwaysApply -> may drop after Cursor summarizes the chat
WARN .claude/skills/big/SKILL.md is 25000 bytes (~6250 tokens) -> truncated after compaction; keep key rules at the top
OK   SessionStart compact hook configured
OK   keep-after-compact block found

0 risk(s), 4 warning(s)
[exit 0]

== Case 2b: after_compact.sh (sh and dash) ==
$ env CLAUDE_PROJECT_DIR=/tmp/test/c2 sh after_compact.sh
This session was just compacted. The notes below come from files in the repo and are current.

## Project rules from AGENTS.md (kept after compaction)
- Never edit files in migrations/.
- Run pnpm test before saying done.

## Current task notes (.claude/NOW.md)
# Now
Task: auth refactor, step 3 of 5. Open: fix token refresh test.


## Git state after compaction
Branch: feat/auth
?? .claude/
?? .cursor/
?? AGENTS.md
?? CLAUDE.md
?? pkg/
?? untracked.txt
[exit 0]

$ env CLAUDE_PROJECT_DIR=/tmp/test/c2 dash after_compact.sh
This session was just compacted. The notes below come from files in the repo and are current.

## Project rules from AGENTS.md (kept after compaction)
- Never edit files in migrations/.
- Run pnpm test before saying done.

## Current task notes (.claude/NOW.md)
# Now
Task: auth refactor, step 3 of 5. Open: fix token refresh test.


## Git state after compaction
Branch: feat/auth
?? .claude/
?? .cursor/
?? AGENTS.md
?? CLAUDE.md
?? pkg/
?? untracked.txt
[exit 0]

== Case 3: output cap with a 50 KB NOW.md (expect <= 9000 bytes) ==
$ after_compact.sh | wc -c
9000

== Case 4: empty folder, not a git repo (expect no output, exit 0) ==
$ env CLAUDE_PROJECT_DIR=/tmp/test/c4 sh after_compact.sh
[exit 0]

== Case 5: log_compact.py with sample PostCompact input ==
[exit 0]
<timestamp>-manual.md
Summary: auth refactor step 3

== Case 6: log_compact.py with bad input (expect exit 0, message on stderr) ==
log_compact: Expecting value: line 1 column 1 (char 0)
[exit 0]
````

## Cursor and Codex

- Cursor: put must-keep rules in the root AGENTS.md or an alwaysApply rule; after a summary ask the agent to read the nested AGENTS.md again, or start a new chat.
- Codex: AGENTS.md comes back after compaction; to keep chat rules too, set compact_prompt in ~/.codex/config.toml:

````toml
# ~/.codex/config.toml
# Tell the summarizer what to keep (inline override of the compaction prompt)
compact_prompt = """Summarize this session for a coding agent that will continue it.
Keep, word for word: every rule the user gave in chat, open tasks,
decisions and their reasons, file paths being edited, failing test names."""
# Optional: compact earlier, before the window is nearly full
# model_auto_compact_token_limit = 200000
````

## Tips

- Rules live in files, not in chat. Anything you type once is summarized away at the next compaction.
- Keep the must-follow rules short and near the top of the root CLAUDE.md or AGENTS.md. Put the five that matter most in the keep-after-compact block.
- Have the agent keep .claude/NOW.md up to date (task, done, next, decisions). It is the cheapest memory that survives every compaction.
- Compact at a natural break with a focus instruction instead of waiting for auto-compact in the middle of a change.
- In big SKILL.md files, put the critical instructions first. Claude Code keeps the start of the file when it truncates a skill after compaction.
- Run compact_risk.sh once on each repo. It lists the rules most likely to drop.

## FAQ

**Does Claude Code forget CLAUDE.md after /compact?**

No. Claude Code re-reads the project-root CLAUDE.md from disk after /compact and re-injects it, along with unscoped rules and auto memory. What disappears is anything you only said in chat, rules with paths: frontmatter, and nested CLAUDE.md files in subfolders until Claude reads a file there again. If a rule vanished, move it into the root CLAUDE.md (or AGENTS.md imported with @AGENTS.md).

**How do I re-inject context after compaction in Claude Code?**

Add a SessionStart hook with the matcher compact to .claude/settings.json. Claude Code runs it after every manual or automatic compaction and adds its stdout to the compacted context. The free after_compact.sh on this page prints your keep-after-compact rules, your current task notes and the git state. Hook output is capped at 10,000 characters, so the script stops at 9,000.

**What is the difference between PreCompact, PostCompact and SessionStart compact?**

PreCompact runs before compaction; it receives your /compact instructions and can block compaction (exit 2), but it can't add context. PostCompact runs after and receives compact_summary, the generated summary, but its output isn't added for Claude. SessionStart with matcher compact is the one that adds text to Claude's context after compaction.

**Can I tell /compact what to keep?**

Yes. In Claude Code run /compact with instructions, for example /compact keep every rule I gave and the open tasks. In Codex, set compact_prompt in config.toml to replace the summarization prompt. A NO COMPACTION ZONE note in chat is only a request to the summarizer, so put rules that must survive in files instead.

**Why does Cursor ignore my nested AGENTS.md after a long chat?**

Cursor attaches nested AGENTS.md files and file-scoped rules once per conversation when the agent reads a file there. After the chat is summarized that text can drop out, and later reads don't re-attach it. Put must-keep rules in the root AGENTS.md or an alwaysApply rule, ask the agent to read pkg/AGENTS.md again after a summary, or start a new chat.

**Should I just make the context window bigger or compact later?**

Not to protect rules. Later compaction means a bigger, lossier summary. Claude Code lets you set the threshold with /autocompact (for example /autocompact 500k) and Codex has model_auto_compact_token_limit. Compacting earlier at a natural break, with a focus instruction, usually keeps more of what matters.

**How do I see what compaction dropped?**

Use the free log_compact.py PostCompact hook. It saves every summary to .claude/compact-log/, so you can compare it with your rules and add a line to CLAUDE.md for anything that keeps getting lost.

## Go further (premium)

[App Builder Agent Pack](https://payhip.com/b/EuRgw) ($19): finished AGENTS.md, CLAUDE.md and six Cursor rules files with a plan-then-build workflow that ends each step with a handoff note. Or [all 5 premium packs](https://payhip.com/b/J8eUb) for $29.
