Codebuff

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:

.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-4-sonnet-20250522",
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: "Create comprehensive 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

Specialized for documenting REST APIs and GraphQL schemas:

.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 create comprehensive API documentation with examples, schemas, and error codes",
model: "anthropic/claude-4-sonnet-20250522",
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. Create clear, comprehensive documentation for REST APIs and GraphQL schemas with examples, request/response formats, and error codes.",
instructionsPrompt: "Analyze the specified API endpoints and create detailed 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

Specialized for creating and reviewing database 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 safe, reversible database migrations with proper indexing and rollback procedures",
model: "anthropic/claude-4-sonnet-20250522",
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. Your goal is to create safe, 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)

🎯 This is where Codebuff agents become truly powerful! While LLM-based agents work well for many tasks, programmatic agents give you 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:

.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-4-sonnet-20250522",
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

Agents