feat(skills): /docs-scaffold 5-phase pipeline

This commit is contained in:
Parfii-bot 2026-04-21 20:57:15 +08:00
parent be20f5ba46
commit 63b6b07c06
6 changed files with 424 additions and 0 deletions

View file

@ -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: <project directory | omit to use $PWD>
---
# 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: <DIR>
Stack: <STACK>
Existing: <list>
Scaffolded: <list of new files>
ADRs added: <ADR_N>
Diagrams: <DIAGRAMS>
Changelog: <CHANGELOG_STATUS>
Next action: <what user should run / review / commit>
```
---
## 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`

View file

@ -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=<DIR> STACK=<STACK>`.
## 1b — Audit existing docs
List presence of each target file; store the set as `EXISTING`:
- `<DIR>/CLAUDE.md`
- `<DIR>/DECISIONS.md`
- `<DIR>/docs/runbook.md`
- `<DIR>/README.md`
- `<DIR>/docs/diagrams/` (directory, non-empty)
- `<DIR>/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.

View file

@ -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=<type> "$DIR"
```
Capture each write line (`[scaffold] wrote: <path>`) 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.

View file

@ -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 `<DIR>/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.

View file

@ -0,0 +1,66 @@
# Phase 4 — Mermaid architecture starter
Goal: seed `<DIR>/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 `<DIR>/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 <DIR>/docs/diagrams/<file>.mmd -o /tmp/preview.svg
```
No AskUserQuestion; this is just a hint line.
## Verify-criterion
- `<DIR>/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 `<DIR>/` were touched.

View file

@ -0,0 +1,70 @@
# Phase 5 — CHANGELOG via `kei-changelog`
Goal: initialize or refresh `<DIR>/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 <ref>", "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 <user_ref> --version <user_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 `<DIR>/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).
- `<DIR>/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.