# 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](#1-repository-structure) 2. [Core Architecture Deep Dive](#2-core-architecture-deep-dive) 3. [Desktop UI Architecture](#3-desktop-ui-architecture) 4. [MCP Integration System](#4-mcp-integration-system) 5. [Extension/Plugin System](#5-extensionplugin-system) 6. [Permission & HITL System](#6-permission--hitl-system) 7. [Forking Strategy](#7-forking-strategy) 8. [Community Extensions & Patterns](#8-community-extensions--patterns) 9. [Key Findings for Custom Agent Development](#9-key-findings-for-custom-agent-development) 10. [Sources](#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.) ### Deep Link Protocol 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.json` — `productName: "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) ```yaml extensions: github: name: GitHub cmd: npx args: [-y, @modelcontextprotocol/server-github] enabled: true envs: { "GITHUB_PERSONAL_ACCESS_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: ```typescript 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: '

Hello World

' }, encoding: 'text', }), ], }; }); ``` --- ## 5. Extension/Plugin System ### Extension Trait (Rust) ```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>; async fn call_tool(&self, tool_name: &str, parameters: HashMap) -> ToolResult; } ``` ### 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: ```yaml # 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 ```bash # 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 |