@vibes.diy/prompts 2.5.11 → 2.5.13

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/fireproof.js CHANGED
@@ -1,7 +1,7 @@
1
1
  export const fireproofConfig = {
2
2
  name: "fireproof",
3
3
  label: "useFireproof",
4
- description: "local-first database with encrypted live sync",
4
+ description: "cloud-backed document database with live sync",
5
5
  importModule: "use-fireproof",
6
6
  importName: "useFireproof",
7
7
  };
package/llms/fireproof.md CHANGED
@@ -1,27 +1,27 @@
1
1
  # Fireproof Database API Guide
2
2
 
3
- Fireproof is a lightweight embedded document database with encrypted live sync, designed to make browser apps easy. Use it in any JavaScript environment with a unified API that works both in React (with hooks) and as a standalone core API.
3
+ Fireproof is a document database with live sync, designed to make browser apps easy. On vibes.diy it runs against Firefly, a cloud-centralized backend: writes are sent to a server that validates them with your `access.js`, persists them, and streams them live to every viewer. Use it in any JavaScript environment with a unified API that works both in React (with hooks) and as a standalone core API.
4
4
 
5
5
  ## Key Features
6
6
 
7
7
  - **Apps run anywhere:** Bundle UI, data, and logic together.
8
- - **Real-Time & Offline-First:** Automatic persistence and live queries, runs in the browser - no loading or error states.
8
+ - **Real-Time, cloud-backed:** Writes are validated and persisted server-side, then streamed live to every viewer. `useLiveQuery` keeps the UI in sync as data arrives, so you render empty states rather than loading spinners but writes can fail (access denied, conflicts, network), so handle write rejections.
9
9
  - **Unified API:** TypeScript works with Deno, Bun, Node.js, and the browser.
10
10
  - **React Hooks:** Leverage `useLiveQuery` and `useDocument` for live collaboration. Note: these are NOT top-level exports — they are returned by the `useFireproof()` hook. Always destructure from `const { useLiveQuery, useDocument, database } = useFireproof("dbName")`.
11
11
 
12
12
  **File structure:** A vibe's source is one or more files. `/App.jsx` is the entry point (React component). `/access.js` is optional — include it when the app needs per-document write validation or channel-based read isolation. Both files are pushed together and the server discovers `/access.js` automatically.
13
13
 
14
- Fireproof enforces cryptographic causal consistency and ledger integrity using hash history, providing git-like versioning with lightweight blockchain-style verification. Data is stored and replicated as content-addressed encrypted blobs, making it safe and easy to sync via commodity object storage providers.
14
+ Fireproof enforces cryptographic causal consistency and ledger integrity using hash history, providing git-like versioning with lightweight blockchain-style verification. On vibes.diy, the Firefly server is the authority for every write: it stores each document in a per-document append-only sequence, runs your `access.js` to validate and route it, and then syncs it to viewers. Because writes go through the server, they are subject to access rules and can be rejected.
15
15
 
16
16
  ## Installation
17
17
 
18
- The `use-fireproof` package provides both the core API and React hooks. React hooks are the recommended way to use Fireproof in LLM code generation contexts. Fireproof databases store data across sessions and can sync in real-time. Each database is identified by a string name, and you can have multiple databases per application—often one per collaboration session, as they are the unit of sharing.
18
+ The `use-fireproof` package provides both the core API and React hooks. React hooks are the recommended way to use Fireproof in LLM code generation contexts. Fireproof databases persist data through the Firefly server and sync it live to every viewer. Each database is identified by a string name, and you can have multiple databases per application—often one per collaboration session, as they are the unit of sharing.
19
19
 
20
- Each document has an `_id`, which can be auto-generated or set explicitly. Auto-generation is recommended to ensure uniqueness and avoid conflicts. If multiple replicas update the same database, Fireproof merges them via CRDTs, deterministically choosing the winner for each `_id`.
20
+ Each document has an `_id`, which can be auto-generated or set explicitly. Auto-generation is recommended to ensure uniqueness and avoid conflicts. The server keeps a per-document sequence, so two clients writing the same `_id` at the same time can collide and one write will be rejected — see the note on continuous updates below. Prefer one document per event over many rapid writes to a single hot document.
21
21
 
22
22
  Use granular documents, e.g. one document per user action, so saving a form or clicking a button should typically create or update a single document, or just a few documents. Avoid patterns that require a single document to grow without bound.
23
23
 
24
- Fireproof is a local database, no loading states required, just empty data states.
24
+ `useLiveQuery` populates and refreshes the UI reactively as data arrives, so you usually render empty states rather than loading spinners. Writes, however, go to the server and can fail — wrap `put()`/`save()`/`del()` in `try/catch` (or attach a `.catch`) so a rejected write surfaces to the user instead of becoming an unhandled promise rejection.
25
25
 
26
26
  ### Basic Example
27
27
 
@@ -121,6 +121,44 @@ App.jsx
121
121
 
122
122
  Never call hooks inside handlers — `const { doc, save } = useDocument({ _id: id })` inside an onClick BREAKS the Rules of Hooks.
123
123
 
124
+ ### Continuous Controls — `merge()` on every event, `save()` once on commit
125
+
126
+ A continuous control (slider, drag, color picker, live-typed text bound to one doc) fires many events in quick succession. **Never call `database.put()` or `save()` on every `onChange`** — that floods the server with rapid concurrent writes to the same `_id`, which collide on the per-document sequence and get rejected (`Failed to put document …`). Instead, `merge()` locally on each event to keep the UI live, and `save()` once when the interaction commits (`onPointerUp`, `onBlur`, `onChange` for a range input's final value, or a debounced trailing call). Editing a single doc with a slider:
127
+
128
+ App.jsx
129
+
130
+ ```jsx
131
+ <<<<<<< SEARCH
132
+ const { useDocument, useLiveQuery, database } = useFireproof("myLedger");
133
+ =======
134
+ const { useDocument, useLiveQuery, database } = useFireproof("myLedger");
135
+
136
+ // One shared mix doc; slider updates the UI on every event, persists on commit
137
+ const { doc: mix, merge: mergeMix, save: saveMix } = useDocument({ _id: "mix:current", level: 50 });
138
+ >>>>>>> REPLACE
139
+ ```
140
+
141
+ App.jsx
142
+
143
+ ```jsx
144
+ <<<<<<< SEARCH
145
+ <h3>Recent Documents</h3>
146
+ =======
147
+ <input
148
+ type="range"
149
+ min="0"
150
+ max="100"
151
+ value={mix.level}
152
+ onChange={(e) => mergeMix({ level: Number(e.target.value) })} // live, no write
153
+ onPointerUp={() => saveMix().catch((err) => console.error("save failed", err))} // one write on commit
154
+ />
155
+
156
+ <h3>Recent Documents</h3>
157
+ >>>>>>> REPLACE
158
+ ```
159
+
160
+ If you genuinely need to persist mid-drag, debounce the `save()` so at most one write is in flight, and still `.catch()` the rejection. Better yet, prefer one document per event (see the Counter Pattern) over hammering a single hot document.
161
+
124
162
  ### Query Data
125
163
 
126
164
  Data is queried by sorted indexes defined by the application. Sort by strings, numbers, or booleans, as well as arrays for grouping. Use numbers when possible for sorting continuous data. You can use the `_id` field for temporal sorting so you don't have to write code to get simple recent document lists, as in the basic example above.
@@ -295,12 +333,23 @@ Other `acl` variants: `useFireproof("drafts", { acl: { read: ["editors"], write:
295
333
 
296
334
  ## Reading Resolved Grants (`access`)
297
335
 
298
- `useFireproof()` returns an `access` property — the viewer's resolved roles and channels for that database, computed server-side from the access function's `members` and `grant` declarations. Use `access.roles` (ReadonlySet), `access.channels` (ReadonlySet), `access.hasRole(name)`, and `access.hasChannel(name)`.
336
+ `useFireproof()` returns an `access` property — the viewer's resolved roles and channels for that database, computed server-side from the access function's `members` and `grant` declarations. Use `access.roles` (ReadonlySet), `access.channels` (ReadonlySet), `access.hasRole(name)`, and `access.hasChannel(name)`. Use these to reflect roles/channels in the UI; gate writes with `useVibe(dbName).can`.
299
337
 
300
338
  For databases without an access function export, `access` has empty roles and channels. No separate pending flag — grants arrive alongside the viewer identity, so `useViewer().isViewerPending` covers both.
301
339
 
302
340
  App.jsx
303
341
 
342
+ ```jsx
343
+ <<<<<<< SEARCH
344
+ import { useFireproof } from "use-fireproof";
345
+ =======
346
+ import { useFireproof } from "use-fireproof";
347
+ import { useVibe } from "use-vibes";
348
+ >>>>>>> REPLACE
349
+ ```
350
+
351
+ App.jsx
352
+
304
353
  ```jsx
305
354
  <<<<<<< SEARCH
306
355
  const { useLiveQuery, database } = useFireproof("announcements", {
@@ -308,6 +357,7 @@ App.jsx
308
357
  });
309
358
  =======
310
359
  const { database, useLiveQuery, access } = useFireproof("comments");
360
+ const { can, me } = useVibe("comments");
311
361
  >>>>>>> REPLACE
312
362
  ```
313
363
 
@@ -327,17 +377,18 @@ App.jsx
327
377
  ))}
328
378
  </ul>
329
379
  =======
330
- {access.hasRole("poster") && <CommentForm database={database} />}
331
- {access.hasRole("moderator") && <ModTools database={database} />}
380
+ {/* gate writes with useVibe().can, not access.* and gate the SAME db you write to */}
381
+ {can.create({ type: "comment", authorHandle: me?.userHandle }).ok && <CommentForm database={database} />}
382
+ {access.hasRole("moderator") && <ModToolsBadge />}
332
383
  {access.hasChannel("announcements") && <Announcements />}
333
384
  >>>>>>> REPLACE
334
385
  ```
335
386
 
336
387
  The AI agent writes the access function (so it knows the role names) and writes the UI (so it knows which roles gate which components). The `access` object is the bridge — it lets the UI reflect server-enforced permissions without duplicating the logic.
337
388
 
338
- The access function is the single source of truth for permissions. The UI reads its verdict from `access` gate with `access.hasChannel(name)` and `access.hasRole(name)`. Grants may reflect logic the UI can't see (other documents, role memberships, owner state), so `access` is always the right check.
389
+ The access function is the single source of truth for permissions. Gate write surfaces with `useVibe(dbName).can`, which runs this same access function. The `access` object (`access.hasRole(name)`, `access.hasChannel(name)`) reflects the viewer's resolved roles/channels for DISPLAY role badges, showing/hiding read-only sections not as the write gate.
339
390
 
340
- `access.hasChannel()` covers every grant path — public channels, restricted channels, role-expanded channels. The access function decides who gets access and how; the UI just asks `access.hasChannel(name)`.
391
+ `access.hasChannel()` covers every grant path — public channels, restricted channels, role-expanded channels. The access function decides who gets access and how; the UI uses `access.hasChannel(name)` to reflect membership for display.
341
392
 
342
393
  ### Complete example: Team announcements with channels
343
394
 
@@ -346,7 +397,7 @@ This example shows the full round-trip — access.js declares channels and grant
346
397
  - **Owner bootstrap:** `user.isOwner` gates management operations (channel setup, role grants, moderation). No bootstrap problem — the owner can always manage without needing a role granted first.
347
398
  - **Channel identity:** Channel docs use `_id: "ch:" + name` so names are unique. The `_id` is the channel identifier everywhere — in `channels`, `grant`, and `ctx.requireAccess()`.
348
399
  - **Channel grant:** A channel document grants the creator (`grant.users`), adds `grant.public` so all members can read, and `grant.roles` so posters can write.
349
- - **Write surfaces** are gated with `viewer` (signed in?), `access.hasChannel()` (channel access), or `isOwner` (management).
400
+ - **Write surfaces** are gated with `useVibe(dbName).can.create/edit/delete` it runs this same access function, so the UI verdict matches the server. Render `.reason` when denied. (See use-vibe docs.)
350
401
  - **`ViewerTag`** takes `userHandle` when rendering another user.
351
402
 
352
403
  access.js
@@ -382,20 +433,28 @@ export function announcements(doc, oldDoc, user, ctx) {
382
433
  }
383
434
  ```
384
435
 
385
- App.jsx — `isOwner` and `access.hasChannel()` gate the UI based on what the access function declared:
436
+ App.jsx — `useVibe().can` gates every write surface (posts AND owner-only management); `access.hasChannel()` reflects display-only membership; `isOwner` is a display hint only:
386
437
 
387
438
  ```jsx
388
439
  import React from "react";
389
440
  import { useFireproof } from "use-fireproof";
390
- import { useViewer } from "use-vibes";
441
+ import { useViewer, useVibe } from "use-vibes";
391
442
 
392
443
  export default function App() {
393
- const { viewer, isOwner, isViewerPending, ViewerTag } = useViewer();
444
+ const { viewer, isViewerPending, ViewerTag } = useViewer();
394
445
  const { database, useLiveQuery, access } = useFireproof("announcements");
446
+ const { can } = useVibe("announcements");
395
447
 
396
448
  const { docs: posts } = useLiveQuery("type", { key: "post" });
397
449
  const [draft, setDraft] = React.useState("");
398
450
  const [channel, setChannel] = React.useState("general");
451
+ // Build each candidate from the doc you'll actually write — the access function
452
+ // checks authorHandle/channel (and owner-only for roleGrant), so a bare partial
453
+ // would be denied and hide the control even from users who can act.
454
+ const canPost = can.create({ type: "post", channel, authorHandle: viewer?.userHandle });
455
+ // Owner-only management gates on can.* too — the access fn throws "owner only"
456
+ // for non-owners, so this verdict is false for everyone but the owner.
457
+ const canGrant = can.create({ type: "roleGrant", role: "poster", userHandle: "newUser" });
399
458
 
400
459
  if (isViewerPending) return null;
401
460
 
@@ -415,8 +474,8 @@ export default function App() {
415
474
  <div>
416
475
  <ViewerTag />
417
476
 
418
- {/* access.hasChannel covers public + restricted — the access function handles the distinction */}
419
- {viewer && access.hasChannel(channel) && (
477
+ {/* gate the write surface on useVibe().can it runs the access function */}
478
+ {canPost.ok ? (
420
479
  <form
421
480
  onSubmit={(e) => {
422
481
  e.preventDefault();
@@ -426,10 +485,12 @@ export default function App() {
426
485
  <textarea value={draft} onChange={(e) => setDraft(e.target.value)} />
427
486
  <button type="submit">Post</button>
428
487
  </form>
488
+ ) : (
489
+ viewer && <p style={{ color: "var(--muted, #888)" }}>{canPost.reason}</p>
429
490
  )}
430
491
 
431
- {/* owner-only management */}
432
- {isOwner && (
492
+ {/* owner-only management — gated on can.*, not isOwner */}
493
+ {canGrant.ok && (
433
494
  <button onClick={() => database.put({ type: "roleGrant", role: "poster", userHandle: "newUser" })}>
434
495
  Grant poster role
435
496
  </button>
@@ -439,7 +500,7 @@ export default function App() {
439
500
  <div key={p._id}>
440
501
  <ViewerTag userHandle={p.authorHandle} />
441
502
  <p>{p.body}</p>
442
- {isOwner && <button onClick={() => database.del(p._id)}>Delete</button>}
503
+ {can.delete(p).ok && <button onClick={() => database.del(p._id)}>Delete</button>}
443
504
  </div>
444
505
  ))}
445
506
  </div>
@@ -447,11 +508,11 @@ export default function App() {
447
508
  }
448
509
  ```
449
510
 
450
- The pattern: `viewer` checks sign-in, `access.hasChannel()` checks what the access function granted, `isOwner` gates management. The access function is the server-side authority — the UI just reflects its decisions. Real apps can graduate to `access.hasRole("moderator")` when they need to delegate management to non-owners.
511
+ The pattern: `useVibe().can` gates every write surface — including owner-only management, which the access function enforces via `if (!user.isOwner) throw` so `can.create({ type: "roleGrant", … })` is false for non-owners. `access.hasChannel()` reflects display-only membership, and `isOwner` is a display hint only, never the write gate. The access function is the server-side authority — `useVibe().can` is how the UI reflects its decisions for writes.
451
512
 
452
513
  ### Example: Channel board with restricted channels
453
514
 
454
- Some channels are open to all members, others are restricted. The access function decides — the UI just asks `access.hasChannel()`.
515
+ Some channels are open to all members, others are restricted. The access function decides — the UI uses `access.hasChannel()` to filter which channels to display, and `useVibe().can` to gate writes.
455
516
 
456
517
  access.js
457
518
 
@@ -480,7 +541,7 @@ export function chat(doc, oldDoc, user, ctx) {
480
541
  }
481
542
  ```
482
543
 
483
- App.jsx — the UI uses `access.hasChannel()` for everything. It has no idea which channels are restricted that's the access function's job:
544
+ App.jsx — `access.hasChannel()` filters which channels are visible (display); `useVibe().can` gates the write surface:
484
545
 
485
546
  ```jsx
486
547
  <<<<<<< SEARCH
@@ -488,6 +549,7 @@ App.jsx — the UI uses `access.hasChannel()` for everything. It has no idea whi
488
549
  =======
489
550
  const { database, useLiveQuery, access } = useFireproof("chat");
490
551
  const { docs: channels } = useLiveQuery("type", { key: "channel" });
552
+ const canPost = useVibe("chat").can.create({ type: "post" });
491
553
  >>>>>>> REPLACE
492
554
  ```
493
555
 
@@ -495,13 +557,13 @@ App.jsx — the UI uses `access.hasChannel()` for everything. It has no idea whi
495
557
  <<<<<<< SEARCH
496
558
  {viewer && access.hasChannel(channel) && (
497
559
  =======
498
- {/* filter to channels the viewer can see — use _id as channel identifier */}
560
+ {/* filter to channels the viewer can see — use _id as channel identifier (display only) */}
499
561
  {channels.filter((ch) => isOwner || access.hasChannel(ch._id)).map((ch) => (
500
562
  <button key={ch._id} onClick={() => setChannel(ch._id)}>{ch.name}</button>
501
563
  ))}
502
564
 
503
- {/* can post? just check channel access */}
504
- {viewer && (isOwner || access.hasChannel(channel)) && (
565
+ {/* gate the write surface on useVibe().can */}
566
+ {canPost.ok ? (
505
567
  >>>>>>> REPLACE
506
568
  ```
507
569
 
@@ -670,7 +732,7 @@ function crewChat(doc, oldDoc, user, ctx) {
670
732
  ctx.requireAccess(doc.channelId);
671
733
  return { channels: [doc.channelId] };
672
734
  }
673
- export { crewChat as "crew-chat" }
735
+ export { crewChat as "crew-chat" };
674
736
  ```
675
737
 
676
738
  ### Catch-all with `export default`
@@ -765,7 +827,7 @@ Other common `oldDoc` patterns: `if (oldDoc === null) { /* create-only logic */
765
827
 
766
828
  ## Architecture: Where's My Data?
767
829
 
768
- Data is stored in the browser, and is automatically synced with all invited users.
830
+ Data lives on the Firefly server, which is the source of truth. The browser keeps a local cache for instant reads, but every write is sent to the server, validated by your `access.js`, persisted, and then synced to all users who have read access. A write that fails validation, hits a conflict, or loses the network is rejected — handle those rejections rather than assuming the write always lands.
769
831
 
770
832
  ## Using Fireproof in JavaScript
771
833
 
@@ -785,12 +847,17 @@ import { fireproof } from "use-fireproof";
785
847
 
786
848
  const database = fireproof("myLedger");
787
849
 
788
- // The document API is async, but doesn't require loading states or error handling.
850
+ // The document API is async reads and writes both await the server.
851
+ // Writes can fail (access denied, conflict, network), so wrap them.
789
852
  async function main() {
790
- const ok = await database.put({ text: "Sample Data" });
791
- const doc = await database.get(ok.id);
792
- const latest = await database.query("_id", { limit: 10, descending: true });
793
- console.log("Latest documents:", latest.docs);
853
+ try {
854
+ const ok = await database.put({ text: "Sample Data" });
855
+ const doc = await database.get(ok.id);
856
+ const latest = await database.query("_id", { limit: 10, descending: true });
857
+ console.log("Latest documents:", latest.docs);
858
+ } catch (err) {
859
+ console.error("write failed (access denied, conflict, or network):", err);
860
+ }
794
861
  }
795
862
  >>>>>>> REPLACE
796
863
  ```
package/llms/index.d.ts CHANGED
@@ -6,5 +6,6 @@ export { d3Config } from "./d3.js";
6
6
  export { threeJsConfig } from "./three-js.js";
7
7
  export { webxrConfig } from "./webxr.js";
8
8
  export { useViewerConfig } from "./use-viewer.js";
9
+ export { useVibeConfig } from "./use-vibe.js";
9
10
  export type { LlmConfig } from "./types.js";
10
- export declare const allConfigs: readonly [import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig];
11
+ export declare const allConfigs: readonly [import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig, import("./types.js").LlmConfig];
package/llms/index.js CHANGED
@@ -6,6 +6,7 @@ import { d3Config } from "./d3.js";
6
6
  import { threeJsConfig } from "./three-js.js";
7
7
  import { webxrConfig } from "./webxr.js";
8
8
  import { useViewerConfig } from "./use-viewer.js";
9
+ import { useVibeConfig } from "./use-vibe.js";
9
10
  export { callaiConfig } from "./callai.js";
10
11
  export { fireproofConfig } from "./fireproof.js";
11
12
  export { imageGenConfig } from "./image-gen.js";
@@ -14,6 +15,7 @@ export { d3Config } from "./d3.js";
14
15
  export { threeJsConfig } from "./three-js.js";
15
16
  export { webxrConfig } from "./webxr.js";
16
17
  export { useViewerConfig } from "./use-viewer.js";
18
+ export { useVibeConfig } from "./use-vibe.js";
17
19
  export const allConfigs = [
18
20
  callaiConfig,
19
21
  imageGenConfig,
@@ -23,5 +25,6 @@ export const allConfigs = [
23
25
  fireproofConfig,
24
26
  webxrConfig,
25
27
  useViewerConfig,
28
+ useVibeConfig,
26
29
  ];
27
30
  //# sourceMappingURL=index.js.map
package/llms/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../jsr/llms/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAIlD,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,YAAY;IACZ,cAAc;IACd,cAAc;IACd,QAAQ;IACR,aAAa;IACb,eAAe;IACf,WAAW;IACX,eAAe;CACP,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../jsr/llms/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAI9C,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,YAAY;IACZ,cAAc;IACd,cAAc;IACd,QAAQ;IACR,aAAa;IACb,eAAe;IACf,WAAW;IACX,eAAe;IACf,aAAa;CACL,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { LlmConfig } from "./types.js";
2
+ export declare const useVibeConfig: LlmConfig;
@@ -0,0 +1,8 @@
1
+ export const useVibeConfig = {
2
+ name: "use-vibe",
3
+ label: "Vibe Write Gating",
4
+ description: "Gate write surfaces on the app's own access.js via useVibe().can",
5
+ importModule: "use-vibes",
6
+ importName: "useVibe",
7
+ };
8
+ //# sourceMappingURL=use-vibe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"use-vibe.js","sourceRoot":"","sources":["../../jsr/llms/use-vibe.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAc;IACtC,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,mBAAmB;IAC1B,WAAW,EAAE,kEAAkE;IAC/E,YAAY,EAAE,WAAW;IACzB,UAAU,EAAE,SAAS;CACtB,CAAC"}
@@ -0,0 +1,46 @@
1
+ # useVibe Hook — write gating
2
+
3
+ `useVibe(dbName)` is how you gate write surfaces. It runs the app's own `access.js` — the **same function the server enforces** — against a candidate document, so the UI's enabled/disabled state matches what the server will actually allow. You never re-implement permissions; you ask the access function.
4
+
5
+ ```jsx
6
+ const { me, can, ready } = useVibe("comments");
7
+ ```
8
+
9
+ Pass the Fireproof database name you are writing to. You get:
10
+
11
+ - `can.create(draft)` / `can.edit(doc)` / `can.delete(doc)` → `{ ok: boolean, reason?: string }`. Gate the write surface on `.ok`; when `!ok`, render `.reason` as the fallback copy (e.g. "authentication required", "not in channel: team").
12
+ - `ready` — `false` until identity and the access function have resolved. While `false`, show a neutral skeleton or disabled control; gating on it avoids a flash of the wrong state.
13
+ - `me` — `{ userHandle, displayName?, isOwner } | null` (null = anonymous). For display only.
14
+
15
+ **Build the candidate from the doc you'll actually write.** `can.create(draft)` runs the access function against `draft`, so `draft` must carry the fields the function checks — `authorHandle`, `channelId`, etc. A bare `can.create({ type: "post" })` gets denied (e.g. `"not author"`) and hides the form even from users who could post. Stamp the same fields you'll `put`: `can.create({ type: "post", channelId, authorHandle: me?.userHandle })`. And gate the **same database** you write to — `useVibe(dbName)` selects the access function and grants by `dbName`, so a gate on a different db won't reflect server enforcement.
16
+
17
+ ## The rule
18
+
19
+ Gate every write affordance on `can.*`. Render `reason` when denied. Never branch write permission on `viewer`, `isOwner`, `access.hasRole()`/`access.hasChannel()`, or document fields — those drift from what `access.js` actually does. Identity display (avatars, "signed in as") comes from `useViewer()`'s `ViewerTag`, not from `useVibe`.
20
+
21
+ ```jsx
22
+ import { useVibe, useViewer } from "use-vibes";
23
+
24
+ function PromptBar({ database }) {
25
+ const { can, ready } = useVibe("aestheticBoard");
26
+ const { ViewerTag } = useViewer();
27
+ if (!ready) return <div className="skeleton" />;
28
+ const v = can.create({ type: "tile" });
29
+ if (!v.ok) return <p className="muted">{v.reason}</p>; // e.g. "authentication required"
30
+ return (
31
+ <form onSubmit={/* … */}>
32
+ <ViewerTag />
33
+ <input placeholder="Add a tile…" />
34
+ <button type="submit">Post</button>
35
+ </form>
36
+ );
37
+ }
38
+ ```
39
+
40
+ ## Owner-only and role-gated surfaces
41
+
42
+ Don't gate management UI on `isOwner` directly. Encode the rule in `access.js` (e.g. `if (!user.isOwner) throw { forbidden: "owner only" }`) and gate the UI on `can.*` for that database — the verdict reflects the same rule. Per-row edit/delete affordances: `{can.edit(doc).ok && <EditButton doc={doc} />}`.
43
+
44
+ ## The server is still the authority
45
+
46
+ `can.*` is a fast, faithful preview, not the final word. A write can still be rejected server-side (the source may be stale, async, or unevaluable — in which case `can.*` optimistically returns `ok` and defers to the server). Keep the optimistic-write + rollback pattern: apply the change immediately, revert and surface an error if the `put` rejects.
@@ -1,8 +1,8 @@
1
1
  # useViewer Hook
2
2
 
3
- `useViewer()` is a **read-only window** into runtime-managed access control. The platform owns the rules — who's the owner, who has been granted read or write — and `useViewer()` lets your app see what the runtime decided. You cannot grant or revoke access from code; you can only reflect the runtime's verdict in your UI.
3
+ `useViewer()` is a **read-only window** into viewer identity. The platform owns the rules — who's the owner, who has been granted read or write — and `useViewer()` lets your app see who's signed in and render their identity. You cannot grant or revoke access from code; you can only reflect the runtime's verdict in your UI.
4
4
 
5
- The contract: **every write surface (form, submit button, edit input, delete button) must check `viewer`** (signed in?) and render a read-only fallback when null. For apps with access functions, gate further with `access.hasRole()` or `access.hasChannel()` from `useFireproof()`. The access function is the server-side authority the UI reflects its decisions.
5
+ Use `useViewer()` for identity and display only `ViewerTag`, avatars, and showing who's signed in. **Write surfaces are gated with `useVibe(dbName).can`** (see use-vibe docs), not with `viewer`/`isOwner`/`access.*`.
6
6
 
7
7
  ## Basic Usage
8
8
 
@@ -25,7 +25,7 @@ export default function App() {
25
25
  <header>
26
26
  <ViewerTag />
27
27
  </header>
28
- {!viewer && <p>Sign in to post.</p>}
28
+ {!viewer && <p>Sign in.</p>}
29
29
  {viewer && <p>Welcome back!</p>}
30
30
  </div>
31
31
  );
@@ -36,31 +36,60 @@ export default function App() {
36
36
 
37
37
  - `viewer` — `{ userHandle, displayName? }` or `null` for anonymous visitors. Avatars are not on the payload — render them with `<ViewerTag userHandle={...} />`, which resolves the avatar from the handle. Don't build avatar URLs yourself.
38
38
  - `isViewerPending` — `true` while the platform is still resolving the viewer identity (e.g. on first render before the parent shell has pushed the identity update). **Gate any auth-dependent UI on `!isViewerPending`** to avoid flashing the wrong state. Once it becomes `false`, `viewer` is either populated or definitively `null`.
39
- - `isOwner` — `true` when the viewer owns this vibe. Use it for management UI (settings, role grants, moderation).
40
- - `can(action, dbName?)` — `true`/`false` for `"read"`, `"write"`, `"delete"`. Checks app-level ACLs. In most apps `viewer` and `access.hasRole()`/`access.hasChannel()` are the right gates instead.
39
+ - `isOwner` — `true` when the viewer owns this vibe. A display hint only (e.g. an "admin" badge). Gate owner-only management WRITES (settings, role grants, moderation) on `useVibe(dbName).can` — the access function encodes the owner-only rule — never on `isOwner`.
40
+ - `can(action, dbName?)` — legacy ACL boolean for `"read"`/`"write"`/`"delete"`. Prefer `useVibe(dbName).can.create/edit/delete` for write gating; it runs the app's access function and returns a `reason`.
41
41
  - `ViewerTag` — ready-made user pill; see the ViewerTag section below.
42
42
 
43
43
  ## Gating UI
44
44
 
45
- Add a "commenting as" label and a gated form. The ViewerTag handles sign-in/identity display:
45
+ Add a "commenting as" label and a write-gated form. Use `useVibe("comments").can` to gate the form; `ViewerTag` handles sign-in/identity display:
46
46
 
47
47
  App.jsx
48
48
 
49
49
  ```jsx
50
50
  <<<<<<< SEARCH
51
- {!viewer && <p>Sign in to post.</p>}
51
+ import { useViewer } from "use-vibes";
52
+ =======
53
+ import { useViewer, useVibe } from "use-vibes";
54
+ >>>>>>> REPLACE
55
+ ```
56
+
57
+ App.jsx
58
+
59
+ ```jsx
60
+ <<<<<<< SEARCH
61
+ const { viewer, isViewerPending, ViewerTag } = useViewer();
62
+ =======
63
+ const { viewer, isViewerPending, ViewerTag } = useViewer();
64
+ const { can, ready, me } = useVibe("comments");
65
+ >>>>>>> REPLACE
66
+ ```
67
+
68
+ App.jsx
69
+
70
+ ```jsx
71
+ <<<<<<< SEARCH
72
+ {!viewer && <p>Sign in.</p>}
52
73
  {viewer && <p>Welcome back!</p>}
53
74
  =======
75
+ {/* identity display */}
54
76
  <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
55
77
  {viewer && <span style={{ fontSize: 13, color: "var(--muted, #888)" }}>commenting as</span>}
56
78
  <ViewerTag />
57
79
  </div>
58
80
 
59
- {!viewer && <p>Sign in to post.</p>}
60
- {viewer && <form>
61
- <input placeholder="Add a comment..." />
62
- <button type="submit">Post</button>
63
- </form>}
81
+ {/* write gate: useVibe().can, not viewer */}
82
+ {!ready ? null : (() => {
83
+ const v = can.create({ type: "comment", authorHandle: me?.userHandle });
84
+ return v.ok ? (
85
+ <form>
86
+ <input placeholder="Add a comment..." />
87
+ <button type="submit">Post</button>
88
+ </form>
89
+ ) : (
90
+ <p>{v.reason}</p>
91
+ );
92
+ })()}
64
93
  >>>>>>> REPLACE
65
94
  ```
66
95
 
@@ -74,50 +103,41 @@ App.jsx
74
103
 
75
104
  ```jsx
76
105
  <<<<<<< SEARCH
77
- export default function App() {
78
- const { viewer, isViewerPending, ViewerTag } = useViewer();
79
-
80
- if (isViewerPending) return null;
81
-
82
- return (
83
- <div>
84
- <header>
85
- <ViewerTag />
86
- </header>
87
- <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
88
- {viewer && <span style={{ fontSize: 13, color: "var(--muted, #888)" }}>commenting as</span>}
89
- <ViewerTag />
90
- </div>
106
+ import { useViewer, useVibe } from "use-vibes";
107
+ =======
108
+ import { useViewer, useVibe } from "use-vibes";
109
+ import { useFireproof } from "use-fireproof";
110
+ >>>>>>> REPLACE
111
+ ```
91
112
 
92
- {!viewer && <p>Sign in to post.</p>}
93
- {viewer && <form>
94
- <input placeholder="Add a comment..." />
95
- <button type="submit">Post</button>
96
- </form>}
97
- </div>
98
- );
99
- }
113
+ ```jsx
114
+ <<<<<<< SEARCH
115
+ const { viewer, isViewerPending, ViewerTag } = useViewer();
116
+ const { can, ready, me } = useVibe("comments");
100
117
  =======
101
- export default function App() {
102
118
  const { viewer, isViewerPending, ViewerTag } = useViewer();
119
+ const { can, ready, me } = useVibe("comments");
103
120
  const { useLiveQuery, database } = useFireproof("comments");
104
121
  const { docs: comments } = useLiveQuery("createdAt");
105
122
  const [body, setBody] = React.useState("");
123
+ >>>>>>> REPLACE
124
+ ```
106
125
 
107
- async function post() {
108
- if (!viewer || !body.trim()) return;
109
- await database.put({
110
- body: body.trim(),
111
- createdAt: Date.now(),
112
- authorHandle: viewer.userHandle,
113
- });
114
- setBody("");
115
- }
116
-
117
- if (isViewerPending) return null;
118
-
119
- return (
120
- <div>
126
+ ```jsx
127
+ <<<<<<< SEARCH
128
+ {/* write gate: useVibe().can, not viewer */}
129
+ {!ready ? null : (() => {
130
+ const v = can.create({ type: "comment", authorHandle: me?.userHandle });
131
+ return v.ok ? (
132
+ <form>
133
+ <input placeholder="Add a comment..." />
134
+ <button type="submit">Post</button>
135
+ </form>
136
+ ) : (
137
+ <p>{v.reason}</p>
138
+ );
139
+ })()}
140
+ =======
121
141
  <ul>
122
142
  {comments.map((c) => (
123
143
  <li key={c._id}>
@@ -127,20 +147,44 @@ export default function App() {
127
147
  ))}
128
148
  </ul>
129
149
 
150
+ {/* identity display */}
130
151
  <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
131
152
  {viewer && <span style={{ fontSize: 13, color: "var(--muted, #888)" }}>commenting as</span>}
132
153
  <ViewerTag />
133
154
  </div>
134
- {!viewer && <p>Sign in to post.</p>}
135
- {viewer && (
136
- <form onSubmit={(e) => { e.preventDefault(); post(); }}>
137
- <input value={body} onChange={(e) => setBody(e.target.value)} />
138
- <button type="submit">Post</button>
139
- </form>
140
- )}
141
- </div>
142
- );
143
- }
155
+
156
+ {/* write gate: useVibe().can, not viewer */}
157
+ {!ready ? null : (() => {
158
+ const v = can.create({ type: "comment", authorHandle: me?.userHandle });
159
+ return v.ok ? (
160
+ <form onSubmit={(e) => { e.preventDefault(); post(); }}>
161
+ <input value={body} onChange={(e) => setBody(e.target.value)} placeholder="Add a comment..." />
162
+ <button type="submit">Post</button>
163
+ </form>
164
+ ) : (
165
+ <p>{v.reason}</p>
166
+ );
167
+ })()}
168
+ >>>>>>> REPLACE
169
+ ```
170
+
171
+ Also add the `post` handler before `if (isViewerPending)`:
172
+
173
+ ```jsx
174
+ <<<<<<< SEARCH
175
+ if (isViewerPending) return null;
176
+ =======
177
+ async function post() {
178
+ if (!body.trim()) return;
179
+ await database.put({
180
+ body: body.trim(),
181
+ createdAt: Date.now(),
182
+ authorHandle: me?.userHandle,
183
+ });
184
+ setBody("");
185
+ }
186
+
187
+ if (isViewerPending) return null;
144
188
  >>>>>>> REPLACE
145
189
  ```
146
190
 
@@ -154,7 +198,7 @@ Key points:
154
198
 
155
199
  - Never use Clerk user IDs. Only `userHandle` crosses into vibe code.
156
200
  - Avatar URLs are stable indirection URLs — when a user changes their avatar, the URL stays the same and the bytes update. Treat them as opaque strings.
157
- - For per-database permissions (roles and channels), use `access` from `useFireproof()`: `access.hasRole("moderator")`, `access.hasChannel("engineering")`. The access function (access.js) is the server-side authority; `access` in the UI reflects its decisions.
201
+ - To reflect a viewer's roles/channels for display, use `access` from `useFireproof()`: `access.hasRole("moderator")`, `access.hasChannel("engineering")`. To gate a write surface, use `useVibe(dbName).can` (it runs the same access.js). The access function is the server-side authority either way.
158
202
 
159
203
  ## ViewerTag
160
204
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibes.diy/prompts",
3
- "version": "2.5.11",
3
+ "version": "2.5.13",
4
4
  "type": "module",
5
5
  "main": "./index.js",
6
6
  "description": "",
@@ -30,9 +30,9 @@
30
30
  "@fireproof/core-types-base": "~0.24.19",
31
31
  "@fireproof/core-types-protocols-cloud": "~0.24.19",
32
32
  "@fireproof/use-fireproof": "~0.24.19",
33
- "@vibes.diy/call-ai-v2": "^2.5.11",
34
- "@vibes.diy/identity": "^2.5.11",
35
- "@vibes.diy/use-vibes-types": "^2.5.11",
33
+ "@vibes.diy/call-ai-v2": "^2.5.13",
34
+ "@vibes.diy/identity": "^2.5.13",
35
+ "@vibes.diy/use-vibes-types": "^2.5.13",
36
36
  "arktype": "~2.2.1",
37
37
  "json-schema-faker": "~0.6.2"
38
38
  },
package/prompts.js CHANGED
@@ -24,9 +24,9 @@ export async function resolveEffectiveModel(settingsDoc, vibeDoc) {
24
24
  return defaultCodingModel();
25
25
  }
26
26
  export async function getDefaultSkills() {
27
- return ["fireproof", "callai", "image-gen", "web-audio"];
27
+ return ["fireproof", "callai", "image-gen", "web-audio", "use-vibe"];
28
28
  }
29
- const PRE_ALLOC_PLATFORM_PARAGRAPH = "Platform stack: a vibe is a single-file React app that runs in the user's browser. Fireproof is a peer-replicated document database — `useFireproof(name)` returns a database handle and `useLiveQuery(field)` keeps every viewer's UI in lockstep with the underlying docs in real time, no separate sync layer. callAI is a typed call to a hosted LLM that returns JSON matching a schema the app declares; the JSON is saved as a Fireproof doc so it persists and shows up live for every viewer. useViewer is a read-only window into runtime-managed access control: the platform owns who can read and who can write, and `useViewer().can('write')` lets the app reflect that verdict in its UI without ever setting it. ImgGen renders a generated illustration tile when imagery is naturally part of the experience, not as decoration.";
29
+ const PRE_ALLOC_PLATFORM_PARAGRAPH = "Platform stack: a vibe is a single-file React app that runs in the user's browser. Fireproof is a cloud-backed document database — `useFireproof(name)` returns a database handle and `useLiveQuery(field)` keeps every viewer's UI in lockstep with the underlying docs in real time; writes are validated and persisted server-side and can fail, so handle write rejections. callAI is a typed call to a hosted LLM that returns JSON matching a schema the app declares; the JSON is saved as a Fireproof doc so it persists and shows up live for every viewer. useViewer surfaces the signed-in viewer's identity for display (avatars, who's posting). Write surfaces are gated with `useVibe(dbName).can`, which runs the app's own access function and tells the UI whether a create/edit/delete is allowed — the app reflects that verdict, it never sets it. ImgGen renders a generated illustration tile when imagery is naturally part of the experience, not as decoration.";
30
30
  export async function makePreAllocUserMessage(userPrompt) {
31
31
  const catalog = await getLlmCatalog();
32
32
  const catalogText = catalog.map((l) => `- ${l.name}: ${l.description}`).join("\n");
@@ -82,7 +82,7 @@ export const preAllocSchema = {
82
82
  "REQUIRED. A 3-sentence preamble grounding THIS app in our platform — dense narrative, no padding, no flourishes.",
83
83
  "Sentence 1: what users see and do in this app, and that Fireproof's live sync shares the activity with every viewer in real time.",
84
84
  "Sentence 2: name the callAI role that fits this app's central activity. Common roles to pick from: (a) AI-suggest / autofill for form fields — the user taps a button next to an input and callAI returns an example value drawn from the app's domain, ready to accept or edit; (b) critique or extend user-authored content — callAI scores, rewrites, summarizes, or proposes the next thing (next line of a poem, follow-up task, related recipe); (c) categorize, tag, or score content on save — sentiment, topical tags, priority. Pick ONE role that genuinely fits this app. Name the user action that triggers the call and what kind of structured response comes back.",
85
- "Sentence 3: name the write actions in this app, and that non-owners see a read-only view because the runtime's access control hides the write surfaces — useViewer reflects that verdict, the app never sets it. If generated imagery is naturally part of the app's domain, add a brief clause naming what an ImgGen tile depicts.",
85
+ "Sentence 3: name the write actions in this app, and that non-owners see a read-only view because the runtime's access control hides the write surfaces — useVibe().can reflects that verdict (and useViewer shows identity), the app never sets it. If generated imagery is naturally part of the app's domain, add a brief clause naming what an ImgGen tile depicts.",
86
86
  'Do NOT include code: no function names like `useLiveQuery` or `database.put`, no doc-shape objects in braces, no `can("write")` syntax, no backtick-quoted field names. Plain narrative, not a code spec.',
87
87
  "Do NOT invent imagery features when the app's domain wouldn't naturally include them.",
88
88
  ].join(" "),
@@ -138,6 +138,11 @@ export async function makeBaseSystemPrompt(model, sessionDoc) {
138
138
  if (selectedNames.length === 0) {
139
139
  selectedNames = [...(await getDefaultSkills())];
140
140
  }
141
+ for (const required of ["use-vibe", "use-viewer"]) {
142
+ if (llmsCatalogNames.has(required) && !selectedNames.includes(required)) {
143
+ selectedNames.push(required);
144
+ }
145
+ }
141
146
  const includeDemoData = sessionDoc?.demoData === true;
142
147
  const chosenLlms = llmsCatalog.filter((l) => selectedNames.includes(l.name));
143
148
  const concatenatedLlmsTxts = [];
package/prompts.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../jsr/prompts.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"prompts.js","sourceRoot":"","sources":["../jsr/prompts.ts"],"names":[],"mappings":"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"}
@@ -17,7 +17,7 @@ You are an AI assistant tasked with creating React components. You should create
17
17
  - Always show loading states during any async operation (callAI, fetch, database queries): use a useState boolean (e.g. `isLoading`), set it true before the call and false in .finally(). While loading: (1) disable the trigger button with `disabled={isLoading}`, (2) replace the button text with a spinning SVG icon using CSS animation `animate-spin` (a simple circle with a gap), (3) optionally show a short status text like 'Loading...' near the button. Never leave the user clicking a button with no visual feedback. Pattern: `setIsLoading(true); try { await callAI(...); } finally { setIsLoading(false); }`
18
18
  - Give instant feedback for Fireproof writes too, not just for callAI/fetch. A `database.put` (toggling a checkbox, marking done, inline edits, reorder, like/vote counters) resolves fast but isn't instant, so the UI must react the moment the user acts. Apply the change optimistically — flip the visible value immediately and let `useLiveQuery` reconcile when the write lands. While the write is in flight, show ONE subtle per-item saving cue on that row: disable it, dim it slightly, and add a small inline `Saving…` spinner or text. Do NOT change the value's own glyph to signal saving — no indeterminate/half-checked checkbox, since that reads as a real tri-state value rather than a transient network state. Track pending state in a keyed collection (e.g. a `Set` of saving ids in `useState` — add the id before the write, delete it in `.finally()`), not a single `savingId` or one global flag, so concurrent writes to different rows each keep their own cue and unrelated rows stay interactive. On failure, revert the optimistic value and surface a brief error (inline or toast) with a way to retry — never let the optimistic UI silently lie when a `put` rejects. Never let a checkbox tap, toggle, or saved inline edit sit with no visible response.
19
19
  - For file uploads use drag and drop and store using the `doc._files` API; for AI image generation use `<ImgGen prompt="..." />`
20
- - Access control is decided by the runtime, not by your code. `useViewer()` from `"use-vibes"` gives you `const { viewer, isOwner, isViewerPending, ViewerTag } = useViewer();`. `viewer` is `{ userHandle, displayName? } | null` (null for anonymous). **Gate write surfaces on `viewer`** show forms only when signed in, render a read-only fallback otherwise. For apps with an access function (`access.js`), gate further with `access.hasRole()` or `access.hasChannel()` from `useFireproof()` never re-derive permissions from document fields client-side. Use `isOwner` for management UI (settings, moderation). Render avatars with `<ViewerTag userHandle={authorHandle} />`. This applies to every app — never skip useViewer because the app "sounds single-user"; the runtime decides sharing, not the prompt. See use-viewer docs.
20
+ - Access control is decided by the runtime, not your code. Gate every write surface forms, submit/edit/delete buttons, any mutating action — on `useVibe(dbName).can`. `const { me, can, ready } = useVibe("comments")` from `"use-vibes"`, passing the Fireproof database name you write to. Show the editor when `can.create(draft).ok` (or `can.edit(doc)` / `can.delete(doc)`); while `ready` is false show a neutral skeleton/disabled state; when denied, render `can.create(draft).reason` as the fallback copy (the sign-in or join prompt). `can.*` runs the app's own `access.js` the same function the server enforces — so NEVER derive write permission from `viewer`, `isOwner`, `access.hasRole()`/`access.hasChannel()`, or document fields. `useViewer()` is identity/display only: `const { ViewerTag } = useViewer()` for avatars and showing who's signed in. Owner-only management UI is gated on `can.*` too (the access.js encodes the owner rule). This applies to every app — the runtime decides sharing, not the prompt. Writes can still be rejected server-side even when `can.*` allows, so keep the optimistic-write + rollback handling. See use-vibe docs.
21
21
  - Don't try to generate png or base64 data, use placeholder image APIs instead, like https://picsum.photos/400 where 400 is the square size
22
22
  - Never use emojis in the UI. Use inline SVG icons instead — simple, single-color, stroke-based SVGs (24x24 viewBox, strokeWidth 2, strokeLinecap round, strokeLinejoin round). Build icons directly in JSX, do not import icon libraries.
23
23
  - List data items on the main page of your app so users don't have to hunt for them
@@ -41,35 +41,36 @@ Every code block must be preceded by the file name on its own line — `App.jsx`
41
41
  - The `<header>` with the real brand title and any always-visible chrome.
42
42
  - One stub function component per feature with a heading — these are the anchors for later edits.
43
43
  - A default-exported `App` function composing them inside `<main id="app">` with `<header id="app-header">`.
44
- - `useViewer` destructured at the top of `App()` — `const { viewer, isOwner, isViewerPending, ViewerTag } = useViewer();`
44
+ - When a write surface needs gating, destructure `useVibe` for the database it writes to — `const { can, ready } = useVibe("<dbName>");` — and `useViewer` for identity — `const { ViewerTag } = useViewer();`
45
45
  - **Be creative with the layout, but respect mobile idioms.** Thumb-reachable primary actions, generous tap targets (`min-h-[44px]`), scrollable lists, no hover-only interactions.
46
- - NO hooks beyond `useViewer`, NO data wiring — those land in the feature edits.
46
+ - NO hooks beyond `useVibe`/`useViewer`, NO data wiring — those land in the feature edits.
47
47
 
48
48
  Target ~40–60 lines. The shell should look like a real app with empty sections, not a blank page.
49
49
 
50
- **Step 2 — Access function (if needed).** Emit `access.js` as a complete fenced block with comments explaining the permission model: what each doc type does, who can write it, what channels/roles it creates. This commits to the permission design before any feature edits, so every subsequent edit can destructure `access` and gate with `access.hasRole()` / `access.hasChannel()` from the start.
50
+ **Step 2 — Access function (if needed).** Emit `access.js` as a complete fenced block with comments explaining the permission model: what each doc type does, who can write it, what channels/roles it creates. This commits to the permission design before any feature edits, so every subsequent edit can gate its write surfaces on `useVibe(dbName).can` the same rules the access function enforces.
51
51
 
52
52
  **Step 3 — Feature edits.** Wire each feature with SEARCH/REPLACE edits. Each edit gets exactly one prose line (≤25 words) before it. Wire hooks, data, handlers, and `useFireproof` with `access` in these edits. The first feature edit should also add the `useFireproof` destructure to `App()`. Keep edits focused — one feature per edit, fully working after it lands.
53
53
 
54
54
  > Access function — owner manages channels, authenticated users post to channels they have access to.
55
55
  >
56
56
  > access.js
57
+ >
57
58
  > ```js
58
59
  > // Each channel doc grants public read access to that channel.
59
60
  > // Posts require channel access — the server enforces this via ctx.requireAccess.
60
61
  > // Only the owner can create channels.
61
62
  > export function chat(doc, oldDoc, user, ctx) {
62
- > if (!user) throw { forbidden: "sign in" }
63
+ > if (!user) throw { forbidden: "sign in" };
63
64
  > if (doc.type === "channel") {
64
- > if (!user.isOwner) throw { forbidden: "owner only" }
65
- > return { channels: [doc.name], grant: { public: [doc.name] } }
65
+ > if (!user.isOwner) throw { forbidden: "owner only" };
66
+ > return { channels: [doc.name], grant: { public: [doc.name] } };
66
67
  > }
67
68
  > if (doc.type === "message") {
68
- > if (doc.authorHandle !== user.userHandle) throw { forbidden: "not author" }
69
- > ctx.requireAccess(doc.channelId)
70
- > return { channels: [doc.channelId] }
69
+ > if (doc.authorHandle !== user.userHandle) throw { forbidden: "not author" };
70
+ > ctx.requireAccess(doc.channelId);
71
+ > return { channels: [doc.channelId] };
71
72
  > }
72
- > throw { forbidden: "unknown document type" }
73
+ > throw { forbidden: "unknown document type" };
73
74
  > }
74
75
  > ```
75
76
 
package/system-prompt.md CHANGED
@@ -17,7 +17,7 @@ You are an AI assistant tasked with creating React components. You should create
17
17
  - Always show loading states during any async operation (callAI, fetch, database queries): use a useState boolean (e.g. `isLoading`), set it true before the call and false in .finally(). While loading: (1) disable the trigger button with `disabled={isLoading}`, (2) replace the button text with a spinning SVG icon using CSS animation `animate-spin` (a simple circle with a gap), (3) optionally show a short status text like 'Loading...' near the button. Never leave the user clicking a button with no visual feedback. Pattern: `setIsLoading(true); try { await callAI(...); } finally { setIsLoading(false); }`
18
18
  - Give instant feedback for Fireproof writes too, not just for callAI/fetch. A `database.put` (toggling a checkbox, marking done, inline edits, reorder, like/vote counters) resolves fast but isn't instant, so the UI must react the moment the user acts. Apply the change optimistically — flip the visible value immediately and let `useLiveQuery` reconcile when the write lands. While the write is in flight, show ONE subtle per-item saving cue on that row: disable it, dim it slightly, and add a small inline `Saving…` spinner or text. Do NOT change the value's own glyph to signal saving — no indeterminate/half-checked checkbox, since that reads as a real tri-state value rather than a transient network state. Track pending state in a keyed collection (e.g. a `Set` of saving ids in `useState` — add the id before the write, delete it in `.finally()`), not a single `savingId` or one global flag, so concurrent writes to different rows each keep their own cue and unrelated rows stay interactive. On failure, revert the optimistic value and surface a brief error (inline or toast) with a way to retry — never let the optimistic UI silently lie when a `put` rejects. Never let a checkbox tap, toggle, or saved inline edit sit with no visible response.
19
19
  - For file uploads use drag and drop and store using the `doc._files` API; for AI image generation use `<ImgGen prompt="..." />`
20
- - Access control is decided by the runtime, not by your code. `useViewer()` from `"use-vibes"` gives you `const { viewer, isOwner, isViewerPending, ViewerTag } = useViewer();`. `viewer` is `{ userHandle, displayName? } | null` (null for anonymous). **Gate write surfaces on `viewer`** show forms only when signed in, render a read-only fallback otherwise. For apps with an access function (`access.js`), gate further with `access.hasRole()` or `access.hasChannel()` from `useFireproof()` never re-derive permissions from document fields client-side. Use `isOwner` for management UI (settings, moderation). Render avatars with `<ViewerTag userHandle={authorHandle} />`. This applies to every app — never skip useViewer because the app "sounds single-user"; the runtime decides sharing, not the prompt. See use-viewer docs.
20
+ - Access control is decided by the runtime, not your code. Gate every write surface forms, submit/edit/delete buttons, any mutating action — on `useVibe(dbName).can`. `const { me, can, ready } = useVibe("comments")` from `"use-vibes"`, passing the Fireproof database name you write to. Show the editor when `can.create(draft).ok` (or `can.edit(doc)` / `can.delete(doc)`); while `ready` is false show a neutral skeleton/disabled state; when denied, render `can.create(draft).reason` as the fallback copy (the sign-in or join prompt). `can.*` runs the app's own `access.js` the same function the server enforces — so NEVER derive write permission from `viewer`, `isOwner`, `access.hasRole()`/`access.hasChannel()`, or document fields. `useViewer()` is identity/display only: `const { ViewerTag } = useViewer()` for avatars and showing who's signed in. Owner-only management UI is gated on `can.*` too (the access.js encodes the owner rule). This applies to every app — the runtime decides sharing, not the prompt. Writes can still be rejected server-side even when `can.*` allows, so keep the optimistic-write + rollback handling. See use-vibe docs.
21
21
  - Don't try to generate png or base64 data, use placeholder image APIs instead, like https://picsum.photos/400 where 400 is the square size
22
22
  - Never use emojis in the UI. Use inline SVG icons instead — simple, single-color, stroke-based SVGs (24x24 viewBox, strokeWidth 2, strokeLinecap round, strokeLinejoin round). Build icons directly in JSX, do not import icon libraries.
23
23
  - Consider and potentially reuse/extend code from previous responses if relevant
@@ -49,11 +49,11 @@ Every code block must be preceded by the file name on its own line — `App.jsx`
49
49
  - one stub function component per feature with a heading — these are the anchors for later edits
50
50
  - a default-exported `App` function composing them inside `<main id="app">` with `<header id="app-header">`
51
51
  - name the section ids and components after the features (e.g. `id="board"`, `id="compose"`), not literal `feature-one`
52
- - `useViewer` destructured at the top of `App()` when identity is needed — `const { viewer, isOwner, isViewerPending, ViewerTag } = useViewer();`
53
- - NO hooks beyond `useViewer`, NO data wiring — those land in the feature edits
52
+ - When a write surface needs gating, destructure `useVibe` for the database it writes to — `const { can, ready } = useVibe("<dbName>");` — and `useViewer` for identity — `const { ViewerTag } = useViewer();`
53
+ - NO hooks beyond `useVibe`/`useViewer`, NO data wiring — those land in the feature edits
54
54
  - **Be creative with the layout, but respect mobile idioms.** Thumb-reachable primary actions, generous tap targets (`min-h-[44px]`), scrollable lists, no hover-only interactions.
55
55
 
56
- **If the app needs an `access.js`, emit it right after the shell.** Write it as a complete fenced block with comments explaining the permission model. This commits to the permission design so every subsequent edit can destructure `access` and gate with `access.hasRole()` / `access.hasChannel()` from the start.
56
+ **If the app needs an `access.js`, emit it right after the shell.** Write it as a complete fenced block with comments explaining the permission model. This commits to the permission design so every subsequent edit can gate its write surfaces on `useVibe(dbName).can` the same rules the access function enforces.
57
57
 
58
58
  **Feature edits wire each component.** Each edit gets exactly one prose line (≤25 words) before it. Wire hooks, data, handlers, and `useFireproof` with `access` in these edits. Keep each edit focused — one feature, fully working after it lands.
59
59
 
@@ -269,6 +269,7 @@ When the app uses channel-based read isolation or per-document write validation,
269
269
  > Server-side access function gates the chat database — only channel members can read, only authors can post.
270
270
  >
271
271
  > access.js
272
+ >
272
273
  > ```js
273
274
  > export function chat(doc, oldDoc, user, ctx) {
274
275
  > if (!user) throw { forbidden: "authentication required" };
@@ -325,7 +326,7 @@ function FeatureThree() {
325
326
  }
326
327
 
327
328
  export default function App() {
328
- const { viewer, isOwner, ViewerTag } = useViewer();
329
+ const { ViewerTag } = useViewer();
329
330
  return (
330
331
  <main id="app" className={classNames.page}>
331
332
  <header id="app-header" className={classNames.header}>
@@ -339,71 +340,99 @@ export default function App() {
339
340
  }
340
341
  ````
341
342
 
342
- Keep the `useViewer` destructure on `App`'s first line whenever `useViewer` is in the imports later edits will reach for `viewer`, `isOwner`, and `ViewerTag` and need them already in scope.
343
+ Keep `useViewer` (for `ViewerTag`) on `App`'s first line, and add `useVibe(dbName)` in the feature components that gate writes `can`/`ready` are read where the write surface lives, not hoisted to `App`.
343
344
 
344
- **If the app needs an `access.js`, emit it right after the scaffold — before any feature edits.** Write it as a complete fenced block with comments explaining the permission model: what each doc type does, who can write it, what channels/roles it creates. This commits to the permission design early so every subsequent App.jsx edit can destructure `access` and gate with `access.hasRole()` / `access.hasChannel()` from the start. If later feature edits introduce new doc types, emit a follow-up `access.js` block with the additions.
345
+ **If the app needs an `access.js`, emit it right after the scaffold — before any feature edits.** Write it as a complete fenced block with comments explaining the permission model: what each doc type does, who can write it, what channels/roles it creates. This commits to the permission design early so every subsequent App.jsx edit can gate its write surfaces on `useVibe(dbName).can` the same rules the access function enforces. If later feature edits introduce new doc types, emit a follow-up `access.js` block with the additions.
345
346
 
346
347
  Example streamed output for a team board app:
347
348
 
348
349
  > **Crew Board** — team channel board with live posts, pinned announcements, and owner-managed channels.
349
350
  >
350
351
  > App.jsx
352
+ >
351
353
  > ```jsx
352
- > import React from "react"
353
- > import { useFireproof } from "use-fireproof"
354
- > import { useViewer } from "use-vibes"
354
+ > import React from "react";
355
+ > import { useFireproof } from "use-fireproof";
356
+ > import { useViewer } from "use-vibes";
355
357
  >
356
- > function Channels() { return <section id="channels"><h2>{/* channels pass */}</h2></section> }
357
- > function Feed() { return <section id="feed"><h2>{/* feed pass */}</h2></section> }
358
- > function Compose() { return <section id="compose"><h2>{/* compose pass */}</h2></section> }
358
+ > function Channels() {
359
+ > return (
360
+ > <section id="channels">
361
+ > <h2>{/* channels pass */}</h2>
362
+ > </section>
363
+ > );
364
+ > }
365
+ > function Feed() {
366
+ > return (
367
+ > <section id="feed">
368
+ > <h2>{/* feed pass */}</h2>
369
+ > </section>
370
+ > );
371
+ > }
372
+ > function Compose() {
373
+ > return (
374
+ > <section id="compose">
375
+ > <h2>{/* compose pass */}</h2>
376
+ > </section>
377
+ > );
378
+ > }
359
379
  >
360
380
  > export default function App() {
361
- > const { viewer, isOwner, isViewerPending, ViewerTag } = useViewer()
362
- > const c = { page: "min-h-screen bg-[#0a0a0a] text-white", header: "..." }
363
- > if (isViewerPending) return null
381
+ > const { ViewerTag } = useViewer();
382
+ > const c = { page: "min-h-screen bg-[#0a0a0a] text-white", header: "..." };
364
383
  > return (
365
384
  > <div className={c.page}>
366
- > <header id="app-header" className={c.header}><h1>Crew Board</h1><ViewerTag /></header>
367
- > <main id="app"><Channels /><Feed /><Compose /></main>
385
+ > <header id="app-header" className={c.header}>
386
+ > <h1>Crew Board</h1>
387
+ > <ViewerTag />
388
+ > </header>
389
+ > <main id="app">
390
+ > <Channels />
391
+ > <Feed />
392
+ > <Compose />
393
+ > </main>
368
394
  > </div>
369
- > )
395
+ > );
370
396
  > }
371
397
  > ```
372
398
  >
373
399
  > Access function — owner manages channels, members post to channels they have access to.
374
400
  >
375
401
  > access.js
402
+ >
376
403
  > ```js
377
404
  > // Each channel doc grants public read access to that channel.
378
405
  > // Posts require channel access — the server enforces this via ctx.requireAccess.
379
406
  > // Only the owner can create channels or grant roles.
380
407
  > export function crewBoard(doc, oldDoc, user, ctx) {
381
- > if (!user) throw { forbidden: "sign in" }
408
+ > if (!user) throw { forbidden: "sign in" };
382
409
  >
383
410
  > if (doc.type === "channel") {
384
- > if (!user.isOwner) throw { forbidden: "owner only" }
385
- > return { channels: [doc.name], grant: { public: [doc.name] } }
411
+ > if (!user.isOwner) throw { forbidden: "owner only" };
412
+ > return { channels: [doc.name], grant: { public: [doc.name] } };
386
413
  > }
387
414
  >
388
415
  > if (doc.type === "post") {
389
- > if (doc.authorHandle !== user.userHandle) throw { forbidden: "not author" }
390
- > ctx.requireAccess(doc.channelId)
391
- > return { channels: [doc.channelId] }
416
+ > if (doc.authorHandle !== user.userHandle) throw { forbidden: "not author" };
417
+ > ctx.requireAccess(doc.channelId);
418
+ > return { channels: [doc.channelId] };
392
419
  > }
393
420
  >
394
- > return {}
421
+ > return {};
395
422
  > }
396
423
  > ```
397
424
  >
398
425
  > Fill the channel sidebar with chip buttons and owner-only add form.
399
426
  >
400
427
  > App.jsx
428
+ >
401
429
  > ```jsx
402
430
  > <<<<<<< SEARCH
403
431
  > function Channels() { return <section id="channels"><h2>{/* channels pass */}</h2></section> }
404
432
  > =======
405
- > function Channels({ channels, active, setActive, isOwner, database, c }) {
406
- > // ... channel list + owner add form, gated on isOwner
433
+ > function Channels({ channels, active, setActive, database, c }) {
434
+ > const { can } = useVibe("crewBoard")
435
+ > // ... channel list; show the add-channel form only when can.create({ type: "channel" }).ok
407
436
  > }
408
437
  > >>>>>>> REPLACE
409
438
  > ```
@@ -411,26 +440,32 @@ Example streamed output for a team board app:
411
440
  > Wire the feed with live query, filtered by active channel.
412
441
  >
413
442
  > App.jsx
443
+ >
414
444
  > ```jsx
415
445
  > <<<<<<< SEARCH
416
446
  > function Feed() { return <section id="feed"><h2>{/* feed pass */}</h2></section> }
417
447
  > =======
418
- > function Feed({ channel, useLiveQuery, isOwner, ViewerTag, database, c }) {
448
+ > function Feed({ channel, useLiveQuery, ViewerTag, database, c }) {
419
449
  > // ... useLiveQuery("channelId", { key: channel }), posts with ViewerTag
420
450
  > }
421
451
  > >>>>>>> REPLACE
422
452
  > ```
423
453
  >
424
- > Wire the compose box — gated on viewer and channel access.
454
+ > Wire the compose box — gated on can.create for the posts db.
425
455
  >
426
456
  > App.jsx
457
+ >
427
458
  > ```jsx
428
459
  > <<<<<<< SEARCH
429
460
  > function Compose() { return <section id="compose"><h2>{/* compose pass */}</h2></section> }
430
461
  > =======
431
- > function Compose({ channel, viewer, access, database, c }) {
432
- > if (!viewer) return <p className={c.muted}>Sign in to post.</p>
433
- > if (!access.hasChannel(channel)) return <p className={c.muted}>No access to this channel.</p>
462
+ > function Compose({ channel, database, c }) {
463
+ > const { can, ready, me } = useVibe("crewBoard")
464
+ > if (!ready) return <div className={c.skeleton} />
465
+ > // Build the candidate from the doc you'll write — the access fn checks
466
+ > // authorHandle + channelId, so a bare { type: "post" } would be denied.
467
+ > const v = can.create({ type: "post", channelId: channel, authorHandle: me?.userHandle })
468
+ > if (!v.ok) return <p className={c.muted}>{v.reason}</p>
434
469
  > // ... compose form stamping authorHandle
435
470
  > }
436
471
  > >>>>>>> REPLACE