We have an intern with a brain and a loop, and so far it can do exactly what a chatbot can do: talk. The magic word in "AI agent" isn't the AI. It's the doing. Tools are what let the intern step out of the conversation and touch the real world, and adding one is far less code than you'd guess. Let's give ours a tool it genuinely needs.
What a tool actually is
A tool is two things: a plain function that does the work, and a short description that tells the model when to reach for it. The function is ordinary code you already know how to write. The description is you, the manager, explaining the intern's options. Here's the whole thing:
from datetime import datetime
# 1. The function: ordinary code that does the actual work.
def get_current_time():
return datetime.now().strftime("%A, %B %d, %Y at %I:%M %p")
# 2. The description: tells Claude the tool exists and when to use it.
tools = [
{
"name": "get_current_time",
"description": "Get the current date and time. Use this whenever "
"the answer depends on what day or time it is right now.",
"input_schema": {
"type": "object",
"properties": {},
},
}
]Notice how much of that is just a good job description. A vague description gets a confused intern who uses the tool at the wrong moment. A clear one, "use this whenever the answer depends on what time it is right now," gets an intern who reaches for it exactly when it helps. Writing good tool descriptions is a surprising amount of the job, and it's a very human one.
Wiring the tool into the loop
Now we fill in the hole we left in the last post. When Claude asks for a tool, we run the matching function and hand the result back. Here's the complete agent, loop and all:
import anthropic
from datetime import datetime
client = anthropic.Anthropic()
def get_current_time():
return datetime.now().strftime("%A, %B %d, %Y at %I:%M %p")
tools = [
{
"name": "get_current_time",
"description": "Get the current date and time. Use this whenever "
"the answer depends on what day or time it is right now.",
"input_schema": {"type": "object", "properties": {}},
}
]
messages = [{"role": "user", "content": "How many days until the end of the month?"}]
while True:
response = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
tools=tools,
messages=messages,
)
if response.stop_reason != "tool_use":
# No tool needed. The intern is done.
print("".join(b.text for b in response.content if b.type == "text"))
break
# The intern asked for a tool. Run it and hand the result back.
messages.append({"role": "assistant", "content": response.content})
results = []
for block in response.content:
if block.type == "tool_use" and block.name == "get_current_time":
results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": get_current_time(),
})
messages.append({"role": "user", "content": results})Ask a plain chatbot how many days are left in the month and it has to guess, because it doesn't know today's date. This agent does something better. It realizes it needs the date, calls get_current_time, reads the real answer, does the arithmetic, and tells you the number. Same model, one small tool, and now it can answer a question it couldn't touch before.
A model with no tools can only tell you what it already knew. A model with the right tool can go and find out.
From a clock to real work
A clock is a safe place to start because reading the time can't hurt anyone. Real agents get their power from tools that reach further: searching the web, reading a file, querying a database, sending a message, updating a record. The code shape never changes. You write a function, describe it, and add it to the tools list. The intern gains a new ability every time you do.
But notice the line you just crossed. get_current_time only reads. The moment a tool can send an email or delete a row, a confidently wrong intern can do real damage at machine speed. This is where being the manager stops being a slogan and starts being the job.
- Separate reading from doing. Tools that only fetch information are safe to run automatically. Tools that change something deserve a pause.
- Ask before the irreversible. For anything you couldn't easily undo, have the loop stop and get your approval before it runs the tool.
- Return errors, don't hide them. When a tool fails, hand the error back to the model so it can adjust, the same way you'd tell an intern "that didn't work, try another way."
- Watch it work first. Run new tools in a mode where you can see every call before you ever let them run unattended.
Key takeaways
- A tool is a plain function plus a clear description of when to use it. The description is most of the skill.
- Adding a tool is the same three steps every time: write the function, describe it, add it to the list.
- Tools close the gap between what the model knows and what it can find out or do.
- Read-only tools are safe to automate. The moment a tool can change the world, you're the manager who decides what it may do alone.
That's a real agent: a model, a loop, and a tool you wrote yourself, doing something a chatbot can't. From here it's all variations on the same idea: sharper tools, clearer descriptions, and more trust as the intern earns it. The hype around agents is loud, but the machinery underneath is this small.



