Skip to content
stacks
Docs menu

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.

View as MarkdownOpen in ClaudeOpen in ChatGPT

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

stacks create stack my-api
Terminal

For a fragment, give its category: agent-ops, app, ci, deploy, release, service, vendor or tooling.

stacks create fragment my-ci --category ci
Terminal

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:

stacks create stack go-cli --from bundled
Terminal

Fill 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: [] }
---
~/.config/stacks/stacks/my-api/STACK.md

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 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-api
Terminal

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

--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 --sandbox
Terminal

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:

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"
Terminal

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