Skip to content
stacks
Docs menu

How stacks works

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

View as MarkdownOpen in ClaudeOpen in ChatGPT

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.

stacks list stacks
Terminal
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
Output

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 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 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:

fragments:
  required: [claude-harness]
  default: [git-hooks, ci-github, effect]
  optional: [rr, ce-plugin, bun-release, openrouter-chat-cli]
stacks/typescript-cli/STACK.md
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
stacks new typescript-cli my-cli --without ci-github --with bun-release
Terminal

That project gets claude-harness, git-hooks, effect and bun-release, and leaves out CI. Fragments you list under always in your configuration 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 documents every key, and Write your own stack or fragment 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 covers that.