In the previous lesson, you learned how to configure your agent's fundamental behavior using ClaudeAgentOptions — selecting models, shaping personality through system prompts, and limiting reasoning cycles. These settings control how the agent thinks and communicates, but they don't give the agent the ability to act on your environment. This is where tools come in — they transform your agent from a conversational assistant into an active participant that can search the web, read and write files, and execute commands. In this lesson, you'll learn how to enable built-in tools, understand the new message block types that represent tool usage, and configure permissions that control how the agent executes these actions.
The Claude Agent SDK provides multiple built-in tools that give your agent diverse capabilities — from web search and file manipulation to task management and Jupyter notebook editing. While this comprehensive toolkit enables sophisticated workflows, this lesson focuses on five foundational tools that cover the most common use cases: searching the web, reading files, writing files, and executing commands. Understanding these core tools will give you a solid foundation for building practical agents, and you can explore the additional tools as your needs grow.
The SDK includes the following built-in tools:
Task— Create a sub-task or subagent with a description/promptBash— Execute a shell command in the working directoryEdit— Modify an existing file by replacing stringsRead— Read contents of a file (text or image)Write— Write new content to a fileGlob— Find files matching a glob patternGrep— Search within files for patterns (regex, filters, etc.)NotebookEdit— Edit a Jupyter notebook cell (code or markdown)WebFetch— Fetch a URL and run a prompt on the fetched contentWebSearch— Perform a web search query and return resultsTodoWrite— Write a set of to-do items and get statistics- — Retrieve output/status of a background shell command
WebSearch allows the agent to search the internet for current information. When the agent uses this tool, it submits a search query and receives a list of relevant web pages with titles, URLs, and brief descriptions. This tool is essential for tasks that require up-to-date information that wasn't in the model's training data, such as finding recent documentation, checking current events, or discovering resources.
WebFetch retrieves the full content from specific URLs. While WebSearch finds relevant pages, WebFetch actually reads the content from those pages so the agent can analyze, summarize, or extract information. This tool is automatically enabled when you enable WebSearch, since searching without the ability to read results would be incomplete. The agent can optionally provide a prompt parameter to focus on specific information within the fetched content.
Bash executes shell commands in your terminal. This tool gives the agent the ability to run any command you could run yourself — checking if directories exist, creating folders, running tests, starting servers, or executing scripts. The agent provides both the command to execute and a description of what it's trying to accomplish, which helps you understand the agent's reasoning when reviewing tool usage.
Read accesses files from your filesystem. The agent can read the contents of any file within its working directory, which is useful for analyzing code, reviewing configuration files, or understanding project structure. This tool respects the working directory you configure, preventing the agent from accessing files outside your intended scope.
Write creates or modifies files on your filesystem. The agent can write new files or overwrite existing ones, which is essential for tasks like generating code, creating documentation, or saving analysis results. Like the Read tool, Write operations are scoped to the configured working directory for safety. These five tools work together to enable complex workflows where the agent can search for information, read existing files, and create new content, all in response to a single prompt.
To give your agent access to tools, you use the allowed_tools parameter in ClaudeAgentOptions. This parameter accepts a list of tool names as strings, and only the tools you explicitly list will be available to the agent during that query. This explicit allowlist approach gives you fine-grained control over what actions the agent can perform, which is important for security and cost management.
The code creates a configuration that enables all five built-in tools. The agent can now search the web, fetch content from URLs, execute bash commands, read files, and write files. Note that even though WebFetch is automatically enabled when you enable WebSearch, it's good practice to list it explicitly in your allowed_tools array to make your configuration clear and self-documenting. You don't have to enable all tools for every task — if you're building a simple documentation search agent, you might only enable WebSearch and WebFetch, while a code analysis tool might enable Read and Bash but exclude Write to prevent modifications.
Every tool call needs permission before the agent can use it. The SDK gives you two ways to grant that permission:
allowed_tools– which tools are the agent allowed to call.permission_mode– extra rules that can relax or tighten permissions for certain kinds of tools.
In this lesson we’ll focus on one of them: acceptEdits.
With permission_mode="acceptEdits", the SDK automatically approves any tool that edits files (such as Write and Edit), even if those tools are not explicitly listed in allowed_tools. This is why, in practice, you may see Claude successfully edit files after turning on acceptEdits even when Write or Edit are missing from the allow‑list.
Other modes exist (default, plan, ), but for this course we’ll stick with as our main example.
Before we let the agent edit files or run commands, we need to tell it where in our project it should work. That’s what the cwd (current working directory) option does.
When you call query() with the Python Agent SDK, it starts a Claude Code process that actually runs tools like Bash, Read, and Write.
- By default, that process uses the current working directory of your Python process (the folder you run
python ...from), not necessarily the folder where your script file lives. - The
cwdoption lets you override this and say, “Always start here.”
From the cwd folder:
- Bash commands run as if you had
cd’d intocwd. - File tools resolve relative paths (like
project/my_file.md) starting fromcwd.
The model still decides which paths to use. If it picks an absolute path such as /project/my_file.md, that path starts at the filesystem root and ignores cwd—which is why you might see a first attempt fail from /... and then a second attempt succeed once it finds the file under your actual project directory.
To make sure the working directory always follows the script (even if you move the file to another folder), you can set based on :
When you enable tools, the streaming messages you receive from query() include new block types that represent tool usage. You're already familiar with TextBlock objects inside AssistantMessage — these contain the agent's text responses. Now you'll also encounter two new block types:
-
ToolUseBlock— Appears inAssistantMessage.contentwhen the agent decides to call a tool. This block represents the agent's intention to use a tool — it contains the tool name and the input parameters the agent wants to pass to that tool. The block doesn't contain the result of the tool execution; it only shows what the agent is trying to do. EachToolUseBlockhas three key attributes:name(the tool being called),input(a dictionary of parameters), andid(a unique identifier for this specific tool call). -
ToolResultBlock— Appears inUserMessage.contentafter a tool executes. This block contains the output from the tool execution — the search results from WebSearch, the file contents from Read, the command output from Bash, or a success confirmation from Write. The block includes the tool call ID (linking it back to the correspondingToolUseBlock), the content (the actual result), and metadata about whether the execution succeeded or failed.
To observe which tools your agent is using, you need to check for ToolUseBlock objects within the AssistantMessage.content list. Each assistant message can contain multiple blocks — some might be TextBlock objects with explanatory text, and others might be ToolUseBlock objects representing tool calls. By iterating through the content blocks and checking their types, you can see exactly when and how the agent decides to use tools.
The code iterates through each block in the assistant message's content. When it encounters a TextBlock, it prints the agent's text response with a speech bubble emoji. When it encounters a ToolUseBlock, it prints the tool name and shows a preview of the input parameters. The block.input is a dictionary where keys are parameter names and values are the arguments the agent wants to pass to the tool. For example, a WebSearch tool call might have {"query": "Claude Agent SDK documentation"}, while a Write tool call might have {"file_path": "./summary.md", "content": "# Summary\n..."}. The code truncates long values to 30 characters to keep the output readable, since tool inputs can contain large amounts of text. Now let's see how to capture the results that come back from these tool executions.
After the agent calls a tool, the system executes that tool and returns the result in a UserMessage containing a ToolResultBlock. To see what happened during tool execution, you need to check for these blocks in user messages. The result block contains the tool's output, which could be search results, file contents, command output, or a simple success confirmation.
The code checks if the message is a UserMessage, then iterates through its content blocks looking for ToolResultBlock objects. When it finds one, it prints a checkmark emoji to indicate a tool result. The block.content attribute contains the actual output from the tool execution. Some tools return substantial output (like WebSearch returning a list of search results or Read returning file contents), while others return minimal or no output (like Bash commands that succeed silently or Write operations that just confirm success). The code handles both cases by showing a preview of non-empty content or displaying "(completed successfully)" for operations that finished without producing output. With both tool calls and results visible, you can now trace the complete workflow of your agent's actions.
When you run the complete code with tool configuration, the agent begins by explaining its plan and then makes its first tool call to search for information. The streaming output shows each step of the agent's work, giving you visibility into its decision-making process.
The output shows the agent first explaining its plan in a text response, then calling WebSearch to find information about the Claude Agent SDK. After receiving search results containing links and descriptions, the agent can evaluate what it found and decide on the next action. Notice how the tool call shows a preview of the query parameter, and the tool result shows a preview of the search results returned. This pattern of explanation, action, and result continues throughout the agent's workflow.
After reviewing the search results, the agent decides it needs more detailed information from the official documentation, so it uses WebFetch to retrieve the full content from a specific URL.
The agent explains its reasoning before calling WebFetch, showing that it wants more detailed information from the official documentation. The tool call includes both a URL parameter (the documentation page to fetch) and an optional prompt parameter (focusing the fetch on specific information about what the SDK is). The tool result contains the actual content from that page, which the agent can now analyze to create the summary. With the information gathered, the agent moves on to preparing the file system for writing.
Before writing the summary file, the agent realizes it needs to ensure the target directory exists, so it uses Bash to check if the summaries directory is present.
The agent explains that it's about to create the summary file but first needs to check if the directory exists. The Bash tool call includes both the command to execute and a description of what the agent is trying to accomplish. The command uses ls -la ./summaries 2>/dev/null to check for the directory, and the tool result indicates that the directory doesn't exist. This information allows the agent to adapt its strategy and create the directory before attempting to write the file.
Having discovered that the summaries directory doesn't exist, the agent uses Bash again to create it before proceeding with the file write operation.
The agent explains its next action, then calls Bash with the mkdir -p ./summaries command to create the directory. The -p flag ensures the command succeeds even if the directory already exists, which is a defensive programming practice. The tool result shows "(completed successfully)" because the mkdir command produces no output when it succeeds — it simply creates the directory and exits. With the directory now in place, the agent can proceed to write the summary file.
With the directory created and the information gathered, the agent finally uses the Write tool to save the summary to the specified file path.
The Write tool call includes two parameters: the file path where the content should be saved, and the actual content to write (shown truncated in the output). The tool result confirms that the file was created successfully at the specified location. This completes the core task the agent was asked to perform — searching for information and saving a summary. Now the agent provides a final response summarizing what it accomplished.
After successfully writing the file, the agent provides a final text response that summarizes what it accomplished and offers to help further.
The agent's final response explains what it accomplished, provides details about what's included in the summary, and offers to continue helping if needed. This complete workflow demonstrates how tool-enabled agents work — they think, act, observe results, adapt their strategy, and continue until the task is complete. The agent used five different tool calls across four different tools (WebSearch, WebFetch, Bash twice, and Write) to accomplish a task that would have been impossible with text generation alone.
You've now learned how to transform your agent from a text responder into an active assistant that can search the web, read and write files, and execute commands. By configuring allowed_tools, permission_mode, and cwd in ClaudeAgentOptions, and by inspecting ToolUseBlock and ToolResultBlock objects in streaming messages, you can build and observe agents that accomplish real tasks through intelligent tool use. In the practice exercises ahead, you'll build your own tool-enabled agents that combine multiple tools to solve complex problems.
