One-time discovery that teaches the spec-driven-dev pipeline how THIS project works, and saves the answers to .spec-driven.yml — project layout (single repo, monorepo, or multiple repos), issue tracker, base branch, PR target, branch naming, commit style, and the lint/typecheck/test/ build/dev commands. It also builds the project's memory: for an existing repo a shallow audit plus one round of questions, for a new one the intended stack and conventions, saved to a small specs/CONTEXT.md that ...
Installs into .claude/skills of the current project.
Sponsors
SSkills DirectorySkills Directory
Know which skills are safe — weekly.
SSkills DirectorySkills Directory
Is that skill safe to install?
Are you the author of Spec Setup?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/benjaminthomas-spec-setup)
---
name: spec-setup
description: >
One-time discovery that teaches the spec-driven-dev pipeline how THIS project works, and saves
the answers to .spec-driven.yml — project layout (single repo, monorepo, or multiple repos),
issue tracker, base branch, PR target, branch naming, commit style, and the lint/typecheck/test/
build/dev commands. It also builds the project's memory: for an existing repo a shallow audit
plus one round of questions, for a new one the intended stack and conventions, saved to a small
specs/CONTEXT.md that later skills load cheaply. Use when the user says "set up spec-driven",
"configure the pipeline", "spec-setup", "audit this repo", "refresh the project context",
"change our branch rules", "turn GitRisk on/off", "turn on run-through", or when any other spec-* skill finds no .spec-driven.yml or no
CONTEXT.md. Detects everything it can first and only asks about what is ambiguous. Writes config
and context files only — never changes code, branches, or commits.
license: MIT
---
# spec-setup
Learn this project's rules and context once, save them, and let every other `spec-*` skill reuse
them. This is **the** setup: the npm installer only copies the skills and then sends people here, so
treat it as their first conversation with the workflow. Explain each question in a line, and let
them change any earlier answer at any point ("actually it's Jira") before you write anything. Team rules live in a config file the team can review and change — never in the skills
themselves. What the project *knows* (areas, conventions, decisions) lives in
`{specs_dir}/CONTEXT.md`, kept small so loading it is cheap.
## Where the config lives
`.spec-driven.yml`, found by walking up from the current directory (stop at the home folder). The
first one found wins.
| Layout | Put the file in | Share it? |
|---|---|---|
| `single` | the repo root | Commit it — the whole team gets the same rules |
| `monorepo` | the repo root | Commit it |
| `multi-repo` | the shared parent folder of the repos (usually not itself a git repo) | The team's rules go in `team.yml` in the specs repo (shared); this file keeps only local paths |
A multi-repo config only applies inside the repos it lists. If the current repo sits under that
folder but isn't listed, treat it as having no config (ask whether to add it).
## Step 0 — Join a team that's already set up
Before detecting anything, look for a team setup someone already shared: a folder next to this repo
(or in the workspace folder) containing `team.yml` or `team-repos.yml`, or a specs repo the user
names (a path, or a git URL to clone). If you find one, say so with what it is, and ask with a menu:
> Found your team's setup in ~/Projects/soreto-specs: 5 repos, Jira STP, branches from staging.
> `Join it (Recommended)`: use the team's rules; I'll only ask which of its repos you have here.
> `Set up separately`: ignore it and answer everything yourself.
**Joining:** ask only which of the team's repos you work on (tick boxes, from `team-repos.yml`;
mark the ones not cloned here and offer their `git clone` command, cloning only on a yes), then run
`spec-driven-dev setup --join=<specs repo> --repos=<chosen>` (or `npx -y @benjaminthomas/spec-driven-dev …`).
Don't audit, don't ask about conventions, and never change the team's files: `CONTEXT.md`,
`team.yml` and `team-repos.yml` are shared. Then run `doctor`. If any of their repos lack the
pointer line (Step 4, item 5), offer to add it there. Finish with "You've joined. Say
*investigate STP-123* to start." Only `team-repos.yml` and no `team.yml` (an older setup): join
anyway, and tell the user the team's rules aren't shared yet, so the person who set it up should
run `spec-driven-dev team init`.
## Step 1 — Detect before asking
Read, don't guess. Collect a draft of every field in `references/config-template.yml`:
1. **Layout.**
- Inside a git repo with workspace markers (`pnpm-workspace.yaml`, `workspaces` in
`package.json`, `turbo.json`, `nx.json`, `lerna.json`, `go.work`, `[workspace]` in
`Cargo.toml`, several `apps/*`/`packages/*`/`services/*` with their own manifests) →
`monorepo`; list the packages.
- **Not a monorepo:** a Shopify app (`shopify.app*.toml` at the root) whose workspaces only cover
`extensions/`. Those are parts of one app deployed together, so it's `single` (or one repo of a
multi-repo workspace). The same goes for any repo whose "packages" are plug-ins of one app.
- **Ask when one repo works with others.** Even inside a single repo, ask once: "Does this repo
change together with other repos (for example a backend)?" A yes means `multi-repo`.
- Not inside a git repo, but sibling folders are git repos → candidate `multi-repo`.
- **Choosing the repos is a required question for `multi-repo`, never a detection.** Someone new
doesn't know what `soreto-melissa` is, so never show bare folder names. Follow
`references/repo-picker.md`: say what each candidate repo is, show evidence of how it connects
to the current repo, note whether the user commits to it, and recommend a selection with a
reason per repo. Ask once, and don't write the config until they've answered. Always also
offer repos in **other folders** (e.g. `~/clients/billing`). Check each path is a git repo,
and store paths inside the workspace as relative and paths outside it as absolute.
- The repos of one workspace can live in unrelated places (`/Projects/frontend`,
`~/Work/backend`, `/srv/database`). Put the config in their shared parent folder, or in
`~/.spec-driven/<name>/` when that parent would be the home folder or `/`. Then record it in
`~/.spec-driven/workspaces.json` (`{"<config path>": ["<repo path>", …]}`) so every repo can
find it.
- The user can override the detected layout. If they choose `multi-repo` from inside one repo,
the workspace folder defaults to that repo's parent, with the current repo pre-selected. If
they choose `monorepo`, ask for the package folders. Never write a `multi-repo` config with
no repos.
- Otherwise → `single`.
2. **Existing written rules.** `CLAUDE.md`, `AGENTS.md`, `CONTRIBUTING.md`, PR templates,
`.github/workflows`. Anything stated there is a strong default — quote it back to the user.
3. **Tracker.** Ticket IDs in recent branch names and commit subjects (`STP-123`, `#45`,
`ENG-91`, `AB#4512`, `CU-86a1b2c3d`, `sc-1234`), tracker links in PR templates or docs, the
remote's host (GitLab, Azure DevOps), whether GitHub Issues are enabled
(`gh repo view --json hasIssuesEnabled`), and which tracker MCP servers this host has. Any
tracker is fine; `references/trackers.md` lists the common ID shapes and tools.
4. **Git, per repo.** Default branch (`git symbolic-ref refs/remotes/origin/HEAD` or
`gh repo view --json defaultBranchRef`); integration branches (`staging`, `develop`,
`pre-prod`); which branch recent PRs targeted (`gh pr list --state merged --limit 20 --json
baseRefName`); the pattern of the last ~20 remote branch names; the commit style from
`git log -30 --format=%s`. Judge commit style **per repo**: when one repo writes `STP-123: …` and
the others write `feat: …`, keep the majority at the top level and give that repo its own
`git.commit_style`.
5. **Commands, per repo/package.** `package.json` scripts plus the lockfile's package manager,
`Makefile`, `pyproject.toml`/`tox.ini`, `Cargo.toml`, `go.mod`, `composer.json`, CI workflow
steps (CI is often the most truthful source). Dev URL from the dev script, `.env.example`, or
framework defaults.
6. **Models per tier.** Write the `models:` block from the template; the defaults work as they are
(Claude haiku / sonnet / opus, Cursor `fast` / `inherit`). Tools that offer several vendors'
models (Cursor, OpenCode, Copilot: Claude, GPT/Codex, Gemini…) can map each tier to a real model.
Offer it in one line ("Want light tasks on a cheaper model and deep ones on a stronger one?"),
and on a yes:
- **Read the choices, don't guess them.** Use the model values your subagent tool accepts (its
parameter's allowed list, e.g. Cursor's Task tool `model`), or ask the user to copy names from
the tool's model picker. Never write a model name from memory.
- Suggest one family for all tiers (cheapest for light, strongest for deep, e.g. a Haiku / Sonnet
/ Opus or a Flash / Pro split), and say mixing vendors is fine.
- Write the exact names to `models.<tool>`. A name the tool later rejects falls back to the
session's model, and spec-implement says so.
7. **After approval.** Ask whether an approved spec should stop after each stage (`stop`), or
run implement → verify → review → checkpoint in one go (`run-through`), stopping at any failure and never
pushing. Store it as `pipeline.after_approval`.
8. **New or existing project.** Detect it (commit and file counts) and confirm in one line. Store
it as `context.project`. This decides what Step 4 does.
9. **Where specs live (multi-repo).** One specs folder serves the whole workspace: each ticket gets
one folder there even when it changes several repos; code, branches and PRs stay in each repo.
Offer, in this order, with the reason for each:
- **A dedicated specs repo (recommended for teams where developers work on different subsets of
repos):** everyone clones it, whatever code repos they have. Use an existing one (path or git
URL; offer the `git clone` command) or create one: only after a yes, `mkdir` it next to the
repos and `git init`. Never create a remote repo; say how to push it (`gh repo create`).
Then set `specs_dir: <specs-repo>` (its root holds `CONTEXT.md`, `context/` and feature folders).
- **Inside one code repo** (`<repo>/specs`): fine when every developer has that repo.
- **The workspace folder:** on this machine only, since it isn't a git repo.
10. **The team's repo list.** Keep `{specs_dir}/team-repos.yml` (see `references/config-template.yml`)
listing every repo the team works across with its git URL and a one-line role. Each developer's
own `.spec-driven.yml` lists only the repos they have. When the file exists, offer its repos
instead of making people remember them, and for any not cloned here show
`git clone <url> <workspace>/<name>`. When someone adds a repo, add it to the file too.
11. **Sharing with the team.** Find out what git does with the specs folder today:
`git check-ignore -v {specs_dir}/CONTEXT.md` and `git check-ignore -v {specs_dir}/x/README.md`.
Then ask once, saying what's true now (e.g. "your .gitignore ignores `specs/`, so nothing is
shared today"):
- **Share everything (recommended):** commit plans, investigations, reviews and project memory,
so teammates and PR reviewers see the reasoning and the memory grows for everyone.
- **Share project memory only:** commit `CONTEXT.md` and `context/`; feature files stay local.
- **Keep everything local:** ignore the specs folder.
**Multi-repo:** if the config folder isn't a git repo, specs kept there can't be shared. Say so
and offer `specs_dir: <repo>/specs` inside the repo the team treats as home.
Store the answer as `context.share`. A dedicated specs repo is shared by nature: set
`context.share: all`.
## How to ask
Two kinds of question, asked two different ways:
1. **Choices** (layout and repos, sharing, specs location, after-approval mode, a guessed command):
use the host's **interactive question tool** when it has one (Claude Code: `AskUserQuestion`).
- Up to 4 questions per call; each needs **2 to 4 options** (a one-option question is rejected
and the user never sees it; "Other" is added automatically and doesn't count).
- Put the recommended option first and end its label with "(Recommended)". Put the evidence in
each option's description (e.g. "called via BACKBONE_URL, app/services/x.ts:105").
- **Layout and repos are two separate calls, always** (Step 2). Never ask layout together with
other questions.
- **Repos are never offered as preset bundles** ("+backend +melissa", "all four"); bundles don't
scale and stop people mixing their own. Ask in two calls:
1. **Layout first**, on its own: "Single repo" vs "Several repos that change together"
(vs "Monorepo" when it fits), recommendation first with the evidence.
2. **Only if several:** a `multiSelect` question with **one option per repo**: label = repo
name (the recommended ones first, marked "(Recommended)"), description = what it is plus the
link evidence. At most 4 options. The menu can't show the rest, so the **question text** must
end by naming the other repos found ("Also found: a, b, c (no code link).") and saying how to
add them: "To add any of these, or a repo from another folder, choose *Type something* and
enter names or paths, e.g. `a, ~/Work/billing`." Put the remaining choices (specs location,
sharing, pipeline) in this same call.
- If the tool isn't available (or a call fails), ask the same choices as a short numbered list
in text instead. Never drop a question.
2. **Open questions** (what the product does, fragile spots, direction, unwritten rules): plain text
in **one chat message**, asked **after** the choices are answered. Never turn these into a menu.
## Step 2 — Confirm in one round
Show the draft as a short table grouped by layout, tracker, git, commands, and specs location.
Mark each value **detected** (with where it came from) or **guess**. Then ask in exactly this order
(interactive question tool when there is one; see How to ask):
**Call 1: layout, alone. Nothing else in this call.** Use these option labels exactly; no repo names
in them:
- `Single repo`: "Only <this repo>." (+ the evidence for or against)
- `Several repos`: "<this repo> changes together with other repos. You'll pick which next."
- `Monorepo`: only when workspace markers were found.
Recommend one (first, with "(Recommended)") and put the evidence in the question text.
**Call 2: repos (only if the answer was `Several repos`).** The repo tick-box list (`multiSelect`, one
option per repo, see `references/repo-picker.md`) and where specs live (a dedicated specs repo, inside
one code repo, or this machine only).
**Call 3: git conventions, always, even when detected.** These decide how every branch and commit is
made, and detection can be wrong, so confirm them. Four questions, the detected value first with its
evidence in the description, then the common alternatives:
- **Base branch** (work starts from): e.g. `staging (Recommended)`: "16 of the last 20 merged PRs";
`main`; `develop`. In multi-repo, say which repos differ ("staging; soreto-cms has none, uses main").
- **PR target**: usually the same as the base branch.
- **Branch names**: e.g. `STP-123 (Recommended)` (bare ticket id, seen in recent branches);
`feat/STP-123-short-name`; `feat/short-name`.
- **Commit style**: e.g. `STP-123: message (Recommended)`; `feat: message`; free text. In multi-repo,
name any repo that uses a different style.
**Call 4: tracker, team and pipeline.** The tracker, confirmed like the git conventions (e.g.
`Jira, key STP (Recommended)`: "STP-123 in recent branches", then the other likely ones, `None`; any
tracker can be typed under *Type something*, see `references/trackers.md`), then
sharing (if specs are inside a repo), after approval (stop / run straight through), and any command
that's a guess (e.g. typecheck). At most 4; a guessed command that doesn't fit goes in the summary as
"I'll use X, say if that's wrong". Don't ask about tracker updates: they default to `ask`, so the
first update on each ticket is confirmed then. Mention it in one line of the summary.
Then the open questions, as plain text (see How to ask).
Typical things to flag in the descriptions:
- "Your repos default to `master`, but recent PRs targeted `staging`."
- "Recent branches are bare ticket IDs (`STP-282`)."
- "These 6 repos share the `acme` GitHub org."
If the user says "just use the defaults", accept the detected values and the template defaults
for the rest.
## Step 3 — Write and report
1. Write `.spec-driven.yml` using `references/config-template.yml` as the shape. Keep its
comments; drop fields that don't apply (e.g. `repos:` for `single`). Per-repo values only go
under `repos:` where they differ from the top level.
2. If it's inside a repo, tell the user it's meant to be committed (so teammates get the same
rules) — don't commit it yourself.
**Multi-repo with specs in a repo:** run `spec-driven-dev team init --fresh` right after writing
the file (`--fresh` skips the backup, since you wrote the file this run; leave it off when
splitting a config that existed before). It moves the team's rules (tracker, git conventions, commands, models, GitRisk, sharing)
into `{specs_dir}/team.yml`, which is committed with the specs, and leaves only local paths in
`.spec-driven.yml`. Tell the user to commit `team.yml`, and that colleagues then just say
"run spec-setup" and choose *Join*.
3. If `npx` is available, run `npx -y @benjaminthomas/spec-driven-dev doctor` from the config's folder. It checks
that every branch, folder, and `npm run` script in the file really exists. Fix anything it
reports before finishing.
4. Report: the file path, a one-line summary per section, and "re-run spec-setup any time these
change".
## Step 4 — Project context
Skip if `{specs_dir}/CONTEXT.md` already exists (offer a refresh instead, see `references/audit.md`).
1. Read `references/audit.md` and follow it: a shallow audit for an existing project, or the
intended stack and conventions for a new one. One round of questions, no more.
2. Write `{specs_dir}/CONTEXT.md` (and any area files) using `references/context-template.md`.
Keep the index to 60 lines and area files to 150.
3. **Apply the sharing choice.** Show the exact `.gitignore` lines that will be replaced or added,
and change it only after a yes, by running `spec-driven-dev settings --share=<all|memory|none>`
(it manages one marked block and only replaces lines about the specs folder). Never rewrite
other `.gitignore` lines.
4. **Risk scores.** For an existing project, run `spec-driven-dev risk` (or
`npx -y @benjaminthomas/spec-driven-dev risk`) to write `{specs_dir}/context/risk.md`. It uses
git only, no model, and adds `risk.md` to `.gitignore` because it's regenerated on every run. Skip it for a new project with no history. Mention the hotspot count in the
report. Set `risk.enabled: off` only if the user doesn't want it.
5. **Offer, don't do:** ask whether to add one pointer line to `CLAUDE.md` / `AGENTS.md` (whichever
each repo uses), so hosts reload the project memory after compaction and in every new session.
- Single repo or monorepo: `For spec work, read specs/CONTEXT.md first, then the "Resume here" block of any unfinished spec.`
- Multi-repo: offer it for **every repo in this person's workspace** in one question, not just
the current one. Name the specs repo rather than assuming a layout:
`For spec work, read CONTEXT.md in the <specs repo name> repo first (usually ../<specs repo name>/CONTEXT.md), then the "Resume here" block of any unfinished spec.`
- Skip repos that already have a line mentioning `CONTEXT.md`. It's committed with each repo, so
teammates get it when they pull, and nobody adds it twice.
Add it only on a yes, and never commit. Each repo is its own commit; list them in the report, in
that repo's commit style and onto its base branch (e.g. `git -C reverb-backend commit -m "STP-123:
point AI tools to the project memory" AGENTS.md`). If a repo is on a feature branch, say the edit
is there and suggest committing it on its own so it doesn't ride along in that PR.
6. Re-run `npx -y @benjaminthomas/spec-driven-dev doctor` if available. It checks the size limits
and flags context lines that point to files which no longer exist.
## After setup
Finish with **one** next step, not a list: "Setup's done. Say *investigate STP-123* to start your
first ticket." If anything was left out (a tracker URL, a repo not cloned), name it in one line.
## Quick switches (plain words, no YAML)
When the user asks to switch a feature on or off, change only that one line of `.spec-driven.yml`,
keep every other line and comment, and confirm in one sentence. Don't re-run discovery.
| They say | Set |
|---|---|
| "turn GitRisk off", "stop using risk scores", "ignore risky files" | `risk.enabled: off` |
| "turn GitRisk on", "use the risk scores" | `risk.enabled: on`, then run `spec-driven-dev risk` if `{specs_dir}/context/risk.md` doesn't exist yet |
| "run straight through after I approve", "fewer stops" | `pipeline.after_approval: run-through` |
| "stop after each stage" | `pipeline.after_approval: stop` |
| "change our branch rules", "use main for PRs" (when `team.yml` exists) | edit `team.yml`, since it's a team rule, and remind them to commit it; only change `.spec-driven.yml` if they say it's just for them |
| "stop updating Jira", "don't comment on tickets", "update Jira without asking" | `tracker.updates: off` / `on` (default `ask`), in `team.yml` when it exists; see `references/tracker-updates.md` |
| "our statuses are To Do / Doing / Code Review" | `tracker.statuses.start` / `.review`, from the project's real transitions |
| "add reverb-react to the workspace", "I also work on X" | check each named repo first and say what you found, per repo: **already in the workspace** (change nothing for it), **in `team-repos.yml` but not cloned here** (offer the `git clone`), **not found** (ask for its path), or **new**. For new ones: add under `repos:` and to `team-repos.yml` if new to the team, audit only that repo and add its areas to `CONTEXT.md` (Step 4), re-run `spec-driven-dev risk`, offer the pointer line for it (Step 4, item 5), then `doctor` |
| "share the specs with the team", "keep specs local", "share only the project memory" | `context.share: all / none / memory`: show the `.gitignore` change, then run `spec-driven-dev settings --share=…` on a yes |
Reply with what changed and what it means, for example: "GitRisk is now off. Investigations, plans
and reviews will ignore risk scores until you turn it back on." People who prefer a menu can run
`spec-driven-dev settings` in a terminal.
## Updating
Re-running `spec-setup` with an existing config: load it, re-detect, and show only what changed or
looks stale (a branch that no longer exists, a script that was renamed). Never silently overwrite
a value the user set by hand.
## Boundaries
- Writes `.spec-driven.yml`, `{specs_dir}/CONTEXT.md` and `{specs_dir}/context/*.md`, plus the
one-line pointer in `CLAUDE.md` / `AGENTS.md` only if the user says yes. No branches, commits,
pushes, installs, or code. Never installs graphify or anything else.
- Never put secrets, tokens, or credentials in the config or context files. Ask before saving
sensitive business details.
- A value in the config beats a detected value. If the config looks wrong mid-run (a base
branch that doesn't exist), the other skills stop and point back here rather than overriding it.