Skip to content

/sdlc:setup

Generated from solutions/ontological/skills/setup/SKILL.md.

Initialize the docs/planning// directory layout in the current project for every artifact type the sdlc plugin ships a schema for (today: backlog, epic, milestone, task; bug/feature/roadmap to follow). Idempotent — safe to re-run; reports created vs already-existing.

  • Bash
  • Skill

Usage:

  • /sdlc:setup — ensure docs/planning/<type>/ exists for every schema the plugin ships, ensure a top-level sdlc.yaml exists at the project root for per-project runtime configuration (a fresh file is written fully defined — a schema-driven projection of SdlcConfigSchema: every key at its default with the schema’s own descriptions as comments, so a new consumer sees the whole surface at a glance and it cannot drift from the schema. Preview it with sdlc config scaffold; see ${CLAUDE_PLUGIN_ROOT}conventions/sdlc-yaml.md), and ensure the project’s .gitignore contains the canonical # --- Claude Code project-local --- block (including !.claude/hooks/ and !.claude/hooks/** so hook scripts under .claude/hooks/<name>.py can be committed without git add -f). All three pieces are idempotent — existing dirs / files are left alone; a fence-present .gitignore block missing only the hooks un-ignore lines is patched in place, leaving the rest of the file byte-identical.
  • /sdlc:setup --dry-run — report what would be created or patched without touching the filesystem. Applies to every write path: directories, sdlc.yaml, and .gitignore.
  • /sdlc:setup --obsidian — additionally emit one Obsidian Bases file per entity that ships a view template, at docs/planning/<plural>/<plural>.base, copied verbatim from ${CLAUDE_PLUGIN_ROOT}entities/<type>/obsidian-index.yaml. Idempotent: existing .base files are skipped unless --force is also passed.
  • /sdlc:setup --obsidian --force — overwrite existing .base files from the template.
  • /sdlc:setup --detect — when creating a fresh sdlc.yaml, probe the project with the same runner-detection logic as sdlc quality detect and write the detected verbs as commented-out suggestions under quality_checks: so the user opts in by uncommenting. No effect on an existing sdlc.yaml (re-run /sdlc:find-quality-checks to refresh interactively).

Once the structure and sdlc.yaml are in place, /sdlc:setup calls the two interactive gate configurators — /sdlc:find-quality-checks (Step 6) then /sdlc:find-worktree-init (Step 7), unless --dry-run — to populate sdlc.yaml’s quality_checks: list (the gates /sdlc:task-work Step 7 runs before opening a PR) and its worktree_init: list (the verbs Step 4 runs to bootstrap a fresh worktree — install deps, arm git hooks, trust tools).

Project context (don’t re-derive every run):

  • The plugin keeps one schema per artifact type at ${CLAUDE_PLUGIN_ROOT}entities/<type>/schema.ts (e.g. entities/task/schema.ts), validated via sdlc entities validate. For each, the canonical home is docs/planning/<plural>/ under the project root — taskdocs/planning/tasks/. Other skills (/sdlc:task-work, /sdlc:task-review) assume those paths exist.
  • sdlc.yaml at the project root holds per-project runtime configuration consumed by other skills (/sdlc:task-work Step 7 reads its quality_checks: list; Step 4 reads its worktree_init: list). Shape documented at ${CLAUDE_PLUGIN_ROOT}conventions/sdlc-yaml.md. Setup creates an empty starter when the file is absent (with a commented-out worktree_init: hint block); both quality_checks: and worktree_init: are then populated interactively by the configurator steps below (Steps 6 and 7) — or edited directly.
  • .gitignore at the project root needs a canonical # --- Claude Code project-local --- block so project-local Claude Code state (.claude/settings.json, .claude/skills/, .claude/commands/, .claude/agents/, .claude/hooks.json, and .claude/hooks/<name>.py) is committable while transient state under .claude/ stays ignored. Setup writes the block on a fresh .gitignore, appends it when no fence is present, and patches in the !.claude/hooks/ / !.claude/hooks/** lines when the fence exists but those lines don’t. A fully-populated block is left alone.
  1. Run the setup op from the project root:

    ${CLAUDE_PLUGIN_ROOT}cli/sdlc project setup

    Append --dry-run if the user invoked the skill with --dry-run. Append --obsidian (optionally with --force) if the user invoked the skill with those flags — the op then emits one <plural>.base file per entity into the matching docs/planning/<plural>/ directory after creating the directories themselves. Append --detect if the user invoked with that flag — the op then runs the sdlc quality detect runner-detection logic and pre-populates the new sdlc.yaml with commented-out runner suggestions.

  2. Read the op output. Summarize for the user:

    • How many dirs were created (or would be, in dry-run).
    • How many already existed.
    • The full list of resulting docs/planning/<type>/ paths.
    • Whether sdlc.yaml was created or already existed; if created with --detect, mention the number of detected runner suggestions written as commented lines.
    • What .gitignore action was taken: created (no prior file), appended block (file existed without the Claude fence), patched (fence present but hooks lines missing), or left alone (canonical block already present). Under --dry-run the verbs are prefixed with would ….
  3. If nothing was created and everything already existed (planning dirs, sdlc.yaml, and the canonical .gitignore block), say so plainly — the planning environment is already set up.

  4. Check plugin runtime dependencies advisorily. Run:

    ${CLAUDE_PLUGIN_ROOT}cli/sdlc project doctor

    project doctor probes the core runtime deps (bun/node, git, gh, and the recommended claude) and emits any missing ones as MISSING-DEP: <name>; install via <hint> lines on stderr. Pass those lines through to the user, ignore the doctor exit code here, and continue setup regardless of what’s missing. Separately remind the user that /project-check’s mermaid-parse lint needs mmdc (npm i -g @mermaid-js/mermaid-cli) — project doctor does not probe it, so call it out explicitly when relevant.

  5. Surface a lease-namespace conflict if the setup op reports one. When sdlc.yaml declares a lease_authority: carrying a literal refs/sdlc ref that shadows the lease namespace, the setup op (Step 1) exits with code 3 and emits a NAMESPACE-CONFLICT ref=refs/sdlc sha=<sha> line plus a one-line remediation (delete the offending ref on the authority, or pick a different namespace). Pass both through to the user and point them at the ADR’s Namespace conflict guard for context. Resolving the conflict is the operator’s call; do NOT delete the ref yourself.

  6. Configure quality-check gates. Unless --dry-run, invoke /sdlc:find-quality-checks via the Skill tool. It probes the project for runner candidates (just / npm / make / cargo / python / pyproject tools), asks (via AskUserQuestion) which to gate into sdlc.yaml’s quality_checks: list, and writes the approved subset to the file Step 1 ensured exists. Capture its terminal marker — FIND-QUALITY-CHECKS-WROTE quality_checks=<count> path=<path> or FIND-QUALITY-CHECKS-UNCHANGED quality_checks=<count> path=<path> — and fold the count into the Step 2 summary.

    Skip this step entirely under --dry-run: it is interactive and writes sdlc.yaml, neither of which belongs in a dry-run.

  7. Configure worktree-init verbs. Unless --dry-run, invoke /sdlc:find-worktree-init via the Skill tool. It probes the project for dependency-install, git-hook-arming, and tool-trust commands, asks (via AskUserQuestion) which to write to sdlc.yaml’s worktree_init: list, and writes the approved subset to the file Step 1 ensured exists. Capture its terminal marker — FIND-WORKTREE-INIT-WROTE worktree_init=<count> path=<path> or FIND-WORKTREE-INIT-UNCHANGED worktree_init=<count> path=<path> — and fold the count into the Step 2 summary.

    Skip this step entirely under --dry-run: it is interactive and writes sdlc.yaml, neither of which belongs in a dry-run.

  8. Audit existing entities against current schemas. Run:

    ${CLAUDE_PLUGIN_ROOT}cli/sdlc entities audit

    This is read-only — it reports drift but never modifies files. Skip this step when --dry-run is set (the audit doesn’t write anything anyway, but the structure may not exist yet in a dry-run scenario).

    Interpret the exit code:

    • 0 — every existing entity is in sync with the current schemas. Tell the user so.
    • 1 — drift was found on at least one active entity. Print the audit’s markdown output and tell the user they can run /sdlc:entities-audit for the same report standalone, or /sdlc:entities-migrate to apply the auto_fixable=true drift mechanically. Closed entities are skipped by default (they’re frozen artefacts of an earlier schema generation); pass --include-closed to opt them back into both audit and migrate.
    • 2 — op error; show the stderr.

    Do NOT attempt to fix any drift from inside /sdlc:setup — setup scaffolds structure (directories); fixing content (instance files) is /sdlc:entities-migrate’s job.

  • Steps 6 and 7 call the two interactive gate configurators — /sdlc:find-quality-checks (quality_checks:) and /sdlc:find-worktree-init (worktree_init:) — both skipped under --dry-run. They are symmetric: each probes the project, asks which detected commands to keep, and writes the approved subset. Re-run either skill standalone any time to refresh its list. Without a configured quality_checks: list, /sdlc:task-work Step 7 warn-and-skips.
  • Adopting the plugin in a project that already has planning content (READMEs with roadmap sections, brain-dump notes, dated checklists)? Run /sdlc:import-planning after this skill — it walks the repo, surfaces planning-shaped files, and produces draft tasks/milestones from them so prior intent isn’t re-keyed by hand.
  • --obsidian writes Obsidian Bases files (per-folder YAML query files that render frontmatter as tables). The per-entity templates live at ${CLAUDE_PLUGIN_ROOT}entities/<type>/obsidian-index.yaml and are copied verbatim — edit those templates to change column sets or sort order, then re-run with --obsidian --force to refresh. Only entities that ship an obsidian-index.yaml get a .base.
  • The op discovers artifact types from ${CLAUDE_PLUGIN_ROOT}entities/<type>/schema.ts. When a new schema is added to the plugin later, re-running /sdlc:setup picks it up automatically.
  • The op does not create README/template files inside the new dirs; the skill is scoped to “directories exist.”
  • Re-running setup is the update path; there is no separate /sdlc:update.