Module 4: The Agent's Toolbox — How They Interact with Your Code

How Agents "See" Your Codebase

Description

There's a fundamental misunderstanding about how coding agents work: most developers assume the agent "sees" their whole project at once, like when you open a project in your IDE and navigate between files. The reality is radically different.

A coding agent sees nothing until it investigates it. It starts with zero knowledge of your project and builds its understanding step by step, file by file, search by search. It's like a detective who arrives at the scene: they don't have the case solved — they have tools to investigate.


The Detective Analogy

A DETECTIVE ARRIVES AT THE CRIME SCENE:

What they DON'T have:
→ The case solved
→ A panoramic photo of all the evidence
→ Prior knowledge of those involved

What they DO have:
→ Tools: magnifying glass, analysis kit, database
→ A method: observe, hypothesize, investigate, verify
→ The ability to request additional information

HOW THEY WORK:
1. Observe the general scene (overview)
2. Identify the areas of interest
3. Examine each area in detail
4. Connect the pieces
5. Form a hypothesis
6. Verify

A CODING AGENT ARRIVES AT YOUR PROJECT:

What it DOESN'T have:
→ Your code in memory
→ A "map" of the project
→ Knowledge of the conventions

What it DOES have:
→ Tools: search, file_read, list_dir, shell
→ A method: the agentic loop (observe → think → act)
→ The ability to ask the developer

HOW IT WORKS:
1. Look at the general structure (list_dir, tree)
2. Search for areas relevant to the task (search, grep)
3. Read specific files (file_read)
4. Connect what it finds
5. Form a plan
6. Execute and verify

The Context Gathering Strategies

Efficient agents use systematic strategies to build their understanding of the codebase. These are the most common ones:

Strategy 1: Top-Down (from general to specific)

STEP 1: Overview
→ list_dir("/") → see the project root
→ list_dir("src/") → see the main structure
→ file_read("package.json") → see dependencies and scripts
→ file_read("README.md") → if it exists, project context

STEP 2: Identify the relevant area
→ "The task is about auth"
→ list_dir("src/auth/") or search("auth", path="src/")

STEP 3: Go deeper
→ file_read("src/auth/login.ts")
→ file_read("src/auth/middleware.ts")

WHEN IT WORKS BEST:
→ A project unknown to the agent
→ Tasks that require understanding the structure
→ First interaction with the codebase

Strategy 2: Search-First (search directly)

STEP 1: Search for what's relevant
→ search("validateEmail") → finds files and lines
→ grep("TODO|FIXME|HACK") → finds technical debt

STEP 2: Read what was found
→ file_read only of the relevant files

STEP 3: Expand if necessary
→ search("import.*validateEmail") → who uses it

WHEN IT WORKS BEST:
→ Specific tasks ("fix function X")
→ When you know what to search for
→ Large projects where top-down would be slow

Strategy 3: Trace-Based (follow the flow)

STEP 1: Find the entry point
→ search("router.get.*users") → finds the route

STEP 2: Follow the calls
→ "The route calls UserController.getAll()"
→ file_read("src/controllers/UserController.ts")
→ "The controller calls UserService.findAll()"
→ file_read("src/services/UserService.ts")
→ "The service uses UserModel"
→ file_read("src/models/User.ts")

STEP 3: Understand the complete flow
→ Route → Controller → Service → Model

WHEN IT WORKS BEST:
→ Debugging (follow the error from the route to the source)
→ Understanding how an existing feature works
→ Before modifying something that touches multiple layers

Strategy 4: Pattern-Based (search for conventions)

STEP 1: Find an example
→ "How are the controllers organized?"
→ file_read of an existing controller that works

STEP 2: Extract the pattern
→ "The controllers use classes with static methods"
→ "Each one has getAll, getById, create, update, delete"
→ "They use try-catch with a common errorHandler"

STEP 3: Apply the pattern
→ Create the new controller following the convention

WHEN IT WORKS BEST:
→ Creating something new that must follow existing patterns
→ Refactoring to maintain consistency
→ When you ask it to "follow the pattern of X"

What the Agent SEES vs What YOU SEE

YOU (DEVELOPER):
→ You have the IDE open with the whole project
→ You can navigate files instantly
→ You see the complete project tree in the sidebar
→ You have months/years of mental context working here
→ You know which files are important and which aren't
→ You remember design decisions from the past

THE AGENT:
→ Starts with an empty context window
→ Each file it reads consumes tokens
→ It only "sees" what it has read in this session
→ It has no historical context
→ It doesn't know which files are important
→ It doesn't know the past design decisions

IMPLICATION:
→ The agent is "blind" at the start of each session
→ Your instructions compensate for that blindness
→ "Look at src/auth/" is more useful than "fix the auth"
→ Context you give = fewer tool calls = more efficient

The cost of exploration

EACH SEARCH AND READ CONSUMES CONTEXT WINDOW:

Typical exploration at the start of a task:
→ list_dir("src/")                    →    200 tokens
→ file_read("package.json")           →    500 tokens
→ search("auth")                      →    300 tokens
→ file_read("src/auth/login.ts")      →  2,000 tokens
→ file_read("src/auth/middleware.ts")  →  1,500 tokens
→ file_read("src/auth/validate.ts")   →    800 tokens
──────────────────────────────────────────────────
Total exploration:                      5,300 tokens

This is BEFORE starting to work.
In a 200K-token context window, it's only 2.6%.
But if the agent reads 20 files → 40,000+ tokens → 20%.

How to Help the Agent "See" Better

Technique 1: Point out the direction

❌ "Fix the login bug"
→ The agent has to guess where to look
→ Multiple exploration tool calls
→ It can go down the wrong path

✅ "Fix the login bug in src/auth/login.ts.
   The error is that the email validation in
   src/auth/validate.ts doesn't accept '+' in emails."
→ The agent knows exactly where to look
→ Fewer tool calls, more efficient
→ Less context window consumed on exploration

Technique 2: Describe the codebase patterns

❌ "Create a new endpoint"
→ The agent has to explore to discover the patterns

✅ "Create a new GET /api/products endpoint.
   Follow the pattern of src/routes/users.ts and
   src/controllers/UserController.ts. We use
   Express + TypeScript with Prisma."
→ The agent reads the reference files
→ Extracts the pattern
→ Replicates it directly

Technique 3: Provide the "map"

❌ "Refactor the payments module"

✅ "Refactor the payments module. The files are:
   - src/services/PaymentService.ts (main logic)
   - src/routes/payments.ts (endpoints)
   - src/models/Payment.ts (data model)
   - src/__tests__/payments.test.ts (tests)
   The problem is that PaymentService has 500 lines
   and should be split into PaymentService and InvoiceService."
→ The agent has the complete map
→ It saves 10+ exploration tool calls
→ It can go straight to planning and executing

Static Context: The Shortcut Agents Take Advantage Of

Besides actively exploring with tools, agents can receive static context — information that's injected automatically at the start of each session without the agent having to search for it.

Configuration files as a "project map"

CLAUDE.md / .cursorrules / AGENTS.md

These files are loaded BEFORE the agent makes
any tool call. They're like giving the
detective a briefing before they arrive at the scene.

TYPICAL CONTENT:
→ Project description
→ Technology stack
→ Directory structure
→ Code conventions
→ Common commands (build, test, deploy)
→ Important files

IMPACT ON TOOL CALLS:
Without CLAUDE.md:
  list_dir → file_read(package.json) → search(conventions)
  → file_read(README.md) → 4+ exploration tool calls

With CLAUDE.md:
  The agent ALREADY KNOWS the structure and conventions
  → Goes straight to the task → 0 exploration tool calls

Concrete example

# CLAUDE.md (minimalist but effective example)

## Project
E-commerce REST API in TypeScript + Express + Prisma.

## Structure
src/
  routes/     → Endpoints (one file per resource)
  services/   → Business logic
  models/     → Prisma schemas
  middleware/ → Auth, validation, error handling

## Conventions
- Each route imports its corresponding service
- Services never access req/res directly
- Tests in __tests__/ with jest
- Naming: camelCase for functions, PascalCase for classes

## Commands
npm test           → Run all the tests
npm run dev        → Development server
npx prisma migrate → Database migrations
WITH THIS FILE, THE AGENT:
→ Knows it's TypeScript + Express + Prisma
→ Knows the routes are in src/routes/
→ Knows it should follow the Service pattern
→ Knows how to run tests
→ Doesn't need to explore any of this

ESTIMATED SAVINGS:
→ 3-5 fewer tool calls per task
→ 500-2000 fewer tokens of context window
→ Less risk of the agent assuming incorrect patterns

Capsule 05 goes deeper into configuration files and permissions. The point here is: static context is the most efficient tool for helping the agent "see" your codebase — because it costs no tool calls.


Efficient vs Inefficient Exploration: A Real Case

To make the difference tangible, here's a complete example of the same task with and without context:

TASK: "Add rate limiting to the POST /api/orders endpoint"

────────────────────────────────────────
AGENT WITHOUT CONTEXT (10 tool calls):
────────────────────────────────────────
1. list_dir("src/")                   → sees folders
2. list_dir("src/routes/")            → sees the route files
3. file_read("src/routes/orders.ts")  → reads the route
4. search("rate-limit", "src/")       → checks if rate limiting already exists
5. file_read("package.json")          → sees dependencies
6. search("middleware", "src/")       → searches for where the middlewares are
7. file_read("src/middleware/auth.ts") → reads an existing middleware
8. web_search("express rate limit")   → searches for how to implement it
9. file_edit("src/routes/orders.ts")  → applies the change
10. shell_execute("npm test")         → verifies

Exploration: 8 tool calls (80%)
Real work: 2 tool calls (20%)

────────────────────────────────────────
AGENT WITH CONTEXT (4 tool calls):
────────────────────────────────────────
Prompt: "Add rate limiting to the POST /api/orders endpoint
in src/routes/orders.ts. Use express-rate-limit (it's already
in package.json). The middleware goes in src/middleware/.
Follow the pattern of src/middleware/auth.ts."

1. file_read("src/routes/orders.ts")   → reads the route
2. file_read("src/middleware/auth.ts")  → reads the pattern
3. file_write("src/middleware/rate-limit.ts") → creates the middleware
4. file_edit("src/routes/orders.ts")    → imports and applies
(+ shell_execute tests if it wants to verify)

Exploration: 2 tool calls (50%)
Real work: 2 tool calls (50%)

The difference: 10 vs 4 tool calls. The agent with context did the same task in less than half the steps, consumed less context window, and had fewer opportunities to make incorrect decisions.


How Different Agents Explore

CLAUDE CODE (terminal):
→ Tends to do extensive search/grep at the start
→ Reads relevant files before acting
→ Uses shell to verify structure (ls, find)
→ CLAUDE.md gives it static context upfront

CURSOR AGENT (IDE):
→ Has access to the open files by default
→ Uses the project index for fast search
→ .cursorrules gives it context about patterns
→ The interface shows which files it reads

COPILOT AGENT:
→ Has access to the IDE's workspace
→ AGENTS.md gives it project context
→ It can use more or less context depending on the config
→ GitHub integration gives it access to issues/PRs

Practical Exercise

Exercise 1: Exploration map

Give your agent a task and document its exploration strategy:

TASK: _______________________________________________

Which strategy did it use?
□ Top-Down (general structure first)
□ Search-First (search directly)
□ Trace-Based (follow the flow)
□ Pattern-Based (search for examples)
□ Other: _______________

Order of tool calls:
1. _________ → what did it find?
2. _________ → what did it find?
3. _________ → what did it find?
4. _________ → what did it find?
5. _________ → what did it find?

Was it efficient? Would it have been faster with
more context in your prompt?
See guided reflection

When analyzing your agent's exploration strategy, look for these indicators:

  • Top-Down: The agent started with list_dir("/") or list_dir("src/") before anything else. Typical in the first interaction with an unknown project.
  • Search-First: It went straight to search("keyword") without exploring the structure. More efficient for specific tasks like "fix function X."
  • Trace-Based: It read a file, found an import or function call, and then read the next file following the chain. Common in debugging.
  • Pattern-Based: It read a similar existing file before creating something new. Common when you ask "create an endpoint like the ones that already exist."

On efficiency: If the agent made more than 5 tool calls before starting to work on the real task, it probably would have been faster with more context in your prompt. Exploration is necessary, but excessive exploration indicates the agent doesn't have enough direction.

Exercise 2: Reduce the tool calls

Compare these two approaches:

APPROACH 1 (minimal prompt):
"Add validation to the contact form"
→ How many tool calls did it do? _____
→ How much exploration time? _____

APPROACH 2 (prompt with context):
"Add validation to the contact form in
src/components/ContactForm.tsx. Use the same validation
pattern as src/components/RegisterForm.tsx.
The project uses react-hook-form with zod."
→ How many tool calls did it do? _____
→ How much exploration time? _____

DIFFERENCE: _____ fewer tool calls with more context
See solution

Typical comparison result:

MetricMinimal promptPrompt with context
Total tool calls8-123-5
Exploration tool calls5-80-1
Files read unnecessarily3-50-1

Why the difference?

With the minimal prompt ("Add validation to the contact form"), the agent must:

  1. Search for where the form is → search("ContactForm") or list_dir
  2. Read several candidate files → file_read × 2-3
  3. Search for existing validation patterns → search("validation") or search("zod")
  4. Read the pattern found → file_read
  5. Read package.json to know which validation library it uses

With the prompt with context, the agent already knows:

  • Where it is: src/components/ContactForm.tsx
  • Which pattern to follow: src/components/RegisterForm.tsx
  • Which library to use: react-hook-form with zod

Typical difference: 5-7 fewer tool calls. This saves context window and reduces the probability of the agent making incorrect decisions based on incomplete exploration.


Common Mistakes

MistakeReality
"The agent sees my whole project"It sees only what it actively reads in this session
"I don't need to tell it where to look"Your context saves tool calls and improves results
"The agent remembers previous sessions"Each session starts from zero (empty context window)
"More files read = better comprehension"More files = more context window consumed, not always better
"The agent chooses the optimal strategy"Sometimes it explores inefficiently; your direction helps

Summary

HOW AGENTS "SEE" YOUR CODEBASE:

→ They DON'T see everything at once — they investigate step by step
→ They start with zero knowledge each session
→ They use tools (search, read, list) to build comprehension
→ Each tool consumes context window

EXPLORATION STRATEGIES:
1. Top-Down: general structure → specific
2. Search-First: search directly for what's relevant
3. Trace-Based: follow the code's flow
4. Pattern-Based: find and replicate patterns

HOW TO HELP:
→ Point out the direction (specific files)
→ Describe the codebase patterns
→ Provide the "map" of the files involved
→ More context in your prompt = less blind exploration

Next capsule: 04 - Context management — what fits in the context window and how to handle large projects.


Resources

  1. Anthropic: Claude Code Best Practices — "Be specific about files and locations"
  2. Agentic Coding: Context Strategies — Context gathering strategies
  3. Cursor: Working with Large Projects — How Cursor handles large projects