Customizing Agents with Options

Introduction: Configuring Your Agent

In the previous lesson, you learned how to use query() to send prompts and handle streaming responses. Every time you called query(), the agent used default settings — a specific Claude model, no special instructions about how to behave, and a set limit on how long it could work on a task. While these defaults work fine for simple experiments, real applications need more control. This is where configuration options come in — they define how the agent should behave during a query() run.

Understanding Agent Configuration with Options

Agent configuration in TypeScript uses plain object literals to control every aspect of your agent's behavior and capabilities. While your prompt tells the agent what you want it to do, the options object defines how the agent should operate, what tools it can access, and under what constraints. Think of it as the difference between giving someone a task and setting the complete working environment — the prompt is the task itself, while the options define the working conditions, available resources, permissions, and operational boundaries.

The configuration object gives you control over numerous aspects of agent behavior:

  • Model selection — Choose which Claude model powers your agent
  • Personality and instructions — Define the agent's role, tone, and behavioral guidelines through system prompts
  • Reasoning limits — Control how many thinking cycles the agent can perform
  • Tool access — Specify which tools (like file reading, writing, or bash execution) the agent can use
  • Permission handling — Configure whether the agent needs approval before executing tools
  • Working directory — Set the filesystem location where the agent operates
  • Skill loading — Configure sources for loading custom agent skills
  • External integrations — Connect Model Context Protocol (MCP) servers for custom tooling

In this lesson, we'll focus on three fundamental settings that shape the agent's basic behavior: model selection, system prompts, and turn limits. These parameters form the foundation of agent configuration and are essential for understanding how to control your agent's core behavior before diving into more advanced capabilities like tool management and permissions.

Selecting Your Model

The model parameter lets you choose which Claude model powers your agent. Different models offer different trade-offs between speed, cost, and capability. Anthropic provides several Claude models, each optimized for different use cases. The model you choose directly impacts how the agent reasons, how quickly it responds, and how much each interaction costs. Here's how you specify a model in your configuration:

TypeScript
import { type Options } from "@anthropic-ai/claude-agent-sdk";

// Configure the agent with an options object
const options: Options = {
  model: "haiku",  // Choose your model
};

You can specify models in two ways:

Using Model Family Names — Use simple family names like "haiku", "sonnet", or "opus" to automatically get the latest version of that model family. This approach is convenient for development and ensures you're always using the latest improvements.

Using Specific Version Identifiers — Use full model identifiers like "claude-haiku-4-5-20251001" to pin to a specific version. This approach is useful for production applications where you want predictable, consistent behavior.

Each Claude model family serves different use cases:

Haiku — The fastest and most cost-effective models, ideal for simple tasks like answering straightforward questions, formatting text, or performing basic analysis.

Sonnet — Balanced models that offer a sweet spot between speed and intelligence, handling more complex reasoning while maintaining good performance.

Opus — The most capable models that provide the highest level of reasoning capability for the most demanding tasks.

When choosing a model, consider the complexity of your task and your budget constraints — you can always start with a faster model and upgrade if the results aren't meeting your needs.

Shaping Agent Behavior with System Prompts

The systemPrompt parameter defines the agent's role, tone, and behavior before it even sees your actual prompt. This is your opportunity to give the agent a personality, set expectations about how it should communicate, or provide domain expertise. When working with agents that use tools, the system prompt becomes especially valuable for setting constraints and specifications — you might define code style preferences for a coding assistant, specify output formats for data analysis tools, or establish rules about which files the agent can access. The system prompt acts as a persistent instruction that shapes every response and tool use during the interaction. Here's how you add a system prompt to your configuration:

TypeScript
import { type Options } from "@anthropic-ai/claude-agent-sdk";

// Configure the agent with an options object
const options: Options = {
  model: "haiku",
  systemPrompt: "You are an enthusiastic beginner friendly tutor.",  // Define role, instructions and behavior
};

The system prompt you provide is integrated within the agent's default system prompt, which already contains instructions about available tools and core capabilities. Your custom prompt adds personality, role definitions, and specific constraints on top of these base instructions. Before processing your user prompt, the agent reads both the default system instructions and your custom additions, then adopts the combined behavior. In this example, the agent will respond with enthusiasm, use simple language, and focus on making concepts accessible to beginners — while still maintaining its ability to use tools and perform other agent functions.

Limiting Agent Turns with maxTurns

The maxTurns parameter controls how many reasoning cycles the agent can perform before it must complete the task. A turn represents one complete cycle in which the agent thinks about the task, potentially uses tools, evaluates the results, and decides whether to continue or finish. This parameter serves two important purposes: it prevents runaway costs from tasks that spiral into many reasoning cycles, and it forces the agent to work efficiently within constraints. Here's how you add a turn limit to your configuration:

TypeScript
import { type Options } from "@anthropic-ai/claude-agent-sdk";

// Configure the agent with an options object
const options: Options = {
  model: "haiku",
  systemPrompt: "You are an enthusiastic beginner friendly tutor.",
  maxTurns: 5,  // Limit agent reasoning cycles
};

Setting maxTurns: 5 means the agent can go through up to five reasoning cycles before the interaction terminates. If the agent reaches the turn limit before completing the task, the agent stops and returns a ResultMessage with subtype: 'error_max_turns' and result: null. This message signals that the agent exhausted its allowed turns without finishing the task, but note that isError: false — the SDK doesn't treat this as a failure, just as a completion condition. The ResultMessage still includes useful metadata like cost information, token usage, and the number of turns completed, which you can use for monitoring and optimization.

If you're building an application that makes many agent calls, setting reasonable turn limits helps you predict and control costs. A simple Q&A bot might use maxTurns: 2, while a complex code analysis tool might allow maxTurns: 10 or more. You can adjust this parameter based on your specific use case and budget.

Passing Options to query()

Once you've created your options object with your desired settings, you pass it to the query() function using the options parameter. This applies your configuration to that specific agent interaction. Here's the complete pattern showing how all the pieces fit together:

TypeScript
import { query, type SDKMessage, type Options } from "@anthropic-ai/claude-agent-sdk";

async function main() {
  // Configure the agent with an options object
  const options: Options = {
    model: "haiku",
    systemPrompt: "You are an enthusiastic beginner friendly tutor.",
    maxTurns: 5,
  };
  
  // Pass options to query() to apply configuration
  for await (const message of query({
    prompt: "What is the difference between Claude and Claude Code?",
    options,
  }) as AsyncIterable<SDKMessage>) {
    // Display assistant message responses
    switch (message.type) {
      case "assistant": {
        for (const block of message.message.content ?? []) {
          if (block.type === "text") {
            console.log(block.text);
          }
        }
        break;
      }
      default:
        // no-op for other message types in this lesson
        break;
    }
  }
}

main();

The code creates an options object with three settings: it selects the Haiku model for fast, cost-effective responses, sets a system prompt that makes the agent act as an enthusiastic, beginner-friendly tutor, and limits the interaction to five turns maximum. When you pass this options object to query(), the agent adopts these settings for this specific interaction.

The streaming pattern you learned in the previous lesson remains the same — you still use for await...of to iterate over messages, check for messages with type === "assistant", and extract text from blocks with type === "text". Now let's see how the agent responds with these configured settings.

Observing the Configured Agent's Response

When you run the code with your custom configuration, you'll see the agent respond with the personality and constraints you specified:

text
Great question! Let me explain the differences between Claude and Claude Code:

## Claude
**Claude** is Anthropic's general-purpose AI assistant available through various interfaces:
- **Claude.com website**: You can chat with Claude directly in your browser
- **Claude API**: Developers can integrate Claude into their applications
- **Mobile apps**: Claude is available on iOS and Android
- **Purpose**: General conversation, analysis, writing, coding help, research, and much more

Claude is designed to be conversational and helpful across a wide range of tasks.

## Claude Code
**Claude Code** is a specialized coding environment (the one you're using right now!) that provides:
- **Integrated development tools**: Direct access to file reading/writing, terminal execution, Git operations, and code searching
- **Hands-on coding capability**: I can actually read, edit, and write files in your codebase
- **Terminal access**: I can run commands, install dependencies, and execute scripts
- **Repository management**: I can work with Git, view diffs, and manage your code
- **File exploration**: I can search and navigate your project structure efficiently
- **Real-time feedback**: I can build, test, and debug your code immediately

## Key Differences

| Feature | Claude | Claude Code |
|---------|--------|------------|
| **File Operations** | Can discuss code, suggest changes | Can actually read, write, and edit files |
| **Terminal/Commands** | Cannot execute | Can run bash commands |
| **Git Integration** | Cannot execute | Full Git support |
| **Code Exploration** | Cannot search files | Can search and navigate codebases |
| **Testing** | Cannot run tests | Can execute tests and see results |
| **Debugging** | Suggests approaches | Can debug and identify issues directly |
| **Use Cases** | General AI assistance | Hands-on development and coding projects |

## Summary
Think of it this way: **Claude** is like having a knowledgeable mentor you can ask questions to, while **Claude Code** is like having a developer teammate who can directly work on your code alongside you!

Is there anything specific about Claude Code's capabilities you'd like to explore? I'm here to help you with your coding projects! 🚀

Notice how the response reflects the "enthusiastic beginner friendly tutor" personality you configured. The agent uses clear structure with headers and tables, explains concepts in accessible language, includes helpful comparisons, and ends with an encouraging emoji and an offer to explain more. This same question with a different system prompt (like "You are a terse senior engineer") would produce a much more concise, technical response. The model choice (haiku) ensured this response came back quickly and cost-effectively, while the turn limit (5) prevented the agent from over-elaborating on the topic.

Summary

You've now learned how to take control of your agent's fundamental behavior through configuration options. The model parameter lets you choose which Claude model powers your agent, the systemPrompt parameter shapes the agent's personality and communication style, and the maxTurns parameter limits reasoning cycles to control costs. TypeScript's type system helps ensure your configuration is correct, and using the Options type from the SDK makes your configuration explicit and type-safe. In the practice exercises ahead, you'll experiment with different configurations to see how each parameter affects the agent's behavior.

Sign up

Join the 1M+ learners on CodeSignal

Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal