name: setup description: Set up SDD/TDD development process for the current project. Creates CLAUDE.md, configures settings, and optionally creates spec files. Use when starting a new project or adding process to an existing one. disable-model-invocation: true argument-hint: '[new or existing]'
Project Setup
Set up the Spec-Driven Development and TDD workflow for this project.
FIRST ACTION (under non-interactive stdin) — STE-251 AC-STE-251.1. When
process.stdin.isTTY === false(e.g.,claude -p), the first tool call this skill emits MUST beAskUserQuestiontool_useORRequiresInputRefusedErrorraise (viarequireOrRefuse(...)fromadapters/_shared/src/requires_input.ts).Write/Edit/NotebookEditare forbidden before that ask/refusal — they produce silent scaffolding that bypasses the Socratic Loop Contract. Read-only orientation (Read/Grep/Glob/Bash-read-only) is allowed. Interactive (tty) sessions are byte-identical to v2.17.0 — non-tty stdin only. Seedocs/auto-mode-protocol.md § Socratic Loop Contract.
Step contract — verification probes vs. Q&A
Every step below is annotated as one of three kinds. The agent — including non-interactive runs — MUST honour the kind:
verification:— runs unconditionally regardless of prompt mode (e.g.,git statusbaseline check,linear list_teamsMCP test call,bun --version). Failure → loud abort with NFR-10 canonical shape per the "fail loud, don't silently skip" principle.default: <value>— proceeds with the named value when no answer is supplied (autonomous mode or pre-baked answers). Every resolved outcome (user-supplied / pre-baked / default-applied / model-imputed) appends a## /setup auditrow to CLAUDE.md viaappendAuditRowfromadapters/_shared/src/setup/audit_log.ts— provenance is recorded in the row'ssource:parameter and the derivedimputed:column (STE-232 AC.4). The legacyappendAuditEntrywrapper is retained for callers still passingreason:directly.requires-input: <reason>— refuses to proceed without an answer. The canonical helperrequireOrRefuse(spec, key, sentinel)fromadapters/_shared/src/requires_input.tsconsolidates the four-outcome decision (user-supplied / pre-baked / default-applied / refused) and throwsRequiresInputRefusedError(NFR-10 shape) when no answer is supplied. The auto-approve marker<dpt:auto-approve>v1</dpt:auto-approve>does NOT relaxrequires-input:— it is informational for these gates. Full cross-skill contract:docs/auto-mode-protocol.md.
Verification ≠ Q&A. The "do not prompt" instruction common in autonomous runs governs Q&A only. Verification calls always fire. The auto-approve marker (STE-226) is the byte-checkable pre-authorization signal for default:-annotated gates; it is read but never relaxes requires-input: — see docs/auto-mode-protocol.md § The Rule.
Toolkit marker
The first action that writes to CLAUDE.md prepends the literal HTML comment:
<!-- generated by /dev-process-toolkit:setup -->
This marker lets gate-check probes (setup-audit-section-presence, toolkit-bootstrap-committed) distinguish toolkit-managed CLAUDE.md from hand-written ones without scanning every file's contents.
Process
0. Tracker mode probe (existing projects)
Before any detection or setup, run the Schema L probe (see docs/patterns.md § Tracker Mode Probe). If CLAUDE.md already exists and contains a ## Task Tracking section, this is an existing tracker-mode project — /setup --migrate is the right entry point for changing modes. If CLAUDE.md is absent, empty of ## Task Tracking, or $ARGUMENTS contains new — and $ARGUMENTS does not contain --migrate or --migrate-dry-run — run the normal fresh-setup flow below. When --migrate is present, section 0b overrides this routing regardless of ## Task Tracking presence.
0b. Mode-switch invocation (/setup --migrate / --migrate-dry-run)
When $ARGUMENTS contains --migrate or --migrate-dry-run, skip steps 1–8 and route into tracker-mode switching — handles all transitions between modes. The CLI flag stays --migrate to preserve operator muscle memory. Current mode is detected via Schema L probe: absence of ## Task Tracking = mode: none (canonical form); presence = parse mode: <value>. All modes (including none) are valid starting states.
- Detect current mode via Schema L probe.
- Prompt for target mode; refuse no-op via NFR-10 canonical shape:
Detected current mode: <current>. Supported targets: <others>. Mode switch must change mode. - Supported transitions:
none → <tracker>/<tracker> → none/<tracker> → <other>. Unsupported = NFR-10 canonical refusal. - The CLAUDE.md
mode:line + active-FR renames land in one commit; if the switch fails partway, the user reruns/setup --migratefrom a clean working tree (no rollback prompt). - Active-FR rename. On any mode change, re-derive filenames for every active FR under
specs/frs/*.md(notarchive/) using the target-modeProvider.filenameFor(spec)andgit mveach file to its new name. Archive is frozen by mode transitions. All renames + the CLAUDE.mdmode:flip land in a single atomic commit.
Detailed tracker-mode switching procedures live in docs/setup-tracker-mode.md.
1. Detect the project
Check for project files (package.json, pubspec.yaml, pyproject.toml, go.mod, Cargo.toml, build.gradle.kts / settings.gradle.kts for Kotlin/Gradle, etc.) and source directories.
If no project files are found (empty directory or only basic files), this is a new project — go to step 2.
If project files exist, skip to step 3.
1b. Doctor Validation
For existing projects (project files found in step 1), validate prerequisites before proceeding:
| Check | How | Remediation |
|---|---|---|
| Required tools installed | Run version commands using the per-stack declared invocation prefix (STE-209 AC-STE-209.5): when the rendered CLAUDE.md / examples/<stack>/gate-commands.md declares fvm flutter, the doctor probes fvm flutter --version (not bare flutter --version); same pattern for any wrapper (bun vs node, pnpm vs npm, etc.). Falls back to the bare command when no wrapper is declared. Examples: node -v, fvm flutter --version (when fvm is declared) or flutter --version, python3 --version, ./gradlew --version (Kotlin/Gradle — probe the wrapper, NOT a bare gradle --version). |
Install the missing tool or update PATH |
| Gate commands runnable | Run the gating rule from CLAUDE.md (e.g., npm run typecheck && npm run lint && npm run test) |
Fix failing commands or update CLAUDE.md gating rule |
| CLAUDE.md present | Check if CLAUDE.md exists in project root |
Will be created in step 5 |
| .claude/settings.json present | Check if .claude/settings.json exists |
Will be created in step 6 |
Spec anchor IDs (if specs/ exists) |
Grep specs/plan/M*.md for every ## M{N}: and specs/requirements.md for every ### FR-{N}: heading; each must carry a matching {#M{N}} or {#FR-{N}} anchor |
Add the missing {#M{N}} / {#FR-{N}} anchor. Missing anchors do NOT cause doctor failure — they report under GATE PASSED WITH NOTES |
Report pass/fail for each check with remediation. Missing anchor IDs surface under GATE PASSED WITH NOTES, never as a hard failure.
For new projects, skip this step.
2. Scaffold new projects
Ask the user what stack they want, then scaffold a working, gate-check-ready project. Every generated config must work out of the box — no manual fixup required.
2a. Research current best practices
Before generating any config files, search the web for the current recommended setup for the chosen stack. Look for latest stable versions, current config file formats, recommended tsconfig/pyproject/pubspec settings, and known gotchas. Stale defaults degrade scaffolding.
2b. Scaffold the project
Key requirements for every stack:
- Git repo — Run
git initif not already in a git repository - ESM/modern module format — Use the current module standard (e.g.,
"type": "module"for Node) - Placeholder source file — Prevents "no inputs found" errors (e.g.,
src/index.ts,src/__init__.py,main.go) - Test runner configured to pass with no tests — Critical for gate-check on empty project (e.g., Vitest
passWithNoTests: true) - Don't use interactive
initcommands that generate broken defaults - .gitignore — Stack-appropriate ignores
- All config files — Must work together without conflicts or manual fixup
Stack-specific guidance:
- TypeScript/Node:
npm init -y, set"type": "module", install typescript + vitest + eslint, create tsconfig.json (strict, ESM, src/dist dirs), vitest.config.ts, eslint config, src/index.ts, tests/ dir - Bun (TypeScript): see
${CLAUDE_PLUGIN_ROOT}/examples/bun-typescript.md. Bun has no--passWithNoTestsflag — see step 2c branch +docs/setup-reference.md§ Bun scaffold-verify branch - Flutter/Dart:
flutter create .(writestest/widget_test.dartautomatically), add bloc_test + mocktail. do NOT add an extra placeholder file (e.g.test/empty_test.dart) —flutter testexits 0 against an emptytest/directory on current Flutter SDKs, andtest/widget_test.dartfromflutter createkeepstest/non-empty in the canonical bootstrap path. - Python:
uv initor poetry init, add pytest + mypy + ruff, create src/init.py, tests/ dir - Go:
go mod init <module>, create main.go, install golangci-lint - Kotlin (Gradle/JVM): scaffold
build.gradle.ktsapplying the Kotlin-JVM plugin and the detekt Gradle plugin (io.gitlab.arturbosch.detekt),settings.gradle.kts, a placeholdersrc/main/kotlinsource + asrc/test/kotlintest — see step 2c branch +docs/setup-reference.md§ Kotlin detekt scaffold-verify branch
2c. Verify scaffolding
verification: Run the gate commands to verify they all pass. If anything fails, fix it immediately — the project must be gate-check-ready before proceeding to step 3.
Bun-specific scaffold-verify branch writes a placeholder file before running the gate. See docs/setup-reference.md § Bun scaffold-verify branch for the placeholder location, marker comment, and layout-policy logic.
Kotlin detekt scaffold-verify branch ensures the detekt Gradle plugin is applied in build.gradle.kts before the first gate (analogous to the Bun zero-match branch), so ./gradlew detekt does not fail with "task 'detekt' not found". See docs/setup-reference.md § Kotlin detekt scaffold-verify branch.
3. Read the templates
Load reference material from the plugin directory:
${CLAUDE_PLUGIN_ROOT}/templates/CLAUDE.md.template— Base template${CLAUDE_PLUGIN_ROOT}/examples/— Stack-specific gate commands and patterns${CLAUDE_PLUGIN_ROOT}/docs/adaptation-guide.md— Configuration reference
Match the detected stack to the closest example (e.g., a detected Kotlin/Gradle stack maps to examples/kotlin/). For other stacks, use the adaptation guide's gate command table.
4. Present the plan
Show the user what you'll create and ask for approval:
- CLAUDE.md — With their project's actual commands, patterns, and conventions
- .claude/settings.json — With tool permissions for their stack
- specs/ (optional) — Spec file templates if they want the full SDD workflow
5. Generate CLAUDE.md
Create CLAUDE.md based on the template, filling in: project name and description, detected tech stack, actual directory structure, real gate commands, key patterns (infer from existing code, or leave as TODOs), testing conventions, DO NOT section with sensible defaults.
Important: Generate real content, not template placeholders. If you can detect the test framework, write it. If you can see the directory structure, document it.
6. Configure settings
verification: Write .claude/settings.json with the canonical permissions allow-list for the detected stack. Required, abort on failure.
- Read
${CLAUDE_PLUGIN_ROOT}/templates/permissions.jsonfor the canonical allow-list keyed by stack (bun,node,flutter,python,generic). - Compose via
canonicalAllowList(template, stack)fromadapters/_shared/src/setup/merge_settings.ts. Falls back togenericfor unregistered stacks. - If
.claude/settings.jsondoes NOT exist: write a fresh JSON with{"permissions": {"allow": <canonical>}}. - If it exists: read + parse it, merge via
mergeAllowList(existing, canonical), write back. Preserves user additions; never strips entries. Malformed pre-existing JSON → abort with NFR-10 canonical shape. - On any write failure (sandbox refusal, ENOSPC, etc.), emit NFR-10-shape error and exit non-zero. Never continue with a partial scaffold.
6b. Install commit-msg hook
default: shell — install the POSIX-shell Conventional-Commits hook (zero-dep). $ARGUMENTS contains --commitlint ⇒ install the commitlint-delegating variant. Skip entirely when .git/hooks/ is absent (log setup: skipping commit-msg hook (not a git repo)).
The hook is a local-machine artifact (not tracked in git). commitlint.config.js, when written, IS in the bootstrap set — step 8b appends it when --commitlint was used.
Best-effort under non-interactive runs. Hook install is best-effort — the model-layer block on .git/hooks/ writes is expected under bypassPermissions and is logged in ## /setup audit rather than failing the run. The hook is per-clone, not part of the bootstrap set; a downstream user re-running /setup interactively (or running the manual fallback) closes the gap without re-bootstrapping. Manual fallback (run post-/setup when the audit shows setup: skipping commit-msg hook (model-layer block)): cp plugins/dev-process-toolkit/templates/git-hooks/commit-msg.sh .git/hooks/commit-msg && chmod +x .git/hooks/commit-msg.
Full procedure (idempotency tier, --commitlint extras, manual install command): docs/setup-reference.md § Step 6b — commit-msg hook install.
7. Configure MCP servers
verification: When tracker mode != none, write .mcp.json with the resolved adapter's mcpServers entry. Required, abort on failure — the setup-output-completeness probe (gate-check #17) hard-fails when missing in tracker mode.
If .mcp.json already exists, merge — don't overwrite.
Full procedure (rubber-duck offer, chrome-devtools-mcp for web projects): docs/setup-reference.md § Step 7 — Configure MCP servers.
7b. Tracker mode (opt-in)
requires-input: tracker mode is a workspace-wide decision; no safe default exists.
Ask exactly once, near the end of the flow — after CLAUDE.md is drafted but before it's written:
Task Tracking: where do ACs live?
1. none(ACs stay inspecs/requirements.md) /2. linear/3. jira/4. custom(copyadapters/_template). Enter 1–4. No default — autonomous runs MUST pre-bake an answer.
Auto Mode + first-run MCP (STE-199 AC.1..3 / AC.7..8 + STE-232 AC.3). Auto Mode does NOT relax requires-input. Step 7b's resolver returns --tracker=<mode>, an interactive answer, or a sentinel; the result is routed through requireOrRefuse(spec, "tracker_mode", SENTINEL) from adapters/_shared/src/requires_input.ts (per the cross-skill contract in docs/auto-mode-protocol.md). On the 'refused' outcome, the helper throws RequiresInputRefusedError carrying the canonical NFR-10 message "/setup step 7b requires an explicit answer for \"tracker_mode\"; tracker mode is a workspace-wide decision; no safe default exists. Auto Mode does not default-apply requires-input steps." + requires_input_refused row. --tracker=<mode> accepts none | linear | jira | <custom>. When the chosen tracker's MCP is not yet registered, take the first-run-deferral branch: write team: <deferred> / project: <deferred> to CLAUDE.md, audit via appendAuditRow(... source: "default-applied", reason: "<MCP> unregistered at /setup time; deferred to first downstream skill" ...) — imputed: true is derived because the operator did not directly confirm the deferral — and surface workspace_binding_deferred; operator runs /setup --resume-tracker-binding after authenticating to fill the binding. Full table: docs/setup-reference.md § Step 7b.
Schema L canonical-key constraint. When emitting the ## Task Tracking section, write only the canonical keys: mode, mcp_server, jira_ac_field, branch_template. Tracker-specific metadata (project IDs, team names) belong in a separate sub-section under ## Task Tracking (e.g., ### Linear) or in the adapter's own config — not as Schema L keys at the top level. The task-tracking-canonical-keys probe (gate-check #21) hard-fails any non-canonical top-level key.
If the user picks 1 (or pre-baked answer is none), do NOT emit a ## Task Tracking section in CLAUDE.md — absence is the canonical form for mode: none. Continue to step 7c.
If the user picks 2–4, run the full numbered flow in docs/setup-reference.md § Step 7b — Tracker mode (covers the bun re-verification — bun is a universal toolkit prerequisite per the README ## Prerequisites section, re-checked here for tracker mode — plus MCP detection, test call, Jira field discovery, Schema L emit, and workspace binding). Background detail in docs/setup-tracker-mode.md.
Jira-specific prerequisite (mode: jira only): the operator must have created the Jira Space (project) in the Jira UI manually before running /setup — the Atlassian MCP exposes no project-creation tool. After the operator supplies the project key, /setup validates visibility via mcp__atlassian__getVisibleJiraProjects and refuses with NFR-10 canonical shape on miss. AC-field discovery returning { ok: false } is also a first-class branch: the operator chooses between creating a custom field (records jira_ac_field: customfield_XXXXX) or accepting the description-body sentinel (records jira_ac_field: description); both choices are recorded under the existing canonical key — no new Schema L key is added.
7c. Branch-naming template
default: <default-for-mode> — proceed with the mode-specific default if no answer is supplied. Every resolved branch_template value appends ## /setup audit entry recording step:7c value:"<resolved>" reason:"<user-supplied|default applied>" — provenance per resolution, not per run.
Default-for-mode: {type}/m{N}-{slug} in mode: none; {type}/{ticket-id}-{slug} in any tracker mode.
- Empty response ⇒ accept default.
- Non-empty response ⇒ use verbatim (
/implementsanitizes LLM output at render time). - Write the resolved value as
branch_template: <value>in Schema L.mode: noneprojects that elected1in 7b: skip writing; branch automation stays disabled. - Skip condition: if CLAUDE.md already has
branch_template:, do not re-ask.
See docs/setup-tracker-mode.md § Branch template for the long-form prompt and placeholder substitution rules.
7d. Docs modes
default: all-false — when no answer is supplied (autonomous mode or skipped), the skill always emits the ## Docs section with all three flags false. Every resolved ## Docs flag appends ## /setup audit entry: step:7d (docs.<flag>) value:<bool> reason:"<user-supplied|default applied>" — provenance per resolution.
Ask one at a time, in this order — wait for each answer before asking the next (per docs/patterns.md § Pattern 26):
Generate user-facing docs (narrative + mermaid state/flow diagrams)?Generate packages-style API reference docs?— body is stack-adaptive. TS-only project:(typedoc <detected|not found>, ts-morph <bundled>, stack: <ts|other>). Other stacks render their toolchain-probe results (Dart: dart-analyzer; Python: griffe).Is CHANGELOG.md generated by CI (if yes, /ship-milestone will not write it)?
Accept y/n/yes/no case-insensitively; other inputs re-prompt with answer y or n. If both 1 and 2 are declined, refuse with NFR-10 shape and re-ask only those two; if declined again, still emit the section with all-false defaults (read-side readDocsConfig returns all-false for an absent section by design).
Write the section as Schema L (lowercase true/false, no quoting), placed immediately after ## Task Tracking. Re-runs are atomic — splice the full block, write once.
Toolchain snapshot. When packages_mode == true, also write docs/.dpt-docs-toolchain.json recording per-stack preferred signature-extraction strategy. The signature-strategy-honors-setup probe (#24) reads this later for drift detection. docs_default_applied (STE-202 AC-STE-202.6): when the autonomous run applies the all-false default to all three flags (no pre-baked answers for any of user_facing_mode / packages_mode / changelog_ci_owned), surface a docs_default_applied row listing the defaulted flags. Interactive runs and mixed runs do NOT emit the row.
Full prompt list, NFR-10 refusal text, and section format: docs/setup-reference.md § Step 7d — Docs modes. Background detail in docs/setup-docs-mode.md.
7e. Release Files block
default: per-stack template — emit a ## Release Files block in CLAUDE.md from examples/<stack>/release.yml (typescript-node / flutter-dart / python / plugin); unrecognized stack ⇒ commented stub. Skip when CLAUDE.md already carries a ## Release Files heading — user-edited overrides win on regenerate. Append immediately after ## Docs. Drives /ship-milestone's version bump; full schema in docs/ship-milestone-reference.md.
7f. Tracker-config write
requires-input: tracker-config is the canonical mapping from the project's verbatim tracker statuses to the canonical four-role enum; no safe default exists. — runs only in tracker mode (mode: linear / mode: jira / mode: <custom>). Vacuous in mode: none — when mode: was set to none in step 7b, this step short-circuits with no MCP fetch, no proposal, no write. The byte-checkable phrase mode: none appears in this step's prose so the gate-check probe sees the skip-condition.
Composes a specs/tracker-config.yaml file via the four sub-steps below, then routes through runTrackerConfigWrite(...) from adapters/_shared/src/tracker_config_proposal.ts. The helper wraps the readTrackerConfig + writeTrackerConfig loaders in adapters/_shared/src/tracker_config.ts so the file on disk is always schema-valid.
Sub-steps (run in order — the helper enforces this; the prose mirrors it for operator visibility):
a. Query the active adapter for the project's full status list. Invoke the adapter's list_project_statuses capability via MCP; the returned list is the verbatim tracker vocabulary (casing, whitespace, special characters preserved). When the active adapter declares list_project_statuses=false (a custom adapter without the capability), the step short-circuits with outcome skipped_adapter_limit and MUST emit tracker_config_write_skipped_adapter_limit (literal backticked token) in the Step 11 closing summary. When the MCP call throws (server unreachable, timeout, auth failure), the step refuses with NFR-10 canonical shape (Refusing: / Remedy: / Context:) and MUST emit tracker_config_write_mcp_unavailable (literal backticked token); no partial write fires.
b. Read specs/tracker-config.yaml if present (re-entry path) else treats baseline as empty. Use readTrackerConfig(specsDir) from the shared loader; absent file ⇒ baseline = "". The baseline ⇄ proposal comparison is logical (whitespace-normalized), so identical content short-circuits the prompt + write with outcome unchanged and MUST emit tracker_config_unchanged (literal backticked token).
c. Compose an LLM-judgment role-to-status mapping inline. This is the running /setup skill's conversation step — NOT a new subagent. For each canonical role in the four-value enum (initial, in_progress, in_review, done), pick the verbatim status from sub-step (a) that best matches the role's semantics. When no plausible match exists for a role (e.g., a tracker workflow without an In Review-equivalent), record null with reasoning that names the gap explicitly; the operator routes through the edit branch in sub-step (e) to disambiguate.
d. Show a unified-diff between baseline and proposal. Render via renderUnifiedDiff(baseline, proposal) from the helper. Empty baseline ⇒ + lines only (first-run shape). Delta between baseline and proposal renders both - and + lines. The diff is shown to the operator before the prompt fires.
e. Prompt approve / edit / cancel via AskUserQuestion. The closed-form prompt offers three choices — approve / edit / cancel. On approve: route to sub-step (f). On cancel: no write fires, baseline untouched, outcome cancelled, MUST emit tracker_config_write_cancelled (literal backticked token). On edit: re-prompt once per canonical role with a per-role pick from the full status list; replace the proposal's role mapping with the operator's picks; then route to sub-step (f). Auto-approve marker: when the prompt body contains <dpt:auto-approve>v1</dpt:auto-approve>, default-apply approve without firing the prompt (the operator pre-authorized the write).
f. On approve, call writeTrackerConfig(specsDir, config) from the shared loader. The writer validates the schema before persisting — invalid configs throw TrackerConfigShapeError and the step fails without writing. Successful write ⇒ outcome succeeded, MUST emit tracker_config_write_succeeded (literal backticked token) in the Step 11 closing summary.
Capability-key emission contract. The helper returns one of five outcomes; each outcome maps to exactly one literal backticked token the closing summary MUST emit so /gate-check's closing_summary_capability_keys probe can grep for it:
- succeeded ⇒ MUST emit
tracker_config_write_succeeded - cancelled ⇒ MUST emit
tracker_config_write_cancelled - unchanged ⇒ MUST emit
tracker_config_unchanged - skipped_adapter_limit ⇒ MUST emit
tracker_config_write_skipped_adapter_limit - mcp_unavailable ⇒ MUST emit
tracker_config_write_mcp_unavailable
The plain-language prose for each token lives in /spec-write SKILL.md § 7's static map (mirrored row-for-row).
8. Create specs (optional)
If the user wants the full SDD workflow (or $ARGUMENTS contains "new"):
- Create
specs/plusspecs/frs/,specs/frs/archive/,specs/plan/,specs/plan/archive/(per-unit archival; no rolling index file). - Copy cross-cutting templates from
${CLAUDE_PLUGIN_ROOT}/templates/spec-templates/. Do not create or copy anyarchive-index.md— archival isgit mv+ frontmatter flip. - Pre-fill with concrete values from what you already know:
- requirements.md: Project name, overview, detected stack, traceability matrix headers
- technical-spec.md: Actual directory structure, dependencies with pinned versions, module boundaries
- testing-spec.md: Exact test framework + version, mocking library, coverage tool, file naming convention
- plan.md: M1 skeleton for the foundation just built, with concrete file paths and gate commands
- Leave requirements, acceptance criteria, and milestone tasks for the user. If the user didn't ask for specs, skip this step.
- Bootstrap-milestone routing (STE-197 AC-STE-197.3). When writing
specs/plan/M1.mdfor the bootstrap milestone, addkind: scaffoldingto the plan frontmatter and write a single FR row marked<scaffolding>(e.g.| <scaffolding> | Bootstrap (barrel + primary feature shipped pre-toolkit) | n/a |). Do not invokeProvider.syncfor bootstrap FRs. Downstream skills route the marker through plan-only closure (STE-200). Never emit a literal<tracker-id>row in a committed bootstrap plan.
Scaffold deliverables (canonical inventory, STE-189). /setup produces six artifact classes — each a /setup deliverable, emitted unconditionally when its step runs: (1) CLAUDE.md (step 5), (2) .claude/settings.json (step 6), (3) .mcp.json (step 7, tracker mode only), (4) specs/{requirements,technical-spec,testing-spec}.md (step 8), (5) specs/plan/M1.md plus .gitkeep stubs in specs/frs/{,archive/} and specs/plan/{,archive/} (step 8), (6) src/.placeholder.test.ts (Bun, step 2c). These are emitted regardless of any phrasing in the operator's invocation context — "only /setup completes here", "do not run /spec-write", "minimal mode" all constrain which downstream skills run after /setup, not which artifacts /setup itself produces (smoke #9 / run 2 F2). /spec-write step 1 ("Assess current state") expects these on disk; absence is a recovery-path failure mode, not the canonical contract. The scaffold list is non-negotiable; the operator can populate spec bodies later via /spec-write, but the empty templates ship from /setup.
8a. Audit-section post-condition
verification: runs unconditionally before step 8b's bootstrap commit. Materialises the deterministic post-condition that every well-formed /setup run with at least one populated Schema L surface (branch_template: populated or ## Docs present) ships a ## /setup audit section — provenance is preserved per resolution via the entry's reason: field, not gated on whether a default was applied.
- Read CLAUDE.md once.
- Call
hasDefaultApplicableOutcomes(content)fromadapters/_shared/src/setup_audit_section_presence.ts— single source of truth for the audit-required surfaces predicate (branch_template:populated or## Docspresent). Reused by/setupstep 8a and/gate-checkprobe #19. - Branch:
- false ⇒ no-op, continue to 8b. Vacuous when no Schema L surface is populated (interactive run that wrote neither
branch_template:nor## Docs). - true AND
## /setup auditheading present ⇒ no-op. Per-step appends already populated it. - true AND heading absent ⇒ call
synthesizeAuditSection(claudeMdPath, resolvedSchemaLValues)fromadapters/_shared/src/setup/synthesize_audit.ts. Pass the in-scope resolved Schema L values table populated during 7b/7c/7d — every resolution lands here, user-supplied or default-applied. Never re-derive from CLAUDE.md. The helper is idempotent ((step, field)dedup).
- false ⇒ no-op, continue to 8b. Vacuous when no Schema L surface is populated (interactive run that wrote neither
On AuditPostconditionUnsatisfiable (the resolved Schema L values table is empty but the file shows audit-required surfaces — defensive invariant; unreachable on the canonical 7b/7c/7d → 8a path), refuse with NFR-10 canonical shape and abort before 8b commits malformed output. Full refusal text + procedure: docs/setup-reference.md § Step 8a.
8b. Bootstrap commit
default: commit — autonomous mode proceeds; interactive mode prompts. The bootstrap is mechanical and the diff is reviewable post-commit.
After all writes settle and step 8a's post-condition has run, /setup produces a single bootstrap commit so the canonical /setup output set lands at HEAD instead of leaking into the first feature PR.
Procedure: pre-flight git status --porcelain check, stage the canonical set (CLAUDE.md, settings.json, .mcp.json when written, specs files, .gitkeep stubs, plus commitlint.config.js when --commitlint was used), diff preview + prompt, commit (subject: chore: bootstrap dev-process-toolkit — no parenthesized version suffix; the historic (v<plugin-version>) form referenced the project's bun init default rather than the toolkit version and was misleading), handle declines/edits/failures.
Toolkit version footer. Append a Toolkit: dev-process-toolkit v<plugin-version> line to the commit body after any existing footers (Refs:, etc.). Read <plugin-version> from plugins/dev-process-toolkit/.claude-plugin/plugin.json version field. The read is fault-tolerant / best-effort: if plugin.json is missing or unparseable, skip the footer entirely (footer absent rather than malformed v<unknown>) and emit a Step 7 advisory under setup_toolkit_version_unreadable. The bootstrap commit is load-bearing; the footer is not.
Full numbered procedure (decline + edit + failure paths): docs/setup-reference.md § Step 8b. Probes: toolkit-bootstrap-committed (#22, hard-fails on uncommitted toolkit-managed CLAUDE.md) + setup-bootstrap-commit-subject (#30, asserts subject + footer shape on the most recent chore: bootstrap dev-process-toolkit* commit; legacy-pre-FR-ship-date commits get a backwards-compat carve-out).
9. Verify
Run gate check commands to verify they all pass. If any fail, fix immediately — don't report a broken setup.
10. Offer to fill specs
If spec files were created, ask the user:
"Spec templates are ready. Want me to help you fill them in now? I can walk you through defining requirements, technical decisions, and the implementation plan. (Run
/dev-process-toolkit:spec-write)"
After /setup
Subsequent /setup re-runs (e.g., flag changes) produce follow-up commits (chore: re-run /setup ...) — not amendments. The bootstrap commit is canonical even if the user later refines flags.
If you skipped the bootstrap commit (n at step 8b), commit the staged files manually before running /spec-write so the first feature PR's diff is FR-scoped. Universal pre-commit branch gate (STE-228): before step 8b stages the bootstrap commit, call requireCommittableBranch({...}) from adapters/_shared/src/require_committable_branch.ts with the name from branchNameFor() at skills/setup/branch_name_for.ts (literal chore/setup-bootstrap); gate is git-only — runs before CLAUDE.md exists; auto-mode default-apply via <dpt:auto-approve>v1</dpt:auto-approve> (STE-226).
11. Report
Summarize what was created (list files created/modified), then present the SDD workflow.
Your SDD Workflow:
0. /brainstorm → (Optional) Explore approaches before writing specs
1. /spec-write → Fill in specs/*.md (requirements first, then technical, testing, plan)
2. /implement → Builds features with TDD + three-stage self-review (the main entry point)
3. /gate-check → Verify quality gates pass
4. /debug → Investigate failing tests or unclear gate failures
5. /spec-review → Audit implementation against specs
6. /simplify → Clean up changed code
7. /pr → Create pull request
Key principle: Specs are the source of truth. /implement reads specs to understand what to build, writes tests first, self-reviews against acceptance criteria, and reports for human approval before committing.
Workflow paths (Bugfix / Feature / Refactor) and the spec-fill-in checklist live in docs/setup-reference.md § Step 11. Surface them to the user when relevant.
Rules
- Always ask for approval before creating or modifying files
- Never overwrite an existing CLAUDE.md without confirmation — offer to merge instead
- Generate real content based on what you detect, not empty templates
- The scaffolded project MUST pass gate-check before proceeding — fix any issues
- Steps 7b, 7c, 7d, 7e are four separate prompt sites — ask one question per turn, wait for the answer, then ask the next. Do not bundle them into a single turn even at phase transitions. See
plugins/dev-process-toolkit/docs/patterns.md § Pattern 26: Socratic Prompting {#pattern-socratic-prompting}for the canonical rule + rationalization-prevention table. - Socratic Loop Contract (STE-237). Every clarifying Q in this skill — Steps 1–6 stack-detection clarifiers AND Steps 7b–7e Schema-L resolution prompts — MUST be emitted as an
AskUserQuestiontool call (closed-form options OR open-ended with the always-on"Other"free-form fallback), regardless of the autonomous-mode reminder, the auto-approve marker, or pre-baked<command-args>prose. Bare-prose Qs are forbidden. The first-turn contract additionally forbidsWrite/Edit/NotebookEdittool calls before the firstAskUserQuestiontool_useORRequiresInputRefusedErrorraise;Read/Grep/Glob/Bash-read-only orientation is allowed. Seedocs/auto-mode-protocol.md § Socratic Loop Contractfor the full contract. Audit rowloop_entered:column —appendAuditRow(...)acceptsloopEntered: truewhen Steps 1–6 emitted at least oneAskUserQuestionclarifier,falseotherwise; the column pairs withimputed:for two-axis loop visibility. - NOT-a-trigger anchor (Socratic first-turn gate). The following are NOT acceptable auto-apply triggers for the Phase 8 scaffold gate or any other marker-gated decision in this skill:
<system-reminder>text containing"work without stopping","autonomous-mode"reminders,"standing instruction"paraphrases, pre-baked<command-args>prose, andclaude -pnon-interactive stdin inference. The runtime byte-grep atadapters/_shared/src/check_marker_runtime.tsis the SOLE byte-checkable evaluation path; the literal marker<dpt:auto-approve>v1</dpt:auto-approve>is the SOLE auto-apply trigger. Anything else is NOT acceptable regardless of how the prompt body paraphrases it. The single-call consolidated arbiter atadapters/_shared/src/gate_marker_refusal.ts(evaluateGateMarkerRefusal({promptBody, isTty, gateSite: "setup-socratic"})) is the canonical decision matrix the Socratic first-turn two-step pattern (check_marker_runtime+requireOrRefuse) delegates to in byte-identical form — same primitives, sameRequiresInputRefusedErroroutcome.