@skyf0xx/hedgehog 0.1.0 → 0.1.5
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/LICENSE +21 -0
- package/README.md +7 -29
- package/bin/cli.mjs +4 -1
- package/package.json +5 -1
- package/src/agents/planner.md +145 -20
- package/src/skills/hedgehog-bootstrap/SKILL.md +99 -6
- package/src/templates/CLAUDE.md +14 -7
- package/src/templates/TODO.md +4 -4
- package/src/templates/package.json +5 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Will
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ A complete development methodology combining:
|
|
|
16
16
|
|
|
17
17
|
**Build faster, Save context**. Stay aligned. Ship software you can still understand six months later.
|
|
18
18
|
|
|
19
|
-

|
|
19
|
+

|
|
20
20
|
|
|
21
21
|
## Hedgehog gives AI
|
|
22
22
|
|
|
@@ -31,7 +31,7 @@ A complete development methodology combining:
|
|
|
31
31
|
- 🌳 **Self-documenting architecture:** the codebase carries the context, not the AI
|
|
32
32
|
- 🔁 **Traceable evolution:** decisions are preserved through conventional commits
|
|
33
33
|
|
|
34
|
-

|
|
34
|
+

|
|
35
35
|
|
|
36
36
|
## Why Hedgehog Exists
|
|
37
37
|
|
|
@@ -60,7 +60,7 @@ Backend comes first. Every module gets a working, typed API before any screen is
|
|
|
60
60
|
|
|
61
61
|
The build order is not something you negotiate with the AI. It is encoded into the process.
|
|
62
62
|
|
|
63
|
-

|
|
63
|
+

|
|
64
64
|
|
|
65
65
|
## The Hedgehog Loop
|
|
66
66
|
|
|
@@ -79,43 +79,21 @@ Repeat for the next module or the next step
|
|
|
79
79
|
```
|
|
80
80
|
|
|
81
81
|
|
|
82
|
-

|
|
82
|
+

|
|
83
83
|
|
|
84
84
|
## Installation
|
|
85
85
|
|
|
86
|
-
|
|
87
|
-
skills land in `.claude/` and get committed alongside your code — because
|
|
88
|
-
the discipline is only real if it travels with the project, versioned and
|
|
89
|
-
visible to your team and CI.
|
|
90
|
-
|
|
91
|
-
From the root of the repo you want to build with Hedgehog:
|
|
86
|
+
From an empty project folder:
|
|
92
87
|
|
|
93
88
|
``` bash
|
|
94
89
|
npx @skyf0xx/hedgehog init
|
|
95
90
|
```
|
|
96
91
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
- `src/agents/*` → `.claude/agents/` — the `planner`, `ui-builder`, and
|
|
100
|
-
`reviewer` roles
|
|
101
|
-
- `src/skills/*` → `.claude/skills/` — `hedgehog-bootstrap`,
|
|
102
|
-
`hedgehog-loop`, and `conventional-commits`
|
|
103
|
-
- `CLAUDE.md` and `TODO.md` templates into the repo root
|
|
104
|
-
|
|
105
|
-
If a target file already exists, `init` warns and stops without touching
|
|
106
|
-
it. Re-run with `--force` to overwrite:
|
|
107
|
-
|
|
108
|
-
``` bash
|
|
109
|
-
npx @skyf0xx/hedgehog init --force
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
Then commit the `.claude/` payload, open Claude Code, and say:
|
|
92
|
+
Then open Claude Code and say:
|
|
113
93
|
|
|
114
94
|
> bootstrap this project
|
|
115
95
|
|
|
116
|
-
|
|
117
|
-
wires the enforcement config (Nx boundaries, lefthook, commitlint, phase
|
|
118
|
-
gate). From there, `hedgehog-loop` takes over one module at a time.
|
|
96
|
+
Or paste the repo URL to your Agent and have it install for you.
|
|
119
97
|
|
|
120
98
|
## For Builders
|
|
121
99
|
|
package/bin/cli.mjs
CHANGED
|
@@ -33,6 +33,9 @@ const PLAN = [
|
|
|
33
33
|
{ type: 'dir', from: 'src/skills', to: '.claude/skills' },
|
|
34
34
|
{ type: 'file', from: 'src/templates/CLAUDE.md', to: 'CLAUDE.md' },
|
|
35
35
|
{ type: 'file', from: 'src/templates/TODO.md', to: 'TODO.md' },
|
|
36
|
+
// A minimal root package.json so bootstrap's `nx init` scaffolds a real
|
|
37
|
+
// pnpm workspace rather than falling into standalone (.nx wrapper) mode.
|
|
38
|
+
{ type: 'file', from: 'src/templates/package.json', to: 'package.json' },
|
|
36
39
|
];
|
|
37
40
|
|
|
38
41
|
const exists = (p) =>
|
|
@@ -127,7 +130,7 @@ async function init({ force }) {
|
|
|
127
130
|
)}\n`,
|
|
128
131
|
);
|
|
129
132
|
console.log('Next steps:');
|
|
130
|
-
console.log(` 1. ${bold('git add .claude CLAUDE.md TODO.md && git commit')}`);
|
|
133
|
+
console.log(` 1. ${bold('git add .claude CLAUDE.md TODO.md package.json && git commit')}`);
|
|
131
134
|
console.log(` 2. Open Claude Code and say: ${bold('"bootstrap this project"')}\n`);
|
|
132
135
|
}
|
|
133
136
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skyf0xx/hedgehog",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Install the Hedgehog build discipline (agents + skills) into a repo.",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/skyf0xx/hedgehog.git"
|
|
9
|
+
},
|
|
6
10
|
"publishConfig": {
|
|
7
11
|
"access": "public"
|
|
8
12
|
},
|
package/src/agents/planner.md
CHANGED
|
@@ -56,8 +56,13 @@ Revising a draft is a normal edit — the Correction Protocol
|
|
|
56
56
|
|
|
57
57
|
1. **Scope boundary** — what's in, what's explicitly out.
|
|
58
58
|
2. **Domain vocabulary** — the nouns and verbs of the problem.
|
|
59
|
-
3.
|
|
60
|
-
|
|
59
|
+
3. **`docs/context.md`** — the product narrative, scope boundary, and
|
|
60
|
+
domain vocabulary, written as current state (see below). Mandatory,
|
|
61
|
+
every project gets one.
|
|
62
|
+
4. **Screen/flow notes** — captured by module in
|
|
63
|
+
`docs/design/<module>-notes.md`, for `ux-planner` to act on at that
|
|
64
|
+
module's Phase B (see below). Mandatory per module in scope, even when
|
|
65
|
+
nothing was offered for that module.
|
|
61
66
|
|
|
62
67
|
### Screens, flows, and other visual input
|
|
63
68
|
|
|
@@ -68,11 +73,70 @@ here, and doubles as raw material for Phase B later.
|
|
|
68
73
|
|
|
69
74
|
Layout, styling, and interaction described — "the dashboard should show X
|
|
70
75
|
and Y together," "this should feel like Stripe's checkout" — are
|
|
71
|
-
captured under the relevant module in `docs/design/<module>-notes.md
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
+
captured under the relevant module in `docs/design/<module>-notes.md`.
|
|
77
|
+
`ux-planner` turns this into a screen rationale once that module's
|
|
78
|
+
contract and hook exist, in Phase A build order. Name this in the moment:
|
|
79
|
+
"noted for `<module>`'s screen — that gets built after its API is
|
|
80
|
+
working."
|
|
81
|
+
|
|
82
|
+
Every module in scope gets this file, whether or not anything was
|
|
83
|
+
offered for it — a module with no screen input yet still gets a
|
|
84
|
+
`docs/design/<module>-notes.md` stating that plainly, not a missing
|
|
85
|
+
file.
|
|
86
|
+
|
|
87
|
+
### Interview formatting
|
|
88
|
+
|
|
89
|
+
The interview is the whole UI — there's no screen to lean on, so
|
|
90
|
+
structure carries the weight a layout normally would. Keep a light,
|
|
91
|
+
consistent set of markers so the person can tell at a glance what kind of
|
|
92
|
+
turn they're reading, without turning the transcript noisy:
|
|
93
|
+
|
|
94
|
+
- A bold section title on entering a new stage (`**Scope**`,
|
|
95
|
+
`**Domain vocabulary**`, `**Confirm & lock**`) — once per stage, not
|
|
96
|
+
once per message.
|
|
97
|
+
- 🧭 for the opening brain-dump prompt, ❓ for a single follow-up
|
|
98
|
+
question, 🔍 for reading supplied material (a screenshot, a
|
|
99
|
+
spreadsheet), 📋 for a synthesis recap, 🔒 for the final confirmation
|
|
100
|
+
gate. One icon per turn, at most — this marks the kind of turn, it
|
|
101
|
+
isn't decoration.
|
|
102
|
+
- Tables for anything tabular (scope boundary, vocabulary) — never
|
|
103
|
+
prose pretending to be a table.
|
|
104
|
+
- Short paragraphs, one question per turn (already required below) —
|
|
105
|
+
never stack multiple asks in one block just because both fit.
|
|
106
|
+
|
|
107
|
+
This applies to every Intake turn from here on, not just the ones
|
|
108
|
+
below.
|
|
109
|
+
|
|
110
|
+
### Confidence tracking
|
|
111
|
+
|
|
112
|
+
Track a running confidence estimate for "I know what this person
|
|
113
|
+
actually wants" — not "I have enough to start guessing." Confidence
|
|
114
|
+
rises only when an answer resolves genuine ambiguity; a detail that
|
|
115
|
+
just restates something already clear doesn't move it.
|
|
116
|
+
|
|
117
|
+
State it out loud periodically as elicitation progresses — after
|
|
118
|
+
synthesis produces a draft, and any time confidence is low enough that
|
|
119
|
+
continuing to guess would be worse than asking:
|
|
120
|
+
|
|
121
|
+
> Confidence: ~70% — clear on the core flow and the actors, still open
|
|
122
|
+
> on what "cancel" means once payment's been taken, and whether
|
|
123
|
+
> `status` is a single lifecycle or independent tags.
|
|
124
|
+
|
|
125
|
+
Keep asking until confidence reaches **95%**: every module has a
|
|
126
|
+
resolved "owned by," at least one out-of-scope item has surfaced, and
|
|
127
|
+
no term is doing double duty for two different lifecycles (see "When
|
|
128
|
+
to ask instead of guess," below). 95% is a floor on understanding
|
|
129
|
+
what's real, not a ceiling on how much detail to gather — don't pad the
|
|
130
|
+
interview past the point where more questions stop resolving
|
|
131
|
+
ambiguity. If the person answers "I don't know, just pick something,"
|
|
132
|
+
that's a resolved answer (their call, recorded as such) — it moves
|
|
133
|
+
confidence up, not down.
|
|
134
|
+
|
|
135
|
+
Never silently settle for "what I think they should want." If a
|
|
136
|
+
guess would fill a gap, surface it as a candidate to confirm or
|
|
137
|
+
correct instead of writing it into the draft unchallenged — this is
|
|
138
|
+
the same move as "offering a candidate boundary... to confirm or
|
|
139
|
+
correct" below, applied to every gap, not just scope.
|
|
76
140
|
|
|
77
141
|
### Elicitation — what to ask
|
|
78
142
|
|
|
@@ -141,10 +205,50 @@ on — read which one this is early and let it set the pace.
|
|
|
141
205
|
to.
|
|
142
206
|
5. **Mark it provisional** — consumed by Bootstrap and revised there or
|
|
143
207
|
at the schema step as needed.
|
|
144
|
-
6. **
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
208
|
+
6. **Run Confirm & lock** (below) before writing anything. Only after
|
|
209
|
+
the person confirms does synthesis proceed to steps 7–8.
|
|
210
|
+
7. **Write `docs/context.md`**: product narrative, scope boundary, and
|
|
211
|
+
the domain vocabulary table, stated as current state only — no record
|
|
212
|
+
of alternatives considered, no "originally X, now Y." A later Intake
|
|
213
|
+
updates this file in place so it keeps reading as current state; it
|
|
214
|
+
never grows into a history.
|
|
215
|
+
8. **File screen/flow notes** under their module in
|
|
216
|
+
`docs/design/<module>-notes.md`, one file per module in scope, even
|
|
217
|
+
when nothing was offered for that module (say so plainly instead of
|
|
218
|
+
omitting the file) — verbatim or lightly organized, raw material for
|
|
219
|
+
`ux-planner`, not a rationale, so don't polish or structure beyond
|
|
220
|
+
attributing it to the right module.
|
|
221
|
+
|
|
222
|
+
### Confirm & lock
|
|
223
|
+
|
|
224
|
+
Everything above this point is provisional and cheap to change — nothing
|
|
225
|
+
has been written yet. This stage is the last point before that stops
|
|
226
|
+
being true, so it's a hard stop, not a recap in passing.
|
|
227
|
+
|
|
228
|
+
🔒 **Confirm & lock**. Show, in full, not condensed:
|
|
229
|
+
|
|
230
|
+
- The scope boundary table (in / out).
|
|
231
|
+
- The domain vocabulary table (entity, definition, attributes, owned
|
|
232
|
+
by).
|
|
233
|
+
- The module list in build order, with any cross-module FK dependencies
|
|
234
|
+
flagged.
|
|
235
|
+
- The confidence estimate, and what it's based on (e.g. "95% — every
|
|
236
|
+
module has a resolved owner, one out-of-scope item confirmed, no
|
|
237
|
+
double-duty terms remaining").
|
|
238
|
+
|
|
239
|
+
Then state plainly what happens on confirmation, before it happens:
|
|
240
|
+
|
|
241
|
+
> This locks in `docs/context.md` and the per-module design notes, and
|
|
242
|
+
> starts Phase A build (schema first) on the first module. Anything
|
|
243
|
+
> wrong or missing — say so now; it's a normal edit before this point,
|
|
244
|
+
> and a Correction Protocol entry after. Confirm to proceed, or tell me
|
|
245
|
+
> what to change.
|
|
246
|
+
|
|
247
|
+
Wait for an explicit go-ahead. A revision here is just another
|
|
248
|
+
elicitation turn — update the draft, re-run this stage, don't write
|
|
249
|
+
anything until the confirmation holds. Don't lower the bar because the
|
|
250
|
+
person seems eager to start; the cost of a wrong schema is exactly why
|
|
251
|
+
this gate exists.
|
|
148
252
|
|
|
149
253
|
### Worked example
|
|
150
254
|
|
|
@@ -199,15 +303,20 @@ ask now than fix forward later.
|
|
|
199
303
|
schema.
|
|
200
304
|
- Update `TODO.md` to reflect the checklist for what's in scope, mirroring
|
|
201
305
|
the phase/step structure from `hedgehog-loop`.
|
|
306
|
+
- Write and maintain `docs/context.md` — the product narrative, scope
|
|
307
|
+
boundary, and domain vocabulary, stated as current state only.
|
|
308
|
+
Mandatory on every project; not conditional on domain complexity.
|
|
202
309
|
- Screens or flows described during Intake are captured under the
|
|
203
|
-
relevant module (`docs/design/<module>-notes.md
|
|
204
|
-
|
|
310
|
+
relevant module (`docs/design/<module>-notes.md`, one per module in
|
|
311
|
+
scope, always present); Phase B, after the backend exists for that
|
|
312
|
+
module, is when they get acted on.
|
|
205
313
|
|
|
206
314
|
## Workflow
|
|
207
315
|
|
|
208
316
|
1. **Read the requirement** fully before doing anything.
|
|
209
|
-
2. **Check `TODO.md` and the commit log** for what's
|
|
210
|
-
`feat(<module>): api` commits mark modules with a
|
|
317
|
+
2. **Check `TODO.md`, `docs/context.md`, and the commit log** for what's
|
|
318
|
+
already built — `feat(<module>): api` commits mark modules with a
|
|
319
|
+
closed Phase A.
|
|
211
320
|
3. **Run Intake** if this is project start: extract scope boundary and
|
|
212
321
|
domain vocabulary per the procedure above. If input is insufficient,
|
|
213
322
|
ask — don't guess at scope.
|
|
@@ -217,19 +326,35 @@ ask now than fix forward later.
|
|
|
217
326
|
referenced by another's FK doesn't need to exist first — FK-by-ID
|
|
218
327
|
means no compile-time coupling — but flag it if joined reads are
|
|
219
328
|
expected from day one, since that shapes contract design).
|
|
220
|
-
6. **
|
|
329
|
+
6. **Run Confirm & lock** (Intake procedure, above) before writing
|
|
330
|
+
anything below. On a project's first Intake this is mandatory; on a
|
|
331
|
+
later Intake adding new scope, re-run it scoped to what's new.
|
|
332
|
+
7. **Write/update `TODO.md`**: a checklist mirroring the Phase A and
|
|
221
333
|
Phase B steps per module in scope. Checked or unchecked is its only
|
|
222
334
|
state. On a second Intake (new scope entering play), append new
|
|
223
335
|
module sections only — never touch an existing module's checked
|
|
224
336
|
boxes or reorder modules already in progress.
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
337
|
+
8. **Write/update `docs/context.md`**: product narrative, scope boundary,
|
|
338
|
+
domain vocabulary — current state only. On a second Intake, update it
|
|
339
|
+
in place to reflect the new current state; don't append a log of what
|
|
340
|
+
changed or why.
|
|
341
|
+
9. **File screen/flow notes** captured during Intake under
|
|
342
|
+
`docs/design/<module>-notes.md`, one file per module in scope — create
|
|
343
|
+
it even for a module with no screen input yet, stating that plainly.
|
|
344
|
+
10. **Return a summary**: scope boundary, module list, any open
|
|
345
|
+
questions.
|
|
228
346
|
|
|
229
347
|
## Constraints
|
|
230
348
|
|
|
231
349
|
- Never write or modify application code. Read-only against the
|
|
232
|
-
codebase; you may write `TODO.md
|
|
350
|
+
codebase; you may write `TODO.md`, `docs/context.md`, and
|
|
351
|
+
`docs/design/<module>-notes.md`.
|
|
352
|
+
- `docs/context.md` and `docs/design/<module>-notes.md` are not
|
|
353
|
+
optional — every project gets the former, every module in scope gets
|
|
354
|
+
the latter, regardless of how much material Intake produced.
|
|
355
|
+
- State current state only in `docs/context.md` — no negation of
|
|
356
|
+
alternatives, no changelog-style narration, no "we used to say X." If
|
|
357
|
+
Intake revises something, edit the file to say what's true now.
|
|
233
358
|
- Never invent scope. Ambiguous scope means stop and ask.
|
|
234
359
|
- Don't replan a module's internal step sequence — fixed by
|
|
235
360
|
`hedgehog-loop`, not a per-project decision.
|
|
@@ -99,16 +99,53 @@ Confirm this hasn't already run: check for an existing Nx workspace
|
|
|
99
99
|
existing workspace is a Correction Protocol case (patch the specific
|
|
100
100
|
config step at its source, per `hedgehog-loop`), not a re-scaffold.
|
|
101
101
|
|
|
102
|
+
If a fresh `pnpm install` in the generated workspace fails on a binary
|
|
103
|
+
package's postinstall script with a version-mismatch error (e.g.
|
|
104
|
+
"Expected X but got Y" for a native binary like `esbuild`), don't assume
|
|
105
|
+
project misconfiguration or a corrupted pnpm store — check **Known issue:
|
|
106
|
+
esbuild postinstall version mismatch** below first; this is a known,
|
|
107
|
+
deterministic collision, not something to misdiagnose from scratch.
|
|
108
|
+
|
|
102
109
|
## Steps (run in sequence, one commit per step)
|
|
103
110
|
|
|
104
111
|
### 1. Nx workspace + `packages/config`
|
|
105
112
|
|
|
113
|
+
The installer has already placed files at the repo root (`.claude/`, the
|
|
114
|
+
`CLAUDE.md`/`TODO.md` templates, a minimal root `package.json`, and git).
|
|
115
|
+
`create-nx-workspace` refuses a non-empty directory, so scaffold Nx *in
|
|
116
|
+
place* instead — `nx init` tolerates the existing files and merges into
|
|
117
|
+
them (appends to `.gitignore`, injects an Nx block into `CLAUDE.md` between
|
|
118
|
+
marker comments, adds `nx` to the root `package.json`):
|
|
119
|
+
|
|
106
120
|
```bash
|
|
107
|
-
npx
|
|
121
|
+
npx nx@latest init
|
|
122
|
+
pnpm add -D @nx/js
|
|
108
123
|
```
|
|
109
124
|
|
|
110
|
-
|
|
111
|
-
|
|
125
|
+
`nx init` needs the root `package.json` the installer dropped — without
|
|
126
|
+
one it falls into standalone (`.nx` wrapper) mode instead of a proper
|
|
127
|
+
pnpm workspace.
|
|
128
|
+
|
|
129
|
+
`nx init` does not reliably respect an existing `packageManager: pnpm@...`
|
|
130
|
+
field — it can run its own install via npm regardless, leaving a
|
|
131
|
+
`package-lock.json` next to the intended `pnpm-lock.yaml`. Immediately
|
|
132
|
+
after `nx init` completes, check for `package-lock.json` at the repo
|
|
133
|
+
root; if present, delete it and run `pnpm install` to regenerate
|
|
134
|
+
`pnpm-lock.yaml` before continuing to step 2. Don't assume `nx init`
|
|
135
|
+
respects the locked package manager — verify.
|
|
136
|
+
|
|
137
|
+
Then generate the first lib. The **first** `@nx/js:lib` call materializes
|
|
138
|
+
the whole workspace shape (`tsconfig.base.json`, root `eslint.config.mjs`,
|
|
139
|
+
`.prettierrc`, `vitest.workspace.ts`, the `packages/` layout, and the
|
|
140
|
+
tsconfig `paths` mapping) — the same scaffolding the `ts` preset would
|
|
141
|
+
have produced, generated lazily on first use:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
npx nx g @nx/js:lib packages/config --bundler=none --unitTestRunner=vitest
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`packages/config` is a plain `@nx/js` lib holding the locked, shared
|
|
148
|
+
files:
|
|
112
149
|
|
|
113
150
|
- `packages/config/eslint-base.js` — flat config, extended by every
|
|
114
151
|
app/lib. Include `@nx/enforce-module-boundaries` and `depConstraints`
|
|
@@ -121,6 +158,18 @@ shared files:
|
|
|
121
158
|
declares the project tags table below (`scope:*`, `type:*`) as comments
|
|
122
159
|
or a lookup, so every later generator step tags its project correctly.
|
|
123
160
|
|
|
161
|
+
Add an `esbuild` override to root `package.json` in this step, before step
|
|
162
|
+
2 installs `drizzle-kit` — see **Known issue: esbuild postinstall version
|
|
163
|
+
mismatch** below for why.
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"pnpm": {
|
|
168
|
+
"overrides": { "esbuild": "0.25.12" }
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
124
173
|
Commit: `feat(config): workspace + shared config`
|
|
125
174
|
|
|
126
175
|
### 2. `packages/db` — Drizzle client + connection
|
|
@@ -279,13 +328,13 @@ pre-commit:
|
|
|
279
328
|
commands:
|
|
280
329
|
typecheck:
|
|
281
330
|
glob: "*.{ts,tsx}"
|
|
282
|
-
run: npx nx affected -t typecheck --
|
|
331
|
+
run: npx nx affected -t typecheck --base=HEAD
|
|
283
332
|
lint:
|
|
284
333
|
glob: "*.{ts,tsx}"
|
|
285
|
-
run: npx nx affected -t lint --
|
|
334
|
+
run: npx nx affected -t lint --base=HEAD
|
|
286
335
|
test:
|
|
287
336
|
glob: "*.{ts,tsx}"
|
|
288
|
-
run: npx nx affected -t test --
|
|
337
|
+
run: npx nx affected -t test --base=HEAD
|
|
289
338
|
|
|
290
339
|
commit-msg:
|
|
291
340
|
commands:
|
|
@@ -293,6 +342,14 @@ commit-msg:
|
|
|
293
342
|
run: npx commitlint --edit {1}
|
|
294
343
|
```
|
|
295
344
|
|
|
345
|
+
Don't pass `--files={staged_files}` to `nx affected` — `nx affected`
|
|
346
|
+
forwards unrecognized args straight through to the underlying target
|
|
347
|
+
command (e.g. `eslint .`), so `--files={staged_files}` becomes
|
|
348
|
+
`eslint . <path>` and errors on any path that doesn't match eslint's own
|
|
349
|
+
glob expectations. `--base=HEAD` (comparing against the last commit) is
|
|
350
|
+
what makes `nx affected` scope correctly to a pre-commit hook's staged
|
|
351
|
+
changes.
|
|
352
|
+
|
|
296
353
|
**`commitlint.config.js`:**
|
|
297
354
|
|
|
298
355
|
```js
|
|
@@ -313,6 +370,14 @@ exists once it compiles and passes.
|
|
|
313
370
|
Run `pnpm dlx lefthook install` once `lefthook.yml` exists so the gate is
|
|
314
371
|
active from step 2 onward.
|
|
315
372
|
|
|
373
|
+
A machine with lefthook installed globally (e.g. via Homebrew) on `PATH`
|
|
374
|
+
can have that version picked up by the git hook shim instead of the
|
|
375
|
+
project's pinned local one, silently running different — possibly
|
|
376
|
+
incompatible — behavior. After `lefthook install`, verify the hook is
|
|
377
|
+
invoking the local pinned version (check `lefthook version` output during
|
|
378
|
+
a commit, or that the hook script under `.git/hooks/` resolves to
|
|
379
|
+
`node_modules/.bin/lefthook`) rather than a global shadow.
|
|
380
|
+
|
|
316
381
|
### Env validation (fail fast)
|
|
317
382
|
|
|
318
383
|
Types-first extended to config. Boot fails immediately on a missing or
|
|
@@ -380,6 +445,34 @@ One shared config, extended everywhere:
|
|
|
380
445
|
|
|
381
446
|
A per-app override request signals to fix the base config at the source.
|
|
382
447
|
|
|
448
|
+
## Known issue: esbuild postinstall version mismatch
|
|
449
|
+
|
|
450
|
+
`@nx/vite` (step 1) declares `esbuild` as an *optional* peer dependency
|
|
451
|
+
(`^0.27.0 || ^0.28.0`), while `drizzle-kit` (step 2) pins a hard dependency
|
|
452
|
+
on `esbuild@^0.25.4`. pnpm's isolated store correctly keeps both esbuild
|
|
453
|
+
majors side by side — but esbuild's own `install.js` resolves its platform
|
|
454
|
+
binary (`@esbuild/<platform>`) via **ambient** Node module resolution
|
|
455
|
+
rather than a path scoped to its own package instance. With multiple
|
|
456
|
+
esbuild majors in the tree, that ambient resolution can walk up and grab a
|
|
457
|
+
sibling major's platform binary, hardlinking the wrong version's binary
|
|
458
|
+
into a package that still claims a different version number. The result
|
|
459
|
+
is a postinstall failure like:
|
|
460
|
+
|
|
461
|
+
```
|
|
462
|
+
Error: Expected "0.28.1" but got "0.25.12"
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
This is deterministic (not registry/store corruption) and reproduces even
|
|
466
|
+
from a fully clean pnpm store — it's a real collision in esbuild's install
|
|
467
|
+
script when it meets pnpm's multi-version isolation. The fix is the
|
|
468
|
+
`pnpm.overrides.esbuild` pin added in step 1 above: collapsing to a single
|
|
469
|
+
esbuild version (drizzle-kit's hard-pinned range, since it's non-optional
|
|
470
|
+
— `@nx/vite`'s peer is optional and simply goes unfilled) removes the
|
|
471
|
+
ambiguity that triggers the bug. If this resurfaces after a stack version
|
|
472
|
+
bump, re-check drizzle-kit's current `esbuild` dependency range
|
|
473
|
+
(`pnpm view drizzle-kit dependencies.esbuild`) and update the override to
|
|
474
|
+
match rather than removing it.
|
|
475
|
+
|
|
383
476
|
## After Bootstrap
|
|
384
477
|
|
|
385
478
|
Update `TODO.md`: check off every Bootstrap line now built, leave Phase
|
package/src/templates/CLAUDE.md
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
{{PROJECT_SUMMARY — 2–4 sentences the `planner` writes at Intake: what
|
|
15
15
|
this project is, who it's for, and what it does. State current intent, not
|
|
16
|
-
history. Keep it tight —
|
|
17
|
-
docs/
|
|
16
|
+
history. Keep it tight — the full product narrative, scope boundary, and
|
|
17
|
+
domain vocabulary live in docs/context.md, not here.}}
|
|
18
18
|
|
|
19
19
|
This project is built with **Hedgehog**: a backend-first, one-step-at-a-time
|
|
20
20
|
build discipline. The rules below aren't project preferences — they're how
|
|
@@ -28,6 +28,10 @@ whole plan in context — the plan lives in the structure:
|
|
|
28
28
|
- **`TODO.md`** is the live checklist and the source of truth for what's
|
|
29
29
|
next. Read it at the start of every session. Its only state is
|
|
30
30
|
checked/unchecked.
|
|
31
|
+
- **`docs/context.md`** is the product's current-state document — product
|
|
32
|
+
narrative, scope boundary, domain vocabulary. Every project has one,
|
|
33
|
+
written by `planner` at Intake and kept current on later Intakes. It
|
|
34
|
+
states what's true now, never a history of what changed.
|
|
31
35
|
- **The commit log** is the record of what's built and why. Conventional
|
|
32
36
|
commits (`feat(<module>): schema`, `feat(<module>): api`, …) are how
|
|
33
37
|
progress is read, not a conversation summary.
|
|
@@ -63,8 +67,8 @@ steps from memory:
|
|
|
63
67
|
### The agents — delegate the judgment calls
|
|
64
68
|
|
|
65
69
|
- **`planner`** — Intake (scope boundary + domain vocabulary) at project
|
|
66
|
-
start, and module scoping when new scope enters play. Writes `TODO.md
|
|
67
|
-
and `docs/design/<module>-notes.md`.
|
|
70
|
+
start, and module scoping when new scope enters play. Writes `TODO.md`,
|
|
71
|
+
`docs/context.md`, and `docs/design/<module>-notes.md`.
|
|
68
72
|
- **`ux-planner`** — once per module in Phase B, after the hook exists and
|
|
69
73
|
before the screen: writes `docs/design/<module>.md`.
|
|
70
74
|
- **`ui-builder`** — builds screens from the ux-planner rationale.
|
|
@@ -106,6 +110,7 @@ packages/
|
|
|
106
110
|
libs/
|
|
107
111
|
<module>/port · <module>/repository · <module>/service (one triplet per table)
|
|
108
112
|
docs/
|
|
113
|
+
context.md product narrative, scope boundary, domain vocabulary (Intake)
|
|
109
114
|
design <module>-notes.md (Intake) and <module>.md (ux-planner)
|
|
110
115
|
```
|
|
111
116
|
|
|
@@ -147,7 +152,8 @@ off. Keep it thin.
|
|
|
147
152
|
**When the build is done:** once every module in scope has both phases
|
|
148
153
|
checked, the build session is complete. **Delete `TODO.md`** — a finished
|
|
149
154
|
checklist is noise, and the commit log is the durable record of what was
|
|
150
|
-
built.
|
|
155
|
+
built. **`docs/context.md` stays** — it's the product's current-state
|
|
156
|
+
document, not a checklist.
|
|
151
157
|
|
|
152
158
|
## Managing context
|
|
153
159
|
|
|
@@ -159,8 +165,9 @@ context small:
|
|
|
159
165
|
`TODO.md` and continue. Nothing is lost, because the checklist, commits,
|
|
160
166
|
and code hold all the state. Prefer this over letting one session
|
|
161
167
|
accumulate the entire project.
|
|
162
|
-
- **A cleared or new session recovers by reading `TODO.md
|
|
163
|
-
log**, never by needing the prior
|
|
168
|
+
- **A cleared or new session recovers by reading `TODO.md`,
|
|
169
|
+
`docs/context.md`, and the commit log**, never by needing the prior
|
|
170
|
+
conversation.
|
|
164
171
|
- **Delegate heavy work to agents.** Intake elicitation (`planner`),
|
|
165
172
|
screen builds (`ui-builder`), and reviews (`reviewer`) each run in their
|
|
166
173
|
own isolated context — so that work doesn't pile up in the main thread.
|
package/src/templates/TODO.md
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# TODO
|
|
2
2
|
|
|
3
|
-
<!-- 2-3 sentences: what is this project.
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
<!-- 2-3 sentences: what is this project. Full product narrative, scope
|
|
4
|
+
boundary, and domain vocabulary live in docs/context.md — every project
|
|
5
|
+
has one, written by planner at Intake. -->
|
|
6
6
|
|
|
7
7
|
## Context
|
|
8
8
|
|
|
9
|
-
(fill in per project)
|
|
9
|
+
(fill in per project — see docs/context.md for the full picture)
|
|
10
10
|
|
|
11
11
|
## Bootstrap
|
|
12
12
|
|