Back to home

03 — BEHAVIOR CONTROL

Tool descriptions and usage guidelines

8 min read

Your tool descriptions aren't just documentation. They're instructions that directly shape how your agent behaves. A vague description leads to confused tool usage. A detailed one with clear guidelines prevents entire categories of mistakes.

Most people write tool descriptions like API docs: "This tool reads a file." That tells the model what the tool does, but not when to use it, what mistakes to avoid, or how it fits into the broader workflow. The result? Your agent calls bash to read files when it has a dedicated Read tool, or uses find when you have a faster Glob tool.

Good tool descriptions are mini training manuals that teach the agent not just what each tool does, but how to think about using it.

Anatomy of an Effective Tool Description

Let's break down what makes a tool description actually work. Here's the pattern that reliably produces good behavior:

Start With Purpose

Begin with a clear, one-line statement of what the tool does:

Reads a file from the local filesystem.

Simple. Direct. The agent immediately knows what this is for.

Add Usage Guidelines

This is where most people stop, but it's where you should really begin. Usage guidelines tell the agent when and how to use the tool:

Usage:
- By default, reads up to 2000 lines from the beginning
- Optionally specify offset and limit for long files
- Results use cat -n format with line numbers
- You can call multiple Read tools in parallel when needed

These guidelines shape behavior. The parallel usage note? That encourages the agent to batch operations instead of reading files one by one. That's a 3-5x speed improvement right there.

Define Anti-Patterns

This is critical. Tell the agent what NOT to do:

IMPORTANT: NEVER invoke grep or rg as a Bash command.
The Grep tool has been optimized for correct permissions and access.
Use this tool instead.

Without this, your agent will absolutely use bash grep instead of your dedicated Grep tool. Models default to familiar patterns unless you explicitly redirect them.

Parameter Descriptions with Examples

Don't just list parameters. Show examples:

Args:
    glob_pattern: Glob pattern to match files against
                    Examples: "*.json", "src/**/*.test.tsx", "**/README.md"
    base_path: Base directory to search from (default is project root ".")

Examples ground the agent's understanding. Abstract descriptions like "pattern to match" leave too much ambiguity.

Return Value Format

Tell the agent exactly what to expect back:

Returns:
    List of file paths matching the pattern, sorted alphabetically

This helps the agent plan next steps and handle the output correctly.

Real-World Example: The Bash Tool

Let's look at a complex tool with lots of rules. The Bash tool needs heavy guidance because it's powerful and can be misused:

Executes bash commands in a persistent shell session.

Before executing:
1. Verify parent directories exist if creating new files
2. Quote paths with spaces using double quotes
3. Use absolute paths instead of cd when possible

Usage notes:
- MUST avoid search commands (find, grep) - use Grep/Glob tools instead
- MUST avoid read commands (cat, head, tail, ls) - use Read/LS tools
- Chain commands with ';' or '&&', not newlines
- Can run in background with run_in_background: true for dev servers
- Build commands blocked for Next.js projects (handled during deployment)

ALLOWED:
  - Shell commands (echo, mkdir, touch)
  - Read-only git (status, log, diff, show)
  - Package management (npm, yarn, pnpm)
  - Testing frameworks

PROHIBITED:
  - Destructive git commands (commit, reset, push --force)
  - Destructive operations (rm -rf, sudo)
  - File reading commands (use dedicated tools)

Examples:
  GOOD: pytest /path/to/tests
  BAD: cd /path && pytest tests

Notice how explicit this is. It doesn't assume the agent knows best practices. It teaches them.

Zod Schemas and Parameter Validation

You'll use Zod schemas to define and validate parameters:

const READ_SCHEMA = z.object({
  file_path: z.string().describe("The path to the file to read"),
  offset: z.number().optional().describe(
    "Line number to start from. Only for large files"
  ),
  limit: z.number().optional().describe(
    "Number of lines to read. Only for large files"
  ),
});

The describe() method on each field becomes part of what the model sees. Use it to clarify edge cases and usage patterns.

Convert your Zod schema to JSON Schema for the model:

import { zodToJsonSchema } from "zod-to-json-schema";
 
const READ_PARAMETERS = zodToJsonSchema(READ_SCHEMA);

Embedding Guidelines in Descriptions

Here's a pattern that works well - embed specific guidelines directly in the description:

For search tools:

- Use this for exact text matches across files
- Filter with glob patterns (e.g., "*.tsx", "src/**/*.ts")
- For open-ended searches requiring multiple rounds, use Task tool
- Pattern uses ripgrep syntax (not grep)

For file operations:

- Read the file with Read tool BEFORE using this tool
- This tool will fail if you haven't read the file first
- ALWAYS prefer editing existing files over creating new ones

These aren't just nice-to-haves. They prevent the agent from making mistakes you'll see repeatedly without them.

Security and Safety Rules

For tools that can cause problems, be explicit about restrictions:

Security hardening:
- Only "npm install" commands are allowed
- Destructive operations will be rejected
- Commands run from within project folder
- Output truncated at 30,000 characters

List prohibited operations clearly. Models respect explicit boundaries better than implicit ones.

Tool Relationships and When to Delegate

Teach the agent how tools relate to each other:

This tool handles all database operations.
Always use integer IDs (never UUID) in schemas.

For seeder requests: First analyze UI by reading components
to find mock data, then pass that to database agent for realistic seeds.

Trust database agent outputs completely - use schemas and APIs
exactly as provided. Never validate or modify results.

This creates proper delegation patterns. The agent learns to trust specialized sub-agents instead of second-guessing their output.

Examples That Teach Patterns

Include examples that demonstrate the pattern you want:

Examples:
  curl("/api/users") - GET request to localhost:3000
  curl("/api/users", "POST", '{"name":"John"}') - POST with JSON
  curl("https://api.github.com/users/octocat") - External API

Each example teaches a use case. The agent learns by pattern matching against these.

Output Format Specifications

Be precise about what comes back:

Returns:
    Formatted search results with titles, URLs, and content summaries

Or more detailed:

Returns:
    File contents with line numbers in cat -n format

Format example:
     1  import React from 'react';
     2
     3  export function Component() {

Show the actual format. This prevents confusion when the agent tries to parse results.

Common Mistakes in Tool Descriptions

Too terse - "Reads a file" doesn't tell the agent when to use this vs bash cat.

No anti-patterns - Without explicit "don't do X", agents will do X all the time.

Vague parameters - "pattern: the pattern to search for" is useless. Show examples.

No context - Tools don't exist in isolation. Explain how they relate to other tools.

Missing edge cases - What happens with an empty file? A missing file? Long output? Document it.

Testing Your Descriptions

How do you know if your tool descriptions work? Watch for patterns:

If your agent keeps calling bash grep instead of Grep tool, your Grep description needs stronger anti-patterns.

If it creates files when it should edit them, your Write tool needs clearer guidance about preferring edits.

If it uses tools incorrectly, your parameter examples aren't clear enough.

Track these mistakes and update descriptions to prevent them. Your tool descriptions should evolve based on observed behavior.

The Compound Effect

Here's what happens when you invest in detailed tool descriptions:

Your agent makes fewer mistakes. It uses the right tool for each job. It batches operations efficiently. It follows security rules without being prompted. It delegates to specialized agents appropriately.

All of this comes from descriptions that teach rather than just document.

Most coding agents have 10-15 core tools and maybe 5-10 specialized ones. Spending time to write comprehensive descriptions for each one pays dividends on every single request your agent handles.

What's Next

You now understand how to write tool descriptions that actually guide agent behavior. But having all tools available all the time isn't always right.

In the next guide, we'll cover agent modes - how to switch between full agent mode with all tools and chat mode with limited, read-only access. Different contexts need different capabilities, and mode switching is how you control that.

Let's build that next.