Learning Objectives
- Understand Claude Code's six core file tools and when to use each
- Learn how Claude autonomously explores your codebase using the gather phase
- Master @ mentions and strategies for guiding Claude through large projects
- Apply permission modes and navigate real-world codebases effectively
Claude Code doesn't just read your files — it explores them intelligently. When you ask Claude to "add authentication to the API," it doesn't randomly grep through thousands of files. It follows patterns, reads related modules, and builds a mental model of your codebase before making changes.
This lesson reveals the tool system powering that exploration: six core tools Claude uses to read, search, and modify your code. You'll learn not just what each tool does, but how Claude thinks when using them — and how to guide that exploration for better results.
The Tool System: Unix Philosophy for AI
Claude Code operates on a simple principle: one tool, one job, done well. Each tool in Claude's arsenal has a focused purpose:
- Read files
- Edit specific strings
- Write new files
- Glob for file patterns
- Grep for code patterns
- Bash for shell commands
When you ask Claude to do something, it autonomously selects the right tools. Ask it to "refactor the auth module," and Claude might:
- Use Glob to find
src/auth/**/*.ts - Use Read to examine
auth/login.tsandauth/token.ts - Use Grep to find all imports of
AuthService - Use Edit to update function signatures
- Use Bash to run tests
You don't orchestrate this — Claude does. Your job is to guide the exploration, not micromanage the tools.
Core File Tools: Deep Dive
Read: The Explorer
Read is Claude's eyes into your codebase. It loads file contents so Claude can analyze code, understand structure, and make informed decisions.
Basic usage:
Read /path/to/file.ts
What makes Read powerful:
-
Line offsets for large files: If a file has 10,000 lines, Claude can read lines 500-600 instead of loading everything.
Read /path/to/huge-file.ts (offset: 500, limit: 100) -
Multimodal support: Read works with more than just text.
- Images: Claude can read PNG, JPG files and describe what's in them.
- PDFs: Specify page ranges for large documents (e.g.,
pages: "1-5"). - Jupyter notebooks: Reads all cells with outputs, combining code and visualizations.
-
Auto-read with @ mentions: When you reference
@file.tsin your message, Claude automatically reads it. No manual Read tool call needed.
Example scenario:
You: "Why is the homepage loading slowly? @src/app/page.tsx"
Claude automatically reads page.tsx, might notice a heavy component import, then reads that component file to diagnose the bottleneck.
@ Mentions Are Your Navigation System
Use @ mentions liberally. Reference specific files (@auth/login.ts), directories (@src/components), or even screenshots (@screenshots/error.png). Claude will read what it needs to understand your question.
Edit: The Surgeon
Edit performs precise, surgical changes to existing files. It uses an old_string/new_string pattern — like find-and-replace, but with context.
Basic pattern:
Edit /path/to/file.ts
old_string: "function login(username: string)"
new_string: "function login(username: string, rememberMe: boolean)"
Critical rules:
-
old_string must be unique: If the same string appears twice in a file, Edit fails. Provide more surrounding context to make it unique.
Bad (ambiguous):
old_string: "const API_URL"Good (unique):
old_string: "const API_URL = 'https://api.example.com';\nconst TIMEOUT = 5000;" -
Preserve exact indentation: The indentation in
old_stringmust match the file exactly (spaces vs tabs, number of spaces). -
replace_all for renaming: Use the
replace_all: trueflag to rename variables/functions across a file.Edit /path/to/file.ts (replace_all: true) old_string: "oldFunctionName" new_string: "newFunctionName"
When Edit fails, it's usually because:
- The old_string doesn't exist exactly as written (whitespace mismatch)
- The old_string appears multiple times (not unique)
- You included line numbers from Read output (strip those out)
Write: The Creator
Write creates new files or completely overwrites existing ones. Use it sparingly — prefer Edit for existing files.
Basic usage:
Write /path/to/new-file.ts
content: "export const config = { apiUrl: '...' };"
Key restrictions:
- Must Read before Write for existing files: Claude must read a file before overwriting it. This prevents accidental data loss.
- No emoji by default: Claude won't add emojis to files unless you explicitly request them.
- Prefer Edit over Write: Editing preserves file history better in git, and Edit fails gracefully if something's wrong.
When to use Write:
- Creating new configuration files (
.env,tsconfig.json) - Generating boilerplate (components, tests)
- Creating documentation that doesn't exist yet
When NOT to use Write:
- Updating existing code (use Edit)
- Refactoring (use Edit)
- Fixing bugs (use Edit)
Glob: The Pattern Matcher
Glob finds files by name pattern. It's fast, works on any codebase size, and returns results sorted by modification time (newest first).
Common patterns:
Glob "**/*.ts" # All TypeScript files
Glob "src/**/*.tsx" # All TSX files in src/
Glob "**/*.test.ts" # All test files
Glob "components/**/Button*" # All Button-related files in components/
When to use Glob:
- Finding files by naming convention (e.g., all
*.config.jsfiles) - Listing files in a directory
- Discovering related files (e.g., all components in a folder)
Glob vs Grep:
- Glob: Matches file names/paths
- Grep: Searches file contents
Example workflow:
You: "Find all API route files"
Claude: Glob "src/app/api/**/*.ts"
Result:
- src/app/api/auth/route.ts
- src/app/api/users/route.ts
- src/app/api/posts/route.ts
Grep: The Code Hunter
Grep searches file contents using regex. It's powered by ripgrep (fast, powerful, designed for code search).
Three output modes:
-
files_with_matches (default): Returns file paths that match.
Grep pattern="AuthService" Result: src/auth/login.ts, src/auth/token.ts, src/app/api/auth/route.ts -
content: Shows matching lines with context.
Grep pattern="function.*login" output_mode="content" context=2 Result: src/auth/login.ts:15 14: */ 15: function loginUser(username: string, password: string) { 16: return authService.authenticate({ username, password }); -
count: Shows number of matches per file.
Grep pattern="TODO" output_mode="count" Result: src/auth/login.ts (3), src/app/page.tsx (1)
Advanced features:
-
Regex support: Use full regex syntax.
Grep pattern="log.*Error" # Matches logError, logger.Error, etc. -
Glob filtering: Search only specific file types.
Grep pattern="useState" glob="**/*.tsx" -
Type filtering: Use common file type shortcuts.
Grep pattern="def " type="py" # Only Python files -
Case-insensitive: Use the
-iflag.Grep pattern="api_key" -i=true # Matches API_KEY, api_key, ApiKey -
Multiline matching: For patterns spanning multiple lines.
Grep pattern="interface.*\\{[\\s\\S]*?email" multiline=true
Example scenario:
You: "Where do we use the old API endpoint?"
Claude: Grep pattern="api.old-domain.com" output_mode="content"
Result: Shows all files + line numbers where the old endpoint appears.
Grep Uses Ripgrep Syntax
Grep uses ripgrep, not traditional grep. For literal braces in Go/TypeScript, escape them: interface\\{\\} to find interface{}.
Bash: The Swiss Army Knife
Bash executes shell commands. Use it for git operations, running tests, npm commands, docker, and anything else you'd do in a terminal.
Common use cases:
-
Git operations:
bashgit status git log --oneline -10 git blame src/auth/login.ts git diff main...feature-branch -
Running tests:
bashnpm test pytest tests/ cargo test -
Package management:
bashnpm install axios pip install requests cargo add tokio -
Build operations:
bashnpm run build docker build -t myapp .
Key features:
- Timeout support: Commands timeout after 2 minutes by default (configurable up to 10 minutes).
- Background execution: Use
run_in_background: truefor long-running commands. - Working directory persists: Each Bash call remembers the current directory.
- Quoted paths for spaces: Always use quotes for paths with spaces.
bash
cd "/Users/name/My Documents" # Correct cd /Users/name/My Documents # Wrong — will fail
What NOT to use Bash for:
- Reading files (use Read)
- Searching files (use Grep)
- Editing files (use Edit)
- Finding files (use Glob)
Use the specialized tools — they're faster, safer, and designed for the task.
How Claude Explores: The Gather Phase
When you ask Claude to do something, it doesn't jump straight to code changes. It enters a gather phase — autonomously exploring your codebase to understand what needs to happen.
Example exploration flow:
You: "Add a forgot password feature to the auth system"
Claude's gather phase:
- Glob
src/auth/**/*.ts→ Discovers auth module structure - Read
auth/login.ts→ Understands current login flow - Read
auth/token.ts→ Sees how tokens are generated - Grep
"sendEmail"→ Finds existing email service - Read
services/email.ts→ Understands email infrastructure - Bash
git log --oneline src/auth/→ Checks recent auth changes - Read
auth/register.ts→ Finds pattern for new auth endpoints
Now Claude has enough context to propose a solution: create auth/forgot-password.ts, add a password reset route, integrate with the email service, and follow the existing auth patterns.
You didn't tell Claude to do any of that exploration — it inferred what to read based on the task.
Guiding Exploration: Make Claude Smarter
Claude explores autonomously, but your guidance makes it faster and more accurate. Here's how to steer the exploration:
1. Use @ Mentions to Point Claude
The most powerful navigation tool: @ mentions.
Examples:
"Explain how @src/auth/login.ts works"
"Why is @components/Header.tsx re-rendering so often?"
"Compare @old-api.ts and @new-api.ts"
"Look through @screenshots/error.png and debug the issue"
When you use @, Claude automatically reads that file/directory. No need to say "read the file first."
2. Be Specific About Location
Vague request:
"Find the login code"
Claude might search the entire codebase, finding 10 files with "login" in them.
Specific request:
"Look at the auth module in src/auth/ and find the login handler"
Claude starts in the right directory, saving time and tokens.
3. Reference Patterns
If your codebase has established patterns, point Claude to examples.
Example:
"Create a new widget for hot dogs. Follow the same pattern as @widgets/HotDogWidget.php"
Claude reads the example widget, extracts the pattern (file structure, naming conventions, methods), and applies it to the new widget.
4. Point to Git History
For complex refactors or debugging, git history is gold.
Example:
"Look through git history of ExecutionFactory.php — when did the performance regression start?"
Claude runs:
git log --oneline src/ExecutionFactory.php
git show <commit-hash>And pinpoints when the issue was introduced.
5. Start Broad, Then Narrow
For unfamiliar codebases, use a funnel approach:
- Broad overview: "Give me an overview of the project structure"
- Module-level: "Explain the auth module"
- Function-level: "How does token refresh work in auth/token.ts?"
Each level gives Claude more context for the next.
Large Codebase Strategies
When working with massive projects (10,000+ files), standard exploration hits limits. Here's how to stay efficient:
1. Use Subagents for Exploration
Create a subagent to explore and report back. This keeps your main conversation context clean.
Example:
You: "Create a subagent to map out the auth system and summarize how it works"
The subagent explores, reads 20 files, and returns a summary. Your main agent doesn't pay the token cost for all that reading.
2. Leverage CLAUDE.md
A well-written CLAUDE.md file in your project root acts as a map.
Example CLAUDE.md snippet:
## Project Structure
- `src/auth/` - Authentication (login, token refresh, password reset)
- `src/api/` - API routes (REST endpoints)
- `src/db/` - Database layer (Prisma ORM)
## Key Patterns
- API routes: `src/api/<resource>/route.ts`
- Components: `src/components/<name>/<Name>.tsx`
- Tests: `__tests__/<name>.test.ts`Claude reads this first, navigates faster, and asks fewer clarifying questions.
3. Use Directory @ Mentions for Listings
Reference directories to get a file listing:
"What's in @src/components?"
Claude lists files without reading contents — useful for getting oriented.
4. Incremental Context Building
Don't ask Claude to understand the entire codebase at once. Build context incrementally:
Session 1: "Map out the auth module" Session 2: "Now explain how auth integrates with the API layer" Session 3: "Show me how errors are handled across auth and API"
Each session builds on the last, and you can save summaries to CLAUDE.md for future reference.
Permission System Overview
Not all tools are created equal. Some read data (safe), others modify files or execute commands (potentially dangerous).
Permission tiers:
- No permission required: Read, Glob, Grep
- Permission required: Edit, Write, Bash
Approval modes (Shift+Tab to cycle):
- Ask mode: Claude asks before running Edit/Write/Bash
- Autorun mode: Claude runs Edit automatically (still asks for Bash)
- Full auto mode: Claude runs everything without asking
Best practice for learning: Start in Ask mode. See what Claude wants to do before approving. Once you trust it, move to Autorun.
Key Takeaway
Claude's tools aren't just file operations — they're how Claude thinks. Read builds understanding. Glob and Grep discover patterns. Edit makes surgical changes. Bash validates. When you guide Claude's exploration with @ mentions and specific requests, you're teaching it to think like you do about the codebase.
Exercise: Navigate a Real Project
Let's apply what you've learned. Find a project on your machine (or clone a public repo) and try these tasks:
Get oriented
Ask Claude: "Give me an overview of this project's structure"
Watch which tools Claude uses. Does it Glob for file patterns? Read key files like package.json or README.md?
Trace a data flow
Pick a user-facing feature (e.g., login, checkout, file upload). Ask:
"Trace the data flow for [feature] from the UI to the database"
Claude should Read UI components, follow imports to API routes, and Read database models.
Find all files matching a pattern
Ask Claude to find all test files, or all components named "Button", or all API routes.
Example: "Find all React components that use useState"
Claude should use Grep with appropriate patterns and output modes.
Use @ mentions for comparison
Find two similar files (e.g., two API endpoints). Ask:
"Compare @api/users/route.ts and @api/posts/route.ts — are they using the same error handling pattern?"
Claude reads both, compares implementations, and reports differences.
Explore git history
Ask Claude to investigate when a specific file was last changed and why:
"Look through git history of @src/auth/login.ts — what were the last 3 changes?"
Claude uses Bash (git log, git show) to retrieve commit messages and diffs.
Reflection questions:
- How many tools did Claude use for each task?
- Did @ mentions make Claude's exploration more accurate?
- Were there moments where Claude read irrelevant files? How could you have guided it better?
What's Next
You've mastered how Claude reads and explores codebases. Next lesson: Writing Features from Scratch — where you'll learn to build complete, multi-file features by decomposing requirements into clear steps, guiding Claude to follow existing codebase patterns, and verifying each piece as you go.
The exploration skills you just learned become the foundation for everything that follows.