Module 4: The Agent's Toolbox — How They Interact with Your Code
File Operations, Shell, and Web Search: The Three Categories of Tools
Description
Every coding agent, regardless of its interface or model, has tools that fall into three categories: file operations (read, write, search files), shell commands (run in the terminal), and web (search external information). These three categories cover 95% of what an agent needs to work in your codebase.
This capsule details each category with concrete examples of real use.
Category 1: File Operations
The file tools
┌─────────────────────────────────────────────────┐
│ FILE OPERATIONS │
│ │
│ READING: │
│ → file_read Read a file's content │
│ → search/grep Search text in files │
│ → list_dir List files/folders │
│ → glob Find files by pattern │
│ │
│ WRITING: │
│ → file_write Create or replace a file │
│ → file_edit Modify part of a file │
│ → file_delete Delete a file │
│ │
│ NAVIGATION: │
│ → tree See the project structure │
│ → find Find files by name │
│ │
└─────────────────────────────────────────────────┘
file_read — The most used tool
WHAT IT DOES:
→ Reads the complete content of a file
→ Returns the text to the LLM as part of the context
EXAMPLE:
Agent: tool_call(file_read, path="src/auth/login.ts")
System: "export async function login(email: string, password: string) {
const user = await db.users.findUnique({ where: { email } });
..."
WHEN THE AGENT USES IT:
→ When it needs to understand how something works
→ When the developer tells it "read X"
→ When a search found a relevant file
→ To verify changes it made
COST:
→ The whole file enters the context window
→ A 500-line file ≈ 2,000-4,000 tokens
→ Large files can consume a lot of context
search/grep — Find without reading everything
WHAT IT DOES:
→ Searches for text or patterns in multiple files
→ Returns the matching lines + their location
→ Much more efficient than reading every file
EXAMPLE:
Agent: tool_call(search, query="validateEmail", path="src/")
System: "src/utils/validators.ts:15: export function validateEmail(email) {
src/routes/auth.ts:42: const isValid = validateEmail(req.body.email);
src/__tests__/validators.test.ts:8: describe('validateEmail', () => {"
WHEN THE AGENT USES IT:
→ To find where a function is used
→ To find relevant files without knowing their location
→ To understand the scope of a change (what's affected)
→ To search for codebase patterns or conventions
WHY IT MATTERS:
→ It's more efficient than a file_read of each file
→ It consumes less context window (only the relevant lines)
→ The most efficient agents search before reading
file_write / file_edit — Modify code
file_write:
→ Creates a new file or REPLACES the complete content
→ Useful for creating new files
→ Dangerous for existing files (overwrites everything)
file_edit:
→ Modifies a specific SECTION of a file
→ Replaces specific lines, not the whole file
→ Safer for partial changes
EXAMPLE (file_edit):
Agent: tool_call(file_edit,
path="src/auth/login.ts",
old_text="const user = await db.users.findUnique",
new_text="const user = await db.users.findFirst")
WHEN IT USES EACH ONE:
→ file_write: create new files, rewrite small files
→ file_edit: specific changes in existing files, fixes
→ Modern agents prefer file_edit (less risk)
list_dir / tree — See the structure
WHAT IT DOES:
→ Shows the files and folders in a directory
→ tree shows the complete hierarchical structure
EXAMPLE:
Agent: tool_call(list_dir, path="src/")
System: "auth/
routes/
models/
middleware/
utils/
config/
__tests__/
app.ts
index.ts"
WHEN THE AGENT USES IT:
→ At the start of a task (exploration)
→ When it needs to understand the project's organization
→ To decide where to create a new file
→ To verify a file exists before reading it
Category 2: Shell Commands
The execution tool
┌─────────────────────────────────────────────────┐
│ SHELL COMMANDS │
│ │
│ → shell_execute / run_command │
│ │
│ Runs ANY command in the terminal: │
│ │
│ Testing: npm test, pytest, jest │
│ Building: npm run build, tsc, cargo build │
│ Git: git status, git diff, git commit │
│ Package: npm install, pip install │
│ Linting: eslint, prettier, ruff │
│ Scripts: any project script │
│ System: ls, cat, echo, curl (with limits) │
│ │
└─────────────────────────────────────────────────┘
Running tests
EXAMPLE:
Agent: tool_call(shell_execute, command="npm test -- --testPathPattern=auth")
System: "PASS src/__tests__/auth.test.ts
✓ should login with valid credentials (45ms)
✓ should reject invalid password (12ms)
✓ should handle missing email (8ms)
3 tests passed"
WHEN THE AGENT USES IT:
→ After making changes (verification)
→ To understand which tests exist
→ To diagnose a failure reported by the developer
→ As part of the Execute → Validate cycle
WHY IT MATTERS:
→ It's the ONLY way to verify that the code works
→ Without shell_execute, the agent can't validate its work
→ Agents that run tests produce better code
Git operations
EXAMPLE:
Agent: tool_call(shell_execute, command="git diff --stat")
System: "src/auth/login.ts | 4 ++--
src/utils/validate.ts | 8 ++++++
2 files changed, 10 insertions(+), 2 deletions(-)"
Agent: tool_call(shell_execute, command="git status")
System: "On branch feature/auth-fix
Changes not staged for commit:
modified: src/auth/login.ts
Untracked files:
src/utils/validate.ts"
WHEN THE AGENT USES IT:
→ To see what changed (git diff)
→ To understand the state of the repo (git status)
→ To make commits (git add + git commit)
→ To see history (git log)
Installing dependencies
EXAMPLE:
Agent: tool_call(shell_execute, command="npm install express-rate-limit")
System: "added 1 package in 2.1s"
CAUTION:
→ Installing packages is an action with permanent side effects
→ It modifies package.json and node_modules
→ Some agents ask for confirmation before installing
→ Verify you actually need the dependency
Category 3: Web
External search and query
┌─────────────────────────────────────────────────┐
│ WEB TOOLS │
│ │
│ → web_search Search the internet │
│ → web_fetch Get the content of a URL │
│ │
│ NOT all agents have these tools: │
│ → Claude Code: has web search and fetch │
│ → Cursor: has web search │
│ → Copilot: limited access │
│ │
└─────────────────────────────────────────────────┘
web_search — Search for information
EXAMPLE:
Agent: tool_call(web_search, query="express-rate-limit npm documentation")
System: "Results:
1. npmjs.com/package/express-rate-limit - Rate limiting...
2. github.com/express-rate-limit/express-rate-limit - ..."
WHEN THE AGENT USES IT:
→ To find up-to-date documentation
→ To resolve errors it can't diagnose from the code
→ To verify whether an API exists (vs hallucination)
→ To find the current version of a package
WHY IT MATTERS:
→ It compensates for the LLM's training data cutoff
→ The agent can verify information before generating
→ It reduces hallucinations about APIs and versions
web_fetch — Get content
EXAMPLE:
Agent: tool_call(web_fetch, url="https://docs.stripe.com/api/customers/create")
System: "[content of the documentation page]"
WHEN THE AGENT USES IT:
→ To read specific documentation
→ To get examples of an API
→ When web_search found a relevant URL
LIMITATION:
→ Not all pages are accessible (auth required, etc.)
→ The content consumes context window
→ Some pages return HTML that's hard to process
Risks and Security by Category
Not all tools have the same level of risk. Understanding this is key to calibrating your confidence (Module 05) and configuring permissions (capsule 05 of this module).
Risk level: File Operations
READING (low risk):
→ file_read: Only reads. Doesn't modify anything.
→ search/grep: Only searches. Doesn't modify anything.
→ list_dir/tree: Only lists. Doesn't modify anything.
→ WORST CASE: consumes context window unnecessarily
WRITING (medium-high risk):
→ file_write: CREATES or OVERWRITES a complete file
⚠️ If the file existed, the previous content is lost
⚠️ There's no automatic "undo" (unless you use git)
→ file_edit: Modifies PART of a file
⚠️ It can introduce subtle bugs if the context isn't correct
⚠️ Safer than file_write but not risk-free
→ file_delete: DELETES a file
⚠️ Irreversible without git
⚠️ Most agents ask for confirmation for this
MITIGATION:
→ Use git before the agent modifies (git stash or commit)
→ Review the diffs after each modification
→ Configure the agent's permissions to ask for confirmation on writes
Risk level: Shell Commands
LOW RISK (reading):
→ ls, cat, head, tail, grep: only read
→ git status, git log, git diff: only read
MEDIUM RISK (reversible):
→ npm test, pytest: run code but don't modify
→ npm run build, tsc: generate derived files
HIGH RISK (permanent side effects):
→ npm install: modifies node_modules and package.json
→ git commit: creates a commit (reversible but with effort)
→ git push: sends changes to the remote (hard to revert)
→ rm, rmdir: deletes files or directories
CRITICAL RISK (potentially destructive):
→ rm -rf: recursive deletion
→ sudo: privilege escalation
→ curl | sh: remote code execution
→ DROP TABLE, truncate: destructive operations on the DB
MITIGATION:
→ Configure lists of allowed commands
→ Use sandboxes or containers for isolated execution
→ NEVER allow sudo or automatic privilege escalation
→ Review shell commands BEFORE approving them
Risk level: Web Tools
LOW RISK:
→ web_search: only searches for information
→ web_fetch: only reads a URL
POTENTIAL RISK:
→ External content can confuse the LLM (injection via web)
→ Outdated documentation can lead to incorrect code
→ The agent can cite information without verifying it
MITIGATION:
→ Verify the sources the agent consults
→ Don't trust "I found it on the internet" without validating
→ Web results consume context window
The golden rule of security
READ-ONLY TOOL → Trust (but monitor context)
TOOL THAT WRITES → Verify before approving
TOOL THAT EXECUTES → Review the command first
TOOL THAT DELETES → Require explicit confirmation
CONNECTION WITH MODULE 05:
This is trust calibration applied to tools.
More risk = more supervision needed.
How the Agent Decides Which Tool to Use
The decision flow
DEVELOPER'S TASK: "Fix the bug in the login"
THE AGENT REASONS (ReAct):
"I need to find the login code"
→ Do I know where it is? NO
→ ACTION: search("login", path="src/")
→ RESULT: src/auth/login.ts, src/routes/auth.ts
"I found the files. I need to read the main one"
→ Which one is relevant? login.ts is the service
→ ACTION: file_read("src/auth/login.ts")
→ RESULT: [file content]
"I see the code. I need to understand the error"
→ Did the developer describe the error? Yes, "login fails"
→ Can I reproduce it? Yes, by running tests
→ ACTION: shell_execute("npm test -- auth")
→ RESULT: 1 test fails: "expected 200, got 401"
"The test expects 200 but receives 401. There's an auth error"
→ I need to see the validation logic
→ ACTION: file_read("src/auth/validate.ts")
→ RESULT: [content]
"I found the bug: the regex doesn't accept '+' in emails"
→ ACTION: file_edit(fix the regex)
→ RESULT: file modified
"I verify it works"
→ ACTION: shell_execute("npm test -- auth")
→ RESULT: all tests pass ✅
The common pattern
EXPLORE → search, list_dir, tree
UNDERSTAND→ file_read, grep
VERIFY → shell_execute (tests, build)
MODIFY → file_write, file_edit
CONFIRM → shell_execute (tests again)
The most efficient agents follow this order.
The less efficient ones go straight to MODIFY.
Table of Tools by Agent
┌──────────────────┬────────────┬────────────┬────────────┐
│ TOOL │ CLAUDE │ CURSOR │ COPILOT │
│ │ CODE │ AGENT │ AGENT │
├──────────────────┼────────────┼────────────┼────────────┤
│ file_read │ ✅ │ ✅ │ ✅ │
│ file_write │ ✅ │ ✅ │ ✅ │
│ file_edit │ ✅ │ ✅ │ ✅ │
│ search/grep │ ✅ │ ✅ │ ✅ │
│ list_dir │ ✅ │ ✅ │ ✅ │
│ shell_execute │ ✅ │ ✅ │ ✅* │
│ git operations │ ✅ (shell) │ ✅ │ ✅ │
│ web_search │ ✅ │ ✅ │ partial │
│ web_fetch │ ✅ │ partial │ partial │
└──────────────────┴────────────┴────────────┴────────────┘
* Copilot Agent has shell with variable restrictions
depending on the configuration and platform.
NOTE: The capabilities change frequently with updates.
What matters is understanding the CATEGORIES, not memorizing
the exact table.
Practical Exercise
Exercise 1: Observe the tools in action
Give your coding agent a task and document each tool call:
TASK: "Find all the deprecated functions in my project"
Tool call 1: ___________ (which tool? which arguments?)
Tool call 2: ___________
Tool call 3: ___________
[...]
QUESTIONS:
→ How many file_read did it do? _____
→ How many search/grep? _____
→ Did it use shell_execute? For what? _____
→ Was the order logical? _____
See guided reflection
For the task "Find all the deprecated functions," an efficient agent would typically do:
search/grep("@deprecated", path="src/")— search for the standard annotationsearch/grep("deprecated", path="src/")— search for mentions in commentsfile_readof each file found — to see the complete context
Expected answers:
- file_read: 2-5 (only the files where it found matches)
- search/grep: 1-3 (the main tool for this task)
- shell_execute: Possibly 0. Some agents might use
grep -rvia shell, but it's not necessary for this task - Logical order? Yes, if it started with search and then read only the relevant files. No, if it started reading files one by one without searching first
Key: This task is dominated by searches, not by complete reads. An agent that does 10 file_read instead of 2 search is being inefficient.
Exercise 2: Predict the tools
BEFORE giving the task to the agent, predict which tools it will use:
TASK: "Add a GET /api/health endpoint that returns
status 200 with { status: 'ok' }"
MY PREDICTION:
→ Tools it will use: ___________________________________
→ Order: ____________________________________________
→ Number of tool calls: _____
ACTUAL RESULT:
→ Tools it used: _____________________________________
→ Order: ____________________________________________
→ Number of tool calls: _____
Did it match? _______________
See solution
For "Add a GET /api/health endpoint that returns status 200 with { status: 'ok' }":
Likely tool sequence:
searchorlist_dir("src/routes/")— find where the routes arefile_readof the routes file — see the existing endpoint patternfile_editorfile_write— add the new endpointshell_execute("npm test")— verify it works
Breakdown:
- Tools it will use: search or list_dir, file_read, file_edit, shell_execute
- Order: Explore → Understand the pattern → Modify → Verify
- Number of tool calls: 4-6 typically
Note: An agent that receives context like "the routes are in src/routes/api.ts, follow the pattern of the other endpoints" can reduce it to 2-3 tool calls (read the file, edit, verify). This demonstrates the impact of giving context in the prompt.
Common Mistakes
| Mistake | Reality |
|---|---|
| "The agent reads the whole project" | It reads files selectively using search + read |
| "All tools are equally expensive" | A file_read of a large file consumes much more context than a search |
| "The agent always chooses the correct tool" | Sometimes it uses file_read when search would be more efficient |
| "Shell execute is only for tests" | It's used for tests, builds, git, install, linting, and more |
| "Web search solves the training data cutoff" | It helps, but not all agents have it and they don't always use it |
Summary
THREE CATEGORIES OF TOOLS:
1. FILE OPERATIONS (read, write, search)
→ file_read, file_write, file_edit
→ search, grep, list_dir, glob
→ The most used category
2. SHELL COMMANDS (execute)
→ Tests, builds, git, install, linting
→ The ONLY way to verify that the code works
→ With real side effects (be careful)
3. WEB (external information)
→ web_search, web_fetch
→ Compensates for the training data cutoff
→ Not always available
COMMON PATTERN:
Explore → Understand → Verify → Modify → Confirm
FOR MODULE 07:
You'll implement: read_file, write_file, list_directory, run_command
Next capsule: 03 - How agents "see" your codebase — context gathering strategies.
Resources
- Anthropic: Claude Code Tool Reference — Available tools
- Cursor: Agent Mode Capabilities — What Cursor Agent can do
- GitHub Copilot: Agent Tools — Copilot's tools
- OpenAI: Function Calling — The technical foundation of tool calling