Chapter 1: Getting Started

April 13, 2026 · View on GitHub

Welcome to Chapter 1: Getting Started. In this part of Goose Tutorial: Extensible Open-Source AI Agent for Real Engineering Work, you will build an intuitive mental model first, then move into concrete implementation details and practical production tradeoffs.

This chapter establishes a clean Goose baseline so you can move into advanced workflows without setup drift.

Learning Goals

  • install Goose Desktop or CLI on your platform
  • configure your first LLM provider
  • run your first session in a target repository
  • identify common startup failures and quick fixes

Installation Paths

PathCommand / FlowBest For
Desktop appDownload from Goose releases and launchVisual workflows and session management in UI
CLI install scriptcurl -fsSL https://github.com/block/goose/releases/download/stable/download_cli.sh | bashFast terminal bootstrap
Homebrew CLIbrew install block-goose-climacOS/Linux environments using package managers

First Configuration Checklist

  1. run goose configure
  2. select a provider and authenticate
  3. choose a model suitable for tool calling
  4. start a session from your working directory
  5. run a low-risk task (for example, repo summary + TODO extraction)

First Session Flow

cd /path/to/repo
goose session

Inside the session, start with a scoped prompt such as:

  • "Summarize this repo structure and propose a 3-step refactor plan."

Platform-Specific Installation Notes

macOS

Both Homebrew and the install script work. Homebrew is preferred if you manage other CLI tools through it — updates come via brew upgrade block-goose-cli. The install script places the binary in ~/.local/bin; ensure this is on your PATH.

Linux

Use the install script. After running it, verify the install with:

goose --version
goose info

goose info prints the config file path, log directory, and current version — useful for confirming the binary and config are where Goose expects them.

Windows

Use the desktop installer from the GitHub releases page. The CLI is available but the desktop app provides a more stable setup flow on Windows. WSL2 is a supported path for CLI-only usage.

Desktop vs CLI Tradeoffs

FactorDesktop AppCLI
first-time setupguided UI with provider wizardgoose configure interactive prompts
session visibilityvisual conversation paneterminal output with streaming
extension managementtoggle UI per extensiongoose configure or --with-builtin flag
scripting / CInot suitablegoose run with headless flags
context usage displaytoken meter in sidebarprinted before each prompt

Most developers use the CLI for scripted tasks and the desktop app for exploratory sessions. Both share the same ~/.config/goose/config.yaml configuration file.

What goose info Shows

After setup, running goose info outputs your runtime baseline:

version:       v1.28.0
config file:   ~/.config/goose/config.yaml
log dir:       ~/.config/goose/logs/
sessions dir:  ~/.config/goose/sessions/
provider:      anthropic
model:         claude-sonnet-4-5

This is the first command to run when diagnosing unexpected behavior.

Early Failure Triage

SymptomLikely CauseFirst Fix
no model responseprovider not configured correctlyrerun goose configure and re-authenticate
tool calls fail unexpectedlypermission mode mismatchswitch mode or adjust per-tool permissions
noisy or irrelevant contextwrong working directoryrestart session from repo root
command not found: goosebinary not on PATHcheck ~/.local/bin is in PATH
auth errors with AnthropicAPI key expired or incorrectregenerate key at console.anthropic.com

Source References

Updating Goose

Keep your installation current to get bug fixes and new provider support:

# Upgrade to latest stable release
goose update --channel stable

# Check what version you have
goose info

For Homebrew installations, use brew upgrade block-goose-cli instead. The install-script path and Homebrew path are independent; do not mix them on the same machine.

Custom Distros

If your organization wants to ship a pre-configured Goose with specific providers, extensions, and branding, the CUSTOM_DISTROS.md file at the repo root documents the distro build process. This is relevant for platform teams that want to standardize Goose across a large engineering org without requiring each developer to run goose configure from scratch.

Summary

You now have Goose installed, configured, and running in a real project context.

Next: Chapter 2: Architecture and Agent Loop

Source Code Walkthrough

crates/goose-cli/src/cli.rs — CLI entry point and command structure

The top-level Cli struct in crates/goose-cli/src/cli.rs defines the complete command surface you interact with during setup and every session:

#[derive(Parser)]
#[command(name = "goose", author, version, display_name = "", about, long_about = None)]
pub struct Cli {
    #[command(subcommand)]
    command: Option<Command>,
}

Key argument groups surfaced by this file include:

  • Identifier — selects a session by --name (-n), --session-id, or legacy --path
  • SessionOptions — controls --debug, --max-tool-repetitions, --max-turns (default 1000), and --container
  • InputOptions — accepts --instructions (-i) (file path or stdin), --text (-t), --recipe, --system, and --params
  • ExtensionOptions — adds extensions via --with-extension, --with-builtin, or disables defaults with --no-profile

This is the interface boundary you see when running goose --help or goose session --help.

crates/goose-cli/src/commands/configure.rs — interactive provider setup

The configure_provider_dialog() function in crates/goose-cli/src/commands/configure.rs runs when you execute goose configure:

pub async fn configure_provider_dialog() -> anyhow::Result<bool> {
    let config = Config::global();
    let mut available_providers = providers().await;
    available_providers.sort_by(|a, b| a.0.display_name.cmp(&b.0.display_name));

    let provider_items: Vec<(&String, &str, &str)> = available_providers
        .iter()
        .map(|(p, _)| (&p.name, p.display_name.as_str(), p.description.as_str()))
        .collect();

    let current_provider: Option<String> = config.get_goose_provider().ok();
    let default_provider = current_provider.unwrap_or_default();

    let provider_name = cliclack::select("Which model provider should we use?")
        .initial_value(&default_provider)
        .items(&provider_items)
        .filter_mode()
        .interact()?;

    // ... iterate config_keys, collect credentials, test provider
    Ok(true)
}

The function reads ProviderMetadata for each registered provider, prompts for required ConfigKey credentials via secure input, and validates the connection before writing to Config::global(). This is the first thing you run after installing Goose.

How These Components Connect

flowchart TD
    A["goose CLI binary\n(crates/goose-cli/src/main.rs)"]
    B["Cli struct + subcommands\n(src/cli.rs)"]
    C["configure subcommand\n(src/commands/configure.rs)"]
    D["Config::global() singleton\n(providers, model, extensions)"]
    A --> B
    B --> C
    C --> D