diff --git a/skills/docs-scaffold/SKILL.md b/skills/docs-scaffold/SKILL.md new file mode 100644 index 0000000..1661b92 --- /dev/null +++ b/skills/docs-scaffold/SKILL.md @@ -0,0 +1,93 @@ +--- +name: docs-scaffold +description: 5-phase documentation scaffolder — auto-detect project type, audit existing docs, generate CLAUDE.md / DECISIONS.md / runbook / README / diagrams / CHANGELOG from KeiSeiKit templates. Each phase is a click-driven file in this skill directory. +argument-hint: +--- + +# Docs-Scaffold — Project Documentation Pipeline (index) + +You are bootstrapping or auditing the documentation layer of a repository. +The pipeline runs 5 phases in order; each phase owns one concern and has +its own verify-criterion. Never skip a phase. Never re-order. + +This `SKILL.md` is the INDEX. Each phase lives in its own file. + +--- + +## Pipeline overview (5 phases) + +| Phase | File | Purpose | AskUserQuestion | +|---|---|---|---| +| 1 | [phase-1-intake.md](phase-1-intake.md) | Auto-detect stack + audit existing docs + pick gaps | 1× | +| 2 | [phase-2-scaffold.md](phase-2-scaffold.md) | Run `kei-docs-scaffold.sh` with selected type | 1× | +| 3 | [phase-3-decisions.md](phase-3-decisions.md) | Walk through first ADR (optional) | 1× | +| 4 | [phase-4-diagrams.md](phase-4-diagrams.md) | Seed Mermaid architecture starter | 1× | +| 5 | [phase-5-changelog.md](phase-5-changelog.md) | Init CHANGELOG via `kei-changelog` | 1× | + +Minimum AskUserQuestion count: **5** (one per phase). Phases 3-5 each have +an early "Skip this phase" option to keep a lightweight run short. + +--- + +## Variables the pipeline produces + +| Name | Set in | Meaning | +|---|---|---| +| `DIR` | Phase 1a | Target repo directory (defaults to `$PWD`) | +| `STACK` | Phase 1a | Detected stack label (Rust / Flutter / Node / …) | +| `EXISTING` | Phase 1b | Set of docs already present (CLAUDE.md, DECISIONS.md, …) | +| `GAPS` | Phase 1c | User-selected subset to scaffold | +| `SCAFFOLDED` | Phase 2 | Files actually written (could be < `GAPS` if `--force` declined) | +| `ADR_N` | Phase 3 | Number of ADR entries appended (0 if skipped) | +| `DIAGRAMS` | Phase 4 | Mermaid files seeded (0 if skipped) | +| `CHANGELOG_STATUS` | Phase 5 | initialized / updated / skipped | + +--- + +## Final report (emit after Phase 5) + +``` +=== DOCS-SCAFFOLD REPORT === +Target: +Stack: +Existing: +Scaffolded: +ADRs added: +Diagrams: +Changelog: +Next action: +``` + +--- + +## Rules (apply throughout) + +- **Pure-click contract.** Every phase has exactly one `AskUserQuestion` + call. Only Phase 1a takes free-text (the target directory path). +- **NO DOWNGRADE (RULE -1).** If scaffolding fails, return 2-3 concrete + alternative paths; never "can't be done". +- **NO HALLUCINATION (RULE 0.4).** Every primitive / block / template + referenced MUST exist on disk. Phase 1 greps before citing. Phase 2 + verifies `kei-docs-scaffold.sh` is executable before invoking. +- **Plan Mode First (RULE 0.5).** This skill IS the plan. No Edit/Write + before the corresponding phase's confirm click. +- **Constructor Pattern (RULE ZERO).** This `SKILL.md` stays < 200 LOC. + Each phase file < 80 LOC. +- **Surgical Changes.** Scaffold only creates files; never modifies code. + Only touches: `CLAUDE.md`, `DECISIONS.md`, `docs/runbook.md`, + `README.md`, `docs/diagrams/*.mmd`, `CHANGELOG.md`. Never edits source. +- **Idempotent.** Re-runs skip existing files unless `--force` is passed + in Phase 2. No duplicate ADR numbering in Phase 3. +- **Public-publish gate.** README scaffold refuses to write if the repo is + on the banned-public list (see `~/.claude/rules/security.md`). User + must type "yes, deploy" + "confirm publication" to override. + +--- + +## References + +- Phases: [phase-1-intake.md](phase-1-intake.md) · [phase-2-scaffold.md](phase-2-scaffold.md) · [phase-3-decisions.md](phase-3-decisions.md) · [phase-4-diagrams.md](phase-4-diagrams.md) · [phase-5-changelog.md](phase-5-changelog.md) +- Primitive: `_primitives/kei-docs-scaffold.sh` — detector + generator (POSIX sh) +- Primitive: `_primitives/_rust/kei-changelog/` — Conventional Commit → CHANGELOG.md +- Blocks: `_blocks/docs-claude-md.md`, `_blocks/docs-decisions-adr.md`, `_blocks/docs-runbook.md`, `_blocks/docs-readme-template.md`, `_blocks/docs-architecture-diagrams.md` +- Rules: `~/.claude/rules/doc-conventions.md`, `~/.claude/rules/security.md` diff --git a/skills/docs-scaffold/phase-1-intake.md b/skills/docs-scaffold/phase-1-intake.md new file mode 100644 index 0000000..b86db0c --- /dev/null +++ b/skills/docs-scaffold/phase-1-intake.md @@ -0,0 +1,67 @@ +# Phase 1 — Intake (auto-detect + audit + pick gaps) + +Goal: identify the target repo, detect its stack, enumerate docs that +already exist, and let the user pick which gaps to scaffold. + +## 1a — Target directory + stack detect + +If the skill was invoked with a directory argument, use it. Otherwise use +`$PWD`. Store as `DIR`. Reject non-directories with a short error + the +user re-enters. + +Run `_primitives/kei-docs-scaffold.sh --dry-run --type=all "$DIR"` just +to print the detected stack, or replicate the detection via Read: + +- `Cargo.toml` → **Rust (Cargo)** +- `pubspec.yaml` → **Flutter / Dart** +- `package.json` → **Node.js / TypeScript** +- `pyproject.toml` | `requirements.txt` → **Python** +- `go.mod` → **Go** +- `Package.swift` → **Swift (SPM)** +- `docker-compose.yml` → **Docker (compose)** +- else → **Unknown** + +Store as `STACK`. Print: `[docs-scaffold] DIR= STACK=`. + +## 1b — Audit existing docs + +List presence of each target file; store the set as `EXISTING`: + +- `/CLAUDE.md` +- `/DECISIONS.md` +- `/docs/runbook.md` +- `/README.md` +- `/docs/diagrams/` (directory, non-empty) +- `/CHANGELOG.md` + +## 1c — Pick gaps to scaffold (AskUserQuestion #1, multi-select) + +```json +{ + "questions": [ + { + "question": "Which docs to scaffold? (existing files are skipped unless --force selected in Phase 2)", + "header": "Gaps", + "multiSelect": true, + "options": [ + {"label": "CLAUDE.md", "description": "Agent-facing project guide (architecture, stack, constraints)"}, + {"label": "DECISIONS.md", "description": "MADR 4.0 append-only ADR log"}, + {"label": "docs/runbook.md", "description": "Ops playbook (symptom → check → fix → escalation)"}, + {"label": "README.md", "description": "Public README — scaffolder checks banned-public list first"}, + {"label": "docs/diagrams/", "description": "Mermaid architecture starter (Phase 4 seeds one file)"}, + {"label": "CHANGELOG.md", "description": "Via kei-changelog from conventional commits (Phase 5)"} + ] + } + ] +} +``` + +Store selection as `GAPS`. If empty → skip to final report with +"Nothing to scaffold". + +## Verify-criterion + +- `DIR` exists as a directory on disk. +- `STACK` is one of the labels above (or `Unknown`). +- `EXISTING` is computed and reported to the user inline. +- `GAPS` is captured from the click. diff --git a/skills/docs-scaffold/phase-2-scaffold.md b/skills/docs-scaffold/phase-2-scaffold.md new file mode 100644 index 0000000..e2b7cb9 --- /dev/null +++ b/skills/docs-scaffold/phase-2-scaffold.md @@ -0,0 +1,72 @@ +# Phase 2 — Scaffold (run `kei-docs-scaffold.sh`) + +Goal: produce the files selected in `GAPS`, non-destructively by default. + +## 2a — Confirm scaffold mode (AskUserQuestion #2) + +```json +{ + "questions": [ + { + "question": "Scaffold mode?", + "header": "Mode", + "multiSelect": false, + "options": [ + {"label": "Safe — skip existing files", "description": "Recommended. Writes only to files not already on disk."}, + {"label": "Force — overwrite existing", "description": "Pass --force. Existing files are replaced (one git checkpoint emitted first)."}, + {"label": "Dry-run — print planned actions only", "description": "No writes. Use for an audit report before committing."}, + {"label": "Abort", "description": "Stop — nothing gets written."} + ] + } + ] +} +``` + +## 2b — Invoke the primitive + +Locate the scaffolder at `_primitives/kei-docs-scaffold.sh` (repo-local) +or `~/.claude/agents/_primitives/kei-docs-scaffold.sh` (installed). If +neither exists, abort with a NO DOWNGRADE error listing two paths: + +1. Run `./install.sh` from the KeiSeiKit repo to install primitives. +2. Clone KeiSeiKit and invoke the scaffolder directly from the repo. + +For each `GAPS` entry (except `CHANGELOG.md` — that is Phase 5, and +`docs/diagrams/` — Phase 4), map to the scaffolder's `--type` value: + +| GAPS entry | `--type` | +|---|---| +| CLAUDE.md | `claude` | +| DECISIONS.md | `decisions` | +| docs/runbook.md | `runbook` | +| README.md | `readme` | + +Invoke per selected type (or `--type=all` if all four non-Phase 4/5 +entries are selected): + +```bash +kei-docs-scaffold.sh [--force] [--dry-run] --type= "$DIR" +``` + +Capture each write line (`[scaffold] wrote: `) into `SCAFFOLDED`. + +## 2c — README banned-public gate + +If `README.md` is in `GAPS`, grep the project for banned-public markers +BEFORE invoking the scaffolder: + +``` +grep -rEi "weight|checkpoint|training-loop|offensive|kernel|guidance-law" "$DIR" --include="*.md" --include="*.toml" +``` + +If matches found → stop and require the user to type `"yes, deploy"` + +`"confirm publication"` literal phrases before proceeding. See +`~/.claude/rules/security.md`. + +## Verify-criterion + +- The scaffolder exited with status 0. +- `SCAFFOLDED` is a non-empty list (unless dry-run was chosen). +- No file outside `$DIR` was written. +- If README was scaffolded, the banned-public grep was clean OR the + double-confirmation was captured. diff --git a/skills/docs-scaffold/phase-3-decisions.md b/skills/docs-scaffold/phase-3-decisions.md new file mode 100644 index 0000000..3406374 --- /dev/null +++ b/skills/docs-scaffold/phase-3-decisions.md @@ -0,0 +1,56 @@ +# Phase 3 — First ADR walk-through (optional) + +Goal: if `DECISIONS.md` was just scaffolded, offer to append one real ADR +now while context is fresh. Otherwise skip. + +## 3a — Gate (AskUserQuestion #3) + +```json +{ + "questions": [ + { + "question": "Append a real ADR now?", + "header": "ADR", + "multiSelect": false, + "options": [ + {"label": "Yes — walk me through ADR-002", "description": "Interactive: I ask context / drivers / options / outcome; I write the entry"}, + {"label": "No — keep the template only", "description": "Phase 2 already wrote ADR-001 Constructor Pattern template; leave it"}, + {"label": "Skip this phase", "description": "Move to Phase 4 diagrams"} + ] + } + ] +} +``` + +On `Skip` or `No` → `ADR_N = 0`, continue to Phase 4. + +## 3b — Free-text elicitation (only if "Yes") + +Ask the user, in a single message (no AskUserQuestion), for four lines: + +1. **Title** (≤ 60 chars) — short decision name +2. **Context** (1-2 sentences) — what forced the decision +3. **Options considered** — comma-separated list (2-4 items) +4. **Chosen option + evidence grade [E1-E6]** — one line + +## 3c — Compose the ADR entry + +Renumber: Read `DECISIONS.md`, find the highest existing `ADR-NNN`, +assign `NNN+1` (three-digit zero-pad). Append the block using the MADR +4.0 shape from `_blocks/docs-decisions-adr.md`. Never rewrite existing +ADR entries. Never drop below the highest existing number. + +Set `ADR_N = 1`. + +## 3d — Show the user the appended block + +Print the new entry inline so they can confirm correctness. No +AskUserQuestion here — they can ask to amend in the next turn. Append- +only invariant stands: amendments become ADR-MMM that supersedes. + +## Verify-criterion + +- `DECISIONS.md` exists at `/DECISIONS.md`. +- The new ADR number is strictly greater than all prior numbers. +- Evidence grade is one of E1-E6; if missing, re-ask before writing. +- No existing ADR entry was modified. diff --git a/skills/docs-scaffold/phase-4-diagrams.md b/skills/docs-scaffold/phase-4-diagrams.md new file mode 100644 index 0000000..c3f75f7 --- /dev/null +++ b/skills/docs-scaffold/phase-4-diagrams.md @@ -0,0 +1,66 @@ +# Phase 4 — Mermaid architecture starter + +Goal: seed `/docs/diagrams/` with a minimal Mermaid file the user +can evolve. Keep it small; the block `_blocks/docs-architecture-diagrams.md` +carries the full pattern catalogue. + +## 4a — Pick starter pattern (AskUserQuestion #4) + +```json +{ + "questions": [ + { + "question": "Seed which Mermaid pattern?", + "header": "Diagram", + "multiSelect": false, + "options": [ + {"label": "System context (flowchart LR)", "description": "One-page overview — User / API / Service / DB / Queue. Good default."}, + {"label": "Sequence (sequenceDiagram)", "description": "Request flow — Client / API / DB. Pick for API-first projects."}, + {"label": "State machine (stateDiagram-v2)","description": "FSM-driven projects — Pending / Running / Done / Failed."}, + {"label": "ER (erDiagram)", "description": "DB schema summary — two related entities."}, + {"label": "Skip this phase", "description": "No diagram seeded; move to Phase 5"} + ] + } + ] +} +``` + +On `Skip` → `DIAGRAMS = 0`, continue to Phase 5. + +## 4b — Write the starter file + +Create `/docs/diagrams/` and write one `.mmd` file matching the +click: + +- `context.mmd` — system context +- `request.mmd` — sequence +- `lifecycle.mmd` — state machine +- `schema.mmd` — ER + +Use the short templates from `_blocks/docs-architecture-diagrams.md` §1-4 +verbatim. Placeholders (User / API / Service / DB / Queue) are fine — +the user evolves them next session. + +If the target file exists → skip and warn; do not overwrite without +`--force` (same contract as Phase 2). + +Set `DIAGRAMS = 1`. + +## 4c — Preview hint (no write) + +After writing, print: + +``` +[docs-scaffold] preview locally: + npm install -g @mermaid-js/mermaid-cli # one-time + mmdc -i /docs/diagrams/.mmd -o /tmp/preview.svg +``` + +No AskUserQuestion; this is just a hint line. + +## Verify-criterion + +- `/docs/diagrams/` directory exists after writing. +- Exactly one `.mmd` file was created (or zero if `Skip` was chosen). +- File is syntactically valid Mermaid (heading matches the picked pattern). +- No other files under `/` were touched. diff --git a/skills/docs-scaffold/phase-5-changelog.md b/skills/docs-scaffold/phase-5-changelog.md new file mode 100644 index 0000000..2e75b06 --- /dev/null +++ b/skills/docs-scaffold/phase-5-changelog.md @@ -0,0 +1,70 @@ +# Phase 5 — CHANGELOG via `kei-changelog` + +Goal: initialize or refresh `/CHANGELOG.md` from the repo's +conventional-commit history using the Rust primitive. + +## 5a — Pick invocation mode (AskUserQuestion #5) + +```json +{ + "questions": [ + { + "question": "CHANGELOG action?", + "header": "Changelog", + "multiSelect": false, + "options": [ + {"label": "Initialize — full history as v0.1.0", "description": "First run. Walks from root to HEAD, writes a single v0.1.0 section."}, + {"label": "Unreleased — since last tag", "description": "Prepends an Unreleased block since the most recent annotated tag."}, + {"label": "Update — since explicit --from ", "description": "User supplies a git ref in the next message (tag name or SHA)"}, + {"label": "Skip this phase", "description": "No CHANGELOG changes; final report only"} + ] + } + ] +} +``` + +On `Skip` → `CHANGELOG_STATUS = skipped`, continue to the final report. + +## 5b — Resolve the binary + +The Rust primitive lives at `_primitives/_rust/kei-changelog/`. Build if +not yet built: + +```bash +( cd _primitives/_rust/kei-changelog && cargo build --release --offline ) \ + || ( cd _primitives/_rust/kei-changelog && cargo build --release ) +``` + +Binary path: `_primitives/_rust/kei-changelog/target/release/kei-changelog`. + +If the build fails (missing `git2` system deps — on Linux needs +`libgit2-dev`), fall back to NO DOWNGRADE advice: + +1. Install system dep: `apt install libgit2-dev` / `brew install libgit2`. +2. Re-run this phase after install. + +## 5c — Run the binary + +Map the click to CLI flags: + +| Click | Command | +|---|---| +| Initialize | `kei-changelog --version v0.1.0 --update "$DIR/CHANGELOG.md" --repo "$DIR"` | +| Unreleased | `kei-changelog --unreleased --from "$(git -C "$DIR" describe --tags --abbrev=0)" --update "$DIR/CHANGELOG.md" --repo "$DIR"` | +| Update | `kei-changelog --from --version --update "$DIR/CHANGELOG.md" --repo "$DIR"` | + +If the `Unreleased` variant fails because there are no annotated tags, +fall back to `--version v0.1.0` and continue — print a short note. + +## 5d — Verify the result + +Read the first 30 lines of `/CHANGELOG.md` and show them inline so +the user confirms the output. Set `CHANGELOG_STATUS` to `initialized`, +`updated`, or `skipped`. + +## Verify-criterion + +- The binary exited with status 0 (or the Skip branch was chosen). +- `/CHANGELOG.md` exists and starts with `# CHANGELOG`. +- New content was prepended, not appended, when the file already existed. +- `CHANGELOG_STATUS` is set to one of the three values above.