Write your own stack or fragment
Turn a project you trust into a stack or fragment in your user registry, validate it, preview its brief and test it with an agent build.
# Write your own stack or fragment
> Turn a project you trust into a stack or fragment in your user registry, validate it, preview its brief and test it with an agent build.
Your own stacks and fragments live in your user registry, and every command treats them like the bundled ones. This guide creates an entry, validates it, previews its brief, tests it with an agent build and submits it to the public registry.
A coding agent can do most of this for you. The `stacks-author` skill covers turning one of your repositories into a stack, designing a new one by asking you questions, and submitting it. Install it with `stacks skill install stacks-author` or the [Claude Code plugin](https://stacks.steamfield.io/docs/agents.md#install-the-skill-as-a-claude-code-plugin), or have any agent read it with `stacks guide author`, then ask it to "turn this repo into a stack".
## Choose the source project and the kind of entry
Write a stack from a project you've built yourself and would start again the same way: one you can build from an empty directory, whose layout and checks you'd defend. The stack records its structure, its rules and how to prove it works, and leaves details that change, like versions and config formats, to the agent.
Pick the right kind of entry first:
- A **stack** describes one kind of project end to end.
- A **fragment** adds one capability to several stacks, such as CI, a database or a deploy target. If two of your stacks would differ only in CI or deployment, write one stack plus a fragment for the part that differs.
- An **app** is a fragment with `category: app` that builds a working feature on top of a stack.
## Create the entry
Start a skeleton:
```sh title="Terminal"
stacks create stack my-api
```
For a fragment, give its category: `agent-ops`, `app`, `ci`, `deploy`, `release`, `service`, `vendor` or `tooling`.
```sh title="Terminal"
stacks create fragment my-ci --category ci
```
The entry goes in `~/.config/stacks/stacks/my-api/` (or `$XDG_CONFIG_HOME/stacks/`). `create` runs nothing and refuses a target that already exists, so you can't lose work to it.
To start from a bundled entry instead, copy it. The copy keeps the same id and every byte, including its files and adapters, and from then on your copy shadows the bundled one:
```sh title="Terminal"
stacks create stack go-cli --from bundled
```
## Fill in the frontmatter
`STACK.md` (or `FRAGMENT.md`) opens with YAML between two `---` lines. This is the skeleton `create stack` writes:
```yaml title="~/.config/stacks/stacks/my-api/STACK.md"
---
schema_version: 1
id: "my-api"
kind: stack
name: "my-api"
description: "stacks:fill: describe the stack"
tags: [make]
deps: {}
commands:
install: Install dependencies
lint: Run lint
typecheck: Check types
test: Run tests
tools: []
decisions: ["Project layout (default: a single package)."]
env: {}
verify:
- { name: install, phase: setup, layer: install, run: make install }
- { name: lint, phase: check, layer: lint, run: make lint }
- { name: typecheck, phase: check, layer: typecheck, run: make typecheck }
- { name: test, phase: check, layer: test, run: make test }
- name: readme
phase: check
layer: docs
run: "test -s README.md && ! grep -n 'stacks:fill' README.md"
merge: []
fragments: { required: [], default: [], optional: [] }
---
```
Replace each part with what your project does:
- `deps` lists packages by role, names only. Never a version: the agent installs whatever is current.
- `commands` lists every project command and what it does. Every verify step must call a command declared here.
- `decisions` are the choices the agent asks about. Each one needs a `(default: ...)` so sandbox projects can proceed without asking.
- `verify` is your definition of done. Every stack has to cover the `install`, `lint`, `typecheck` and `test` layers, plus a probed server if it's tagged `web` or `api`.
- `tags` include exactly one task runner, `make` or `scripts`.
Keys are snake_case (`applies_to`, `requires_tools`), and an unknown key is an error, so a typo fails validation instead of being ignored. [Entry file format](https://stacks.steamfield.io/docs/reference/entry-format.md) documents every key.
A server step starts the app and probes it until it answers:
```yaml
verify:
- name: dev
phase: serve
layer: serve
run: make dev
expect: { http: "http://localhost:3000/", within: 60s }
```
## Write the agent guidance in the body
Everything after the frontmatter is Markdown for the building agent. Keep the skeleton's headings: Layout, Setup, Conventions, Tool configuration, Testing, Commands and Gotchas.
Write rules that will still be true after the next major release of every tool involved. Where a detail will go stale, tell the agent how to find it instead: "inspect the generator's current `--help` and run it non-interactively into a subdirectory" outlasts a list of flags. Keep Setup as a numbered list.
Prose can depend on the composition. This paragraph appears in the brief only when `ci-github` is part of the project:
```md
<!-- stacks:when with=ci-github -->
CI reads the Go version from go.mod.
<!-- stacks:end -->
```
The other conditions are `preset=`, `stack=`, `tag=`, `tag!=` and `mode=` (`new` or `add`). Blocks don't nest.
## Add starter files
Files under `files/` are copied into every project under their real names, so `files/.gitignore` becomes `.gitignore`. Ship content that's stable across tool releases: a `.gitignore`, a Makefile, hook scripts. Describe version-sensitive config in the guidance and let the agent generate it.
A file ending in `.tmpl` is a template. Only these variables exist: `{{project_name}}`, `{{project_slug}}`, `{{env_prefix}}`, `{{package_scope}}`, `{{author}}` and `{{year}}`.
Files for one agent go under `adapters/claude/`, `adapters/codex/`, `adapters/opencode/` or `adapters/cursor/`, and are copied only when that agent is a target.
Replace every `stacks:fill` marker the skeleton left. The skeleton's `readme` step fails while one remains in the README. Plain `validate` doesn't flag the rest; `validate --submission` does.
## Validate the entry
```sh title="Terminal"
stacks validate ~/.config/stacks/stacks/my-api
```
`validate` reads files only and runs nothing. It checks the frontmatter, references to other fragments, conditional markers, verify coverage and word budgets, and it composes the stack with each optional fragment it could take. Errors exit 2. Fix warnings too: they catch pinned versions, dated phrases and config files that will go stale.
Stack bodies have to stay under 2,000 words, fragments under 1,000 and apps under 3,000. A composed brief stays under 6,000 words, or 9,000 with an app. [Validation checks](https://stacks.steamfield.io/docs/reference/validation.md) lists everything it looks for.
## Preview the brief
See exactly what an agent would receive, without writing a project:
```sh title="Terminal"
stacks validate ~/.config/stacks --brief my-api --sandbox
stacks show my-api --kind stack
```
`--brief` prints the composed brief with its word count. `show` prints every guidance branch and every file the entry would ship.
## Test the entry with an agent build
To find out whether an agent can build from the brief, write a sandbox project into an unused directory and hand it to your agent:
```sh title="Terminal"
stacks new my-api /tmp/my-api-trial --sandbox
```
Let the agent follow the brief until `stacks verify` is green, without weakening any step. Then read `.stacks/NOTES.md`. Under `## Findings` the agent recorded where the brief was ambiguous, wrong or made it guess, and under `## Asked` every time it needed you. Fix the entry at the source and run again.
`stacks runs` in the trial project shows how many verify runs it took and how long it took to reach green.
## Submit the entry to the public registry
Once an agent build reaches green, check the entry against the submission bar, preview the pull request, then open it:
```sh title="Terminal"
stacks validate ~/.config/stacks/stacks/my-api --submission
stacks submit my-api --dry-run --query "a REST API in Go with Postgres"
stacks submit my-api --query "a REST API in Go with Postgres"
```
`--submission` adds checks for leftover fill markers, credential-shaped strings, `.env` files, personal absolute paths and a missing search card. `submit` needs the GitHub CLI (`gh`) signed in. It forks [steamfield/stacks](https://github.com/steamfield/stacks), opens a draft pull request with your entry, and records your GitHub login as its author. Each `--query` proposes a search the entry should rank first for. Maintainers then review the search card, the dependencies and the shipped files, prove the entry with a test build, and sign it into the next index. The [contributing guide](https://github.com/steamfield/stacks/blob/main/CONTRIBUTING.md) covers the review, updates to a merged entry, and licensing. [`stacks submit`](https://stacks.steamfield.io/docs/reference/commands.md#stacks-submit) has every step and exit code.
## Share entries through a repository
To share entries through a repository, put them under `.stacks/stacks/` or `.stacks/fragments/` in that repository. Anyone working there sees them. They're untrusted, because cloning a repository shouldn't be enough to make stacks act on its contents: stacks never auto-launches an agent on a project entry, and copying one into your own registry with `create --from project` shows a full report and needs you at a terminal to confirm.
[Registries and trust](https://stacks.steamfield.io/docs/concepts/registries-and-trust.md) covers the origins, their lookup order and the signed index.
## Next steps
- [Entry file format](https://stacks.steamfield.io/docs/reference/entry-format.md): every frontmatter key and body convention.
- [Validation checks](https://stacks.steamfield.io/docs/reference/validation.md): each check, severity and budget.
- [How stacks works](https://stacks.steamfield.io/docs/concepts.md): how stacks and fragments compose.
View as MarkdownOpen in ClaudeOpen in ChatGPTYour own stacks and fragments live in your user registry, and every command treats them like the bundled ones. This guide creates an entry, validates it, previews its brief, tests it with an agent build and submits it to the public registry.
A coding agent can do most of this for you. The stacks-author skill covers turning one of your repositories into a stack, designing a new one by asking you questions, and submitting it. Install it with stacks skill install stacks-author or the Claude Code plugin, or have any agent read it with stacks guide author, then ask it to "turn this repo into a stack".
Choose the source project and the kind of entry
Write a stack from a project you've built yourself and would start again the same way: one you can build from an empty directory, whose layout and checks you'd defend. The stack records its structure, its rules and how to prove it works, and leaves details that change, like versions and config formats, to the agent.
Pick the right kind of entry first:
- A stack describes one kind of project end to end.
- A fragment adds one capability to several stacks, such as CI, a database or a deploy target. If two of your stacks would differ only in CI or deployment, write one stack plus a fragment for the part that differs.
- An app is a fragment with
category: appthat builds a working feature on top of a stack.
Create the entry
Start a skeleton:
stacks create stack my-apiFor a fragment, give its category: agent-ops, app, ci, deploy, release, service, vendor or tooling.
stacks create fragment my-ci --category ciThe entry goes in ~/.config/stacks/stacks/my-api/ (or $XDG_CONFIG_HOME/stacks/). create runs nothing and refuses a target that already exists, so you can't lose work to it.
To start from a bundled entry instead, copy it. The copy keeps the same id and every byte, including its files and adapters, and from then on your copy shadows the bundled one:
stacks create stack go-cli --from bundledFill in the frontmatter
STACK.md (or FRAGMENT.md) opens with YAML between two --- lines. This is the skeleton create stack writes:
---
schema_version: 1
id: "my-api"
kind: stack
name: "my-api"
description: "stacks:fill: describe the stack"
tags: [make]
deps: {}
commands:
install: Install dependencies
lint: Run lint
typecheck: Check types
test: Run tests
tools: []
decisions: ["Project layout (default: a single package)."]
env: {}
verify:
- { name: install, phase: setup, layer: install, run: make install }
- { name: lint, phase: check, layer: lint, run: make lint }
- { name: typecheck, phase: check, layer: typecheck, run: make typecheck }
- { name: test, phase: check, layer: test, run: make test }
- name: readme
phase: check
layer: docs
run: "test -s README.md && ! grep -n 'stacks:fill' README.md"
merge: []
fragments: { required: [], default: [], optional: [] }
---Replace each part with what your project does:
depslists packages by role, names only. Never a version: the agent installs whatever is current.commandslists every project command and what it does. Every verify step must call a command declared here.decisionsare the choices the agent asks about. Each one needs a(default: ...)so sandbox projects can proceed without asking.verifyis your definition of done. Every stack has to cover theinstall,lint,typecheckandtestlayers, plus a probed server if it's taggedweborapi.tagsinclude exactly one task runner,makeorscripts.
Keys are snake_case (applies_to, requires_tools), and an unknown key is an error, so a typo fails validation instead of being ignored. Entry file format documents every key.
A server step starts the app and probes it until it answers:
verify:
- name: dev
phase: serve
layer: serve
run: make dev
expect: { http: "http://localhost:3000/", within: 60s }Write the agent guidance in the body
Everything after the frontmatter is Markdown for the building agent. Keep the skeleton's headings: Layout, Setup, Conventions, Tool configuration, Testing, Commands and Gotchas.
Write rules that will still be true after the next major release of every tool involved. Where a detail will go stale, tell the agent how to find it instead: "inspect the generator's current --help and run it non-interactively into a subdirectory" outlasts a list of flags. Keep Setup as a numbered list.
Prose can depend on the composition. This paragraph appears in the brief only when ci-github is part of the project:
<!-- stacks:when with=ci-github -->
CI reads the Go version from go.mod.
<!-- stacks:end -->The other conditions are preset=, stack=, tag=, tag!= and mode= (new or add). Blocks don't nest.
Add starter files
Files under files/ are copied into every project under their real names, so files/.gitignore becomes .gitignore. Ship content that's stable across tool releases: a .gitignore, a Makefile, hook scripts. Describe version-sensitive config in the guidance and let the agent generate it.
A file ending in .tmpl is a template. Only these variables exist: {{project_name}}, {{project_slug}}, {{env_prefix}}, {{package_scope}}, {{author}} and {{year}}.
Files for one agent go under adapters/claude/, adapters/codex/, adapters/opencode/ or adapters/cursor/, and are copied only when that agent is a target.
Replace every stacks:fill marker the skeleton left. The skeleton's readme step fails while one remains in the README. Plain validate doesn't flag the rest; validate --submission does.
Validate the entry
stacks validate ~/.config/stacks/stacks/my-apivalidate reads files only and runs nothing. It checks the frontmatter, references to other fragments, conditional markers, verify coverage and word budgets, and it composes the stack with each optional fragment it could take. Errors exit 2. Fix warnings too: they catch pinned versions, dated phrases and config files that will go stale.
Stack bodies have to stay under 2,000 words, fragments under 1,000 and apps under 3,000. A composed brief stays under 6,000 words, or 9,000 with an app. Validation checks lists everything it looks for.
Preview the brief
See exactly what an agent would receive, without writing a project:
stacks validate ~/.config/stacks --brief my-api --sandbox
stacks show my-api --kind stack--brief prints the composed brief with its word count. show prints every guidance branch and every file the entry would ship.
Test the entry with an agent build
To find out whether an agent can build from the brief, write a sandbox project into an unused directory and hand it to your agent:
stacks new my-api /tmp/my-api-trial --sandboxLet the agent follow the brief until stacks verify is green, without weakening any step. Then read .stacks/NOTES.md. Under ## Findings the agent recorded where the brief was ambiguous, wrong or made it guess, and under ## Asked every time it needed you. Fix the entry at the source and run again.
stacks runs in the trial project shows how many verify runs it took and how long it took to reach green.
Submit the entry to the public registry
Once an agent build reaches green, check the entry against the submission bar, preview the pull request, then open it:
stacks validate ~/.config/stacks/stacks/my-api --submission
stacks submit my-api --dry-run --query "a REST API in Go with Postgres"
stacks submit my-api --query "a REST API in Go with Postgres"--submission adds checks for leftover fill markers, credential-shaped strings, .env files, personal absolute paths and a missing search card. submit needs the GitHub CLI (gh) signed in. It forks steamfield/stacks, opens a draft pull request with your entry, and records your GitHub login as its author. Each --query proposes a search the entry should rank first for. Maintainers then review the search card, the dependencies and the shipped files, prove the entry with a test build, and sign it into the next index. The contributing guide covers the review, updates to a merged entry, and licensing. stacks submit has every step and exit code.
Share entries through a repository
To share entries through a repository, put them under .stacks/stacks/ or .stacks/fragments/ in that repository. Anyone working there sees them. They're untrusted, because cloning a repository shouldn't be enough to make stacks act on its contents: stacks never auto-launches an agent on a project entry, and copying one into your own registry with create --from project shows a full report and needs you at a terminal to confirm.
Registries and trust covers the origins, their lookup order and the signed index.
Next steps
- Entry file format: every frontmatter key and body convention.
- Validation checks: each check, severity and budget.
- How stacks works: how stacks and fragments compose.