> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/block/goose/llms.txt
> Use this file to discover all available pages before exploring further.

# Agents

> Understanding agent orchestration, lifecycle, and subagent patterns in Goose

Agents are the core orchestration component of Goose. They manage the conversation flow between users, AI models, and tools, coordinating complex multi-step tasks autonomously.

## What is an Agent?

An agent in Goose is a stateful orchestrator that:

* Maintains conversation context and history
* Invokes AI models with appropriate prompts and tools
* Executes tool calls returned by the model
* Manages permissions and security checks
* Handles errors and retries
* Coordinates with subagents for complex workflows

```rust theme={null}
// Core agent structure (simplified)
pub struct Agent {
    provider: SharedProvider,                      // AI model
    extension_manager: Arc<ExtensionManager>,      // Available tools
    prompt_manager: Mutex<PromptManager>,          // System prompts
    config: AgentConfig,                           // Configuration
    retry_manager: RetryManager,                   // Error handling
    // ...
}
```

## Agent Lifecycle

The typical lifecycle of an agent interaction:

```mermaid theme={null}
stateDiagram-v2
    [*] --> Initialize: Create Agent
    Initialize --> Ready: Load Extensions & Config
    Ready --> Processing: User Message
    Processing --> ModelCall: Build Prompt
    ModelCall --> ToolExecution: Model Returns Tools
    ToolExecution --> ModelCall: Tool Results
    ModelCall --> Response: Model Returns Text
    Response --> Ready: Stream to User
    Ready --> [*]: Session End
    
    ToolExecution --> PermissionCheck: Check Security
    PermissionCheck --> ToolExecution: Approved
    PermissionCheck --> Response: Denied
```

### 1. Initialization

When an agent is created, it:

```rust theme={null}
// From crates/goose/src/agents/agent.rs
impl Agent {
    pub async fn new(
        config: AgentConfig,
        provider: SharedProvider,
        extension_manager: Arc<ExtensionManager>,
    ) -> Result<Arc<Self>> {
        // Initialize prompt manager with system prompts
        let prompt_manager = PromptManager::new();
        
        // Set up permission handling
        let (confirmation_tx, confirmation_rx) = mpsc::channel(32);
        
        // Initialize retry manager
        let retry_manager = RetryManager::new();
        
        // Create agent instance
        Ok(Arc::new(Self {
            provider,
            extension_manager,
            config,
            prompt_manager: Mutex::new(prompt_manager),
            confirmation_tx,
            confirmation_rx: Mutex::new(confirmation_rx),
            retry_manager,
            // ...
        }))
    }
}
```

### 2. Message Processing

When a user sends a message:

1. **Build Context**: Gather conversation history, system prompts, and available tools
2. **Model Invocation**: Send to AI provider with streaming enabled
3. **Stream Processing**: Handle chunks as they arrive (text or tool calls)
4. **Tool Execution**: Execute any tools the model requests
5. **Continue Loop**: Feed tool results back to model
6. **Completion**: Return final response to user

```rust theme={null}
// Simplified message processing flow
pub async fn reply(
    &self,
    session: &Session,
    messages: Vec<Message>,
) -> Result<impl Stream<Item = AgentEvent>> {
    let mut conversation = session.conversation.clone();
    let tools = self.extension_manager.get_tools().await?;
    
    loop {
        // Get model response
        let stream = self.provider.complete(
            system_prompt,
            conversation.messages(),
            tools.clone(),
        ).await?;
        
        // Process response stream
        while let Some(chunk) = stream.next().await {
            match chunk {
                ProviderMessage::Text(text) => {
                    // Stream text to user
                    yield AgentEvent::MessageChunk(text);
                }
                ProviderMessage::ToolUse(tool) => {
                    // Execute tool
                    let result = self.execute_tool(&tool).await?;
                    conversation.add_tool_result(result);
                    // Continue loop to get model's next response
                }
                ProviderMessage::Done => break,
            }
        }
        
        if no_more_tool_calls {
            break;
        }
    }
}
```

### 3. Tool Execution

When the model requests a tool:

```rust theme={null}
async fn execute_tool(&self, tool_request: &ToolRequest) -> Result<ToolResult> {
    // 1. Security check
    let permission = self.check_permission(&tool_request).await?;
    if permission.denied() {
        return Ok(ToolResult::denied());
    }
    
    // 2. Call extension
    let result = self.extension_manager
        .call_tool(
            &tool_request.name,
            tool_request.arguments.clone(),
        )
        .await?;
    
    // 3. Return result to conversation
    Ok(result)
}
```

## Agent Configuration

Agents can be configured through multiple mechanisms:

### Session Config

```rust theme={null}
pub struct SessionConfig {
    pub working_directory: PathBuf,           // Where agent operates
    pub extensions: Vec<ExtensionConfig>,     // Available tools
    pub system_prompt: Option<String>,        // Override default prompt
    pub max_turns: Option<u32>,               // Limit conversation length
    pub temperature: Option<f32>,             // Model creativity
}
```

### Recipe-Based Config

Recipes provide pre-configured agent behaviors:

```yaml theme={null}
# research-assistant.yaml
title: Research Assistant
instructions: |
  You are a research assistant that helps gather and synthesize information.
  Use web search and file reading tools to find relevant data.
  Always cite your sources.

extensions:
  - type: builtin
    name: developer
  - type: stdio
    name: brave-search
    cmd: npx
    args: ["-y", "@modelcontextprotocol/server-brave-search"]

settings:
  goose_model: claude-sonnet-4-20250514
  max_turns: 30
  temperature: 0.2
```

### Runtime Config

```rust theme={null}
// Override settings per session
let config = AgentConfig {
    session_manager,
    permission_manager,
    scheduler_service: None,
    goose_mode: GooseMode::Chat,
    disable_session_naming: false,
    goose_platform: GoosePlatform::GooseCli,
};
```

## Subagents

Subagents are independent agent instances spawned to handle specific sub-tasks. This enables:

* **Parallel execution**: Multiple tasks running simultaneously
* **Context isolation**: Prevent context window overflow
* **Specialized behaviors**: Different instructions per task
* **Composed workflows**: Break complex tasks into manageable pieces

### Creating Subagents

Subagents can be created in two ways:

#### 1. Ad-hoc Subagents

Create on-the-fly with custom instructions:

```yaml theme={null}
prompt: |
  To analyze this codebase:
  
  1. Spawn a subagent to analyze frontend:
     subagent(instructions: "List all React components and their props")
  
  2. Spawn another for backend:
     subagent(instructions: "Document all API endpoints")
  
  3. Synthesize findings from both into a report.
```

The model uses the `subagent` tool:

```json theme={null}
{
  "name": "subagent",
  "arguments": {
    "instructions": "List all React components and their props",
    "settings": {
      "model": "gpt-4o-mini",
      "max_turns": 10
    }
  }
}
```

#### 2. Sub-recipes

Predefined subagent templates:

```yaml theme={null}
# main-recipe.yaml
title: Code Analysis Workflow

sub_recipes:
  - name: "find_files"
    path: "./sub-recipes/file-finder.yaml"
    description: "Locate relevant files"
  
  - name: "analyze_code"
    path: "./sub-recipes/code-analyzer.yaml"
    sequential_when_repeated: true

prompt: |
  First, find relevant files:
  subagent(subrecipe: "find_files", parameters: {"pattern": "*.rs"})
  
  Then analyze each file found.
```

### Subagent Architecture

```mermaid theme={null}
graph TB
    subgraph "Parent Agent"
        PA[Parent Agent]
        PConv[Conversation]
    end
    
    subgraph "Subagent 1"
        SA1[Subagent]
        SA1Conv[Isolated Conversation]
        SA1Tools[Scoped Tools]
    end
    
    subgraph "Subagent 2"
        SA2[Subagent]
        SA2Conv[Isolated Conversation]
        SA2Tools[Scoped Tools]
    end
    
    PA -->|spawn| SA1
    PA -->|spawn| SA2
    SA1 -->|summary| PA
    SA2 -->|summary| PA
    PA --> PConv
    SA1 --> SA1Conv
    SA2 --> SA2Conv
```

### Subagent Implementation

```rust theme={null}
// From crates/goose/src/agents/subagent_handler.rs
pub async fn run_subagent_task(
    params: SubagentRunParams
) -> Result<String> {
    // Create isolated agent instance
    let agent = Agent::new(
        params.config,
        provider,
        extension_manager,
    ).await?;
    
    // Create new session for subagent
    let session = SessionManager::create_session(
        SessionType::SubAgent,
        params.recipe,
    ).await?;
    
    // Execute task with isolated context
    let messages = agent.reply(
        &session,
        vec![Message::user(params.task_config.instructions)],
    ).await?;
    
    // Return summary or full conversation
    if params.return_last_only {
        extract_last_message(&messages)
    } else {
        extract_all_text(&messages)
    }
}
```

### Parallel Subagent Execution

Multiple subagent calls in one model response run in parallel:

```rust theme={null}
// When model returns multiple subagent tool calls:
[
  {"name": "subagent", "id": "1", "args": {"instructions": "Task A"}},
  {"name": "subagent", "id": "2", "args": {"instructions": "Task B"}},
  {"name": "subagent", "id": "3", "args": {"instructions": "Task C"}}
]

// Agent executes all three concurrently
let results = futures::future::join_all(
    tool_calls.iter().map(|call| execute_subagent(call))
).await;
```

### Subagent Best Practices

<AccordionGroup>
  <Accordion title="Use summary mode by default">
    Subagents return concise summaries to the parent, preventing context overflow:

    ```rust theme={null}
    // Default behavior (summary mode)
    subagent(instructions: "Analyze file.rs")
    // Returns: "The file contains 3 functions..."

    // Full conversation mode (use sparingly)
    subagent(instructions: "...", summary: false)
    // Returns: Complete message history
    ```
  </Accordion>

  <Accordion title="Scope extensions appropriately">
    Give subagents only the tools they need:

    ```yaml theme={null}
    prompt: |
      subagent(
        instructions: "Read all markdown files",
        extensions: ["developer"]  # Read-only access
      )
    ```
  </Accordion>

  <Accordion title="Use sequential_when_repeated for stateful tasks">
    Prevent parallel execution when tasks have side effects:

    ```yaml theme={null}
    sub_recipes:
      - name: "database_migration"
        path: "./migrations.yaml"
        sequential_when_repeated: true  # Don't run migrations in parallel
    ```
  </Accordion>

  <Accordion title="Choose the right model per task">
    Use cheaper/faster models for simple subagent tasks:

    ```yaml theme={null}
    prompt: |
      # Simple file counting - use fast model
      subagent(
        instructions: "Count files in src/",
        settings: {model: "gpt-4o-mini", max_turns: 3}
      )
      
      # Complex analysis - use powerful model
      subagent(
        instructions: "Analyze security vulnerabilities",
        settings: {model: "claude-sonnet-4-20250514"}
      )
    ```
  </Accordion>
</AccordionGroup>

## Agent Modes

Goose supports different operational modes:

```rust theme={null}
pub enum GooseMode {
    Chat,      // Interactive conversation mode
    Execute,   // Task execution mode (recipes)
}
```

### Chat Mode

* Interactive back-and-forth conversation
* User can interrupt and provide feedback
* Agent asks for clarification when needed
* Suitable for exploratory tasks

### Execute Mode

* Recipe-driven execution
* Runs to completion with minimal interaction
* Uses final\_output tool to return structured results
* Suitable for automated workflows

## Turn Management

Agents limit conversation length to prevent runaway execution:

```rust theme={null}
const DEFAULT_MAX_TURNS: u32 = 1000;

// In agent loop
for turn in 0..max_turns {
    let response = provider.complete(...).await?;
    
    if turn >= max_turns {
        return Err(anyhow!("Max turns exceeded"));
    }
    
    if response.is_final {
        break;
    }
}
```

Turns can be configured via:

* Recipe `settings.max_turns`
* Session config
* Subagent parameters

## Context Management

Agents automatically compact conversation history when approaching token limits:

```rust theme={null}
// From crates/goose/src/context_mgmt/
const DEFAULT_COMPACTION_THRESHOLD: f64 = 0.75;

if token_count > (context_limit * COMPACTION_THRESHOLD) {
    // Compact older messages while preserving:
    // - System prompt
    // - Recent messages
    // - Important context
    messages = compact_messages(messages, context_limit);
}
```

## Error Handling and Retries

Agents include sophisticated retry logic for transient failures:

```rust theme={null}
// From crates/goose/src/agents/retry.rs
pub struct RetryManager {
    max_retries: u32,
    backoff: ExponentialBackoff,
}

impl RetryManager {
    pub async fn retry_with_backoff<F, T>(
        &self,
        operation: F,
    ) -> Result<T>
    where
        F: Fn() -> Future<Output = Result<T>>,
    {
        let mut attempts = 0;
        loop {
            match operation().await {
                Ok(result) => return Ok(result),
                Err(e) if is_retryable(&e) && attempts < self.max_retries => {
                    attempts += 1;
                    sleep(self.backoff.next_delay()).await;
                }
                Err(e) => return Err(e),
            }
        }
    }
}
```

Retryable errors include:

* Network timeouts
* Rate limiting (429)
* Server errors (5xx)
* Transient provider errors

## Security and Permissions

Agents enforce security policies before tool execution:

```rust theme={null}
async fn check_permission(
    &self,
    tool_request: &ToolRequest,
) -> Result<PermissionCheckResult> {
    // 1. Check configured permission level
    let level = self.config.permission_manager
        .get_permission_level(&tool_request.name);
    
    match level {
        PermissionLevel::Allow => Ok(PermissionCheckResult::Allowed),
        PermissionLevel::Deny => Ok(PermissionCheckResult::Denied),
        PermissionLevel::Confirm => {
            // 2. Request user confirmation
            let confirmation = self.request_confirmation(&tool_request).await?;
            Ok(PermissionCheckResult::from(confirmation))
        }
    }
}
```

See [Sessions](/concepts/sessions) for session isolation and [Extensions](/concepts/extensions) for tool sandboxing.

## Next Steps

<CardGroup cols={2}>
  <Card title="Providers" icon="brain" href="/concepts/providers">
    Learn how agents interact with AI models
  </Card>

  <Card title="Extensions" icon="puzzle-piece" href="/concepts/extensions">
    Understand the tools agents can use
  </Card>

  <Card title="Recipes" icon="book" href="/concepts/recipes">
    Create pre-configured agent behaviors
  </Card>

  <Card title="Sessions" icon="comments" href="/concepts/sessions">
    Manage agent state and history
  </Card>
</CardGroup>
