Skip to main content
Goose is an AI agent framework written in Rust with CLI and Electron desktop interfaces. This guide explains the codebase structure and key architectural decisions.

Project Structure

goose/
├── crates/              # Rust workspace
│   ├── goose            # Core logic
│   ├── goose-acp        # Agent Client Protocol
│   ├── goose-acp-macros # ACP procedural macros
│   ├── goose-cli        # CLI entry point
│   ├── goose-server     # Backend (binary: goosed)
│   ├── goose-mcp        # MCP extensions
│   ├── goose-test       # Test utilities
│   └── goose-test-support # Test helpers
├── ui/
│   └── desktop/         # Electron app
├── evals/
│   └── open-model-gym/  # Benchmarking & evals
├── examples/            # Example extensions
└── documentation/       # Docusaurus site

Core Crates

goose

The heart of the framework. Contains:
  • agents/ - Agent implementations and lifecycle management
    • agent.rs - Main agent loop
    • extension.rs - Extension configuration
    • extension_manager.rs - Extension lifecycle
  • providers/ - LLM provider integrations
    • base.rs - Provider trait definition
    • anthropic.rs, openai.rs, etc. - Specific providers
    • declarative/ - JSON-based provider configs
    • canonical/ - Model capability registry
  • conversation/ - Message handling
    • message.rs - Message types
    • Conversation state management
  • config/ - Configuration management
    • Provider configs
    • Extension configs
    • Path management

goose-cli

Command-line interface. Entry point: crates/goose-cli/src/main.rs Provides commands:
  • session - Start interactive session
  • configure - Configure providers
  • run - Execute recipes
  • version - Version info

goose-server

HTTP/WebSocket server for the desktop UI. Entry point: crates/goose-server/src/main.rs Features:
  • REST API for agent management
  • WebSocket for streaming responses
  • Session management
  • OpenAPI schema generation

goose-mcp

Builtin MCP (Model Context Protocol) extensions:
  • autovisualiser - Automatic visualization generation
  • computercontroller - Desktop automation
  • memory - Long-term memory storage
  • tutorial - Interactive tutorials
Each extension implements the rmcp::ServerHandler trait.

goose-acp

Agent Client Protocol - defines communication between agents and extensions.

Key Architectural Patterns

Provider Trait

All LLM providers implement the Provider trait (crates/goose/src/providers/base.rs:456):
#[async_trait]
pub trait Provider: Send + Sync {
    fn get_name(&self) -> &str;
    
    async fn stream(
        &self,
        model_config: &ModelConfig,
        session_id: &str,
        system: &str,
        messages: &[Message],
        tools: &[Tool],
    ) -> Result<MessageStream, ProviderError>;
    
    fn get_model_config(&self) -> ModelConfig;
    // ... more methods
}
Key methods:
  • stream() - Primary method for streaming responses
  • complete() - Non-streaming completion
  • generate_session_name() - Create session titles
  • configure_oauth() - OAuth authentication

Extension System

Extensions are MCP servers that provide:
  • Tools - Functions the agent can call
  • Resources - Data sources
  • Prompts - Reusable prompt templates
Builtin extensions are spawned as in-process MCP servers using tokio::io::DuplexStream.

Message Flow

User Input

Agent (goose/agents/agent.rs)

Provider (streaming)

Tool Calls → Extension Manager

MCP Extensions

Tool Results → Agent

Provider (next turn)

Response

Declarative Providers

Simple providers can be defined with JSON (crates/goose/src/providers/declarative/):
{
  "name": "groq",
  "engine": "openai",
  "display_name": "Groq (d)",
  "description": "Fast inference with Groq hardware",
  "api_key_env": "GROQ_API_KEY",
  "base_url": "https://api.groq.com/openai/v1/chat/completions",
  "models": [
    {
      "name": "llama-3.3-70b-versatile",
      "context_limit": 131072,
      "max_tokens": 32768
    }
  ],
  "supports_streaming": true
}
This creates a full provider without writing Rust code.

Entry Points

  • CLI: crates/goose-cli/src/main.rs
  • Server: crates/goose-server/src/main.rs
  • UI: ui/desktop/src/main.ts
  • Agent: crates/goose/src/agents/agent.rs

Configuration Paths

Goose uses platform-specific directories:
  • Linux: ~/.config/goose/
  • macOS: ~/Library/Application Support/goose/
  • Windows: %APPDATA%\goose\
Structure:
config/
  └── providers/       # Provider configurations
data/
  └── sessions/        # Session history
state/                 # Runtime state
Override with GOOSE_PATH_ROOT environment variable.

Testing Architecture

Tests are organized:
  • Unit tests - Within crate files
  • Integration tests - crates/*/tests/ directories
  • MCP tests - crates/goose/tests/mcp_integration_test.rs
  • Test utilities - goose-test and goose-test-support crates
See Testing for details.

Build System

  • Cargo - Rust build system and package manager
  • Just - Task runner for common commands (see Justfile)
  • npm - UI dependencies and scripts
  • Hermit - Development environment manager

Design Principles

  1. Simplicity - Trust Rust’s type system, avoid defensive code
  2. Composability - Small, focused components
  3. Extensibility - MCP-based extension system
  4. Provider agnostic - Works with any LLM
  5. Local-first - Runs entirely on your machine

Common Code Patterns

Error Handling

Use anyhow::Result for error propagation:
use anyhow::Result;

fn do_something() -> Result<()> {
    // ...
    Ok(())
}

Async Code

Heavy use of tokio and async_trait:
use async_trait::async_trait;

#[async_trait]
trait MyTrait {
    async fn process(&self) -> Result<()>;
}

Streaming

Providers return streams of message chunks:
type MessageStream = Pin<Box<dyn Stream<Item = Result<
    (Option<Message>, Option<ProviderUsage>),
    ProviderError
>> + Send>>;

Next Steps

Build docs developers (and LLMs) love