ASK KNOX
beta
LESSON 305

Defining Your Agent

An agent definition is the contract between your requirements and Anthropic's infrastructure — every field is a decision with operational consequences.

9 min read

An agent in the Managed Agents API is a durable resource — not a temporary configuration you pass per-call, but a named, versioned definition that persists and is referenced by sessions. This distinction matters. You create an agent once and run it many times. The agent definition is the contract.

Getting the definition right is the architectural work. The API call to create it is trivial. Understanding what each field does and why — and what the consequences of getting it wrong are — is the lesson.

The Core Fields

import anthropic

client = anthropic.Anthropic()

agent = client.beta.agents.create(
    name="competitor-intelligence-agent",
    model="claude-sonnet-4-6",
    system="""You are a competitive intelligence specialist. 
When given a company name, gather publicly available information 
about their recent product launches (last 90 days), funding rounds, 
executive changes, and strategic announcements.

Synthesize findings into a structured report with these sections:
- Recent Products
- Business Development  
- Leadership Changes
- Strategic Implications

Cite sources for every claim. Do not speculate beyond what sources support.""",
    tools=[
        {"type": "web_search"},
        {"type": "bash"}
    ],
    skills=[]
)

print(f"Agent created: {agent.id}")

Each field is a decision.

The name Field

The name is not just a label. In multi-agent systems, it is an identifier in session thread events. When an orchestrator agent dispatches work to a subagent, the events that flow back are tagged with the subagent's name. If you name your agent agent-v1, your logs contain agent-v1. If you name it competitor-intelligence-agent, your logs tell you what ran.

Name agents for what they do, not what they are. research-agent is ambiguous. competitor-intelligence-agent is not. In a fleet of ten agents, you will be glad you were specific.

The model Field

The model field pins the agent to a specific Claude model. Use the full model string — never an alias.

For production agents: claude-sonnet-4-6 is the standard starting point. It handles complex reasoning and agentic behavior reliably. claude-opus-4-6 is appropriate for agents that require maximum reasoning depth on frontier tasks. Cost scales significantly — reserve Opus for tasks that justify it.

The model field is part of the agent's version identity. Changing the model is a potentially breaking change — the agent may behave differently, produce different output formats, or make different tool calling decisions. Treat a model change the same way you would treat a major version bump.

The system Field

The system prompt is the agent's constitution. It defines:

  • What the agent does and what it does not do
  • How it should reason through tasks
  • What output format it should produce
  • What quality standards it should apply
  • What it should do when it encounters errors or ambiguity

For Managed Agents, the system prompt carries more weight than in interactive use. There is no human in the loop to redirect the agent when it takes a wrong turn. The system prompt must be thorough enough to handle edge cases without intervention.

Practical rules:

  • Specify output format explicitly. Agents that produce structured output (JSON, markdown with specific sections) should have the format defined in the system prompt, not left implicit.
  • Define error handling. What should the agent do if a web search returns no results? If a tool call fails? If the input is malformed? Specify it.
  • Scope the task. A system prompt that says "you can help with anything" produces agents that drift. Scope the system prompt to the specific task domain.

The tools Field

Tools are the agent's capabilities beyond text generation. Built-in tools:

  • {"type": "web_search"} — search the web and retrieve content
  • {"type": "bash"} — execute shell commands in the container
  • {"type": "file_search"} — search files in the session's file system
  • MCP server tools — if MCP servers are attached, their tools are available by name

The critical mistake is including every tool by default. Each tool you add:

  • Increases the token overhead in every turn (the tool schema goes into context)
  • Expands the agent's potential action space, increasing the risk of unintended actions
  • Adds noise to the model's tool-selection reasoning

Include only tools the agent actually needs for its defined task. A research agent that only reads the web needs web_search. It does not need bash unless it needs to run scripts. A data processing agent needs bash. It may not need web_search.

The skills Field

Skills are versioned knowledge libraries referenced by ID. They load into context progressively — full content only when the agent determines the skill is relevant.

# Create a skill first
skill = client.beta.skills.create(
    name="competitor-report-format",
    description="Standard format for competitor intelligence reports",
    content="[detailed format specification...]"
)

# Reference it in the agent
agent = client.beta.agents.create(
    name="competitor-intelligence-agent",
    model="claude-sonnet-4-6",
    system="You are a competitive intelligence specialist...",
    tools=[{"type": "web_search"}],
    skills=[skill.id]
)

Skills are most useful when the agent has a procedural workflow that is too long to include in the system prompt efficiently, or when the same workflow needs to be reused across multiple agents.

The callable_agents Field

In multi-agent architectures, an orchestrator agent can dispatch work to subagent agents. The callable_agents field specifies which agents this agent can call:

orchestrator = client.beta.agents.create(
    name="pipeline-orchestrator",
    model="claude-sonnet-4-6",
    system="You are a research pipeline orchestrator. Decompose research requests into subtasks and dispatch them to specialized agents.",
    tools=[{"type": "bash"}],
    callable_agents=[
        competitor_intel_agent.id,
        market_research_agent.id,
        financial_data_agent.id
    ]
)

When the orchestrator calls a subagent, that call creates a new session thread within the parent session. The orchestrator sends a task; the subagent executes it; the result returns to the orchestrator's thread. This enables specialization — each subagent is optimized for its specific task — and parallelism — the orchestrator can dispatch multiple subagents concurrently.

Agent Versioning

Treat agents like APIs:

Backward-compatible changes (no version bump needed): improving the system prompt without changing output format, adding tools that the agent will use alongside existing ones, adding skills.

Breaking changes (create a new agent): changing the output format, changing the model to a significantly different behavior profile, removing tools that callers depend on, changes to the system prompt that alter fundamental agent behavior.

The pattern: keep the old agent ID active for existing callers while new callers reference the new agent. Retire old agents explicitly rather than deleting them — retained agent definitions are useful for audit and rollback.

# v1 agent
agent_v1 = client.beta.agents.create(
    name="competitor-intelligence-agent-v1",
    ...
)

# v2 with breaking format change
agent_v2 = client.beta.agents.create(
    name="competitor-intelligence-agent-v2",
    ...
)

# Migrate callers to v2; keep v1 for existing sessions