← Back to learning path
Level 5

Level 5: Advanced Planning Frameworks (GSD)

The definitive guide to context management, session control, and phase-based planning -- from understanding context rot to building…

Level 5: Advanced Planning Frameworks (GSD)

The definitive guide to context management, session control, and phase-based planning -- from understanding context rot to building complete planning workflows that scale.


Table of Contents

  1. Overview & Goal
  2. Understanding Context -- The #1 Resource
  3. Compaction & Context Management
  4. Session Management
  5. The GSD Framework (Get Stuff Done)
  6. Phase-Based Planning in Detail
  7. Context Isolation Strategies
  8. The Plan-Execute-Verify Loop
  9. Working with Large Codebases
  10. Advanced Session Patterns
  11. Combining GSD with Other Levels
  12. Exercises
  13. Pro Tips from Boris Cherny
  14. Anti-Patterns
  15. Official Documentation Links

1. Overview & Goal

Levels 1 through 4 taught you how to prompt effectively, configure project context, use commands and hooks, and integrate external tools through MCP. Those skills work well for small-to-medium tasks: fixing a bug, adding a feature, writing tests.

But what happens when the task is large? A multi-day feature. A system redesign. A migration across hundreds of files. At that scale, the techniques from earlier levels start breaking down -- not because they are wrong, but because they ignore the single most important constraint in Claude Code:

The context window is a finite, degrading resource.

Every file Claude reads, every command it runs, every message you exchange -- all of it accumulates in the context window. As it fills, Claude's ability to follow instructions, remember earlier decisions, and produce reliable output decreases. This is called context rot, and it is the primary failure mode for complex, multi-step work.

Level 5 introduces the GSD Framework (Get Stuff Done): a structured approach to planning, executing, and verifying work in phases. The framework is designed around one principle: keep Claude's context clean, focused, and relevant at all times.

What You Will Learn

Who This Is For

You should already be comfortable with:

If those feel solid, you are ready.


2. Understanding Context -- The #1 Resource

How Claude Code's Agentic Loop Works

When you give Claude a task, it works through three phases that blend together:

Your Prompt
    |
    v
[Gather Context] --> Read files, search code, explore codebase
    |
    v
[Take Action]    --> Edit files, run commands, make changes
    |
    v
[Verify Results] --> Run tests, check output, validate
    |
    v
[Loop or Complete]

Claude Code is the agentic harness around Claude. It provides the tools (file reading, editing, bash execution, search), the context management, and the execution environment that turn the language model into a coding agent. The model reasons about what to do; the tools let it act.

Each tool use returns information that feeds back into the loop. When Claude reads a file, that file's contents go into the context window. When Claude runs a test, the test output goes into the context window. When you send a message, that message goes into the context window. Everything accumulates.

The Context Window Explained

The context window holds everything Claude knows about your current conversation:

Component Examples Token Impact
System instructions CLAUDE.md, skills descriptions, tool definitions Loaded at session start, persistent
Your messages Every prompt you have typed Accumulates over session
Claude's responses Every response Claude has generated Accumulates over session
Tool inputs File read requests, bash commands Moderate
Tool outputs File contents, command output, search results Often very large
MCP tool definitions Schemas for every connected MCP server Persistent per-session overhead

Input tokens are everything Claude receives: your messages, file contents, system prompts, tool outputs. Output tokens are everything Claude generates: responses, tool calls, reasoning. Both count against the window.

A single file read can consume thousands of tokens. A large test suite output can consume tens of thousands. A verbose build log can fill a significant portion of the window in one command.

Context Rot: What It Is and Why It Happens

Context rot is the progressive degradation of Claude's output quality as the context window fills with accumulated conversation history, file contents, and tool outputs.

It happens because:

  1. Attention dilution -- With more tokens in the window, each individual instruction or piece of context gets proportionally less attention from the model.
  2. Conflicting information -- Earlier failed approaches, superseded decisions, and stale file contents can contradict current state, confusing the model.
  3. Instruction burial -- Important instructions from the beginning of the conversation get pushed further from the model's current focus as new content accumulates.
  4. Noise accumulation -- Irrelevant file contents, verbose command outputs, and tangential discussions add noise without signal.

The Reliability Curve

Think of the relationship between token count and output quality as a curve:

Output Quality
     ^
100% |====\
     |     \
 80% |      \
     |       \
 60% |        \
     |         \
 40% |          \=========
     |
     +---|---|---|---|---|---> Tokens Used
         5K  10K 20K 50K 100K

The exact numbers vary by task complexity, but the pattern is universal: more tokens means less reliability. This is not a Claude limitation -- it is a fundamental property of transformer-based language models.

Monitoring Context Usage

You can monitor how much context you are using:

The /cost command:

> /cost

This shows your current session's token usage and estimated cost.

The /context command:

> /context

This shows what is consuming space in your context window, broken down by category.

Custom status line: You can configure a custom status line to show context usage continuously. See the statusline documentation for setup.

Watch for these warning signs of context rot:

When you see any of these, it is time to compact, clear, or start a new session.


3. Compaction & Context Management

Compaction is the process of summarizing conversation history to free space in the context window. It is the primary tool for fighting context rot.

What Compaction Does

When compaction runs, Claude summarizes the conversation history into a condensed form. The original messages are replaced with the summary. This frees space for new work while preserving the essential decisions, code patterns, and file states from the conversation.

Think of it like compressing a zip file: you keep the important data but reduce the size. Some detail is inevitably lost.

The /compact Command

Run /compact at any time to manually trigger compaction:

> /compact

This summarizes the entire conversation. Claude decides what to keep and what to condense.

Focused compaction is more powerful. You can tell Claude what to prioritize during compaction:

> /compact Focus on the API changes and the database schema decisions
> /compact Keep the list of modified files and the test commands that work
> /compact Preserve the authentication flow design and the error handling patterns

Focused compaction gives you control over what survives summarization. Without focus instructions, Claude uses its own judgment, which may not match your priorities.

Auto-Compaction

Claude Code automatically compacts when your context reaches approximately 95% capacity. This is a safety net -- it prevents the session from failing due to context overflow.

Auto-compaction uses a general-purpose summarization strategy. It preserves code patterns, file states, and key decisions, but it may lose specific instructions or nuanced context that you care about.

The problem with relying on auto-compaction: By the time it triggers, you have been operating with a nearly-full context for a while. Output quality has already degraded. Auto-compaction is the emergency brake, not the steering wheel.

CLAUDE_AUTOCOMPACT_PCT_OVERRIDE

You can trigger compaction earlier by setting this environment variable:

# Compact when context reaches 50% capacity
export CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=50

# Compact when context reaches 70% capacity
export CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=70

Set it in your shell profile for persistence:

echo 'export CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=50' >> ~/.zshrc
source ~/.zshrc

Or in your settings.json:

{
  "env": {
    "CLAUDE_AUTOCOMPACT_PCT_OVERRIDE": "50"
  }
}

Recommended values:

Value Use Case
50 Aggressive compaction. Best for long multi-phase work where you want consistently clean context.
70 Balanced. Good default for most development work.
80 Light touch. Works for focused single-task sessions.
95 Default behavior. Emergency-only compaction.

A value of 50 means Claude compacts frequently, keeping context lean at the cost of losing some conversation history sooner. A value of 95 means Claude waits until the last moment, preserving full history but risking quality degradation.

Compaction Instructions in CLAUDE.md

You can embed compaction instructions directly in your CLAUDE.md to ensure critical information survives every compaction:

# CLAUDE.md

## Compact Instructions
When compacting, always preserve:
- The full list of modified files and their paths
- All test commands and their expected outputs
- Architecture decisions and the reasoning behind them
- The current phase and task status from .planning/
- Any error patterns we identified and their fixes

These instructions are loaded at the start of every session and persist through compaction because CLAUDE.md itself is re-read after compaction.

/clear for Full Reset

When compaction is not enough -- when the conversation has gone in too many wrong directions, or when you are switching to a completely unrelated task -- use /clear:

> /clear

This completely resets the context window. CLAUDE.md is reloaded, but all conversation history is gone. It is the equivalent of starting a fresh session without leaving your terminal.

When to /clear vs /compact:

Situation Action
Staying on the same task, need more room /compact with focus
Switching to a different task in the same project /clear
Claude is confused and going in circles /clear with a better prompt
You have corrected Claude 2+ times on the same issue /clear and restate the problem
Routine maintenance during long session /compact

What Gets Preserved vs Lost During Compaction

Always preserved:

Usually preserved (in summary):

Often lost:

Strategies for Important Information Survival

  1. Put it in CLAUDE.md -- Anything Claude must always know goes here.
  2. Put it in a file -- Write important decisions to .planning/decisions.md or similar files. Claude can re-read them.
  3. Use focused /compact -- Tell Claude exactly what to keep.
  4. Repeat critical instructions -- After compaction, restate the most important constraints.
  5. Use checkpoints -- Before compaction, save your current state by writing a status file.

Example of writing a status checkpoint before compacting:

> Before we compact, write a status file at .planning/status.md that
> captures: what we have done so far, what files we changed, what the
> current blockers are, and what we need to do next.

Then after compaction:

> Read .planning/status.md and continue from where we left off.

This pattern turns volatile conversation memory into durable file-based memory.


4. Session Management

Claude Code saves conversations locally. Every message, tool use, and result is stored. This enables resuming work across terminal sessions, days, and even weeks.

Starting Sessions

# Start a new session in the current directory
claude

# Start with a specific prompt
claude "Implement the user authentication flow"

# Start in Plan Mode (read-only exploration first)
claude --permission-mode plan

claude --continue (Resume Most Recent)

Resume the most recent conversation in the current directory:

claude --continue

This picks up exactly where you left off. Your full conversation history is restored. Session-scoped permissions (things you approved during the previous session) are NOT restored -- you will need to re-approve them.

You can also combine --continue with a prompt:

claude --continue "Now implement the tests we discussed"

claude --resume (Select from List)

Browse and select from recent sessions:

claude --resume

This opens an interactive session picker with:

Keyboard shortcuts in the picker:

Key Action
Up/Down arrows Navigate between sessions
Right/Left arrows Expand/collapse grouped sessions
Enter Resume the highlighted session
P Preview session content
R Rename the session
/ Search/filter sessions
A Toggle between current directory and all projects
B Filter to sessions from your current git branch
Esc Exit

Resume by name directly:

claude --resume auth-refactor

/rename for Descriptive Session Names

Give sessions descriptive names so you can find them later:

> /rename oauth-migration
> /rename debugging-memory-leak
> /rename phase-2-api-implementation

You can also rename from the session picker by pressing R on any session.

Naming convention for GSD work:

phase-1-discovery-auth
phase-2-design-auth
phase-3-impl-auth-api
phase-3-impl-auth-ui
phase-4-testing-auth

This makes it easy to see which phase each session belongs to and what area of the codebase it covers.

/rewind and Esc+Esc for Checkpoints

Every action Claude takes creates a checkpoint. You can restore conversation, code, or both to any previous checkpoint.

Double-tap Escape: Press Esc twice quickly to open the rewind menu. From there you can:

The /rewind command:

> /rewind

Opens the same rewind menu.

Single Escape: Press Esc once to stop Claude mid-action. Context is preserved -- you can redirect Claude immediately without rewinding.

Checkpoints persist across sessions. You can close your terminal, come back later, resume the session, and still rewind to earlier checkpoints.

Session Persistence and Storage

Sessions are stored locally in your Claude Code data directory:

~/.claude/projects/<project-hash>/sessions/

Each session contains the full transcript as JSONL (JSON Lines). Sessions are tied to the directory where they were started.

Multiple Sessions for Different Workstreams

Treat sessions like branches. Different workstreams can have separate, persistent contexts:

# Terminal 1: Working on API
claude --resume api-endpoints

# Terminal 2: Working on frontend
claude --resume frontend-components

# Terminal 3: Working on tests
claude --resume test-coverage

Each session has its own context, its own history, and its own compaction state. They do not interfere with each other.

Combining with worktrees for full isolation:

# Each worktree gets its own files AND its own session
claude -w auth-api
claude -w auth-ui
claude -w auth-tests

5. The GSD Framework (Get Stuff Done)

The GSD Framework is a structured approach to large-scale work with Claude Code. It is built on three core principles:

  1. Plan before you execute. Research the codebase, design the approach, document the plan -- all before writing a single line of implementation code.
  2. Execute in phases. Break work into discrete phases with clear boundaries, deliverables, and verification criteria.
  3. Verify after every phase. Run tests, check outputs, validate behavior. Never move to the next phase until the current one passes.

Philosophy: Plan/Execute/Verify Loops

Every phase of work follows the same loop:

[Plan]    --> What will we do? What files? What approach?
   |
   v
[Execute] --> Implement the plan. Write code. Make changes.
   |
   v
[Verify]  --> Does it work? Do tests pass? Does the behavior match?
   |
   v
[Pass?]
  |    \
  No    Yes --> Move to next phase
  |
  v
[Adjust plan and re-execute]

This loop happens at every scale:

The .planning/ Directory Structure

The GSD Framework uses a .planning/ directory in your project root to store all planning artifacts:

.planning/
  roadmap.md              # High-level overview, goals, timeline
  phases/
    phase-1-discovery.md   # Research & discovery tasks
    phase-2-design.md      # Architecture & design decisions
    phase-3-implement.md   # Implementation tasks with file assignments
    phase-4-testing.md     # Test plans and verification criteria
    phase-5-cleanup.md     # Documentation, refactoring, polish
  state.md                 # Current status: active phase, blockers, progress
  decisions.md             # Architecture decisions log (ADR-style)
  context/
    api-schema.md          # API design reference
    data-model.md          # Database schema reference
    dependencies.md        # External dependencies and versions

Add .planning/ to your .gitignore if you do not want planning artifacts in version control. Some teams prefer to commit them for visibility; others treat them as ephemeral.

Roadmap Document

The roadmap is the top-level planning document. It defines what you are building, why, and how the phases connect:

# .planning/roadmap.md

## Project: User Authentication System

### Goal
Replace the current session-based auth with JWT-based authentication
supporting OAuth2 providers (Google, GitHub).

### Success Criteria
- [ ] Users can log in with email/password
- [ ] Users can log in with Google OAuth
- [ ] Users can log in with GitHub OAuth
- [ ] JWT tokens issued with 1-hour expiry
- [ ] Refresh token rotation implemented
- [ ] All existing tests pass
- [ ] New auth endpoints have >90% test coverage
- [ ] Migration path for existing sessions documented

### Phases
1. **Discovery** -- Understand current auth system, identify all touchpoints
2. **Design** -- Define JWT schema, OAuth flow, API contracts
3. **Implementation** -- Build auth endpoints, OAuth integration, middleware
4. **Testing** -- Unit tests, integration tests, security review
5. **Cleanup** -- Documentation, migration guide, code review

### Dependencies
- Google OAuth2 API credentials (in .env)
- GitHub OAuth App credentials (in .env)
- jsonwebtoken npm package
- passport.js with Google and GitHub strategies

### Timeline Estimate
- Phase 1: 1 session (~30 min)
- Phase 2: 1-2 sessions (~1 hour)
- Phase 3: 3-5 sessions (~3 hours)
- Phase 4: 2-3 sessions (~1.5 hours)
- Phase 5: 1 session (~30 min)

Phase Documents with Task Breakdowns

Each phase gets its own document with specific, actionable tasks:

# .planning/phases/phase-3-implement.md

## Phase 3: Implementation

### Prerequisites
- Phase 2 design document approved
- API contracts finalized in .planning/context/api-schema.md
- OAuth credentials configured in .env

### Tasks

#### 3.1 JWT Token Service
- **Files:** src/services/tokenService.ts (new)
- **Description:** Create JWT generation, validation, and refresh logic
- **Acceptance Criteria:**
  - [ ] generateAccessToken(userId) returns signed JWT with 1hr expiry
  - [ ] generateRefreshToken(userId) returns signed refresh token with 7d expiry
  - [ ] validateToken(token) returns decoded payload or throws
  - [ ] refreshTokens(refreshToken) rotates both tokens
- **Status:** not started

#### 3.2 Auth Middleware
- **Files:** src/middleware/authMiddleware.ts (new)
- **Description:** Express middleware that validates JWT from Authorization header
- **Acceptance Criteria:**
  - [ ] Extracts Bearer token from Authorization header
  - [ ] Validates token using tokenService
  - [ ] Attaches decoded user to req.user
  - [ ] Returns 401 for missing/invalid tokens
  - [ ] Passes through for public routes
- **Status:** not started

#### 3.3 Auth API Endpoints
- **Files:** src/routes/auth.ts (new), src/controllers/authController.ts (new)
- **Description:** Login, register, refresh, and logout endpoints
- **Acceptance Criteria:**
  - [ ] POST /api/auth/register -- create user, return tokens
  - [ ] POST /api/auth/login -- validate credentials, return tokens
  - [ ] POST /api/auth/refresh -- rotate tokens
  - [ ] POST /api/auth/logout -- invalidate refresh token
- **Status:** not started

#### 3.4 Google OAuth Integration
- **Files:** src/services/googleOAuth.ts (new), src/routes/oauth.ts (new)
- **Status:** not started

#### 3.5 GitHub OAuth Integration
- **Files:** src/services/githubOAuth.ts (new)
- **Status:** not started

### Verification
After all tasks complete:
1. Run: `npm test -- --testPathPattern=auth`
2. Run: `npm run lint`
3. Manual test: POST /api/auth/register with valid data
4. Manual test: POST /api/auth/login with registered user
5. Manual test: GET /api/protected-route with valid JWT

State Tracking Across Phases

The state document is your "save game" -- it tells you (and Claude) exactly where things stand:

# .planning/state.md

## Current Status
- **Active Phase:** Phase 3 - Implementation
- **Active Task:** 3.2 Auth Middleware
- **Last Updated:** 2026-02-20 14:30

## Completed
- [x] Phase 1: Discovery (completed 2026-02-19)
- [x] Phase 2: Design (completed 2026-02-20 morning)
- [x] Task 3.1: JWT Token Service (completed, tests passing)

## In Progress
- [ ] Task 3.2: Auth Middleware (authMiddleware.ts created, 401 handling done, public routes TODO)

## Blocked
- Task 3.4: Google OAuth -- waiting on credentials from team lead

## Files Modified So Far
- src/services/tokenService.ts (new)
- src/services/tokenService.test.ts (new)
- src/middleware/authMiddleware.ts (new, in progress)
- package.json (added jsonwebtoken, @types/jsonwebtoken)

## Key Decisions
- Using RS256 algorithm for JWT signing (see decisions.md #3)
- Refresh tokens stored in database, not in JWT (see decisions.md #4)

## Next Steps
1. Finish public route passthrough in authMiddleware.ts
2. Write auth middleware tests
3. Start Task 3.3: Auth API Endpoints

User Acceptance Testing per Phase

After each phase, you verify the work before moving on. This can be as simple as running tests or as thorough as manual testing:

> Read .planning/phases/phase-3-implement.md and check off each
> acceptance criterion. Run the tests. Update .planning/state.md
> with the results. If anything fails, list the failures and what
> needs to be fixed before we can move to Phase 4.

Complete Example: Building a Feature with GSD

Here is a condensed walkthrough of the GSD framework for adding a notification system:

Session 1: Discovery (Phase 1)

claude --permission-mode plan
> Read .planning/roadmap.md for context. We are starting Phase 1:
> Discovery for the notification system. Investigate:
> 1. How the current messaging system works (src/services/messaging/)
> 2. What database tables exist for user preferences
> 3. How the WebSocket connection is set up
> 4. What notification patterns exist in the codebase already
>
> Write findings to .planning/phases/phase-1-discovery.md
> Update .planning/state.md to reflect Phase 1 in progress.
> /rename phase-1-discovery-notifications

Session 2: Design (Phase 2)

claude
> Read .planning/phases/phase-1-discovery.md for our research findings.
> Design the notification system:
> 1. Database schema for notifications table
> 2. API contract for notification endpoints
> 3. WebSocket event schema for real-time delivery
> 4. UI component hierarchy
>
> Write the design to .planning/phases/phase-2-design.md
> Write the API schema to .planning/context/api-schema.md
> Update .planning/state.md

Sessions 3-5: Implementation (Phase 3)

claude
> Read .planning/state.md for current status and
> .planning/phases/phase-3-implement.md for the task list.
> Start with Task 3.1: Notification Database Schema.
> After each task, update state.md with completion status.

Session 6: Testing (Phase 4)

claude
> Read .planning/state.md. We are starting Phase 4: Testing.
> Read .planning/phases/phase-4-testing.md for the test plan.
> Write and run all tests. Update state.md with results.

6. Phase-Based Planning in Detail

Phase 1: Discovery & Research

Goal: Understand the existing codebase and constraints before making any changes.

Activities:

Best practice: Use Plan Mode (--permission-mode plan or Shift+Tab) so Claude cannot accidentally modify files during research.

Best practice: Use subagents for research to keep your main context clean:

> Use subagents to investigate:
> 1. How the current auth middleware works in src/middleware/
> 2. What database models exist for users in src/models/
> 3. What test patterns are used in src/__tests__/
> Report findings back as a summary.

Output: A discovery document with findings, a list of files to modify, and a list of patterns to follow.

Phase 2: Architecture & Design

Goal: Design the solution before writing code.

Activities:

Best practice: Press Ctrl+G to open the plan in your text editor for direct editing before Claude proceeds with implementation.

Output: Design documents, API schemas, architecture decision records, and a task breakdown for Phase 3.

Phase 3: Implementation

Goal: Build the solution according to the design.

Activities:

Best practice: Implement one task at a time. After each task, run tests and compact:

> Task 3.1 is complete. Run the tests for tokenService.
> Update .planning/state.md with the results.
> /compact Focus on the current implementation progress and remaining tasks

Best practice: Start new sessions for each major task if context is getting heavy:

claude --resume phase-3-impl-auth
> Read .planning/state.md for where we left off.
> Continue with Task 3.3: Auth API Endpoints.

Output: Working code with unit tests passing.

Phase 4: Testing & Verification

Goal: Validate that the implementation works correctly and handles edge cases.

Activities:

Best practice: Use a dedicated verification subagent:

# .claude/agents/verify-app.md
---
name: verify-app
description: Runs full verification suite. Use before completing any phase.
tools: Bash, Read, Grep
model: sonnet
---

Run the full verification pipeline:
1. Lint: npm run lint
2. Type check: npx tsc --noEmit
3. Tests: npm test
4. Build: npm run build

Report pass/fail for each step with full error output for failures.

Output: All tests passing, linting clean, build successful.

Phase 5: Documentation & Cleanup

Goal: Polish the implementation and document it for future developers.

Activities:

Output: Clean, documented, production-ready code.

How to Break Large Projects into Phases

The phases above are a template. Adapt them to your project:

Small feature (1-2 sessions):

Phase 1: Quick exploration + implementation
Phase 2: Testing + cleanup

Medium feature (3-5 sessions):

Phase 1: Discovery
Phase 2: Implementation
Phase 3: Testing
Phase 4: Cleanup

Large feature (5+ sessions):

Phase 1: Discovery & Research
Phase 2: Architecture & Design
Phase 3a: Implementation - Core
Phase 3b: Implementation - Integration
Phase 3c: Implementation - UI
Phase 4: Testing & Verification
Phase 5: Documentation & Cleanup

System redesign (10+ sessions): Break the system into components. Each component gets its own set of phases:

Component A: Phases 1-5
Component B: Phases 1-5
Integration: Phases 3-5

Dependencies Between Phases

Map dependencies explicitly in your roadmap:

## Phase Dependencies

Phase 1 --> Phase 2 (design depends on discovery findings)
Phase 2 --> Phase 3a, 3b, 3c (implementation depends on design)
Phase 3a --> Phase 3b (integration depends on core)
Phase 3a, 3b --> Phase 3c (UI depends on API)
Phase 3a, 3b, 3c --> Phase 4 (testing needs all code)
Phase 4 --> Phase 5 (cleanup after tests pass)

Phases without dependencies can run in parallel (using separate sessions or agent teams from Level 6).

Example .planning/ Directory Tree

A fully fleshed-out planning directory for a real project:

.planning/
  roadmap.md
  state.md
  decisions.md
  phases/
    phase-1-discovery.md
    phase-2-design.md
    phase-3a-impl-core.md
    phase-3b-impl-integration.md
    phase-3c-impl-ui.md
    phase-4-testing.md
    phase-5-cleanup.md
  context/
    api-schema.md
    data-model.md
    dependencies.md
    existing-patterns.md
    security-requirements.md
  archive/
    phase-1-raw-notes.md
    exploration-scratch.md

7. Context Isolation Strategies

The core idea: store context in files, not in conversation. Files persist across sessions, survive compaction, and can be selectively loaded. Conversation memory is volatile, fills the context window, and degrades over time.

Store Context in Individual Files

Instead of asking Claude to "remember" something, ask Claude to write it to a file:

> Don't just tell me the findings -- write them to
> .planning/phases/phase-1-discovery.md so we can reference them later.

Instead of re-explaining context at the start of each session:

> Read .planning/state.md and .planning/context/api-schema.md
> for the current state of the project.

Project Context Files

Create a .claude/context/ directory for project-level reference material:

.claude/
  context/
    architecture.md        # System architecture overview
    coding-standards.md    # Code style and patterns
    api-reference.md       # API endpoints and contracts
    deployment.md          # Deployment procedures
    troubleshooting.md     # Common issues and fixes

These files can be referenced from CLAUDE.md using @ syntax:

# CLAUDE.md

## Project Context
- Architecture overview: @.claude/context/architecture.md
- API reference: @.claude/context/api-reference.md
- Coding standards: @.claude/context/coding-standards.md

Architecture Decision Records

Document important decisions so Claude can understand "why" things are the way they are:

# .planning/decisions.md

## ADR-001: JWT over Session Tokens
**Date:** 2026-02-19
**Status:** Accepted
**Decision:** Use JWT tokens instead of server-side sessions
**Rationale:** Enables stateless auth, simplifies horizontal scaling,
supports microservice architecture we are planning for Q3.
**Consequences:** Need to handle token revocation explicitly (no server-side session to invalidate).

## ADR-002: RS256 over HS256 for JWT Signing
**Date:** 2026-02-20
**Status:** Accepted
**Decision:** Use RS256 (asymmetric) instead of HS256 (symmetric)
**Rationale:** Allows services to verify tokens without access to the signing key.
Only the auth service needs the private key.
**Consequences:** Slightly slower verification, need to manage key pairs.

Using Subagents to Offload Research

Subagents run in their own context window, completely separate from your main conversation. They explore, read files, and analyze code without cluttering your context. When done, they return a summary.

> Use a subagent to investigate how our current rate limiting works.
> Check src/middleware/ for rate limiting middleware, src/config/ for
> rate limit settings, and any tests related to rate limiting.
> Report back a summary of findings.

The subagent might read 20 files and consume 15K tokens doing so. Your main context only receives the summary -- maybe 500 tokens.

This is one of the most powerful context management techniques. Use subagents for:

The "File as Memory" Pattern

This pattern treats files as Claude's persistent memory:

  1. Before starting work: Write the plan to a file
  2. During work: Update the state file after each completed task
  3. Before compacting: Write current status to a checkpoint file
  4. After compacting/clearing: Read the checkpoint file to restore context
  5. Between sessions: All state is in files, ready for the next session

Example workflow:

> Write our implementation plan to .planning/phases/phase-3-implement.md

(Work happens, context fills up)

> Update .planning/state.md with what we have completed so far.
> /compact Focus on remaining work from .planning/state.md

(Context is compacted, details are lost, but state.md is still on disk)

> Read .planning/state.md to see where we are.
> Read .planning/phases/phase-3-implement.md for the next task.
> Continue.

The conversation context can be completely reset, but the project state persists in files.


8. The Plan-Execute-Verify Loop

Plan Mode for Research and Design

Plan Mode restricts Claude to read-only operations. Claude can read files, search the codebase, and answer questions, but it cannot write files, run commands that modify state, or make changes.

Enter Plan Mode:

Plan Mode is ideal for:

Edit the plan directly: Press Ctrl+G to open the plan in your default text editor. You can edit Claude's plan directly before switching to implementation mode.

Implementation Mode for Coding

Switch back to Normal Mode (or Auto-Accept Mode) when you are ready to implement:

Shift+Tab  --> cycles through: Default -> Auto-Accept -> Plan Mode

In Normal Mode, Claude asks permission for file writes and shell commands. In Auto-Accept Mode, Claude edits files without asking but still asks for shell commands.

Implementation best practices:

Verification (Tests, Linting, Manual Checks)

Verification is the step most people skip, and the one that matters most. After every implementation step:

> Run the tests for the code we just wrote.
> If tests pass, update .planning/state.md and move to the next task.
> If tests fail, fix them before moving on.

Types of verification:

Type When to Use Command Example
Unit tests After every function/module npm test -- --testPathPattern=auth
Type checking After any TypeScript changes npx tsc --noEmit
Linting After any code changes npm run lint
Integration tests After connecting components npm run test:integration
Build verification After significant changes npm run build
Manual testing For UI or user-facing features Start dev server and check

When to Loop Back to Planning

Go back to Plan Mode when:

> The integration tests are revealing that our token refresh approach
> will not work with the WebSocket connection. Switch to Plan Mode.
> Let us redesign the refresh flow.

Setting Up Verification Hooks

Automate verification with hooks so it happens every time, not just when you remember:

// .claude/settings.json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "npx tsc --noEmit 2>&1 | head -20",
            "timeout": 30,
            "statusMessage": "Type checking..."
          }
        ]
      }
    ]
  }
}

This runs the TypeScript compiler after every file edit, catching type errors immediately rather than at the end of the session.


9. Working with Large Codebases

Large codebases amplify every context management challenge. A single file read in a monorepo can pull in thousands of tokens. Understanding the system requires reading dozens of files. The GSD framework becomes essential at this scale.

Strategies for Monorepos

Monorepos present a unique challenge: the codebase is so large that Claude cannot hold all of it in context. You need to be surgical about what Claude reads.

Scope your work explicitly:

> We are only working in packages/auth/. Do not read or modify
> files outside of this package unless I specifically ask.

Use CLAUDE.md to set boundaries:

# CLAUDE.md

## Monorepo Structure
This is a pnpm workspace monorepo. Key packages:
- packages/auth/ -- Authentication service (OUR FOCUS)
- packages/api/ -- API gateway
- packages/shared/ -- Shared utilities
- packages/web/ -- Frontend app

## Current Work Scope
We are working exclusively in packages/auth/. Only reference other
packages for their exported interfaces, never their internals.

.claudeignore

The .claudeignore file works like .gitignore -- it tells Claude Code to skip certain files and directories during searches and exploration:

# .claudeignore

# Build outputs
dist/
build/
*.min.js

# Dependencies
node_modules/

# Large generated files
*.lock
coverage/

# Data files
*.csv
*.sql
*.db

# Irrelevant packages in monorepo
packages/legacy/
packages/deprecated/
packages/docs-site/

Place .claudeignore in your project root. This prevents Claude from wasting context on files that are never relevant to development work.

Targeted Context Loading

Instead of letting Claude explore freely, point it directly to what matters:

> Read only these files for context:
> @src/services/tokenService.ts
> @src/middleware/authMiddleware.ts
> @src/routes/auth.ts
> Then implement the refresh token rotation.

Use @ references to load specific files without requiring Claude to search for them.

Using Explore Subagent for Reconnaissance

Before starting implementation in a large codebase, send out a scout:

> Use a subagent to explore the codebase and answer these questions:
> 1. What test framework is used? Where are test files located?
> 2. What is the directory structure for services?
> 3. Are there existing auth-related files we should know about?
> 4. What database ORM is used and where are the models?
> Report back a concise summary.

The subagent reads as many files as needed, but your main context only gets the summary. This is dramatically more context-efficient than exploring yourself.

Breaking Work into Independent Pieces

For large features, identify pieces that can be developed independently:

## Independent Work Streams

### Stream A: Token Service (no dependencies)
- tokenService.ts
- tokenService.test.ts

### Stream B: Auth Middleware (depends on Token Service interface only)
- authMiddleware.ts
- authMiddleware.test.ts

### Stream C: OAuth Integration (depends on Token Service interface only)
- googleOAuth.ts
- githubOAuth.ts
- oauth.test.ts

### Stream D: API Endpoints (depends on all above)
- authController.ts
- auth.routes.ts
- auth.integration.test.ts

Streams A, B, and C can be built in parallel (separate sessions, or even agent teams). Stream D integrates everything at the end.


10. Advanced Session Patterns

Dedicated Sessions per Feature Branch

Create a one-to-one mapping between git branches and Claude sessions:

# Create branch and session together
git checkout -b feature/oauth-integration
claude
> /rename feature-oauth-integration

When you switch branches, start or resume the matching session:

git checkout feature/oauth-integration
claude --resume feature-oauth-integration

This keeps each session's context relevant to the work on that branch.

Research Session to Implementation Session Handoff

The most effective pattern for complex features:

Session 1: Research (Read-Only)

claude --permission-mode plan
> Investigate the current auth system. Write findings to
> .planning/phases/phase-1-discovery.md
> /rename research-auth-system

(Claude explores extensively, fills context with file contents)

Session 2: Implementation (Clean Context)

claude
> Read .planning/phases/phase-1-discovery.md and
> .planning/phases/phase-3-implement.md
> Start implementing Task 3.1: JWT Token Service
> /rename impl-auth-tokens

The implementation session starts with a clean context. It loads only the distilled research findings (from a file), not the full exploration history. This produces dramatically better implementation quality.

Shared Context Through Files

When multiple sessions need to coordinate, share context through files:

Session A (API work):
> Write the API schema to .planning/context/api-schema.md when done.

Session B (UI work):
> Read .planning/context/api-schema.md for the API contract.
> Implement the frontend to match.

This is a lightweight coordination pattern that does not require agent teams or messaging. It works because files are shared across all sessions in the same directory.

Using Git Commits as Checkpoints

Combine Git with the GSD framework for robust checkpointing:

> We finished Task 3.1. Commit the changes with a descriptive message.
> Update .planning/state.md to mark Task 3.1 complete.

If something goes wrong later, you can:

  1. Use /rewind to restore Claude's context
  2. Use git revert or git reset to restore the code
  3. Resume from the last known-good state documented in state.md

11. Combining GSD with Other Levels

The GSD framework integrates with everything you learned in Levels 1-4. Here is how they combine.

GSD + CLAUDE.md (Level 2)

Your CLAUDE.md file is loaded at the start of every session and reloaded after every compaction. Use it to embed GSD instructions:

# CLAUDE.md

## GSD Framework
This project uses the GSD planning framework.
- Planning artifacts are in .planning/
- Always read .planning/state.md at the start of a session
- After completing any task, update .planning/state.md
- Follow the phase structure in .planning/roadmap.md

## Compact Instructions
When compacting, always preserve:
- Current phase and task status from .planning/state.md
- The list of files modified in the current phase
- Any blocking issues or open questions

Because CLAUDE.md is persistent, these instructions survive compaction and session restarts.

GSD + Hooks (Level 3)

Hooks can automate the verify step of the plan-execute-verify loop:

// .claude/settings.json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "npx tsc --noEmit 2>&1 | tail -5",
            "timeout": 30,
            "statusMessage": "Type checking after edit..."
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "osascript -e 'display notification \"Claude completed a task\" with title \"GSD Framework\"'"
          }
        ]
      }
    ]
  }
}

With this configuration:

GSD + Subagents (Level 5)

Subagents are the primary tool for keeping research out of your main context:

> Use a subagent to review the code we just wrote in src/services/tokenService.ts
> for security issues, edge cases, and consistency with our patterns.

Create specialized subagents for GSD workflows:

# .claude/agents/phase-reviewer.md
---
name: phase-reviewer
description: Reviews completed phase work against acceptance criteria.
tools: Read, Grep, Glob, Bash
model: sonnet
---

Review the completed phase work:
1. Read the phase document for acceptance criteria
2. Check each criterion against the actual implementation
3. Run relevant tests
4. Report pass/fail for each criterion
5. List any issues that must be fixed before moving to the next phase

GSD + Agent Teams (Level 6)

For large projects, combine GSD phases with agent teams for parallel execution:

Phase 3 tasks that are independent:
- Agent 1 (backend-dev): Task 3.1 + 3.2 (token service + middleware)
- Agent 2 (oauth-dev): Task 3.4 + 3.5 (Google + GitHub OAuth)
- Agent 3 (test-writer): Write test scaffolding for all tasks

Phase 4 (after Phase 3 completes):
- Agent 1 (integration-tester): Run full integration suite
- Agent 2 (security-reviewer): Security audit

The .planning/ directory serves as the shared coordination layer. All agents read the same roadmap, phase documents, and state file. The team lead updates state.md as agents complete their tasks.


12. Exercises

Exercise 1: Context Monitoring

Goal: Develop intuition for context usage.

  1. Start a new Claude Code session
  2. Run /cost and note the starting token count
  3. Ask Claude to read 3 files from your project
  4. Run /cost again -- how much did reading those files cost?
  5. Have Claude run a test suite and capture the output
  6. Run /cost -- how much did the test output cost?
  7. Try /compact Focus on the test results only
  8. Run /cost -- how much space did compaction free?

What you should learn: File reads and command outputs are the biggest context consumers, not your messages or Claude's responses.

Exercise 2: The Compaction Drill

Goal: Practice different compaction strategies.

  1. Start a session and work on any task for at least 10 messages
  2. Run /compact with no instructions -- note what is preserved
  3. Use /rewind to go back to before the compaction
  4. Run /compact Preserve only the file changes and test commands
  5. Compare the two compaction results
  6. Try /compact with your own custom focus instructions
  7. Add compaction instructions to your CLAUDE.md

What you should learn: Focused compaction preserves dramatically more relevant context than unfocused compaction.

Exercise 3: The File-as-Memory Pattern

Goal: Practice storing and retrieving context from files.

  1. Create a .planning/ directory in your project
  2. Ask Claude to explore a module in your codebase and write findings to .planning/exploration.md
  3. Run /clear to completely reset the context
  4. Start a new message: "Read .planning/exploration.md and summarize what we learned"
  5. Verify that Claude can reconstruct the key findings from the file alone

What you should learn: Files are more durable than conversation memory. You can completely clear context and restore it from files.

Exercise 4: Build a GSD Planning Directory

Goal: Create a complete .planning/ structure for a real feature.

  1. Pick a feature you want to build (or a feature from a project you know well)
  2. Create the .planning/ directory structure:
    .planning/
      roadmap.md
      state.md
      decisions.md
      phases/
        phase-1-discovery.md
        phase-2-design.md
        phase-3-implement.md
        phase-4-testing.md
        phase-5-cleanup.md
      context/
    
  3. Fill in the roadmap with goals, success criteria, phases, and timeline
  4. Write the Phase 1 discovery document with specific investigation tasks
  5. Have Claude review your planning documents for completeness

What you should learn: Planning upfront saves significant time during implementation. The structure forces you to think through the work before starting.

Exercise 5: Research-to-Implementation Handoff

Goal: Practice the two-session handoff pattern.

  1. Start a session in Plan Mode: claude --permission-mode plan
  2. Have Claude research a specific module in your codebase
  3. Write all findings to .planning/phases/phase-1-discovery.md
  4. Name the session: /rename research-[module-name]
  5. Start a completely new session: /clear or open a new terminal
  6. In the new session, load only the discovery document: "Read .planning/phases/phase-1-discovery.md and propose a refactoring plan"
  7. Compare the quality of Claude's output in the clean session vs if you had continued in the research session

What you should learn: A clean session with file-based context produces better implementation plans than a session cluttered with exploration history.

Exercise 6: Session Management Workflow

Goal: Practice managing multiple named sessions.

  1. Create three named sessions for different aspects of a project:
    claude
    > /rename api-work
    > /clear
    
    > /rename frontend-work
    > /clear
    
    > /rename test-coverage
    
  2. Do some work in each session (at least 3-4 messages each)
  3. Close your terminal entirely
  4. Reopen and use claude --resume to browse sessions
  5. Resume each session by name: claude --resume api-work
  6. Verify that each session's context is independent

What you should learn: Named sessions let you context-switch between workstreams without losing progress in any of them.

Exercise 7: Set Up CLAUDE_AUTOCOMPACT_PCT_OVERRIDE

Goal: Experience the difference between early and late compaction.

  1. Set CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=50 in your environment
  2. Work on a medium-complexity task (reading several files, making edits)
  3. Notice when auto-compaction triggers (should happen earlier than usual)
  4. Change to CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=80
  5. Do similar work and compare
  6. Choose the value that feels right for your workflow and add it to your settings

What you should learn: Lower values keep context cleaner at the cost of losing history sooner. Higher values preserve more history but risk quality degradation.


13. Pro Tips from Boris Cherny

Boris Cherny is an engineer at Anthropic who works on Claude Code. His publicly documented workflow provides some of the best practical guidance for working with Claude at scale.

"The Context Window is the Most Important Resource"

This is the foundational insight. Everything else in this guide follows from it. When Boris works with Claude Code, he monitors context usage continuously and makes decisions based on it:

"A Good Plan is Really Important"

Boris uses Plan Mode extensively before implementing anything non-trivial. His workflow:

  1. Enter Plan Mode
  2. Go back and forth with Claude until the plan is solid
  3. Press Ctrl+G to edit the plan directly in his text editor
  4. Switch to implementation mode
  5. Let Claude execute the plan

The plan serves as an anchor. When context gets compacted, the plan (stored as a file or re-loaded from CLAUDE.md context) survives. Without a plan, Claude drifts.

"Use Subagents to Keep Exploration Out of Main Context"

When Boris needs to understand something about the codebase, he does not explore in his main session. He delegates:

> Use subagents to investigate how our authentication system handles
> token refresh, and whether we have any existing OAuth utilities
> I should reuse.

The subagent explores 20 files, consuming 15K tokens in its own context window. Boris's main context receives a 500-token summary. This is a 30x context efficiency gain.

Track Context Usage Continuously

Boris does not wait for auto-compaction to tell him context is full. He monitors it proactively:

Custom Subagents for Repetitive Tasks

Boris creates purpose-built subagents for tasks he does frequently:

These agents have focused prompts and limited tool access, making them fast and context-efficient.


14. Anti-Patterns

Anti-Pattern 1: Trying to Do Everything in One Session

What it looks like: You start with a research question, then implement a feature, then debug a different issue, then write tests for something else. The session is 50+ messages deep.

Why it fails: By message 20, Claude has forgotten the constraints from message 3. By message 40, the context is a jumble of unrelated work. Auto-compaction summarizes everything into a mush.

Fix: One session, one task. Use /clear between unrelated tasks. Use /rename so you can find sessions later.

Anti-Pattern 2: Never Compacting

What it looks like: You work for an hour in a single session without ever running /compact. You rely entirely on auto-compaction at 95%.

Why it fails: Output quality degrades steadily from 20% context usage onward. By the time auto-compaction triggers, you have been producing lower-quality work for a while. And the auto-compaction at 95% is a blunt instrument -- it does not know what you care about.

Fix: Compact proactively. Set CLAUDE_AUTOCOMPACT_PCT_OVERRIDE to 50-70. Run /compact with focus instructions when you notice context building up.

Anti-Pattern 3: Not Using Plan Mode for Large Features

What it looks like: You jump straight to "implement OAuth2 login." Claude starts writing code immediately without understanding the existing auth system.

Why it fails: Claude builds something that does not fit the existing architecture. You spend more time correcting than you would have spent planning.

Fix: Use Plan Mode first. Explore the codebase. Understand the patterns. Create a plan. Then implement.

Anti-Pattern 4: Ignoring Context Rot Symptoms

What it looks like: Claude asks you a question you already answered. Claude produces code that contradicts its own earlier changes. Claude uses a pattern from the wrong part of the codebase. You think "Claude is being dumb" and keep pushing.

Why it fails: These are not intelligence failures -- they are context failures. Claude literally cannot "see" the earlier information as clearly. More messages will not fix it; they will make it worse.

Fix: Recognize the symptoms. When you see them, /compact with focused instructions or /clear and restart with a better prompt.

Anti-Pattern 5: Storing All Context in Conversation

What it looks like: You tell Claude about your architecture decisions, API schema, deployment process, and coding standards all in conversation messages. After compaction, Claude forgets half of it.

Why it fails: Conversation memory is volatile. Compaction summarizes and condenses it. Details are lost.

Fix: Put persistent context in files. CLAUDE.md for things Claude needs every session. .planning/ files for project-specific context. .claude/context/ for reference material. Files survive compaction.

Anti-Pattern 6: Mega-CLAUDE.md Files

What it looks like: Your CLAUDE.md is 500+ lines with every possible instruction, style guide, and workflow documented in detail.

Why it fails: CLAUDE.md is loaded into context at the start of every session and reloaded after every compaction. A huge file consumes significant context before you even start working. Worse, when the file is too long, Claude starts ignoring parts of it.

Fix: Keep CLAUDE.md concise. If Claude already does something correctly without the instruction, remove it. Move detailed reference material to separate files that Claude can read on demand (skills or .claude/context/ files).

Anti-Pattern 7: No Verification Step

What it looks like: Claude implements a feature. You read the code, it looks right. You move on. No tests were run. No linting was done.

Why it fails: Code that "looks right" often has subtle bugs. Without verification, they compound. You discover them later when the context is completely different, making debugging harder.

Fix: Every implementation step ends with verification. Run tests. Run the linter. Check the build. Set up hooks to automate this. Never skip verification.


15. Official Documentation Links

Core Concepts

Context & Session Management

Extensions

Configuration

Scaling

Community Resources


Last Updated: 2026-02-20 Part of the Claude Code Upskilling Path -- Level 5 of 7 Compiled from official Anthropic documentation and community best practices