--- name: project-init description: 'Scaffold an unconfigured directory into a configured pi project. Interactive, profile-driven: previews the planned writes, then writes AGENTS.md, .pi/settings.json and prompt files — optionally also a knowledge base, an openspec/ scaffold, and user-global ~/.pi/agent/settings.json. Use on a bare directory, or when the dashboard''s "Initialize" button spawns this session.' license: MIT metadata: author: pi-dashboard version: "1.0" --- # Project Init Turn the current directory into a configured pi project through a guided, conversational flow. You are running as a first-class interactive session — converse, confirm, and only write files after the user agrees. **Target directory** = your current working directory (`cwd`). All writes land there. All profile/doctrine paths below are relative to THIS skill's directory (the folder containing this `SKILL.md`); call it ``. ## Step 1 — Resolve the available profiles A profile is a directory bundle: `profile.json` (optional, carries `description` + `dox`), `AGENTS.md.tmpl`, `settings.json.tmpl`, and `prompts/*.md`. Enumerate profiles from two sources, **user wins by name**: 1. Shipped: `/profiles/*` 2. User: `~/.pi/project-profiles/*` ```bash ls -1 "/profiles" 2>/dev/null ls -1 "$HOME/.pi/project-profiles" 2>/dev/null ``` Merge: a user profile of the same name fully shadows the shipped one. A directory is only a usable profile when it contains BOTH `AGENTS.md.tmpl` and `settings.json.tmpl`. Read each `profile.json` for its `description` and `dox` flag (`dox` defaults to `false` when absent or unreadable). ## Step 2 — Ask which profile Use `ask_user` (select) to present the resolved profiles by name + description. Shipped defaults are `coding` (TDD/simplicity/surgical, OpenSpec on, `npm ci` worktree-init) and `docs` (writing structure, OpenSpec off, no build step). ## Step 2b — Resolve the technology stack (stack-aware profiles only) When the chosen profile's `profile.json` has `"stackAware": true` (the shipped `coding` profile does), its templates carry technology placeholders (`{{INSTALL_CMD}}`, `{{TEST_CMD}}`, `{{BUILD_CMD}}`, `{{INIT_GATE}}`, `{{INIT_COMMAND}}`) that must be filled from the project's stack — a coding repo may be Node, Rust, Go, Python, Java, etc. **Auto-detect + confirm:** 1. Detect a best guess from marker files in the target directory: | Marker file(s) | Stack | install / test / build | init gate + run | |---|---|---|---| | `pnpm-lock.yaml` | pnpm | `pnpm install --frozen-lockfile` / `pnpm test` / `pnpm build` | `test ! -d node_modules` / `pnpm install --frozen-lockfile` | | `yarn.lock` | yarn | `yarn install --frozen-lockfile` / `yarn test` / `yarn build` | `test ! -d node_modules` / `yarn install --frozen-lockfile` | | `bun.lockb` / `bun.lock` | bun | `bun install` / `bun test` / `bun run build` | `test ! -d node_modules` / `bun install` | | `package-lock.json` / `package.json` | npm | `npm ci` / `npm test` / `npm run build` | `test ! -d node_modules` / `npm ci` | | `Cargo.toml` | cargo | `cargo fetch` / `cargo test` / `cargo build` | `test ! -d target` / `cargo fetch` | | `go.mod` | go | `go mod download` / `go test ./...` / `go build ./...` | `test ! -f go.sum` / `go mod download` | | `poetry.lock` or `pyproject.toml`+`[tool.poetry]` | poetry | `poetry install` / `poetry run pytest` / `poetry build` | `test ! -d .venv` / `poetry install` | | `requirements.txt` / `pyproject.toml` | pip | venv+pip install / `.venv/bin/pytest` / `python -m build` | `test ! -d .venv` / venv+pip install | | `pom.xml` | maven | `mvn -q dependency:go-offline` / `mvn test` / `mvn -q package -DskipTests` | `test ! -d target` / `mvn -q dependency:go-offline` | | `build.gradle`(`.kts`) | gradle | `./gradlew dependencies` / `./gradlew test` / `./gradlew build -x test` | `test ! -d .gradle` / `./gradlew dependencies` | Prefer a JS lockfile over a plain `package.json`. A bare directory yields no guess. 2. **Confirm with the user** (`ask_user`): show the detected stack (or "none detected") and let them confirm or pick a different stack from the table. Never scaffold a stack-aware profile without a resolved stack. 3. Substitute the chosen stack's values for the `{{…}}` placeholders when writing the templates in Step 4. After writing, verify NO `{{…}}` placeholder remains in `AGENTS.md` or `.pi/settings.json` — an unfilled placeholder means the stack was not resolved; go back and ask. ## Step 3 — Ask about optional capabilities, preview, then confirm ### 3a — Ask about DOX (all profiles) DOX seeds a directory-level documentation doctrine and wires the kb toolset (see Step 5). It is now an **interactive choice on every profile**, not a fixed per-profile switch. Ask with `ask_user` (confirm), pre-selecting the profile's `dox` value as the DEFAULT answer: > Enable DOX documentation doctrine? Seeds a directory-level AGENTS.md discipline > into `./AGENTS.md` and enables the kb toolset. (default: ``) Record the answer as `DOX_ENABLED`. The `dox` flag in `profile.json` only sets the default; the user's answer decides. Step 5 gates on `DOX_ENABLED`, not the raw flag. ### 3b — Ask about OpenSpec init (coding profile only) **Gate: only when the selected profile is `coding`** (skip for `docs` / any OpenSpec-off profile), mirroring Steps 4b and 5. Skip the prompt entirely when an `openspec/` directory already exists in the target (idempotent — treat as already-initialized). Otherwise ask with `ask_user` (confirm): > Initialize OpenSpec for this project? Runs `openspec init --tools pi`, which > creates the `openspec/` scaffold and wires the OpenSpec commands into pi. Record the answer as `OPENSPEC_INIT`. The actual run happens in Step 6. ### 3c — Preview + confirm List exactly what you will write, then ask the user to confirm (`ask_user` confirm). The writes for profile `

` are: - `./AGENTS.md` ← `/profiles/

/AGENTS.md.tmpl` (substitute `{{PROJECT_NAME}}` with the directory basename) - `./.pi/settings.json` ← `/profiles/

/settings.json.tmpl` - `./.pi/prompts/*.md` ← each file in `/profiles/

/prompts/` When `DOX_ENABLED` is true, ALSO name in the preview: - the DOX pointer block appended to `./AGENTS.md` (see Step 5) - the `doctrine` choice + kb toolset flip written to `./.pi/dashboard/knowledge_base.json` When `OPENSPEC_INIT` is true, ALSO disclose the side effect (see Step 6) — NOT a plain file write: - runs `openspec init --tools pi`, scaffolding `./openspec/` and wiring pi When the chosen profile is `coding`, ALSO disclose the possible side effect (see Step 4b) — NOT a file write: - may offer to `pi install` the `eng-disciplines` skills **user-globally** (writes `~/.pi/agent/settings.json`). This is machine-wide: the skills become available in **all** projects on this machine, not just this one. Always opt-in via a separate prompt; never forced. Needs Node/npm on the machine (the install runs `pi install npm:…`); the scaffolded repo itself gains no dependency. **Idempotency:** before writing, check whether `./AGENTS.md` or `./.pi/settings.json` already exist. If they do, ask before overwriting — never clobber silently. ## Step 4 — Write the scaffold On confirmation, write the files listed above. Substitute `{{PROJECT_NAME}}` in `AGENTS.md.tmpl` with the target directory's basename, and — for a stack-aware profile — the stack placeholders resolved in Step 2b. **Validate the hook.** After writing `./.pi/settings.json`, confirm its `worktreeInit` is a valid change-A hook: a non-empty `gate` string plus a `run` that is either `{ type: "script", command: "" }` or `{ type: "agent", prompt: "" }`. If it is not valid, warn the user — an invalid hook fails open (change-A ignores it) and the Initialize button will loop back to this skill instead of running the hook. ## Step 4b — Ensure discipline skills (only when the profile is `coding`) The `coding` template's `## Discipline Skills` checkpoint table references the `eng-disciplines` skills. This step makes those references live. **Gate: run only when the selected profile is `coding`** (skip for `docs` / any OpenSpec-off profile), mirroring how Step 5 gates on `dox: true`. **Detect** (read-only; both forms tolerate a missing `pi` binary): ```bash pi list 2>/dev/null | grep -q pi-dashboard-eng-disciplines \ || stat ~/.pi/agent/npm/node_modules/@blackbelt-technology/pi-dashboard-eng-disciplines >/dev/null 2>&1 ``` If `pi` is not on PATH and the stat misses, treat as ABSENT but do NOT error the init — fall through to the footnote. (Known limit: the stat form only sees the `npm:` global path; a `git:`/renamed install is invisible and would re-prompt.) **PRESENT** → skills already global. Skip the prompt (idempotent re-run) and write NO activation footnote into `./AGENTS.md`. If a prior run left the "not detected" footnote (e.g. the skills were installed after a decline), remove that line before exiting so the file never claims the skills are missing when they are present. Done. **ABSENT** → `ask_user` (confirm): > Install the discipline skills globally? They power the checkpoint table this > project's AGENTS.md references, and become available in ALL projects on this > machine. Writes `~/.pi/agent/settings.json` (user-global, not project-local). - **Yes** → run `pi install npm:@blackbelt-technology/pi-dashboard-eng-disciplines` and verify exit 0. On success, write NO footnote. On non-zero exit (or a missing `pi`), fall through to the footnote path. - **No / install failed** → append ONE line under the `## Discipline Skills` table in `./AGENTS.md`: > Discipline skills not detected — run `pi install npm:@blackbelt-technology/pi-dashboard-eng-disciplines` to activate the checkpoints above. The footnote is **detection-conditional**: written only on the absent/declined branch, never on the present/installed path (so a successfully-wired project never carries a false "not detected" line). The install is always user-global and never forced. ## Step 5 — DOX pointer seed (only when `DOX_ENABLED` is true) > Gated on the user's Step 3a answer (`DOX_ENABLED`), NOT the raw `profile.json` > `dox` flag — the flag only supplied the default. Skip this step entirely when > the user declined DOX. Do NOT copy any doctrine text. The per-turn DOX doctrine (READ + WRITE) is injected by the `pi-dashboard-kb-extension`; the project's `AGENTS.md` carries only a marker + pointer block. Tune it via `.pi/dashboard/knowledge_base.json`. **1. Seed the pointer block.** Append it to `./AGENTS.md` **only when it does not already carry the marker** `` (idempotent — if the marker is present, skip this step entirely): ```markdown ## DOX doctrine Per-turn DOX doctrine — the kb-first READ discipline and the directory `AGENTS.md` WRITE discipline — is injected by the `pi-dashboard-kb-extension`. Tune it in `.pi/dashboard/knowledge_base.json` under the `doctrine` key (`inject`, `write`). ``` **2. Record the doctrine choice.** Read-merge-write `./.pi/dashboard/knowledge_base.json` — read the file if present, set ONLY the `doctrine` key, preserve every other key, write valid JSON. Since `DOX_ENABLED` is true here, write: ```json "doctrine": { "inject": "kb", "write": true } ``` When the file is absent, also enable the directory-level AGENTS.md toolset: ```json { "sources": [{ "kind": "filesystem", "ref": "." }], "indexAgentsFiles": true, "directoryLevelAgents": { "enabled": true }, "doctrine": { "inject": "kb", "write": true } } ``` **3. Scaffold the directory `AGENTS.md` tree** (path-only rows): ```bash kb dox init ``` **4. Offer `dox-describe`.** After the tree is scaffolded, ask the user (`ask_user` confirm): "Fill the empty Purpose cells now with `dox-describe`? (one subagent per `AGENTS.md`, plan-then-confirm, ≤50 rows per run)". On yes, invoke the `dox-describe` skill (ships with `packages/kb-extension`); on no, tell the user they can run it later. ## Step 6 — Run OpenSpec init (only when `OPENSPEC_INIT` is true) Gated on the user's Step 3b answer (`OPENSPEC_INIT`); this only becomes true for the `coding` profile when no `openspec/` dir pre-existed. Mirrors Step 4b's side-effect pattern — opt-in, verified, never forced. **Run** (always non-interactive so it never hijacks the conversation): ```bash openspec init --tools pi ``` The `--tools pi` flag pins the wiring to pi and skips OpenSpec's interactive tool picker. Verify exit 0 and that `./openspec/` now exists. On success, tell the user OpenSpec is wired (the `coding` AGENTS.md already documents `openspec change new `). On non-zero exit (or a missing `openspec` binary), warn the user and point them at `openspec init --tools pi` to run manually — do NOT error the init; the scaffold is already written. **Idempotent re-run:** if `./openspec/` already existed, Step 3b never asked, so `OPENSPEC_INIT` is false and this step is skipped — no clobber. ## Step 7 — Done Confirm what was written. Writing `worktreeInit` flips the directory to "configured": the next dashboard **Initialize** click runs the hook (change-A) instead of re-launching this skill. Tell the user they can click Initialize again to run `npm ci` (or the profile's hook).