# How stacks works

> How stacks, fragments, apps, presets and agent adapters fit together when stacks composes a project, with examples from the default registry.

stacks hands a coding agent a recipe for a project and a fixed definition of done. This page covers what a recipe is made of (stacks, fragments and apps) and how the CLI composes them into a brief and a set of verify steps.

## What the CLI does and what the agent does

A stack holds the parts of starting a project that stay true for years: how to lay the project out, what to test, what "done" means. The agent supplies the parts that go stale in months, such as package versions, generator flags and config file formats, by reading current docs and running current generators each time it builds a project. A build goes like this:

1. You pick a stack, and optionally add or remove fragments.
2. `stacks new` composes them and writes two files: `.stacks/BRIEF.md`, the agent's task, and `.stacks/manifest.json`, the verify steps.
3. The agent reads the brief and builds the project with current versions.
4. The agent runs `stacks verify`, fixes what fails, and runs it again.
5. The project is done when verify reports `green`.

The CLI installs nothing and runs no generator. It copies a few starter files, writes the brief and the manifest, and later runs the manifest's steps.

## Stacks

A stack is a recipe for one kind of project. `go-cli` is a Go command-line tool with cobra and viper. `astro-blog` is a static Astro blog. `python-react` is a FastAPI backend with a React frontend.

A stack names its packages by role and never pins a version. `go-cli` says "cobra and viper for the CLI, testify for tests", and the agent installs whatever is current. It describes the layout and the rules the project must keep, leaves config files for the agent to generate with current tools, and ends with the commands that must pass.

```sh title="Terminal" group="list"
stacks list stacks
```

```text title="Output" group="list"
Stacks
  astro-blog               historical pass 2026-10-27
    A static Astro blog with MDX posts in a zod-validated content collection (draft/published/unlisted status), React islands, Tailwind with typography, sitemap and RSS, optional generated OG images, and vitest plus astro check.
  astro-fullstack          unproven
    A Bun workspace with a static Astro site (React islands, Tailwind), a Node API on Effect's HttpApi and a shared contract package, so islands call the API through a typed client. The API can also serve the built site.
  ...
  go-cli                   historical pass 2026-10-27
    A Go command-line tool with cobra commands, viper config (file, env, flags), structured errors with actionable suggestions, human and JSON output, testify tests with race detection and a coverage floor, and golangci-lint.
  ...

Next: stacks new astro-blog my-project --sandbox
Next: stacks list --json
```

`historical pass <date>` means a full composition of that stack once reached green on that date. `unproven` means no recorded run yet. Neither is a promise about the next build. `stacks show <id>` prints one stack in full: its decisions, commands, verify steps and the files it ships. The [directory](https://stacks.steamfield.io/stacks/) lists the same entries on the web.

## Fragments

A fragment is one capability that several stacks can share: GitHub Actions CI, lefthook git hooks, a Postgres database, Cloudflare deployment. The CI instructions live in one fragment, so stacks that want CI don't each carry a copy that drifts from the others.

Each fragment has a category:

| Category | Adds | Example |
| --- | --- | --- |
| `agent-ops` | Agent configuration and guardrails | `agent-ops`, `claude-harness` |
| `ci` | Continuous integration | `ci-github` |
| `deploy` | Deployment | `cloudflare-pages`, `docker-deploy` |
| `release` | Building and publishing releases | `bun-release`, `goreleaser` |
| `service` | A backing service | `postgres`, `cloudflare-d1` |
| `vendor` | A third-party service | `clerk`, `posthog` |
| `tooling` | Developer tooling | `git-hooks`, `effect` |
| `app` | A whole application on top of a stack | `openrouter-chat` |

`stacks list fragments` lists them, and the [fragments directory](https://stacks.steamfield.io/fragments/) shows them on the web.

## Apps

An app is a fragment with `category: app` that adds a working product to a stack, where the other categories add infrastructure. `openrouter-chat` turns a bare `react-router` project into a streaming chat app.

Apps get a larger brief budget (9,000 words instead of 6,000), and their verify steps run as a second stage after the base project passes. A failed base skips every app step, so the agent gets the base project passing before it works on the app. `stacks list apps` lists them.

## How fragments are picked for a project

Composition picks the fragments for a project and merges them with the stack. A stack lists its fragments in three groups, `required`, `default` and `optional`. Here is `typescript-cli`:

```yaml title="stacks/typescript-cli/STACK.md"
fragments:
  required: [claude-harness]
  default: [git-hooks, ci-github, effect]
  optional: [rr, ce-plugin, bun-release, openrouter-chat-cli]
```

| Group | Included when |
| --- | --- |
| `required` | Always. The stack depends on it, so `--without` can't remove it |
| `default` | Unless you name it with `--without` |
| `optional` | Only when you name it with `--with` |

```sh title="Terminal"
stacks new typescript-cli my-cli --without ci-github --with bun-release
```

That project gets `claude-harness`, `git-hooks`, `effect` and `bun-release`, and leaves out CI. Fragments you list under `always` in your [configuration](https://stacks.steamfield.io/docs/reference/configuration.md) also join every composition they fit.

A fragment can also declare how it relates to other fragments:

- `requires` pulls in another fragment automatically. `claude-harness` requires `agent-ops`, and `effect` requires `effect-schema`, so a default `typescript-cli` project gets six fragments although the stack names four.
- `conflicts` names fragments it can't coexist with. Asking for both is a `ComposeConflict` error (exit 2).
- `applies_to` lists the stacks or tags it works with. `postgres` says `applies_to: [python-react, python-api]`, so it isn't offered for an Astro blog.

Composition is deterministic: the same stack, fragments, preset and agents always produce the same brief and the same verify steps. `stacks validate` composes every stack with every fragment that fits it, which catches combinations that don't work before anyone builds one.

## Presets

A preset sets whether the agent asks about decisions, which deploy, release and app fragments are included, and whether `prod` steps run. There are two:

| Preset | Decisions | Deploy, release and app fragments | Steps tagged `prod` |
| --- | --- | --- | --- |
| `default` | The agent asks you about each one | Included when the stack defaults to them | Run |
| `sandbox` (`--sandbox`) | The agent takes every default without asking | Left out unless you name them with `--with` | Skipped, unless you run `stacks verify --all` |

Use `--sandbox` to see a stack working locally. Use the default preset for a project you'll deploy. `--yes` takes every decision's default without switching to sandbox, and `--sandbox` implies `--yes`.

## Adapters and target agents

Each entry can ship files for specific coding agents under `adapters/<agent>/`: Claude Code settings, Codex config, and so on. `--agents` picks which agents get their files (default `claude`), and every target gets `AGENTS.md`.

| Agent | `--agents` value | Status |
| --- | --- | --- |
| Claude Code | `claude` | Proven |
| Codex | `codex` | Proven |
| OpenCode | `opencode` | Unproved |
| Cursor | `cursor` | Unproved |

Proven means projects have been built to green with that agent. The OpenCode and Cursor adapters ship, but no project has been proven with them yet, so expect rough edges.

## Entry files and origins

"Entry" means a stack or a fragment; both are built the same way. Each is a directory holding a Markdown file (`STACK.md` or `FRAGMENT.md`) with YAML frontmatter and guidance prose, plus optional `files/` (starter files copied into every project) and `adapters/` (files for one agent). The frontmatter is what composition reads; the prose is what ends up in the brief. [Entry file format](https://stacks.steamfield.io/docs/reference/entry-format.md) documents every key, and [Write your own stack or fragment](https://stacks.steamfield.io/docs/guides/authoring.md) walks through making one.

Entries come from several places, called origins: your project, your user registry, the signed index from stacks.steamfield.io and the registry bundled with the CLI. Where an entry comes from decides whether stacks trusts it. [Registries and trust](https://stacks.steamfield.io/docs/concepts/registries-and-trust.md) covers that.

## Related

- [The brief and the manifest](https://stacks.steamfield.io/docs/concepts/brief-and-manifest.md): what `new` writes and what each file is for.
- [Verify: the definition of done](https://stacks.steamfield.io/docs/concepts/verify.md): how the manifest's steps run and why an agent can't quietly edit them.
- [CLI commands](https://stacks.steamfield.io/docs/reference/commands.md): every flag of `new`, `add`, `list` and `show`.
