hstack 0.4.0 → 0.5.1
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 +47 -0
- package/README.md +56 -14
- package/VERSION +1 -1
- package/package.json +1 -1
- package/template/.claude/agents/app-architect.md +154 -0
- package/template/.claude/agents/data-architect.md +147 -0
- package/template/.claude/agents/product-discovery.md +165 -0
- package/template/.claude/agents/stack-architect.md +137 -0
- package/template/.claude/agents/verifier.md +6 -2
- package/template/.claude/skills/hstack-app-architecture/SKILL.md +109 -0
- package/template/.claude/skills/{hstack-init → hstack-brownfield-init}/SKILL.md +17 -11
- package/template/.claude/skills/hstack-data-architecture/SKILL.md +100 -0
- package/template/.claude/skills/hstack-greenfield-init/SKILL.md +150 -0
- package/template/.claude/skills/hstack-product-discovery/SKILL.md +101 -0
- package/template/.claude/skills/hstack-scaffold/SKILL.md +140 -0
- package/template/.claude/skills/hstack-stack-decide/SKILL.md +108 -0
- package/template/.claude/skills/hstack-verify/SKILL.md +15 -4
- package/template/CLAUDE.md +20 -6
- package/template/templates/app-architecture.md +102 -0
- package/template/templates/bootstrap.md +105 -0
- package/template/templates/data-architecture.md +147 -13
- package/template/templates/discovery/brainstorm.md +69 -0
- package/template/templates/discovery/forcing-questions.md +76 -0
- package/template/templates/discovery/project-brief.md +53 -0
- package/template/templates/product-brief.md +56 -0
|
@@ -20,6 +20,15 @@ description: |
|
|
|
20
20
|
Discrepancies between predicted and observed behavior are exactly what section 4 exists to capture. Marking `passed` over a discrepancy would defeat the purpose of the gate.
|
|
21
21
|
</commentary>
|
|
22
22
|
</example>
|
|
23
|
+
|
|
24
|
+
<example>
|
|
25
|
+
Context: The integration suite is gated by `RUN_INTEGRATION=1` and the engineer ran `npm test` without setting it; the runner reported `Tests: 0 passed, 0 failed`.
|
|
26
|
+
user: "/hstack:verify 2026-06-knowledge-citations"
|
|
27
|
+
assistant: "I'll invoke verifier. Per V-05, an integration suite that executed zero tests is recorded as `not-run`, not `pass` — zero failures is not evidence of correctness when there were zero assertions to fail. The Skill halts at `status: ran` with a high-severity Discrepancy naming the suspected reason (env-gated, all-skipped, empty-collection, or filter-collapse)."
|
|
28
|
+
<commentary>
|
|
29
|
+
V-05 closes the verifier false-positive where a suite gated by an unset env var would silently pass on the absence of failures. The remediation is either supplying the missing env / fixture and re-running, or amending the plan's Verifier Expectations via scope amendment so the zero-test state is intentional and recorded.
|
|
30
|
+
</commentary>
|
|
31
|
+
</example>
|
|
23
32
|
tools:
|
|
24
33
|
- Read
|
|
25
34
|
- Write
|
|
@@ -28,8 +37,8 @@ tools:
|
|
|
28
37
|
- Glob
|
|
29
38
|
- Bash
|
|
30
39
|
- Task
|
|
31
|
-
- "{{TODO-SCRIPT: hstack/scripts/run-gates.sh — runs the consuming repo's test/lint/typecheck suite and captures output}}"
|
|
32
|
-
- "{{TODO-SCRIPT: hstack/scripts/validate-spec.ts — validates verification.md frontmatter and V-01/V-02}}"
|
|
40
|
+
- "{{TODO-SCRIPT: hstack/scripts/run-gates.sh — runs the consuming repo's test/lint/typecheck suite and captures output, including an observed-test-count per suite for V-05}}"
|
|
41
|
+
- "{{TODO-SCRIPT: hstack/scripts/validate-spec.ts — validates verification.md frontmatter and V-01/V-02/V-05}}"
|
|
33
42
|
---
|
|
34
43
|
|
|
35
44
|
## Purpose
|
|
@@ -62,7 +71,7 @@ Before any work:
|
|
|
62
71
|
|
|
63
72
|
3. **Phase coverage mapping.** For each phase in `plan.steps-completed`, the subagent emits an entry in `phase-coverage` with a PASS / FAIL value computed from whether the phase's Verifier Expectations are met. Per V-01, `phase-coverage` keys must equal `plan.steps-completed`.
|
|
64
73
|
|
|
65
|
-
4. **Test-results map.** The subagent writes the top-level `test-results` map covering `unit`, `integration`, `e2e`, `lint`, `typecheck`. Per V-02, any `failed` value blocks `status: passed`.
|
|
74
|
+
4. **Test-results map.** The subagent writes the top-level `test-results` map covering `unit`, `integration`, `e2e`, `lint`, `typecheck`. Per V-02, any `failed` value blocks `status: passed`. Per V-05, before mapping `unit`, `integration`, or `e2e` to `pass`, the subagent confirms the runner's observed-test-count for that suite is greater than zero — a suite gated by an unset env var, all-skipped, empty-collection, or filter-collapsed to zero tests is recorded as `not-run` with a high-severity Discrepancy, not as `pass` on the absence of failures.
|
|
66
75
|
|
|
67
76
|
5. **Test-plan coverage check.** The subagent walks the test-plan's Edge Cases bullets, Tenant Isolation Tests array, and Performance Budgets table, and confirms each observed in the test run. `test-plan-coverage` frontmatter map captures the three subsections. Per V-03, any tenant-isolation test absent or skipped blocks `status: passed` and is escalated to adversarial-review via Discrepancies. Per V-04, any performance-budget assertion that did not execute or that observed values outside the declared budget blocks `status: passed`.
|
|
68
77
|
|
|
@@ -72,7 +81,7 @@ Before any work:
|
|
|
72
81
|
|
|
73
82
|
8. **Change-spec advance (mechanical, only on `passed`, Skill-orchestrator write per ADR-0002).** When and only when the subagent returned with `verification.md` at `status: passed`, read `hstack/specs/changes/<change-id>/spec.md` and inspect its `status` frontmatter. If `status: ready-for-implementation`, print a proposed-diff preview of the change-spec edit (`status: ready-for-implementation → ready-for-review`; `updated: <today>`) and prompt "Proceed with this change-spec advance? (Y/n)". Default Yes. On confirmation, perform the edit via the `Edit` tool, run `{{TODO-SCRIPT: hstack/scripts/validate-spec.ts}}` against the change-spec, then `git add` and commit with message `change-spec(<change-id>): ready-for-review`. This is a separate commit from the `verification(<change-id>): passed` commit — one commit per status transition, matching the finalize precedent. If the change-spec is already at `ready-for-review` or any downstream status, this step is a no-op (idempotent on re-runs). When verification status is `ran` or `failed`, this step does not run — the change-spec remains at `ready-for-implementation` until a subsequent re-run lands `passed`. Do NOT invoke `spec-author` for this write; per the kernel's Mechanical operations section, the value to write is fully determined by the verification postcondition and the change-spec's current status, so the Skill writes directly.
|
|
74
83
|
|
|
75
|
-
9. **Validate.** Run `{{TODO-SCRIPT: hstack/scripts/validate-spec.ts}}` — V-01, V-02, V-03, V-04.
|
|
84
|
+
9. **Validate.** Run `{{TODO-SCRIPT: hstack/scripts/validate-spec.ts}}` — V-01, V-02, V-03, V-04, V-05.
|
|
76
85
|
|
|
77
86
|
## Outputs
|
|
78
87
|
|
|
@@ -121,6 +130,7 @@ Beyond the kernel's general stop conditions:
|
|
|
121
130
|
- A canonical command in `ci-cd.md` is missing or cannot execute (missing dependency, missing env var).
|
|
122
131
|
- A phase's Verifier Expectations cannot be evaluated because the relevant test file is missing.
|
|
123
132
|
- A test failure blocks `status: passed`. The Skill halts at `status: ran` (or `failed`) until the implementer fixes the failing test via a new `hstack-implement` invocation.
|
|
133
|
+
- A `unit`, `integration`, or `e2e` suite executed zero tests (V-05). The Skill halts at `status: ran`; the subagent records the suite as `not-run` and logs the Discrepancy. Remediation is either (a) the implementer supplies the missing env / fixture so the suite collects and runs, or (b) a scope amendment removes the suite from the plan's Verifier Expectations so the zero-test state is intentional and recorded.
|
|
124
134
|
|
|
125
135
|
## Failure modes
|
|
126
136
|
|
|
@@ -131,6 +141,7 @@ Beyond the kernel's general stop conditions:
|
|
|
131
141
|
## Anti-patterns
|
|
132
142
|
|
|
133
143
|
- Never invent a PASS. If tests are not green, status is `ran` or `failed`, not `passed`.
|
|
144
|
+
- Never record a suite as `pass` on the absence of failures alone (V-05). A suite that ran zero tests — gated by an unset env var, all `.skip` / `.todo`, empty collection, or filter-collapsed — is `not-run`, not `pass`. The Skill propagates the zero-tests-ran signal from the runner output into the subagent context so the rule is enforceable rather than inferred.
|
|
134
145
|
- Never skip a canonical command. The consuming repo's commands in `ci-cd.md` are mandatory.
|
|
135
146
|
- Never silently drop a discrepancy. Even benign discrepancies get a one-line note.
|
|
136
147
|
- Never score security or data. Stay in the mechanical-verification lane.
|
package/template/CLAUDE.md
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
hstack-version: v0.
|
|
2
|
+
hstack-version: v0.5.0
|
|
3
3
|
authority: kernel
|
|
4
4
|
---
|
|
5
5
|
|
|
@@ -139,12 +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)
|
|
142
|
+
**Change-spec carries `internal-tooling` (Category A), `enables` (Category B), and `area: bootstrap` (Category C) as the three no-story carve-outs.** A change-spec with no driving user story must declare one of three categories before status advances past `draft` (SP-09):
|
|
143
143
|
|
|
144
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
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
|
+
- **Category C — `area: bootstrap`.** The one-time greenfield scaffold change-spec. The code ships on user paths, but the explicit `enables` list would be degenerate (every future change-spec would be a target) and `internal-tooling: true` would be dishonest. The `area: bootstrap` value satisfies SP-09 as the third carve-out. Bootstrap is produced by `/hstack:scaffold` (Phase 6 of `/hstack:greenfield-init`) and runs at most once per project lifetime; the canonical template is `hstack/templates/bootstrap.md`.
|
|
146
147
|
|
|
147
|
-
The
|
|
148
|
+
The three flags are mutually exclusive (SP-13): a change is Category A, Category B, or Category C — never two. If none applies, `user-stories` must be non-empty. The audit query *"what's the user value of this change?"* follows the `enables` chain (Category B) until it hits a spec with `user-stories` non-empty, terminates at Category A with "none, it's internal", or terminates at Category C with "it bootstraps the project; all subsequent changes inherit from it." 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
149
|
|
|
149
150
|
---
|
|
150
151
|
|
|
@@ -198,6 +199,8 @@ Subagents are expensive. Each fresh subagent invocation pays the cost of its sys
|
|
|
198
199
|
|
|
199
200
|
The kernel rule reading: *"spec-author is the only **subagent** permitted to write under `hstack/specs/`, `hstack/adr/`, and `hstack/tech-debt/`."* The Skill orchestrator running in the main Claude Code session is not a subagent. Skills are therefore permitted to perform mechanical frontmatter writes directly, without invoking a subagent. ADR-0001 documents the decision.
|
|
200
201
|
|
|
202
|
+
**Narrow carve-out for `app-architect`.** The `app-architect` subagent may scaffold `hstack/specs/<module>/spec.md` **stubs** (headers only, `status: draft`, body note pointing to `/hstack:module-spec`) at the terminal state of its own atom, as pre-allocation for downstream `spec-author` work. The carve-out is scoped narrowly: stubs are not authored content (no body prose, no filled sections), they land in one atomic commit alongside `app-architecture.md` advancing to `current`, and the engineer's first invocation of `/hstack:module-spec <module>` reverse-engineers the stub into authored content via the normal `spec-author` interview. Any other subagent attempting to write under `hstack/specs/` is rejected per the original rule.
|
|
203
|
+
|
|
201
204
|
**What counts as a mechanical operation.** Operations where no open-ended interview is required — values are determined by the Skill's preconditions, the engineer's invocation arguments, or a structured-elicitation loop with a fixed question set and bounded answer shape:
|
|
202
205
|
|
|
203
206
|
- **Status flips** — advancing an artifact's `status` field along the lifecycle. The engineer's invocation of the Skill (and any acknowledgement gate the Skill carries) is the confirmation.
|
|
@@ -216,6 +219,9 @@ The kernel rule reading: *"spec-author is the only **subagent** permitted to wri
|
|
|
216
219
|
- `/hstack:tech-debt-wontfix` — TD `open → wontfix`; `wontfix-reason` and `wontfix-accepted-alternative` writes; Resolution Log append.
|
|
217
220
|
- `/hstack:tech-debt-stale` — TD `open → stale-no-longer-reproducible`; `stale-verified-at` and `stale-verification-method` writes; Resolution Log append.
|
|
218
221
|
- `/hstack:tech-debt-new` — reciprocal `creates-tech-debt` write on the originating change-spec after `spec-author` finishes the TD authoring interview.
|
|
222
|
+
- `/hstack:app-architecture` — at terminal state, three-file atomic commit: `app-architecture.md` advances to `status: current`; one `hstack/specs/<module>/spec.md` stub per module from Section 1 (under the `app-architect` carve-out above); `hstack/config.yaml`'s `surfaces` enum updated to match Section 5. All three writes land in one git commit; the proposed-diff preview runs before commit per the standard mechanical-operations contract.
|
|
223
|
+
- `/hstack:stack-decide` — optional `hstack/config.yaml` default-stack update after per-layer ADRs land, when the engineer wants a layer's choice to become the project-wide default. Mechanical write, proposed-diff preview, single commit.
|
|
224
|
+
- `/hstack:scaffold` — generates the bootstrap change-spec's `in-scope` enumeration (from app-architecture Module Map + data-architecture Migration Sketches + standard infra files) and pre-populates `related-adrs` from Phase 4 ADRs. The change-spec lands at `status: draft`; `spec-author` walks the engineer through confirm-or-revise to reach `ready-to-plan`. After that, the standard per-change workflow Skills run unchanged.
|
|
219
225
|
|
|
220
226
|
**Discipline preserved.** Skills doing direct writes still honor:
|
|
221
227
|
|
|
@@ -297,11 +303,13 @@ Subagents and Skills in v1 must not falsely assert v2 guarantees. The `security-
|
|
|
297
303
|
|
|
298
304
|
The product context layer lives at `hstack/context/`:
|
|
299
305
|
|
|
306
|
+
- `product/product-brief.md` — the durable thinking artifact capturing the project's product reasoning. Produced by `product-discovery` via one of three techniques (Brainstorm, Forcing-Questions, Project-Brief). Upstream of `vision.md`, `mvp-scope.md`, `personas/`, `glossary.md` — those are refreshed from the brief by `product-manager` via auto-route.
|
|
300
307
|
- `vision.md` — what the product is, what it does, what it is not.
|
|
301
308
|
- `glossary.md` — terms with non-obvious meaning.
|
|
302
309
|
- `mvp-scope.md` — in MVP, in v2, deferred.
|
|
303
310
|
- `personas/` — one file per persona, or one row per persona in the configured store.
|
|
304
|
-
- `data-architecture.md` —
|
|
311
|
+
- `data-architecture.md` — five-section foundational design (Tenancy, Entities, RLS, RAG, Migration Sketches). Produced by `data-architect`. Carries `assumes-database: postgres` in frontmatter (or alternative with explicit rationale).
|
|
312
|
+
- `app-architecture.md` — five-section internal-architecture design (Module Map, Agent Orchestration, Deterministic-vs-LLM Split, State-Ownership, Surface Boundaries). Produced by `app-architect`. Stack-agnostic by design; does not name frameworks.
|
|
305
313
|
- `tech-stack.md` — canonical languages, frameworks, libraries.
|
|
306
314
|
- `ci-cd.md` — CI/CD setup of the consuming repo.
|
|
307
315
|
- `infrastructure.md` — operational truth: hosting, networking, secrets, environments, deploy pipeline, observability, cost, disaster recovery, blast-radius matrix, access control, compliance posture, third-party dependencies. Truth-gathering, not policy — `threat-model.md` and `hardening-checklist.md` carry the policy and score against this file.
|
|
@@ -311,7 +319,11 @@ The product context layer lives at `hstack/context/`:
|
|
|
311
319
|
|
|
312
320
|
Load-at-session-start rules by subagent:
|
|
313
321
|
|
|
314
|
-
- `product-
|
|
322
|
+
- `product-discovery`: kernel, the chosen technique script (`hstack/templates/discovery/<technique>.md`), `product-brief.md` if it exists (resume mode), and in extract mode any source documents the engineer points at.
|
|
323
|
+
- `product-manager`: vision, personas, mvp-scope, glossary. In auto-route from `product-discovery`: also the brief.
|
|
324
|
+
- `data-architect`: kernel, product-brief, vision, mvp-scope, personas, glossary, data-architecture if it exists. In extract mode: live schema via Supabase MCP and `supabase/migrations/`.
|
|
325
|
+
- `app-architect`: kernel, product-brief, data-architecture, vision, mvp-scope, personas, glossary, app-architecture if it exists. Explicitly NOT `tech-stack.md` — app-architecture is stack-agnostic by design. In extract mode: consuming-repo source tree.
|
|
326
|
+
- `stack-architect`: kernel, product-brief, data-architecture, app-architecture, `hstack/config.yaml`'s default-stack declaration, all existing ADRs, threat-model and hardening-checklist if they exist. In standalone mode (`--layer <name>`): additionally `infrastructure.md`.
|
|
315
327
|
- `spec-author`: glossary, tech-stack, the relevant module-spec.
|
|
316
328
|
- `test-strategist`: change-spec, module-spec, tech-stack, ci-cd, data-architecture (when surfaces includes db), existing test files within in-scope.
|
|
317
329
|
- `planner`: change-spec, test-plan, ui-brief, figma-handoff, data-review (when present).
|
|
@@ -362,7 +374,9 @@ When a Skill or subagent halts at any of the stop conditions above, it emits one
|
|
|
362
374
|
HSTACK-HALT: reason=<enum>
|
|
363
375
|
```
|
|
364
376
|
|
|
365
|
-
Where `<enum>` is one of: `scope-amendment | upstream-non-terminal | mcp-unreachable | forbidden-tool | test-immutability-protocol | missing-context | ambiguous-spec | environment-misconfig | branch-mismatch | other`.
|
|
377
|
+
Where `<enum>` is one of: `scope-amendment | upstream-non-terminal | mcp-unreachable | forbidden-tool | test-immutability-protocol | missing-context | ambiguous-spec | environment-misconfig | branch-mismatch | upstream-drift | other`.
|
|
378
|
+
|
|
379
|
+
The `upstream-drift` value is emitted by discovery atoms (`product-discovery`, `data-architect`, `app-architect`, `stack-architect`) when a section's drift challenge surfaces a contradiction with an upstream artifact (e.g., a data-architecture entity that has no trace to a persona in the product-brief, or an app-architecture flow whose state-ownership requires an entity the data-architecture doesn't have). Distinct from `upstream-non-terminal` (which means an upstream artifact is still at `draft`) and from `scope-amendment` (which means an in-scope file is missing). Drift is bidirectional: a downstream atom finding an upstream gap reroutes through `/hstack:configure <upstream-atom>`, the upstream refreshes, the downstream resumes.
|
|
366
380
|
|
|
367
381
|
The sentinel is a single line, costs zero LLM tokens to emit, and makes post-hoc halt-frequency analysis cheap (see `/hstack:telemetry` § WS-6). The sentinel is appended to the auto-commit body when a halt coincides with a status-flip commit; otherwise it appears in the conversation alone (the telemetry parser reads both transcript text and commit bodies). Halting still includes the prose explanation of the situation — the sentinel does not replace the human-readable reason, it complements it.
|
|
368
382
|
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: app-architecture
|
|
3
|
+
type: app-architecture
|
|
4
|
+
status: draft # draft | current | needs-refresh | archived
|
|
5
|
+
owner: <git-handle>
|
|
6
|
+
derived-from: [product-brief, data-architecture]
|
|
7
|
+
downstream: [threat-model, hardening-checklist, tech-stack, module-spec/*]
|
|
8
|
+
created: <YYYY-MM-DD>
|
|
9
|
+
updated: <YYYY-MM-DD>
|
|
10
|
+
schema-version: 1
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. Module Map
|
|
14
|
+
|
|
15
|
+
_The set of modules and what each owns. Each module must trace to either a persona-named action in `product-brief.md` or to a logical clustering of entities from `data-architecture.md`. Orphan modules (no trace) halt the section with the drift challenge._
|
|
16
|
+
|
|
17
|
+
**Modules**
|
|
18
|
+
|
|
19
|
+
| Module | Owns | Traces to |
|
|
20
|
+
| --- | --- | --- |
|
|
21
|
+
| <module-name> | <one-line statement of what this module owns> | <persona-action OR entity-cluster> |
|
|
22
|
+
|
|
23
|
+
**Drift challenge answered**
|
|
24
|
+
|
|
25
|
+
_"Does any module here own state a persona never interacts with, OR does any persona's journey traverse modules in a way the boundaries don't support?"_
|
|
26
|
+
|
|
27
|
+
## 2. Agent Orchestration Model
|
|
28
|
+
|
|
29
|
+
_How LLM calls compose. Which modules call the LLM, what each call returns, how downstream modules consume the output. Tool boundaries. Where prompts live. For an AI-native SaaS, this is the meaty section — implicit "the LLM handles it" answers are rejected; named call sites and downstream consumers are required._
|
|
30
|
+
|
|
31
|
+
**LLM call sites**
|
|
32
|
+
|
|
33
|
+
| Call site (module.fn) | Trigger | Model | Returns | Downstream consumer |
|
|
34
|
+
| --- | --- | --- | --- | --- |
|
|
35
|
+
| <module>.<function> | <what triggers this call> | <model identifier> | <structured-output schema or one-line description> | <module that consumes> |
|
|
36
|
+
|
|
37
|
+
**Tool boundaries**
|
|
38
|
+
|
|
39
|
+
_Which tools each call site can invoke, and which are explicitly out-of-bounds. Names the kill switches for LLM-driven actions._
|
|
40
|
+
|
|
41
|
+
**Drift challenge answered**
|
|
42
|
+
|
|
43
|
+
_"Does any LLM call site bypass the tool boundaries declared, or have an unnamed retry / fallback path?"_
|
|
44
|
+
|
|
45
|
+
## 3. Deterministic-vs-LLM Split
|
|
46
|
+
|
|
47
|
+
_Per user-facing flow, the per-step decision: code or prompt, with a rationale that ties to a measurable property (determinism, cost, latency, capability). Implicit "AI handles it end-to-end" answers are rejected; per-step declaration is mandatory._
|
|
48
|
+
|
|
49
|
+
**Flow tables**
|
|
50
|
+
|
|
51
|
+
For each flow named in the brief's persona vignettes:
|
|
52
|
+
|
|
53
|
+
### Flow: <flow-name>
|
|
54
|
+
|
|
55
|
+
_From <persona>'s Tuesday-morning workflow._
|
|
56
|
+
|
|
57
|
+
| Step | Mechanism | Rationale (ties to measurable property) |
|
|
58
|
+
| --- | --- | --- |
|
|
59
|
+
| 1. <step description> | deterministic \| llm | <one sentence — property: determinism \| cost \| latency \| capability> |
|
|
60
|
+
| 2. ... | ... | ... |
|
|
61
|
+
|
|
62
|
+
**Drift challenge answered**
|
|
63
|
+
|
|
64
|
+
_"Does any flow have a step where the mechanism is undeclared, or a rationale that doesn't tie to a measurable property?"_
|
|
65
|
+
|
|
66
|
+
## 4. State-Ownership Map
|
|
67
|
+
|
|
68
|
+
_Where conversation state lives, workspace state lives, ephemeral / browser-session state lives. Each state class names its owning module from Section 1 and its persistence layer from `data-architecture.md`. State without an owning module triggers the drift challenge._
|
|
69
|
+
|
|
70
|
+
**State classes**
|
|
71
|
+
|
|
72
|
+
| State class | Owning module | Persistence layer | Lifetime |
|
|
73
|
+
| --- | --- | --- | --- |
|
|
74
|
+
| <e.g., conversation history> | <module from §1> | <entity from data-architecture OR "ephemeral"> | <durable \| session \| request> |
|
|
75
|
+
|
|
76
|
+
**Drift challenge answered**
|
|
77
|
+
|
|
78
|
+
_"Does any state class lack an owning module from Section 1?"_
|
|
79
|
+
|
|
80
|
+
## 5. Surface Boundaries
|
|
81
|
+
|
|
82
|
+
_What the project's `surfaces` enum contains. The canonical floor is `[ui, api, agent, db, auth, infra]`; projects may add (e.g., `payments`) or omit (e.g., no `auth` if relying on a host system). Each declared surface is mapped to at least one module from Section 1._
|
|
83
|
+
|
|
84
|
+
**Surface declaration**
|
|
85
|
+
|
|
86
|
+
| Surface | In v1? | Modules carrying this surface | Deferred to |
|
|
87
|
+
| --- | --- | --- | --- |
|
|
88
|
+
| ui | yes/no | <module names> | <v2 \| later \| N/A> |
|
|
89
|
+
| api | ... | ... | ... |
|
|
90
|
+
| agent | ... | ... | ... |
|
|
91
|
+
| db | ... | ... | ... |
|
|
92
|
+
| auth | ... | ... | ... |
|
|
93
|
+
| infra | ... | ... | ... |
|
|
94
|
+
| <custom> | ... | ... | ... |
|
|
95
|
+
|
|
96
|
+
**Drift challenge answered**
|
|
97
|
+
|
|
98
|
+
_"Does any surface in the enum have no module from Section 1 mapped to it?"_
|
|
99
|
+
|
|
100
|
+
## Coherence check (end-of-atom)
|
|
101
|
+
|
|
102
|
+
_When the atom reaches terminal state, the agent re-runs all five drift challenges to ensure section-targeted edits did not silently break other sections. The coherence check is fatal — any unanswered challenge halts the commit._
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: <YYYY-MM-bootstrap> # canonical bootstrap change-id; one per project
|
|
3
|
+
type: change-spec # bootstrap is a change-spec variant, not a new type
|
|
4
|
+
status: draft
|
|
5
|
+
owner: <git-handle>
|
|
6
|
+
area: bootstrap # the no-story carve-out for the bootstrap variant; SP-09 satisfied via this
|
|
7
|
+
surfaces: [infra] # bootstrap is infra-only; UI / agent / api work begins post-bootstrap
|
|
8
|
+
user-stories: [] # bootstrap has no user-story; the area: bootstrap field satisfies SP-09 as a third carve-out alongside internal-tooling and enables
|
|
9
|
+
related-spec: bootstrap # equals area
|
|
10
|
+
related-adrs: [] # populated with every stack ADR from Phase 4
|
|
11
|
+
creates-tech-debt: []
|
|
12
|
+
resolves-tech-debt: []
|
|
13
|
+
parent-change: null
|
|
14
|
+
children: []
|
|
15
|
+
revisits-change: []
|
|
16
|
+
internal-tooling: false # bootstrap is NOT internal-tooling — the code ships on the user path
|
|
17
|
+
enables: [] # bootstrap implicitly enables every downstream change-spec; the explicit list would be degenerate, so we leave it empty and rely on area: bootstrap as the SP-09 carve-out
|
|
18
|
+
enabled-by: []
|
|
19
|
+
trivial: false
|
|
20
|
+
in-scope: [] # explicit file enumeration — NOT ["."]
|
|
21
|
+
out-of-scope: [] # required, may be empty
|
|
22
|
+
threat-model-delta: true # bootstrap always touches threat-model (auth posture, RLS defaults, secret handling)
|
|
23
|
+
created: <YYYY-MM-DD>
|
|
24
|
+
updated: <YYYY-MM-DD>
|
|
25
|
+
schema-version: 1
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Problem
|
|
29
|
+
|
|
30
|
+
_What this change is doing: standing up the repo from empty. One paragraph._
|
|
31
|
+
|
|
32
|
+
This change scaffolds the project from an empty repository to a bootable, tested, and ready-to-ship state. It is the only change in the project's history with `area: bootstrap`; subsequent changes target real modules.
|
|
33
|
+
|
|
34
|
+
## Current Behavior
|
|
35
|
+
|
|
36
|
+
_N/A for bootstrap — there is no current state. Repository is empty (or contains only `hstack/` after greenfield-init Phases 1–5)._
|
|
37
|
+
|
|
38
|
+
- N/A.
|
|
39
|
+
|
|
40
|
+
## Target Behavior
|
|
41
|
+
|
|
42
|
+
_What shipping looks like, observably. Bootstrap's targets are bootability and gate-passing, not feature behavior._
|
|
43
|
+
|
|
44
|
+
- The repository builds: `<configured-build-command>` exits 0.
|
|
45
|
+
- The repository's test suite runs and passes: `<configured-test-command>` exits 0.
|
|
46
|
+
- Every module declared in `app-architecture.md` Section 1 has a corresponding source directory with the minimal shell required for the module-spec to be reverse-engineered post-merge.
|
|
47
|
+
- The initial migration sequence sketched in `data-architecture.md` Section 5 lands as actual `.sql` files under `supabase/migrations/` (or the chosen DB's migration directory) in the order: schema → RLS → pgvector → seeds.
|
|
48
|
+
- CI runs the canonical commands from `ci-cd.md` and the gates pass.
|
|
49
|
+
|
|
50
|
+
## Acceptance Criteria
|
|
51
|
+
|
|
52
|
+
_GIVEN / WHEN / THEN. Bootstrap's acceptance is gate-based, not user-flow-based._
|
|
53
|
+
|
|
54
|
+
GIVEN the repository at HEAD
|
|
55
|
+
WHEN the engineer runs `<configured-build-command>` and `<configured-test-command>`
|
|
56
|
+
THEN both exit 0 and no test is skipped.
|
|
57
|
+
|
|
58
|
+
GIVEN the database after `m_0002_rls_policies.sql` has run
|
|
59
|
+
WHEN any tenant-scoped table is queried without setting `app.<tenant-column>`
|
|
60
|
+
THEN the query returns zero rows (RLS enforced from line zero).
|
|
61
|
+
|
|
62
|
+
GIVEN the repository at HEAD
|
|
63
|
+
WHEN a downstream engineer runs `/hstack:module-spec <module>` for any module from `app-architecture.md` Section 1
|
|
64
|
+
THEN the Skill finds a target directory to reverse-engineer against and does not halt on missing source.
|
|
65
|
+
|
|
66
|
+
## Invariants
|
|
67
|
+
|
|
68
|
+
_Three or more bullets per SP-04. Bootstrap's invariants name the foundational guarantees that must survive every future change._
|
|
69
|
+
|
|
70
|
+
- **RLS-enforced from line zero.** Every tenant-scoped table created by `m_0001_initial_schema.sql` has its RLS policy applied in `m_0002_rls_policies.sql` BEFORE any data lands. The migration ordering is a contract, not a convenience.
|
|
71
|
+
- **Module boundaries match the declaration.** Every module in `app-architecture.md` Section 1 has a corresponding source directory; no module is silently dropped or renamed during scaffold. Future changes cannot add modules without updating the declaration first.
|
|
72
|
+
- **Stack ADRs are authoritative.** Every choice in this scaffold (framework, DB client, auth integration, hosting deploy file, observability wiring) traces to an ADR from Phase 4. No silent stack divergence.
|
|
73
|
+
|
|
74
|
+
## Scope Boundaries
|
|
75
|
+
|
|
76
|
+
_Pointer to `in-scope` and `out-of-scope` frontmatter arrays. Bootstrap's `in-scope` is an explicit enumeration of every file being created. Wildcards are permitted but the engineer must list every top-level destination explicitly so the implementer's scope-lock does meaningful work._
|
|
77
|
+
|
|
78
|
+
The `in-scope` enumeration is the contract: the implementer creates exactly the listed files and no others. Files appearing in the final scaffold but not in `in-scope` indicate a scaffold-spec gap and require a scope amendment.
|
|
79
|
+
|
|
80
|
+
## Surfaces
|
|
81
|
+
|
|
82
|
+
_Pointer to `surfaces` frontmatter. Bootstrap is `[infra]` only — UI / agent / api / db / auth surface work begins with the first feature change-spec after bootstrap merges._
|
|
83
|
+
|
|
84
|
+
- **infra**: build configuration, dependency manifest, CI workflow, DB migration tooling setup, deployment configuration, observability wiring.
|
|
85
|
+
|
|
86
|
+
UI work begins post-bootstrap; the scaffold ships only the minimum shell (layout, theme tokens) needed for the build to pass.
|
|
87
|
+
|
|
88
|
+
## Linked Stories and Personas
|
|
89
|
+
|
|
90
|
+
_N/A — bootstrap has `user-stories: []` and satisfies SP-09 via `area: bootstrap`. The bootstrap variant is a third carve-out alongside `internal-tooling: true` (Category A) and `enables: [...]` (Category B); `area: bootstrap` is mutually exclusive with both. See kernel addendum for the rule._
|
|
91
|
+
|
|
92
|
+
## Related ADRs and Tech-Debt
|
|
93
|
+
|
|
94
|
+
_Every stack ADR from Phase 4 (greenfield-init) goes here as a pointer with one-sentence justification. Examples:_
|
|
95
|
+
|
|
96
|
+
- ADR-NNNN — Stack defaults adopted: <list>. Adopted as the project foundation.
|
|
97
|
+
- ADR-NNNN+1 — Observability stack: PostHog + Sentry. Configured in this scaffold.
|
|
98
|
+
|
|
99
|
+
## Resolves Tech-Debt
|
|
100
|
+
|
|
101
|
+
_N/A — bootstrap creates the project; it does not resolve prior tech-debt._
|
|
102
|
+
|
|
103
|
+
## Open Questions
|
|
104
|
+
|
|
105
|
+
_Populated when status moves from draft to ready-to-plan. Bootstrap-specific examples: "Do we lint the migration SQL via sqlfluff or via Supabase's built-in lint?" "Do we vendor a UI component library in the initial commit or wait for the first UI feature?"_
|
|
@@ -1,35 +1,169 @@
|
|
|
1
1
|
---
|
|
2
2
|
id: data-architecture
|
|
3
3
|
type: data-architecture
|
|
4
|
-
status:
|
|
4
|
+
status: draft # draft | current | needs-refresh | archived
|
|
5
5
|
owner: <git-handle>
|
|
6
|
+
assumes-database: postgres # explicit so Phase 4 stack-decide can flag drift
|
|
6
7
|
schema-snapshot-date: <YYYY-MM-DD>
|
|
7
8
|
rag-architecture-version: 1
|
|
9
|
+
derived-from: [product-brief]
|
|
10
|
+
downstream: [app-architecture, threat-model, hardening-checklist, module-spec/*]
|
|
8
11
|
created: <YYYY-MM-DD>
|
|
9
12
|
updated: <YYYY-MM-DD>
|
|
10
13
|
schema-version: 1
|
|
11
14
|
---
|
|
12
15
|
|
|
13
|
-
##
|
|
16
|
+
## 1. Tenancy Model
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
_The load-bearing question. The data-architect refuses to advance past this section until the tenant definition is concrete and ties to a persona in the brief._
|
|
16
19
|
|
|
17
|
-
|
|
20
|
+
**Pattern** — one of:
|
|
18
21
|
|
|
19
|
-
|
|
22
|
+
- **A. Tenant = the customer organization** — single workspace per paying customer; users inside share visibility.
|
|
23
|
+
- **B. Tenant = a sub-team within the customer organization** — multi-workspace per customer.
|
|
24
|
+
- **C. Tenant = the individual user** — workspace-per-user.
|
|
25
|
+
- **D. Custom** — document the pattern explicitly and explain why none of A/B/C fit.
|
|
20
26
|
|
|
21
|
-
|
|
27
|
+
**Rationale**
|
|
22
28
|
|
|
23
|
-
|
|
29
|
+
_One sentence tying the chosen pattern to the persona in `product-brief.md`. Example: "Pattern A because Maya (Director of CS) shares visibility with her 6 reps; sub-team isolation isn't requested by any v1 persona."_
|
|
24
30
|
|
|
25
|
-
|
|
31
|
+
**Tenant identifier**
|
|
26
32
|
|
|
27
|
-
|
|
33
|
+
_The column name and type used to scope every tenant-scoped table (`workspace_id uuid`, `org_id text`, etc.). All downstream RLS predicates reference this column._
|
|
28
34
|
|
|
29
|
-
##
|
|
35
|
+
## 2. Entity Graph
|
|
30
36
|
|
|
31
|
-
|
|
37
|
+
_The set of entities and their relationships. Each entity must trace to either a persona-named action in `product-brief.md` or to the tenancy model from Section 1. Orphan entities halt with the drift challenge._
|
|
32
38
|
|
|
33
|
-
|
|
39
|
+
**Entities**
|
|
34
40
|
|
|
35
|
-
|
|
41
|
+
| Entity | Owns | Traces to | Relationships |
|
|
42
|
+
| --- | --- | --- | --- |
|
|
43
|
+
| <entity-name> | <one-line statement> | <persona-action OR tenancy-derived> | <FK refs> |
|
|
44
|
+
|
|
45
|
+
**Conventions** (subsumed from prior template)
|
|
46
|
+
|
|
47
|
+
_Naming (snake_case, plural tables), timestamps (`created_at`, `updated_at` on every table, ISO 8601), soft-deletes vs hard-deletes per entity, UUID vs serial choice with rationale, audit fields if any._
|
|
48
|
+
|
|
49
|
+
**Drift challenge answered**
|
|
50
|
+
|
|
51
|
+
_"Does any entity here have no trace to a persona or feature in the brief? Name it."_
|
|
52
|
+
|
|
53
|
+
## 3. RLS Posture
|
|
54
|
+
|
|
55
|
+
_Per-table policy sketch. Every entity from Section 2 falls into one of two categories — no third._
|
|
56
|
+
|
|
57
|
+
**Tenant-scoped tables**
|
|
58
|
+
|
|
59
|
+
| Table | Policy predicate sketch | Notes |
|
|
60
|
+
| --- | --- | --- |
|
|
61
|
+
| <table> | `<tenant-column> = current_setting('app.<tenant-column>')::uuid` | <e.g., RPC-only writes, no direct INSERT> |
|
|
62
|
+
|
|
63
|
+
**Intentionally global tables**
|
|
64
|
+
|
|
65
|
+
| Table | Why no RLS | Rationale |
|
|
66
|
+
| --- | --- | --- |
|
|
67
|
+
| <table> | <lookup data \| public reference \| ...> | <one sentence> |
|
|
68
|
+
|
|
69
|
+
**Drift challenge answered**
|
|
70
|
+
|
|
71
|
+
_"Does any tenant-scoped entity have an RLS policy that the chosen tenancy model wouldn't enforce? Name it."_
|
|
72
|
+
|
|
73
|
+
## 4. RAG / pgvector
|
|
74
|
+
|
|
75
|
+
_Whether v1 uses embeddings, what entity carries them, which embedding model, the tenant-scoped retrieval RPC signature. If v1 does not use RAG, mark this section `not-in-v1` with rationale and skip ahead._
|
|
76
|
+
|
|
77
|
+
**Use in v1**
|
|
78
|
+
|
|
79
|
+
_`yes` or `not-in-v1`. If not-in-v1, justify in one sentence (e.g., "v1 ships change-awareness without semantic retrieval; pgvector is a v2 layer")._
|
|
80
|
+
|
|
81
|
+
**Embedding-bearing entities**
|
|
82
|
+
|
|
83
|
+
| Entity | Embedding column | Model | Dimensions | Tenant-scoped retrieval RPC |
|
|
84
|
+
| --- | --- | --- | --- | --- |
|
|
85
|
+
| <entity> | <column name> | <e.g., openai:text-embedding-3-small> | <e.g., 1536> | <RPC signature with tenant predicate> |
|
|
86
|
+
|
|
87
|
+
**Tenant-scoping requirement**
|
|
88
|
+
|
|
89
|
+
_Every retrieval RPC MUST filter by the Section 1 tenant identifier. The drift challenge verifies this._
|
|
90
|
+
|
|
91
|
+
**Drift challenge answered**
|
|
92
|
+
|
|
93
|
+
_"Does any embedding-bearing entity have a retrieval RPC that bypasses tenant scoping? Name it."_
|
|
94
|
+
|
|
95
|
+
## 5. Migration Sketches
|
|
96
|
+
|
|
97
|
+
_Postgres-dialect DDL sketches for the initial migrations, with `-- TODO: confirm` markers on uncertain parts. The implementer reads these during bootstrap and writes the actual `.sql` files; the sketches are intent, not executable. Typical ordering: schema → RLS → pgvector. Data must never land before RLS._
|
|
98
|
+
|
|
99
|
+
**Migration sequence**
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
m_0001_initial_schema.sql -- Section 2 entities, tables + FKs, no policies yet
|
|
103
|
+
m_0002_rls_policies.sql -- Section 3 policies, applied per tenant-scoped table
|
|
104
|
+
m_0003_pgvector_setup.sql -- Section 4 RPCs and indexes (skip if not-in-v1)
|
|
105
|
+
m_0004_seed_global_data.sql -- Section 3 intentionally-global table seeds (optional)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Sketch — m_0001_initial_schema.sql**
|
|
109
|
+
|
|
110
|
+
```sql
|
|
111
|
+
-- TODO: confirm UUID extension is enabled
|
|
112
|
+
create extension if not exists "uuid-ossp";
|
|
113
|
+
|
|
114
|
+
-- TODO: confirm column types and FK ON DELETE behaviors per entity
|
|
115
|
+
create table <entity> (
|
|
116
|
+
id uuid primary key default uuid_generate_v4(),
|
|
117
|
+
<tenant-column> uuid not null references <tenant-table>(id) on delete cascade,
|
|
118
|
+
-- entity-specific columns
|
|
119
|
+
created_at timestamptz not null default now(),
|
|
120
|
+
updated_at timestamptz not null default now()
|
|
121
|
+
);
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Sketch — m_0002_rls_policies.sql**
|
|
125
|
+
|
|
126
|
+
```sql
|
|
127
|
+
-- TODO: confirm session-variable name matches app convention
|
|
128
|
+
alter table <entity> enable row level security;
|
|
129
|
+
|
|
130
|
+
create policy <entity>_tenant_isolation on <entity>
|
|
131
|
+
for all
|
|
132
|
+
using (<tenant-column> = current_setting('app.<tenant-column>')::uuid);
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**Sketch — m_0003_pgvector_setup.sql** (skip if Section 4 is `not-in-v1`)
|
|
136
|
+
|
|
137
|
+
```sql
|
|
138
|
+
-- TODO: confirm pgvector version compatible with embedding model dimensions
|
|
139
|
+
create extension if not exists vector;
|
|
140
|
+
|
|
141
|
+
alter table <embedding-bearing-entity>
|
|
142
|
+
add column embedding vector(<dimensions>);
|
|
143
|
+
|
|
144
|
+
create index on <embedding-bearing-entity> using ivfflat (embedding vector_cosine_ops);
|
|
145
|
+
|
|
146
|
+
-- TODO: confirm RPC signature and tenant predicate
|
|
147
|
+
create or replace function nearest_<entity>(query_embedding vector, k int, p_<tenant-column> uuid)
|
|
148
|
+
returns table (id uuid, score float4)
|
|
149
|
+
language sql stable
|
|
150
|
+
as $$
|
|
151
|
+
select id, embedding <=> query_embedding as score
|
|
152
|
+
from <embedding-bearing-entity>
|
|
153
|
+
where <tenant-column> = p_<tenant-column>
|
|
154
|
+
order by score
|
|
155
|
+
limit k;
|
|
156
|
+
$$;
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Data lifecycle** (subsumed from prior template)
|
|
160
|
+
|
|
161
|
+
_Retention windows per entity (e.g., "interactions: 18 months hot, archived after"), archival path, deletion guarantees (hard-delete vs soft-delete vs anonymize-and-retain). Lifecycle differences per tenant tier (free vs paid) noted here._
|
|
162
|
+
|
|
163
|
+
**Drift challenge answered**
|
|
164
|
+
|
|
165
|
+
_"Does any migration in the sketch sequence land data before its RLS policy? Name it."_
|
|
166
|
+
|
|
167
|
+
## Coherence check (end-of-atom)
|
|
168
|
+
|
|
169
|
+
_When the atom reaches terminal state, the agent re-runs all five drift challenges. Any unanswered challenge halts the commit._
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: discovery-brainstorm
|
|
3
|
+
type: discovery-technique
|
|
4
|
+
technique: brainstorm
|
|
5
|
+
applies-to: product-brief
|
|
6
|
+
schema-version: 1
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Brainstorm — technique script
|
|
10
|
+
|
|
11
|
+
This is the prompt sequence `product-discovery` runs in Brainstorm mode. Use this when the engineer has a problem domain but no concrete concept. The mode is **facilitated ideation** — the agent acts as coach pulling ideas out via structured exercises, not generating ideas for the engineer.
|
|
12
|
+
|
|
13
|
+
## Pre-flight check
|
|
14
|
+
|
|
15
|
+
Before entering the script, the agent confirms:
|
|
16
|
+
|
|
17
|
+
- The engineer can name the problem domain in one sentence ("CS teams losing follow-up context") even if the solution is undefined.
|
|
18
|
+
- The engineer has 60+ minutes available. Brainstorm runs multi-round; cutting it short produces shallow output.
|
|
19
|
+
|
|
20
|
+
## Round 1 — SCAMPER pass on the problem statement
|
|
21
|
+
|
|
22
|
+
For each SCAMPER lens, ask the engineer one question and write their answer:
|
|
23
|
+
|
|
24
|
+
- **Substitute** — "What current workflow could be substituted away?"
|
|
25
|
+
- **Combine** — "What two things, combined, would create new value here?"
|
|
26
|
+
- **Adapt** — "What other industry has solved a similar pain — what did they do?"
|
|
27
|
+
- **Modify** — "What single behavior, if amplified, would solve most of the pain?"
|
|
28
|
+
- **Put to another use** — "What's a non-obvious user who has this same pain?"
|
|
29
|
+
- **Eliminate** — "What part of the current workflow could disappear entirely?"
|
|
30
|
+
- **Reverse** — "What if the user did the opposite of what they do today?"
|
|
31
|
+
|
|
32
|
+
Answers land as raw text in a scratch section. Do NOT synthesize yet.
|
|
33
|
+
|
|
34
|
+
## Round 2 — Reverse brainstorming
|
|
35
|
+
|
|
36
|
+
Ask: "How would you make this problem **worse** for the user? List five ways."
|
|
37
|
+
|
|
38
|
+
The engineer's answers reveal the load-bearing failure modes — the things the product must NOT do. These directly seed the **Explicitly NOT** section of the brief.
|
|
39
|
+
|
|
40
|
+
## Round 3 — Six Thinking Hats on the strongest thread
|
|
41
|
+
|
|
42
|
+
The agent picks the strongest 1–2 threads from Rounds 1 and 2 (the threads with the most concrete user actions named) and proposes them back. For each thread, walk the hats:
|
|
43
|
+
|
|
44
|
+
- **White hat (facts)** — "What do we observably know about this user's workflow today?"
|
|
45
|
+
- **Red hat (intuition)** — "What feels right or wrong about this thread, gut-check?"
|
|
46
|
+
- **Black hat (caution)** — "What's the strongest case against this thread?"
|
|
47
|
+
- **Yellow hat (optimism)** — "What's the strongest case for this thread?"
|
|
48
|
+
- **Green hat (creativity)** — "What's the wildest version of this thread?"
|
|
49
|
+
- **Blue hat (process)** — "Is this the right thread to deepen, or should we drop it?"
|
|
50
|
+
|
|
51
|
+
After the Six Hats run, the engineer either commits to a thread or returns to Round 1 with a sharper problem statement.
|
|
52
|
+
|
|
53
|
+
## Round 4 — Synthesis
|
|
54
|
+
|
|
55
|
+
The agent proposes a one-paragraph synthesis of the strongest thread, framed as: "Here is what I heard you converge on. Concept: X. Underlying pain: Y. Target user: Z." The engineer confirms or revises.
|
|
56
|
+
|
|
57
|
+
On confirmation, the agent transitions to the **product-brief.md** template and walks the sections, using the synthesis as the seed for Underlying Pain, Target User, and Value Proposition.
|
|
58
|
+
|
|
59
|
+
## Required reframes (mandatory before brief lands)
|
|
60
|
+
|
|
61
|
+
These run during the section walk of `product-brief.md`, regardless of which Brainstorm round produced the synthesis:
|
|
62
|
+
|
|
63
|
+
- "Who specifically pays for this?" — concrete persona required.
|
|
64
|
+
- "What's the smallest useful wedge?" — minimum shippable surface required.
|
|
65
|
+
- "What would you have to believe to be wrong about this?" — falsifiability required.
|
|
66
|
+
|
|
67
|
+
## Park-and-resume
|
|
68
|
+
|
|
69
|
+
The agent surfaces a parking offer after each Round commits. If the engineer parks, the round's output is persisted in `hstack/.session-state/<session-id>.yaml`. Resume picks up at the next round.
|