---
title: 'Creating New Agents'
section: 'advanced'
tags: ['customization', 'agent templates', 'agents']
order: 2
---

# Creating New Agents

Create specialized agents from scratch using TypeScript files in the `.agents/` directory.

**Types:**

- **LLM-based** - Use prompts and language models
- **Programmatic** - Use TypeScript generator functions with `handleSteps`

**Control Flow:**

- `yield 'STEP'` - Run one LLM generation step
- `yield 'STEP_ALL'` - Run until completion
- `return` - End the agent's turn

**Accessing Context:**

- `agentState` - Current agent state and message history
- `prompt` - User's prompt to the agent
- `params` - Additional parameters passed to the agent

## Basic Structure

Create a new TypeScript file in `.agents/` directory. This example uses the [`researcher`](/publishers/codebuff/agents/researcher) as a spawnable subagent:

**.agents/my-custom-agent.ts**

```typescript
import { AgentDefinition } from './types/agent-definition'

const definition: AgentDefinition = {
  id: 'my-custom-agent',
  version: '1.0.0',

  displayName: 'My Custom Agent',
  spawnerPrompt:
    'Spawn this agent for specialized workflow tasks requiring custom logic',
  model: 'anthropic/claude-sonnet-4.5',
  outputMode: 'last_message',
  includeMessageHistory: true,
  toolNames: ['read_files', 'write_file', 'end_turn'],
  spawnableAgents: ['codebuff/researcher@0.0.1'], // Use full name for built-in agents

  inputSchema: {
    prompt: {
      type: 'string',
      description: 'What documentation to create or update',
    },
  },

  systemPrompt: `You are a documentation specialist.`,
  instructionsPrompt:
    "Write documentation based on the user's request. Research existing code and patterns first.",
  stepPrompt:
    'Continue working on the documentation. Use end_turn when complete.',
}

export default definition
```

## Domain-Specific Examples

### API Documentation Agent

Writes REST and GraphQL docs with examples. Uses the [`researcher`](/publishers/codebuff/agents/researcher) for documentation lookup:

**.agents/api-documenter.ts**

```typescript
import { AgentDefinition } from './types/agent-definition'

const definition: AgentDefinition = {
  id: 'api-documenter',
  version: '1.0.0',

  displayName: 'API Documentation Specialist',
  spawnerPrompt:
    'Spawn this agent to write API documentation with examples, schemas, and error codes',
  model: 'anthropic/claude-sonnet-4.5',
  outputMode: 'last_message',
  includeMessageHistory: true,

  toolNames: [
    'read_files',
    'code_search',
    'write_file',
    'spawn_agents',
    'end_turn',
  ],
  spawnableAgents: ['codebuff/researcher@0.0.1'], // Use full name for built-in agents

  inputSchema: {
    prompt: {
      type: 'string',
      description: 'What API endpoints or schemas to document',
    },
  },

  systemPrompt:
    'You are an API documentation specialist. Write clear documentation for REST APIs and GraphQL schemas with examples, request/response formats, and error codes.',
  instructionsPrompt:
    'Analyze the specified API endpoints and create documentation including examples, parameters, and response schemas.',
  stepPrompt:
    'Continue documenting the API. Include practical examples and edge cases. Use end_turn when complete.',
}

export default definition
```

### Database Migration Agent

Builds and reviews database migrations. Uses the [`reviewer`](/publishers/codebuff/agents/reviewer) for checking migrations:

**.agents/migration-specialist.ts**

```typescript
import { AgentDefinition } from './types/agent-definition'

const definition: AgentDefinition = {
  id: 'migration-specialist',
  version: '1.0.0',

  displayName: 'Database Migration Specialist',
  spawnerPrompt:
    'Spawn this agent to create reversible database migrations with proper indexing and rollback procedures',
  model: 'anthropic/claude-sonnet-4.5',
  outputMode: 'last_message',
  includeMessageHistory: true,

  toolNames: [
    'read_files',
    'write_file',
    'code_search',
    'run_terminal_command',
    'end_turn',
  ],
  spawnableAgents: ['codebuff/reviewer@0.0.1'],

  systemPrompt:
    'You are a database migration specialist. Create reversible database migrations with proper indexing and rollback procedures.',
  instructionsPrompt:
    "Create a database migration for the requested schema changes. Ensure it's reversible and includes proper indexing.",
  stepPrompt:
    'Continue working on the migration. Test it if possible and spawn a reviewer to check for issues.',
}

export default definition
```

## Programmatic Agents (Advanced)

LLM-based agents cover many tasks. Programmatic agents add precise control over complex workflows while still letting you tap into LLMs when you want them.

### Why Use Programmatic Agents?

- **Deterministic workflows** - Guarantee specific steps happen in order
- **Dynamic decision making** - Branch based on your own logic
- **Complex orchestration** - Coordinate multiple agents and tools with logic
- **State management** - Maintain state across multiple agent steps

### How It Works

Use TypeScript generator functions with the `handleSteps` field to control execution. This example spawns [`thinker`](/publishers/codebuff/agents/thinker) and [`reviewer`](/publishers/codebuff/agents/reviewer) subagents:

**.agents/code-analyzer.ts**

```typescript
import { AgentDefinition } from './types/agent-definition'

const definition: AgentDefinition = {
  id: 'code-analyzer',
  displayName: 'Code Analysis Expert',
  spawnerPrompt: 'Spawn for deep code analysis and refactoring suggestions',
  model: 'anthropic/claude-sonnet-4.5',

  toolNames: ['read_files', 'code_search', 'spawn_agents', 'write_file'],
  spawnableAgents: ['codebuff/thinker@0.0.1', 'codebuff/reviewer@0.0.1'],

  handleSteps: function* ({ agentState, prompt, params }) {
    // First, find relevant files
    const { toolResult: files } = yield {
      toolName: 'find_files',
      input: { query: prompt },
    }

    // Read the most important files
    if (files) {
      const filePaths = JSON.parse(files).slice(0, 5)
      yield {
        toolName: 'read_files',
        input: { paths: filePaths },
      }
    }

    // Spawn a thinker for deep analysis
    yield {
      toolName: 'spawn_agents',
      input: {
        agents: [
          {
            agent_type: 'thinker',
            prompt: `Analyze the code structure and suggest improvements for: ${prompt}`,
          },
        ],
      },
    }

    // Let the agent generate its response
    yield 'STEP_ALL'
  },
}

export default definition
```

### Key Concepts for Programmatic Agents

#### 1. Generator Function Basics

Your `handleSteps` function receives context and yields actions:

```typescript
handleSteps: function* ({ agentState, prompt, params }) {
  // agentState: Current conversation and agent state
  // prompt: What the user asked this agent to do
  // params: Additional parameters passed to the agent

  // Your logic here...
}
```

#### 2. Yielding Tool Calls

Execute tools and get their results:

```typescript
const { toolResult, toolError } = yield {
  toolName: 'read_files',
  input: { paths: ['file1.ts', 'file2.ts'] }
}

if (toolError) {
  // Handle error case
  console.error('Failed to read files:', toolError)
} else {
  // Use the result
  const fileContent = JSON.parse(toolResult)
}
```

#### 3. Control Flow Options

**Control Flow:**

- `yield 'STEP'` - Run one LLM generation step
- `yield 'STEP_ALL'` - Run until completion
- `return` - End the agent's turn

#### 4. Advanced Example: Conditional Workflow

```typescript
handleSteps: function* ({ agentState, prompt, params }) {
  // Step 1: Analyze the codebase
  const { toolResult: analysis } = yield {
    toolName: 'spawn_agents',
    input: {
      agents: [{
        agent_type: 'thinker',
        prompt: `Analyze: ${prompt}`
      }]
    }
  }

  // Step 2: Based on analysis, choose action
  if (analysis?.includes('refactor')) {
    // Get all files that need refactoring
    const { toolResult: files } = yield {
      toolName: 'find_files',
      input: { query: 'needs refactoring' }
    }

    // Step 3: Refactor each file
    for (const file of JSON.parse(files || '[]')) {
      yield {
        toolName: 'write_file',
        input: {
          path: file,
          instructions: 'Refactor for better performance',
          content: '// ... refactored code ...'
        }
      }
    }
  }

  // Step 4: Final review
  yield {
    toolName: 'spawn_agents',
    input: {
      agents: [{
        agent_type: 'reviewer',
        prompt: 'Review all changes'
      }]
    }
  }

  // Let the agent summarize
  yield 'STEP_ALL'
}
```

### When to Choose Programmatic vs LLM-based

**Use Programmatic (`handleSteps`) when:**

- You need guaranteed execution order
- Decisions depend on specific file contents
- Complex multi-step workflows with branching
- Integration with external systems
- Error recovery is critical

**Use LLM-based (prompts only) when:**

- Task is straightforward
- Agent needs creative freedom
- Natural language understanding is key
- Workflow is simple and linear
