clawdbot-workspace/research-goose-architecture.md
2026-02-06 23:01:30 -05:00

23 KiB

Goose (Block) AI Agent — Architecture & Customization Research Report

Last Updated: 2026-02-06
Purpose: Deep research for forking/cloning Goose into a custom agent
License: Apache 2.0 (permissive, allows derivative works & white-labeling)


Table of Contents

  1. Repository Structure
  2. Core Architecture Deep Dive
  3. Desktop UI Architecture
  4. MCP Integration System
  5. Extension/Plugin System
  6. Permission & HITL System
  7. Forking Strategy
  8. Community Extensions & Patterns
  9. Key Findings for Custom Agent Development
  10. Sources

1. Repository Structure

Repo: https://github.com/block/goose

Goose is a Rust + TypeScript monorepo with the following key structure:

block/goose/
├── crates/
│   ├── goose/              # Core agent logic (the brain)
│   │   └── src/
│   │       ├── agents/
│   │       │   ├── agent.rs        # Main agent implementation
│   │       │   └── extension.rs    # ExtensionConfig enum (L87-200)
│   │       └── providers/
│   │           └── base.rs         # Provider trait definition
│   ├── goose-bench/        # Benchmarking framework
│   ├── goose-cli/          # CLI entry point
│   │   └── src/
│   │       ├── main.rs             # CLI entry point
│   │       └── commands/
│   │           ├── configure.rs    # Provider/extension configuration
│   │           └── mcp.rs          # MCP server command handling
│   ├── goose-server/       # Backend HTTP server (binary: goosed)
│   │   └── src/main.rs            # Server entry point
│   ├── goose-mcp/          # Built-in MCP extensions (developer, memory, etc.)
│   │   └── src/
│   │       └── developer/
│   │           └── tools/
│   │               └── shell.rs    # Shell tool example
│   ├── goose-test/         # Test utilities
│   ├── mcp-client/         # MCP client implementation
│   ├── mcp-core/           # MCP shared types/primitives
│   └── mcp-server/         # MCP server framework
├── temporal-service/       # Go-based scheduler service
├── ui/desktop/             # Electron + React desktop app
│   ├── package.json        # Dependencies & build scripts
│   ├── src/
│   │   ├── main.ts                 # Electron main process
│   │   ├── App.tsx                 # React root component
│   │   ├── goosed.ts               # Backend connection manager
│   │   ├── built-in-extensions.json # Built-in extension registry
│   │   ├── components/             # React UI components
│   │   │   ├── BaseChat.tsx        # Base chat container
│   │   │   ├── ChatInput.tsx       # User input component (59KB!)
│   │   │   ├── ChatSessionsContainer.tsx
│   │   │   ├── ElicitationRequest.tsx  # MCP elicitation UI
│   │   │   ├── ConfigContext.tsx
│   │   │   ├── ExtensionInstallModal.test.tsx
│   │   │   └── ErrorBoundary.tsx
│   │   ├── api/                    # Generated OpenAPI client
│   │   ├── assets/                 # Static assets (branding)
│   │   ├── contexts/               # React contexts
│   │   ├── constants/
│   │   └── utils/
│   │       ├── logger.ts
│   │       ├── autoUpdater.ts
│   │       ├── settings.ts
│   │       └── urlSecurity.ts
│   └── openapi.json        # Auto-generated, DO NOT EDIT
├── AGENTS.md               # AI-agent dev instructions
├── HOWTOAI.md              # AI-assisted dev guide
├── GOVERNANCE.md           # Project governance
├── LICENSE                 # Apache 2.0
└── Justfile                # Task runner recipes

Entry Points

Entry Point File Purpose
CLI crates/goose-cli/src/main.rs Terminal interface
Server crates/goose-server/src/main.rs Backend daemon (goosed)
Desktop UI ui/desktop/src/main.ts Electron main process
Agent Core crates/goose/src/agents/agent.rs Core agent logic

2. Core Architecture Deep Dive

Execution Flow

The core flow is: Message → Agent → Provider (LLM) → Tool execution → Response

The agent operates in an interactive loop:

  1. Human Request → User provides input via CLI or Desktop
  2. Provider Chat → Agent sends request + available tools list to LLM provider
  3. Model Extension Call → LLM returns tool call request (JSON); Goose executes it
  4. Response to Model → Tool results sent back to LLM; loop repeats if more tools needed
  5. Context Revision → Old/irrelevant info pruned (token management)
  6. Model Response → Final text response back to user

Session Management

  • Sessions are persisted as JSONL files with automatic backup and recovery
  • Session history includes conversation, tool execution results, and user preferences
  • Sessions survive restarts via the session/load mechanism
  • Config stored at ~/.config/goose/config.yaml (macOS/Linux) or %APPDATA%\Block\goose\config\config.yaml (Windows)

Provider Abstraction

Goose supports multiple LLM providers through a unified Provider trait:

  • Defined in crates/goose/src/providers/base.rs
  • Implementations handle auth, request formatting, response streaming
  • Multi-model config: supports lead/worker mode, planner model, and tool shim model
  • Key config variables: GOOSE_PROVIDER, GOOSE_MODEL, GOOSE_TEMPERATURE

Backend Server (goosed)

The backend goosed runs as a separate process, currently using a custom REST + SSE streaming API:

  • Current: Custom SSE-based streaming consumed by the Electron desktop app
  • Upcoming (ACP migration — Issue #6642): Replacing with Agent Communication Protocol (ACP) over HTTP
    • JSON-RPC 2.0 transport
    • POST /acp/session — Create session
    • POST /acp/session/{id}/message — Send JSON-RPC request
    • GET /acp/session/{id}/stream — SSE stream for all server→client messages
    • Supports permission flow: server sends request_permission, client responds with allow_once/deny

Error Handling

  • Errors are captured and sent back to the model as tool responses
  • Uses anyhow::Result throughout the Rust codebase
  • Invalid JSON, missing tools, etc. → LLM gets error context to self-correct

3. Desktop UI Architecture

Tech Stack

Layer Technology
Framework Electron (v40.1.0)
Frontend React 19 + TypeScript
Build Vite + electron-forge
Styling TailwindCSS 4 + Radix UI primitives
State SWR for data fetching, React contexts
Markdown react-markdown + remark-gfm + rehype-katex
Code Highlighting react-syntax-highlighter
Icons lucide-react + react-icons
API Client Auto-generated from OpenAPI spec (@hey-api/openapi-ts)
Testing Vitest + Playwright (E2E) + Testing Library
MCP UI @mcp-ui/client (v5.17.3)

Key UI Components

Component File Purpose
Base Chat BaseChat.tsx (17.7KB) Core chat container, message rendering
Chat Input ChatInput.tsx (59KB) User input with slash commands, file attachments
Chat Sessions ChatSessionsContainer.tsx Multi-session management
Elicitation ElicitationRequest.tsx MCP elicitation request UI
Extension Install ExtensionInstallModal.test.tsx Extension installation flow
Config ConfigContext.tsx App configuration context
Error Boundary ErrorBoundary.tsx Error handling wrapper
API Key Tester ApiKeyTester.tsx Provider key validation

Frontend-Backend Communication

  1. Electron main process (main.ts) spawns goosed backend
  2. React frontend communicates via generated OpenAPI client
  3. Real-time streaming via SSE connections
  4. IPC bridge for Electron-specific features (file dialogs, system tray, etc.)

Goose supports goose:// protocol URLs for:

  • goose://extension?cmd=... — Install extensions
  • goose://bot or goose://recipe — Launch recipes
  • goose://sessions — Open shared sessions

Branding Files

Key branding touchpoints for white-labeling:

  • ui/desktop/package.jsonproductName: "Goose", name: "goose-app"
  • ui/desktop/src/assets/ — Logo, icons, images
  • ui/desktop/src/main.ts — Window title, tray icon, protocol handler (goose://)
  • ui/desktop/src/built-in-extensions.json — Default extension list

4. MCP Integration System

Architecture

Goose acts as an MCP Host managing multiple MCP clients, each connected to a server (extension):

┌─────────────────────────────────────┐
│ Goose Host Process                  │
│ ┌────────────────────────────────┐  │
│ │ Goose Application (Host)       │  │
│ │                                │  │
│ │ ┌──────────┐  ┌──────────┐    │  │
│ │ │ Client 1 │  │ Client 2 │    │  │
│ │ └────┬─────┘  └────┬─────┘    │  │
│ └──────┼──────────────┼──────────┘  │
└────────┼──────────────┼─────────────┘
         │              │
         ▼              ▼
  ┌──────────┐   ┌──────────┐
  │ Server 1 │   │ Server 2 │
  │(Developer)│  │(Memory)  │
  └──────────┘   └──────────┘

How Goose Discovers & Connects to MCP Servers

  1. Built-in extensions are compiled into the goosed binary (defined in crates/goose-mcp/)
  2. Config-based extensions are defined in ~/.config/goose/config.yaml
  3. Deep links install via goose://extension?cmd=...
  4. Extension Manager (built-in platform extension) can dynamically discover, enable, and disable extensions during a session
  5. Smart Extension Recommendation analyzes user tasks and suggests relevant extensions automatically

Transport Mechanisms

Type Config Key Use Case
STDIO type: stdio Local extensions (process-based, stdin/stdout)
SSE type: sse Remote HTTP-based extensions
Streamable HTTP type: streamablehttp Modern remote transport

Extension Config Format (config.yaml)

extensions:
  github:
    name: GitHub
    cmd: npx
    args: [-y, @modelcontextprotocol/server-github]
    enabled: true
    envs: { "GITHUB_PERSONAL_ACCESS_TOKEN": "<YOUR_TOKEN>" }
    type: stdio
    timeout: 300

MCP UI Rendering (Issue #3562 — Active Development)

Goose is building support for rendering rich UI from MCP tool responses:

  • Inline display: Embedded in chat flow (data viz, previews)
  • Sidecar display: Side panel for rich interaction (app-like experiences)
  • Uses @mcp-ui/client library for deterministic rendering
  • Tool responses include _meta.goose.toolUI metadata specifying display type and renderer
  • Example MCP tool returning UI:
server.tool('render_ui_inline', 'Display UI', {}, async () => {
  return {
    _meta: {
      goose: {
        toolUI: {
          displayType: 'inline',
          name: 'inline example',
          renderer: 'mcp-ui',
        },
      },
    },
    content: [
      createUIResource({
        uri: 'ui://component-html',
        content: { type: 'rawHtml', htmlString: '<p>Hello World</p>' },
        encoding: 'text',
      }),
    ],
  };
});

5. Extension/Plugin System

Extension Trait (Rust)

#[async_trait]
pub trait Extension: Send + Sync {
    fn name(&self) -> &str;
    fn description(&self) -> &str;
    fn instructions(&self) -> &str;
    fn tools(&self) -> &[Tool];
    async fn status(&self) -> AnyhowResult<HashMap<String, Value>>;
    async fn call_tool(&self, tool_name: &str, parameters: HashMap<String, Value>) -> ToolResult<Value>;
}

Built-in Extensions

Defined in ui/desktop/src/built-in-extensions.json:

ID Name Default Enabled Description
developer Developer Shell, file editing, project tools
computercontroller Computer Controller Webscraping, file caching, automations
memory Memory Learn and recall user preferences
autovisualiser Auto Visualiser Auto-generate data visualizations
tutorial Tutorial Interactive learning guides

Platform Extensions (Always Available)

Extension Purpose
Chat Recall Search across all session history
Code Execution Execute JavaScript for tool discovery
Extension Manager Dynamic extension discovery/management (enabled by default)
Skills Load agent skills from project/global directories (enabled by default)
Todo Task tracking across sessions (enabled by default)

Building Custom Extensions

Extensions are MCP servers. The recommended pattern:

  1. Create an MCP server (Python with FastMCP, TypeScript with @modelcontextprotocol/sdk, or Rust)
  2. Define tools with @mcp.tool() decorator (Python) or equivalent
  3. Test with MCP Inspector (mcp dev server.py)
  4. Register in Goose via Desktop UI, CLI, config file, or deep link

Extension Allowlist (Enterprise)

For corporate environments, administrators can restrict which extensions can be installed:

# Deployed YAML file at GOOSE_ALLOWLIST URL
extensions:
  - id: slack
    command: uvx mcp_slack
  - id: github
    command: uvx mcp_github

Set via export GOOSE_ALLOWLIST=https://example.com/goose-allowlist.yaml


6. Permission & HITL System

Permission Modes

Mode Config Value Behavior
Autonomous auto Full autonomy, no approval needed (default)
Manual Approval approve Confirmation before any tool use
Smart Approval smart_approve Risk-based: auto-approve low-risk, flag high-risk
Chat Only chat No tool use, conversation only

Configuration: GOOSE_MODE: smart_approve in config.yaml

How Approval Works

In approve and smart_approve modes:

  1. Goose classifies tools as read or write (best-effort, LLM-interpreted)
  2. Write tools trigger "Allow" / "Deny" buttons in the UI
  3. The server sends a request_permission JSON-RPC request
  4. Client responds with { outcome: "allow_once" } or deny
  5. Only after approval does the tool execute

Additional Safety

  • .gooseignore file prevents access to sensitive files (.env*, *.key, target/, .git/)
  • .goosehints provides project-specific guidance to the agent
  • Prompt injection detection (SECURITY_PROMPT_ENABLED: true)
  • ML-based classifier endpoint for advanced threat detection
  • Malware scanning for external extensions before activation
  • Maximum turns limit (GOOSE_MAX_TURNS) prevents runaway loops

7. Forking Strategy

License: Apache 2.0

Permissive license — allows:

  • Commercial use
  • Modification and derivative works
  • Distribution under different terms
  • White-labeling and rebranding
  • No copyleft/share-alike requirements

Requirements: Must include original copyright notice and license text.

Note: As of Dec 2025, Goose was contributed to the Agentic AI Foundation (AAIF) under the Linux Foundation. The Apache 2.0 license remains; governance is now community-driven.

Key Files to Modify for White-Labeling

What to Change Files
App Name & Branding ui/desktop/package.json (productName, name, description)
Window Title ui/desktop/src/main.ts (BrowserWindow title)
Protocol Handler ui/desktop/src/main.ts (goose://yourapp://)
Logo & Icons ui/desktop/src/assets/
Built-in Extensions ui/desktop/src/built-in-extensions.json
Default Config crates/goose-server/ + crates/goose-cli/ default values
Config Directory Code references to ~/.config/goose/
System Prompts crates/goose/src/agents/ — agent instructions
Provider Defaults GOOSE_PROVIDER, GOOSE_MODEL defaults
Update Server ui/desktop/src/utils/autoUpdater.ts
Telemetry GOOSE_TELEMETRY_ENABLED and endpoints
Extension Directory URL in extension browsing/discovery code

Adding Custom MCP Servers as Built-in Extensions

Two approaches:

  1. Rust built-in (compiled into binary):

    • Add to crates/goose-mcp/src/
    • Register in the built-in server matching logic (crates/goose-cli/src/commands/mcp.rs)
    • Update ui/desktop/src/built-in-extensions.json
  2. Bundled external (shipped alongside but run as separate process):

    • Include the MCP server binary/package in the distribution
    • Pre-configure in default config.yaml
    • Set bundled: true in extension config

Build Process

# Setup
source bin/activate-hermit
cargo build

# Build release
cargo build --release
just release-binary

# Desktop app
just generate-openapi   # After server changes
just run-ui             # Development
cd ui/desktop && npm run bundle:default  # Production build

8. Community Extensions & Patterns

Extension Discovery

  • Official directory: https://block.github.io/goose/extensions/ (web-based catalog)
  • Community lists: appcypher/awesome-mcp-servers, punkpeye/awesome-mcp-servers
  • Registries: PulseMCP, Playbooks, MCP.so
  • Dynamic discovery: Extension Manager extension searches available servers at runtime

Common Extension Patterns

  1. STDIO MCP servers (most common): uvx, npx, jbang, docker launchers
  2. Python + FastMCP: Simplest pattern for custom tools
  3. TypeScript + @modelcontextprotocol/sdk: For Node.js ecosystem
  4. Rust: For performance-critical or compiled extensions

Notable Community Extensions

Extension Command Purpose
GitHub npx -y @modelcontextprotocol/server-github GitHub API integration
Slack uvx mcp_slack Slack workspace access
Postgres uvx mcp-server-postgres Database querying
Fetch uvx mcp-server-fetch HTTP request making
Filesystem uv run mcp-filesystem File system access
Playwright MCP server Browser automation
Tavily Search npx -y mcp-tavily-search Web search
Perplexity npx -y mcp-perplexity-search AI search

Recipes System

Goose supports recipes — shareable YAML files that package entire workflows:

  • Include goal, required extensions, setup steps, example activities
  • Configurable via GOOSE_RECIPE_GITHUB_REPO
  • Custom slash commands can trigger recipes
  • Deep linkable: goose://recipe?...

Subagents

Goose supports spawning subagents — isolated instances for parallel/long-running tasks:

  • Keep main conversation clean
  • Process isolation for experimental work
  • Parallel execution of independent tasks

9. Key Findings for Custom Agent Development

Why Fork Goose?

Advantage Detail
Mature MCP integration Best-in-class MCP host with dynamic discovery
Desktop + CLI Two interfaces already built
Apache 2.0 Full commercial freedom
Active development Frequent releases, large community
Multi-provider Works with any LLM (OpenAI, Anthropic, Google, local)
Permission system Built-in HITL with smart approval
Extension ecosystem Thousands of MCP servers available

Customization Effort Estimate

Change Effort Complexity
Rebrand (name, logo, colors) 1-2 days Low
Custom default extensions 1 day Low
Custom system prompts Hours Low
New built-in MCP extension (Rust) 3-5 days Medium
Custom UI components in chat 1-2 weeks Medium-High
Custom approval flow 1 week Medium
Replace backend protocol (ACP) Already in progress upstream High

Desktop App is More Extensible

The Electron desktop app provides:

  • Full React component library for custom UI
  • Deep link protocol for integrations
  • Extension install modal workflow
  • MCP UI rendering (inline + sidecar) — under active development
  • System tray, keyboard shortcuts, auto-updates
  • Multi-window/multi-session support

The CLI is simpler but less extensible for custom UI experiences.

Risks & Considerations

  1. Active ACP migration (Issue #6642): The backend communication protocol is being replaced. Fork timing matters.
  2. Governance shift: Now under AAIF/Linux Foundation — community governance may affect upstream direction
  3. Rapid iteration: Multiple releases per week; staying in sync with upstream requires effort
  4. Electron size: Desktop app ships Chromium (~200MB+)
  5. Rust build times: Full build can be slow; incremental builds are faster

10. Sources

Source URL
GitHub Repository https://github.com/block/goose
Official Documentation https://block.github.io/goose/
AGENTS.md (repo structure) https://raw.githubusercontent.com/block/goose/main/AGENTS.md
HOWTOAI.md (architecture) https://raw.githubusercontent.com/block/goose/main/HOWTOAI.md
GOVERNANCE.md https://raw.githubusercontent.com/block/goose/main/GOVERNANCE.md
Architecture Overview https://block.github.io/goose/docs/goose-architecture/
Extensions Design https://block.github.io/goose/docs/goose-architecture/extensions-design/
Config Files Guide https://block.github.io/goose/docs/guides/config-files/
Permission Modes https://block.github.io/goose/docs/guides/goose-permissions/
Using Extensions https://block.github.io/goose/docs/getting-started/using-extensions/
Extension Allowlist https://block.github.io/goose/docs/guides/allowlist/
MCP UI Issue #3562 https://github.com/block/goose/issues/3562
ACP Migration Issue #6642 https://github.com/block/goose/issues/6642
Block Announcement https://block.xyz/inside/block-open-source-introduces-codename-goose
AAIF Launch https://www.linuxfoundation.org/press/linux-foundation-announces-the-formation-of-the-agentic-ai-foundation
Extension Deep Dive (dev.to) https://dev.to/lymah/deep-dive-into-gooses-extension-system-and-model-context-protocol-mcp-3ehl
Dynamic MCP Discovery https://dev.to/amandamartindev/dynamic-mcp-server-discovery-with-goose-3m41
What is Block Goose https://jeffbailey.us/blog/2025/07/29/what-is-block-goose/
Docker + Goose https://www.docker.com/blog/building-ai-agents-with-goose-and-docker/
Extensions Directory https://block.github.io/goose/extensions/
Desktop package.json https://raw.githubusercontent.com/block/goose/main/ui/desktop/package.json
Built-in Extensions JSON https://raw.githubusercontent.com/block/goose/main/ui/desktop/src/built-in-extensions.json
DeepWiki Overview https://deepwiki.com/block/goose