Block built Goose β an open-source CLI agent β and pushed it across its own engineering org. The pattern that scaled wasn't the model or the prompt, it was a small YAML file that any engineer can author. Here's the architecture, the recipe format, and a copy-paste walkthrough you can run on your own machine in ten minutes.
Block β the company behind Square, Cash App, and Afterpay β released Goose in early 2025 as an open-source AI agent. A year later it has 44k+ stars on GitHub, 368+ contributors, and 2,600+ forks. The project recently moved from block/goose to the Agentic AI Foundation under the Linux Foundation, which means it's no longer governed by a single company.
The adoption story inside Block is the part most coverage glosses over. Public reporting puts it at roughly 60% of the company's ~12,000 employees using Goose weekly, with around 4,000 of 10,000 employees in active use across 15 different job profiles β engineering, sales, design, product, customer success. That breadth is the thing. The same tool is being used by an engineer fixing a flaky test and by a product manager pulling a Jira ticket.
What lets one tool serve both is the recipe.
What Goose Actually Is
Goose is a local agent. It's a Rust binary that runs on your machine, talks to an LLM provider of your choice, and uses MCP servers as its tools. The interface is a CLI (goose) and a desktop app. The architecture has three pieces:
β’ A core agent loop β plan, call tools, evaluate, repeat until done.
β’ A provider abstraction β point it at Anthropic, OpenAI, Gemini, Mistral, xAI, or a local model running under Ollama, Docker Model Runner, or Ramalama. 25+ providers are supported.
β’ An extension system built on MCP β every tool the agent uses is an MCP server.
That last point matters more than it looks. Because tools are MCP servers, an extension is a configuration entry, not a code change. Adding GitHub access is a line in a config file. Adding a private internal API is a line in a config file. The agent itself stays the same.
!Goose architecture overview
The piece that turns this from "yet another agent CLI" into something a 12,000-person company can adopt is the recipe.
The Recipe Is a YAML File
A recipe is a YAML document that bundles instructions, required extensions, parameters, and the actual prompt into a single shareable file. Anyone can write one. Anyone can run one. The command is one line:
``bash
goose recipe run review-pr
`
The recipe behind that command might be 30 lines of YAML. It defines what tools the agent gets, what input it needs, and what it's supposed to do step by step. The agent doesn't decide which tools to load β the recipe does. The agent doesn't free-form its way through the task β the recipe gives it a sequence with checkpoints.
A real one looks like this:
`yaml
name: review-pr recipe:
version: 1.0.0 title: Review a Pull Request
description: |
Pull a GitHub PR, read the diff, surface risk areas,
and post a structured review comment.
settings:
goose_provider: anthropic
goose_model: claude-sonnet-4-20250514 parameters:
β’ key: pr_url
input_type: string
requirement: required
description: The GitHub PR URL to review.
instructions: |
You are reviewing {{ pr_url }}. Track progress in ./scratchpad.txt using checkboxes.
Stop and surface anything you are unsure about β do not guess.
prompt: |
Fetch the PR diff and the list of changed files.
For each file, identify: behavior changes, new dependencies, missing tests, anything that looks rushed.
Group findings by severity: must-fix, should-fix, nit. Post a single review comment with the grouped findings.
Mark the scratchpad complete.
extensions:
β’ type: builtin
name: developer
timeout: 300 bundled: true
β’ type: stdio
name: github
cmd: npx
args: ["-y", "@modelcontextprotocol/server-github"]
env_keys: ["GITHUB_TOKEN"]
`
A few things to notice about the shape of this file.
The parameters block makes the recipe a function. pr_url is required and becomes {{ pr_url }} in the instructions. You don't write a new recipe per PR β you write one recipe and call it with different inputs.
The extensions block is the MCP surface. Two extensions here: developer (built-in, gives shell + file access) and github (a stdio MCP server that the recipe pulls in by name). Goose installs nothing globally to make this work. The extension is loaded for this recipe and discarded when the run ends.
The prompt is numbered. Goose treats numbered steps as a planning skeleton. The agent doesn't have to reinvent the workflow on every run because the recipe encodes it.
Why Block Chose This Shape
This is the part that explains the adoption number. A YAML file is a thing a product manager can author. They can copy a recipe a teammate wrote, change the prompt, run it, see what happened. That feedback loop doesn't require a deploy or a code review. It's editing a text file and re-running a command.
For engineers the trade is different. A recipe is a thing you can put in a Git repo next to the code it operates on. Your team's review workflow lives at recipes/review-pr.yaml in the same repo as the service. A new hire reads the recipe to understand the workflow. The recipe gets reviewed like any other artifact. The thing both groups get is a shared mental model. The agent isn't a black box you talk to. It's a script you run, written in a language anyone can read.
!Recipe runs are reproducible workflows, not chat sessions
The MCP Layer Is the Quiet Win
The extension system is where Goose's design pays off. MCP is the protocol Anthropic published in late 2024 for standardizing how agents talk to tools. By building every extension as an MCP server, Goose inherits the rest of the ecosystem for free. Any MCP server someone else writes β for Jira, Linear, Stripe, Postgres, internal company APIs β drops into a recipe with three lines:
`yaml
extensions:
β’ type: stdio
name: jira
cmd: uvx
args: ["mcp-jira-server"]
env_keys: ["JIRA_TOKEN", "JIRA_URL"]
`
That's all it takes to give the agent Jira access for the duration of one recipe. No SDK install, no client wrapper, no bespoke integration code. The agent gets a set of tools (jira_get_ticket, jira_search, etc.) the moment the recipe loads.
The reason this matters for adoption: each new internal capability is a one-time MCP server build, then it's available to every recipe and every team. Block doesn't write a separate "PR review agent" and "ticket triage agent." They write one Goose binary, then ship a directory of recipes and a directory of MCP servers. Composition does the rest.
Try It Yourself Goose is open source under Apache 2.0. The whole stack runs locally β you provide the LLM credentials, Goose runs on your machine. Here is the minimum to go from nothing to a working recipe in about ten minutes.
Install
Install on macOS, Linux, or WSL with the official one-liner:
`bash
curl -fsSL https://github.com/block/goose/releases/download/stable/download_cli.sh | bash
`
On macOS via Homebrew:
`bash
brew install goose
`
Verify the install:
`bash
goose --version `
Configure
Run the interactive setup once:
`bash
goose configure
`
This walks through three things: choosing an LLM provider, entering your API key, and selecting a default model. Pick Anthropic and claude-sonnet-4-5 if you want the same setup most internal Goose users at Block run on. The config file lands at ~/.config/goose/config.yaml:
`yaml
GOOSE_PROVIDER: anthropic
GOOSE_MODEL: claude-sonnet-4-5
ANTHROPIC_API_KEY: sk-ant-...
`
You can edit this file directly later β for example, to switch providers per project by exporting GOOSE_PROVIDER in a shell session.
Add an MCP Extension
Extensions are managed by name. To add the GitHub MCP server so any recipe can use it:
`bash
goose session --with-extension "npx -y @modelcontextprotocol/server-github" `
Or wire it persistently in your config:
`yaml
extensions:
github:
type: stdio
cmd: npx
args: ["-y", "@modelcontextprotocol/server-github"] enabled: true
env_keys: ["GITHUB_TOKEN"] `
Set the token:
`bash
export GITHUB_TOKEN=ghp_... `
Write a Recipe
Create recipes/morning-standup.yaml in any project directory:
`yaml
name: morning-standup recipe:
version: 1.0.0 title: Morning Standup Summary
description: Summarize what changed in this repo since yesterday.
settings:
goose_provider: anthropic
goose_model: claude-sonnet-4-5 parameters:
β’ key: repo_path
input_type: string
requirement: required
description: Local path to the repo to summarize.
prompt: |
cd into {{ repo_path }}.
Run git log --since=yesterday --oneline and read the commits.
For each commit, read the diff and write one plain-English line
describing what changed and why it matters.
Output the result as a markdown bullet list grouped by author.
Do not invent commits that aren't there.
extensions:
β’ type: builtin
name: developer
bundled: true
`
Run It
`bash
goose recipe run morning-standup --params repo_path=$PWD `
Goose loads the recipe, attaches the developer extension, hands the prompt to Claude, and Claude drives the agent loop β running git log, reading diffs, writing the summary. Output streams to your terminal. The agent stops when the prompt is satisfied or when it hits a step it can't complete.
If you want to share the recipe with the team, commit recipes/morning-standup.yaml` to the repo. Anyone with Goose installed can now run the same workflow with one command. !Recipes are committable artifacts that travel with the code
What This Pattern Tells You
The pattern Block is shipping internally is small enough to copy. Three pieces:
β’ A local agent binary that takes recipes as input.
β’ A recipe format that any non-engineer can read and most can author.
β’ An MCP extension layer so adding capabilities is a config line, not a code change.
If you're building an internal agent platform and you don't have an analog for the recipe, you're going to end up with bespoke agent builds per team. The recipe is what lets one tool serve a 12,000-person company without forking. You also don't need to use Goose to copy the pattern. The same shape works on top of Claude Code skills, Cursor agents, or anything else that supports YAML-defined workflows and MCP tools. The interesting move was the architectural one: separate the agent (the runtime) from the workflow (the recipe) from the capability (the MCP server). Each layer evolves on its own. Adoption climbs because changes to one layer don't break the others.
The thing Block got right is making the abstraction boring. A YAML file with a name, a prompt, and an extension list. That's it. Boring is how you reach 60% of the company.
Where the Project Is Going
Since the move to the Agentic AI Foundation, the roadmap is community-driven. Recent activity on GitHub points toward better recipe discovery (a public registry of community recipes), tighter MCP server interop with the wider ecosystem, and richer parameter types β including file uploads and structured objects, not just strings.
The fact that this is now a foundation project, not a Block project, changes the calculus for adopting it. The governance risk a year ago was "what if Block stops investing." That risk is gone. The tool now belongs to the ecosystem it runs on.
Goose is worth a look for any team that's been pasting agent prompts into a wiki and calling it a workflow. A YAML file in a repo is the better unit. The fact that one specific company shipped this pattern to its own workforce β and the workforce kept using it β is the strongest signal in the space right now.