hstack 0.3.0 → 0.5.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 +60 -0
- package/README.md +56 -14
- package/VERSION +1 -1
- package/dist/lib/wire.js +18 -0
- package/dist/lib/wire.js.map +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/kernel-fit-analyst.md +53 -0
- package/template/.claude/agents/product-discovery.md +165 -0
- package/template/.claude/agents/stack-architect.md +137 -0
- 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-flag/SKILL.md +138 -0
- package/template/.claude/skills/hstack-greenfield-init/SKILL.md +150 -0
- package/template/.claude/skills/hstack-kernel-fit-scan/SKILL.md +31 -14
- 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.md +23 -7
- 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/kernel-fit-finding.md +1 -0
- package/template/templates/kernel-fit-flag.md +52 -0
- package/template/templates/product-brief.md +56 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hstack-data-architecture
|
|
3
|
+
description: |
|
|
4
|
+
Use this skill when the engineer wants to produce or refresh `hstack/context/data-architecture.md` — the deep five-section foundational data-layer design (Tenancy, Entities, RLS, RAG, Migration Sketches). The Skill is Phase 2 of `/hstack:greenfield-init`, the data-architecture step of `/hstack:brownfield-init`, or a standalone atom for refreshing a single section after drift. It invokes the `data-architect` subagent and routes downstream phases to halt at `HSTACK-HALT: reason=upstream-drift` when contradictions surface. Examples:
|
|
5
|
+
|
|
6
|
+
<example>
|
|
7
|
+
Context: Phase 2 of greenfield-init opens after product-brief is current.
|
|
8
|
+
user: "/hstack:data-architecture"
|
|
9
|
+
assistant: "Loading product-brief, vision, mvp-scope, personas. Section 1 — Tenancy — is load-bearing: I'll walk Patterns A/B/C explicitly and refuse to advance until the tenant definition is concrete with a rationale tied to a persona. Subsequent sections (Entities, RLS, RAG, Migration Sketches) build on it."
|
|
10
|
+
<commentary>
|
|
11
|
+
Tenancy ambiguity is the #1 multi-tenant SaaS failure mode. The atom enforces concreteness at Section 1 before any downstream section can stabilize.
|
|
12
|
+
</commentary>
|
|
13
|
+
</example>
|
|
14
|
+
|
|
15
|
+
<example>
|
|
16
|
+
Context: An app-architect drift challenge revealed a missing entity in data-architecture. The engineer routes back.
|
|
17
|
+
user: "/hstack:data-architecture --section entities"
|
|
18
|
+
assistant: "Section-targeted entry. I'll fast-jump to Section 2 Entities for the missing entity, but the end-of-atom coherence check still runs across all five sections before commit — section edits cannot silently break other sections."
|
|
19
|
+
<commentary>
|
|
20
|
+
Section-targeted re-entry is precision when needed, but coherence is non-negotiable. The end-of-atom check is the v1 guarantee against drift-from-edit.
|
|
21
|
+
</commentary>
|
|
22
|
+
</example>
|
|
23
|
+
tools:
|
|
24
|
+
- Read
|
|
25
|
+
- Write
|
|
26
|
+
- Edit
|
|
27
|
+
- Grep
|
|
28
|
+
- Glob
|
|
29
|
+
- Bash
|
|
30
|
+
- Task
|
|
31
|
+
- "{{TODO-MCP: Supabase MCP — live schema introspection in extract mode}}"
|
|
32
|
+
- "{{TODO-SCRIPT: hstack/scripts/validate-spec.ts — frontmatter validator}}"
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Purpose
|
|
36
|
+
|
|
37
|
+
`hstack-data-architecture` is the atom that produces or refreshes `hstack/context/data-architecture.md` via the `data-architect` subagent. The artifact is the foundational design of the data layer in five sections; downstream subagents (`data-specialist` for per-change reviews, `implementer` for migration writing) read it as canonical posture.
|
|
38
|
+
|
|
39
|
+
## When to invoke
|
|
40
|
+
|
|
41
|
+
- Phase 2 of `/hstack:greenfield-init` (elicit mode).
|
|
42
|
+
- Delegated by `/hstack:brownfield-init` mini-session 5a (extract mode).
|
|
43
|
+
- Standalone via `/hstack:data-architecture [--mode extract|elicit] [--section <name>]` for refresh or single-section edits.
|
|
44
|
+
- Routed-into-from-downstream when `/hstack:app-architecture` finds a state-ownership gap that requires an entity addition (the bidirectional drift recovery path).
|
|
45
|
+
|
|
46
|
+
## Inputs
|
|
47
|
+
|
|
48
|
+
- `--mode extract | elicit` — defaults: `extract` if the live schema is reachable via Supabase MCP or migration files exist; `elicit` otherwise.
|
|
49
|
+
- `--section <name>` — one of `tenancy | entities | rls | rag | migrations`. Fast-jumps but re-runs end-of-atom coherence.
|
|
50
|
+
|
|
51
|
+
## Preconditions
|
|
52
|
+
|
|
53
|
+
- `hstack/config.yaml` at `init-status: minimal-complete` or later.
|
|
54
|
+
- `hstack/context/product/product-brief.md` at `status: current`. The brief is upstream; entities trace to it. If brief is at `draft` or `needs-refresh`, halt with `HSTACK-HALT: reason=upstream-non-terminal`.
|
|
55
|
+
- `hstack/templates/data-architecture.md` present.
|
|
56
|
+
- In extract mode, the Supabase MCP is reachable OR `supabase/migrations/` exists OR equivalent schema source is reachable; otherwise halt.
|
|
57
|
+
|
|
58
|
+
## Orchestration steps
|
|
59
|
+
|
|
60
|
+
1. **Detect mode + entry.** Read disk state. If artifact at `current` and no `--section` and no `--force`: print summary, exit no-op.
|
|
61
|
+
2. **Invoke `data-architect` subagent.** Via the Task tool with `subagent_type: data-architect`. Pass mode, optional section, the canonical session-start context, and (in extract mode) the live-schema introspection results.
|
|
62
|
+
3. **Walk sections.** The subagent walks Section 1 first (Tenancy is gate). For section-targeted entry, jumps directly. Each confirmed section writes to disk + auto-commits.
|
|
63
|
+
4. **Run drift challenge prompts.** Each section ends with a drift challenge before confirmation. A real drift halts with `HSTACK-HALT: reason=upstream-drift` and offers (a) revise this section, (b) re-enter the upstream atom (`/hstack:product-discovery` or `/hstack:configure vision`), (c) log as ADR via `/hstack:adr-new`.
|
|
64
|
+
5. **End-of-atom coherence check.** Even on section-targeted entry, the subagent re-runs all five drift challenges before terminal commit. Any unanswered challenge blocks the commit.
|
|
65
|
+
|
|
66
|
+
## Outputs
|
|
67
|
+
|
|
68
|
+
- `hstack/context/data-architecture.md` at `status: current` with `assumes-database: postgres` in frontmatter (or alternative with rationale).
|
|
69
|
+
- `hstack/.session-state/<session-id>.yaml` (transient).
|
|
70
|
+
|
|
71
|
+
## Auto-commit triggers
|
|
72
|
+
|
|
73
|
+
- Each confirmed section writes immediately and auto-commits.
|
|
74
|
+
- Artifact reaches `status: current` → final commit with the coherence-check evidence in the body.
|
|
75
|
+
|
|
76
|
+
## Idempotency contract
|
|
77
|
+
|
|
78
|
+
- Artifact at `current` + no `--section` + no `--force`: print summary, exit no-op.
|
|
79
|
+
- Artifact at `draft` or partial: read disk + session-state, resume at next non-confirmed section.
|
|
80
|
+
- Artifact at `needs-refresh`: walk all sections in confirm-or-revise mode.
|
|
81
|
+
|
|
82
|
+
## Stop conditions
|
|
83
|
+
|
|
84
|
+
- Product-brief at non-terminal status.
|
|
85
|
+
- Section 1 Tenancy answer is vague after one re-ask.
|
|
86
|
+
- A drift challenge surfaces an unresolved contradiction.
|
|
87
|
+
- Extract mode invoked but no schema source reachable.
|
|
88
|
+
- The `assumes-database: postgres` value contradicts an in-flight stack decision.
|
|
89
|
+
|
|
90
|
+
## Failure modes
|
|
91
|
+
|
|
92
|
+
- **Subagent unreachable.** Persist session state; retry later.
|
|
93
|
+
- **Supabase MCP unreachable in extract mode.** If migrations or other schema source exist, the subagent falls back to those. Otherwise halt with `HSTACK-HALT: reason=mcp-unreachable` per the kernel's load-bearing-MCP rule.
|
|
94
|
+
|
|
95
|
+
## Anti-patterns
|
|
96
|
+
|
|
97
|
+
- Never write migration `.sql` files from this Skill. Sketches only; the implementer writes the files during bootstrap or per-change.
|
|
98
|
+
- Never bypass the Section 1 Tenancy gate.
|
|
99
|
+
- Never let the end-of-atom coherence check be skipped on section-targeted re-entry.
|
|
100
|
+
- Never silently honor a database change that contradicts `assumes-database`. Halt and surface; route through stack-architect or refresh this artifact deliberately.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hstack-flag
|
|
3
|
+
description: |
|
|
4
|
+
Use this skill when the engineer notices in-the-moment friction in the hstack workflow — a Skill loop that felt off, a subagent output that read wrong, a halt firing for an unexpected reason, a confirmation diff that revealed an unstated assumption — and wants to surface it for kernel-fit review without halting the current work. The Skill is the engineer-triggered side of the kernel-fit closed loop (ADR-0005). It drops a tiny frontmatter-only pin to `hstack/kernel-fit/flags/pending/` carrying session-id + transcript path + branch + HEAD + timestamp, completes in under a second, and exits. No interview, no confirmation, no commit. The next `/hstack:kernel-fit-scan` reads each pin, opens the referenced transcript, classifies the friction, and either folds the signal into an existing finding or emits a new one. Examples:
|
|
5
|
+
|
|
6
|
+
<example>
|
|
7
|
+
Context: Mid-implementation the engineer notices a Skill produced a confirmation diff that revealed an assumption the kernel does not name.
|
|
8
|
+
user: "/hstack:flag"
|
|
9
|
+
assistant: "📌 pinned at hstack/kernel-fit/flags/pending/flag-20260523T143208-a3f9.md — kernel-fit will review on next scan."
|
|
10
|
+
<commentary>
|
|
11
|
+
Zero-friction is load-bearing. No interview, no confirmation gate, no diff preview. The Skill captures session-id (from most-recently-modified jsonl under ~/.claude/projects/<encoded-cwd>/), branch, HEAD, timestamp, and writes the pin in under a second. The engineer continues working immediately.
|
|
12
|
+
</commentary>
|
|
13
|
+
</example>
|
|
14
|
+
|
|
15
|
+
<example>
|
|
16
|
+
Context: The engineer wants to leave a one-word hint so future-them remembers the rough shape of the friction when they re-read the transcript.
|
|
17
|
+
user: "/hstack:flag halt-loop"
|
|
18
|
+
assistant: "📌 pinned with hint 'halt-loop' — kernel-fit will review on next scan."
|
|
19
|
+
<commentary>
|
|
20
|
+
The optional positional hint argument is a one-word string. Multi-word hints are rejected (the Skill takes argv[0] and ignores the rest with a one-line note). The hint is for the engineer's future audit, not for the analyst — per ADR-0005, the analyst forms its classification from the transcript window, not from engineer-written hints, to preserve the no-contamination contract.
|
|
21
|
+
</commentary>
|
|
22
|
+
</example>
|
|
23
|
+
|
|
24
|
+
<example>
|
|
25
|
+
Context: The engineer flags from a workspace where the encoded-path directory under ~/.claude/projects/ does not exist (e.g., the harness is storing transcripts elsewhere or the workspace is brand-new).
|
|
26
|
+
user: "/hstack:flag"
|
|
27
|
+
assistant: "📌 pinned with session-id-source: fallback-cwd (no jsonl found under ~/.claude/projects/<encoded>; session-id may not resolve at scan-time). The analyst will classify as transcript-truncated if the transcript cannot be located. Re-flag in a session whose transcript is reachable if the friction is recurring."
|
|
28
|
+
<commentary>
|
|
29
|
+
The session-id capture is heuristic in v1 (per ADR-0005). The Skill does not halt when the heuristic fails — it writes the pin with whatever metadata it can capture and a note in `session-transcript-path` indicating the fallback. The analyst's `transcript-truncated` classification is the safety net. v2 substrate will replace the heuristic with a harness-exposed session-id.
|
|
30
|
+
</commentary>
|
|
31
|
+
</example>
|
|
32
|
+
tools:
|
|
33
|
+
- Bash
|
|
34
|
+
- Read
|
|
35
|
+
- Write
|
|
36
|
+
- Glob
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Purpose
|
|
40
|
+
|
|
41
|
+
`hstack-flag` is the engineer-triggered feeder into the kernel-fit closed loop (ADR-0005). It captures a *pointer to the moment* — session-id, transcript path, branch, HEAD, timestamp — so the `kernel-fit-analyst` can later read the surrounding transcript window and classify whatever friction prompted the flag. The Skill carries no engineer interpretation of the friction; the analyst forms its classification independently to preserve the no-contamination contract.
|
|
42
|
+
|
|
43
|
+
This Skill is mechanical per ADR-0001. No subagent is invoked. The values to write are determined entirely by the invocation context (git state, working directory, the active Claude Code session-id, current transcript message count) plus the optional one-word hint. There is no interview, no confirmation gate, no proposed-diff preview, and no commit — the pin is additive, immutable, and out-of-band from the lifecycle state machine.
|
|
44
|
+
|
|
45
|
+
## When to invoke
|
|
46
|
+
|
|
47
|
+
Invoke when:
|
|
48
|
+
|
|
49
|
+
- A Skill loop felt off — looped longer than expected, asked a question that revealed a wrong assumption, produced output that read strangely.
|
|
50
|
+
- A subagent's output read wrong — challenge prompts seemed to dodge real risk, evidence rows looked thin, a finding's category felt mis-categorized.
|
|
51
|
+
- A halt fired for an unexpected reason — the halt enum value did not seem to capture what actually happened, or the halt felt like it should have been routine.
|
|
52
|
+
- A confirmation diff revealed an unstated kernel assumption — the proposed write surfaced something the kernel does not name but probably should.
|
|
53
|
+
- Anything else where the engineer wants the transcript window remembered for later review, but cannot stop the current work to write a tech-debt item or an ADR.
|
|
54
|
+
|
|
55
|
+
Do NOT invoke for:
|
|
56
|
+
|
|
57
|
+
- Bugs in individual code changes (those are tech-debt items or revisits-change entries).
|
|
58
|
+
- Security gaps in a specific change (those are security-review concerns).
|
|
59
|
+
- Genuine emergencies — if the situation requires halting, halt and address it directly.
|
|
60
|
+
|
|
61
|
+
## Inputs
|
|
62
|
+
|
|
63
|
+
- Optional positional `<hint>` (one word, ≤ 32 characters). Multi-word arguments are truncated to the first whitespace-delimited token with a one-line note. The hint is for the engineer's future audit, not for the analyst.
|
|
64
|
+
|
|
65
|
+
## Preconditions
|
|
66
|
+
|
|
67
|
+
- Working directory is a git repository (`git rev-parse --git-dir` succeeds). If not, halt with "not in a git repo — flag only works inside hstack-governed code."
|
|
68
|
+
- The consuming repo has at least the `hstack/kernel-fit/flags/pending/` directory writable (the Skill creates it on demand if absent — no halt).
|
|
69
|
+
- No status check on any other artifact. The Skill is intentionally orthogonal to the lifecycle state machine; flagging is permitted in any branch, at any time, regardless of in-flight artifacts.
|
|
70
|
+
|
|
71
|
+
## Orchestration steps
|
|
72
|
+
|
|
73
|
+
1. **Capture git state.** Run in parallel:
|
|
74
|
+
- `git rev-parse HEAD` → `head`
|
|
75
|
+
- `git rev-parse --abbrev-ref HEAD` → `branch`
|
|
76
|
+
- `pwd` → `workspace`
|
|
77
|
+
|
|
78
|
+
2. **Resolve the session-id.** Heuristic per ADR-0005 (v2 substrate will replace this with a harness-exposed mechanism):
|
|
79
|
+
- Compute the encoded workspace path: replace `/` with `-` in the absolute cwd path, prefix with `-`. Example: `/Users/jane/code/moso` → `-Users-jane-code-moso`.
|
|
80
|
+
- Glob `~/.claude/projects/<encoded-cwd>/*.jsonl`.
|
|
81
|
+
- If at least one match: pick the most recently modified (`stat -f %m` on macOS, `stat -c %Y` on Linux) and extract its `session-id` from the filename (basename minus `.jsonl`). Set `session-transcript-path` to its absolute path.
|
|
82
|
+
- If zero matches: set `session-id` to `fallback-<short-uuid>` (generate a short random hex), set `session-transcript-path` to the literal string `fallback-cwd:<workspace>` so the analyst can detect the fallback at scan time. Do NOT halt — the pin still has audit value (timestamp + branch + HEAD), and the analyst's `transcript-truncated` classification is the safety net.
|
|
83
|
+
|
|
84
|
+
3. **Capture pre-compaction message count.** Count lines in `session-transcript-path` if it points at a real jsonl file (`wc -l < <path>`); else set to 0. The analyst compares this to the file's line count at scan-time to detect compaction.
|
|
85
|
+
|
|
86
|
+
4. **Read and normalize the hint.** If the engineer passed an argument: take the first whitespace-delimited token, truncate to 32 characters, store as `hint`. If multi-word was passed, note in stdout "hint truncated to first token: <hint>". If no argument: `hint: null`.
|
|
87
|
+
|
|
88
|
+
5. **Compose the pin id.** Format: `flag-<YYYYMMDD>T<HHMMSS>-<session-id-short>` where `<session-id-short>` is the first 4 characters of the session-id (or `fallback-<hex>`). Example: `flag-20260523T143208-a3f9`.
|
|
89
|
+
|
|
90
|
+
6. **Write the pin.** Ensure `hstack/kernel-fit/flags/pending/` exists (`mkdir -p`); write `<pin-id>.md` with the frontmatter-only content per `template/templates/kernel-fit-flag.md`. The body is intentionally empty (a single HTML comment from the template is acceptable, but no prose).
|
|
91
|
+
|
|
92
|
+
7. **Confirm to stdout.** Print one line: `📌 pinned at hstack/kernel-fit/flags/pending/<pin-id>.md — kernel-fit will review on next scan.` If the hint was set, mention it. If the session-id fell back, mention it. Exit 0.
|
|
93
|
+
|
|
94
|
+
## Outputs
|
|
95
|
+
|
|
96
|
+
- One new file at `hstack/kernel-fit/flags/pending/<pin-id>.md`.
|
|
97
|
+
- No git operations. No commits. No subagent invocations. No edits to any other file.
|
|
98
|
+
|
|
99
|
+
## Auto-commit triggers
|
|
100
|
+
|
|
101
|
+
None. Pins are gitignored per ADR-0005 (derivative signal, mirroring `.telemetry/` sidecars from ADR-0004). The flag is not a lifecycle event, so the kernel's auto-commit-at-status-transition rule does not apply.
|
|
102
|
+
|
|
103
|
+
## Idempotency contract
|
|
104
|
+
|
|
105
|
+
Each invocation produces a new pin with a unique id (timestamp granularity is one second; session-id-short is appended for collision safety across rapid re-flags). Re-running the Skill on the same friction produces a second pin — this is intentional. The analyst processes both and the duplication itself is signal (engineer felt strongly enough to flag twice). The Skill never overwrites or deduplicates.
|
|
106
|
+
|
|
107
|
+
## Stop conditions
|
|
108
|
+
|
|
109
|
+
Beyond the kernel's general stop conditions:
|
|
110
|
+
|
|
111
|
+
- Not inside a git repo. Halt with the explanation above. The Skill is meaningful only inside hstack-governed code where the analyst can correlate the pin to a finding surface.
|
|
112
|
+
|
|
113
|
+
The Skill explicitly does NOT halt on:
|
|
114
|
+
|
|
115
|
+
- Missing jsonl under `~/.claude/projects/<encoded-cwd>/` — falls back to `fallback-cwd` and writes the pin anyway.
|
|
116
|
+
- Branch mismatch with an in-flight change-spec — flagging is orthogonal to lifecycle.
|
|
117
|
+
- A `validate-spec.ts` failure on the pin frontmatter — until the validator ships, FL-01 and FL-02 are advisory only; the pin lands.
|
|
118
|
+
- Disk-write failure on the pin file. (If `mkdir -p` or `Write` errors, halt with the OS error — there is nothing useful the Skill can do.)
|
|
119
|
+
|
|
120
|
+
No halt sentinel is emitted by this Skill in the success path. The success path is a clean exit-0 with the one-line stdout confirmation.
|
|
121
|
+
|
|
122
|
+
## Failure modes
|
|
123
|
+
|
|
124
|
+
- **`~/.claude/projects/<encoded-cwd>/` does not exist or is empty.** Fall back as described in step 2; write the pin with `session-transcript-path: fallback-cwd:<workspace>`. The analyst will classify `transcript-truncated` at scan-time.
|
|
125
|
+
- **Multiple `.jsonl` files in the encoded directory.** Pick the most recently modified. This is the v1 heuristic; v2 will replace it with a harness-exposed session-id.
|
|
126
|
+
- **Engineer flags many times in rapid succession.** Each flag produces a distinct pin (timestamp granularity + session-id-short suffix prevents collisions). The high flag-rate itself becomes signal in the next scan's Slack tail summary.
|
|
127
|
+
- **Engineer flags from inside a subagent's session.** The encoded-cwd heuristic resolves to the main-session jsonl (subagents do not get their own jsonl under `~/.claude/projects/`), which is correct — the analyst wants the main session's transcript. No special handling required.
|
|
128
|
+
- **Engineer passes a quoted multi-word hint.** Truncate to the first token, note it in stdout, write the pin. Do not halt.
|
|
129
|
+
|
|
130
|
+
## Anti-patterns
|
|
131
|
+
|
|
132
|
+
- Never prompt the engineer for a description of the friction. The Skill is one-shot and silent. Asking for prose re-opens the contamination surface the analyst guards against and defeats the zero-friction goal.
|
|
133
|
+
- Never invoke a subagent. The pin's value is determined by invocation context; no subagent decision-making is needed.
|
|
134
|
+
- Never commit the pin. Pins are gitignored. Committing them would (a) defeat the cadence (every flag becomes a commit), (b) pollute git history with derivative-cache files, and (c) break the gitignore decision recorded in ADR-0005's Decision and Consequences.
|
|
135
|
+
- Never edit an existing pin to add context. Pins are immutable from the engineer's perspective; the only legal post-creation writes are by the analyst at processing time. To add context, re-flag in a follow-up turn.
|
|
136
|
+
- Never invoke a confirmation gate. The proposed-diff preview rule from the kernel's Mechanical operations section does not apply here because the pin is additive (not a state-machine write) and there is no risk to mitigate: the pin is immutable, gitignored, and out-of-band from every lifecycle gate.
|
|
137
|
+
- Never block the conversation on slow operations. The Skill's wall-clock budget is <1s. If `wc -l` against a multi-gigabyte jsonl is too slow, accept an approximate count (the field is for change-detection at scan-time, not exact accounting) — but `wc -l` on jsonl files in practice completes in tens of milliseconds and this concern is theoretical.
|
|
138
|
+
- Never escalate a flag into a tech-debt item, ADR, or research session automatically. Promotion is exclusively the analyst's call at scan-time, gated by the engineer via `/hstack:kernel-fit-triage` and `/hstack:kernel-fit-promote`. The Skill is a feeder, not a router.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hstack-greenfield-init
|
|
3
|
+
description: |
|
|
4
|
+
Use this skill when an engineer is starting a **new project from an empty repository** and wants hstack discipline baked in from line zero. Greenfield-init is the sibling of `/hstack:brownfield-init`: where brownfield extracts existing context, greenfield elicits it. The Skill composes the discovery atoms in order (product-discovery → data-architecture → app-architecture → stack-decide → threat-model/hardening → scaffold), with hard gates between phases and bidirectional drift recovery for downstream phases that surface upstream gaps. Total elapsed time is 4–8 hours of conversation spread across as many sessions as the engineer wants — every phase ends at a commit point and is interruptible. Until greenfield-init completes through Phase 6 (scaffold), no per-change workflow Skill works; the repo is bootable only after scaffold lands. Examples:
|
|
5
|
+
|
|
6
|
+
<example>
|
|
7
|
+
Context: A founder runs `npx hstack@latest greenfield-init` against an empty repository.
|
|
8
|
+
user: "/hstack:greenfield-init"
|
|
9
|
+
assistant: "I'll walk you through 6 phases. Phase 1 (product discovery) opens first — pick a technique: Brainstorm, Forcing-Questions, or Project-Brief. Each phase ends at a commit point; you can park and resume any time. Total elapsed time is founder-paced, typically 4–8 hours of conversation across multiple sessions."
|
|
10
|
+
<commentary>
|
|
11
|
+
Greenfield is deliberately slower than brownfield because every layer is being created from elicitation rather than extracted from existing source. The Skill is structured as 6 hard-gated phases; each phase delegates to a standalone atom or subagent.
|
|
12
|
+
</commentary>
|
|
13
|
+
</example>
|
|
14
|
+
|
|
15
|
+
<example>
|
|
16
|
+
Context: Greenfield-init was started yesterday; Phases 1–3 are committed; the engineer wants to resume.
|
|
17
|
+
user: "/hstack:greenfield-init"
|
|
18
|
+
assistant: "I see Phases 1–3 at `status: current` on disk. Resuming at Phase 4 — stack-decide. Loading product-brief, data-architecture, app-architecture, and the default-stack declaration from hstack/config.yaml."
|
|
19
|
+
<commentary>
|
|
20
|
+
Idempotency is the same contract as brownfield-init: read disk state, recognize completed phases, resume at the first incomplete one. No re-interview of committed phases.
|
|
21
|
+
</commentary>
|
|
22
|
+
</example>
|
|
23
|
+
tools:
|
|
24
|
+
- Read
|
|
25
|
+
- Write
|
|
26
|
+
- Edit
|
|
27
|
+
- Grep
|
|
28
|
+
- Glob
|
|
29
|
+
- Bash
|
|
30
|
+
- Task
|
|
31
|
+
- "{{TODO-SCRIPT: hstack/scripts/validate-spec.ts — frontmatter validator}}"
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Purpose
|
|
35
|
+
|
|
36
|
+
`hstack-greenfield-init` is the **empty-repo entry point** for adopting hstack. It composes six phases of work — five discovery atoms plus one scaffold execution — into a single orchestrator. It writes `hstack/config.yaml` and populates the full context layer, then bootstraps the repository from empty to bootable via a generated bootstrap change-spec.
|
|
37
|
+
|
|
38
|
+
Greenfield-init is the only Skill that ends with code being written to the consuming repo (via the scaffold phase invoking `implementer`). Brownfield-init never writes source code — it only writes `hstack/` content against existing source.
|
|
39
|
+
|
|
40
|
+
## When to invoke
|
|
41
|
+
|
|
42
|
+
Invoke when:
|
|
43
|
+
|
|
44
|
+
- The consuming repo has no source code (or only an `hstack/` install and standard hidden files like `.git/`, `.gitignore`).
|
|
45
|
+
- The engineer wants discipline (ADRs, RLS posture, declared LLM/code split) baked in from line zero rather than retrofitted later.
|
|
46
|
+
|
|
47
|
+
Do NOT invoke when:
|
|
48
|
+
|
|
49
|
+
- The repo has existing source code — use `/hstack:brownfield-init` instead.
|
|
50
|
+
- The engineer wants to add a single layer to an already-adopted repo — use `/hstack:configure <layer>` or the standalone atom (`/hstack:product-discovery`, etc.).
|
|
51
|
+
|
|
52
|
+
## Inputs
|
|
53
|
+
|
|
54
|
+
- No positional arguments. The Skill drives entirely from on-disk state and conversation.
|
|
55
|
+
- Optional `--resume` is implicit: every phase reads disk state at session start and continues from the first incomplete artifact.
|
|
56
|
+
|
|
57
|
+
## Preconditions
|
|
58
|
+
|
|
59
|
+
Before any work:
|
|
60
|
+
|
|
61
|
+
- Verify the repo is empty (no `src/`, no `app/`, no `package.json`). If non-empty, halt and direct the engineer to `/hstack:brownfield-init`. `--force` is not offered; mixing modes corrupts the artifact taxonomy.
|
|
62
|
+
- Verify `hstack/` exists with `CLAUDE.md`, `templates/`, `.claude/`. If missing, halt and ask the engineer to run `npx hstack@latest init`.
|
|
63
|
+
- Probe Claude Code's MCP configuration and draft `hstack/context/mcp-status.md`.
|
|
64
|
+
- If `hstack/.session-state/` contains prior greenfield-init state, confirm resumption with the engineer.
|
|
65
|
+
|
|
66
|
+
## Orchestration steps
|
|
67
|
+
|
|
68
|
+
Six phases, hard-gated. The Skill does not advance past a phase until its artifact is at `status: current`.
|
|
69
|
+
|
|
70
|
+
### Phase 0 — Config skeleton
|
|
71
|
+
|
|
72
|
+
Same interview as brownfield-init Mini-session 0: story store, personas store, design system (per-resource), module-to-area mapping (will be populated from app-architecture in Phase 3), adversarial-review floor, agent ledger, active MCP set. Writes `hstack/config.yaml` with `schemaVersion: 1` and `init-status: minimal-complete`. Default-stack declaration is **set to the engineer's preferences** in this phase, so Phase 4 can fast-path. Commit.
|
|
73
|
+
|
|
74
|
+
### Phase 1 — Product discovery
|
|
75
|
+
|
|
76
|
+
Invokes `/hstack:product-discovery` in elicit mode (no source documents). The atom:
|
|
77
|
+
|
|
78
|
+
- Prompts the engineer to pick a technique (Brainstorm / Forcing-Questions / Project-Brief).
|
|
79
|
+
- Runs the technique to completion, producing `hstack/context/product/product-brief.md` at `status: current`.
|
|
80
|
+
- Auto-routes to `product-manager` to refresh `vision.md`, `mvp-scope.md`, `personas/`, `glossary.md` from the brief.
|
|
81
|
+
|
|
82
|
+
Greenfield-init proceeds to Phase 2 only when the brief AND all four refreshed context docs are at `status: current`.
|
|
83
|
+
|
|
84
|
+
### Phase 2 — Data architecture
|
|
85
|
+
|
|
86
|
+
Invokes `/hstack:data-architecture` in elicit mode. The atom walks the five sections (Tenancy, Entities, RLS, RAG, Migrations). Produces `hstack/context/data-architecture.md` at `status: current`. The `assumes-database: postgres` frontmatter is set explicitly so Phase 4 can flag drift if the stack changes the DB choice.
|
|
87
|
+
|
|
88
|
+
### Phase 3 — App architecture
|
|
89
|
+
|
|
90
|
+
Invokes `/hstack:app-architecture` in elicit mode. The atom walks the five sections (Module Map, Agent Orchestration, Deterministic-vs-LLM Split, State-Ownership, Surface Boundaries). Produces `hstack/context/app-architecture.md` at `status: current` AND scaffolds `hstack/specs/<module>/spec.md` stubs at `status: draft` for each module from Section 1. Updates `hstack/config.yaml`'s `surfaces` enum to match Section 5.
|
|
91
|
+
|
|
92
|
+
### Phase 4 — Stack decisions
|
|
93
|
+
|
|
94
|
+
Invokes `/hstack:stack-decide`. The `stack-architect` reads `hstack/config.yaml`'s default-stack declaration (set in Phase 0) and fast-paths through layers the engineer accepted defaults for. Layers requiring explicit deep-dive get the constraint interview; each layer's choice routes through `spec-author` for ADR authoring. Produces one rollup ADR plus per-layer ADRs for deep-dived layers.
|
|
95
|
+
|
|
96
|
+
### Phase 5 — Threat model + hardening
|
|
97
|
+
|
|
98
|
+
Invokes `security-reviewer` in `--mode foundational` (scores against proposed posture, not diff). Walks `threat-model.md` and `hardening-checklist.md` using the now-current product-brief, data-architecture, app-architecture, and stack ADRs as anchors. Also produces `infrastructure.md` (via `spec-author`) and `incident-runbook.md` (via `spec-author`, `git-ignored: true`) per the brownfield-init pattern.
|
|
99
|
+
|
|
100
|
+
### Phase 6 — Scaffold
|
|
101
|
+
|
|
102
|
+
Invokes `/hstack:scaffold`. The scaffold Skill generates a bootstrap change-spec from `hstack/templates/bootstrap.md` with `area: bootstrap`, `surfaces: [infra]`, and `in-scope` enumerated from the app-architecture Module Map plus the data-architecture Migration Sketches. Runs `data-review` and `security-review` in `--mode foundational` against the proposed posture, then planner → implementer (phase-by-phase) → verifier. At terminal state the repo is bootable: the build command exits 0, the test command exits 0, the initial migrations have landed with RLS enforced from line zero.
|
|
103
|
+
|
|
104
|
+
After Phase 6, `hstack/config.yaml`'s `init-status` advances to `complete` and the per-change workflow Skills become available.
|
|
105
|
+
|
|
106
|
+
## Outputs
|
|
107
|
+
|
|
108
|
+
- `hstack/config.yaml` at `init-status: complete`.
|
|
109
|
+
- `hstack/context/product/product-brief.md` at `current` (Phase 1).
|
|
110
|
+
- `hstack/context/vision.md`, `mvp-scope.md`, `personas/*`, `glossary.md` at `current` (Phase 1 auto-route).
|
|
111
|
+
- `hstack/context/data-architecture.md` at `current` (Phase 2).
|
|
112
|
+
- `hstack/context/app-architecture.md` at `current` plus module-spec stubs (Phase 3).
|
|
113
|
+
- `hstack/adr/ADR-*` files — rollup + per-layer (Phase 4).
|
|
114
|
+
- `hstack/context/threat-model.md`, `hardening-checklist.md`, `infrastructure.md`, `incident-runbook.md` (Phase 5).
|
|
115
|
+
- The bootstrap change-spec at `shipped` plus the actual source files, migrations, CI config, and module shells in the consuming repo (Phase 6).
|
|
116
|
+
|
|
117
|
+
## Auto-commit triggers
|
|
118
|
+
|
|
119
|
+
- `hstack/config.yaml` reaches `init-status: minimal-complete` (end of Phase 0).
|
|
120
|
+
- Each phase's terminal artifact reaches `status: current` (end of Phases 1–5).
|
|
121
|
+
- Each phase of the bootstrap change-spec's plan completes (Phase 6 per-phase commits).
|
|
122
|
+
- The bootstrap change-spec reaches `shipped` (end of Phase 6).
|
|
123
|
+
- `hstack/config.yaml`'s `init-status` advances to `complete` (after Phase 6 ships).
|
|
124
|
+
|
|
125
|
+
## Idempotency contract
|
|
126
|
+
|
|
127
|
+
Re-running `hstack-greenfield-init` reads disk state, recognizes completed phases (artifacts at `current`), and resumes at the first incomplete phase. No re-interview of committed phases. If a downstream phase had triggered an upstream drift recovery, the upstream artifact will be at `needs-refresh` rather than `current`; the Skill resumes at the upstream's refresh interview.
|
|
128
|
+
|
|
129
|
+
## Stop conditions
|
|
130
|
+
|
|
131
|
+
Beyond the kernel's general stop conditions, this Skill halts when:
|
|
132
|
+
|
|
133
|
+
- The repo is not empty at session start.
|
|
134
|
+
- A phase's atom halts (e.g., `HSTACK-HALT: reason=upstream-drift`). The Skill surfaces the halt and offers the engineer the recovery paths the atom named.
|
|
135
|
+
- A configured MCP that a downstream phase requires (Supabase MCP for Phase 2 extract-mode references, Notion MCP for persona storage) is unreachable and the phase is load-bearing on it.
|
|
136
|
+
- The engineer signals end-of-session — persist state, exit cleanly.
|
|
137
|
+
|
|
138
|
+
## Failure modes
|
|
139
|
+
|
|
140
|
+
- **Phase 6 implementer halts.** Bootstrap is partially scaffolded; the change-spec is at `ready-for-implementation` with some phases of `plan.md` complete. Re-running greenfield-init resumes from the first incomplete plan phase via the standard `/hstack:implement` idempotency.
|
|
141
|
+
- **Bidirectional drift recovery during Phases 2–4.** A downstream phase finds an upstream gap; the Skill routes the engineer through `/hstack:configure <upstream-atom>` and resumes after the upstream artifact returns to `current`.
|
|
142
|
+
- **Stack-architect contradicts data-architecture's Postgres assumption.** Phase 4 halts and surfaces; the engineer either revises data-architecture or revises the stack choice.
|
|
143
|
+
|
|
144
|
+
## Anti-patterns
|
|
145
|
+
|
|
146
|
+
- Never invoke greenfield-init against a non-empty repo. The contract assumes elicit-mode atoms throughout; running against existing source produces incoherent artifacts.
|
|
147
|
+
- Never collapse the six phases into one long block. The phase structure is the resumability contract AND the gate-discipline contract.
|
|
148
|
+
- Never skip Phase 5 (threat-model + hardening) to get to Phase 6 faster. Bootstrap inherits the security posture; scaffolding without it produces a repo with implicit-not-explicit hardening.
|
|
149
|
+
- Never bypass the bidirectional drift recovery. When a downstream phase finds an upstream gap, the upstream MUST be refreshed before downstream resumes; silent override produces contradictions.
|
|
150
|
+
- Never advance `init-status: complete` while any phase artifact is below `current` or while the bootstrap change-spec is below `shipped`.
|
|
@@ -78,13 +78,17 @@ The Skill is opt-in. There is no cron, no automatic invocation, no event-driven
|
|
|
78
78
|
|
|
79
79
|
2. **Run detection.** Shell out: `python3 hstack/scripts/telemetry/run_kernel_fit.py --repo <repo-root> --window <N>`. Capture stdout as JSON; capture stderr as the diagnostic log. On non-zero exit, surface the traceback and halt with `HSTACK-HALT: reason=missing-context`.
|
|
80
80
|
|
|
81
|
-
3. **
|
|
81
|
+
3. **Enumerate pending engineer flags.** Glob `hstack/kernel-fit/flags/pending/*.md`. Capture the list (may be empty). The analyst processes these per ADR-0005's Pending Flags Processing loop documented in `template/.claude/agents/kernel-fit-analyst.md`; this Skill is responsible for surfacing the list to the analyst and for the post-analyst pin-file moves at step 5.
|
|
82
82
|
|
|
83
|
-
4. **
|
|
83
|
+
4. **Decide whether to invoke the subagent.** Parse the detector JSON. If every pattern has `fired: false` **and** no pending flags exist, exit clean: print "kernel-fit-scan: no patterns fired in window, no pending flags — kernel is consistent with shipped practice in current corpus" to stdout, write nothing, do not invoke the subagent, do not nudge Slack, do not commit. If patterns fired OR pending flags exist (or both), proceed to step 5.
|
|
84
84
|
|
|
85
|
-
5. **
|
|
85
|
+
5. **Invoke `kernel-fit-analyst`.** Invoke via Task tool with `subagent_type: kernel-fit-analyst`. The prompt includes (a) the JSON evidence blob verbatim, (b) the list of pending flag paths from step 3 (or "no pending flags" when empty), (c) the canonical reminder of session-isolation (no implementer transcripts loaded), (d) the explicit instruction "one file per fired pattern; mandatory two-bullet counter-explanation; never write outside `hstack/kernel-fit/findings/`; process pending flags per the Pending Flags Processing section of the analyst prompt". The subagent's writes land in the working tree before the subagent returns. The analyst's response object reports the flag-processing counts (`processed`, `folded`, `emitted`, `not_actionable`, `transcript_truncated`).
|
|
86
86
|
|
|
87
|
-
6. **
|
|
87
|
+
6. **Move processed pin files.** For each pin the analyst updated to `status: processed`, `git mv hstack/kernel-fit/flags/pending/<pin>.md hstack/kernel-fit/flags/processed/<pin>.md`. Create the `processed/` directory if missing. This move lands in the same commit as the finding writes at step 7 — the analyst's pin frontmatter updates (classification, classification-rationale, folded-into, emitted-as, status) plus the file move must be atomic from git's perspective. **Note**: pin files are gitignored per ADR-0005, so `git mv` operates only on the filesystem (git will not stage either side). The "atomicity" here is filesystem-only — the analyst's in-place frontmatter update and the directory move complete together before stdout reports flag-processing counts. If the gitignore is later relaxed (would require an ADR amendment), this step's `git mv` becomes a real staged operation.
|
|
88
|
+
|
|
89
|
+
7. **Stage and commit findings.** Compute the set of newly-written or modified finding files (analyst may have superseded a prior finding atomically with a new one, or appended evidence rows to existing findings via fold). Print the proposed diff for engineer confirmation (per the kernel's "AI writes, humans confirm" mechanical-operations adaptation). On Y/n confirmation `Y` (default Yes), `git add` the finding files and commit with message `kernel-fit: <N> finding(s) detected` (or `kernel-fit: <N> finding(s) detected, <M> superseded` when supersession edits landed; or `kernel-fit: <N> finding(s) detected (<F> from flags), <M> superseded` when flag-emit landed). One commit per scan run, atomic across all new/edited findings. When patterns did not fire and only pending flags were processed, the commit message reads `kernel-fit: <F> flag(s) processed (<E> emit, <FF> fold, <NA> not-actionable, <TT> transcript-truncated)`.
|
|
90
|
+
|
|
91
|
+
8. **Notification — Slack nudge (best-effort).** Compute the notification set:
|
|
88
92
|
|
|
89
93
|
```
|
|
90
94
|
notify = [f for f in newly_written_findings
|
|
@@ -97,8 +101,8 @@ The Skill is opt-in. There is no cron, no automatic invocation, no event-driven
|
|
|
97
101
|
```
|
|
98
102
|
hstack kernel-fit: <N> new finding(s)
|
|
99
103
|
|
|
100
|
-
• KF-NNNN — <title> [confidence: high|medium]
|
|
101
|
-
Pattern: <KF-P1|KF-P2|KF-P3>
|
|
104
|
+
• KF-NNNN — <title> [confidence: high|medium] [via: detector|flag]
|
|
105
|
+
Pattern: <KF-P1|KF-P2|KF-P3|KF-FLAG-NNNN>
|
|
102
106
|
Kernel surface: <one-line>
|
|
103
107
|
hstack/kernel-fit/findings/KF-NNNN-<slug>.md
|
|
104
108
|
|
|
@@ -107,29 +111,39 @@ The Skill is opt-in. There is no cron, no automatic invocation, no event-driven
|
|
|
107
111
|
Promote: /hstack:kernel-fit-promote KF-NNNN --slug <adr-slug>
|
|
108
112
|
```
|
|
109
113
|
|
|
110
|
-
Bundle multiple findings into a single message when more than one fires in this scan.
|
|
114
|
+
Bundle multiple findings into a single message when more than one fires in this scan. When flag-processing occurred, append the **flag tail summary** as the last line of the same Slack message:
|
|
115
|
+
|
|
116
|
+
```
|
|
117
|
+
Flags processed: <P> total — <FF> folded, <E> emitted, <NA> not-actionable, <TT> transcript-truncated.
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The tail is included only when at least one pin was processed AND at least one of `folded` or `emitted` is non-zero, OR when `transcript_truncated > 0` (the transcript-truncated count is operationally interesting because it surfaces v1-heuristic edge cases the engineer should know about). When every processed pin was classified `not-actionable` the tail is suppressed — it would otherwise be pure noise. When the scan produces zero detector findings AND only `not-actionable` pin processing, the Slack message is suppressed entirely (no findings, no tail-worthy signal).
|
|
111
121
|
|
|
112
|
-
|
|
122
|
+
9. **Graceful degradation when Slack is unreachable.** If the MCP call raises (tool not configured, network failure, channel-not-found, etc.), log to stderr: `kernel-fit: Slack MCP unreachable; <N> finding(s) written to disk without notification. <P> flag(s) processed; triage via /hstack:help to discover open findings.` Exit 0. The disk write from step 7 is the load-bearing action; Slack is a side-channel pointer. This is a deliberate carve-out from the kernel's general MCP-unreachable stop condition — Slack is not load-bearing for kernel-fit (the canonical state lives on disk and is reachable via `/hstack:help`). The carve-out is documented here and in the kernel's `## How hstack improves itself` section.
|
|
113
123
|
|
|
114
|
-
|
|
124
|
+
10. **Report.** Print to stdout: the count of patterns fired, the count of new findings written, the count of supersessions, the count of flags processed broken down by classification (`folded`, `emitted`, `not-actionable`, `transcript-truncated`), and the count of Slack notifications fired (or "skipped — Slack unreachable" / "skipped — within dedup window for all findings" / "skipped — no signal worth surfacing"). Done.
|
|
115
125
|
|
|
116
126
|
## Outputs
|
|
117
127
|
|
|
118
128
|
- Zero or more files at `hstack/kernel-fit/findings/KF-NNNN-<slug>.md` at `status: open`.
|
|
119
129
|
- Zero or more supersession edits (status flip + `superseded-by` set) on prior finding files.
|
|
120
|
-
- Zero or
|
|
121
|
-
- Zero or
|
|
130
|
+
- Zero or more evidence-row appends to existing findings (from flag fold).
|
|
131
|
+
- Zero or more pin transitions from `hstack/kernel-fit/flags/pending/` to `hstack/kernel-fit/flags/processed/` with `status: processed` and the analyst-owned classification fields populated. Pins are gitignored per ADR-0005, so the moves are filesystem-only — not staged in git.
|
|
132
|
+
- Zero or one git commits (covering finding writes only; pin moves are not staged).
|
|
133
|
+
- Zero or one Slack messages (bundled when multiple findings notify, with the flag tail summary appended when applicable).
|
|
122
134
|
|
|
123
135
|
## Auto-commit triggers
|
|
124
136
|
|
|
125
|
-
- One commit at the writing of finding files (per the kernel's auto-commit-at-status-transition rule applied at the artifact-creation moment). No commit when no patterns fire.
|
|
137
|
+
- One commit at the writing of finding files (per the kernel's auto-commit-at-status-transition rule applied at the artifact-creation moment). No commit when no patterns fire AND no flag-emit or flag-fold landed (i.e., only `not-actionable` / `transcript-truncated` flag processing occurred). Pin file moves are filesystem-only (pins are gitignored) and do not require a commit.
|
|
126
138
|
|
|
127
139
|
## Idempotency contract
|
|
128
140
|
|
|
129
|
-
- Re-running the Skill when no patterns fire: zero new disk artifacts, no commit, no Slack message. Pure no-op.
|
|
141
|
+
- Re-running the Skill when no patterns fire AND no pending flags exist: zero new disk artifacts, no commit, no Slack message. Pure no-op.
|
|
142
|
+
- Re-running when no patterns fire but pending flags exist: the analyst is invoked to process flags only. Outcomes depend on classification — fold/emit may produce finding writes and a commit; not-actionable/transcript-truncated produce only pin moves (no commit).
|
|
130
143
|
- Re-running when patterns fire that already have open findings within the dedup window: the analyst is invoked, sees existing findings, and may skip-write or supersede; Slack notification is suppressed by the dedup gate.
|
|
131
144
|
- Re-running when the same patterns fire with new evidence: the analyst may produce supersession edits; the dedup gate still suppresses Slack (already-notified within the window).
|
|
132
|
-
- Re-running with `--no-slack`: identical to a run with Slack unreachable — findings land on disk, no Slack message.
|
|
145
|
+
- Re-running with `--no-slack`: identical to a run with Slack unreachable — findings land on disk, flags are processed normally, no Slack message.
|
|
146
|
+
- Re-running after pending flags were processed in a prior scan: the prior pins are now in `processed/` and the analyst is forbidden from re-processing them (per the kernel-fit-analyst's discipline rules). Only newly-flagged pins (added to `pending/` since the last scan) are processed this run.
|
|
133
147
|
|
|
134
148
|
## Stop conditions
|
|
135
149
|
|
|
@@ -178,3 +192,6 @@ What you do NOT need to do: no code to write, no hook to install. The Skill is p
|
|
|
178
192
|
- Never write outside `hstack/kernel-fit/findings/` or modify any artifact not produced by the analyst this run. This Skill orchestrates; it does not author.
|
|
179
193
|
- Never claim the analyst's output is measured truth. Frame every finding as LLM-strategized judgment per the kernel's v1 / v2 split rule.
|
|
180
194
|
- Never bundle a Slack notification across scan runs. One scan, one message (or zero, when the dedup gate suppresses or Slack is unreachable).
|
|
195
|
+
- Never re-process a pin already in `hstack/kernel-fit/flags/processed/`. The analyst's discipline rule (no re-processing) is mirrored here: the Skill globs only `pending/`, never `processed/`. If the engineer believes a processed pin was mis-classified, the path is to re-flag (creating a fresh pin), not to move the prior pin back.
|
|
196
|
+
- Never include the flag tail summary in the Slack message when every pin was classified `not-actionable`. The tail's purpose is to surface actionable signal — the all-not-actionable case is pure noise and the suppression is deliberate.
|
|
197
|
+
- Never commit a pin move. Pins are gitignored per ADR-0005; the `git mv` from `pending/` to `processed/` is filesystem-only and produces no staged change.
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hstack-product-discovery
|
|
3
|
+
description: |
|
|
4
|
+
Use this skill when the engineer wants to produce or refresh `hstack/context/product/product-brief.md` — the durable thinking artifact that captures the project's product reasoning. The Skill is Phase 1 of `/hstack:greenfield-init` (elicit mode), an optional enrichment phase of `/hstack:brownfield-init` when source docs are thin (extract mode), or a standalone atom for retroactive brief authoring. It invokes the `product-discovery` subagent in one of three engineer-chosen techniques (Brainstorm, Forcing-Questions, Project-Brief), produces a single synthesis at `hstack/context/product/product-brief.md`, and auto-routes to `product-manager` for downstream context-doc refresh. Examples:
|
|
5
|
+
|
|
6
|
+
<example>
|
|
7
|
+
Context: Phase 1 of greenfield-init opens. The engineer types `/hstack:product-discovery` directly.
|
|
8
|
+
user: "/hstack:product-discovery"
|
|
9
|
+
assistant: "Pick a technique: [1] Brainstorm — facilitated ideation; [2] Forcing-Questions — reframe-driven probing (Gstack-style); [3] Project-Brief — structured walk. Default mode is elicit (no source docs). The brief lives at hstack/context/product/product-brief.md and is parkable any time."
|
|
10
|
+
<commentary>
|
|
11
|
+
The technique choice is the engineer's, not the agent's. Each technique's script is in hstack/templates/discovery/<technique>.md. Mid-technique switching is allowed but halts to confirm — mixing technique outputs produces an incoherent brief.
|
|
12
|
+
</commentary>
|
|
13
|
+
</example>
|
|
14
|
+
|
|
15
|
+
<example>
|
|
16
|
+
Context: A brownfield repo's brief never landed during init; /hstack:help flagged the missing artifact.
|
|
17
|
+
user: "/hstack:product-discovery --mode extract"
|
|
18
|
+
assistant: "Extract mode. I'll read existing vision.md, README, and any product docs you point me at, propose the brief sections from what I find, and walk you through confirm-or-revise. The three required forcing prompts still run — extract mode does not bypass blind-spot probes."
|
|
19
|
+
<commentary>
|
|
20
|
+
Extract+confirm mode is how brownfield enrichment works. The unification of modes is load-bearing: the brief produced is the same artifact whether elicited or extracted, so downstream phases load it identically.
|
|
21
|
+
</commentary>
|
|
22
|
+
</example>
|
|
23
|
+
tools:
|
|
24
|
+
- Read
|
|
25
|
+
- Write
|
|
26
|
+
- Edit
|
|
27
|
+
- Grep
|
|
28
|
+
- Glob
|
|
29
|
+
- Bash
|
|
30
|
+
- Task
|
|
31
|
+
- "{{TODO-SCRIPT: hstack/scripts/validate-spec.ts — frontmatter validator}}"
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Purpose
|
|
35
|
+
|
|
36
|
+
`hstack-product-discovery` is the atom that produces `hstack/context/product/product-brief.md` via the `product-discovery` subagent. It is the canonical authoring path for the brief; the brief never lands via a generic spec-author interview.
|
|
37
|
+
|
|
38
|
+
## When to invoke
|
|
39
|
+
|
|
40
|
+
- Phase 1 of `/hstack:greenfield-init` (elicit mode, no source).
|
|
41
|
+
- Optional enrichment within `/hstack:brownfield-init` when existing product docs are thin and the engineer wants the deeper reframe-style brief.
|
|
42
|
+
- Standalone via `/hstack:product-discovery [--mode extract|elicit] [--section <name>]` for retroactive brief authoring on any repo.
|
|
43
|
+
|
|
44
|
+
## Inputs
|
|
45
|
+
|
|
46
|
+
- `--mode extract | elicit` — defaults: `elicit` if no source docs are reachable; `extract` if a `product-brief.md` exists or the engineer points at source documents.
|
|
47
|
+
- `--section <name>` — optional, fast-jumps to a specific section for refresh. Re-runs the end-of-atom check across all sections before commit.
|
|
48
|
+
|
|
49
|
+
## Preconditions
|
|
50
|
+
|
|
51
|
+
- `hstack/config.yaml` exists and `init-status` is at least `minimal-complete` — the atom does not run standalone until config exists.
|
|
52
|
+
- `hstack/CLAUDE.md` and `hstack/templates/product-brief.md` are present.
|
|
53
|
+
- `hstack/templates/discovery/{brainstorm,forcing-questions,project-brief}.md` are present.
|
|
54
|
+
- In extract mode, at least one source document must be reachable; otherwise halt and ask the engineer to either supply source pointers or fall back to elicit mode.
|
|
55
|
+
|
|
56
|
+
## Orchestration steps
|
|
57
|
+
|
|
58
|
+
1. **Detect mode.** Read disk state. If `hstack/context/product/product-brief.md` exists at `status: current` and no `--section` flag, this is a refresh confirmation — print summary and exit unless engineer opts into full re-interview.
|
|
59
|
+
2. **Pick technique** (elicit mode only). Prompt the engineer to choose Brainstorm / Forcing-Questions / Project-Brief. Persist the choice as `technique-used` in the brief frontmatter.
|
|
60
|
+
3. **Invoke `product-discovery` subagent.** Via the Task tool with `subagent_type: product-discovery`. Pass mode, technique, optional section, and the canonical session-start context (kernel, template, technique script, source docs in extract mode).
|
|
61
|
+
4. **Walk sections.** The subagent runs the chosen technique's script and walks the brief sections with confirmation gates. Each confirmed section writes to disk and auto-commits.
|
|
62
|
+
5. **Run forcing prompts.** The three required reframes (Who pays? What's the wedge? What would falsify this?) fire before terminal state regardless of technique.
|
|
63
|
+
6. **Auto-route at terminal state.** When the brief reaches `status: current`, the Skill prints the auto-route message (with alternative-path commands) and hands off to `product-manager` via the Task tool with `subagent_type: product-manager` to refresh `vision.md`, `mvp-scope.md`, `personas/`, `glossary.md`. If the engineer types `skip-routing`, the Skill commits the brief and exits cleanly — downstream Skills will halt on missing context docs.
|
|
64
|
+
|
|
65
|
+
## Outputs
|
|
66
|
+
|
|
67
|
+
- `hstack/context/product/product-brief.md` at `status: current`.
|
|
68
|
+
- `hstack/.session-state/<session-id>.yaml` (transient).
|
|
69
|
+
- Via auto-route: `vision.md`, `mvp-scope.md`, `personas/*`, `glossary.md` refreshed (unless skip-routing).
|
|
70
|
+
|
|
71
|
+
## Auto-commit triggers
|
|
72
|
+
|
|
73
|
+
- Each confirmed section writes immediately and auto-commits.
|
|
74
|
+
- Brief reaches `status: current` → final commit with the auto-route message in the body.
|
|
75
|
+
- Downstream refreshes by `product-manager` each auto-commit per the product-manager subagent's contract.
|
|
76
|
+
|
|
77
|
+
## Idempotency contract
|
|
78
|
+
|
|
79
|
+
- Brief at `current` + no `--section` + no `--force`: print summary, exit no-op.
|
|
80
|
+
- Brief at `draft` or partial: read disk + session-state, resume at next non-confirmed section.
|
|
81
|
+
- Brief at `needs-refresh` (flipped by `/hstack:configure` because upstream changed): walk all sections in confirm-or-revise mode.
|
|
82
|
+
|
|
83
|
+
## Stop conditions
|
|
84
|
+
|
|
85
|
+
- A required source document in extract mode is unreachable.
|
|
86
|
+
- Forcing-prompt answer is too vague after one re-ask. The subagent halts with `HSTACK-HALT: reason=ambiguous-spec` or `missing-context`.
|
|
87
|
+
- Mid-technique switch requested.
|
|
88
|
+
- Engineer signals end-of-session.
|
|
89
|
+
- Downstream auto-route fails (e.g., `product-manager` cannot reach the configured personas store). The Skill surfaces the failure; the brief stays at `current`, downstream context docs stay at their prior status until the engineer resolves.
|
|
90
|
+
|
|
91
|
+
## Failure modes
|
|
92
|
+
|
|
93
|
+
- **Subagent unreachable.** Persist session state; retry later.
|
|
94
|
+
- **Auto-route partial failure.** If `product-manager` succeeds on vision but fails on personas (e.g., Notion MCP unreachable), the partial state is on disk; re-running auto-route via `/hstack:configure personas --from-brief` recovers.
|
|
95
|
+
|
|
96
|
+
## Anti-patterns
|
|
97
|
+
|
|
98
|
+
- Never write to `vision.md`, `mvp-scope.md`, `personas/`, `glossary.md` from this Skill directly. Those refreshes belong to `product-manager` via the auto-route.
|
|
99
|
+
- Never bypass the three required forcing prompts, even in Project-Brief mode (the lightest touch).
|
|
100
|
+
- Never silently switch techniques mid-session.
|
|
101
|
+
- Never advance the brief to `current` while the Explicitly NOT section has fewer than two bullets.
|