@fungi.computer/oyster 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/README.md +228 -176
  2. package/dist/agent-avatars.d.ts +103 -0
  3. package/dist/agent-avatars.js +66 -0
  4. package/dist/agents.d.ts +12 -2
  5. package/dist/agents.js +39 -2
  6. package/dist/app-builds.d.ts +76 -17
  7. package/dist/app-builds.js +207 -63
  8. package/dist/app-sources.d.ts +7 -22
  9. package/dist/app-sources.js +49 -14
  10. package/dist/apps/gate.d.ts +7 -7
  11. package/dist/apps/gate.js +6 -6
  12. package/dist/apps/installation.d.ts +35 -35
  13. package/dist/apps/installation.js +20 -19
  14. package/dist/build/artifact-writer.d.ts +40 -0
  15. package/dist/build/artifact-writer.js +181 -0
  16. package/dist/build/build-jobs.js +7 -1
  17. package/dist/build/build-policy.d.ts +10 -0
  18. package/dist/build/build-policy.js +10 -0
  19. package/dist/build/build-step.d.ts +12 -1
  20. package/dist/build/build-step.js +9 -1
  21. package/dist/build/candidate-builder.d.ts +68 -0
  22. package/dist/build/candidate-builder.js +91 -0
  23. package/dist/build/candidate-cli.d.ts +1 -0
  24. package/dist/build/candidate-cli.js +119 -0
  25. package/dist/build/candidate-cli.mjs +28220 -0
  26. package/dist/build/content-objects.d.ts +37 -0
  27. package/dist/build/content-objects.js +53 -0
  28. package/dist/build/effect.d.ts +18 -0
  29. package/dist/build/effect.js +52 -12
  30. package/dist/build/git-environment.d.ts +3 -0
  31. package/dist/build/git-environment.js +21 -9
  32. package/dist/build/local-build.d.ts +13 -3
  33. package/dist/build/local-build.js +149 -99
  34. package/dist/build/snapshot-package-store.d.ts +10 -0
  35. package/dist/build/snapshot-package-store.js +15 -0
  36. package/dist/build/snapshot-program-scripts.js +1 -1
  37. package/dist/build/snapshot-programs/snapshot-path.d.ts +2 -0
  38. package/dist/build/snapshot-programs/snapshot-path.js +6 -0
  39. package/dist/build/submission-contract.d.ts +461 -17
  40. package/dist/build/submission-contract.js +136 -26
  41. package/dist/build/workspace-build.d.ts +7 -2
  42. package/dist/build/workspace-build.js +55 -11
  43. package/dist/build-contract.d.ts +3 -0
  44. package/dist/build-contract.js +3 -0
  45. package/dist/build-egress.d.ts +62 -0
  46. package/dist/build-egress.js +148 -0
  47. package/dist/build.d.ts +1 -0
  48. package/dist/build.js +1 -0
  49. package/dist/cloudflare.js +4 -4
  50. package/dist/frame-binding-wire-script.js +1 -1
  51. package/dist/frame-binding-wire.d.ts +1 -1
  52. package/dist/frame-binding-wire.js +1 -1
  53. package/dist/git-journal.js +4 -4
  54. package/dist/index.d.ts +1 -0
  55. package/dist/index.js +1 -0
  56. package/dist/installation-consent.d.ts +3 -1
  57. package/dist/installation-consent.js +2 -0
  58. package/dist/mcp-owner.js +20 -8
  59. package/dist/pack.d.ts +6 -3
  60. package/dist/pack.js +28 -11
  61. package/dist/page/gill-observation.d.ts +4 -0
  62. package/dist/page/gill-observation.js +31 -0
  63. package/dist/page/mount.d.ts +4 -8
  64. package/dist/page/window-launch.d.ts +18 -0
  65. package/dist/page/window-launch.js +11 -0
  66. package/dist/page-script.js +4 -4
  67. package/dist/release.d.ts +11 -0
  68. package/dist/release.js +4 -1
  69. package/dist/shell/app-directory.d.ts +50 -45
  70. package/dist/shell/app-directory.js +19 -18
  71. package/dist/shell/shell-module.d.ts +26 -2
  72. package/dist/shell/shell-module.js +51 -2
  73. package/dist/shell/window-manager.d.ts +5 -1
  74. package/dist/shell/window-manager.js +21 -2
  75. package/dist/shell/workbench-directory.d.ts +332 -0
  76. package/dist/shell/workbench-directory.js +35 -0
  77. package/dist/shell/workbench-host-types.d.ts +1 -1
  78. package/dist/shell/workbench-host.js +5 -0
  79. package/dist/shell/workbench-model.d.ts +3 -1
  80. package/dist/source/index.d.ts +6 -7
  81. package/dist/source/index.js +6 -7
  82. package/dist/source/template-push.d.ts +33 -0
  83. package/dist/source/template-push.js +223 -0
  84. package/dist/source/template-repository.d.ts +2 -0
  85. package/dist/source/template-repository.js +13 -0
  86. package/dist/source/{template-write.d.ts → template-seed.d.ts} +19 -20
  87. package/dist/source/template-seed.js +80 -0
  88. package/dist/standalone/agent-directory.d.ts +4 -0
  89. package/dist/standalone/agent-directory.js +4 -0
  90. package/dist/standalone/agents.d.ts +227 -0
  91. package/dist/standalone/agents.js +834 -0
  92. package/dist/standalone/app-builds-binding.d.ts +36 -0
  93. package/dist/standalone/app-builds-binding.js +119 -0
  94. package/dist/standalone/app-set.d.ts +91 -0
  95. package/dist/standalone/app-set.js +395 -0
  96. package/dist/standalone/app-source.d.ts +41 -0
  97. package/dist/standalone/app-source.js +59 -0
  98. package/dist/standalone/builds.d.ts +18 -0
  99. package/dist/standalone/builds.js +101 -0
  100. package/dist/standalone/computer-egress.d.ts +37 -0
  101. package/dist/standalone/computer-egress.js +111 -0
  102. package/dist/standalone/computer.d.ts +122 -0
  103. package/dist/standalone/computer.js +714 -0
  104. package/dist/standalone/install-apps-cli.d.ts +2 -0
  105. package/dist/standalone/install-apps-cli.js +126 -0
  106. package/dist/standalone/instance.d.ts +35 -0
  107. package/dist/standalone/instance.js +74 -0
  108. package/dist/standalone/media.d.ts +76 -0
  109. package/dist/standalone/media.js +227 -0
  110. package/dist/standalone/preview.d.ts +51 -0
  111. package/dist/standalone/preview.js +167 -0
  112. package/dist/standalone/registry.d.ts +102 -0
  113. package/dist/standalone/registry.js +193 -0
  114. package/dist/standalone/tenancy.d.ts +42 -0
  115. package/dist/standalone/tenancy.js +241 -0
  116. package/dist/standalone/worker.d.ts +55 -0
  117. package/dist/standalone/worker.js +147 -0
  118. package/dist/standalone/workflow-authority-readers.d.ts +16 -0
  119. package/dist/standalone/workflow-authority-readers.js +35 -0
  120. package/dist/standalone/workflow-binding.d.ts +216 -0
  121. package/dist/standalone/workflow-binding.js +217 -0
  122. package/dist/standalone/workflow-events.d.ts +46 -0
  123. package/dist/standalone/workflow-events.js +39 -0
  124. package/dist/standalone/workflow-git-capture.d.ts +7 -0
  125. package/dist/standalone/workflow-git-capture.js +62 -0
  126. package/dist/standalone/workflow-host.d.ts +955 -0
  127. package/dist/standalone/workflow-host.js +778 -0
  128. package/dist/standalone/workflow-node-capture.d.ts +13 -0
  129. package/dist/standalone/workflow-node-capture.js +72 -0
  130. package/dist/standalone/workflow-root-authority.d.ts +27 -0
  131. package/dist/standalone/workflow-root-authority.js +87 -0
  132. package/dist/standalone/workflow-schedules.d.ts +52 -0
  133. package/dist/standalone/workflow-schedules.js +40 -0
  134. package/dist/standalone/workflow-trigger-host.d.ts +1716 -0
  135. package/dist/standalone/workflow-trigger-host.js +52 -0
  136. package/dist/standalone/workflows.d.ts +713 -0
  137. package/dist/standalone/workflows.js +554 -0
  138. package/dist/tenancy/auth0.d.ts +64 -0
  139. package/dist/tenancy/auth0.js +198 -0
  140. package/dist/tenancy/cloudflare/rate-limit.d.ts +8 -0
  141. package/dist/tenancy/cloudflare/rate-limit.js +19 -0
  142. package/dist/tenancy/cloudflare/registry.d.ts +50 -0
  143. package/dist/tenancy/cloudflare/registry.js +301 -0
  144. package/dist/tenancy/cloudflare.d.ts +2 -0
  145. package/dist/tenancy/cloudflare.js +2 -0
  146. package/dist/tenancy/cold-directory.d.ts +13 -0
  147. package/dist/tenancy/cold-directory.js +43 -0
  148. package/dist/tenancy/contracts.d.ts +195 -0
  149. package/dist/tenancy/contracts.js +1 -0
  150. package/dist/tenancy/index.d.ts +19 -0
  151. package/dist/tenancy/index.js +156 -0
  152. package/dist/tenancy/owner-key.d.ts +26 -0
  153. package/dist/tenancy/owner-key.js +63 -0
  154. package/dist/tenancy/oyster.d.ts +4 -0
  155. package/dist/tenancy/oyster.js +25 -0
  156. package/dist/tenancy/registry-record.d.ts +7 -0
  157. package/dist/tenancy/registry-record.js +44 -0
  158. package/dist/tenancy/registry.d.ts +27 -0
  159. package/dist/tenancy/registry.js +138 -0
  160. package/dist/tenancy/resolve.d.ts +7 -0
  161. package/dist/tenancy/resolve.js +64 -0
  162. package/dist/workers-git.js +1 -4
  163. package/dist/workers.d.ts +2 -2
  164. package/dist/workers.js +3 -1
  165. package/docs/api/build-contract.md +829 -32
  166. package/docs/api/build.md +253 -17
  167. package/docs/api/modules.md +40 -32
  168. package/docs/api/pack.md +6 -3
  169. package/docs/api/shell/app-directory.md +267 -0
  170. package/docs/api/shell/shell-module.md +64 -3
  171. package/docs/api/shell/workbench-directory.md +119 -0
  172. package/docs/api/shell/workbench.md +19 -0
  173. package/docs/api/shell.md +127 -0
  174. package/docs/api/tenancy/auth0.md +110 -0
  175. package/docs/api/tenancy/cloudflare.md +221 -0
  176. package/docs/api/tenancy/cold-directory.md +46 -0
  177. package/docs/api/tenancy/owner-key.md +63 -0
  178. package/docs/api/tenancy/registry.md +77 -0
  179. package/docs/api/tenancy/resolve.md +69 -0
  180. package/docs/api/tenancy.md +430 -0
  181. package/docs/api/workers-git.md +140 -21
  182. package/docs/api/workers.md +15 -2
  183. package/docs/site/agent-quickstart.mdx +52 -55
  184. package/examples/standalone/worker.ts +7 -14
  185. package/examples/standalone/wrangler.jsonc +67 -6
  186. package/package.json +78 -25
  187. package/dist/build/r2-artifact-writer.d.ts +0 -31
  188. package/dist/build/r2-artifact-writer.js +0 -179
  189. package/dist/source/template-write.js +0 -344
  190. package/docs/media/architecture.mmd +0 -32
  191. package/docs/media/architecture.png +0 -0
  192. package/docs/media/bonsai-network.png +0 -0
  193. package/docs/media/bonsai-repository.png +0 -0
  194. package/examples/git/worker.ts +0 -39
  195. package/examples/git/wrangler.jsonc +0 -32
@@ -234,39 +234,75 @@ unknown, revoked, expired or suspended key.
234
234
 
235
235
  ### OysterWebhooks
236
236
 
237
- Webhook subscriptions, their secrets and signed, retried deliveries.
237
+ The tenant's App event delivery owner: webhook subscriptions with signed,
238
+ retried deliveries, and host recipients with durable per-recipient records. An
239
+ emit commits here and returns; every delivery happens on the alarm.
238
240
 
239
241
  #### Extends
240
242
 
241
- - `DurableObject`\<[`OysterKeysEnv`](#oysterkeysenv)\>
243
+ - `DurableObject`\<`Env`\>
244
+
245
+ #### Type Parameters
246
+
247
+ | Type Parameter | Default type |
248
+ | ------------------------------------------------- | --------------------------------- |
249
+ | `Env` _extends_ [`OysterKeysEnv`](#oysterkeysenv) | [`OysterKeysEnv`](#oysterkeysenv) |
242
250
 
243
251
  #### Constructors
244
252
 
245
253
  ##### Constructor
246
254
 
247
255
  ```ts
248
- new OysterWebhooks(ctx, env): OysterWebhooks;
256
+ new OysterWebhooks<Env>(ctx, env): OysterWebhooks<Env>;
249
257
  ```
250
258
 
251
259
  ###### Parameters
252
260
 
253
- | Parameter | Type |
254
- | --------- | --------------------------------- |
255
- | `ctx` | `DurableObjectState` |
256
- | `env` | [`OysterKeysEnv`](#oysterkeysenv) |
261
+ | Parameter | Type |
262
+ | --------- | -------------------- |
263
+ | `ctx` | `DurableObjectState` |
264
+ | `env` | `Env` |
257
265
 
258
266
  ###### Returns
259
267
 
260
- [`OysterWebhooks`](#oysterwebhooks)
268
+ [`OysterWebhooks`](#oysterwebhooks)\<`Env`\>
261
269
 
262
270
  ###### Overrides
263
271
 
264
272
  ```ts
265
- DurableObject<OysterKeysEnv>.constructor
273
+ DurableObject<Env>.constructor
266
274
  ```
267
275
 
268
276
  #### Methods
269
277
 
278
+ ##### recipientDeliveries()
279
+
280
+ ```ts
281
+ recipientDeliveries(recipient): Readonly<{
282
+ recipient: string;
283
+ eventId: string;
284
+ type: string;
285
+ state: "pending" | "failed" | "delivered";
286
+ attempts: number;
287
+ lastError: string | null;
288
+ updatedAt: number;
289
+ }>[];
290
+ ```
291
+
292
+ Recent deliveries to one host recipient, newest first.
293
+
294
+ ###### Parameters
295
+
296
+ | Parameter | Type |
297
+ | ----------- | -------- |
298
+ | `recipient` | `string` |
299
+
300
+ ###### Returns
301
+
302
+ `Readonly`\<\{ `recipient`: `string`; `eventId`: `string`; `type`: `string`;
303
+ `state`: `"pending"` \| `"failed"` \| `"delivered"`; `attempts`: `number`;
304
+ `lastError`: `string` \| `null`; `updatedAt`: `number`; \}\>[]
305
+
270
306
  ##### subscribe()
271
307
 
272
308
  ```ts
@@ -358,25 +394,29 @@ Recent deliveries for one subscription, newest first.
358
394
 
359
395
  ```ts
360
396
  enqueue(
361
- installationId,
397
+ source,
362
398
  payload,
363
- eventId
364
- ): number;
399
+ eventId,
400
+ recipients
401
+ ): Promise<number>;
365
402
  ```
366
403
 
367
- Queue an event for every matching subscription (idempotent per event id).
404
+ Accept an emitted event: queue it for every matching subscription and every
405
+ named host recipient (idempotent per event id). Nothing is delivered before this
406
+ returns, so no recipient can fail the emitter's write.
368
407
 
369
408
  ###### Parameters
370
409
 
371
- | Parameter | Type |
372
- | ---------------- | --------------------------------------------------------- |
373
- | `installationId` | `string` |
374
- | `payload` | [`StandardWebhookPayload`](git.md#standardwebhookpayload) |
375
- | `eventId` | `string` |
410
+ | Parameter | Type |
411
+ | ------------ | --------------------------------------------------------- |
412
+ | `source` | [`HostEventSource`](#hosteventsource) |
413
+ | `payload` | [`StandardWebhookPayload`](git.md#standardwebhookpayload) |
414
+ | `eventId` | `string` |
415
+ | `recipients` | readonly `string`[] |
376
416
 
377
417
  ###### Returns
378
418
 
379
- `number`
419
+ `Promise`\<`number`\>
380
420
 
381
421
  ##### alarm()
382
422
 
@@ -384,7 +424,7 @@ Queue an event for every matching subscription (idempotent per event id).
384
424
  alarm(): Promise<void>;
385
425
  ```
386
426
 
387
- Deliver due webhooks, then schedule the next retry.
427
+ Deliver due webhooks and recipient rows, then schedule the next retry.
388
428
 
389
429
  ###### Returns
390
430
 
@@ -1015,6 +1055,57 @@ host handle decodes.
1015
1055
 
1016
1056
  ## Type Aliases
1017
1057
 
1058
+ ### HostEventSource
1059
+
1060
+ ```ts
1061
+ type HostEventSource = Readonly<{
1062
+ installationId: string;
1063
+ appId: string;
1064
+ releaseId: string;
1065
+ }>;
1066
+ ```
1067
+
1068
+ The emitting installation as the host attested it on the emit's frame.
1069
+
1070
+ ---
1071
+
1072
+ ### HostRecipientEvent
1073
+
1074
+ ```ts
1075
+ type HostRecipientEvent = Readonly<{
1076
+ source: HostEventSource;
1077
+ type: string;
1078
+ eventId: string;
1079
+ payload: Readonly<{
1080
+ type: string;
1081
+ timestamp: string;
1082
+ data: unknown;
1083
+ }>;
1084
+ }>;
1085
+ ```
1086
+
1087
+ One accepted event, as a host recipient receives it.
1088
+
1089
+ ---
1090
+
1091
+ ### RecipientDelivery
1092
+
1093
+ ```ts
1094
+ type RecipientDelivery = Readonly<{
1095
+ recipient: string;
1096
+ eventId: string;
1097
+ type: string;
1098
+ state: "pending" | "delivered" | "failed";
1099
+ attempts: number;
1100
+ lastError: string | null;
1101
+ updatedAt: number;
1102
+ }>;
1103
+ ```
1104
+
1105
+ One recipient's delivery record for one event.
1106
+
1107
+ ---
1108
+
1018
1109
  ### ArtifactsGit
1019
1110
 
1020
1111
  ```ts
@@ -1288,7 +1379,7 @@ One live guest frame's Git custody; never a guest argument.
1288
1379
  const eventsBinding: OysterBindingRow<OysterGitWorkerEnv>;
1289
1380
  ```
1290
1381
 
1291
- EVENTS: signed webhook delivery in this Instance's tenant namespace.
1382
+ EVENTS for a host with webhook subscribers only.
1292
1383
 
1293
1384
  ---
1294
1385
 
@@ -1347,6 +1438,34 @@ The Artifacts namespace: the binding when present, else the REST API.
1347
1438
 
1348
1439
  ---
1349
1440
 
1441
+ ### eventsBindingFor()
1442
+
1443
+ ```ts
1444
+ function eventsBindingFor<Env>(recipients): OysterBindingRow<Env>;
1445
+ ```
1446
+
1447
+ EVENTS: commit the emit to this tenant's delivery owner and return. Webhook
1448
+ subscribers and the host recipients a root names are delivered afterwards, so a
1449
+ subscriber outage never fails the emitting App's write.
1450
+
1451
+ #### Type Parameters
1452
+
1453
+ | Type Parameter |
1454
+ | ----------------------------------------------------------- |
1455
+ | `Env` _extends_ [`OysterGitWorkerEnv`](#oystergitworkerenv) |
1456
+
1457
+ #### Parameters
1458
+
1459
+ | Parameter | Type |
1460
+ | ------------ | -------------------------------------------------------- |
1461
+ | `recipients` | (`context`, `frame`) => `Promise`\<readonly `string`[]\> |
1462
+
1463
+ #### Returns
1464
+
1465
+ [`OysterBindingRow`](workers.md#oysterbindingrow)\<`Env`\>
1466
+
1467
+ ---
1468
+
1350
1469
  ### gitAdminRoutes()
1351
1470
 
1352
1471
  ```ts
@@ -1557,7 +1557,16 @@ Files in an R2 bucket under `prefix` (one workspace per prefix).
1557
1557
  ### r2ArtifactStore()
1558
1558
 
1559
1559
  ```ts
1560
- function r2ArtifactStore(bucket): ArtifactStore;
1560
+ function r2ArtifactStore(bucket): Readonly<{
1561
+ get: (artifactRef) => Promise<Uint8Array<ArrayBufferLike> | null>;
1562
+ put: (artifactRef, bytes) => Promise<void>;
1563
+ }> &
1564
+ Readonly<{
1565
+ head: (artifactRef) => Promise<Readonly<{
1566
+ byteLength: number;
1567
+ digest: Sha256Digest | null;
1568
+ }> | null>;
1569
+ }>;
1561
1570
  ```
1562
1571
 
1563
1572
  Store Release artifacts in an R2 bucket.
@@ -1570,7 +1579,11 @@ Store Release artifacts in an R2 bucket.
1570
1579
 
1571
1580
  #### Returns
1572
1581
 
1573
- [`ArtifactStore`](host.md#artifactstore)
1582
+ `Readonly`\<\{ `get`: (`artifactRef`) =>
1583
+ `Promise`\<`Uint8Array`\<`ArrayBufferLike`\> \| `null`\>; `put`: (`artifactRef`,
1584
+ `bytes`) => `Promise`\<`void`\>; \}\> & `Readonly`\<\{ `head`: (`artifactRef`)
1585
+ => `Promise`\< \| `Readonly`\<\{ `byteLength`: `number`; `digest`:
1586
+ `Sha256Digest` \| `null`; \}\> \| `null`\>; \}\>
1574
1587
 
1575
1588
  ---
1576
1589
 
@@ -23,7 +23,8 @@ read the "If it fails" notes under it before trying anything else.
23
23
  ## 1. Check prerequisites
24
24
 
25
25
  You need Node 24 or newer, pnpm, Git, curl and openssl. You do not need a
26
- Cloudflare account until step 7, and you never need Docker for these steps.
26
+ Cloudflare account until step 7. Docker is needed only in step 7, where Wrangler
27
+ builds the Computer's container image.
27
28
 
28
29
  ```sh
29
30
  node --version
@@ -43,13 +44,13 @@ If it fails:
43
44
 
44
45
  ## 2. Create a project
45
46
 
46
- Make a new directory, install Oyster and Wrangler, and copy the standalone
47
+ Make a new directory, install Oyster, its Computer and Wrangler, and copy the
47
48
  example Worker out of the package:
48
49
 
49
50
  ```sh
50
51
  mkdir my-oyster
51
52
  cd my-oyster
52
- pnpm add @fungi.computer/oyster
53
+ pnpm add @fungi.computer/oyster @fungi.computer/computer
53
54
  pnpm add -D wrangler
54
55
  cp node_modules/@fungi.computer/oyster/examples/standalone/worker.ts .
55
56
  cp node_modules/@fungi.computer/oyster/examples/standalone/wrangler.jsonc .
@@ -67,26 +68,30 @@ If it fails:
67
68
  `protobufjs`: pnpm installed them without running their install scripts, and
68
69
  nothing in this guide needs those scripts. Go on.
69
70
  - `cp: cannot stat …/examples/standalone/…`: the install did not finish. Run
70
- `pnpm add @fungi.computer/oyster` again and read its first error.
71
+ `pnpm add @fungi.computer/oyster @fungi.computer/computer` again and read its
72
+ first error.
71
73
 
72
74
  ## 3. Run a local Oyster
73
75
 
74
- `worker.ts` and `wrangler.jsonc` are a complete single-owner Oyster. Run it
75
- under `wrangler dev` on your machine. Choose an owner key and keep this terminal
76
- open:
76
+ `worker.ts` and `wrangler.jsonc` are the whole Oyster. Run it under
77
+ `wrangler dev` on your machine, without its Computer container. Oyster serves an
78
+ HTTPS origin; `--local-upstream` presents your loopback requests to it at
79
+ `https://oyster.test`. Choose an owner key and keep this terminal open:
77
80
 
78
81
  ```sh
79
82
  export OYSTER_OWNER_KEY=$(openssl rand -hex 24)
80
83
  export OYSTER_URL=http://127.0.0.1:8787
81
84
  echo "$OYSTER_OWNER_KEY" > .oyster-owner-key
82
- npx wrangler dev --local --ip 127.0.0.1 --port 8787 \
83
- --var OYSTER_OWNER_KEY:$OYSTER_OWNER_KEY --var OYSTER_ORIGIN:$OYSTER_URL
85
+ npx wrangler dev --local --enable-containers=false --ip 127.0.0.1 --port 8787 \
86
+ --local-upstream oyster.test --upstream-protocol https \
87
+ --var OYSTER_OWNER_KEY:$OYSTER_OWNER_KEY --var OYSTER_ORIGIN:https://oyster.test
84
88
  ```
85
89
 
86
- Expected output: a bindings table listing `env.MCP (OysterMcp)`,
87
- `env.REGISTRY (OysterRegistry)`, `env.INSTANCES (OysterInstance)`,
88
- `env.RELEASES (oyster-releases)` and `env.LOADER`, then
89
- `Ready on http://127.0.0.1:8787`.
90
+ Expected output: warnings that the AI and Artifacts bindings reach remote
91
+ resources, a bindings table listing `env.REGISTRY (OysterRegistry)`,
92
+ `env.INSTANCES (StandaloneInstance)`, `env.COMPUTER (ComputerDO)` and the rest,
93
+ then `Ready on http://127.0.0.1:8787`. Locally there is no Computer, git storage
94
+ or Workers AI; steps 3 to 5 need none of them.
90
95
 
91
96
  Keep it running. Open a second terminal in `my-oyster`, set the same two
92
97
  variables there, and check that Oyster answers:
@@ -114,8 +119,9 @@ If it fails:
114
119
  `/login` check prints `200`:
115
120
 
116
121
  ```sh
117
- npx wrangler dev --local --ip 127.0.0.1 --port 8787 \
118
- --var OYSTER_OWNER_KEY:$OYSTER_OWNER_KEY --var OYSTER_ORIGIN:$OYSTER_URL \
122
+ npx wrangler dev --local --enable-containers=false --ip 127.0.0.1 --port 8787 \
123
+ --local-upstream oyster.test --upstream-protocol https \
124
+ --var OYSTER_OWNER_KEY:$OYSTER_OWNER_KEY --var OYSTER_ORIGIN:https://oyster.test \
119
125
  > oyster-dev.log 2>&1 &
120
126
  ```
121
127
 
@@ -265,29 +271,10 @@ If it fails:
265
271
 
266
272
  ## 6. Add Git
267
273
 
268
- The package also ships `examples/git`: the same Oyster with the git door, so
269
- people and agents `clone`, `fetch` and `push` App repositories with ordinary
270
- `git` at `/git/<installation>/<repo>.git`. Repositories live in Cloudflare
271
- Artifacts, which `wrangler dev` cannot emulate, so the Git worker runs once it
272
- is deployed in step 7. To use it, copy it over the standalone files:
273
-
274
- ```sh
275
- cp node_modules/@fungi.computer/oyster/examples/git/worker.ts .
276
- cp node_modules/@fungi.computer/oyster/examples/git/wrangler.jsonc .
277
- ```
278
-
279
- Compared with `examples/standalone`, `examples/git/worker.ts` builds one
280
- `oysterGitRoot` with `ownerOrKeyTenancy` and adds:
281
-
282
- - the git door, mounted by `createOysterGitWorker(root)`;
283
- - owner and named keys that sign in to git, plus `/api/keys` and
284
- `/api/webhooks`;
285
- - `OysterGitInstance` as `OysterInstance`, which hands Apps `env.GIT` and
286
- `env.EVENTS`;
287
- - the `ARTIFACTS` binding and the `KEYS` and `WEBHOOKS` Durable Objects in its
288
- `wrangler.jsonc`, which names the Worker `oyster-git`.
289
-
290
- With the Git worker deployed, give each agent its own key:
274
+ Git is already part of the host: people and agents `clone`, `fetch` and `push`
275
+ App repositories with ordinary `git` at `/git/<installation>/<repo>.git`, with
276
+ repositories in Cloudflare Artifacts. Artifacts runs only once the Worker is
277
+ deployed in step 7. There, give each agent its own key:
291
278
 
292
279
  ```sh
293
280
  curl -s -X POST -H "Authorization: Bearer $OYSTER_OWNER_KEY" \
@@ -299,20 +286,15 @@ curl -s -X POST -H "Authorization: Bearer $OYSTER_OWNER_KEY" \
299
286
  Expected output: JSON with a `plaintext` field starting `oyk_`. Oyster shows it
300
287
  once; that key signs in to `git` and to `/mcp`.
301
288
 
302
- If it fails:
303
-
304
- - `404`: the deployed Worker is the standalone one. Copy the `examples/git`
305
- files and deploy again.
306
-
307
289
  ## 7. Deploy to Cloudflare Workers
308
290
 
309
- This step needs a Cloudflare account on Workers Paid; Git also needs Artifacts
310
- enabled on it. Ask the person before you deploy anything.
291
+ This step needs a Cloudflare account on Workers Paid with Containers, Artifacts,
292
+ Workers AI and Workflows enabled, and Docker running on this machine. Ask the
293
+ person before you deploy anything.
311
294
 
312
- `wrangler.jsonc` names the Worker (`oyster`, or `oyster-git` for Git) and its R2
313
- bucket, `oyster-releases`. The Worker's address is
314
- `https://<worker name>.<your-subdomain>.workers.dev`, or a custom domain. For
315
- the standalone Worker:
295
+ `wrangler.jsonc` names the Worker `oyster`, its R2 bucket `oyster-releases` and
296
+ its Artifacts namespace `oyster`. The Worker's address is
297
+ `https://oyster.<your-subdomain>.workers.dev`, or a custom domain:
316
298
 
317
299
  ```sh
318
300
  npx wrangler login
@@ -322,9 +304,21 @@ npx wrangler deploy --var OYSTER_ORIGIN:$OYSTER_URL
322
304
  printf '%s' "$OYSTER_OWNER_KEY" | npx wrangler secret put OYSTER_OWNER_KEY
323
305
  ```
324
306
 
325
- Expected output: `wrangler deploy` prints the deployed `https://` URL, and
326
- `wrangler secret put` reports the secret uploaded. Then install Hello exactly as
327
- in step 4, with `OYSTER_URL` set to the deployed address.
307
+ Expected output: `wrangler deploy` builds the Computer image, uploads it and
308
+ prints the deployed `https://` URL, and `wrangler secret put` reports the secret
309
+ uploaded.
310
+
311
+ Then install Fungi's seven starter Apps, each built on this Oyster's Computer
312
+ from its own repository:
313
+
314
+ ```sh
315
+ npx oyster install-apps
316
+ ```
317
+
318
+ Expected output: a `source recorded` line per App, `Building … on the Computer`
319
+ and `Installed …` lines (two builds at a time, Tourtois first), a timing table,
320
+ and `Installed 7 Apps`. Open `$OYSTER_URL/login` with the owner key to see the
321
+ Tourtois desktop.
328
322
 
329
323
  To keep `OYSTER_ORIGIN` across later deploys, set `vars.OYSTER_ORIGIN` in
330
324
  `wrangler.jsonc`; every deploy replaces the Worker's variables.
@@ -336,14 +330,17 @@ If it fails:
336
330
  - A secret prompt on stdin: pipe the key as shown; never type it into a log.
337
331
  - Bindings or migrations refused: deploy the copied `wrangler.jsonc` unchanged
338
332
  except for `vars` and the bucket name.
333
+ - `docker` not found or not running: start Docker; Wrangler builds the Computer
334
+ image from `node_modules/@fungi.computer/computer/Dockerfile`.
335
+ - A build `failed` in `install-apps`: run it again; finished Apps are kept and
336
+ replaced in place.
339
337
 
340
338
  ## Where to go next
341
339
 
342
340
  - The Oyster README (`node_modules/@fungi.computer/oyster/README.md`) explains
343
341
  the host, Apps, capabilities, MCP and the shell in depth.
344
- - [oyster.shiit.app](https://oyster.shiit.app/) is a complete deployment of the
345
- Git worker with Fungi's App set: Bonsai, Workflows, Computers, Agents and
346
- media.
342
+ - [oyster.shiit.app](https://oyster.shiit.app/) runs this same host with the
343
+ seven starter Apps.
347
344
  - Oyster is built from the other Fungi packages, each its own repository under
348
345
  [github.com/fungi-computer](https://github.com/fungi-computer) and on npm as
349
346
  `@fungi.computer/<name>`. The README's "Part of Fungi" section lists them.
@@ -1,14 +1,7 @@
1
- // A standalone Oyster: one owner, Apps installed from Releases, each App's
2
- // backend in its own Durable Object with SQLite. Runs on Cloudflare Workers
3
- // (`wrangler deploy`) and on celld (`celld dev`) from the same code.
4
- import { createOysterWorker } from "@fungi.computer/oyster/workers";
5
-
6
- // Every App binding in every invocation frame is the one `OysterBinding` entrypoint.
7
- export {
8
- OysterBinding,
9
- OysterInstance,
10
- OysterRegistry,
11
- OysterMcp,
12
- } from "@fungi.computer/oyster/workers";
13
-
14
- export default createOysterWorker();
1
+ // The whole Oyster: Apps installed from Releases, each with its own Durable
2
+ // Object and SQLite; git through Artifacts; a Computer in a Cloudflare
3
+ // Container that builds App sources and runs terminals and files; Agents on
4
+ // Workers AI; Workflows; and media. Runs on Cloudflare Workers
5
+ // (`wrangler deploy`) and on celld from the same code.
6
+ export * from "@fungi.computer/oyster/standalone";
7
+ export { default } from "@fungi.computer/oyster/standalone";
@@ -1,21 +1,82 @@
1
1
  {
2
- "$schema": "../../../../node_modules/wrangler/config-schema.json",
2
+ "$schema": "./node_modules/wrangler/config-schema.json",
3
+ // The whole Oyster. Copy it beside worker.ts, set OYSTER_ORIGIN, and deploy.
3
4
  "name": "oyster",
4
5
  "main": "worker.ts",
5
6
  "compatibility_date": "2026-09-04",
6
7
  "compatibility_flags": ["nodejs_compat"],
7
- "vars": { "OYSTER_ORIGIN": "https://oyster.example" },
8
+ "workers_dev": true,
9
+ "preview_urls": false,
10
+ "observability": { "enabled": true },
11
+ "workflows": [
12
+ {
13
+ "binding": "GRAPH_WORKFLOWS",
14
+ "name": "oyster-graphs",
15
+ "class_name": "StandaloneGraphWorkflow",
16
+ },
17
+ ],
8
18
  "worker_loaders": [{ "binding": "LOADER" }],
9
- "r2_buckets": [{ "binding": "RELEASES", "bucket_name": "oyster-releases" }],
19
+ "containers": [
20
+ {
21
+ "class_name": "ComputerDO",
22
+ "image": "./node_modules/@fungi.computer/computer/Dockerfile",
23
+ "instance_type": "standard-4",
24
+ "max_instances": 1,
25
+ "rollout_active_grace_period": 0,
26
+ "rollout_step_percentage": [100],
27
+ },
28
+ ],
29
+ "ai": { "binding": "AI" },
30
+ "images": { "binding": "IMAGES" },
31
+ "r2_buckets": [
32
+ { "binding": "RELEASES", "bucket_name": "oyster-releases" },
33
+ { "binding": "APP_ARTIFACTS", "bucket_name": "oyster-releases" },
34
+ ],
35
+ "artifacts": [{ "binding": "ARTIFACTS", "namespace": "oyster" }],
36
+ "vars": {
37
+ "OYSTER_COMPUTER_ID": "workspace",
38
+ "OYSTER_HOME_INSTALLATION": "tourtois",
39
+ "OYSTER_ORIGIN": "https://oyster.example",
40
+ "OYSTER_OWNER_NAME": "owner",
41
+ // Names the AI Gateway that Prints' third-party models (GPT Image 2,
42
+ // Seedance, Veo) and the background media retry owner route through.
43
+ // Not a secret: Cloudflare creates the gateway by this id on first use.
44
+ "AI_GATEWAY_ID": "oyster",
45
+ },
10
46
  "durable_objects": {
11
47
  "bindings": [
48
+ { "name": "TENANTS", "class_name": "StandaloneTenants" },
12
49
  { "name": "MCP", "class_name": "OysterMcp" },
50
+
13
51
  { "name": "REGISTRY", "class_name": "OysterRegistry" },
14
- { "name": "INSTANCES", "class_name": "OysterInstance" },
52
+ { "name": "WORKFLOW_RUNS", "class_name": "StandaloneWorkflowRuns" },
53
+ { "name": "INSTANCES", "class_name": "StandaloneInstance" },
54
+ { "name": "COMPUTER", "class_name": "ComputerDO" },
55
+ { "name": "KEYS", "class_name": "OysterKeys" },
56
+ { "name": "WEBHOOKS", "class_name": "OysterWebhooks" },
57
+ { "name": "AGENTS", "class_name": "StandaloneAgent" },
58
+ { "name": "AGENT_DIRECTORY", "class_name": "AgentDirectory" },
59
+ { "name": "MEDIA_OPERATION", "class_name": "MediaOperationDO" },
15
60
  ],
16
61
  },
62
+ // One initial tag: pre-launch history was collapsed (Levi 10-14, data wipe
63
+ // authorized), so a fresh Worker creates every bound class at once.
17
64
  "migrations": [
18
- { "tag": "v1", "new_sqlite_classes": ["OysterRegistry", "OysterInstance"] },
19
- { "tag": "mcp-session-owner-v1", "new_sqlite_classes": ["OysterMcp"] },
65
+ {
66
+ "tag": "oyster-v1",
67
+ "new_sqlite_classes": [
68
+ "StandaloneTenants",
69
+ "OysterMcp",
70
+ "OysterRegistry",
71
+ "StandaloneWorkflowRuns",
72
+ "StandaloneInstance",
73
+ "ComputerDO",
74
+ "OysterKeys",
75
+ "OysterWebhooks",
76
+ "StandaloneAgent",
77
+ "AgentDirectory",
78
+ "MediaOperationDO",
79
+ ],
80
+ },
20
81
  ],
21
82
  }