hstack 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -9
- package/VERSION +1 -1
- package/package.json +1 -1
- package/template/.claude/agents/spec-author.md +7 -2
- package/template/.claude/skills/hstack-change-new/SKILL.md +7 -5
- package/template/.claude/skills/hstack-help/SKILL.md +6 -1
- package/template/.claude/skills/hstack-implement/SKILL.md +2 -2
- package/template/.claude/skills/hstack-ship/SKILL.md +6 -5
- package/template/.claude/skills/hstack-story-draft/SKILL.md +7 -5
- package/template/.claude/skills/hstack-ui-brief/SKILL.md +1 -1
- package/template/CLAUDE.md +7 -0
- package/template/templates/change-spec.md +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to hstack are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows [SemVer](https://semver.org/).
|
|
4
4
|
|
|
5
|
-
## [Unreleased]
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
_Nothing yet._
|
|
8
|
+
|
|
9
|
+
## [0.2.0] - 2026-05-22
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
- **Category-B `enables` carve-out on change-spec.** New frontmatter fields `enables: []` and `enabled-by: []` separate foundational-prerequisite production code (Category B) from engineering-only `internal-tooling: true` (Category A). SP-09 expands to `user-stories` non-empty UNLESS `internal-tooling: true` UNLESS `enables` non-empty. New validator rules SP-13 (mutual exclusion of A and B) and SP-14 (`enables ↔ enabled-by` reciprocity). `/hstack:change-new` reconciles forward references at downstream scaffold time; `/hstack:help` renders the audit chain; `/hstack:ship` gains GT-12. Backwards-compatible — no schema-version bump; existing specs without the fields validate unchanged. See [ADR-0003](adr/ADR-0003-category-b-enables-field.md).
|
|
13
|
+
|
|
14
|
+
### Infrastructure
|
|
15
|
+
- **GitHub Action `publish.yml`.** Pushes to npm on `v*` tags. Verifies tag matches `package.json` version, publishes with `--provenance` and `--access public`. Requires repo secret `NPM_TOKEN`.
|
|
16
|
+
|
|
17
|
+
## [0.1.0] - 2026-05-22
|
|
6
18
|
|
|
7
19
|
### Added
|
|
8
20
|
- **CLI installer.** Three commands shipped on the `hstack` npm package:
|
|
@@ -18,14 +30,8 @@ All notable changes to hstack are documented here. Format follows [Keep a Change
|
|
|
18
30
|
- Framework files relocated from repo root into `template/`. Consumer-facing layout is unchanged — consumers still see `hstack/CLAUDE.md`, `hstack/templates/`, etc. after install.
|
|
19
31
|
- README installation section: `npx hstack init` is now the documented path; manual `cp -r` is the legacy fallback.
|
|
20
32
|
|
|
21
|
-
###
|
|
33
|
+
### Notes
|
|
34
|
+
- 16 Skills, 10 subagents, 25 templates, kernel — first published npm release.
|
|
22
35
|
- No local-edit detection: `hstack update` overwrites consumer hand-edits without warning; the diff preview is the only signal. Hash-manifest mode is planned for v0.2.
|
|
23
36
|
- No CI for the CLI itself; coverage is manual smoke tests across happy / negative paths plus one real consumer (moso-app).
|
|
24
37
|
- No migration scripts: template schema changes between versions need CHANGELOG-driven manual action.
|
|
25
|
-
|
|
26
|
-
## [0.1.0] - 2026-05-22
|
|
27
|
-
|
|
28
|
-
Initial pre-release. Vendored / symlinked distribution only; npm CLI in progress.
|
|
29
|
-
|
|
30
|
-
- 16 Skills, 10 subagents, 25 templates, kernel.
|
|
31
|
-
- See repo history prior to this changelog for detail.
|
package/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.
|
|
1
|
+
0.2.0
|
package/package.json
CHANGED
|
@@ -77,7 +77,12 @@ For change-spec / module-spec / ADR / tech-debt, fill the YAML frontmatter and p
|
|
|
77
77
|
- Use challenge prompts for sections where omission is the failure mode. Invariants on change-spec and module-spec require minimum three bullets, elicited via "Name three things that look like they could change but must not. If you can't name three, why is the change so narrow?"
|
|
78
78
|
- For ADRs, walk Michael Nygard format strictly: Title, Status, Context, Decision, Consequences, Alternatives Considered. Use the challenge prompt on Consequences: "Name two consequences that look bad."
|
|
79
79
|
- Reference, do not duplicate. When a change-spec needs to cite a persona, story, or ADR, write the id, not the prose.
|
|
80
|
-
- Maintain reciprocity. When `tech-debt.origin` is a change-spec id, ensure that change-spec's `creates-tech-debt` array includes the new tech-debt id (TD-01). When writing `tech-debt.resolved-by`, ensure that change-spec's `resolves-tech-debt` array includes this tech-debt id (TD-04). Same for ADR `supersedes` / `superseded-by`. The reciprocal pair always lands in a single auto-commit; one-sided writes are not permitted.
|
|
80
|
+
- Maintain reciprocity. When `tech-debt.origin` is a change-spec id, ensure that change-spec's `creates-tech-debt` array includes the new tech-debt id (TD-01). When writing `tech-debt.resolved-by`, ensure that change-spec's `resolves-tech-debt` array includes this tech-debt id (TD-04). Same for ADR `supersedes` / `superseded-by`. For `change-spec.enables` (Category B foundational-prerequisite linkage), when writing or editing the `enables` array, also write the reciprocal `enabled-by` entry on each downstream change-spec named in the array (SP-14). Forward references — `enables` entries pointing at a not-yet-scaffolded id — are permitted; `/hstack:change-new` reconciles the reciprocal `enabled-by` when the downstream is later scaffolded. The reciprocal pair always lands in a single auto-commit; one-sided writes are not permitted.
|
|
81
|
+
- **The no-story interview branch.** When a change-spec's `user-stories` array would be empty, do not silently set `internal-tooling: true` (the old default). Ask the engineer: "This change has no linked user story. Which category applies?
|
|
82
|
+
- **(A) Internal tooling** — engineering-only code that never ships on a user path (scripts, dev dashboards, CI tooling). Sets `internal-tooling: true`.
|
|
83
|
+
- **(B) Foundational prerequisite** — production code that ships, but user value lives in a named downstream change-spec that consumes this one's output (schema before UI, plumbing before consumer). Sets `enables: [<downstream-id>, ...]` and writes the reciprocal `enabled-by` on each downstream spec.
|
|
84
|
+
- **(C) Neither** — there is actually a user story; let's draft it via `/hstack:story-draft`."
|
|
85
|
+
Categories A and B are mutually exclusive (SP-13). If the engineer is uncertain, walk the audit-query test: "After this ships, if someone asks 'what's the user value of this change?', is the honest answer (A) 'none, it's internal', (B) 'it teed up change-spec X', or (C) 'this user-facing thing'?"
|
|
81
86
|
- **Mechanical operations are not your job.** Per the kernel's Mechanical operations section, status flips, reciprocal writes, Resolution Log appends, and `updated:` date bumps are performed by Skills directly in the main Claude Code session, not by this subagent. The four resolution Skills (`/hstack:tech-debt-resolve`, `/hstack:tech-debt-wontfix`, `/hstack:tech-debt-stale`, `/hstack:finalize`) own those writes themselves. If you are invoked for a mechanical operation, refuse and direct the engineer to run the appropriate Skill — the invocation is a workflow error, not a request to fulfil.
|
|
82
87
|
- ADR ids are sequential. Read the highest existing `ADR-NNNN` and increment by one. No gaps, no reuse.
|
|
83
88
|
- For module-spec, you may grep the In-Scope module's source to verify claims about exports, RPCs, and tables — but do not modify code.
|
|
@@ -96,7 +101,7 @@ Stop and ask the human when:
|
|
|
96
101
|
|
|
97
102
|
A change-spec at terminal author-state (`status: ready-to-plan`) has:
|
|
98
103
|
|
|
99
|
-
- All universal frontmatter (id, type, status, owner, created, updated, schema-version), all change-spec-specific fields (area, surfaces, user-stories, related-spec, in-scope, out-of-scope), and any conditional fields populated.
|
|
104
|
+
- All universal frontmatter (id, type, status, owner, created, updated, schema-version), all change-spec-specific fields (area, surfaces, user-stories, related-spec, in-scope, out-of-scope, internal-tooling, enables, enabled-by), and any conditional fields populated. Exactly one of {`user-stories` non-empty, `internal-tooling: true`, `enables` non-empty} must hold (SP-09); `internal-tooling: true` and `enables` non-empty must not both hold (SP-13).
|
|
100
105
|
- All ten sections from the schema, with Invariants holding three or more bullets and Open Questions either resolved or explicitly punted.
|
|
101
106
|
- A passing validator run.
|
|
102
107
|
|
|
@@ -60,15 +60,17 @@ Before any work:
|
|
|
60
60
|
|
|
61
61
|
2. **Create the folder.** `mkdir -p hstack/specs/changes/<id>/` via Bash.
|
|
62
62
|
|
|
63
|
-
3. **Seed `spec.md`.** Read `hstack/templates/change-spec.md`, instantiate the frontmatter with `id`, `type: change-spec`, `status: draft`, `owner` (from `git config user.name` or `hstack/config.yaml`'s default owner), `area: <area>`, `related-spec: <area>`, `created` and `updated` set to today, `schema-version: 1`. Leave `surfaces`, `user-stories`, `in-scope`, `out-of-scope`, `related-adrs`, `creates-tech-debt`, `parent-change`, `threat-model-delta`, `internal-tooling`, `trivial` as their template defaults (typically empty arrays or `null`). Leave every prose section empty, with the template's interview-prompt comments intact for `spec-author` to consume.
|
|
63
|
+
3. **Seed `spec.md`.** Read `hstack/templates/change-spec.md`, instantiate the frontmatter with `id`, `type: change-spec`, `status: draft`, `owner` (from `git config user.name` or `hstack/config.yaml`'s default owner), `area: <area>`, `related-spec: <area>`, `created` and `updated` set to today, `schema-version: 1`. Leave `surfaces`, `user-stories`, `in-scope`, `out-of-scope`, `related-adrs`, `creates-tech-debt`, `parent-change`, `threat-model-delta`, `internal-tooling`, `enables`, `enabled-by`, `trivial` as their template defaults (typically empty arrays or `null`). Leave every prose section empty, with the template's interview-prompt comments intact for `spec-author` to consume.
|
|
64
64
|
|
|
65
|
-
4. **
|
|
65
|
+
4. **Forward-reference reconciliation for `enables` chains.** Grep every existing `hstack/specs/changes/*/spec.md` for the new `<id>` in `enables:` arrays. For each match: the matched (upstream) spec already declares this new (downstream) spec as a Category-B enabler. Per SP-14, write the reciprocal `enabled-by: [<upstream-id>, ...]` array on the newly-seeded spec in the same scaffold commit (this is the atomic-pair guarantee — both halves land together). When no match exists, leave `enabled-by: []`. Read-only on the upstream spec — its `enables` array was already written when the upstream was authored; no edit there. This is a mechanical operation per the kernel's Mechanical-operations section; no subagent is invoked. Surface the reconciliation to the engineer: "Detected upstream spec(s) declaring `enables: [<id>]` — populating `enabled-by` reciprocally."
|
|
66
66
|
|
|
67
|
-
5. **
|
|
67
|
+
5. **Validate.** Run `{{TODO-SCRIPT: hstack/scripts/validate-spec.ts}}` against the seeded file. Validation at `status: draft` is permissive — empty arrays and empty prose are allowed at draft — but the universal floor (FM-01) must pass.
|
|
68
68
|
|
|
69
|
-
6. **
|
|
69
|
+
6. **Offer branch creation.** Run `git branch --show-current`. If the current branch is `main` (or the configured default), ask the engineer: "You're on `<current-branch>`. Convention is one branch per change-spec — create `change/<id>` from here and check out before the scaffold commits? [Y/n/type-different-name]". Default Yes. On confirmation, run `git checkout -b change/<id>` BEFORE step 7 so the scaffold commit lands on the correct branch from the start. If the engineer declines or names a different branch, honor the choice and continue on the chosen branch. If the current branch is anything other than the configured default (i.e., already on a feature branch), do nothing — the engineer has a deliberate branching strategy and the Skill respects it.
|
|
70
70
|
|
|
71
|
-
7. **
|
|
71
|
+
7. **Auto-commit.** Commit message: `chore(change-new): scaffold <id>`.
|
|
72
|
+
|
|
73
|
+
8. **Surface next steps.** Print a one-line instruction directing the engineer to invoke `spec-author` (or `hstack-story-draft` first if the change is user-facing and no story exists yet). If the change has Category-B `enabled-by` populated from step 4, also note the upstream linkage so the engineer is reminded which prerequisite this realizes.
|
|
72
74
|
|
|
73
75
|
The Skill does not invoke any subagent. Scaffolding is mechanical and the engineer's subsequent moves vary by change.
|
|
74
76
|
|
|
@@ -66,7 +66,12 @@ No subagents are invoked. Every step is a direct file read or shell call.
|
|
|
66
66
|
|
|
67
67
|
1. **Section 1 — Where you are.**
|
|
68
68
|
- Read `hstack/config.yaml` for `init-status` and the active MCP set.
|
|
69
|
-
- Glob `hstack/specs/changes/*/spec.md`. For each, read frontmatter (`id`, `status`, `surfaces`, `owner`, `internal-tooling`, `trivial`, `parent-change`). Filter to non-terminal status (anything before `shipped`, `archived`).
|
|
69
|
+
- Glob `hstack/specs/changes/*/spec.md`. For each, read frontmatter (`id`, `status`, `surfaces`, `owner`, `internal-tooling`, `enables`, `enabled-by`, `trivial`, `parent-change`). Filter to non-terminal status (anything before `shipped`, `archived`).
|
|
70
|
+
- For each in-flight change, classify and surface the no-story carve-out when present:
|
|
71
|
+
- Category A (`internal-tooling: true`) → annotate "[Category A — internal tooling]".
|
|
72
|
+
- Category B (`enables` non-empty) → annotate "[Category B — enables → <comma-separated downstream ids>]". For each downstream id, also note its on-disk status (or "not yet scaffolded" — informational, not a blocker; reconciliation happens at downstream `/hstack:change-new` time).
|
|
73
|
+
- `enabled-by` non-empty → annotate "[Realizes ← <comma-separated upstream ids>]" so the reverse direction of the chain is visible.
|
|
74
|
+
- SP-13 violation (both `internal-tooling: true` AND `enables` non-empty) → flag explicitly as an error.
|
|
70
75
|
- For each in-flight change, compute the **next blocking action**:
|
|
71
76
|
- `status: draft` → "Author via `spec-author` directly (or run `/hstack:story-draft` first if user-facing)."
|
|
72
77
|
- `status: ready-to-plan` and missing conditional artifacts → name them; suggest the appropriate Skill (`/hstack:test-plan` first if missing — it gates the planner, `/hstack:security-review`, `/hstack:data-review` if db, `/hstack:ui-brief` if ui, `/hstack:change-plan`).
|
|
@@ -47,7 +47,7 @@ tools:
|
|
|
47
47
|
|
|
48
48
|
## When to invoke
|
|
49
49
|
|
|
50
|
-
Invoke once the change-spec is at `status: ready-for-implementation` (which means every upstream gate is terminal: test-plan at `passed` or `concerns-acknowledged`, plan at `ready`, security-review at `passed` or `concerns-acknowledged`, data-review at `passed` or `concerns-acknowledged` when applicable, ui-brief at `drafted` and figma-handoff at `ready` when applicable, user-stories non-empty
|
|
50
|
+
Invoke once the change-spec is at `status: ready-for-implementation` (which means every upstream gate is terminal: test-plan at `passed` or `concerns-acknowledged`, plan at `ready`, security-review at `passed` or `concerns-acknowledged`, data-review at `passed` or `concerns-acknowledged` when applicable, ui-brief at `drafted` and figma-handoff at `ready` when applicable, user-stories non-empty UNLESS `internal-tooling: true` UNLESS `enables` non-empty). One invocation per phase. Re-invoke for each subsequent phase.
|
|
51
51
|
|
|
52
52
|
## Inputs
|
|
53
53
|
|
|
@@ -64,7 +64,7 @@ Before any work — the Skill re-checks every gate even when the change-spec car
|
|
|
64
64
|
- Security-review at `status: passed` or `concerns-acknowledged`.
|
|
65
65
|
- Data-review at `status: passed` or `concerns-acknowledged` when `surfaces` includes `db`.
|
|
66
66
|
- ui-brief at `status: drafted` and figma-handoff at `status: ready` when `surfaces` includes `ui`.
|
|
67
|
-
- User-stories non-empty
|
|
67
|
+
- User-stories non-empty UNLESS `internal-tooling: true` (Category A — engineering-only) UNLESS `enables` non-empty (Category B — foundational prerequisite; user value lives in the named downstream change-spec). SP-13: `internal-tooling: true` and `enables` non-empty are mutually exclusive; if both are set, halt with an SP-13 violation message and direct the engineer to `spec-author` to pick one.
|
|
68
68
|
- The relevant module-spec at `status: current`.
|
|
69
69
|
- **Branch state.** Run `git branch --show-current`. If the current branch is `main` (or the configured default) AND `change-spec.trivial` is not `true`, HARD HALT with: "Refusing to implement on `main` — change-spec `<id>` is not marked trivial. Check out `change/<id>` first, or run `/hstack:branch <id>` to create-and-switch." Trivial changes (`trivial: true`) may proceed on main per the kernel's trivial-changes carve-out. This check enforces the kernel's branch-hygiene contract at the last moment before code lands.
|
|
70
70
|
|
|
@@ -47,7 +47,7 @@ Invoke when every per-change artifact is at terminal status and the engineer is
|
|
|
47
47
|
Before any work:
|
|
48
48
|
|
|
49
49
|
- Verify the change folder `hstack/specs/changes/<change-id>/` exists.
|
|
50
|
-
- Verify the change-spec exists. Read its `surfaces`, `internal-tooling`, `trivial` flags to know which conditional gates apply.
|
|
50
|
+
- Verify the change-spec exists. Read its `surfaces`, `internal-tooling`, `enables`, `enabled-by`, `trivial` flags to know which conditional gates apply.
|
|
51
51
|
|
|
52
52
|
The Skill does not pre-halt on artifact non-terminal status — that is what the scorecard reports. It halts only on missing artifacts or unreadable frontmatter.
|
|
53
53
|
|
|
@@ -55,7 +55,7 @@ The Skill does not pre-halt on artifact non-terminal status — that is what the
|
|
|
55
55
|
|
|
56
56
|
1. **Read every change artifact.** Read `spec.md`, `plan.md`, `test-plan.md`, `security-review.md`, `data-review.md` (when surfaces includes db), `ui-brief.md` and `figma-handoff.md` (when surfaces includes ui), `verification.md`, `adversarial-review.md`. Capture each artifact's `status` and key gating fields.
|
|
57
57
|
|
|
58
|
-
2. **Compute the
|
|
58
|
+
2. **Compute the twelve-gate scorecard.** Run `{{TODO-SCRIPT: hstack/scripts/compute-merge-readiness.ts}}` against the artifact set, or inline the equivalent logic:
|
|
59
59
|
- GT-01: spec presence — change folder exists with non-draft change-spec, or PR carries `trivial: true`.
|
|
60
60
|
- GT-02: diff within scope — every file in the PR diff (against the merge target) is a subset of `change-spec.in-scope`.
|
|
61
61
|
- GT-03: pattern lints — every `hstack/lints/*.yaml` rule passes (the Skill runs `{{TODO-SCRIPT: hstack/scripts/run-gates.sh}}` for this and reads the exit code).
|
|
@@ -63,10 +63,11 @@ The Skill does not pre-halt on artifact non-terminal status — that is what the
|
|
|
63
63
|
- GT-05: security-review at `passed` or `concerns-acknowledged`.
|
|
64
64
|
- GT-06: data-review at `passed` or `concerns-acknowledged` (when applicable).
|
|
65
65
|
- GT-07: ui-brief at `drafted` and figma-handoff at `ready` (when applicable).
|
|
66
|
-
- GT-08: `user-stories` non-empty
|
|
66
|
+
- GT-08: `user-stories` non-empty UNLESS `internal-tooling: true` (Category A) UNLESS `enables` non-empty (Category B). The audit-chain assumption: a Category-B spec's user value lives in one of the change-specs named in `enables`; this gate does not transitively verify that downstream spec has `user-stories` non-empty — that's the downstream's GT-08 check, run at its own ship time.
|
|
67
67
|
- GT-09: every cross-reference rule (CG-01..CG-04) passes.
|
|
68
68
|
- GT-10: test-plan at `passed` or `concerns-acknowledged`, and `verification.test-plan-coverage` shows no missing tenant-isolation tests and no out-of-budget performance assertions.
|
|
69
69
|
- GT-11: When `change-spec.resolves-tech-debt` is non-empty: (a) every referenced tech-debt must exist and be at `status: in-progress` with `resolution-attempted-at` set; (b) the adversarial-review must contain the AR-07 Acceptance-satisfied confirmation enumerating each TD's Acceptance bullets against the diff; (c) no referenced tech-debt may have a non-null `resolved-by` already (that would indicate a double-resolution attempt). When `resolves-tech-debt` is empty, GT-11 is `not-applicable`.
|
|
70
|
+
- GT-12 (SP-13 mutual exclusion): `internal-tooling: true` AND `enables` non-empty is forbidden. Hard FAIL. Reciprocity (SP-14): for every id in `enables`, the named downstream spec must exist on disk and must list this change-id in its `enabled-by` array. Missing downstream specs are a FAIL (forward references are only legal at authoring time — by ship time, the downstream must be scaffolded so reciprocity holds). The reverse direction (`enabled-by` entries that point at non-existent or non-listing upstream specs) is also FAIL.
|
|
70
71
|
|
|
71
72
|
3. **Frontmatter validation.** Run `{{TODO-SCRIPT: hstack/scripts/validate-spec.ts}}` across every artifact. Any FM-* or per-type validation failure blocks ship.
|
|
72
73
|
|
|
@@ -78,7 +79,7 @@ The Skill does not pre-halt on artifact non-terminal status — that is what the
|
|
|
78
79
|
- Tech-debt created: pointers from `change-spec.creates-tech-debt`.
|
|
79
80
|
- Test plan: pulled from `test-plan.md` — pyramid summary, tenant-isolation tests, and performance budgets — cross-referenced with `verification.test-plan-coverage` to show observed-vs-promised.
|
|
80
81
|
- Tech-debt resolved: pointers from `change-spec.resolves-tech-debt` with each TD's Title and Acceptance summary. When non-empty, the body explicitly notes that `/hstack:finalize <change-id>` must be run post-merge to flip each TD to `resolved`.
|
|
81
|
-
- Scorecard summary: the
|
|
82
|
+
- Scorecard summary: the twelve-gate table from step 2.
|
|
82
83
|
|
|
83
84
|
The pr-body.md is for the engineer to copy into the actual PR description — the Skill does not call `gh pr create` or otherwise open the PR.
|
|
84
85
|
|
|
@@ -122,7 +123,7 @@ Beyond the kernel's general stop conditions:
|
|
|
122
123
|
- Never write status transitions on any artifact from this Skill. Ship is read-only across the artifact set.
|
|
123
124
|
- Never call `gh pr create` or perform the merge. The engineer opens the PR.
|
|
124
125
|
- Never silently pass a gate. Every FAIL names the artifact and field.
|
|
125
|
-
- Never collapse the
|
|
126
|
+
- Never collapse the twelve gates into a single PASS / FAIL. The scorecard is per-gate.
|
|
126
127
|
- Never flip a tech-debt status from this Skill. That is `/hstack:finalize`'s job and only runs post-merge. Ship surfaces the directive; it does not perform the write.
|
|
127
128
|
- Never extend `change-spec.in-scope` to make GT-02 pass — the scope amendment goes through `spec-author`, not this Skill.
|
|
128
129
|
- Never overwrite `pr-body.md` content the engineer has hand-edited without confirmation. If the file exists with edits beyond the template, surface a diff and ask before rewriting.
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: hstack-story-draft
|
|
3
3
|
description: |
|
|
4
|
-
Use this skill when a user-facing change needs a story drafted or refined, anchored on an existing persona, with a concrete success metric and the user-visible edge cases enumerated. The Skill orchestrates the `product-manager` subagent and is conditional — it does not run when the parent change-spec
|
|
4
|
+
Use this skill when a user-facing change needs a story drafted or refined, anchored on an existing persona, with a concrete success metric and the user-visible edge cases enumerated. The Skill orchestrates the `product-manager` subagent and is conditional — it does not run when the parent change-spec is Category A (`internal-tooling: true`) or Category B (`enables` non-empty), since both carve-outs satisfy SP-09 without a story. Examples:
|
|
5
5
|
|
|
6
6
|
<example>
|
|
7
7
|
Context: The engineer just scaffolded a billing-overage change-spec and needs a linked user story before SP-09 lets the spec advance past draft.
|
|
8
8
|
user: "Draft a story for the billing overage warning, anchored on the growth-marketer persona."
|
|
9
9
|
assistant: "I'll invoke product-manager to walk the five story sections with the growth-marketer persona as the anchor. The story id will land in the configured story store; the change-spec's user-stories array updates reciprocally."
|
|
10
10
|
<commentary>
|
|
11
|
-
Stories are gated by SP-09 (`user-stories` non-empty
|
|
11
|
+
Stories are gated by SP-09 (`user-stories` non-empty UNLESS `internal-tooling: true` UNLESS `enables` non-empty). The Skill produces the story before the change-spec can advance, and writes the reciprocal `linked-change-specs` entry on the story.
|
|
12
12
|
</commentary>
|
|
13
13
|
</example>
|
|
14
14
|
|
|
@@ -36,7 +36,7 @@ tools:
|
|
|
36
36
|
|
|
37
37
|
## Purpose
|
|
38
38
|
|
|
39
|
-
`hstack-story-draft` produces or refines one user story by orchestrating the `product-manager` subagent. It maintains the reciprocal `user-stories` ↔ `linked-change-specs` linkage between the story and its parent change-spec. It is conditional — skipped automatically for changes marked `internal-tooling: true
|
|
39
|
+
`hstack-story-draft` produces or refines one user story by orchestrating the `product-manager` subagent. It maintains the reciprocal `user-stories` ↔ `linked-change-specs` linkage between the story and its parent change-spec. It is conditional — skipped automatically for changes marked Category A (`internal-tooling: true`) or Category B (`enables` non-empty). For Category B, the user value lives in the downstream change-spec(s) named in `enables`; the story (if any) is drafted against that downstream spec, not this one.
|
|
40
40
|
|
|
41
41
|
## When to invoke
|
|
42
42
|
|
|
@@ -56,7 +56,9 @@ Before any work:
|
|
|
56
56
|
- Verify the parent change-spec exists when `--change` is provided or when context implies it.
|
|
57
57
|
- Verify `hstack/context/personas/` (or the configured personas store) contains at least one persona at `status: current`.
|
|
58
58
|
- Verify the configured story store's MCP is reachable when the store is Notion / Linear / GitHub. If unreachable, halt — the kernel forbids silent fallback to a different store.
|
|
59
|
-
- If the parent change-spec carries `internal-tooling: true`, halt and surface
|
|
59
|
+
- If the parent change-spec carries `internal-tooling: true`, halt and surface: "Story not required — change is Category A (internal tooling, never on a user path)."
|
|
60
|
+
- If the parent change-spec carries `enables` non-empty, halt and surface: "Story not required — change is Category B (foundational prerequisite; user value lives in <enables-ids>). Draft a story against the downstream spec instead."
|
|
61
|
+
- If the parent change-spec carries BOTH `internal-tooling: true` AND `enables` non-empty, halt with SP-13 violation: "Categories A and B are mutually exclusive. Pick one via `spec-author`."
|
|
60
62
|
- Read `hstack/context/vision.md`, `mvp-scope.md`, and the personas index (required by `product-manager`'s session-start protocol).
|
|
61
63
|
|
|
62
64
|
## Orchestration steps
|
|
@@ -104,7 +106,7 @@ Beyond the kernel's general stop conditions:
|
|
|
104
106
|
|
|
105
107
|
## Failure modes
|
|
106
108
|
|
|
107
|
-
- **Parent change-spec is `internal-tooling: true
|
|
109
|
+
- **Parent change-spec is `internal-tooling: true` (Category A) or `enables` non-empty (Category B).** Halt early; the story is unnecessary. For Category B, redirect the engineer to draft a story against the downstream change-spec named in `enables`.
|
|
108
110
|
- **Reciprocal write to the parent change-spec would advance its status.** It should not — the reciprocal write only touches the `user-stories` array. If the validator detects a status change, halt and ask.
|
|
109
111
|
- **Validator fails.** Halt and surface; the engineer rewords the failing field.
|
|
110
112
|
|
|
@@ -52,7 +52,7 @@ Before any work:
|
|
|
52
52
|
- Verify `surfaces` includes `ui`. If not, halt with the surface-conditional message.
|
|
53
53
|
- Verify the configured design-system resources are reachable per their declared source in `hstack/config.yaml` (`design-system.components.source`, `tokens.source`, `brand-guidelines.source`). For each resource the brief will need: `in-repo` paths must resolve; `figma-mcp` / `notion-mcp` sources require the corresponding MCP to be wired and reachable (UI-surface changes are high-stakes — graceful degradation is not safe here); `submodule` / `npm` / `external-other` must fetch. A resource at `source: none` is treated as "not yet captured" — halt if the brief genuinely needs it, otherwise proceed against the resources that ARE configured.
|
|
54
54
|
- Verify the `design-system-version` declared in `hstack/config.yaml` is current and is what the brief will reference. Halt on drift.
|
|
55
|
-
- Read the change-spec's `user-stories` array; verify each story is reachable in the configured store and read it. Halt if any linked story or its persona is missing.
|
|
55
|
+
- Read the change-spec's `user-stories` array; verify each story is reachable in the configured store and read it. Halt if any linked story or its persona is missing. An empty `user-stories` is acceptable when the change is Category A (`internal-tooling: true`) — e.g., an internal dev dashboard — or Category B (`enables` non-empty) — e.g., a design-system primitive whose user-facing consumer is the downstream change. In the Category-B case, surface the upstream/downstream context: the brief still describes layout/copy for THIS change's UI, but the user-value story lives in the downstream spec named in `enables`.
|
|
56
56
|
|
|
57
57
|
## Orchestration steps
|
|
58
58
|
|
package/template/CLAUDE.md
CHANGED
|
@@ -139,6 +139,13 @@ Naming rules: `id` is kebab-case and immutable once written; dates are ISO 8601;
|
|
|
139
139
|
|
|
140
140
|
**Change-spec carries an optional `revisits-change` array.** When a new change-spec is filed to fix a defect, regression, or missed adversarial-review finding from a prior shipped change, the engineer populates `revisits-change: [<predecessor-change-id>]` so post-merge defect correlation is computable (`/hstack:telemetry` § QO-6 when promoted from watch-list to dashboard). Default empty. The field is informational, not gating — no Skill refuses to advance because the array is empty or non-empty.
|
|
141
141
|
|
|
142
|
+
**Change-spec carries `internal-tooling` (Category A) and `enables` (Category B) as the two no-story carve-outs.** A change-spec with no driving user story must declare one of two categories before status advances past `draft` (SP-09):
|
|
143
|
+
|
|
144
|
+
- **Category A — `internal-tooling: true`.** Engineering-only code that never ships on a user path: CI tooling, dev scripts, repo automation, internal dashboards. No `enables` linkage exists because no downstream user-facing change is teed up.
|
|
145
|
+
- **Category B — `enables: [<downstream-change-spec-id>, ...]`.** Production code that ships, but user value is realized by a named downstream change-spec that consumes this one's output. Typical case: schema or plumbing landed ahead of the UI that surfaces it. The reciprocal field `enabled-by: []` on the downstream spec is written atomically with `enables`.
|
|
146
|
+
|
|
147
|
+
The two flags are mutually exclusive (SP-13): a change is Category A *or* Category B, never both. If neither applies, `user-stories` must be non-empty. The audit query *"what's the user value of this change?"* follows the `enables` chain until it hits a spec with `user-stories` non-empty (the user-value realization point) or a dead end. Forward references are permitted at authoring time — if `enables` names a not-yet-scaffolded id, `/hstack:change-new` reconciles the reciprocal `enabled-by` when the downstream spec is later scaffolded. Reciprocity (`change-spec.enables ↔ change-spec.enabled-by`) is enforced by SP-14 and lands in a single atomic commit, matching the kernel's other reciprocal-pair rules.
|
|
148
|
+
|
|
142
149
|
---
|
|
143
150
|
|
|
144
151
|
## Status lifecycle
|
|
@@ -13,7 +13,9 @@ resolves-tech-debt: [] # tech-debt ids this change is intended t
|
|
|
13
13
|
parent-change: null
|
|
14
14
|
children: []
|
|
15
15
|
revisits-change: [] # change-spec ids this change is filed to repair (defects, regressions, missed findings). Informational, not gating.
|
|
16
|
-
internal-tooling: false
|
|
16
|
+
internal-tooling: false # Category A — engineering-only, never on a user path
|
|
17
|
+
enables: [] # Category B — downstream change-spec ids that realize user value from this change
|
|
18
|
+
enabled-by: [] # reciprocal of upstream specs' `enables` arrays; written by /hstack:change-new at scaffold time
|
|
17
19
|
trivial: false
|
|
18
20
|
in-scope: [] # repo-relative globs; must be non-empty
|
|
19
21
|
out-of-scope: [] # required, may be empty
|