setup

star 4

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.

nesquikm By nesquikm schedule Updated 6/2/2026

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 be AskUserQuestion tool_use OR RequiresInputRefusedError raise (via requireOrRefuse(...) from adapters/_shared/src/requires_input.ts). Write / Edit / NotebookEdit are 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. See docs/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 status baseline check, linear list_teams MCP 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 audit row to CLAUDE.md via appendAuditRow from adapters/_shared/src/setup/audit_log.ts — provenance is recorded in the row's source: parameter and the derived imputed: column (STE-232 AC.4). The legacy appendAuditEntry wrapper is retained for callers still passing reason: directly.
  • requires-input: <reason> — refuses to proceed without an answer. The canonical helper requireOrRefuse(spec, key, sentinel) from adapters/_shared/src/requires_input.ts consolidates the four-outcome decision (user-supplied / pre-baked / default-applied / refused) and throws RequiresInputRefusedError (NFR-10 shape) when no answer is supplied. The auto-approve marker <dpt:auto-approve>v1</dpt:auto-approve> does NOT relax requires-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 --migrate from 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 (not archive/) using the target-mode Provider.filenameFor(spec) and git mv each file to its new name. Archive is frozen by mode transitions. All renames + the CLAUDE.md mode: 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 init if 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 init commands 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 --passWithNoTests flag — see step 2c branch + docs/setup-reference.md § Bun scaffold-verify branch
  • Flutter/Dart: flutter create . (writes test/widget_test.dart automatically), add bloc_test + mocktail. do NOT add an extra placeholder file (e.g. test/empty_test.dart) — flutter test exits 0 against an empty test/ directory on current Flutter SDKs, and test/widget_test.dart from flutter create keeps test/ non-empty in the canonical bootstrap path.
  • Python: uv init or 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.kts applying the Kotlin-JVM plugin and the detekt Gradle plugin (io.gitlab.arturbosch.detekt), settings.gradle.kts, a placeholder src/main/kotlin source + a src/test/kotlin test — 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.

  1. Read ${CLAUDE_PLUGIN_ROOT}/templates/permissions.json for the canonical allow-list keyed by stack (bun, node, flutter, python, generic).
  2. Compose via canonicalAllowList(template, stack) from adapters/_shared/src/setup/merge_settings.ts. Falls back to generic for unregistered stacks.
  3. If .claude/settings.json does NOT exist: write a fresh JSON with {"permissions": {"allow": <canonical>}}.
  4. 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.
  5. 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 in specs/requirements.md) / 2. linear / 3. jira / 4. custom (copy adapters/_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 (/implement sanitizes LLM output at render time).
  • Write the resolved value as branch_template: <value> in Schema L. mode: none projects that elected 1 in 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):

  1. Generate user-facing docs (narrative + mermaid state/flow diagrams)?
  2. 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).
  3. 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/ plus specs/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 any archive-index.md — archival is git 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.md for the bootstrap milestone, add kind: scaffolding to 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 invoke Provider.sync for 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.

  1. Read CLAUDE.md once.
  2. Call hasDefaultApplicableOutcomes(content) from adapters/_shared/src/setup_audit_section_presence.ts — single source of truth for the audit-required surfaces predicate (branch_template: populated or ## Docs present). Reused by /setup step 8a and /gate-check probe #19.
  3. 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 audit heading present ⇒ no-op. Per-step appends already populated it.
    • true AND heading absent ⇒ call synthesizeAuditSection(claudeMdPath, resolvedSchemaLValues) from adapters/_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).

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 AskUserQuestion tool 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 forbids Write / Edit / NotebookEdit tool calls before the first AskUserQuestion tool_use OR RequiresInputRefusedError raise; Read / Grep / Glob / Bash-read-only orientation is allowed. See docs/auto-mode-protocol.md § Socratic Loop Contract for the full contract. Audit row loop_entered: columnappendAuditRow(...) accepts loopEntered: true when Steps 1–6 emitted at least one AskUserQuestion clarifier, false otherwise; the column pairs with imputed: 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, and claude -p non-interactive stdin inference. The runtime byte-grep at adapters/_shared/src/check_marker_runtime.ts is 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 at adapters/_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, same RequiresInputRefusedError outcome.
Install via CLI
npx skills add https://github.com/nesquikm/dev-process-toolkit --skill setup
Repository Details
star Stars 4
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator