The definitive guide to context management, session control, and phase-based planning -- from understanding context rot to building complete
The definitive guide to context management, session control, and phase-based planning -- from understanding context rot to building complete planning workflows that scale.
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.
You should already be comfortable with:
If those feel solid, you are ready.
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 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 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:
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.
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.
Compaction is the process of summarizing conversation history to free space in the context window. It is the primary tool for fighting context rot.
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.
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.
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.
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.
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.
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 |
Always preserved:
Usually preserved (in summary):
Often lost:
.planning/decisions.md or similar files. Claude can re-read them.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.
Claude Code saves conversations locally. Every message, tool use, and result is stored. This enables resuming work across terminal sessions, days, and even weeks.
# 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
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"
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
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.
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.
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.
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
The GSD Framework is a structured approach to large-scale work with Claude Code. It is built on three core principles:
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 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.
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)
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
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
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.
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.
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.
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.
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.
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.
Goal: Polish the implementation and document it for future developers.
Activities:
Output: Clean, documented, production-ready code.
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
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).
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
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.
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.
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
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.
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:
This pattern treats files as Claude's persistent memory:
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.
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:
Shift+Tab twice during a session (first tap enables auto-accept edits, second enables Plan Mode)claude --permission-mode planclaude --permission-mode plan -p "..."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.
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 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 |
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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:
/rewind to restore Claude's contextgit revert or git reset to restore the codestate.mdThe GSD framework integrates with everything you learned in Levels 1-4. Here is how they combine.
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.
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:
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
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.
Goal: Develop intuition for context usage.
/cost and note the starting token count/cost again -- how much did reading those files cost?/cost -- how much did the test output cost?/compact Focus on the test results only/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.
Goal: Practice different compaction strategies.
/compact with no instructions -- note what is preserved/rewind to go back to before the compaction/compact Preserve only the file changes and test commands/compact with your own custom focus instructionsWhat you should learn: Focused compaction preserves dramatically more relevant context than unfocused compaction.
Goal: Practice storing and retrieving context from files.
.planning/ directory in your project.planning/exploration.md/clear to completely reset the contextWhat you should learn: Files are more durable than conversation memory. You can completely clear context and restore it from files.
Goal: Create a complete .planning/ structure for a real feature.
.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/
What you should learn: Planning upfront saves significant time during implementation. The structure forces you to think through the work before starting.
Goal: Practice the two-session handoff pattern.
claude --permission-mode plan.planning/phases/phase-1-discovery.md/rename research-[module-name]/clear or open a new terminalWhat you should learn: A clean session with file-based context produces better implementation plans than a session cluttered with exploration history.
Goal: Practice managing multiple named sessions.
claude
> /rename api-work
> /clear
> /rename frontend-work
> /clear
> /rename test-coverage
claude --resume to browse sessionsclaude --resume api-workWhat you should learn: Named sessions let you context-switch between workstreams without losing progress in any of them.
Goal: Experience the difference between early and late compaction.
CLAUDE_AUTOCOMPACT_PCT_OVERRIDE=50 in your environmentCLAUDE_AUTOCOMPACT_PCT_OVERRIDE=80What you should learn: Lower values keep context cleaner at the cost of losing history sooner. Higher values preserve more history but risk quality degradation.
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.
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:
Boris uses Plan Mode extensively before implementing anything non-trivial. His workflow:
Ctrl+G to edit the plan directly in his text editorThe 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.
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.
Boris does not wait for auto-compaction to tell him context is full. He monitors it proactively:
/cost periodically to check token usage/context to see what is consuming spaceBoris creates purpose-built subagents for tasks he does frequently:
These agents have focused prompts and limited tool access, making them fast and context-efficient.
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.
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.
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.
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.
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.
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).
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.
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
New techniques, real-world patterns, and Claude updates — delivered as the guides evolve.