PMaker home
Cut tools by task, not by endpointAPI wrapperForty endpoints, forty toolsHard to pick, hard to changeTask-shaped toolCut and named around the taskPicks right, fills rightDeclared contractRisk, timeout, idempotency, trimmingFails safely, recoversDeclare everything the model cannot infer

Cut tools by task rather than by endpoint, and declare everything the model cannot infer.

A Tool Is a Contract, Not an API Wrapper

Design tools around task semantics and declare schema, risk, timeout, idempotency, and output trimming so the model picks right, fails safely, and recovers.

Design tools around Agent task semantics, not as one-to-one wrappers over existing APIs. If your backend exposes forty REST endpoints, that is not a reason to hand the Agent forty tools. A model picks correctly far more often from six tools with clear task semantics than from forty similarly named endpoints, and tool descriptions sit in context permanently — the more tools you ship, the less attention each one receives.

A tool is a contract with a deterministic system

A contract declares what the model cannot infer from the code: name, version, description, inputSchema, outputSchema, annotations (readOnly, destructive, idempotent, openWorld), riskLevel, approvalPolicy, timeoutMs, retryPolicy, resultPolicy. Leave one out and either the model or the runtime has to guess.

Skip idempotent and a retry can double-charge a customer in production. Skip openWorld and the model does not know the tool reaches the public internet, so it does not know the result may carry untrusted content. Skip timeoutMs and the runtime never learns when to take over. None of these are documentation gaps; they are runtime branch conditions.

readOnly is the field most often treated as a compliance checkbox and the one with the clearest payback. Perception tools do not change the outside world, so their results can be cached safely — a repeat query reuses the answer — and their calls can run in parallel: read five files at once, fire three searches together. Execution tools get no such latitude, since order and side effects both need strict control ai-agent-book. Leave readOnly undeclared and you have given those two optimizations away on purpose.

The description decides selection accuracy

Weak:  search: Search data
Better: supplier.search: Search internal supplier records by normalized product
        requirements. Use this before public web discovery. Returns at most 20
        candidates with IDs, matched fields, and source evidence. Read-only;
        does not contact suppliers.

A good description answers seven questions: what it does, when to use it, when not to use it, what the inputs mean, what comes back, what side effects it has, and how to recover when it fails. The first three decide whether the model selects it; the rest decide whether it fills the arguments correctly and uses the result correctly.

"When not to use it" is the one teams drop most often, and it is exactly what prevents overlap. Put two generically described tools side by side and the model has nothing left to go on but a guess.

Schema cannot carry convention at all. Whether a timestamp is seconds or milliseconds, how filters nest, whether an empty array means "no filtering" or "clear everything" — those belong in prose, not in a type definition. The cheapest way to say them is one to five real call examples per tool; the figure the book gives is tool-call accuracy moving from roughly 72% to roughly 90% on some benchmarks ai-agent-book.

Arguments get rewritten in transit

Some failure modes only exist on the real path. One version of Cursor's edit tool takes old_string and new_string and matches them exactly, while the argument marshalling layer silently converts Chinese curly quotes (\u201c, \u201d) into ASCII straight quotes. The read tool returns the curly form untouched, the model passes it through faithfully, and the tool answers "no match." The model cannot see the conversion, so it retries and fails again ai-agent-book. The write direction is worse: it intends curly quotes, straight ones land on disk, and when it reads the file back the content looks wrong and it believes it made the mistake.

So the contract needs one more line: what the arguments pass through between the model and the executor — quote normalization, Unicode normalization, whitespace collapsing, path separators, newline style. No schema test will catch this class. Tests green while the transport edits your bytes is the hardest bug family to find, because the error surfaces far from its cause.

Trim the output or you are burning context

Outputs must be structured and bounded. Never return raw HTML dumps, entire database rows, or unbounded logs. Compress long logs, test output, process lists, and diffs deterministically while preserving exit codes, failure locations, key errors, statistics, and artifact references.

Anthropic hit this while building a C compiler with sixteen parallel Claudes. The test harness printed kilobytes of useless output and polluted the context window, and agents dropped into fresh containers with no context spent a long time re-orienting. Their fix was to rewrite the harness so each test prints at most a few lines and writes the important detail to a file, so logs are greppable with ERROR and its cause on the same line, and so summary statistics are precomputed instead of recalculated by every agent. anthropic-c-compiler

Send each error to whoever should handle it

The Error Contract draws one line. Expected failures — invalid arguments, missing targets, exhausted quotas — come back as structured error data the Agent can act on. Authentication failures, permission denials, data corruption, runtime defects, and unknown exceptions terminate or interrupt execution at the runtime layer and never reach the model as a raw stack trace.

Error objects carry at least code, category, message, retryable, safeForModel, and suggestedActions. safeForModel is the gate: it decides whether this text may enter the model's context at all. Without it, one database stack trace eats half your window budget and gives the model nothing actionable in return.

Tools need tests too

Every tool needs evals covering eight things: correct selection, abstaining when it should not be called, argument accuracy, recovery from error results, token efficiency, regression after a description change, whether dangerous arguments are blocked by guardrails, and whether retries cause duplicate side effects. anthropic-evals

The last two are safety tests, not quality tests. Skip them and the first place you discover the gap is a production incident.

The cost and how to check

The cost is upfront work: schema, risk, timeouts, compression logic, and evals for every tool. It pays off most where tools are few and tasks are stable. It is not worth it for throwaway scripts or exploratory prototypes.

Three questions audit you quickly: do any of your tools mirror REST endpoints one to one? Do their descriptions say when not to use them? When a tool fails, does the model receive a structured error or an entire stack trace?

References

  1. Building a C compiler with a team of parallel Claudes
  2. Demystifying evals for AI agents
  3. AI Agents in Depth, Chapter 4: Tools