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 stepyield 'STEP_ALL'— Run until completionreturn— End the agent's turn
Accessing Context:
agentState— Current agent state and message historyprompt— User's prompt to the agentparams— Additional parameters passed to the agent
Basic Structure
Create a new TypeScript file in .agents/ directory:
.agents/my-custom-agent.ts
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: 'openai/gpt-5.3-codex',outputMode: 'last_message',includeMessageHistory: true,toolNames: ['read_files', 'write_file', 'end_turn'],spawnableAgents: ['vesper/researcher@0.0.1'],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
Programmatic Agents
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.
How It Works
Use TypeScript generator functions with the handleSteps field to control execution:
.agents/code-analyzer.ts
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: 'openai/gpt-5.3-codex',toolNames: ['read_files', 'code_search', 'spawn_agents', 'write_file'],spawnableAgents: ['vesper/thinker@0.0.1', 'vesper/reviewer@0.0.1'],handleSteps: function* ({ agentState, prompt, params }) {// First, find relevant filesconst { toolResult: files } = yield {toolName: 'find_files',input: { query: prompt },}// Read the most important filesif (files) {const filePaths = JSON.parse(files).slice(0, 5)yield {toolName: 'read_files',input: { paths: filePaths },}}// Spawn a thinker for deep analysisyield {toolName: 'spawn_agents',input: {agents: [{agent_type: 'thinker',prompt: `Analyze the code structure and suggest improvements for: ${prompt}`,},],},}// Let the agent generate its responseyield 'STEP_ALL'},}export default definition
Key Concepts
Generator Function Basics
Your handleSteps function receives context and yields actions:
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}
Yielding Tool Calls
Execute tools and get their results:
const { toolResult, toolError } = yield {toolName: 'read_files',input: { paths: ['file1.ts', 'file2.ts'] }}if (toolError) {console.error('Failed to read files:', toolError)} else {const fileContent = JSON.parse(toolResult)}
Control Flow Options
yield 'STEP'— Run one LLM generation stepyield 'STEP_ALL'— Run until completionreturn— End the agent's turn