# Roast: a Ruby DSL for assembling AI workflows out of reusable cogs

> Shopify's open source tool turns a Ruby file into an ordered workflow of chat, agent and shell steps, published as the roast-ai gem with a Sorbet-typed core.

**Shopify/roast** — Structured AI workflows made easy

- Repository: https://github.com/Shopify/roast
- Stars: 1,250 · Forks: 78
- Language: Ruby
- License: MIT
- Published: 2026-10-07 · Updated: 2026-10-07 · Language: en
- Canonical page: https://hysenlabs.com/projects/shopify-roast

## A workflow is a Ruby file, and cogs are the building blocks

Roast is described as a Ruby-based domain-specific language for structured AI workflows, and it is installed like any other gem:

```bash
gem install roast-ai
```

The unit of work is a cog, and there are seven of them in the README's list. `chat` sends a prompt to a cloud LLM. `agent` runs a local coding agent with filesystem access. `ruby` executes your own Ruby inside the workflow. `cmd` runs a shell command and captures its output. `map` applies an operation across a collection, serially or in parallel. `repeat` iterates until a condition is met. `call` invokes a reusable scope.

The quick example in the README composes three of them. It runs a shell command to collect changed files, passes them to an agent for review, then asks a chat model to summarize that review for a non-technical audience:

```ruby
cmd(:recent_changes) { "git diff --name-only HEAD~5..HEAD" }
```

The pattern that matters is the bang variant. `cmd!` and `agent!` raise on failure, where the non-bang versions return a value you are expected to check. That is the difference between a workflow that stops at the first bad step and one that limps onward, and version 1.2.0 made `abort_on_failure` the default, which pushes every new workflow toward stopping.

You run a workflow by pointing the executable at the file:

```bash
bin/roast execute analyze_codebase.rb
```

## Chat providers and agent providers are configured separately

The two kinds of model call read their configuration from different places, and the README is precise about it. The `chat` cog supports OpenAI, Anthropic, Perplexity and Gemini, defaults to `:openai`, and reads keys from a provider-specific environment variable. OpenAI, Anthropic and Gemini each also take a base URL override; Perplexity does not.

The `agent` cog is a different mechanism entirely. It runs local agent CLIs rather than calling an HTTP API, defaults to `:pi`, and currently supports `:claude` for the Claude Code CLI and `:pi` for the Pi CLI. Those providers handle their own authentication, so there is no API key to set for them in Roast itself.

Both defaults can be overridden globally by environment variable, and both lose to an explicit setting in a workflow's own `config` block. The README also states that an invalid value raises an error rather than falling back, which is a deliberate choice worth noting in a tool where a typo in an environment variable could otherwise silently send your prompts to the wrong provider:

```ruby
config do
  chat do
    provider :anthropic
    model "claude-haiku-4-5"
  end
end
```

One limitation shows up in the same section: the default model is set per provider and can only be overridden inside a `config` block, not through the environment. Version 1.2.0 fixed `use_default_model!` to fall back to the provider default, which suggests that path had been behaving differently before.

## Requirements are short, and the agent CLI is the one that bites

The README lists three requirements: Ruby 3.0 or later, API keys or local credentials for your AI provider, and the Pi CLI installed for the default agent provider. That is a light footprint, with one condition worth expanding.

The agent cog delegates authentication to the CLI it drives. Agent providers must be installed and authenticated according to their own CLI requirements, which means Roast can be installed and working while the agent path is still broken if you are on a machine where the Pi CLI was never set up. If you only need `chat`, that does not matter. If your workflow uses `agent`, the dependency is the CLI, not the gem.

The rest of the toolchain is more serious than the README's front page suggests. The tree contains `sorbet/`, `.rubocop.yml`, `.rubocop_todo.yml`, `Rakefile` and a `shipit.rubygems.yml` for releases, which describes a gem maintained with static type signatures, two layers of RuboCop configuration including a todo file, and Shopify's own deployment tooling. `Gemfile.lock` is committed. `dev.yml` suggests the dev environment is declared as data rather than as a Dockerfile.

There is also an `internal/` directory and an `examples/` directory. The README is explicit that the examples are not decoration: they are toy workflows demonstrating all functional patterns and they double as Roast's end-to-end test suite. That is a good sign for a DSL, because a feature you can read as a complete file is a feature you can trust to behave as advertised.

## Two releases in a row, both adding providers

Roast has three releases on record: `v1.0.2` on 2026-03-02, `1.1.0` on 2026-04-02 and `1.2.0` on 2026-06-26. The last push recorded for the repository is 2026-08-10, so the code is ahead of the newest gem.

`1.1.0` is where the agent cog stopped being a toy. It added the Pi coding agent as an agent cog provider, added multiple prompt support to the agent cog, summed usage across multiple invocations within a single agent cog, moved agent prompt and response printing into the provider, and stopped forking a session on subsequent invocations in the same cog. Those five changes together describe the difference between calling a CLI once and treating it as a stateful participant in a longer flow.

`1.2.0` consolidated providers and ergonomics. It added Anthropic as a supported chat provider, added `templates` as a template search path, supported tilde expansion in template paths, fixed `use_default_model!` to fall back to the provider default, made `abort_on_failure` the default, and improved output display.

`v1.0.2` is the one that reads like a support ticket. It fixed missing paths in log output, dropped an unparsed Claude message warning to DEBUG level because the messages were not actually worth worrying about, and added debug logging for Claude session IDs when they first appear, which makes it possible to resume a Claude session that was in progress when a workflow was aborted. If you hit an aborted agent run and need to pick the thread back up, that release note is the relevant one.

Each release is a flat list of pull requests with authors, which is what you would expect from a project using GitHub's own release notes rather than a curated changelog.

## Documentation is a tutorial that doubles as the manual

Roast's documentation strategy is unusual enough to copy. Instead of a reference manual, the README points at an interactive tutorial in the `tutorial/` directory and lists what it covers: your first workflow, chaining cogs, accepting targets and parameters, configuration, control flow, reusable scopes, processing collections, iterative workflows, and async execution. Nine topics, in the order you would meet them.

Behind that, the README tells you where the real interface documentation lives: in class and method comments on the relevant classes, with a source root at `lib/roast`. It then links specific files for each concern rather than describing them in prose. Configuration is split across `sorbet/rbi/shims/lib/roast/config_context.rbi` for the general block, `sorbet/rbi/shims/lib/roast/cog/config.rbi` for workflow parameters, and then one file per cog under `lib/roast/cogs/`, including `agent/config.rb`, `chat/config.rb`, `cmd/config.rb` and `system_cogs/map.rb`.

That split between generated signatures and hand-written config classes is what a Sorbet project looks like in practice, and it is why `sorbet/` appears in the tree alongside `lib/`. Version 1.1.0 upgraded Sorbet and Tapioca, so the signature files are maintained rather than hand-written once.

The trade-off is that you will be reading Ruby source to answer a question. For a tool whose audience is developers writing Ruby anyway, that is often the faster path. For a reader who wants to know what Roast does before installing it, the README and the tutorial cover it, and nothing between those two points exists.

## Conclusion

Roast's real contribution is making an AI workflow read like a Ruby script rather than a pile of API calls, and it backs that up with a type-checked core, an interactive tutorial that doubles as documentation, and an examples directory that serves as the end-to-end test suite. What it does not offer is retry logic, a scheduler or a persistence layer, so a workflow that needs to survive a process restart is something you build yourself. Two details decide whether it fits. First, the agent cog defaults to the Pi CLI, so a machine without it installed has to install and authenticate it separately, and the chat cog expects provider keys in the environment. Second, the README states the default model can only be changed inside a `config` block, which is a smaller surface than most people expect. Install the gem, work through `tutorial/`, then read `lib/roast/system_cogs/map.rb` to see how parallel execution is scheduled before you commit to it.

## FAQ

### What is Roast used for?

Roast orchestrates AI workflows written in Ruby by composing cogs. A workflow is a Ruby file that chains `chat` calls to cloud models, `agent` calls to local coding CLIs, `cmd` shell commands, `ruby` blocks, and `map` and `repeat` for collections and iteration, then runs through `bin/roast execute`.

### Which AI providers does Roast support?

The `chat` cog supports OpenAI, Anthropic, Perplexity and Gemini, reading keys from `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `PERPLEXITY_API_KEY` and `GEMINI_API_KEY`, and defaults to `:openai`. The `agent` cog is separate and runs the Claude Code CLI or the Pi CLI locally, defaulting to `:pi`, with authentication handled by those CLIs themselves.

### What does Roast require to run?

The README lists Ruby 3.0 or later, API keys or local credentials for your provider, and the Pi CLI installed for the default agent provider. Roast is installed as a gem with `gem install roast-ai`, or added to a Gemfile as `roast-ai`.

## Sources

- [Issues](https://github.com/Shopify/roast/issues)
- [License: MIT](https://github.com/Shopify/roast/blob/main/LICENSE)
- [README](https://github.com/Shopify/roast/blob/main/README.md)
- [Releases](https://github.com/Shopify/roast/releases)
- [Shopify/roast on GitHub](https://github.com/Shopify/roast)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/shopify-roast
