Env Setup
Let:
I_TS := ${CLAUDE_PLUGIN_ROOT}/skills/dev-init/init.ts
Φ := CLAUDE_PLUGIN_ROOT
F := --force flag present in $ARGUMENTS
σ := .dev/stack.yml
D(label, result) := Display: {label} {result}
D✅(label) := D(label, "✅ Created")
D⏭(label) := D(label, "⏭ Skipped")
ensureGitignore(entry) := grep -q '{entry}' .gitignore 2>/dev/null || echo '{entry}' >> .gitignore
Configure local developer environment: stack config, governance rules, docs stubs, editor settings, LSP.
Runs standalone (/R-env-setup) or called by /init as part of full project initialization.
Phase 1 — Stack Configuration
Set up σ early — later phases read runtime, package manager, commands, deploy platform, hooks tool, docs path.
test -f .dev/stack.yml && echo exists || echo missing
- missing ∧ (
test -f .claude/stack.yml ∨ test -f .claude/dev-core.yml) → legacy layout (contract predates .dev/) → Ask: Migrate now (recommended) | Skip.
- Migrate → O_stackMigrate:
mkdir -p .dev && git mv .claude/stack.yml .dev/ 2>/dev/null; git mv .claude/dev-core.yml .dev/ 2>/dev/null; git mv .claude/stack.yml.example .dev/ 2>/dev/null
D("stack.yml", "✅ Migrated to .dev/ — commit alongside code"). ¬cp of the template: the real contract already exists; copying stack.yml.example over it would replace hand-tuned values (release.model, paths, commands) with generic defaults. Continue at step 5.
- Skip → D⏭("stack.yml — contract left in .claude/, dev-core guards stay off"), skip to Phase 2.
- missing ∧ ¬legacy → Ask: Set up stack.yml now (recommended) | Skip (fallback defaults).
- Set up → O_stackSetup:
mkdir -p .dev && cp "${Φ}/stack.yml.example" .dev/stack.yml
- Ask ∀ critical field: Runtime → bun|node|python →
runtime+package_manager | Backend path (e.g. apps/api, blank=none) | Frontend path (e.g. apps/web, blank=none) | Test command → commands.test
- Write values into σ. Inform: "Fill in remaining fields in σ before running agents."
- ¬
.dev/stack.yml.example → mkdir -p .dev && cp "${Φ}/stack.yml.example" .dev/stack.yml.example. D("stack.yml.example", "✅ Created (reference template)").
- existing → D("stack.yml", "✅ Already exists"), skip.
Note: .dev/stack.yml is committed (project stack conventions — no secrets). Only .env is gitignored by dev-core. .dev/dev-core.yml contains only public GitHub Project node IDs and is committed.
Phase 1b — Worktree-setup retrofit
For projects that already have σ but pre-date the worktree-setup hook. Detect the
gap and offer to scaffold tools/worktree-setup.sh + teardown. All steps are
inlined here — cross-skill prose references do not bind at runtime.
Let:
WS := tools/worktree-setup.sh
WT := tools/worktree-teardown.sh
CL := ${CLAUDE_PLUGIN_ROOT}/references/worktree-setup-checklist.md
TS := ${CLAUDE_PLUGIN_ROOT}/tools/worktreeScaffold.ts
σ_has_hook := grep -q 'worktree_setup:' .dev/stack.yml
runtime_supported := σ.runtime ∈ {python, bun, node}
- σ missing → D⏭("Worktree-setup retrofit — requires stack.yml"), skip.
- σ_has_hook true → D("Worktree-setup retrofit", "✅ Already configured"), skip.
- runtime_supported false → D⏭("Worktree-setup retrofit — runtime not in scope"), skip.
- Wider probe — check for existing worktree-setup scripts under non-canonical names:
ALT_SCRIPT=$(grep -rl 'worktree[-_]setup' tools/*.sh scripts/*.sh 2>/dev/null | head -1)
ALT_SCRIPT ∃ ∧ ALT_SCRIPT ≠ "tools/worktree-setup.sh" →
D("Worktree-setup retrofit", "⚠️ Found existing worktree-setup script at ${ALT_SCRIPT} (not tools/worktree-setup.sh). Skipping scaffold — move it to tools/worktree-setup.sh or delete and re-run."), skip.
- test -f tools/worktree-setup.sh ∧ ¬F → D("Worktree-setup retrofit", "⏭ Script present, σ key missing — fix σ only").
- Append
commands.worktree_setup: tools/worktree-setup.sh + commands.worktree_teardown: tools/worktree-teardown.sh under commands: in σ.
- D✅("Worktree-setup retrofit — σ keys added"), skip remainder.
- Both absent → present choice Scaffold worktree-setup hook now | Skip.
- Skip → D⏭("Worktree-setup retrofit"), continue.
- Scaffold → execute the following inline (verbatim duplication of stack-setup Phase 4b — required because cross-skill references do not bind at runtime):
a. Re-detect variables from σ and filesystem:
RUNTIME=$(grep '^runtime:' .dev/stack.yml | awk '{print $2}')
PM=$(grep '^package_manager:' .dev/stack.yml | awk '{print $2}')
MONOREPO_BOOL=$([ -f turbo.jsonc ] || [ -f turbo.json ] || [ -f nx.json ] && echo true || echo false)
HOOKS_TOOL=$([ -f lefthook.yml ] || [ -f .lefthook.yml ] && echo lefthook \
|| ([ -f .pre-commit-config.yaml ] && echo pre-commit) || echo none)
DATABASE=$(grep -lE 'NEON_DATABASE_URL|@neondatabase' .env.example apps/api/package.json 2>/dev/null \
| head -1 > /dev/null && echo neon || echo none)
BE_PATH=$(grep -oP '(?<=packages = \[")[^"]+' pyproject.toml 2>/dev/null | head -1 \
|| (test -d apps/api && echo apps/api) || echo "")
ENV_FILES=$(ls .env.example .env.local 2>/dev/null | head -3 | tr '\n' ' ' || echo "")
b. Build CTX_JSON safely via jq:command -v jq > /dev/null 2>&1 || { echo "jq not found — install jq to continue"; exit 1; }
CTX_JSON=$(jq -n \
--arg runtime "$RUNTIME" \
--arg pm "$PM" \
--argjson monorepo "${MONOREPO_BOOL}" \
--arg hooks_tool "${HOOKS_TOOL:-lefthook}" \
--arg database "${DATABASE:-none}" \
--arg be_path "${BE_PATH:-}" \
--arg env_files "${ENV_FILES:-}" \
'{
runtime: $runtime,
package_manager: $pm,
monorepo: $monorepo,
hooks_tool: $hooks_tool,
env_files: ($env_files | split(" ") | map(select(. != ""))),
database: $database,
backend_paths: ($be_path | if . == "" then [] else [.] end)
}')
c. Preview:IDS=$(bun "${TS}" list-selected --checklist "${CL}" --context-json "${CTX_JSON}")
COUNT=$(echo "$IDS" | awk -F, '{print NF}')
Echo: Worktree-setup retrofit preview — ${RUNTIME}/${PM} · ${COUNT} concerns: ${IDS}
COUNT == 0 → D⏭("Worktree-setup retrofit — no concerns matched"), skip.
d. user choice Write scripts | Preview composed body | Abort.
- Preview composed body →
bun "${TS}" compose --checklist "${CL}" --context-json "${CTX_JSON}" --mode setup | head -80, then re-present user choice Write scripts | Abort.
- Abort → D⏭("Worktree-setup retrofit"), skip.
e. Write:
mkdir -p tools
bun "${TS}" compose --checklist "${CL}" --context-json "${CTX_JSON}" --mode setup > tools/worktree-setup.sh
bun "${TS}" compose --checklist "${CL}" --context-json "${CTX_JSON}" --mode teardown > tools/worktree-teardown.sh
chmod +x tools/worktree-setup.sh tools/worktree-teardown.sh
f. Register keys in σ (idempotent — skip lines already present):
Append under commands: in .dev/stack.yml:
worktree_setup: tools/worktree-setup.sh
worktree_teardown: tools/worktree-teardown.sh
g. D("Worktree-setup retrofit", "✅ Written (${COUNT} concerns: ${IDS}), σ keys registered").
Re-run idempotency: any subsequent /R-env-setup invocation re-evaluates the predicate — once σ has the key, step 2 short-circuits silently.
Phase 2 — Scaffold CLAUDE.md Critical Rules
Generate governance rules (dev process, decision protocol, git conventions, etc.) from σ values. Sections vary by project type.
σ ∄ → D("Critical Rules", "⏭ Skipped — requires stack.yml"), skip to Phase 3.
- Run:
bun $I_TS scaffold-rules --stack-path .dev/stack.yml --claude-md CLAUDE.md
- Parse JSON → extract
projectType, sections, markdown, existing, facts.
- Display:
Project type: {projectType}
Repo facts: baseBranch={facts.baseBranch} pm={facts.packageManager} .env.example={facts.hasEnvExample}
Parent CLAUDE.md: {existing.parentPaths joined | "none"}
Parent imports: {existing.parentImports joined | "none"} ← machine-local; not auto-skip authority
Local sections: {existing.sectionIds or "none"}
Sections to scaffold: {sections.length} ({section ids})
Parent context is reporting only. Silent auto-skip is forbidden — parent/ssot paths are often machine-local; committed CLAUDE.md must stay portable for clones without that parent.
- Present choice (always a gate — user is the gate):
- Scaffold full — all generated sections (portable governance for any clone)
- Scaffold project-local only — tldr + artifact-model + coding-standards + gotchas (when parent already loads fleet rules)
- Merge — append only section ids missing from
existing.sectionIds (local titles only)
- Skip
When
existing.sectionIds already covers all expected → still show table; default bias Skip / already complete.
- Scaffold full / project-local / Replace → write
markdown (for project-local: filter sections to ids ∈ {tldr, artifact-model, coding-standards, gotchas}, renumber). Preserve content before/after ## Critical Rules if present.
- Merge → ∀ section ∈ chosen set ∧ section.id ∉ existing.sectionIds → append after last existing Critical Rules heading.
- D("Critical Rules", "✅ Scaffolded ({N} sections for {projectType}, base={facts.baseBranch})")
Phase 3 — Documentation Scaffolding (Optional)
- Read
docs.path from σ (default: docs). Write format is always Markdown (.md).
{docs.path}/standards/ ∃ → D("Docs scaffolding", "✅ Already present"), skip.
- Ask: Scaffold standard docs (architecture/, standards/, guides/ with templates) | Skip.
- yes:
bun "${CLAUDE_PLUGIN_ROOT}/skills/dev-init/init.ts" scaffold-docs --path <docs.path>
- D("Docs scaffolding", "✅ Created {filesCreated.length} files in {docsPath}/").
Phase 4 — LSP Support (Optional)
Enable ENABLE_LSP_TOOL for richer code intelligence in Claude Code sessions.
Read lsp.enabled from σ. false → D⏭("LSP — Disabled in stack.yml"), skip. true ∨ absent → continue.
grep -q '^ENABLE_LSP_TOOL=' .env 2>/dev/null && echo "set" || echo "missing". set → D("ENABLE_LSP_TOOL", "✅ Already configured"), skip to step 6.
Ask: Enable LSP (ENABLE_LSP_TOOL=1 + language server) | Skip.
yes:
a. Add to .env and .env.example:
echo 'ENABLE_LSP_TOOL=1' >> .env
grep -q '^ENABLE_LSP_TOOL=' .env.example 2>/dev/null || echo 'ENABLE_LSP_TOOL=1' >> .env.example
b. Detect LSP server from lsp.server or runtime:
| runtime |
server |
install |
binary |
bun/node/deno |
typescript-language-server |
bun: bun add -d typescript-language-server typescript / pnpm: pnpm add -D ... / npm: npm install --save-dev ... / yarn: yarn add --dev ... |
typescript-language-server |
python |
pyright |
uv tool install pyright or pip install pyright |
pyright |
rust |
rust-analyzer |
rustup component add rust-analyzer |
rust-analyzer |
go |
gopls |
go install golang.org/x/tools/gopls@latest |
gopls |
c. which <binary> 2>/dev/null. missing → run install → re-check. still-missing → ⚠️ "not in PATH — restart shell".
d. Claude Code LSP plugin — detect from runtime:
| runtime |
claude plugin name |
bun/node/deno |
typescript-lsp |
python |
pyright-lsp |
rust/go |
(none — skip) |
claude plugin list 2>/dev/null | grep -q '<plugin-name>' → installed → skip.
¬installed → Ask: Global (recommended for solo) | Project (commits to .claude/settings.json) | Skip.
- Global:
claude plugin install <plugin-name>
- Project:
claude plugin install <plugin-name> --scope project
e. D("LSP", "✅ ENABLE_LSP_TOOL=1 set, installed, plugin active").
Skip → D⏭("LSP").
Already set ∧ binary ∃ → check Claude Code plugin (step 4d). D("LSP", "✅ Already configured ([, plugin missing → run fix])").
Phase 5 — Report
Env Setup Complete
==================
stack.yml ✅ Configured / ✅ Already exists / ⏭ Skipped
Critical Rules ✅ Scaffolded (N sections) / ✅ Already complete / ⏭ Skipped
Docs scaffolding ✅ Created N files / ✅ Already present / ⏭ Skipped
LSP ✅ Configured / ✅ Already set / ⏭ Disabled / ⏭ Skipped
Worktree-setup ✅ Scaffolded / ✅ Already configured / ⏭ Skipped
Next: run /R-seed-docs to populate docs stubs. Issue triage (labels, blocked-by, parent/child) lives in the companion **issue-triage** plugin.
Safety Rules
- Never overwrite existing
.dev/stack.yml values without F or explicit confirmation
- Always present choices and wait for user reply before any write operation
- Commit
.dev/stack.yml — it holds project stack conventions, not secrets. Gitignore .env only.
- Idempotent — skip already-configured items unless F
$ARGUMENTS
1---2name: r-env-setup3description: Set up local dev environment — stack.yml, CLAUDE.md Critical Rules, docs scaffolding, LSP. Triggered by /R-dev-init or standalone /R-env-setup. Triggers: "env setup" | "setup environment" | "scaffold rules".4---56# Env Setup78Let:9 I_TS := `${CLAUDE_PLUGIN_ROOT}/skills/dev-init/init.ts`10 Φ := CLAUDE_PLUGIN_ROOT11 F := `--force` flag present in `$ARGUMENTS`12 σ := `.dev/stack.yml`13 D(label, result) := Display: `{label} {result}`14 D✅(label) := D(label, "✅ Created")15 D⏭(label) := D(label, "⏭ Skipped")16 ensureGitignore(entry) := `grep -q '{entry}' .gitignore 2>/dev/null || echo '{entry}' >> .gitignore`1718Configure local developer environment: stack config, governance rules, docs stubs, editor settings, LSP.19Runs standalone (`/R-env-setup`) or called by `/init` as part of full project initialization.2021## Phase 1 — Stack Configuration2223Set up σ early — later phases read runtime, package manager, commands, deploy platform, hooks tool, docs path.24251. `test -f .dev/stack.yml && echo exists || echo missing`262. missing ∧ (`test -f .claude/stack.yml` ∨ `test -f .claude/dev-core.yml`) → **legacy layout** (contract predates `.dev/`) → Ask: **Migrate now** (recommended) | **Skip**.27 - **Migrate** → O_stackMigrate: `mkdir -p .dev && git mv .claude/stack.yml .dev/ 2>/dev/null; git mv .claude/dev-core.yml .dev/ 2>/dev/null; git mv .claude/stack.yml.example .dev/ 2>/dev/null`28 D("stack.yml", "✅ Migrated to .dev/ — commit alongside code"). **¬`cp` of the template**: the real contract already exists; copying `stack.yml.example` over it would replace hand-tuned values (`release.model`, paths, commands) with generic defaults. Continue at step 5.29 - **Skip** → D⏭("stack.yml — contract left in .claude/, dev-core guards stay off"), skip to Phase 2.303. missing ∧ ¬legacy → Ask: **Set up stack.yml now** (recommended) | **Skip** (fallback defaults).314. **Set up** → O_stackSetup:32 - `mkdir -p .dev && cp "${Φ}/stack.yml.example" .dev/stack.yml`33 - Ask ∀ critical field: **Runtime** → bun|node|python → `runtime`+`package_manager` | **Backend path** (e.g. `apps/api`, blank=none) | **Frontend path** (e.g. `apps/web`, blank=none) | **Test command** → `commands.test`34 - Write values into σ. Inform: "Fill in remaining fields in σ before running agents."355. ¬`.dev/stack.yml.example` → `mkdir -p .dev && cp "${Φ}/stack.yml.example" .dev/stack.yml.example`. D("stack.yml.example", "✅ Created (reference template)").366. existing → D("stack.yml", "✅ Already exists"), skip.3738Note: `.dev/stack.yml` is **committed** (project stack conventions — no secrets). Only `.env` is gitignored by dev-core. `.dev/dev-core.yml` contains only public GitHub Project node IDs and is committed.3940### Phase 1b — Worktree-setup retrofit4142For projects that already have σ but pre-date the worktree-setup hook. Detect the43gap and offer to scaffold `tools/worktree-setup.sh` + teardown. All steps are44inlined here — cross-skill prose references do not bind at runtime.4546Let:47 WS := tools/worktree-setup.sh48 WT := tools/worktree-teardown.sh49 CL := ${CLAUDE_PLUGIN_ROOT}/references/worktree-setup-checklist.md50 TS := ${CLAUDE_PLUGIN_ROOT}/tools/worktreeScaffold.ts51 σ_has_hook := `grep -q 'worktree_setup:' .dev/stack.yml`52 runtime_supported := σ.runtime ∈ {python, bun, node}53541. **σ missing** → D⏭("Worktree-setup retrofit — requires stack.yml"), skip.552. **σ_has_hook true** → D("Worktree-setup retrofit", "✅ Already configured"), skip.563. **runtime_supported false** → D⏭("Worktree-setup retrofit — runtime not in scope"), skip.574. **Wider probe** — check for existing worktree-setup scripts under non-canonical names:58 ```bash59 ALT_SCRIPT=$(grep -rl 'worktree[-_]setup' tools/*.sh scripts/*.sh 2>/dev/null | head -1)60 ```61 ALT_SCRIPT ∃ ∧ ALT_SCRIPT ≠ "tools/worktree-setup.sh" →62 D("Worktree-setup retrofit", "⚠️ Found existing worktree-setup script at ${ALT_SCRIPT} (not tools/worktree-setup.sh). Skipping scaffold — move it to tools/worktree-setup.sh or delete and re-run."), skip.635. **test -f tools/worktree-setup.sh** ∧ ¬F → D("Worktree-setup retrofit", "⏭ Script present, σ key missing — fix σ only").64 - Append `commands.worktree_setup: tools/worktree-setup.sh` + `commands.worktree_teardown: tools/worktree-teardown.sh` under `commands:` in σ.65 - D✅("Worktree-setup retrofit — σ keys added"), skip remainder.666. **Both absent** → present choice **Scaffold worktree-setup hook now** | **Skip**.67 - **Skip** → D⏭("Worktree-setup retrofit"), continue.68 - **Scaffold** → execute the following inline (verbatim duplication of stack-setup Phase 4b — required because cross-skill references do not bind at runtime):69 a. Re-detect variables from σ and filesystem:70 ```bash71 RUNTIME=$(grep '^runtime:' .dev/stack.yml | awk '{print $2}')72 PM=$(grep '^package_manager:' .dev/stack.yml | awk '{print $2}')73 MONOREPO_BOOL=$([ -f turbo.jsonc ] || [ -f turbo.json ] || [ -f nx.json ] && echo true || echo false)74 HOOKS_TOOL=$([ -f lefthook.yml ] || [ -f .lefthook.yml ] && echo lefthook \75 || ([ -f .pre-commit-config.yaml ] && echo pre-commit) || echo none)76 DATABASE=$(grep -lE 'NEON_DATABASE_URL|@neondatabase' .env.example apps/api/package.json 2>/dev/null \77 | head -1 > /dev/null && echo neon || echo none)78 BE_PATH=$(grep -oP '(?<=packages = \[")[^"]+' pyproject.toml 2>/dev/null | head -1 \79 || (test -d apps/api && echo apps/api) || echo "")80 ENV_FILES=$(ls .env.example .env.local 2>/dev/null | head -3 | tr '\n' ' ' || echo "")81 ```82 b. Build CTX_JSON safely via jq:83 ```bash84 command -v jq > /dev/null 2>&1 || { echo "jq not found — install jq to continue"; exit 1; }85 CTX_JSON=$(jq -n \86 --arg runtime "$RUNTIME" \87 --arg pm "$PM" \88 --argjson monorepo "${MONOREPO_BOOL}" \89 --arg hooks_tool "${HOOKS_TOOL:-lefthook}" \90 --arg database "${DATABASE:-none}" \91 --arg be_path "${BE_PATH:-}" \92 --arg env_files "${ENV_FILES:-}" \93 '{94 runtime: $runtime,95 package_manager: $pm,96 monorepo: $monorepo,97 hooks_tool: $hooks_tool,98 env_files: ($env_files | split(" ") | map(select(. != ""))),99 database: $database,100 backend_paths: ($be_path | if . == "" then [] else [.] end)101 }')102 ```103 c. Preview:104 ```bash105 IDS=$(bun "${TS}" list-selected --checklist "${CL}" --context-json "${CTX_JSON}")106 COUNT=$(echo "$IDS" | awk -F, '{print NF}')107 ```108 Echo: `Worktree-setup retrofit preview — ${RUNTIME}/${PM} · ${COUNT} concerns: ${IDS}`109 COUNT == 0 → D⏭("Worktree-setup retrofit — no concerns matched"), skip.110 d. user choice **Write scripts** | **Preview composed body** | **Abort**.111 - **Preview composed body** → `bun "${TS}" compose --checklist "${CL}" --context-json "${CTX_JSON}" --mode setup | head -80`, then re-present user choice **Write scripts** | **Abort**.112 - **Abort** → D⏭("Worktree-setup retrofit"), skip.113 e. Write:114 ```bash115 mkdir -p tools116 bun "${TS}" compose --checklist "${CL}" --context-json "${CTX_JSON}" --mode setup > tools/worktree-setup.sh117 bun "${TS}" compose --checklist "${CL}" --context-json "${CTX_JSON}" --mode teardown > tools/worktree-teardown.sh118 chmod +x tools/worktree-setup.sh tools/worktree-teardown.sh119 ```120 f. Register keys in σ (idempotent — skip lines already present):121 Append under `commands:` in `.dev/stack.yml`:122 ```yaml123 worktree_setup: tools/worktree-setup.sh124 worktree_teardown: tools/worktree-teardown.sh125 ```126 g. D("Worktree-setup retrofit", "✅ Written (${COUNT} concerns: ${IDS}), σ keys registered").127128Re-run idempotency: any subsequent `/R-env-setup` invocation re-evaluates the predicate — once σ has the key, step 2 short-circuits silently.129130## Phase 2 — Scaffold CLAUDE.md Critical Rules131132Generate governance rules (dev process, decision protocol, git conventions, etc.) from σ values. Sections vary by project type.133134σ ∄ → D("Critical Rules", "⏭ Skipped — requires stack.yml"), skip to Phase 3.1351361. Run: `bun $I_TS scaffold-rules --stack-path .dev/stack.yml --claude-md CLAUDE.md`1372. Parse JSON → extract `projectType`, `sections`, `markdown`, `existing`, `facts`.1383. Display:139 ```140 Project type: {projectType}141 Repo facts: baseBranch={facts.baseBranch} pm={facts.packageManager} .env.example={facts.hasEnvExample}142 Parent CLAUDE.md: {existing.parentPaths joined | "none"}143 Parent imports: {existing.parentImports joined | "none"} ← machine-local; not auto-skip authority144 Local sections: {existing.sectionIds or "none"}145 Sections to scaffold: {sections.length} ({section ids})146 ```147 > Parent context is **reporting only**. Silent auto-skip is forbidden — parent/ssot paths are often machine-local; committed CLAUDE.md must stay portable for clones without that parent.1484. Present choice (always a gate — user is the gate):149 - **Scaffold full** — all generated sections (portable governance for any clone)150 - **Scaffold project-local only** — tldr + artifact-model + coding-standards + gotchas (when parent already loads fleet rules)151 - **Merge** — append only section ids missing from `existing.sectionIds` (local titles only)152 - **Skip**153 When `existing.sectionIds` already covers all expected → still show table; default bias **Skip** / already complete.1545. Scaffold full / project-local / Replace → write `markdown` (for project-local: filter sections to ids ∈ {tldr, artifact-model, coding-standards, gotchas}, renumber). Preserve content before/after `## Critical Rules` if present.1556. Merge → ∀ section ∈ chosen set ∧ section.id ∉ existing.sectionIds → append after last existing Critical Rules heading.1567. D("Critical Rules", "✅ Scaffolded ({N} sections for {projectType}, base={facts.baseBranch})")157158## Phase 3 — Documentation Scaffolding (Optional)1591601. Read `docs.path` from σ (default: `docs`). Write format is always Markdown (`.md`).1612. `{docs.path}/standards/` ∃ → D("Docs scaffolding", "✅ Already present"), skip.1623. Ask: **Scaffold standard docs** (architecture/, standards/, guides/ with templates) | **Skip**.1634. yes:164 ```bash165 bun "${CLAUDE_PLUGIN_ROOT}/skills/dev-init/init.ts" scaffold-docs --path <docs.path>166 ```1675. D("Docs scaffolding", "✅ Created {filesCreated.length} files in {docsPath}/").168169## Phase 4 — LSP Support (Optional)170171Enable `ENABLE_LSP_TOOL` for richer code intelligence in Claude Code sessions.1721731. Read `lsp.enabled` from σ. `false` → D⏭("LSP — Disabled in stack.yml"), skip. `true` ∨ absent → continue.1742. `grep -q '^ENABLE_LSP_TOOL=' .env 2>/dev/null && echo "set" || echo "missing"`. set → D("ENABLE_LSP_TOOL", "✅ Already configured"), skip to step 6.1753. Ask: **Enable LSP** (`ENABLE_LSP_TOOL=1` + language server) | **Skip**.1764. yes:177 a. Add to `.env` and `.env.example`:178 ```bash179 echo 'ENABLE_LSP_TOOL=1' >> .env180 grep -q '^ENABLE_LSP_TOOL=' .env.example 2>/dev/null || echo 'ENABLE_LSP_TOOL=1' >> .env.example181 ```182 b. Detect LSP server from `lsp.server` or `runtime`:183184 | runtime | server | install | binary |185 |---------|--------|---------|--------|186 | `bun`/`node`/`deno` | typescript-language-server | bun: `bun add -d typescript-language-server typescript` / pnpm: `pnpm add -D ...` / npm: `npm install --save-dev ...` / yarn: `yarn add --dev ...` | `typescript-language-server` |187 | `python` | pyright | `uv tool install pyright` or `pip install pyright` | `pyright` |188 | `rust` | rust-analyzer | `rustup component add rust-analyzer` | `rust-analyzer` |189 | `go` | gopls | `go install golang.org/x/tools/gopls@latest` | `gopls` |190191 c. `which <binary> 2>/dev/null`. missing → run install → re-check. still-missing → ⚠️ "not in PATH — restart shell".192 d. **Claude Code LSP plugin** — detect from runtime:193194 | runtime | claude plugin name |195 |---------|--------------------|196 | `bun`/`node`/`deno` | `typescript-lsp` |197 | `python` | `pyright-lsp` |198 | `rust`/`go` | (none — skip) |199200 `claude plugin list 2>/dev/null | grep -q '<plugin-name>'` → installed → skip.201 ¬installed → Ask: **Global** (recommended for solo) | **Project** (commits to `.claude/settings.json`) | **Skip**.202 - Global: `claude plugin install <plugin-name>`203 - Project: `claude plugin install <plugin-name> --scope project`204 e. D("LSP", "✅ ENABLE_LSP_TOOL=1 set, <server> installed, <plugin-name> plugin active").2055. Skip → D⏭("LSP").2066. Already set ∧ binary ∃ → check Claude Code plugin (step 4d). D("LSP", "✅ Already configured (<binary>[, plugin missing → run fix])").207208## Phase 5 — Report209210```211Env Setup Complete212==================213214 stack.yml ✅ Configured / ✅ Already exists / ⏭ Skipped215 Critical Rules ✅ Scaffolded (N sections) / ✅ Already complete / ⏭ Skipped216 Docs scaffolding ✅ Created N files / ✅ Already present / ⏭ Skipped217 LSP ✅ Configured / ✅ Already set / ⏭ Disabled / ⏭ Skipped218 Worktree-setup ✅ Scaffolded / ✅ Already configured / ⏭ Skipped219220Next: run /R-seed-docs to populate docs stubs. Issue triage (labels, blocked-by, parent/child) lives in the companion **issue-triage** plugin.221```222223## Safety Rules2242251. **Never overwrite existing `.dev/stack.yml` values** without F or explicit confirmation2262. **Always present choices and wait for user reply** before any write operation2273. **Commit `.dev/stack.yml`** — it holds project stack conventions, not secrets. Gitignore `.env` only.2284. **Idempotent** — skip already-configured items unless F229230$ARGUMENTS