@skyf0xx/hedgehog 0.1.21 → 2.0.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/README.md +92 -20
- package/bin/cli.mjs +107 -45
- package/package.json +2 -2
- package/src/agents/bootstrap.md +83 -50
- package/src/agents/front-end-eng.md +1 -1
- package/src/agents/landing-builder.md +96 -0
- package/src/agents/landing-critic.md +107 -0
- package/src/agents/landing-sequencer.md +112 -0
- package/src/agents/landing-strategist.md +217 -0
- package/src/agents/landing-systems.md +206 -0
- package/src/agents/planner.md +207 -143
- package/src/golden-cores/landing-page/.prettierignore +4 -0
- package/src/golden-cores/landing-page/.prettierrc.js +11 -0
- package/src/golden-cores/landing-page/.vscode/extensions.json +4 -0
- package/src/golden-cores/landing-page/.vscode/launch.json +11 -0
- package/src/golden-cores/landing-page/astro.config.mjs +11 -0
- package/src/golden-cores/landing-page/eslint.config.mjs +23 -0
- package/src/golden-cores/landing-page/gitignore.template +9 -0
- package/src/golden-cores/landing-page/package.json +40 -0
- package/src/golden-cores/landing-page/pnpm-lock.yaml +4587 -0
- package/src/golden-cores/landing-page/public/favicon.ico +0 -0
- package/src/golden-cores/landing-page/public/favicon.svg +9 -0
- package/src/golden-cores/landing-page/src/motifs/.gitkeep +0 -0
- package/src/golden-cores/landing-page/src/pages/index.astro +24 -0
- package/src/golden-cores/landing-page/src/sections/.gitkeep +0 -0
- package/src/golden-cores/landing-page/src/styles/global.css +18 -0
- package/src/golden-cores/landing-page/tsconfig.json +5 -0
- package/src/skills/hedgehog-bootstrap/SKILL.md +19 -19
- package/src/skills/{hedgehog-bootstrap-core → hedgehog-bootstrap-full-stack-app-core}/SKILL.md +19 -18
- package/src/skills/hedgehog-bootstrap-landing-page-core/SKILL.md +160 -0
- package/src/skills/hedgehog-landing-loop/SKILL.md +188 -0
- package/src/skills/hedgehog-planning-intake/SKILL.md +30 -17
- package/src/templates/CLAUDE.core.full-stack-app.md +131 -0
- package/src/templates/CLAUDE.core.landing-page.md +133 -0
- package/src/templates/CLAUDE.md +54 -183
- package/src/templates/TODO.core.full-stack-app.md +46 -0
- package/src/templates/TODO.core.landing-page.md +24 -0
- package/src/templates/TODO.md +6 -50
- /package/src/{golden-core → golden-cores/full-stack-app}/.env.example +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/.github/workflows/phase-gate.yml +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/.prettierignore +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/.prettierrc +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/.vscode/extensions.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/api/eslint.config.mjs +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/api/package.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/api/src/app/app.module.ts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/api/src/app/health.controller.ts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/api/src/assets/.gitkeep +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/api/src/main.ts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/api/tsconfig.app.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/api/tsconfig.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/api/webpack.config.cjs +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/api-e2e/eslint.config.mjs +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/api-e2e/package.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/api-e2e/src/api/api.spec.ts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/api-e2e/src/support/global-setup.ts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/api-e2e/src/support/test-setup.ts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/api-e2e/tsconfig.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/api-e2e/tsconfig.spec.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/api-e2e/vitest.config.mts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/.prettierrc.js +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/.swcrc +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/components.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/eslint.config.mjs +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/index.d.ts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/next-env.d.ts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/next.config.js +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/package.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/postcss.config.mjs +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/public/.gitkeep +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/public/favicon.ico +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/src/app/global.css +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/src/app/layout.tsx +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/src/app/page.tsx +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/src/app/providers.tsx +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/src/components/theme-toggle.tsx +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/src/components/ui/button.tsx +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/src/lib/utils.ts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web/tsconfig.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web-e2e/eslint.config.mjs +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web-e2e/package.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web-e2e/playwright.config.mts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web-e2e/src/example.spec.ts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/apps/web-e2e/tsconfig.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/commitlint.config.cjs +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/docker-compose.yml +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/eslint.config.mjs +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/gitignore.template +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/lefthook.yml +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/nx.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/package.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/config/eslint-base.js +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/config/package.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/config/prettier.js +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/config/src/env.schema.spec.ts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/config/src/env.schema.ts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/config/src/index.ts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/config/tsconfig.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/config/tsconfig.lib.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/config/tsconfig.spec.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/config/vitest.config.mts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/db/package.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/db/src/index.ts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/db/src/lib/db.spec.ts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/db/src/lib/db.ts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/db/tsconfig.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/db/tsconfig.lib.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/db/tsconfig.spec.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/packages/db/vitest.config.mts +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/pnpm-lock.yaml +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/pnpm-workspace.yaml +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/tools/phase-gate.cjs +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/tsconfig.base.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/tsconfig.json +0 -0
- /package/src/{golden-core → golden-cores/full-stack-app}/vitest.workspace.ts +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# The Antidote to AI Spaghetti Code ⭐
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@skyf0xx/hedgehog)
|
|
4
|
+
|
|
4
5
|
|
|
5
6
|
AI writes code faster than humans ever could, but **speed without discipline creates chaos**.
|
|
6
7
|
|
|
@@ -10,8 +11,8 @@ AI writes code faster than humans ever could, but **speed without discipline cre
|
|
|
10
11
|
|
|
11
12
|
Hedgehog pairs **BMAD's planning** with **disciplined execution**, in one workflow.
|
|
12
13
|
|
|
13
|
-
- Plan: BMAD workflow
|
|
14
14
|
- Build: Hedgehog execution discipline
|
|
15
|
+
- Plan: BMAD workflow
|
|
15
16
|
- Ship: Quality gates and incremental loops
|
|
16
17
|
|
|
17
18
|

|
|
@@ -22,9 +23,18 @@ Hedgehog pairs **BMAD's planning** with **disciplined execution**, in one workfl
|
|
|
22
23
|
2. An enforced build order
|
|
23
24
|
3. Agents and skills that make good engineering the default
|
|
24
25
|
|
|
26
|
+
Hedgehog ships more than one **core** — a fixed stack, agent set, and
|
|
27
|
+
build order for one project shape. `full-stack-app` is the original: Nx,
|
|
28
|
+
NestJS, Drizzle, ts-rest, Next.js, backend-first (see **The Hedgehog
|
|
29
|
+
Loop**, below). A second core, `landing-page`, applies the same
|
|
30
|
+
discipline to a different shape — Astro, GSAP, a fixed pipeline for
|
|
31
|
+
turning a brief into a traceable, non-templated page instead of a
|
|
32
|
+
domain-module build order (see **The Chain Method**, below). Which core
|
|
33
|
+
applies is decided once, at planning intake, from what you describe.
|
|
34
|
+
|
|
25
35
|
## Hedgehog's secret to great outcomes
|
|
26
36
|
|
|
27
|
-
- **Progressive layering:** types → schema → backend → UI
|
|
37
|
+
- **Progressive layering:** each core builds one stable layer at a time — types → schema → backend → UI on `full-stack-app`; brief → feeling → tokens → sequence → artifact on `landing-page`
|
|
28
38
|
- **Small context loops:** decompose work into atomic, verifiable changes
|
|
29
39
|
- **Self-documenting architecture:** the codebase carries the context, not the AI
|
|
30
40
|
- **Traceable evolution:** decisions are preserved through conventional commits
|
|
@@ -45,17 +55,17 @@ Hedgehog doesn't ask the AI to remember a plan. It makes the plan visible in the
|
|
|
45
55
|
|
|
46
56
|
### The AI should never wonder what to do next
|
|
47
57
|
|
|
48
|
-
Instead of asking AI to hold an entire application in context, Hedgehog turns the build into a sequence of small, deterministic steps.
|
|
58
|
+
Instead of asking AI to hold an entire application in context, Hedgehog turns the build into a sequence of small, deterministic steps. The exact sequence depends on the project's core — a stateful app and a landing page don't share a build order, so they don't share an enforcement mechanism either. On the `full-stack-app` core:
|
|
49
59
|
|
|
50
60
|
Each module is built progressively: schema → contract → repository → service → controller. Every step is gated by tests and committed before the next begins.
|
|
51
61
|
|
|
52
62
|
Backend comes first. Every module gets a working, typed API before any screen is built. The frontend becomes a consumer of stable capabilities, not a parallel source of complexity.
|
|
53
63
|
|
|
54
|
-
The build order is not something you negotiate with the AI. It is encoded into the process.
|
|
64
|
+
The build order is not something you negotiate with the AI. It is encoded into the process — the same is true on the `landing-page` core, just for a different sequence (see **The Chain Method**, below).
|
|
55
65
|
|
|
56
66
|

|
|
57
67
|
|
|
58
|
-
## The Hedgehog Loop
|
|
68
|
+
## The Hedgehog Loop (full-stack-app core)
|
|
59
69
|
|
|
60
70
|
``` text
|
|
61
71
|
Planning intake - BMAD-METHOD's brief/PRD/UX spec, mined into scope
|
|
@@ -75,6 +85,36 @@ Repeat for the next module or the next step
|
|
|
75
85
|
|
|
76
86
|

|
|
77
87
|
|
|
88
|
+
## The Chain Method (landing-page core)
|
|
89
|
+
|
|
90
|
+
A different shape gets a different loop, not a variant of this one —
|
|
91
|
+
there's no domain module to build, so the enforced order is a pipeline
|
|
92
|
+
instead of a layer sequence:
|
|
93
|
+
|
|
94
|
+
``` text
|
|
95
|
+
Planning intake - BMAD-METHOD's brief/PR-FAQ/PRD/UX spec, mined into a
|
|
96
|
+
subject/audience/single-job statement (planner agent)
|
|
97
|
+
↓
|
|
98
|
+
Bootstrap (once per project - Astro + Tailwind workspace)
|
|
99
|
+
↓
|
|
100
|
+
Strategy - subject statement → adjective pairs → visceral/behavioral/
|
|
101
|
+
reflective sort → top/heart/base note timing (landing-strategist)
|
|
102
|
+
↓
|
|
103
|
+
Systems - ingredient dials + copy voice (parallel) → token system →
|
|
104
|
+
signature motif (landing-systems)
|
|
105
|
+
↓
|
|
106
|
+
Sequence - per-section transitions, weight, pacing (landing-sequencer)
|
|
107
|
+
↓
|
|
108
|
+
Audit - traceability/distinctiveness + usability, reconciled to a pass
|
|
109
|
+
(landing-critic) - redlines route back to the phase that owns them
|
|
110
|
+
↓
|
|
111
|
+
Build - the artifact, in Astro (landing-builder)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Every choice traces back to a sentence in the subject statement, or it
|
|
115
|
+
gets cut — that traceability is what keeps the output from converging on
|
|
116
|
+
the same templated look every AI-generated page defaults to.
|
|
117
|
+
|
|
78
118
|
## Installation
|
|
79
119
|
|
|
80
120
|
From an empty project folder:
|
|
@@ -83,16 +123,28 @@ From an empty project folder:
|
|
|
83
123
|
npx @skyf0xx/hedgehog init
|
|
84
124
|
```
|
|
85
125
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
brief, PRD, and UX spec - then mines that into what's in scope and which
|
|
89
|
-
add-ons (Auth, Queue, Mobile) you need; once you confirm, it scaffolds
|
|
90
|
-
the project itself.
|
|
126
|
+
This installs the `full-stack-app` core by default. For the landing-page
|
|
127
|
+
core instead:
|
|
91
128
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
129
|
+
``` bash
|
|
130
|
+
npx @skyf0xx/hedgehog init --core=landing-page
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
Then open Claude Code and describe what you want to build. The
|
|
134
|
+
`planner` agent decides which core actually applies (overriding the
|
|
135
|
+
installer's default if what you describe doesn't match it), then runs
|
|
136
|
+
that core's own planning intake — both cores run BMAD-METHOD's
|
|
137
|
+
brainstorming, brief, PR-FAQ, PRD, UX spec, and deep-recon in full;
|
|
138
|
+
`full-stack-app` mines that output into scope boundary and domain
|
|
139
|
+
vocabulary, `landing-page` mines it into a subject/audience/job
|
|
140
|
+
statement. Once you confirm, it scaffolds the project itself.
|
|
141
|
+
|
|
142
|
+
The chosen core's workspace - for `full-stack-app`: Nx, `packages/config`,
|
|
143
|
+
`packages/db`, `apps/api`, `apps/web`, and every enforcement file; for
|
|
144
|
+
`landing-page`: the Astro + Tailwind workspace and its animation library
|
|
145
|
+
set - lands instantly from a pre-verified template rather than being
|
|
146
|
+
generated live; bootstrap then verifies it (and, on `full-stack-app`,
|
|
147
|
+
runs whichever add-ons planning intake determined your project needs).
|
|
96
148
|
|
|
97
149
|
Or paste the repo URL to your Agent and have it install for you.
|
|
98
150
|
|
|
@@ -104,7 +156,7 @@ npx @skyf0xx/hedgehog update
|
|
|
104
156
|
```
|
|
105
157
|
|
|
106
158
|
This refreshes `.claude/agents/` and `.claude/skills/` only — it never
|
|
107
|
-
touches `CLAUDE.md`, `TODO.md`, the
|
|
159
|
+
touches `CLAUDE.md`, `TODO.md`, the core workspace, or
|
|
108
160
|
`skills/BMAD`, since those carry project-specific or write-once content.
|
|
109
161
|
|
|
110
162
|
## For Builders
|
|
@@ -127,7 +179,9 @@ AI becomes the builder operating inside those constraints - turning ideas into s
|
|
|
127
179
|
|
|
128
180
|
## Architecture
|
|
129
181
|
|
|
130
|
-
Hedgehog is a package of agents and skills, built on an opinionated stack so the build order above is mechanical and enforced by the tooling itself
|
|
182
|
+
Hedgehog is a package of agents and skills, built on an opinionated stack per core so the build order above is mechanical and enforced by the tooling itself.
|
|
183
|
+
|
|
184
|
+
### `full-stack-app` core
|
|
131
185
|
|
|
132
186
|
| Layer | Choice | Why |
|
|
133
187
|
| --- | --- | --- |
|
|
@@ -151,11 +205,29 @@ Hedgehog is a package of agents and skills, built on an opinionated stack so the
|
|
|
151
205
|
| Commits | Conventional Commits | Architectural decisions become permanent history. |
|
|
152
206
|
| Observability | Sentry | Failures map cleanly back to module boundaries. |
|
|
153
207
|
|
|
208
|
+
### `landing-page` core
|
|
209
|
+
|
|
210
|
+
Every choice below maps to a specific dial or phase in the Chain
|
|
211
|
+
Method — nothing here is a default reached for out of habit:
|
|
212
|
+
|
|
213
|
+
| Layer | Choice | Why |
|
|
214
|
+
| --- | --- | --- |
|
|
215
|
+
| Framework | Astro | Zero-JS-by-default shell; islands only where interaction is actually needed. |
|
|
216
|
+
| Styling | Tailwind (v4, CSS-first) | Config as token layer only — no component library pre-deciding how things look. |
|
|
217
|
+
| Animation | GSAP + ScrollTrigger | Owns per-section pacing and top/heart/base fade timing with real control. |
|
|
218
|
+
| Scroll feel | Lenis | The "weight and suspension" dial, instead of default browser scroll physics. |
|
|
219
|
+
| Copy reveal | SplitType | Line/word/char splitting — makes copy rhythm visible in motion, not just static text. |
|
|
220
|
+
| Motif | SVG-first + Paper.js | Hand-authored graphics; Paper.js for a motif that evolves (augmentation/inversion) across sections. |
|
|
221
|
+
| Motif transforms | GSAP MorphSVGPlugin | Ships free inside the `gsap` package — for a motif that physically transforms across sections. |
|
|
222
|
+
| Texture | Custom SVG noise/grain filter | Cheap materiality layer nothing else in the stack owns. |
|
|
223
|
+
| Design handoff | Figma MCP / Stitch MCP | Input only, at the Strategist/Builder boundaries — never allowed to set spacing/style defaults directly. |
|
|
224
|
+
| 3D (rare) | React Three Fiber | Only when the subject is genuinely spatial; skipped by default. |
|
|
225
|
+
|
|
154
226
|
## How Hedgehog Compares
|
|
155
227
|
|
|
156
228
|
Superpowers and BMAD both improve on raw prompting: one gives the AI good habits, the other a planning process. Alone, either can still be broken by convention.
|
|
157
229
|
|
|
158
|
-
Hedgehog runs BMAD for planning, then enforces the build that follows with tooling, not convention
|
|
230
|
+
Hedgehog runs BMAD for planning on both cores — the same full shelf either way, mined differently per core's own shape — then enforces the build that follows with tooling, not convention — Nx boundaries, commit hooks, and phase gates on `full-stack-app`; a redline-gated pipeline on `landing-page`.
|
|
159
231
|
|
|
160
232
|
| | Superpowers | BMAD | Hedgehog + BMAD |
|
|
161
233
|
| --- | --- | --- | --- |
|
|
@@ -163,7 +235,7 @@ Hedgehog runs BMAD for planning, then enforces the build that follows with tooli
|
|
|
163
235
|
| **Order comes from** | Skill instructions the agent is told to follow | Sequenced documents (brief → PRD → architecture → stories) | Tooling (Nx, lefthook, phase gate) |
|
|
164
236
|
| **Enforcement mechanism** | None. Prompted convention | None. One optional checklist between phases | Execution mechanically enforced |
|
|
165
237
|
| **Unit of work** | A task, planned in worktree-isolated steps | A story, derived from PRD and architecture docs | A module layer (schema → contract → repo → service → controller → UI) |
|
|
166
|
-
| **Stack** | Whatever the project already uses | No stack opinion | One locked stack (Nx
|
|
238
|
+
| **Stack** | Whatever the project already uses | No stack opinion | One locked stack per core (Nx/NestJS/Drizzle/ts-rest/Next.js for `full-stack-app`; Astro/Tailwind/GSAP for `landing-page`), chosen once at planning intake |
|
|
167
239
|
| **Context per step** | As much as the task pulls in | A full brief, PRD, and architecture doc per story | One module layer at a time - BMAD's docs are mined once, up front |
|
|
168
240
|
| **Finding a bug** | Search wherever the task touched | Search wherever the story touched | Search one layer, in one module, in a fixed order |
|
|
169
241
|
| **Real cost** | No safety net if the model shortcuts its own process | Documentation overhead most solo projects don't need | Stack and order aren't negotiable |
|
|
@@ -183,4 +255,4 @@ The `nx-generate`, `nx-run-tasks`, `nx-workspace`, and
|
|
|
183
255
|
|
|
184
256
|
If Hedgehog helps you build better AI software, consider giving it a ⭐ on GitHub.
|
|
185
257
|
|
|
186
|
-
[](https://github.com/skyf0xx/hedgehog/stargazers)
|
|
258
|
+
[](https://github.com/skyf0xx/hedgehog/stargazers)
|
package/bin/cli.mjs
CHANGED
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
// into the current repo, so the discipline travels with the project.
|
|
4
4
|
//
|
|
5
5
|
// Usage:
|
|
6
|
-
// npx @skyf0xx/hedgehog init
|
|
7
|
-
// npx @skyf0xx/hedgehog init --
|
|
8
|
-
// npx @skyf0xx/hedgehog
|
|
6
|
+
// npx @skyf0xx/hedgehog init scaffold, full-stack-app core (default)
|
|
7
|
+
// npx @skyf0xx/hedgehog init --core=landing-page scaffold with a named core instead
|
|
8
|
+
// npx @skyf0xx/hedgehog init --force overwrite files that already exist
|
|
9
|
+
// npx @skyf0xx/hedgehog update refresh .claude/agents + .claude/skills
|
|
9
10
|
// npx @skyf0xx/hedgehog --help
|
|
10
11
|
|
|
11
|
-
import { cp, mkdir, access, readdir, stat, rm } from 'node:fs/promises';
|
|
12
|
+
import { cp, mkdir, access, readdir, stat, rm, readFile, writeFile } from 'node:fs/promises';
|
|
12
13
|
import { constants } from 'node:fs';
|
|
13
14
|
import { fileURLToPath } from 'node:url';
|
|
14
15
|
import { dirname, join, relative, resolve } from 'node:path';
|
|
@@ -16,6 +17,8 @@ import { dirname, join, relative, resolve } from 'node:path';
|
|
|
16
17
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
17
18
|
const PKG_ROOT = resolve(__dirname, '..');
|
|
18
19
|
const DEST_ROOT = process.cwd();
|
|
20
|
+
const CORES_ROOT = join(PKG_ROOT, 'src/golden-cores');
|
|
21
|
+
const DEFAULT_CORE = 'full-stack-app';
|
|
19
22
|
|
|
20
23
|
// ── tiny ANSI helpers (no deps) ─────────────────────────────────────────
|
|
21
24
|
const useColor = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
@@ -31,35 +34,61 @@ const dim = (s) => paint('2', s);
|
|
|
31
34
|
// this name in the package, renamed back on copy.
|
|
32
35
|
const DOTFILE_RENAMES = { 'gitignore.template': '.gitignore' };
|
|
33
36
|
|
|
37
|
+
// Every subdirectory of src/golden-cores/ is a valid --core value —
|
|
38
|
+
// discovered from disk so a new core added under golden-cores/ doesn't
|
|
39
|
+
// need this list touched separately.
|
|
40
|
+
async function availableCores() {
|
|
41
|
+
return (await readdir(CORES_ROOT, { withFileTypes: true }))
|
|
42
|
+
.filter((e) => e.isDirectory())
|
|
43
|
+
.map((e) => e.name)
|
|
44
|
+
.sort();
|
|
45
|
+
}
|
|
46
|
+
|
|
34
47
|
// ── the payload: what gets copied, and to where under the target repo ───
|
|
35
48
|
// `dir` entries copy a whole tree; `file` entries copy a single file and
|
|
36
|
-
// may rename (templates lose their src/templates/ prefix at the root)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
// may rename (templates lose their src/templates/ prefix at the root);
|
|
50
|
+
// `merge` entries concatenate a shared shell with a core-specific include
|
|
51
|
+
// at {{CORE_SECTION}} (see CLAUDE.md template plumbing below).
|
|
52
|
+
// Agents and skills for every core install regardless of which one is
|
|
53
|
+
// chosen — planner needs the full toolset to run core selection at all,
|
|
54
|
+
// and a project can only switch cores before it's bootstrapped anyway.
|
|
55
|
+
function plan(core) {
|
|
56
|
+
return [
|
|
57
|
+
{ type: 'dir', from: 'src/agents', to: '.claude/agents' },
|
|
58
|
+
{ type: 'dir', from: 'src/skills', to: '.claude/skills' },
|
|
59
|
+
// The vendored BMAD-METHOD planning shelf that hedgehog-planning-intake
|
|
60
|
+
// runs — referenced by repo-root-relative path (skills/BMAD/...), so it
|
|
61
|
+
// lands there rather than under .claude/.
|
|
62
|
+
{ type: 'dir', from: 'skills/BMAD', to: 'skills/BMAD' },
|
|
63
|
+
{
|
|
64
|
+
type: 'merge',
|
|
65
|
+
shell: 'src/templates/CLAUDE.md',
|
|
66
|
+
include: `src/templates/CLAUDE.core.${core}.md`,
|
|
67
|
+
to: 'CLAUDE.md',
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
type: 'merge',
|
|
71
|
+
shell: 'src/templates/TODO.md',
|
|
72
|
+
include: `src/templates/TODO.core.${core}.md`,
|
|
73
|
+
to: 'TODO.md',
|
|
74
|
+
},
|
|
75
|
+
// The pre-built, pre-verified workspace for the chosen core —
|
|
76
|
+
// everything a fresh project of that shape needs at repo root
|
|
77
|
+
// (lands the root package.json too, so there's no separate
|
|
78
|
+
// placeholder for it). The relevant bootstrap-core skill verifies
|
|
79
|
+
// this on first run rather than generating it live.
|
|
80
|
+
{ type: 'dir', from: `src/golden-cores/${core}`, to: '.' },
|
|
81
|
+
];
|
|
82
|
+
}
|
|
54
83
|
|
|
55
|
-
// The subset of
|
|
84
|
+
// The subset of plan() that's the discipline's payload rather than
|
|
56
85
|
// project-specific or write-once content: `update` re-copies exactly
|
|
57
86
|
// this, always overwriting, since a consuming project's own
|
|
58
87
|
// .claude/agents and .claude/skills are supposed to match upstream
|
|
59
|
-
// verbatim. CLAUDE.md/TODO.md carry project-filled content,
|
|
60
|
-
// is verified once by
|
|
61
|
-
// re-vendored only deliberately (bmad-revendor) — none
|
|
62
|
-
// in an update.
|
|
88
|
+
// verbatim. CLAUDE.md/TODO.md carry project-filled content, the core
|
|
89
|
+
// workspace is verified once by its bootstrap-core skill, and
|
|
90
|
+
// skills/BMAD is re-vendored only deliberately (bmad-revendor) — none
|
|
91
|
+
// of those belong in an update.
|
|
63
92
|
const UPDATE_PLAN = [
|
|
64
93
|
{ type: 'dir', from: 'src/agents', to: '.claude/agents' },
|
|
65
94
|
{ type: 'dir', from: 'src/skills', to: '.claude/skills' },
|
|
@@ -71,8 +100,25 @@ const exists = (p) =>
|
|
|
71
100
|
() => false,
|
|
72
101
|
);
|
|
73
102
|
|
|
103
|
+
// Writes one planned file to disk — a straight copy, or for a `merge`
|
|
104
|
+
// entry, the shell template with {{CORE_SECTION}} replaced by the
|
|
105
|
+
// chosen core's include.
|
|
106
|
+
async function writePlannedFile(f) {
|
|
107
|
+
await mkdir(dirname(f.dest), { recursive: true });
|
|
108
|
+
if (f.merge) {
|
|
109
|
+
const shell = await readFile(join(PKG_ROOT, f.merge.shell), 'utf8');
|
|
110
|
+
const section = await readFile(join(PKG_ROOT, f.merge.include), 'utf8');
|
|
111
|
+
await writeFile(f.dest, shell.replaceAll('{{CORE_SECTION}}', section.trimEnd()));
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
await cp(f.src, f.dest);
|
|
115
|
+
}
|
|
116
|
+
|
|
74
117
|
// Every destination file this plan would write, resolved absolute.
|
|
75
118
|
async function plannedFiles(entry) {
|
|
119
|
+
if (entry.type === 'merge') {
|
|
120
|
+
return [{ dest: join(DEST_ROOT, entry.to), merge: entry }];
|
|
121
|
+
}
|
|
76
122
|
const src = join(PKG_ROOT, entry.from);
|
|
77
123
|
if (entry.type === 'file') {
|
|
78
124
|
return [{ src, dest: join(DEST_ROOT, entry.to) }];
|
|
@@ -92,7 +138,8 @@ async function plannedFiles(entry) {
|
|
|
92
138
|
return out;
|
|
93
139
|
}
|
|
94
140
|
|
|
95
|
-
function help() {
|
|
141
|
+
async function help() {
|
|
142
|
+
const cores = await availableCores();
|
|
96
143
|
console.log(`
|
|
97
144
|
${bold('Hedgehog installer')}
|
|
98
145
|
|
|
@@ -101,28 +148,40 @@ CLAUDE.md / TODO.md templates into the repo root, so the discipline is
|
|
|
101
148
|
committed alongside your code.
|
|
102
149
|
|
|
103
150
|
${bold('Usage')}
|
|
104
|
-
npx @skyf0xx/hedgehog init
|
|
105
|
-
npx @skyf0xx/hedgehog init --
|
|
106
|
-
npx @skyf0xx/hedgehog
|
|
151
|
+
npx @skyf0xx/hedgehog init scaffold, ${DEFAULT_CORE} core (default)
|
|
152
|
+
npx @skyf0xx/hedgehog init --core=<name> scaffold with a named core instead
|
|
153
|
+
npx @skyf0xx/hedgehog init --force overwrite existing files
|
|
154
|
+
npx @skyf0xx/hedgehog update refresh .claude/agents + .claude/skills
|
|
107
155
|
npx @skyf0xx/hedgehog --help
|
|
108
156
|
|
|
109
|
-
|
|
110
|
-
|
|
157
|
+
Available cores: ${cores.join(', ')}
|
|
158
|
+
|
|
159
|
+
After it runs, commit the payload, open Claude Code, and say
|
|
160
|
+
"bootstrap this project" to trigger the matching bootstrap-core skill.
|
|
111
161
|
|
|
112
162
|
${bold('update')} re-copies only .claude/agents and .claude/skills from the
|
|
113
163
|
installed Hedgehog version, so an already-bootstrapped project can pick up
|
|
114
164
|
agent/skill changes from a newer release. It always overwrites those two
|
|
115
|
-
directories and never touches CLAUDE.md, TODO.md,
|
|
165
|
+
directories and never touches CLAUDE.md, TODO.md, the core workspace, or
|
|
116
166
|
skills/BMAD — those are project-specific or updated deliberately, not by
|
|
117
167
|
this command.
|
|
118
168
|
`);
|
|
119
169
|
}
|
|
120
170
|
|
|
121
|
-
async function init({ force }) {
|
|
171
|
+
async function init({ force, core }) {
|
|
172
|
+
const cores = await availableCores();
|
|
173
|
+
if (!cores.includes(core)) {
|
|
174
|
+
console.error(
|
|
175
|
+
`${red('Unknown core:')} ${core}\n\nAvailable cores: ${cores.join(', ')}\n`,
|
|
176
|
+
);
|
|
177
|
+
process.exitCode = 1;
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
|
|
122
181
|
// Resolve the full list of writes up front so we can detect conflicts
|
|
123
182
|
// before touching anything.
|
|
124
183
|
const groups = [];
|
|
125
|
-
for (const entry of
|
|
184
|
+
for (const entry of plan(core)) {
|
|
126
185
|
const files = await plannedFiles(entry);
|
|
127
186
|
groups.push({ entry, files });
|
|
128
187
|
}
|
|
@@ -151,8 +210,7 @@ async function init({ force }) {
|
|
|
151
210
|
for (const { files } of groups) {
|
|
152
211
|
for (const f of files) {
|
|
153
212
|
const already = await exists(f.dest);
|
|
154
|
-
await
|
|
155
|
-
await cp(f.src, f.dest);
|
|
213
|
+
await writePlannedFile(f);
|
|
156
214
|
if (already) overwritten++;
|
|
157
215
|
else written++;
|
|
158
216
|
const label = already ? yellow('overwrite') : green('create');
|
|
@@ -169,11 +227,13 @@ async function init({ force }) {
|
|
|
169
227
|
console.log(` 1. ${bold('git add -A && git commit -m "chore: install Hedgehog"')}`);
|
|
170
228
|
console.log(` 2. ${bold('pnpm install')}`);
|
|
171
229
|
console.log(` 3. Open Claude Code and say: ${bold('"bootstrap this project"')}\n`);
|
|
230
|
+
console.log(dim(`Core: ${bold(core)} — already scaffolded and verified.`));
|
|
172
231
|
console.log(
|
|
173
232
|
dim(
|
|
174
|
-
|
|
175
|
-
'apps/web)
|
|
176
|
-
|
|
233
|
+
core === DEFAULT_CORE
|
|
234
|
+
? '(Nx, packages/config, packages/db, apps/api, apps/web) — bootstrap\n' +
|
|
235
|
+
'now only runs whichever add-ons (Auth, Queue, Mobile) Intake calls for.'
|
|
236
|
+
: 'bootstrap now only runs whichever add-on steps this core defines, if any.',
|
|
177
237
|
),
|
|
178
238
|
);
|
|
179
239
|
}
|
|
@@ -205,7 +265,7 @@ async function update() {
|
|
|
205
265
|
console.log(` 2. ${bold('git add -A && git commit -m "chore: update hedgehog"')}\n`);
|
|
206
266
|
console.log(
|
|
207
267
|
dim(
|
|
208
|
-
'CLAUDE.md, TODO.md, the
|
|
268
|
+
'CLAUDE.md, TODO.md, the core workspace, and skills/BMAD are\n' +
|
|
209
269
|
'untouched — those carry project-specific or write-once content.',
|
|
210
270
|
),
|
|
211
271
|
);
|
|
@@ -214,14 +274,16 @@ async function update() {
|
|
|
214
274
|
async function main() {
|
|
215
275
|
const args = process.argv.slice(2);
|
|
216
276
|
if (args.includes('--help') || args.includes('-h') || args.length === 0) {
|
|
217
|
-
help();
|
|
277
|
+
await help();
|
|
218
278
|
return;
|
|
219
279
|
}
|
|
220
280
|
const cmd = args[0];
|
|
221
281
|
const force = args.includes('--force') || args.includes('-f');
|
|
282
|
+
const coreArg = args.find((a) => a.startsWith('--core='));
|
|
283
|
+
const core = coreArg ? coreArg.slice('--core='.length) : DEFAULT_CORE;
|
|
222
284
|
|
|
223
285
|
if (cmd === 'init') {
|
|
224
|
-
await init({ force });
|
|
286
|
+
await init({ force, core });
|
|
225
287
|
return;
|
|
226
288
|
}
|
|
227
289
|
|
|
@@ -231,7 +293,7 @@ async function main() {
|
|
|
231
293
|
}
|
|
232
294
|
|
|
233
295
|
console.error(`${red('Unknown command:')} ${cmd}\n`);
|
|
234
|
-
help();
|
|
296
|
+
await help();
|
|
235
297
|
process.exitCode = 1;
|
|
236
298
|
}
|
|
237
299
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skyf0xx/hedgehog",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Install the Hedgehog build discipline (agents + skills) into a repo.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"src/agents",
|
|
22
22
|
"src/skills",
|
|
23
23
|
"src/templates",
|
|
24
|
-
"src/golden-
|
|
24
|
+
"src/golden-cores",
|
|
25
25
|
"skills/BMAD"
|
|
26
26
|
],
|
|
27
27
|
"engines": {
|