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)

ModelContext windowMax outputNotes
Opus 51M tokens128K tokensExtended thinking, adaptive reasoning
Sonnet 51M tokens64K tokensSpeed/intelligence balance
Haiku 4.5200K tokens64K tokensThe 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:

ElementTypical consumptionExample
Your messageLow (~100-500 tokens)"Create a GET /users endpoint"
Claude's answerMedium-High (~500-5,000 tokens)Generated code + explanation
A file Claude readHigh (~1,000-50,000 tokens)A 500-line file ≈ 5,000 tokens
Terminal outputVariablenpm test output can be enormous
CLAUDE.mdFixed (~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

PreservedLost
The general direction of the workExact code, line by line
Decisions that were madeIntermediate reasoning
The structure of what got builtCommand output
Names of files created/modifiedThe literal contents of files read
Errors found and how they were resolvedFull 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

SignalAction
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 messagesDecide 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:

  1. It compacts at a moment Claude picks, not you
  2. You can't tell it what to prioritize in the summary
  3. It can interrupt your flow at an inconvenient moment
  4. 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

ActionConversation contextCLAUDE.mdFiles on diskWhen to use
/compactSummarizedIntactIntactSame topic, free up space
/clearDeletedIntactIntactReset inside the same terminal
New sessionDoesn't existIntactIntactNew topic or poisoned context

How long you can work before you need to compact

ScenarioMessages before compactingReason
Exploring a large codebase5-8Claude reads many files, heavy consumption
Coding with small files15-20Short messages, low consumption per turn
Debugging with stack traces8-12Stack traces eat a lot of context
Code review3-5Every file read costs a lot
Text-only conversation25-30No 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:

  1. Send a short message ("Hi, what model are you using?")
  2. Ask it to read a small file (<50 lines)
  3. Ask it to read a large file (>300 lines)
  4. Ask it to run ls -la in the project root
  5. 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:

  1. Reading a large file — by far the biggest consumer
  2. Running tests — test output can be extensive
  3. Reading a small file — modest consumption
  4. ls -la — little output, low consumption
  5. 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

  1. Start a session and work until the context is around 60%
  2. Run /compact with a specific focus
  3. Immediately ask: "What have we done so far?"
  4. Judge the quality of the summary: did it capture what mattered?
  5. 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:

  1. Be more specific with the focus of /compact
  2. 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

  1. Start a session and ask Claude to analyze some aspect of your project
  2. During the conversation, identify 3+ findings or conventions Claude discovered
  3. Ask Claude to add them to CLAUDE.md
  4. Run /compact
  5. 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:

  1. How many files does Claude need to read? → High consumption
  2. Does it need to run commands with long output? → High consumption
  3. Is it mostly conversation and generated code? → Medium consumption
  4. 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:

  1. (a) Rename a variable — Reads 1 file, one-off operation. ~2-5K tokens.
  2. (c) CRUD endpoint — Reads 2-3 reference files, generates code. ~15-30K tokens.
  3. (d) Test suite — Runs tests (output can be long), reads the failing files, generates fixes. ~30-80K tokens.
  4. (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.
  • /compact summarizes 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

  1. Claude Code Best Practices — Anthropic Docs — Includes context management guidance
  2. Claude Code Memory System — CLAUDE.md and the memory hierarchy
  3. Claude Code Interactive Mode — Commands like /compact, /clear, and session management
  4. Claude Code CLI Reference — Full reference for commands and flags
  5. Claude Models Overview — Specs for Opus 5, Sonnet 5, and Haiku 4.5
  6. Anthropic Cookbook — Long Context — Techniques for handling long contexts with Claude
  7. Claude Code Overview — Platforms, capabilities, and limits