feat(skills): /docs-scaffold 5-phase pipeline
This commit is contained in:
parent
be20f5ba46
commit
63b6b07c06
6 changed files with 424 additions and 0 deletions
93
skills/docs-scaffold/SKILL.md
Normal file
93
skills/docs-scaffold/SKILL.md
Normal 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`
|
||||
67
skills/docs-scaffold/phase-1-intake.md
Normal file
67
skills/docs-scaffold/phase-1-intake.md
Normal 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.
|
||||
72
skills/docs-scaffold/phase-2-scaffold.md
Normal file
72
skills/docs-scaffold/phase-2-scaffold.md
Normal 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.
|
||||
56
skills/docs-scaffold/phase-3-decisions.md
Normal file
56
skills/docs-scaffold/phase-3-decisions.md
Normal 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.
|
||||
66
skills/docs-scaffold/phase-4-diagrams.md
Normal file
66
skills/docs-scaffold/phase-4-diagrams.md
Normal 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.
|
||||
70
skills/docs-scaffold/phase-5-changelog.md
Normal file
70
skills/docs-scaffold/phase-5-changelog.md
Normal 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.
|
||||
Loading…
Reference in a new issue