11Agents and workflows

Agents and tools

7 min read1,377 words

Four workflow patterns later, time to talk about agents on their own terms. An agent isn't a workflow pattern — it's an architectural stance: give Claude a goal and a set of tools, then get out of the way and let the model decide what to do. The quality of an agent is almost entirely determined by the tools you give it, which is why this lesson is not about "how to build an agent" but rather "how to design tools that an agent can combine creatively."

The agent premise

Workflows require you to know the exact steps for a task in advance. Agents assume you don't. You can't enumerate every programming task a developer might ask Claude Code to do. You can't list every possible report a data analyst might ask for. The agent approach is to provide general-purpose tools and trust Claude to combine them based on whatever request walks in the door.

This is more flexible than a workflow — you build the agent once and it handles a long tail of cases you never planned for. It's also less predictable: the trade-offs we'll catalogue in the last lesson of this module are why agents aren't always the right choice. But when they are the right choice, the quality of your tool design is the whole game.

A small worked example

Recall the reminder project from Module 6. The three tools you built:

  • get_current_datetime — returns the current date and time.
  • add_duration_to_datetime — adds an interval to a datetime.
  • set_reminder — records a reminder at a specific time.

Individually, these are trivially simple. Each function is a few lines of Python. But look at what Claude can do by combining them:

  • "What's the time?" → call get_current_datetime. One tool.
  • "What day of the week is it in 11 days?" → call get_current_datetime, then add_duration_to_datetime with 11 days. Two tools, chained.
  • "Set a reminder for my gym appointment next Wednesday." → call get_current_datetime, compute days until next Wednesday, call add_duration_to_datetime, call set_reminder. All three tools.
  • "When does my 90-day warranty expire?" → recognise that the agent doesn't know when the warranty started, ask the user for the purchase date, then call add_duration_to_datetime. The agent can ask follow-up questions when it's missing information.

None of those combinations were hard-coded. You didn't write a check_warranty_expiration tool. Claude figured out that the tools you provided were sufficient and strung them together. That's the agent flexibility you're buying.

The key design principle: abstract tools

The reminder project is a tiny example of a broader principle that Claude Code illustrates perfectly.

Claude Code does not have a refactor_code tool. It doesn't have an install_dependencies tool. It doesn't have a fix_failing_tests tool. What it has is:

  • bash — run any shell command
  • read — read any file
  • write — create any file
  • edit — modify files
  • glob — find files matching a pattern
  • grep — search file contents

These are abstract, general-purpose tools. A refactor is "read the file, edit it, run the tests." Installing dependencies is "run pip install or npm install via bash." Fixing tests is "run the tests with bash, read the failures, edit the code, repeat." Claude Code has never heard of any of those high-level tasks, but it can do all of them by combining the primitives.

This is the design principle in one sentence: give agents combinable tools that compose well rather than tools tailored to anticipated tasks.

Why abstract tools win

A hyper-specialised tool like refactor_code might work great for the exact refactor pattern you built it for. It will fail silently (or loudly) for every variation you didn't anticipate:

  • The refactor involves a language you didn't code for.
  • The refactor spans multiple files.
  • The refactor requires moving things between modules.
  • The refactor triggers a cascade of test updates.
  • The refactor needs to leave a comment explaining why.

The abstract-tool approach handles all of these. Claude reads the files, decides which edits to make, applies them with edit, runs the tests with bash, reads the failures, iterates. Nothing new has to be built; the combination falls out of the primitives Claude already has.

The corollary: specialised tools are lost effort. Any specialised tool you build is one task the agent handles well and zero tasks you haven't imagined yet. An abstract tool is infinite tasks that compose, most of which you'll never anticipate.

Combinable tools in other domains

The principle generalises:

A social media video agent might have:

  • bash — run any command (for FFmpeg, ImageMagick, anything)
  • generate_image — create images from prompts
  • text_to_speech — convert text to audio
  • post_media — upload to social platforms

That's four abstract tools, and they compose into video creation, thumbnail generation, subtitle overlay, audio replacement, trimming, reposting, cross-posting, and any other workflow the user dreams up. None of those workflows is a dedicated tool. All of them emerge from the primitives.

A data analysis agent might have:

  • sql_query — run any SQL against the warehouse
  • python_repl — run Python code (in a sandbox)
  • fetch_url — grab any URL
  • render_chart — turn a DataFrame into a plot

That's the entire toolkit you need for "answer any question a business analyst might ask." The specific analyses emerge from Claude combining the tools, not from the tools being pre-built for specific analyses.

A customer support agent might have:

  • search_knowledge_base — find relevant docs
  • lookup_customer — fetch customer record
  • create_ticket — escalate to humans
  • send_email — respond to the customer

Four tools, one agent, covers everything from "where's my order" to "I need a refund" to "I found a bug in your product" — because the agent decides which combinations fit which situation.

Design questions to ask yourself

When you're designing tools for an agent, three questions pressure-test your design:

  1. "What do I need if I want Claude to do anything in this domain?" Build those tools first. The general primitives.
  2. "Which two of these tools compose into a task I haven't thought about yet?" If the answer is "lots of them," your tools are the right level of abstract. If the answer is "hardly any," your tools are too specific.
  3. "If I remove this tool, what tasks become impossible vs what tasks become less convenient?" Impossible means the tool is foundational. Less convenient means the tool is specialised — consider whether Claude can accomplish the same thing by combining others.

You want a small set of powerful, flexible primitives, not a large bag of specialised shortcuts. This is the same instinct that made the Unix philosophy work: small composable tools, each doing one thing well, combined into pipelines that solve any problem.

The next piece: observation

Abstract tools give agents the capability to act. The next lesson covers the other thing agents need to do reliably, which is observe the results of their actions — environment inspection. Without that, even the best tool set produces an agent that can do things blindly but can't tell whether it succeeded. Both halves are load-bearing.

Key Takeaways

  • 1Agents derive their power from combining abstract, general-purpose tools in unexpected ways — the quality of an agent is mostly the quality of its tool design.
  • 2Claude Code is the canonical example: its toolkit is bash, read, write, edit, glob, grep — no hyper-specialised tools like refactor_code or install_dependencies.
  • 3The design principle is combinable tools that compose well, not tools tailored to anticipated tasks — the latter handles the tasks you imagined and none of the ones you did not.
  • 4A small set of abstract primitives covers a much larger task space than a big bag of specialised shortcuts, because the agent composes the primitives into combinations you never explicitly built for.
  • 5The Unix philosophy applies directly: small composable tools, each doing one thing well, combined by the agent into solutions to novel problems.
  • 6When designing a tool set, ask what general primitives cover your whole domain, check which two-tool combinations solve tasks you did not anticipate, and drop tools whose removal would only be inconvenient rather than blocking.