Module 4: The agentic workflow: Explore → Plan → Code
Context Window and Compaction: Managing Claude Code's Memory
Context Window and Compaction: Managing Claude Code's Memory
Overview
The context window is Claude Code's working memory. Everything you say, everything Claude answers, every file it reads, every command it runs — all of it takes up space in that window. With Opus 5 and Sonnet 5 you get up to 1M tokens, but that doesn't mean it's infinite, and it doesn't mean you can ignore how you manage it.
A badly managed context window is like a desk buried in paper: technically everything is there, but finding what matters gets harder and harder. When the context fills up, Claude starts "forgetting" details from the early messages, answers lose precision, and performance degrades. Compaction is the tool that lets you clear that desk without losing the thread of your work.
In this capsule you'll learn what the context window is, how to monitor it, what compaction is and when to use it, what gets preserved and what gets lost, and the strategies for keeping conversations productive even on large projects with long sessions.
What the Context Window Is
Technical definition
The context window is the total amount of text (measured in tokens) that Claude can process at any given moment. It includes:
- The system prompt (Claude Code's internal instructions)
- CLAUDE.md and memory files
- Your entire conversation (all your messages + all of Claude's answers)
- The contents of files Claude read
- The output of commands it ran (terminal output)
- Tool calls and results (internal operations)
┌─────────────────────────────────────────────┐
│ CONTEXT WINDOW │
│ │
│ ┌─────────────────────────────────────┐ │
│ │ System prompt + CLAUDE.md │ │
│ │ (~fixed, loaded at startup) │ │
│ └─────────────────────────────────────┘ │
│ ┌─────────────────────────────────────┐ │
│ │ Message 1: "Analyze this project" │ │
│ │ Response 1: [analysis + files] │ │
│ └─────────────────────────────────────┘ │
│ ┌─────────────────────────────────────┐ │
│ │ Message 2: "Create endpoint..." │ │
│ │ Response 2: [generated code] │ │
│ └─────────────────────────────────────┘ │
│ ┌─────────────────────────────────────┐ │
│ │ Message 3: ... │ │
│ │ Response 3: ... │ │
│ └─────────────────────────────────────┘ │
│ ┌─────────────────────────────────────┐ │
│ │ ↓ it keeps growing ↓ │ │
│ └─────────────────────────────────────┘ │
│ │
│ ═══════════════════════════════════════ │
│ Space left for the next response │
│ │
└─────────────────────────────────────────────┘
Current capacities (Feb 2026)
| Model | Context window | Max output | Notes |
|---|---|---|---|
| Opus 5 | 1M tokens | 128K tokens | Extended thinking, adaptive reasoning |
| Sonnet 5 | 1M tokens | 64K tokens | Speed/intelligence balance |
| Haiku 4.5 | 200K tokens | 64K tokens | The fastest |
1M tokens ≈ ~750,000 words ≈ ~3,000 pages of text. It sounds enormous, but it fills up faster than you'd think.
What eats the most tokens
Not everything costs the same. Some elements consume far more than others:
| Element | Typical consumption | Example |
|---|---|---|
| Your message | Low (~100-500 tokens) | "Create a GET /users endpoint" |
| Claude's answer | Medium-High (~500-5,000 tokens) | Generated code + explanation |
| A file Claude read | High (~1,000-50,000 tokens) | A 500-line file ≈ 5,000 tokens |
| Terminal output | Variable | npm test output can be enormous |
| CLAUDE.md | Fixed (~500-2,000 tokens) | Loaded once and persists |
The #1 context consumer isn't your messages — it's the files Claude reads and the output of commands. A single cat package-lock.json can burn 100K+ tokens.
How to Monitor Context
Claude Code's indicator
Claude Code shows context usage in the interface. The indicator tells you what percentage of the context window is occupied.
# Indicator in Claude Code's status bar:
# Shown as a percentage or a visual bar
Context: ████████░░ 78%
Signals that context is filling up
You won't always be watching the indicator. These signals warn you:
1. Slower answers
Claude takes longer to reply because it has to process more context before generating. If an answer that should take 5 seconds takes 20, your context is probably high.
2. "Forgetting" earlier instructions
# 15 messages ago you said:
"Use camelCase for variables"
# But now Claude generates:
const user_name = "..." // snake_case
# Claude isn't ignoring you — old messages simply lose
# "weight" when the context is saturated
3. More generic answers
When the context is full, Claude tends to give safer, more generic answers instead of project-specific ones. If you notice that Claude "forgot" your project's conventions (the ones that aren't in CLAUDE.md), that's a signal.
4. Repeated questions
If Claude asks you something you already answered, the context has degraded.
5. Auto-compaction
Claude Code can run auto-compaction when it detects that the context is very full. If you see a system message about automatic compaction, that's a sign you've been working with a saturated context.
Compaction hooks (PreCompact / PostCompact)
Claude Code exposes two lifecycle hooks for compaction:
PreCompact— fires BEFORE compaction happens. Useful for saving critical state (e.g. committing work in progress, exporting important decisions to a file)PostCompact— fires AFTER compaction completes. Useful for logging what got summarized or notifying the team
{
"hooks": {
"PreCompact": [
{ "hooks": [{ "type": "command", "command": "./scripts/save-checkpoint.sh" }] }
],
"PostCompact": [
{ "hooks": [{ "type": "command", "command": "echo 'Context compacted' >> .claude/logs/compaction.log" }] }
]
}
}
Hooks are covered in depth in Module 05 (Skills and Hooks).
Compaction: What It Is and How It Works
Definition
Compaction is the process of summarizing the conversation to free up space in the context window. Claude Code takes the whole conversation history, condenses it into a concise summary, and replaces the original messages with that summary.
# Before compaction:
┌──────────────────────────────────────┐
│ CLAUDE.md [2K] │
│ Message 1 + Response 1 [5K] │
│ Message 2 + Response 2 [8K] │
│ Message 3 + Response 3 [12K] │
│ Message 4 + Response 4 [3K] │
│ Message 5 + Response 5 [6K] │
│ ────────────────────────────────── │
│ Total: 36K tokens used │
└──────────────────────────────────────┘
# After compaction:
┌──────────────────────────────────────┐
│ CLAUDE.md [2K] │
│ [CONVERSATION SUMMARY] [3K] │
│ ────────────────────────────────── │
│ Total: 5K tokens used │
│ Freed: ~31K tokens │
└──────────────────────────────────────┘
The /compact command
> /compact
That's it. Claude Code compresses the conversation and shows you a short summary of what it preserved.
You can also give instructions about what to emphasize in the compaction:
> /compact focus on the architecture decisions and the endpoints we created
That tells Claude what to prioritize in the summary.
What gets preserved vs what gets lost
| Preserved | Lost |
|---|---|
| The general direction of the work | Exact code, line by line |
| Decisions that were made | Intermediate reasoning |
| The structure of what got built | Command output |
| Names of files created/modified | The literal contents of files read |
| Errors found and how they were resolved | Full stack traces |
| CLAUDE.md (intact, never compacted) | Exploratory conversation |
Key point: The project's files aren't lost. They're on disk. Claude can re-read them after compaction. What's lost is the memory of having read them.
A practical example: before and after
Original conversation (5 messages, ~40K tokens):
You: "Analyze src/auth/ and tell me how authentication works"
Claude: [reads 8 files, explains the JWT flow, middleware, refresh tokens...]
You: "There's a bug: the refresh token isn't invalidated on logout"
Claude: [analyzes, finds the problem in auth.service.ts line 47]
You: "Fix it and add the token to a blacklist in Redis"
Claude: [implements the blacklist, modifies logout, modifies the middleware]
You: "Create tests for the new logout flow"
Claude: [creates 6 tests with Redis mocks]
You: "Test 3 fails because the Redis mock doesn't simulate TTL"
Claude: [fixes the mock, the test passes]
After /compact (~3K tokens):
[Summary]: We worked on the JWT authentication system in src/auth/.
We found and fixed a bug where the refresh token wasn't invalidated
on logout. We implemented a blacklist in Redis (src/auth/token-blacklist.ts).
6 tests were created in src/auth/__tests__/logout.test.ts, all passing.
The Redis mock needed TTL support to work correctly.
Modified files: auth.service.ts, auth.middleware.ts,
token-blacklist.ts (new), logout.test.ts (new).
Claude no longer has the exact code in context, but it knows what it did, where, and why. If it needs the code, it re-reads it from disk.
When to Compact
The 70-80% rule
Compact when the context indicator hits 70-80%. Don't wait for 95% — by then the quality has already degraded.
Context: ████████░░ 78% ← Good moment for /compact
Context: █████████▓ 95% ← Too late, compact now
Signals that it's time to compact
| Signal | Action |
|---|---|
| Indicator > 70% | /compact |
| Answers slower than before | /compact |
| Claude "forgot" something you said | /compact |
| You switched subtask within the same topic | /compact with a focus |
| You're past 15 messages | Decide between /compact and a new session |
When NOT to compact
1. In the middle of a multi-step operation:
# Do NOT compact here:
You: "Migrate the database from SQLite to PostgreSQL"
Claude: "Step 1 of 5: Creating the PostgreSQL schema..."
# ← Don't run /compact here, Claude will lose the 5-step plan
# Wait until it finishes all 5 steps, then compact
2. When you need exact details of the current code:
# If you're in the middle of a debugging session where every line matters,
# compacting can make Claude forget the critical detail.
# Better to finish the debugging and compact afterward.
3. When the context is small:
# If you're 3 messages in and the context is at 15%,
# compacting makes no sense — there's nothing to gain.
Auto-Compaction
How it works
Claude Code can run compaction automatically when it detects that the context window is close to its limit. You don't have to do anything — Claude decides when it's necessary.
# You're working along normally...
You: "Now add validation to the endpoint"
# Claude Code detects context at 90%
[System]: Auto-compacting conversation to free up context...
Claude: "I've compacted the conversation. Here's a summary
of what we've done: [summary]. Continuing with the
endpoint validation..."
Configuration
Auto-compaction is enabled by default. You can control its behavior in Claude Code's settings:
{
"autoCompact": true,
"compactThreshold": 80
}
Should you rely on auto-compaction?
Not as your main strategy. Auto-compaction is a safety net, not a plan. Reasons:
- It compacts at a moment Claude picks, not you
- You can't tell it what to prioritize in the summary
- It can interrupt your flow at an inconvenient moment
- Manual compaction with
/compact [focus]produces better summaries
Best practice: Compact proactively with /compact before auto-compaction kicks in.
CLAUDE.md: Your Compaction-Proof Context
Why CLAUDE.md is key to compaction
CLAUDE.md doesn't get compacted. It's always there, in full, no matter how many times you compact or clear the conversation.
# After /compact:
# ✅ CLAUDE.md → intact
# ⚡ Conversation → summarized
# After /clear:
# ✅ CLAUDE.md → intact
# ❌ Conversation → deleted
# After a new session:
# ✅ CLAUDE.md → intact
# ❌ Previous conversation → doesn't exist
That has an enormous practical implication: anything critical to the project must live in CLAUDE.md, not in the conversation.
What to move to CLAUDE.md after discovering it in conversation
# During the conversation you discovered that:
# - The project uses a specific error-handling pattern
# - There's an undocumented naming convention
# - Certain files must not be touched
# Before compacting:
You: "Add these conventions we discovered to CLAUDE.md:
1. Errors extend BaseAppError in src/errors/base.ts
2. Migrations go in db/migrations/ with the format YYYYMMDD_name.sql
3. Don't modify src/legacy/ — that code is being deprecated"
Claude: [updates CLAUDE.md]
# Now you can compact without fear — the conventions persist
> /compact
Comparisons and decisions
/compact vs /clear vs a new session
| Action | Conversation context | CLAUDE.md | Files on disk | When to use |
|---|---|---|---|---|
/compact | Summarized | Intact | Intact | Same topic, free up space |
/clear | Deleted | Intact | Intact | Reset inside the same terminal |
| New session | Doesn't exist | Intact | Intact | New topic or poisoned context |
How long you can work before you need to compact
| Scenario | Messages before compacting | Reason |
|---|---|---|
| Exploring a large codebase | 5-8 | Claude reads many files, heavy consumption |
| Coding with small files | 15-20 | Short messages, low consumption per turn |
| Debugging with stack traces | 8-12 | Stack traces eat a lot of context |
| Code review | 3-5 | Every file read costs a lot |
| Text-only conversation | 25-30 | No files or commands, low consumption |
Compaction's impact on quality
# Mental formula:
Quality = f(context relevance, not context quantity)
# Context at 90% with lots of noise:
# → Generic answers, forgetting, slowness
# Context at 30% post-compaction with a clean summary:
# → Focused, fast, precise answers
# Counterexample: compacting in the middle of a complex debugging session:
# → Claude loses the thread of the bug, quality drops
Compaction improves quality when a lot of irrelevant context has piled up. It hurts quality when it strips out context that was still relevant.
Common patterns
Pattern 1: "Checkpoint, Save, Compact"
Before compacting, save what matters outside the conversation.
# Step 1: Checkpoint — ask for a summary
You: "Summarize the design decisions we've made so far."
Claude: [list of decisions]
# Step 2: Save — persist what matters
You: "Add those decisions to CLAUDE.md under a section
'## Architecture decisions'."
Claude: [updates CLAUDE.md]
# Step 3: Compact — free up context
> /compact
# Now you have a clean context + decisions persisted in CLAUDE.md
Pattern 2: "Split by phase"
For large tasks, plan when you'll compact.
# Phase 1: Exploration (eats a lot of context reading files)
You: "Analyze the project structure, the dependencies,
and how the routing system works."
Claude: [reads many files, explains]
> /compact focus on the project structure and the routing system
# Phase 2: Design (eats less, it's conversation)
You: "Design a notifications module. Schema, endpoints, flow."
Claude: [designs it]
# Phase 3: Implementation (eats a lot, generates code)
You: "Implement the schema and the model."
Claude: [implements]
> /compact focus on what got implemented and where the files are
# Phase 4: Testing
You: "Create tests for the notifications module."
Pattern 3: "Minimum viable context"
Work only with the files you need, not the whole codebase.
# BAD — unnecessary load:
You: "Read every file in src/ and then modify the login endpoint."
# Claude reads 50 files, burns 200K tokens, only needed 3 files
# GOOD — focused context:
You: "Modify the login endpoint in src/auth/login.controller.ts.
If you need to see how the auth middleware works, it's in
src/middleware/auth.ts."
# Claude reads 2-3 files, burns 10K tokens
Pattern 4: "Fresh context for critical tasks"
For tasks that demand maximum precision, work with fresh context.
# You're at 60% context and you need to do a delicate refactor
# Option A: Continue with partially relevant context
# Risk: Claude could blend in context from earlier tasks
# Option B: /compact and continue with a clean context
> /compact focus on the current state of the authentication files
You: "Refactor src/auth/ to move the token logic
into its own module."
# Option C: A new session for maximum clarity
# (see the next capsule: When to start a new session)
Pitfalls and edge cases
Pitfall 1: Compacting too early
# You're 3 messages in, context at 15%
> /compact ← unnecessary
# You lose conversation detail and gain nothing
# Only compact when there's something to gain (>50% context used)
Pitfall 2: Never compacting
# You're 25 messages in, context at 92%
# The answers are slow and generic
# Claude "forgets" conventions you told it
# → You should have compacted 10 messages ago
Pitfall 3: Compacting without saving decisions
# During the conversation you discovered the project uses a
# specific error-handling pattern. You didn't save it to
# CLAUDE.md. You run /compact. The summary doesn't capture that detail.
# On the next message, Claude generates errors with a different pattern.
# The fix: always persist important findings in CLAUDE.md
# BEFORE compacting
Pitfall 4: Confusing tokens with lines of code
# "My file is 200 lines, it can't eat that much context"
#
# In reality:
# - 200 lines of dense TypeScript ≈ 3,000-5,000 tokens
# - 200 lines of JSON ≈ 2,000-4,000 tokens
# - package-lock.json (thousands of lines) ≈ 100K+ tokens
#
# Tokens are NOT lines. A single line can be 5-50 tokens.
Pitfall 5: Compacting without a focus
# Without a focus:
> /compact
# Claude produces a generic summary — it can drop what matters
# With a focus:
> /compact prioritize the architecture decisions, the modified
files, and the authentication bug we're debugging
# Claude produces a summary that preserves what you need
Edge Case: Very large files
# If Claude read a 10,000-line file, that file
# eats ~50K-100K tokens of context.
# After compaction, the file's contents are gone,
# but Claude can re-read it if it needs to.
#
# Strategy: instead of asking it to "read the whole file", ask it to
# "read lines 100-200 of file.ts" to spend less.
Complete worked example
Scenario: A long development session with context management
# ═══════════════════════════════════════════
# SESSION: Build a comments system
# Project: REST API with Express + PostgreSQL
# ═══════════════════════════════════════════
# ─── Phase 1: Exploration (~15% context) ───
You: "Analyze how the models in src/models/ and the controllers
in src/controllers/ are structured. I need to understand the
pattern before adding a comments system."
Claude: [reads 6 files, explains the patterns]
# Context: ~20%
# ─── Phase 2: Design (~30% context) ───
You: "Design the Comment model: id, postId, userId, content,
createdAt, updatedAt, parentId (for replies). Plus the CRUD
endpoints. Design only, don't implement."
Claude: [designs the schema and endpoints]
# Context: ~28%
You: "Add soft delete (deletedAt) and an 'edited' boolean field."
Claude: [adjusts the design]
# Context: ~32%
# ─── Phase 3: Model implementation (~50% context) ───
You: "Create the migration and the Prisma model for Comment."
Claude: [creates the migration and the model]
# Context: ~40%
You: "Implement the service with full CRUD."
Claude: [implements the service]
# Context: ~52%
# ─── CHECKPOINT: Strategic compaction ───
You: "Before we continue, add this to CLAUDE.md: 'The comments
system uses soft delete, nested replies via parentId,
and an edited field for modified comments. Model in
prisma/schema.prisma, service in src/services/comment.service.ts.'"
Claude: [updates CLAUDE.md]
> /compact focus on: Comment model created with soft delete and replies,
service implemented in src/services/comment.service.ts,
still missing controller, routes, and tests
# Context after compact: ~12%
# ─── Phase 4: Controller and routes (fresh context) ───
You: "Implement the controller and the routes for comments.
Follow the pattern of the project's other controllers."
Claude: [re-reads an existing controller as a reference, implements]
# Context: ~25%
# ─── Phase 5: Tests ───
You: "Tests with Vitest for the comment service:
full CRUD, soft delete, replies, and edit."
Claude: [creates the tests]
# Context: ~40%
You: "Run the tests."
Claude: [runs them, shows the results]
# Context: ~45%
# ─── Final result ───
# A productive session with 1 strategic compaction
# Context never went past 55%
# Consistent quality throughout the session
# Decisions persisted in CLAUDE.md
Practice exercises
Exercise 1: Monitor context consumption
Open a Claude Code session. Run the following operations and watch how the context indicator changes after each one:
- Send a short message ("Hi, what model are you using?")
- Ask it to read a small file (<50 lines)
- Ask it to read a large file (>300 lines)
- Ask it to run
ls -lain the project root - Ask it to run
npm test(or your project's test runner)
Record the changes. Which operation consumed the most context?
What to watch for
Typically the order from most to least consumption is:
- Reading a large file — by far the biggest consumer
- Running tests — test output can be extensive
- Reading a small file — modest consumption
ls -la— little output, low consumption- A short message — minimal
The lesson: the #1 consumption factor is the files Claude reads and command output, not your messages. Be selective about what you ask Claude to read.
Exercise 2: Manual vs automatic compaction
- Start a session and work until the context is around 60%
- Run
/compactwith a specific focus - Immediately ask: "What have we done so far?"
- Judge the quality of the summary: did it capture what mattered?
- If something's missing, note what type of information got lost
What to watch for
The /compact summary should capture:
- Which files were created/modified
- Which decisions were made
- What the goal was
What typically gets lost:
- The exact generated code
- Intermediate reasoning
- Failed attempts
- Command output
If the summary misses something critical, next time:
- Be more specific with the focus of
/compact - Save what's critical to CLAUDE.md before compacting
Exercise 3: Compaction's impact on quality
Do the same task two ways:
Way A: No compaction — pile up 15+ messages of mixed conversation (exploration, code, debugging) and then ask for a task that needs precise context.
Way B: With strategic compaction — every 5-7 messages, compact with a focus. At the end, ask for the same task.
Compare: which one produced a better result for the final task?
What to expect
Way B (with compaction) generally produces better results for the final task because:
- The context is cleaner and more relevant
- Claude has no "noise" from earlier explorations
- The compaction summaries act like "organized notes"
Way A can work fine if:
- The total context still fits comfortably (<50%)
- All the accumulated context is relevant to the final task
Takeaway: compaction isn't always necessary, but when the context is noisy, it noticeably improves quality.
Exercise 4: Persist before compacting
- Start a session and ask Claude to analyze some aspect of your project
- During the conversation, identify 3+ findings or conventions Claude discovered
- Ask Claude to add them to CLAUDE.md
- Run
/compact - Verify that the findings are still available via CLAUDE.md
What to watch for
After compaction:
- Claude can refer to the findings because they live in CLAUDE.md
- If you had compacted WITHOUT saving to CLAUDE.md, those findings would probably have been lost or reduced to a vague mention in the summary
This exercise demonstrates the "Save before Compact" pattern: always persist what's valuable before freeing up context.
Exercise 5: Estimate consumption before you start
Before starting a task, estimate how much context it's going to consume:
- How many files does Claude need to read? → High consumption
- Does it need to run commands with long output? → High consumption
- Is it mostly conversation and generated code? → Medium consumption
- Is it a one-off question? → Low consumption
Rank these tasks from lowest to highest consumption:
- a) "Rename the variable x to userId in auth.ts"
- b) "Analyze all of src/ and suggest architecture improvements"
- c) "Create a CRUD endpoint for products"
- d) "Run the full test suite and fix the failures"
Answer
From lowest to highest consumption:
- (a) Rename a variable — Reads 1 file, one-off operation. ~2-5K tokens.
- (c) CRUD endpoint — Reads 2-3 reference files, generates code. ~15-30K tokens.
- (d) Test suite — Runs tests (output can be long), reads the failing files, generates fixes. ~30-80K tokens.
- (b) Analyze all of src/ — Reads MANY files, produces an extensive analysis. ~100K-500K tokens depending on the size of src/.
Knowing this lets you plan: for (b), you'll probably need to compact afterward. For (a), don't even think about it.
Summary
- The context window is Claude Code's working memory. Everything you say, read, and run takes up space.
- Opus 5 and Sonnet 5 have 1M tokens; Haiku 4.5 has 200K. It sounds like a lot, but large files and command output fill it fast.
- Watch the context indicator. Saturation signals: slow answers, forgetting, generic answers.
/compactsummarizes the conversation and frees up space. It preserves direction, loses the details.- Compact at 70-80%, not at 95%. You can give it a focus:
/compact prioritize X. - Do NOT compact in the middle of a multi-step operation or an active debugging session.
- Auto-compaction exists as a safety net, but don't rely on it.
- CLAUDE.md doesn't get compacted. Everything critical to the project must live there.
- Key pattern: "Checkpoint, Save, Compact" — save findings to CLAUDE.md before compacting.
- The #1 context consumer is the files Claude reads and command output, not your messages.
- Fresh context = better answers. Don't let irrelevant context pile up out of laziness.
Additional resources
- Claude Code Best Practices — Anthropic Docs — Includes context management guidance
- Claude Code Memory System — CLAUDE.md and the memory hierarchy
- Claude Code Interactive Mode — Commands like /compact, /clear, and session management
- Claude Code CLI Reference — Full reference for commands and flags
- Claude Models Overview — Specs for Opus 5, Sonnet 5, and Haiku 4.5
- Anthropic Cookbook — Long Context — Techniques for handling long contexts with Claude
- Claude Code Overview — Platforms, capabilities, and limits