C4 · lesson 1 · 10 min read
Tool definitions and descriptions
Define tools with a name, a description and an input_schema, and write descriptions that make Claude pick the right tool with the right arguments.
Հայերեն
A tool is a function that your code runs and Claude decides to call.
You describe it in the request’s tools array. Claude reads the description,
decides whether the request needs the tool, and answers with a structured call.
Your application runs it and sends the result back. These are called client
tools. Server tools such as web search run on Anthropic’s side instead, and
you never execute them yourself.
Anatomy of a definition
| Field | Required | What it does |
|---|---|---|
name |
yes | Must match ^[a-zA-Z0-9_-]{1,128}$ |
description |
in practice | Plain text: what the tool does, when to use it, what it returns |
input_schema |
yes | A JSON Schema object for the arguments |
input_examples |
no | Example inputs; each one must validate against input_schema |
strict |
no | true guarantees Claude’s inputs match the schema exactly |
Other optional properties include cache_control and defer_loading (lesson 3).
# define_tool.py - needs ANTHROPIC_API_KEY in the environment
import anthropic
client = anthropic.Anthropic() # reads ANTHROPIC_API_KEY itself
pod_logs_tool = {
"name": "k8s_get_pod_logs",
"description": (
"Returns the last lines of logs from one container in one Kubernetes pod. "
"Use it when the user asks why a pod is failing, restarting or erroring, after "
"you know the exact pod name. Do not use it to list pods or to read events; "
"it only returns container stdout/stderr. Read-only: it never changes the cluster. "
"Output is plain text, newest line last, capped at tail_lines."
),
"input_schema": {
"type": "object",
"properties": {
"namespace": {
"type": "string",
"description": "Kubernetes namespace, e.g. payments. Never guess; ask if unknown.",
},
"pod": {"type": "string", "description": "Exact pod name, e.g. checkout-7d9f8-abcde."},
"container": {
"type": "string",
"description": "Container name. Omit for single-container pods.",
},
"tail_lines": {"type": "integer", "minimum": 1, "maximum": 500, "default": 100},
"previous": {
"type": "boolean",
"description": "true = logs of the previous (crashed) container instance.",
},
},
"required": ["namespace", "pod"],
},
}
response = client.messages.create(
model="claude-sonnet-5-5",
max_tokens=1024,
tools=[pod_logs_tool],
messages=[{"role": "user", "content": "Pod checkout-7d9f8-abcde in payments keeps restarting. Why?"}],
)
print(response.stop_reason)
for block in response.content:
if block.type == "tool_use":
print(block.name, block.input)
Descriptions do most of the work
Anthropic’s guidance is blunt: a detailed description is by far the biggest factor in how well tools work. Claude has nothing else to go on. Aim for at least three or four sentences that cover:
- What the tool does and what it returns.
- When to use it, and just as important, when not to.
- What each parameter means, with formats and examples.
- Limits and caveats: what it doesn’t return, side effects, size caps.
Compare "Gets pod logs." with the example above. With the short version Claude
has to guess whether it can list pods, whether previous exists, and whether
calling it is safe. With the long version, “list my pods” clearly doesn’t fit, and a
crash loop clearly calls for previous: true.
Designing the tool set
- Consolidate. Many near-identical tools make selection ambiguous. One
github_prtool with anactionenum (create,review,merge) is often better than three tools. - Namespace. Prefix tool names with the service, for example
k8s_,pagerduty_orgithub_. It removes ambiguity once you have tools from several systems, and it helps tool search (lesson 3). - Return high-signal output. Return stable, meaningful identifiers such as
slugs or UUIDs, not internal row IDs, and only the fields Claude needs for its
next step. A 5,000-line
kubectl get -o jsondump wastes context. - Use
input_examplesfor tricky formats. They help with nested objects or format-sensitive strings. Each example costs prompt tokens, and an invalid one makes the request fail with a 400. - Ask for evidence, not reasoning. If you add a parameter such as
reason, ask for a short explanation. A field that asks for step-by-step thinking can trigger a refusal.
Recap
- A tool is
name,descriptionandinput_schema. Your code runs it; Claude only asks for it with atool_useblock andstop_reason: "tool_use". - The description matters most: say what it does, when to use it and when not to, what the parameters mean, and its limits.
- Prefer fewer, namespaced, well-described tools that return concise output.
- Use
input_examplesfor complex formats andstrict: trueto guarantee schema-valid input.
$ ./try-it.sh
Try it: a read-only pod-logs tool
- Install the SDK with
pip install anthropicand exportANTHROPIC_API_KEYin your shell. Never put the key in the script. - Save the script from this lesson as
define_tool.pyand run it. Confirm that the response hasstop_reasontool_useand atool_useblock fork8s_get_pod_logs. - Replace the description with the one-line version (
Gets pod logs.) and run again with the promptwhy is checkout crashing?. Compare which arguments Claude invents. - Add a second tool,
k8s_describe_pod, and write descriptions that say when to use each one instead of the other.
Check yourself
4 questions. Original practice questions, not taken from the real exam.