@skyf0xx/hedgehog 0.1.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 +180 -0
- package/bin/cli.mjs +156 -0
- package/package.json +30 -0
- package/src/agents/planner.md +245 -0
- package/src/agents/reviewer.md +95 -0
- package/src/agents/ui-builder.md +73 -0
- package/src/agents/ux-planner.md +149 -0
- package/src/skills/conventional-commits/SKILL.md +147 -0
- package/src/skills/hedgehog-bootstrap/SKILL.md +403 -0
- package/src/skills/hedgehog-loop/SKILL.md +197 -0
- package/src/templates/CLAUDE.md +171 -0
- package/src/templates/TODO.md +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# The Antidote to AI Spaghetti Code
|
|
2
|
+
|
|
3
|
+
AI can write code faster than humans ever could.
|
|
4
|
+
|
|
5
|
+
But **speed without discipline creates chaos**.
|
|
6
|
+
|
|
7
|
+
Hedgehog gives AI the guard-rails it needs to **build software that stays clean.**
|
|
8
|
+
|
|
9
|
+
A complete development methodology combining:
|
|
10
|
+
|
|
11
|
+
- structured workflows
|
|
12
|
+
- opinionated architecture
|
|
13
|
+
- composable skills
|
|
14
|
+
- incremental build loops
|
|
15
|
+
- enforced quality gates
|
|
16
|
+
|
|
17
|
+
**Build faster, Save context**. Stay aligned. Ship software you can still understand six months later.
|
|
18
|
+
|
|
19
|
+

|
|
20
|
+
|
|
21
|
+
## Hedgehog gives AI
|
|
22
|
+
|
|
23
|
+
1. An opinionated stack
|
|
24
|
+
2. An enforced build order
|
|
25
|
+
3. Agents and skills that make good engineering the default.
|
|
26
|
+
|
|
27
|
+
## Hedghog's secret to great outcomes
|
|
28
|
+
|
|
29
|
+
- 🧩 **Progressive layering:** types → schema → backend → UI, each layer built on a stable one beneath it
|
|
30
|
+
- 🎯 **Small context loops:** decompose work into atomic, verifiable changes
|
|
31
|
+
- 🌳 **Self-documenting architecture:** the codebase carries the context, not the AI
|
|
32
|
+
- 🔁 **Traceable evolution:** decisions are preserved through conventional commits
|
|
33
|
+
|
|
34
|
+

|
|
35
|
+
|
|
36
|
+
## Why Hedgehog Exists
|
|
37
|
+
|
|
38
|
+
AI coding starts fast then breaks down.
|
|
39
|
+
|
|
40
|
+
Context accumulates, prompts get longer, architecture drifts.
|
|
41
|
+
|
|
42
|
+
Eventually, adding one more feature feels
|
|
43
|
+
dangerous.
|
|
44
|
+
|
|
45
|
+
**The enemy isn't AI. It's the absence of guardrails.**
|
|
46
|
+
|
|
47
|
+
## Plans Expire. Structure Doesn't
|
|
48
|
+
|
|
49
|
+
Without a build order enforced mechanically, an AI (or a person) has to carry the whole plan in its head: architecture, sequencing, past decisions, etc. as an ever-growing prompt.
|
|
50
|
+
|
|
51
|
+
Hedgehog doesn't ask the AI to remember a plan. It makes the plan visible in the structure of the build. The architecture itself guides the next step.
|
|
52
|
+
|
|
53
|
+
### The AI should never wonder what to do next
|
|
54
|
+
|
|
55
|
+
Instead of asking AI to hold an entire application in context, Hedgehog turns the build into a sequence of small, deterministic steps.
|
|
56
|
+
|
|
57
|
+
Each module is built progressively: schema → contract → repository → service → controller. Every step is gated by tests and committed before the next begins.
|
|
58
|
+
|
|
59
|
+
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.
|
|
60
|
+
|
|
61
|
+
The build order is not something you negotiate with the AI. It is encoded into the process.
|
|
62
|
+
|
|
63
|
+

|
|
64
|
+
|
|
65
|
+
## The Hedgehog Loop
|
|
66
|
+
|
|
67
|
+
``` text
|
|
68
|
+
Bootstrap (once per project)
|
|
69
|
+
↓
|
|
70
|
+
Intake — scope boundary + domain vocabulary (planner agent)
|
|
71
|
+
↓
|
|
72
|
+
Phase A, per module — schema → contract → repository → service → controller
|
|
73
|
+
↓
|
|
74
|
+
Phase A closes for the module (gated: typecheck, lint, test)
|
|
75
|
+
↓
|
|
76
|
+
Phase B, per module — hook → UX rationale → screen
|
|
77
|
+
↓
|
|
78
|
+
Repeat for the next module or the next step
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+

|
|
83
|
+
|
|
84
|
+
## Installation
|
|
85
|
+
|
|
86
|
+
Hedgehog installs **into your repo**, not into your editor. The agents and
|
|
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:
|
|
92
|
+
|
|
93
|
+
``` bash
|
|
94
|
+
npx @skyf0xx/hedgehog init
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
This copies:
|
|
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:
|
|
113
|
+
|
|
114
|
+
> bootstrap this project
|
|
115
|
+
|
|
116
|
+
That triggers the `hedgehog-bootstrap` skill, which scaffolds the stack and
|
|
117
|
+
wires the enforcement config (Nx boundaries, lefthook, commitlint, phase
|
|
118
|
+
gate). From there, `hedgehog-loop` takes over one module at a time.
|
|
119
|
+
|
|
120
|
+
## For Builders
|
|
121
|
+
|
|
122
|
+
Hedgehog brings proven software engineering practices into AI-assisted development.
|
|
123
|
+
|
|
124
|
+
Once the project brief is defined, Hedgehog takes over the execution: breaking the work into steps, following the build order, validating progress, and keeping decisions traceable.
|
|
125
|
+
|
|
126
|
+
Under the hood, it applies the practices experienced engineers rely on:
|
|
127
|
+
|
|
128
|
+
- iterative delivery
|
|
129
|
+
- small units of work
|
|
130
|
+
- an opinionated stack
|
|
131
|
+
- clear architectural boundaries
|
|
132
|
+
- ports and adapters
|
|
133
|
+
- continuous verification
|
|
134
|
+
- conventional commits
|
|
135
|
+
|
|
136
|
+
AI becomes the builder operating inside those constraints — turning ideas into software without requiring you to manage every implementation detail.
|
|
137
|
+
|
|
138
|
+
## Architecture
|
|
139
|
+
|
|
140
|
+
Hedgehog is a package of agents and skills. An opinionated stack is used so the build order above is mechanical and enforced by the tooling itself:
|
|
141
|
+
|
|
142
|
+
| Layer | Choice | Why |
|
|
143
|
+
| --- | --- | --- |
|
|
144
|
+
| Monorepo | Nx | Enforces module boundaries at compile time. |
|
|
145
|
+
| Package manager | pnpm | Prevents accidental cross-package dependencies. |
|
|
146
|
+
| Backend | NestJS | Modules naturally mirror Hedgehog's build progression. |
|
|
147
|
+
| ORM | Drizzle + drizzle-zod | Database schema is the single source of truth. |
|
|
148
|
+
| Database | PostgreSQL | Simple, relational, predictable. |
|
|
149
|
+
| Platform | Railway | Infrastructure is available from the first commit. |
|
|
150
|
+
| API contract | ts-rest | Contracts are code, not documentation. |
|
|
151
|
+
| Validation | Zod | One schema for runtime and compile time. |
|
|
152
|
+
| Auth | Better Auth | Secure by default from day one. |
|
|
153
|
+
| Data fetching | TanStack Query | UI consumes typed APIs, never implementation details. |
|
|
154
|
+
| Web | Next.js + ShadCN + Tailwind | UI remains a thin presentation layer. |
|
|
155
|
+
| Mobile | Expo + RN Reusables | Shares contracts and design tokens with web. |
|
|
156
|
+
| Jobs | BullMQ + Redis | Async boundaries exist before they're needed. |
|
|
157
|
+
| Logging | Pino | Structured logs from the first feature. |
|
|
158
|
+
| Linting | ESLint + Prettier | One shared standard across every module. |
|
|
159
|
+
| Testing | Vitest + Playwright | Every step is verifiable before progressing. |
|
|
160
|
+
| Commits | Conventional Commits | Architectural decisions become permanent history. |
|
|
161
|
+
| Observability | Sentry | Failures map cleanly back to module boundaries. |
|
|
162
|
+
|
|
163
|
+
## How Hedgehog Compares
|
|
164
|
+
|
|
165
|
+
Superpowers and BMAD both improve on raw prompting: one gives the AI good habits, the other gives it a planning process.
|
|
166
|
+
|
|
167
|
+
But in both, the order of work is a **convention, not a constraint** it's unable to break.
|
|
168
|
+
|
|
169
|
+
Hedgehog **enforces its build order with tooling** instead: Nx module boundaries, commit hooks, phase gates. The order holds because the tooling holds it, not because the discipline was followed.
|
|
170
|
+
|
|
171
|
+
| | Superpowers | BMAD | Hedgehog |
|
|
172
|
+
| --- | --- | --- | --- |
|
|
173
|
+
| **What it is** | A skills library for Claude Code: brainstorm, plan, TDD, debug, review | A multi-agent planning framework: PM, Architect, Dev, QA personas | A build discipline: fixed stack, enforced module order |
|
|
174
|
+
| **Order comes from** | Skill instructions the agent is told to follow | Sequenced documents (brief → PRD → architecture → stories) | Tooling (Nx boundaries, lefthook, phase gate) |
|
|
175
|
+
| **Enforcement mechanism** | None. Prompted convention | None. One optional agent-run checklist between phases | Mechanically enforced by Nx boundaries, commit hooks, and the phase gate |
|
|
176
|
+
| **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) |
|
|
177
|
+
| **Stack** | Whatever the project already uses | No stack opinion | One locked stack (Nx, NestJS, Drizzle, ts-rest, Next.js) |
|
|
178
|
+
| **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 (e.g. just the repository, just the controller) |
|
|
179
|
+
| **Finding a bug** | Search wherever the task touched | Search wherever the story touched | Search one layer, in one module, in a fixed order |
|
|
180
|
+
| **Real cost** | No safety net if the model shortcuts its own process | Documentation overhead most solo projects don't need | Less flexibility: the stack and order aren't negotiable |
|
package/bin/cli.mjs
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Hedgehog installer. Copies the agents/skills payload and root templates
|
|
3
|
+
// into the current repo, so the discipline travels with the project.
|
|
4
|
+
//
|
|
5
|
+
// Usage:
|
|
6
|
+
// npx @skyf0xx/hedgehog init scaffold into the current directory
|
|
7
|
+
// npx @skyf0xx/hedgehog init --force overwrite files that already exist
|
|
8
|
+
// npx @skyf0xx/hedgehog --help
|
|
9
|
+
|
|
10
|
+
import { cp, mkdir, access, readdir, stat } from 'node:fs/promises';
|
|
11
|
+
import { constants } from 'node:fs';
|
|
12
|
+
import { fileURLToPath } from 'node:url';
|
|
13
|
+
import { dirname, join, relative, resolve } from 'node:path';
|
|
14
|
+
|
|
15
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
16
|
+
const PKG_ROOT = resolve(__dirname, '..');
|
|
17
|
+
const DEST_ROOT = process.cwd();
|
|
18
|
+
|
|
19
|
+
// ── tiny ANSI helpers (no deps) ─────────────────────────────────────────
|
|
20
|
+
const useColor = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
21
|
+
const paint = (code, s) => (useColor ? `\x1b[${code}m${s}\x1b[0m` : s);
|
|
22
|
+
const bold = (s) => paint('1', s);
|
|
23
|
+
const green = (s) => paint('32', s);
|
|
24
|
+
const yellow = (s) => paint('33', s);
|
|
25
|
+
const red = (s) => paint('31', s);
|
|
26
|
+
const dim = (s) => paint('2', s);
|
|
27
|
+
|
|
28
|
+
// ── the payload: what gets copied, and to where under the target repo ───
|
|
29
|
+
// `dir` entries copy a whole tree; `file` entries copy a single file and
|
|
30
|
+
// may rename (templates lose their src/templates/ prefix at the root).
|
|
31
|
+
const PLAN = [
|
|
32
|
+
{ type: 'dir', from: 'src/agents', to: '.claude/agents' },
|
|
33
|
+
{ type: 'dir', from: 'src/skills', to: '.claude/skills' },
|
|
34
|
+
{ type: 'file', from: 'src/templates/CLAUDE.md', to: 'CLAUDE.md' },
|
|
35
|
+
{ type: 'file', from: 'src/templates/TODO.md', to: 'TODO.md' },
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
const exists = (p) =>
|
|
39
|
+
access(p, constants.F_OK).then(
|
|
40
|
+
() => true,
|
|
41
|
+
() => false,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
// Every destination file this plan would write, resolved absolute.
|
|
45
|
+
async function plannedFiles(entry) {
|
|
46
|
+
const src = join(PKG_ROOT, entry.from);
|
|
47
|
+
if (entry.type === 'file') {
|
|
48
|
+
return [{ src, dest: join(DEST_ROOT, entry.to) }];
|
|
49
|
+
}
|
|
50
|
+
const out = [];
|
|
51
|
+
async function walk(rel) {
|
|
52
|
+
const abs = join(src, rel);
|
|
53
|
+
const st = await stat(abs);
|
|
54
|
+
if (st.isDirectory()) {
|
|
55
|
+
for (const name of await readdir(abs)) await walk(join(rel, name));
|
|
56
|
+
} else {
|
|
57
|
+
out.push({ src: abs, dest: join(DEST_ROOT, entry.to, rel) });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
await walk('.');
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function help() {
|
|
65
|
+
console.log(`
|
|
66
|
+
${bold('Hedgehog installer')}
|
|
67
|
+
|
|
68
|
+
Copies the Hedgehog agents and skills into ${bold('.claude/')} and drops the
|
|
69
|
+
CLAUDE.md / TODO.md templates into the repo root, so the discipline is
|
|
70
|
+
committed alongside your code.
|
|
71
|
+
|
|
72
|
+
${bold('Usage')}
|
|
73
|
+
npx @skyf0xx/hedgehog init scaffold into the current directory
|
|
74
|
+
npx @skyf0xx/hedgehog init --force overwrite existing files
|
|
75
|
+
npx @skyf0xx/hedgehog --help
|
|
76
|
+
|
|
77
|
+
After it runs, commit the .claude/ payload, open Claude Code, and say
|
|
78
|
+
"bootstrap this project" to trigger the hedgehog-bootstrap skill.
|
|
79
|
+
`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async function init({ force }) {
|
|
83
|
+
// Resolve the full list of writes up front so we can detect conflicts
|
|
84
|
+
// before touching anything.
|
|
85
|
+
const groups = [];
|
|
86
|
+
for (const entry of PLAN) {
|
|
87
|
+
const files = await plannedFiles(entry);
|
|
88
|
+
groups.push({ entry, files });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const conflicts = [];
|
|
92
|
+
for (const { files } of groups) {
|
|
93
|
+
for (const f of files) {
|
|
94
|
+
if (await exists(f.dest)) conflicts.push(f.dest);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (conflicts.length && !force) {
|
|
99
|
+
console.error(`\n${red(bold('Refusing to overwrite existing files.'))}\n`);
|
|
100
|
+
for (const c of conflicts) {
|
|
101
|
+
console.error(` ${yellow('exists')} ${relative(DEST_ROOT, c) || c}`);
|
|
102
|
+
}
|
|
103
|
+
console.error(
|
|
104
|
+
`\nRe-run with ${bold('--force')} to overwrite, or move these aside first.\n`,
|
|
105
|
+
);
|
|
106
|
+
process.exitCode = 1;
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
let written = 0;
|
|
111
|
+
let overwritten = 0;
|
|
112
|
+
for (const { files } of groups) {
|
|
113
|
+
for (const f of files) {
|
|
114
|
+
const already = await exists(f.dest);
|
|
115
|
+
await mkdir(dirname(f.dest), { recursive: true });
|
|
116
|
+
await cp(f.src, f.dest);
|
|
117
|
+
if (already) overwritten++;
|
|
118
|
+
else written++;
|
|
119
|
+
const label = already ? yellow('overwrite') : green('create');
|
|
120
|
+
console.log(` ${label} ${relative(DEST_ROOT, f.dest)}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
console.log(
|
|
125
|
+
`\n${green(bold('Hedgehog installed.'))} ${dim(
|
|
126
|
+
`${written} created${overwritten ? `, ${overwritten} overwritten` : ''}`,
|
|
127
|
+
)}\n`,
|
|
128
|
+
);
|
|
129
|
+
console.log('Next steps:');
|
|
130
|
+
console.log(` 1. ${bold('git add .claude CLAUDE.md TODO.md && git commit')}`);
|
|
131
|
+
console.log(` 2. Open Claude Code and say: ${bold('"bootstrap this project"')}\n`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function main() {
|
|
135
|
+
const args = process.argv.slice(2);
|
|
136
|
+
if (args.includes('--help') || args.includes('-h') || args.length === 0) {
|
|
137
|
+
help();
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const cmd = args[0];
|
|
141
|
+
const force = args.includes('--force') || args.includes('-f');
|
|
142
|
+
|
|
143
|
+
if (cmd === 'init') {
|
|
144
|
+
await init({ force });
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
console.error(`${red('Unknown command:')} ${cmd}\n`);
|
|
149
|
+
help();
|
|
150
|
+
process.exitCode = 1;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
main().catch((err) => {
|
|
154
|
+
console.error(`\n${red(bold('Install failed:'))} ${err.message}\n`);
|
|
155
|
+
process.exitCode = 1;
|
|
156
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@skyf0xx/hedgehog",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Install the Hedgehog build discipline (agents + skills) into a repo.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"publishConfig": {
|
|
7
|
+
"access": "public"
|
|
8
|
+
},
|
|
9
|
+
"bin": {
|
|
10
|
+
"hedgehog": "bin/cli.mjs"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"bin",
|
|
14
|
+
"src/agents",
|
|
15
|
+
"src/skills",
|
|
16
|
+
"src/templates"
|
|
17
|
+
],
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=18"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"claude",
|
|
23
|
+
"claude-code",
|
|
24
|
+
"agents",
|
|
25
|
+
"skills",
|
|
26
|
+
"scaffold",
|
|
27
|
+
"hedgehog"
|
|
28
|
+
],
|
|
29
|
+
"license": "MIT"
|
|
30
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: planner
|
|
3
|
+
description: Use for Intake (scope boundary + domain vocabulary) at the start of a project, and for determining module scope/order when a new set of domain modules enters play. Not a per-step planner — the step sequence within a module and TODO.md already handle that.
|
|
4
|
+
model: sonnet
|
|
5
|
+
color: yellow
|
|
6
|
+
tools: Read, Glob, Grep, Write
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
You are the planner role in the Hedgehog discipline. The build sequence
|
|
10
|
+
for *how* a module gets built (schema → contract → repository → service →
|
|
11
|
+
controller → hook → screen) and the phase rules for *when* frontend work
|
|
12
|
+
can start are already fixed (`hedgehog-loop` skill) — not yours to
|
|
13
|
+
replan. You handle what the step sequence and `TODO.md` don't decide:
|
|
14
|
+
what's in scope, and what a table-shaped domain model looks like before
|
|
15
|
+
any schema gets written.
|
|
16
|
+
|
|
17
|
+
## When you run
|
|
18
|
+
|
|
19
|
+
- **Intake** (once per project, before step 1 of anything): capture scope
|
|
20
|
+
boundary and domain vocabulary, per the procedure below.
|
|
21
|
+
- **New scope entering play**: modules added to scope need placing in
|
|
22
|
+
build order (dependency order between modules, not within one).
|
|
23
|
+
- When the user says "plan", "scope", "break down", or before a large
|
|
24
|
+
refactor that might cross module boundaries.
|
|
25
|
+
|
|
26
|
+
## Intake
|
|
27
|
+
|
|
28
|
+
The person describes what they want to build, in their own words —
|
|
29
|
+
narration, existing material, or both. Intake extracts scope boundary and
|
|
30
|
+
domain vocabulary from that description through elicitation and
|
|
31
|
+
synthesis.
|
|
32
|
+
|
|
33
|
+
### Opening the first Intake
|
|
34
|
+
|
|
35
|
+
Before eliciting anything, on a project's first Intake only, state the
|
|
36
|
+
order of work and why, in a sentence or two: this builds backend-first —
|
|
37
|
+
schema, then contract, then domain logic, then a thin API — proven
|
|
38
|
+
working before any screen gets built. Screens, layout, and "how it should
|
|
39
|
+
feel" are part of the same conversation and get captured along with
|
|
40
|
+
everything else; deciding and building from them is Phase B's job
|
|
41
|
+
(`ux-planner` and `ui-builder`), module by module, once a finished API
|
|
42
|
+
exists to build against. State this once, plainly, so it's clear talking
|
|
43
|
+
about screens now means capturing for later, not building now.
|
|
44
|
+
|
|
45
|
+
Elicitation anchors on one concrete pass through the thing, start to
|
|
46
|
+
finish — imagined for a new idea, remembered for an existing workflow
|
|
47
|
+
being replaced. A concrete walkthrough surfaces the real nouns and verbs:
|
|
48
|
+
who uses it, what they do, what comes out the other end.
|
|
49
|
+
|
|
50
|
+
The extracted vocabulary is a first draft, revised the moment it's
|
|
51
|
+
written up or the schema step exposes something the interview missed.
|
|
52
|
+
Revising a draft is a normal edit — the Correction Protocol
|
|
53
|
+
(`hedgehog-loop` skill) applies to it like any other step.
|
|
54
|
+
|
|
55
|
+
### What Intake produces
|
|
56
|
+
|
|
57
|
+
1. **Scope boundary** — what's in, what's explicitly out.
|
|
58
|
+
2. **Domain vocabulary** — the nouns and verbs of the problem.
|
|
59
|
+
3. **Screen/flow notes**, when offered — captured verbatim by module, for
|
|
60
|
+
`ux-planner` to act on at that module's Phase B (see below).
|
|
61
|
+
|
|
62
|
+
### Screens, flows, and other visual input
|
|
63
|
+
|
|
64
|
+
A screenshot, mockup, or existing tool the person points to is fair game
|
|
65
|
+
at Intake as a source of entities, attributes, and workflow steps — a
|
|
66
|
+
competitor's app, a sketch, or a spreadsheet works the same as narration
|
|
67
|
+
here, and doubles as raw material for Phase B later.
|
|
68
|
+
|
|
69
|
+
Layout, styling, and interaction described — "the dashboard should show X
|
|
70
|
+
and Y together," "this should feel like Stripe's checkout" — are
|
|
71
|
+
captured under the relevant module in `docs/design/<module>-notes.md`
|
|
72
|
+
(create it if needed). `ux-planner` turns this into a screen rationale
|
|
73
|
+
once that module's contract and hook exist, in Phase A build order. Name
|
|
74
|
+
this in the moment: "noted for `<module>`'s screen — that gets built
|
|
75
|
+
after its API is working."
|
|
76
|
+
|
|
77
|
+
### Elicitation — what to ask
|
|
78
|
+
|
|
79
|
+
Open with room for a full brain dump, not a question: "Describe what you
|
|
80
|
+
want to build, however makes sense to you — who uses it, what they do,
|
|
81
|
+
what comes out the other end. I'll ask follow-ups after."
|
|
82
|
+
|
|
83
|
+
Ask up front whether anything already shows it — a screenshot of a
|
|
84
|
+
similar tool, a spreadsheet, a sample document, a sketch. Read or look at
|
|
85
|
+
whatever exists before asking questions it already answers — a
|
|
86
|
+
screenshot of a cluttered spreadsheet can surface entities and attributes
|
|
87
|
+
faster than ten minutes of narration.
|
|
88
|
+
|
|
89
|
+
Once the dump and any source material are on the table, close gaps with
|
|
90
|
+
questions anchored to one concrete pass through the thing, start to
|
|
91
|
+
finish — a remembered instance if this replaces an existing workflow, an
|
|
92
|
+
imagined one otherwise:
|
|
93
|
+
|
|
94
|
+
- "Walk me through someone using this, start to finish — what do they
|
|
95
|
+
do, in what order."
|
|
96
|
+
- "What goes in, and what comes out the other end — a decision, a
|
|
97
|
+
record, a notification?"
|
|
98
|
+
- "What are the different kinds of [cases/orders/requests/whatever the
|
|
99
|
+
person calls them] this handles, and what actually differs between
|
|
100
|
+
them?"
|
|
101
|
+
- "Who else is involved, and what do they need from this or give it?"
|
|
102
|
+
- "What's explicitly not in the first version?" — surfaces candidates
|
|
103
|
+
for out-of-scope.
|
|
104
|
+
- "What's a case that wouldn't fit the normal pattern?" — surfaces edge
|
|
105
|
+
cases and the real invariants.
|
|
106
|
+
|
|
107
|
+
Ask one question at a time. Prefer a question the person can answer by
|
|
108
|
+
picking from a short concrete set over a fully open one, when honest to
|
|
109
|
+
offer (e.g. "is that a status the case moves through, or a tag that can
|
|
110
|
+
apply more than one at a time?" beats "tell me more about status"). When
|
|
111
|
+
a term is doing double duty — one word for two things needing different
|
|
112
|
+
lifecycles — name the ambiguity and ask them to split it.
|
|
113
|
+
|
|
114
|
+
Close with "anything else?"
|
|
115
|
+
|
|
116
|
+
Questions stay behavioral, anchored to a concrete pass through the thing
|
|
117
|
+
or material already on hand. Once enough is on the table, offering a
|
|
118
|
+
candidate boundary or vocabulary split to confirm or correct is fair
|
|
119
|
+
game.
|
|
120
|
+
|
|
121
|
+
Scale the session to the stakes. A solo tool for one person's own
|
|
122
|
+
workflow needs less pressure-testing than a system others will depend
|
|
123
|
+
on — read which one this is early and let it set the pace.
|
|
124
|
+
|
|
125
|
+
### Synthesis — turning answers into structure
|
|
126
|
+
|
|
127
|
+
1. **Cluster the nouns.** Recurring actors, records, or objects. A
|
|
128
|
+
cluster with its own lifecycle, referenced by other things, is a
|
|
129
|
+
candidate domain module. A thing mentioned only as a property of
|
|
130
|
+
another (e.g. "shipping address" always attached to an order) is an
|
|
131
|
+
attribute, not a module.
|
|
132
|
+
2. **Cluster the verbs.** Actions that mutate state and carry their own
|
|
133
|
+
invariants (e.g. "cancel an order, but only before payment") become
|
|
134
|
+
service methods later. Pure CRUD doesn't need naming.
|
|
135
|
+
3. **Draft the scope boundary.** In scope: what the described instances
|
|
136
|
+
actually required. Out of scope: anything flagged painful-but-not-now,
|
|
137
|
+
deferred, or explicitly unwanted — named explicitly. A boundary needs
|
|
138
|
+
at least one named exclusion; if none surfaced, ask one more question.
|
|
139
|
+
4. **Write the draft vocabulary as a table**: entity, one-sentence
|
|
140
|
+
definition, the attributes that came up, what it's owned by/belongs
|
|
141
|
+
to.
|
|
142
|
+
5. **Mark it provisional** — consumed by Bootstrap and revised there or
|
|
143
|
+
at the schema step as needed.
|
|
144
|
+
6. **File any screen/flow notes** under their module in
|
|
145
|
+
`docs/design/<module>-notes.md`, verbatim or lightly organized — raw
|
|
146
|
+
material for `ux-planner`, not a rationale, so don't polish or
|
|
147
|
+
structure beyond attributing it to the right module.
|
|
148
|
+
|
|
149
|
+
### Worked example
|
|
150
|
+
|
|
151
|
+
**Account given**: "I want an app like this" — a screenshot of a
|
|
152
|
+
competitor's habit tracker — "but for tracking medication instead. You
|
|
153
|
+
check off each dose, and it should nag you if you miss one." The
|
|
154
|
+
screenshot supplies the shape (items with a name, a check-off action, a
|
|
155
|
+
streak); one follow-up question supplies the rest — "walk me through
|
|
156
|
+
someone using this, start to finish" surfaces that doses have times, not
|
|
157
|
+
just days, and that "nag" means a notification, not an in-app-only
|
|
158
|
+
indicator.
|
|
159
|
+
|
|
160
|
+
**Scope boundary**
|
|
161
|
+
|
|
162
|
+
- In scope: add a medication with a schedule, mark a dose taken, missed-
|
|
163
|
+
dose notification.
|
|
164
|
+
- Out of scope: refill tracking, prescriber integration, multiple users
|
|
165
|
+
sharing one list.
|
|
166
|
+
|
|
167
|
+
**Domain vocabulary**
|
|
168
|
+
|
|
169
|
+
| Entity | Definition | Key attributes | Owned by |
|
|
170
|
+
|---|---|---|---|
|
|
171
|
+
| `medications` | a tracked medication | name, schedule | - |
|
|
172
|
+
| `doses` | one scheduled instance of a medication | due_at, taken_at | belongs to `medications` |
|
|
173
|
+
|
|
174
|
+
Verbs: add a medication, mark a dose taken, notify on a missed dose.
|
|
175
|
+
|
|
176
|
+
This is enough to start Bootstrap.
|
|
177
|
+
|
|
178
|
+
A remembered workflow produces the same structure: a lawyer describing
|
|
179
|
+
how they currently triage client intake by email surfaces `clients`,
|
|
180
|
+
`cases`, and `documents` via "walk me through the last time this came
|
|
181
|
+
up" in place of "walk me through someone using this."
|
|
182
|
+
|
|
183
|
+
### When to ask instead of guess
|
|
184
|
+
|
|
185
|
+
If no out-of-scope item has surfaced, or an entity's "owned by" doesn't
|
|
186
|
+
resolve to a plain FK, ask one more targeted question. A wrong guess here
|
|
187
|
+
becomes the schema, the most disruptive place to correct it — cheaper to
|
|
188
|
+
ask now than fix forward later.
|
|
189
|
+
|
|
190
|
+
## Core Responsibilities
|
|
191
|
+
|
|
192
|
+
- Turn a person's description of a problem into: scope boundary (what's
|
|
193
|
+
in, what's explicitly out) and domain vocabulary (the nouns and verbs).
|
|
194
|
+
- Identify domain modules from that vocabulary — one table = one module.
|
|
195
|
+
A noun needing its own identity and lifecycle is probably a module; an
|
|
196
|
+
attribute of another noun probably isn't.
|
|
197
|
+
- Identify cross-module references up front (which module's schema holds
|
|
198
|
+
the FK) so build order between modules is clear before anyone writes a
|
|
199
|
+
schema.
|
|
200
|
+
- Update `TODO.md` to reflect the checklist for what's in scope, mirroring
|
|
201
|
+
the phase/step structure from `hedgehog-loop`.
|
|
202
|
+
- Screens or flows described during Intake are captured under the
|
|
203
|
+
relevant module (`docs/design/<module>-notes.md`); Phase B, after the
|
|
204
|
+
backend exists for that module, is when they get acted on.
|
|
205
|
+
|
|
206
|
+
## Workflow
|
|
207
|
+
|
|
208
|
+
1. **Read the requirement** fully before doing anything.
|
|
209
|
+
2. **Check `TODO.md` and the commit log** for what's already built —
|
|
210
|
+
`feat(<module>): api` commits mark modules with a closed Phase A.
|
|
211
|
+
3. **Run Intake** if this is project start: extract scope boundary and
|
|
212
|
+
domain vocabulary per the procedure above. If input is insufficient,
|
|
213
|
+
ask — don't guess at scope.
|
|
214
|
+
4. **Decompose vocabulary into modules**: one table per module, FK-by-ID
|
|
215
|
+
only across module boundaries, junction tables stand alone.
|
|
216
|
+
5. **Order modules relative to each other** by FK dependency (a module
|
|
217
|
+
referenced by another's FK doesn't need to exist first — FK-by-ID
|
|
218
|
+
means no compile-time coupling — but flag it if joined reads are
|
|
219
|
+
expected from day one, since that shapes contract design).
|
|
220
|
+
6. **Write/update `TODO.md`**: a checklist mirroring the Phase A and
|
|
221
|
+
Phase B steps per module in scope. Checked or unchecked is its only
|
|
222
|
+
state. On a second Intake (new scope entering play), append new
|
|
223
|
+
module sections only — never touch an existing module's checked
|
|
224
|
+
boxes or reorder modules already in progress.
|
|
225
|
+
7. **File any screen/flow notes** captured during Intake under
|
|
226
|
+
`docs/design/<module>-notes.md`, per module.
|
|
227
|
+
8. **Return a summary**: scope boundary, module list, any open questions.
|
|
228
|
+
|
|
229
|
+
## Constraints
|
|
230
|
+
|
|
231
|
+
- Never write or modify application code. Read-only against the
|
|
232
|
+
codebase; you may write `TODO.md` and `docs/design/<module>-notes.md`.
|
|
233
|
+
- Never invent scope. Ambiguous scope means stop and ask.
|
|
234
|
+
- Don't replan a module's internal step sequence — fixed by
|
|
235
|
+
`hedgehog-loop`, not a per-project decision.
|
|
236
|
+
- Keep `TODO.md` thin. It's a checklist, not a design doc — rationale
|
|
237
|
+
lives in the commit log via the Correction Protocol.
|
|
238
|
+
|
|
239
|
+
## Weaknesses
|
|
240
|
+
|
|
241
|
+
- You don't execute — you scope and sequence modules. Implementation is
|
|
242
|
+
the Loop's job, one step at a time.
|
|
243
|
+
- You may over-decompose if the domain vocabulary is fuzzy. When in doubt
|
|
244
|
+
between "one module" and "two modules," prefer one table = one module
|
|
245
|
+
literally, and let the schema step prove it right or wrong.
|