Introduction: From Thinking to Acting

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.

Discovering Built-in Tools

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/prompt
  • Bash — Execute a shell command in the working directory
  • Edit — Modify an existing file by replacing strings
  • Read — Read contents of a file (text or image)
  • Write — Write new content to a file
  • Glob — Find files matching a glob pattern
  • Grep — 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 content
  • WebSearch — Perform a web search query and return results
  • TodoWrite — Write a set of to-do items and get statistics
  • — Retrieve output/status of a background shell command
WebSearch: Finding Information on the Internet

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: Retrieving Content from URLs

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: Executing Shell Commands

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: Accessing Files from Your Filesystem

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: Creating and Modifying Files

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.

Enabling Tools with allowed_tools

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.

Configuring Permission Mode

Every tool call needs permission before the agent can use it. The SDK gives you two ways to grant that permission:

  1. allowed_tools – which tools are the agent allowed to call.
  2. 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.

Setting the Working Directory

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 cwd option lets you override this and say, “Always start here.”

From the cwd folder:

  • Bash commands run as if you had cd’d into cwd.
  • File tools resolve relative paths (like project/my_file.md) starting from cwd.

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 :

New Message Block Types for Tool Use

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 in AssistantMessage.content when 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. Each ToolUseBlock has three key attributes: name (the tool being called), input (a dictionary of parameters), and id (a unique identifier for this specific tool call).

  • ToolResultBlock — Appears in UserMessage.content after 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 corresponding ToolUseBlock), the content (the actual result), and metadata about whether the execution succeeded or failed.

Inspecting Tool Calls in Assistant Messages

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.

Reading Tool Results from User Messages

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.

Observing the Agent's First Tool Call

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.

Fetching Detailed Information

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.

Checking Directory Existence

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.

Creating the Directory

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.

Writing 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.

Completing the Task

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.

Summary and Hands-On Practices

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.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal