@vibes.diy/prompts 14.0.23 → 14.0.25

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/llms/access.md CHANGED
@@ -6,6 +6,13 @@ You are seeing this doc because the app's prompt is **permission-shaped** — it
6
6
 
7
7
  `access.js` is a separate file alongside `App.jsx`; each **named export** gates the database of the same name (`export function chat(...)` gates `useFireproof("chat")`), and an `export default` acts as a catch-all. The `App.jsx` you write gates its write surfaces on `useVibe(dbName).can` — the same function this access.js enforces server-side.
8
8
 
9
+ Construct the document an action will save, check that same value with `can.create` or
10
+ `can.edit`, then write it to the same database. Include every field the access rule checks,
11
+ including the intended next status. For example, cancelling a reservation constructs
12
+ `const next = { ...reservation, status: "cancelled" }`, checks `can.edit(next).ok`, and
13
+ saves `next`. A creation control checks the complete creation draft. Render the verdict's
14
+ reason when denied, and keep loading and signed-out states distinct from denial.
15
+
9
16
  ## Reference
10
17
 
11
18
  ### Function signature
@@ -101,7 +108,7 @@ The platform predicate `ctx.isImgGenVersionAppend(doc, oldDoc)` accepts exactly
101
108
 
102
109
  ### `_id` strategy matters
103
110
 
104
- Documents that represent a unique named resource (channels, user profiles, config singletons, seed/starter content) should use a deterministic `_id` with a short prefix — `"ch:" + name`, `"profile:" + handle`, `"config"`, `"seed:" + key`. This enforces uniqueness: two users creating "general" get the same doc, not two — and a first-load seed that runs again (a fresh tab, another device) overwrites the same starter docs instead of duplicating them. Documents that represent events or content (messages, posts, survey responses) should let `_id` be auto-generated — each one is unique by nature. Use `doc._id` as the channel name for resource docs; use a `channelId` foreign key on content docs.
111
+ Documents that represent a unique named resource (channels, user profiles, config singletons, starter content) should use a deterministic `_id` with a short prefix — `"ch:" + name`, `"profile:" + handle`, `"config"`, `"starter:" + key`. This enforces uniqueness: two users creating "general" get the same doc, not two — and a first-load write that runs again (a fresh tab, another device) overwrites the same starter docs instead of duplicating them. Records a request says the app must already have are created this way, by the app's first render; see "Required starting records" in `fireproof.md`. Documents that represent events or content (messages, posts, survey responses) should let `_id` be auto-generated — each one is unique by nature. Use `doc._id` as the channel name for resource docs; use a `channelId` foreign key on content docs.
105
112
 
106
113
  ### Grants are additive
107
114
 
package/llms/backend.md CHANGED
@@ -40,6 +40,13 @@ the request, the app needs no `backend.js` — don't emit one.
40
40
  `backend.js` + **cache-into-db, never fetch-per-render**; when external data is
41
41
  only launch flavor, take a generation-time snapshot into `seed.json` instead.
42
42
 
43
+ Keep availability separate from a successful empty result. Inspect a successful source
44
+ response before choosing its parser, then validate the fields the app uses. An empty
45
+ validated response is data; an unavailable first read leaves the dependent decision pending.
46
+ For example, a dispatch planner waiting for its closure calendar records that unavailable
47
+ state and postpones calendar-dependent dispatch. A previously validated cache can support
48
+ the declared fallback, with its freshness and failure visible in saved status.
49
+
43
50
  ## Output format
44
51
 
45
52
  `backend.js` is a separate file, exactly like `access.js`: one prose line, the
@@ -268,7 +275,11 @@ const gh = await ctx.github.fetch("/repos/acme/site/issues", { method: "POST", b
268
275
  budget (10 per 10s, 60 per minute) is spent for the moment, which the next tick
269
276
  clears. Check for that shape and surface a useful error. Remedies: read it as a
270
277
  plain `GET`, use a CORS-open endpoint,
271
- request a curated-list addition, or ask about owner blessing. Limits: https
278
+ request a curated-list addition, or ask about owner blessing. The creator-facing
279
+ version of this gate — including what to do when a link is reported as taking
280
+ more power than the app has today — is at
281
+ https://good.vibes.diy/docs/your-app-has-a-backend, which is the page to send
282
+ someone to. Limits: https
272
283
  on port 443 only, 15s per request, 10MB responses, per-vibe rate caps
273
284
  (30/10s, 300/min). Make all outbound calls **before returning** the Response —
274
285
  a `ctx.fetch()` fired while a streamed body is still being pulled after the
@@ -548,6 +559,14 @@ const res = await fetch("/_api/rsvp", { method: "POST", body: JSON.stringify({ n
548
559
 
549
560
  ## onChange — react to committed writes
550
561
 
562
+ **When the request says a record is kept on the server, or that the server reacts
563
+ to something, emit this handler.** A person asking for activity to be recorded
564
+ centrally, for a tally the app maintains, or for something to happen whenever a
565
+ record lands is naming the server as the place it happens — that ask is the
566
+ trigger, and the shape is the activity-mirror example at the end of this file:
567
+ the client writes the document that triggers it, and `onChange` writes what the
568
+ server owes in response.
569
+
551
570
  Runs after any document write to the app's databases commits (user writes and
552
571
  backend writes alike). The event:
553
572
 
@@ -684,6 +703,17 @@ document it reads by id, plus a copy in module scope. A missing or failed state
684
703
  read means *"don't know — use the copy"*, never *"nothing has run yet"*; that
685
704
  second reading is what bills the owner four times for one noon.
686
705
 
706
+ **A status document that must be seen to change carries the tick's timestamp.**
707
+ A write whose content is byte-identical to what is already stored is absorbed:
708
+ the platform stores no new revision, and with no new revision there is no live
709
+ event, so an open page holding that document sees nothing and keeps showing what
710
+ it already had. A tick that rewrites a fixed-id status doc with the same fields
711
+ every time is therefore invisible to a watching reader. Include the moment the
712
+ tick ran — `checkedAt: new Date().toISOString()` — and the write is a real
713
+ change, so the page updates. This is the reader's side of the state-document
714
+ discipline above: state you only ever read back yourself is better off constant,
715
+ and state somebody is watching has to move.
716
+
687
717
  ### Firing on a real-world event
688
718
 
689
719
  **An averaged cycle is not a calendar.** When the moment comes from nature
package/llms/fireproof.md CHANGED
@@ -77,6 +77,35 @@ App.jsx
77
77
 
78
78
  The `useDocument` hook provides several methods: `merge(updates)` updates the document with new fields without saving (use this instead of keeping a `useState` for document data), `submit(e)` handles form submission by preventing default, saving, and resetting, `save()` saves the current document state, and `reset()` resets to initial state. When you call submit, the document is reset, so if you didn't provide an `_id` then you can use the form to create a stream of new documents as in the basic example above.
79
79
 
80
+ ## Required starting records
81
+
82
+ When a request names records the app must already have — the three projects in a
83
+ studio, a template's starter rows, the rooms in a planner — those records are
84
+ created by the app's own first render through the ordinary write path. That is
85
+ the mechanism, and it is the same one described below for starter content.
86
+ `seed.json` is a separate thing: an optional import a person runs by hand from
87
+ the Data tab, applied by no deploy path, so a record that exists only there does
88
+ not exist for anyone who opens the app.
89
+
90
+ Four rules make it hold:
91
+
92
+ - **Each required record gets a fixed `_id` you choose** (`"project:atlas"`), so
93
+ a second write of it lands on the same document instead of minting another.
94
+ - **Create them after `ready` and after `can.create` says yes**, so a write that
95
+ the enforced access rules do not admit yet is skipped quietly and retried on a
96
+ later run.
97
+ - **Restrict their creation to the owner in `access.js`** when the records
98
+ describe the app itself rather than a visitor's own work.
99
+ - **Write parents and membership grants before the records that depend on
100
+ them**, so a dependent document never lands against a container or a grant
101
+ that does not exist yet.
102
+
103
+ Fixed ids are also what makes two tabs safe. Two browsers opening the app for the
104
+ first time at the same moment both see an empty query and both write; with fixed
105
+ ids those are two writes of the same document, and last-writer-wins converges on
106
+ one copy. Reading the query first and then deciding whether to write is the shape
107
+ that races — the read is empty in both tabs before either write lands.
108
+
80
109
  ### Seeding starter data — give each seed a deterministic `_id`
81
110
 
82
111
  When an app ships with default content — starter slides, template rows, example cards — and writes it into the database on first load, give **each seed document a deterministic `_id`** (`"seed:intro"`, `"seed:" + key`). This makes the seeding write **idempotent**: if it ever runs again, it overwrites the same documents instead of creating fresh copies.
package/llms/image-gen.md CHANGED
@@ -25,7 +25,35 @@ export default function App() {
25
25
  }
26
26
  ```
27
27
 
28
- `<ImgGen>` writes the doc into a Fireproof database (default name `"ImgGen"`). The doc carries `_files.v1 = { uploadId, type, size }` and the platform mints `_files.v1.url` on read. To render a stored image doc manually, read the version with `doc.versions?.[doc.currentVersion ?? 0]`, get the file metadata with `doc._files?.[ver.id]`, and use `meta.url` for `<img src>`. The gallery pattern below shows this in a working component with proper hooks.
28
+ `<ImgGen>` stores generated versions in its component-owned media database, associated
29
+ with the host database name and `_id`. Read a saved image through
30
+ `useImgGen({ _id, database })` from `use-vibes`: its `document` composes current media
31
+ versions and legacy host versions. From that composed document, select
32
+ `document.versions?.[document.currentVersion ?? 0]`, then
33
+ `document._files?.[version.id]`. The returned file ref supplies both `.url` for display
34
+ and `.file()` for a transformation input, so a ref you have in hand is ready to pass
35
+ straight to `images`. Ordinary host records hold the app's own data; the image hook
36
+ supplies the associated generated output.
37
+
38
+ For example, refining a saved pottery illustration keeps its original ID and uses its
39
+ actual output as the input to a separate result ID:
40
+
41
+ ```jsx
42
+ import { ImgGen, useImgGen } from "use-vibes";
43
+
44
+ function GlazingPreview({ database }) {
45
+ const { document: original, pending, error } = useImgGen({ _id: "vessel-original", database });
46
+ const version = original?.versions?.[original.currentVersion ?? 0];
47
+ const source = version?.id ? original?._files?.[version.id] : undefined;
48
+ const sourceReady = source !== undefined;
49
+ return <section>
50
+ <ImgGen _id="vessel-original" database={database} showControls={false} />
51
+ {sourceReady ? <ImgGen _id="vessel-glazed" database={database}
52
+ prompt="Add a blue glaze while preserving this vessel's shape and composition"
53
+ images={[source]} /> : <p>{error ? error.message : pending ? "Loading saved source…" : "Source image unavailable"}</p>}
54
+ </section>;
55
+ }
56
+ ```
29
57
 
30
58
  This is the same `_files`-shape contract documented in `fireproof.md`'s "Working with Files" section — read it first if you have not seen the platform's file/URL story.
31
59
 
@@ -88,46 +116,19 @@ Do **not** hide first generation behind an "Illustrate" / "Generate image" butto
88
116
 
89
117
  ## Gallery Pattern
90
118
 
91
- Browse stored images with `useLiveQuery`. Building a gallery below the generator:
92
-
93
- App.jsx
94
-
95
- ```jsx
96
- <<<<<<< SEARCH
97
- export default function App() {
98
- const [file, setFile] = React.useState(null);
99
-
100
- return (
101
- =======
102
- export default function App() {
103
- const { useLiveQuery } = useFireproof("ImgGen");
104
- const { docs } = useLiveQuery("type", { key: "image", descending: true });
105
- const [file, setFile] = React.useState(null);
106
-
107
- return (
108
- >>>>>>> REPLACE
109
- ```
110
-
111
- App.jsx
119
+ Keep gallery entries as app-owned records with the saved image's host `_id`. Query those
120
+ records with `useLiveQuery`, then let each `<ImgGen>` read its associated media. This also
121
+ keeps the app's title, caption and other editable fields separate from image versions:
112
122
 
113
123
  ```jsx
114
- <<<<<<< SEARCH
115
- </div>
116
- );
124
+ function Gallery() {
125
+ const { database, useLiveQuery } = useFireproof("artwork");
126
+ const { docs } = useLiveQuery("type", { key: "artwork" });
127
+ return <div>{docs.map(doc => <figure key={doc._id}>
128
+ <ImgGen _id={doc._id} database={database} showControls={false} />
129
+ <figcaption>{doc.caption}</figcaption>
130
+ </figure>)}</div>;
117
131
  }
118
- =======
119
- <h3>Gallery</h3>
120
- <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 8 }}>
121
- {docs.map((doc) => {
122
- const ver = doc.versions?.[doc.currentVersion ?? 0];
123
- const meta = ver?.id ? doc._files?.[ver.id] : undefined;
124
- return <img key={doc._id} src={meta?.url} alt={doc.prompt} width={128} />;
125
- })}
126
- </div>
127
- </div>
128
- );
129
- }
130
- >>>>>>> REPLACE
131
132
  ```
132
133
 
133
134
  ## Caching and Versions
package/llms/three-js.md CHANGED
@@ -293,31 +293,80 @@ color.setHSL(0, 1, 0.5); // HSL values
293
293
  color.lerp(targetColor, 0.1); // interpolation
294
294
  ```
295
295
 
296
- ## Raycasting (Mouse Interaction)
296
+ ## Picking things in the scene (mouse interaction)
297
+
298
+ Selection has two halves: which objects the ray is allowed to hit, and which
299
+ object a hit stands for. Keep both explicit and clicking a planet selects the
300
+ planet rather than the glow around it.
301
+
302
+ **Raycast against a `selectables` array, never the whole scene graph.** The array
303
+ holds the things a person can pick, so lights, helpers, the skybox and every
304
+ decorative mesh are out of the answer before the ray is cast.
305
+
306
+ **Resolve a hit up `.parent` to the first ancestor carrying `userData.id`.** A hit
307
+ lands on whichever mesh the ray touched first, which is usually a child — a halo
308
+ shell, a label sprite, a bevel — so read the identity off the ancestor that owns
309
+ it instead of off the mesh that happened to be in front.
310
+
311
+ **Decorative children opt out of hit testing with `raycast = () => {}`.** A glow
312
+ shell exists to be seen and not to be picked, and an empty `raycast` removes it
313
+ from every intersection test at the source.
314
+
315
+ **Show selection by changing a material property on the resolved parent.** Adding
316
+ a new mesh to mark the selection adds another thing the ray can hit; changing
317
+ `emissive`, `opacity` or `color` on what is already there does not.
297
318
 
298
319
  ```javascript
299
320
  const raycaster = new THREE.Raycaster();
300
- const mouse = new THREE.Vector2();
321
+ const pointer = new THREE.Vector2();
301
322
 
302
- function onMouseClick(event) {
303
- // Normalize mouse coordinates (-1 to +1)
304
- mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
305
- mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
323
+ // The things a person can pick. Everything else in the scene stays out of it.
324
+ const selectables = [];
306
325
 
307
- // Cast ray from camera through mouse position
308
- raycaster.setFromCamera(mouse, camera);
326
+ function addPlanet(name) {
327
+ const planet = new THREE.Mesh(geometry, new THREE.MeshStandardMaterial({ color: 0x88aaff }));
328
+ planet.userData.id = name; // the identity a hit resolves to
309
329
 
310
- // Find intersections
311
- const intersects = raycaster.intersectObjects(scene.children, true);
330
+ const glow = new THREE.Mesh(glowGeometry, glowMaterial);
331
+ glow.raycast = () => {}; // decorative: never a hit
332
+ planet.add(glow);
312
333
 
313
- if (intersects.length > 0) {
314
- const object = intersects[0].object;
315
- const point = intersects[0].point;
316
- // Handle intersection
317
- }
334
+ scene.add(planet);
335
+ selectables.push(planet);
336
+ return planet;
337
+ }
338
+
339
+ // A hit lands on whichever mesh the ray touched — walk up to the owner of the id.
340
+ function selectableOf(object) {
341
+ let node = object;
342
+ while (node && node.userData?.id === undefined) node = node.parent;
343
+ return node ?? null;
344
+ }
345
+
346
+ function onPointerDown(event) {
347
+ const rect = renderer.domElement.getBoundingClientRect();
348
+ pointer.x = ((event.clientX - rect.left) / rect.width) * 2 - 1;
349
+ pointer.y = -((event.clientY - rect.top) / rect.height) * 2 + 1;
350
+ raycaster.setFromCamera(pointer, camera);
351
+
352
+ const hit = raycaster.intersectObjects(selectables, true)[0];
353
+ const picked = hit ? selectableOf(hit.object) : null;
354
+
355
+ for (const s of selectables) s.material.emissive?.setHex(0x000000);
356
+ if (picked) picked.material.emissive?.setHex(0x333311); // a property change, not a new mesh
357
+ setSelectedId(picked?.userData.id ?? null);
318
358
  }
319
359
  ```
320
360
 
361
+ ## Importing three
362
+
363
+ A bare package name at the top of the file resolves through the platform's esm.sh
364
+ map, and a full esm.sh URL loads too — either form also works with
365
+ `await import()`. The bare form follows whatever version the platform serves,
366
+ which moves as esm.sh publishes; a version-pinned URL such as
367
+ `https://esm.sh/three@0.160.0` is the lever for holding a scene on one release of
368
+ the library.
369
+
321
370
  ## Animation System
322
371
 
323
372
  ### Animation Mixer
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibes.diy/prompts",
3
- "version": "14.0.23",
3
+ "version": "14.0.25",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "exports": {
@@ -34,9 +34,9 @@
34
34
  "license": "Apache-2.0",
35
35
  "dependencies": {
36
36
  "@adviser/cement": "~0.5.34",
37
- "@vibes.diy/call-ai-v2": "14.0.23",
38
- "@vibes.diy/identity": "14.0.23",
39
- "@vibes.diy/use-vibes-types": "14.0.23",
37
+ "@vibes.diy/call-ai-v2": "14.0.25",
38
+ "@vibes.diy/identity": "14.0.25",
39
+ "@vibes.diy/use-vibes-types": "14.0.25",
40
40
  "arktype": "~2.2.3",
41
41
  "json-schema-faker": "~0.6.3"
42
42
  },
@@ -25,6 +25,7 @@ You are an AI assistant tasked with creating React components. You should create
25
25
  - For dynamic components, like autocomplete, don't use external libraries, implement your own
26
26
  - Avoid using external libraries unless they are essential for the component to function
27
27
  - Always use ES module imports at the top of the file (e.g. `import React, { useState } from "react"`). Never reference React or other libraries as globals.
28
+ - A bare package name at the top of the file resolves through the platform's esm.sh map, and a full esm.sh URL such as `https://esm.sh/three@0.160.0` loads too. Either form also works with `await import()` when a module should load on demand.
28
29
  - Your file MUST use `export default function App()` — the runtime loads it as an ES module and imports the default export.
29
30
  - Structure your component code in this order: (1) hooks and document shapes, (2) event handlers, (3) classNames object, (4) JSX return. ClassNames go right before JSX so they are close to where they are used.
30
31
  - Use Fireproof for data persistence
@@ -113,7 +114,9 @@ Rationale: the app's sharing rules are designed later from this object graph. A
113
114
 
114
115
  ### The prompt's content is launch content — emit `seed.json`
115
116
 
116
- When the user's prompt hands you **concrete example data** — an image of items, a pasted list, a screenshot of records, a table — that data is not just design inspiration, it is the app's **launch content**. Extract it into the app's document shape and emit it as a `seed.json` file so the app **opens showing that data** instead of an empty state that asks the user to type back in what they just showed you.
117
+ When the user's prompt hands you **concrete example data** — an image of items, a pasted list, a screenshot of records, a table — extract it into the app's document shape and emit it as a `seed.json` file. This file is an **optional launch-data import**: the owner applies it through the app editor's seed-data control. Saving, publishing and opening the app leave the file unapplied until that action succeeds.
118
+
119
+ **Required starting state belongs to the app's working initialization.** When the request requires named containers or participants to exist on first use, author an idempotent owner initialization path for those required records, separate from optional example content. Wait for identity, access readiness and the initial data read; reuse existing records, and create missing required records with stable identities through the ordinary database write path. Check each complete intended document with `can.create`, await its write, and show an actionable setup error if it fails. Establish the parent records and their membership grants before dependent records or controls need them. Keep existing user edits on later visits. For example, the requested pottery studio and its named apprentice should be represented by actual project and membership records before its work form depends on them. A name present only in `seed.json` describes an offered import, not an existing grant.
117
120
 
118
121
  Emit it with the filename-on-its-own-line convention: the filename `seed.json` on its own line, then a plain fenced ```json block (a bare `json` info-string on the fence — NOT `seed.json` on the fence line; the server keys off the preceding filename line). Emit it **last**, after `App.jsx` and any companion feature files.
119
122
 
@@ -25,6 +25,7 @@ You are an AI assistant tasked with creating React components. You should create
25
25
  - For dynamic components, like autocomplete, don't use external libraries, implement your own
26
26
  - Avoid using external libraries unless they are essential for the component to function
27
27
  - Always use ES module imports at the top of the file (e.g. `import React, { useState } from "react"`). Never reference React or other libraries as globals.
28
+ - A bare package name at the top of the file resolves through the platform's esm.sh map, and a full esm.sh URL such as `https://esm.sh/three@0.160.0` loads too. Either form also works with `await import()` when a module should load on demand.
28
29
  - Your file MUST use `export default function App()` — the runtime loads it as an ES module and imports the default export.
29
30
  - Structure your component code in this order: (1) hooks and document shapes, (2) event handlers, (3) classNames object, (4) JSX return. ClassNames go right before JSX so they are close to where they are used.
30
31
  - Use Fireproof for data persistence
@@ -115,7 +116,9 @@ Rationale: the app's sharing rules are designed later from this object graph. A
115
116
 
116
117
  ### The prompt's content is launch content — emit `seed.json`
117
118
 
118
- When the user's prompt hands you **concrete example data** — an image of items, a pasted list, a screenshot of records, a table — that data is not just design inspiration, it is the app's **launch content**. Extract it into the app's document shape and emit it as a `seed.json` file so the app **opens showing that data** instead of an empty state that asks the user to type back in what they just showed you.
119
+ When the user's prompt hands you **concrete example data** — an image of items, a pasted list, a screenshot of records, a table — extract it into the app's document shape and emit it as a `seed.json` file. This file is an **optional launch-data import**: the owner applies it through the app editor's seed-data control. Saving, publishing and opening the app leave the file unapplied until that action succeeds.
120
+
121
+ **Required starting state belongs to the app's working initialization.** When the request requires named containers or participants to exist on first use, author an idempotent owner initialization path for those required records, separate from optional example content. Wait for identity, access readiness and the initial data read; reuse existing records, and create missing required records with stable identities through the ordinary database write path. Check each complete intended document with `can.create`, await its write, and show an actionable setup error if it fails. Establish the parent records and their membership grants before dependent records or controls need them. Keep existing user edits on later visits. For example, the requested pottery studio and its named apprentice should be represented by actual project and membership records before its work form depends on them. A name present only in `seed.json` describes an offered import, not an existing grant.
119
122
 
120
123
  Emit it with the filename-on-its-own-line convention: the filename `seed.json` on its own line, then a plain fenced ```json block (a bare `json` info-string on the fence — NOT `seed.json` on the fence line; the server keys off the preceding filename line). Emit it **last**, after `App.jsx` and any companion feature files.
121
124
 
package/system-prompt.md CHANGED
@@ -25,6 +25,7 @@ You are an AI assistant tasked with creating React components. You should create
25
25
  - For dynamic components, like autocomplete, don't use external libraries, implement your own
26
26
  - Avoid using external libraries unless they are essential for the component to function
27
27
  - Always use ES module imports at the top of the file (e.g. `import React, { useState } from "react"`). Never reference React or other libraries as globals.
28
+ - A bare package name at the top of the file resolves through the platform's esm.sh map, and a full esm.sh URL such as `https://esm.sh/three@0.160.0` loads too. Either form also works with `await import()` when a module should load on demand.
28
29
  - Your file MUST use `export default function App()` — the runtime loads it as an ES module and imports the default export.
29
30
  - Structure your component code in this order: (1) hooks and document shapes, (2) event handlers, (3) classNames object, (4) JSX return. ClassNames go right before JSX so they are close to where they are used. Never define components (functions that return JSX) inside `App` or any other component — always define them at module scope and pass data as props. Components defined inside other components are recreated on every render, causing React to unmount and remount them, which breaks form focus and input state.
30
31
  - Use Fireproof for data persistence
@@ -675,7 +676,9 @@ Example streamed output for a team board app:
675
676
 
676
677
  ### The prompt's content is launch content — emit `seed.json`
677
678
 
678
- When the user's prompt hands you **concrete example data** — an image of items, a pasted list, a screenshot of records, a table — that data is not just design inspiration, it is the app's **launch content**. Extract it into the app's document shape and emit it as a `seed.json` file so the app **opens showing that data** instead of an empty state that asks the user to type back in what they just showed you.
679
+ When the user's prompt hands you **concrete example data** — an image of items, a pasted list, a screenshot of records, a table — extract it into the app's document shape and emit it as a `seed.json` file. This file is an **optional launch-data import**: the owner applies it through the app editor's seed-data control. Saving, publishing and opening the app leave the file unapplied until that action succeeds.
680
+
681
+ **Required starting state belongs to the app's working initialization.** When the request requires named containers or participants to exist on first use, author an idempotent owner initialization path for those required records, separate from optional example content. Wait for identity, access readiness and the initial data read; reuse existing records, and create missing required records with stable identities through the ordinary database write path. Check each complete intended document with `can.create`, await its write, and show an actionable setup error if it fails. Establish the parent records and their membership grants before dependent records or controls need them. Keep existing user edits on later visits. For example, the requested pottery studio and its named apprentice should be represented by actual project and membership records before its work form depends on them. A name present only in `seed.json` describes an offered import, not an existing grant.
679
682
 
680
683
  Emit it with the filename-on-its-own-line convention: the filename `seed.json` on its own line, then a plain fenced ```json block (a bare `json` info-string on the fence — NOT `seed.json` on the fence line; the server keys off the preceding filename line). Emit it **last**, after `App.jsx` and any companion feature files.
681
684
 
@@ -702,7 +705,7 @@ Rules for the items:
702
705
  - **Seed every app-written document type.** For every string-literal `type` that `App.jsx` writes, include at least one exemplar row of that type — even ephemeral types get one humble example. Types originated by the platform at runtime (for example ImgGen's `"image"`) cannot be seeded — omit them.
703
706
  - **JSON only — no images or binary.** For items whose identity includes an illustration, rely on `<ImgGen>` rendering it on first view (the default); do not put `_files` or image bytes in `seed.json`.
704
707
  - **Platform-originated types can't be seeded.** Types the platform writes at runtime (for example ImgGen's `"image"`) cannot appear in `seed.json`; give those their own `access.js` branch instead.
705
- - **If the app has an `access.js`, every `type` you emit here must have a branch in it** — but don't add an access function _just_ to satisfy this: an app with no per-document rules keeps the default open data model and seeds fine without one. When there **is** an `access.js`, seed docs are written as the **owner** at launch through it, so a `type` it doesn't return a **readable descriptor** for (a non-empty `channels`, or an `audience`) is denied (`unknown document type`) — the doc never seeds, and the same gap later surfaces as a hard error the moment the running app writes that type. Before finishing, if you emitted an `access.js`, confirm it returns a readable descriptor for every distinct `type` present in `seed.json`. (Deletes go through the same gate: a `db.del` writes a tombstone `{ _id, _deleted: true }` that carries **no** `type`, channel, or author — so branch on `doc._deleted`, then authorize and route it off **`oldDoc`** (the persisted document is the only trustworthy record of the doc's type and owner), returning the same descriptor the live doc got. A bare `_deleted` branch that ignores `oldDoc` either fails the app's own deletes or over-broadens them.)
708
+ - **If the app has an `access.js`, every `type` you emit here must have a branch in it** — but don't add an access function _just_ to satisfy this: an app with no per-document rules keeps the default open data model and seeds fine without one. When there **is** an `access.js`, seed docs are written through it as the **owner** when the owner explicitly applies the seed-data import, so a `type` it doesn't return a **readable descriptor** for (a non-empty `channels`, or an `audience`) is denied (`unknown document type`) — the doc never seeds, and the same gap later surfaces as a hard error the moment the running app writes that type. Before finishing, if you emitted an `access.js`, confirm it returns a readable descriptor for every distinct `type` present in `seed.json`. (Deletes go through the same gate: a `db.del` writes a tombstone `{ _id, _deleted: true }` that carries **no** `type`, channel, or author — so branch on `doc._deleted`, then authorize and route it off **`oldDoc`** (the persisted document is the only trustworthy record of the doc's type and owner), returning the same descriptor the live doc got. A bare `_deleted` branch that ignores `oldDoc` either fails the app's own deletes or over-broadens them.)
706
709
 
707
710
  ### Make it fun and alive on screen one
708
711