Start a project on the Visual Stack — a multi-step setup form captures what's being built, recommends a stack, and either instantiates the vstack-template-base template, sets up a specs-and-design-only workspace, or records an existing codebase without touching it. Use when the user wants to start a new project, scaffold a repo, set up a codebase from the Cavalry template, pick a stack or add-ons, run Day-1 setup, or bring an existing app onto the visual stack.
Scanned 8/30/2026
Install to Claude Code
npx -y skills add Cavalry-Collective/visual-stack --skill start --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Start?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/cavalry-collective-start)More formats (shields.io, HTML) on the badges page.
---
name: start
description: Start a project on the Visual Stack — a multi-step setup form captures what's being built, recommends a stack, and either instantiates the vstack-template-base template, sets up a specs-and-design-only workspace, or records an existing codebase without touching it. Use when the user wants to start a new project, scaffold a repo, set up a codebase from the Cavalry template, pick a stack or add-ons, run Day-1 setup, or bring an existing app onto the visual stack.
---
Turns an idea — or an existing repo — into *this* project. One multi-step form, then whichever of three
paths its answers call for.
```
┌─ skip dev ──► specs/ + design/ only (no clone)
idea ──► setup form ──► choice ──┤
└─ full ─────► clone ──► delete the rest ──► toolchain ──► ready
existing code ──► infer ──► confirm screen ──► recorded (nothing touched)
```
Every path ends with two files the rest of the chain reads: **`specs/product.md`** — what this product
is — and **`.vstack/pipeline.json`** — where the pipeline stands.
## 1 · Pick the mode
Look at the target directory first:
| The directory is | Mode |
|---|---|
| empty, missing, or has no real code | **fresh** — the form runs before anything exists |
| template-derived (`stacks/`, `add-ons/`, `design/`, `specs/` all present) | **template** — don't clone again; the form reads the real inventory |
| a real codebase that isn't template-derived | **existing** — infer, confirm, record; never scaffold or delete |
In fresh mode, don't interrogate up front — the form asks the questions. The only thing worth asking
before serving it is where the project directory should go if the user hasn't said.
## 2 · Serve the form
```bash
SKILL=<this skill dir>
node "$SKILL/assets/chooser-server.mjs" --repo <project dir> --port 7799
```
Start it with **`run_in_background: true`**, then tell the user to open **http://localhost:7799/**.
The form is four steps: **what** are you building → **details** (kind, name, one-liner) → **stack &
add-ons**, with a pack recommended from the earlier answers — → **confirm**. On step 3 the user can
instead **skip development setup** entirely; the whole path then produces UI and specs only.
Where the inventory comes from:
- **Template mode** (repo has `stacks/` + `add-ons/`): scanned from disk — a pack added upstream
appears with no change here.
- **Fresh mode** (nothing on disk yet): the server fetches the **live `stacks/` + `add-ons/` listing
of `vstack-template-base` from GitHub** (`"source": "github"`); offline or rate-limited it falls
back to its built-in catalog snapshot (`"source": "snapshot"`). Either way, after cloning,
**reconcile**: if the chosen pack or an add-on doesn't exist in the cloned template, stop and
re-ask; if the template ships packs the form didn't show, mention them before deleting anything.
- **Existing mode**: no inventory. Infer the facts first — read `package.json` / lockfiles / framework
configs / the directory layout / `README` / recent git log — write them as a prefill, and serve:
```bash
node "$SKILL/assets/chooser-server.mjs" --repo <dir> --mode existing --prefill <dir>/.vstack/prefill.json
```
Prefill shape: `{ "building": "webapp", "kind": "saas", "name": "…", "oneLiner": "…",
"detected": "Next.js 14 app router, Prisma + Postgres, deployed on Vercel", "startAt": "confirm" }`.
The page opens on the confirm step with everything filled in and editable.
It asks **once**: on send it writes `<repo>/.vstack/choice.json` and exits. Nothing stays listening.
That makes this the one place in the stack that waits rather than watches — there is a single answer
coming, so the **`run_in_background: true`** start above is also the wait: the server's exit
re-invokes you, and that is the moment to read `<repo>/.vstack/choice.json`. (The review and bridge
tools stream instead, because their pages keep talking.)
If the user would rather answer in chat, that's fine — ask the same questions in prose and write the
same JSON yourself. **Ask in product terms when you do** — *"will several organisations share one
deployment, with their data kept separate?"*, never *"do you want multi-tenancy?"*. The form is the
nicer path, not the only one.
## 3 · Act on the choice
`choice.json` carries `mode`, `building`, `kind`, `name`, `oneLiner`, `skipDev`, `pack`, `addons`,
`deleting`, and (existing mode) `detected`. Three paths:
### 3a · Development skipped → the minimal workspace
No clone. In the project directory:
```bash
mkdir -p <dir>/specs <dir>/design
```
Write `specs/product.md` (§4) and `.vstack/pipeline.json` (§6) with `"specsOnly": true`. Done — say
that `/vstack:review` and the spec stages now have a home, and that running `/vstack:start` again
later adds real development setup.
### 3b · Existing app → record only
Write `specs/product.md` and `.vstack/pipeline.json`; create `specs/` and `design/` only if missing.
**Touch nothing else** — no scaffolding, no deletions, no template. The `detected` text goes into
`product.md` as the stack section.
### 3c · Full setup → clone and instantiate
**With a GitHub repo** — keeps the template link and the history clean:
```bash
gh repo create <name> --template Cavalry-Collective/vstack-template-base --private --clone
```
**Local only:**
```bash
git clone --depth 1 https://github.com/Cavalry-Collective/vstack-template-base.git <name>
rm -rf <name>/.git && git -C <name> init && git -C <name> add -A
```
Then read the contracts — root `CLAUDE.md`, `apps/backend/CLAUDE.md`, `apps/frontend/CLAUDE.md`,
`db/CLAUDE.md`, `infra/CLAUDE.md` — and, if the choice came from the snapshot, **reconcile it** (§2)
before deleting anything.
**Adoption is deletion.** Show the delete list, get a yes, then:
```bash
cd <repo>
for p in $(jq -r '.deleting.packs[]' .vstack/choice.json); do rm -rf "stacks/$p"; done
for a in $(jq -r '.deleting.addons[]' .vstack/choice.json); do rm -rf "add-ons/$a"; done
```
Record the choice in root `CLAUDE.md` **Learnings**: `Stack: <pack>; appendices under stacks/<pack>/`.
Then the rest of the Day-1 checklist, unchanged:
- **Toolchain** from the surviving pack's `README.md`: its **dev** command block → the root `CLAUDE.md`
*Common commands* placeholder (delete the banner); its **CI** block → `.github/workflows/ci.yml`
(**different blocks** — a dev-only migration command in CI is a real bug); `deploy.yml` filled or
deleted per the pack's conflict register; a real `.env.example`; the remaining `ci.yml` gates the
pack doesn't cover — i18n key parity, migration up/down round-trip, a11y scan.
- **Primary form factor** in `apps/frontend/CLAUDE.md` — `mobile-first`, `desktop-first` or
`responsive-equal`. Ask; it isn't inferable and it changes every screen.
- **Rebrand and confirm the design guide** — edit the *primitive* tier in `design/tokens.css` to the
project's brand, open `design/design-guide.html`, and have the user confirm it reads as one system.
**This gates everything visual** — no screen gets built against an unconfirmed system.
- **Copy runtime config** — `.env` and any secrets, which don't come from the template.
## 4 · Write `specs/product.md`
Every path writes it. It is the product's constitution — the durable answer to *what is this*, which
every later stage reads before doing anything. Build it from `choice.json` **plus whatever the
conversation has already established** — constraints, audience, non-goals the user has mentioned:
```markdown
# <name>
<one-liner>
## What it is
<building · kind, in plain words — and anything the conversation added>
## Stack
<pack + add-ons | the detected stack, verbatim from the confirm screen | "Specs & design only — no development setup yet">
## Constraints & principles
<only what's actually been said — never invent principles to fill the section>
```
Thin is fine. A three-line `product.md` that is all true beats a page of boilerplate.
## 5 · Hand back the repo-level steps *(full setup only)*
Protect `main` with a required-CI rule, stand up staging if the pack defines one, confirm the first CI
run is green. **Don't do these unasked** — print them as a checklist and offer to run any of them.
Branch protection must come *after* the first green push, or a required-status rule rejects a branch
whose CI has never run.
Then confirm no placeholder survived — both must return nothing:
```bash
grep -rn 'FILL IN ON SETUP\|TODO: replace' . --exclude-dir=stacks --exclude-dir=specs --exclude-dir=.git \
| grep -v '^\./README\.md:'
grep -n '^<pm> ' CLAUDE.md
```
Delete the template's own root `README.md` once instantiation is done — its Day-1 checklist is spent.
## Notes
- **Never edit `assets/chooser.html` or `chooser-server.mjs`** to fit a project — they're the engine. The shell chrome is stamped in from `lib/shell/` — see `lib/shell/README.md`.
- The form is a **one-shot** by design: it asks once, so it doesn't use the live-link machinery behind
`wireframe` and `user-story-map`. Don't wire it into them.
- Unknown directories still work. A pack or add-on with no built-in blurb renders from its own README,
so an upstream addition never breaks the page.
- Flags: `--out` moves `choice.json`; `--port` moves the port (busy usually means a form is already
up); `--project` names the project when `--repo` doesn't exist yet; `--mode existing` +
`--prefill <file>` is the existing-app path.
- The page always sends straight to the server — there is no copy-paste fallback. If the server has
gone away it shows a retry state and keeps the answers until the tab closes, so if a send fails,
restart the server and have the user press *Try again*.
- The **snapshot catalog** inside `chooser-server.mjs` mirrors the template's packs and add-ons. If
the template gains one, add it there too — fresh mode can't scan what isn't cloned yet.
## State & handoff
- **Read** nothing — this is where the pipeline begins.
- **Write** `specs/product.md` and `<repo>/.vstack/pipeline.json`, the file every later stage reads:
```json
{ "version": 1, "project": "<name>", "stage": "start", "phase": null,
"specsOnly": false,
"artifacts": { "product": "specs/product.md", "stack": "<pack>", "addOns": ["…"] },
"history": [{ "stage": "start", "at": "<iso>", "note": "<pack> + N add-ons" }] }
```
`"specsOnly": true` and no `stack`/`addOns` keys on the skip-dev path; in existing mode `stack` is
the detected description rather than a pack id. Commit it — it's a project record, not scratch.
Keep `.vstack/choice.json` beside it as the raw answer.
- **Next** — `/vstack:requirements` writes `specs/requirements.md`. **That stage isn't built yet**;
until it is, say so and offer to write `specs/requirements.md` by hand together, or go straight to
a first screen with `/vstack:review`. Don't invent a requirements stage to fill the gap. From
there the built chain runs `wireframe → spec → user-story-map → phase-preview → phase-build`.
The former `/vstack:go` router is no longer part of the pipeline; it is a compatibility alias for
the wireframe tool.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!