create-substrat 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -25,7 +25,7 @@ const SUBSTRAT = '^0.29.0';
25
25
  const ENGINES = '^0.3.27';
26
26
  const BOUNDARY_LINT = '^0.0.5';
27
27
 
28
- const DOCS = 'https://substrat.ahlstrand.es';
28
+ const DOCS = 'https://substrat.net';
29
29
 
30
30
  function fail(message) {
31
31
  process.stderr.write(`\n create-substrat: ${message}\n\n`);
@@ -167,9 +167,13 @@ pnpm typecheck
167
167
 
168
168
  function main() {
169
169
  const target = process.argv[2];
170
- if (!target || target === '-h' || target === '--help') {
170
+ if (target === '-h' || target === '--help') {
171
171
  usage();
172
- process.exit(target ? 0 : 1);
172
+ process.exit(0);
173
+ }
174
+ if (!target) {
175
+ usage();
176
+ fail('a target directory is required — e.g. `npm create substrat my-app` (or `.` for here).');
173
177
  }
174
178
 
175
179
  const dest = resolve(target);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "create-substrat",
3
- "version": "0.1.0",
4
- "description": "Scaffold a Substrat vertical — `npm create substrat`. Placeholder reserving the entry point; the initializer is not released yet.",
3
+ "version": "0.1.1",
4
+ "description": "Scaffold a Substrat vertical — `npm create substrat <dir>`.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
7
7
  "type": "git",
@@ -1,21 +1,33 @@
1
1
  # Playbook — build a vertical on Substrat
2
2
 
3
3
  The always-on rules live in [`AGENTS.md`](../AGENTS.md); read them first. This playbook is
4
- the **flow**: interview the user, tell them honestly how much of their app already exists,
5
- then build and run the part that doesn't. Read the whole thing before starting — the
6
- checkpoint in Step 6 is a hard stop.
4
+ the **flow**: interview the user, tell them honestly how much of their app already exists, and
5
+ **land a design document they can review and approve before a line of code is written** — then
6
+ reshape the reference into it. Read the whole thing before starting — both the design gate
7
+ (Step 4) and the checkpoints (Step 7) are hard stops.
8
+
9
+ **The target is a reviewed design, not running code.** Steps 1–2 learn the domain and map it
10
+ onto what already exists; Step 3 writes a checked-in `DESIGN.md` in the user's own vocabulary;
11
+ Step 4 is a **hard stop** where the user reads and approves it. Only then does Step 5 reshape
12
+ the reference into their domain. The design gate (Step 4) is *upstream* of the two code
13
+ checkpoints (Step 7) — a user with zero Substrat knowledge gets to say "yes, that's the app I
14
+ want" before implementation, not after.
7
15
 
8
16
  This project ships with a small **working reference vertical** — a bike-repair shop on
9
- `engine-workorder` + `engine-invoicing`, green out of the box (`npm test`). It is your
10
- worked example and your starting point: you **reshape** it into the user's domain rather
11
- than building from an empty directory. Work in the project root.
17
+ `engine-workorder` + `engine-invoicing`, green out of the box (`npm test`). It is your worked
18
+ example and your build starting point: once the design is approved you **reshape** it into the
19
+ user's domain rather than building from an empty directory. Work in the project root.
12
20
 
13
21
  ---
14
22
 
15
23
  ## Step 1 — Interview
16
24
 
17
- Ask, don't assume. **Three to five questions, conversational, one message.** You are
18
- learning the *shape* of the domain, not writing a spec.
25
+ Ask, don't assume. **Three to five questions, conversational, one message.** You are learning
26
+ the *shape* of the domain — the answers become the design document (Step 3), so listen for
27
+ vocabulary, the cast, and who must be denied what, not just features. **Adapt depth to the
28
+ user**: someone who already knows their domain cold needs fewer, sharper questions; someone
29
+ thinking out loud needs you to draw the shape out. One flow, not branching tracks — read the
30
+ room and dial the teaching up or down.
19
31
 
20
32
  1. **What are you building, and who uses it?** (the firm, the cast)
21
33
  2. **What's the thing that moves through the system?** A job, a repair, an inspection, an
@@ -34,8 +46,10 @@ detail, skip to Step 2 and confirm your reading of it instead of re-asking.
34
46
  ## Step 2 — The coverage map
35
47
 
36
48
  **This is the most valuable thing you do, and the easiest to get wrong by being
37
- flattering.** Tell the user what already exists and what they are actually signing up to
38
- build. Be specific and honest.
49
+ flattering.** Work out what already exists and what the user is actually signing up to build.
50
+ Be specific and honest. This analysis is the analytical core of the design document (Step 3) —
51
+ sections 3 ("what already exists vs. what's yours") and 4 ("who is denied what") are this map,
52
+ written down.
39
53
 
40
54
  **First, list the engines that actually exist. Do not trust any hard-coded list:**
41
55
 
@@ -128,25 +142,86 @@ stop. Do not scaffold.
128
142
 
129
143
  ---
130
144
 
131
- ## Step 3 — Decisions
145
+ ## Step 3 — Write the design document
132
146
 
133
- Short. Recommend a default and move.
147
+ **This is the deliverable.** Everything before now was learning; this is where it lands
148
+ somewhere the user can hold. Write a **checked-in `DESIGN.md`** in the project root, in the
149
+ user's own vocabulary — no Substrat internals, no decision refs, no cross-references to
150
+ platform docs. Someone who has never heard of Substrat must be able to read it and recognise
151
+ their own business.
134
152
 
135
- - **Auth.** Local dev uses an `x-principal` header — a dev seam, not a login. Offer to wire
136
- a real login now if they want it; otherwise default to the dev header and say it **must**
137
- be replaced before anything real. Real auth gates *exposing* the app, not *building* it.
138
- - **The cast.** Confirm the personas and their roles (e.g. `office-admin`, `technician`,
139
- `portal-customer`). Roles are the user's vocabulary — name them for the persona.
140
- - **Two tenants, always.** Seed a second tenant that exists to be attacked. This is how the
141
- isolation gets proven rather than claimed.
153
+ **Top line, verbatim** — the house marker for a pre-code design:
154
+
155
+ ```
156
+ Status: draft v0.1 · Last updated: <date> · For review before any code
157
+ ```
158
+
159
+ **The template** — the coverage map (Step 2) is sections 3–4, already done; the rest is the
160
+ interview written down. Two sections deliberately *preview* the code checkpoints of Step 7 in
161
+ plain language, so nothing there is a surprise:
162
+
163
+ 1. **What we're building & who uses it** — the firm and the cast, one paragraph.
164
+ 2. **The thing that moves through the system** — the core noun and its lifecycle
165
+ (the states it passes through, and which transitions must not be skippable).
166
+ 3. **What already exists vs. what's yours** — the coverage map as tiers: the kernel
167
+ (free), the engines you compose, the connectors, and the Tier-3 vocabulary/pricing/
168
+ screens that are yours. If it's a **bad fit, this is where the honest no lands** — say
169
+ so and stop; do not write the rest.
170
+ 4. **Who is denied what** — the load-bearing section, and a plain-language *preview of the
171
+ permission diff*: each role and what it can and cannot see. Make two answers impossible
172
+ to miss — **who can see the money, and who can see other customers' data.**
173
+ 5. **Money & sign-off** — invoice / quote / receipt / none; anything gated on a signature
174
+ or a check before a step can happen.
175
+ 6. **The cast, roles, and tenancy** — the named roles per persona (roles are the user's
176
+ vocabulary — name them for the persona: `workshop-admin`, not `role_1`). **Two tenants,
177
+ always** — the second exists to be attacked, which is how isolation gets proven rather
178
+ than claimed.
179
+ 7. **The data we'll store** — the vertical's own tables and fields in plain terms. This
180
+ *previews the migration diff*; migrations are **append-only forever after first ship**,
181
+ so this is the cheap moment to get the shape right.
182
+ 8. **The scenario the test will replay** — the happy path plus the denials that prove
183
+ isolation (wrong role denied, customer A sees theirs and customer B sees nothing, a
184
+ cross-tenant attacker gets nothing).
185
+ 9. **Open decisions** — each with a **recommended default**, so the user chooses rather
186
+ than specifies:
187
+ - **Auth.** Local dev uses an `x-principal` header — a dev seam, not a login. Default to
188
+ it and note it must be replaced before anything real; offer to wire a real login (the
189
+ bike-shop reference shows the Better Auth pattern) now if they want it. Real auth gates
190
+ *exposing* the app, not *building* it.
191
+ - **Deploy or stay local.** Local-first is a legitimate endpoint; default to it.
192
+ 10. **Out of scope / deferred** — what you are deliberately not building, so the review is
193
+ about a bounded thing.
194
+
195
+ End with a short **"Review questions for the human"** block (2–3 questions) — the things the
196
+ user must actively confirm, not rubber-stamp.
197
+
198
+ ---
199
+
200
+ ## Step 4 — The design gate. STOP HERE.
201
+
202
+ **Present the design document and wait for approval. Do not reshape the reference, do not
203
+ write code.**
204
+
205
+ This is a *human* gate, and it is the whole point: it happens **before** any code, upstream of
206
+ the two implementation checkpoints in Step 7. Walk the user through section 4 ("who is denied
207
+ what") in **their own vocabulary** until they can answer, without your help: *who can see the
208
+ money, and who can see other customers' data?*
209
+
210
+ **A gate assumes a competent reviewer.** If the user cannot evaluate the permission preview,
211
+ say so rather than letting them wave it through — a design nobody understands is theater, and
212
+ reproduces exactly the failure Substrat exists to prevent. Iterate the document until they
213
+ can, and only then take explicit approval.
214
+
215
+ Approval of the design is what unlocks Step 5. Until you have it, you are still in design.
142
216
 
143
217
  ---
144
218
 
145
- ## Step 4 — Reshape the reference
219
+ ## Step 5 — Reshape the reference
146
220
 
147
- The scaffold already contains a working vertical in `src/` + `test/` — the bike-repair shop.
148
- **Read it first** (it's your Callout: the real, green implementation of every pattern this
149
- step describes), then reshape it into the user's domain from the interview:
221
+ The design is approved. The scaffold already contains a working vertical in `src/` + `test/` —
222
+ the bike-repair shop. **Read it first** (it's your Callout: the real, green implementation of
223
+ every pattern this step describes), then reshape it into the user's domain from the approved
224
+ `DESIGN.md`:
150
225
 
151
226
  - **Rename the vocabulary** — `shop_customers`/`shop_bikes` → the user's nouns, the `shop/*`
152
227
  operation names, the roles, the price-list shape. If the user's core noun maps onto a work
@@ -159,7 +234,7 @@ step describes), then reshape it into the user's domain from the interview:
159
234
  - **Drop what the domain doesn't need, add its own tables** for anything the engines don't
160
235
  own. If the user's core noun *isn't* work-order-shaped, you may replace more of `src/` —
161
236
  but the seed/server/test scaffolding and the layout still hold.
162
- - **Re-run the gates as you go** (Step 5) — the reference is green, so any red is something
237
+ - **Re-run the gates as you go** (Step 6) — the reference is green, so any red is something
163
238
  you just changed.
164
239
 
165
240
  The dependencies are already wired in `package.json` (the `@substrat-run/*` packages, `hono`,
@@ -233,7 +308,7 @@ closed-door assertion with a control proving a neighbouring door is still open.
233
308
 
234
309
  ---
235
310
 
236
- ## Step 5 — Run it
311
+ ## Step 6 — Run it
237
312
 
238
313
  Build confidence in this order, and **show the user the output of each**:
239
314
 
@@ -255,9 +330,10 @@ and typed wrappers over the routes. Ask first — it roughly doubles the work.
255
330
 
256
331
  ---
257
332
 
258
- ## Step 6 — The two checkpoints. STOP HERE.
333
+ ## Step 7 — The two checkpoints. STOP HERE.
259
334
 
260
- **You may never self-approve these. Present them and wait.**
335
+ **You may never self-approve these. Present them and wait.** The design gate (Step 4) already
336
+ took the user's approval of *what* to build; these confirm that the code matches it.
261
337
 
262
338
  1. **Migration diff** — every new `SqlMigration`, verbatim. Append-only forever once
263
339
  shipped, so this is the last cheap moment to change your mind.
@@ -275,7 +351,7 @@ and who can see other tenants' data?* A permission diff nobody understands is th
275
351
 
276
352
  ---
277
353
 
278
- ## Step 7 — Deploy (optional)
354
+ ## Step 8 — Deploy (optional)
279
355
 
280
356
  Only if the user asks. Local-first is a legitimate stopping point.
281
357
 
@@ -301,7 +377,7 @@ cross-tenant hole with a UI.
301
377
 
302
378
  ---
303
379
 
304
- ## Step 8 — Leave the project competent
380
+ ## Step 9 — Leave the project competent
305
381
 
306
382
  The next session — in any tool — starts cold. The scaffold already ships `AGENTS.md`,
307
383
  `CLAUDE.md`, and the Cursor/opencode command stubs, so the rules and this flow survive. Your
@@ -5,8 +5,9 @@ Substrat kernel and its engines. This file is the always-on constitution — the
5
5
  that hold no matter what you touch. It is read by every AI tool (Claude Code, Cursor,
6
6
  opencode); do not duplicate it into tool-specific config.
7
7
 
8
- The full build flow — interview, coverage map, scaffold, run, checkpoints — is a
9
- **playbook**, not always-on context. Invoke it when you start or extend a vertical:
8
+ The full build flow — interview, coverage map, a reviewed design document you approve
9
+ before any code, then reshape, run, and the checkpoints — is a **playbook**, not always-on
10
+ context. Invoke it when you start or extend a vertical:
10
11
 
11
12
  - **Claude Code**: `/substrat`
12
13
  - **Cursor / opencode**: the `new-vertical` command, or read [`.substrat/playbook.md`](.substrat/playbook.md)