@fungi.computer/oyster 0.6.0 → 0.7.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 (163) hide show
  1. package/README.md +132 -78
  2. package/dist/agent-archive-projection.d.ts +8 -0
  3. package/dist/agent-archive-projection.js +49 -0
  4. package/dist/agent-schedules.d.ts +50 -0
  5. package/dist/agent-schedules.js +17 -0
  6. package/dist/agents.d.ts +35 -14
  7. package/dist/agents.js +93 -144
  8. package/dist/app-builds.d.ts +7 -2
  9. package/dist/app-builds.js +19 -2
  10. package/dist/approval-capability.d.ts +1 -1
  11. package/dist/approval-capability.js +11 -16
  12. package/dist/approval-home.d.ts +2 -1
  13. package/dist/approval-home.js +5 -3
  14. package/dist/apps/catalog.js +1 -1
  15. package/dist/apps/gate.d.ts +4 -7
  16. package/dist/apps/gate.js +14 -29
  17. package/dist/apps/index.d.ts +1 -1
  18. package/dist/apps/installation.d.ts +4 -42
  19. package/dist/apps/installation.js +7 -75
  20. package/dist/apps/operations.js +0 -10
  21. package/dist/apps/permissions.d.ts +18 -8
  22. package/dist/apps/permissions.js +7 -1
  23. package/dist/auth.d.ts +1 -24
  24. package/dist/auth.js +9 -39
  25. package/dist/authorization.d.ts +307 -0
  26. package/dist/authorization.js +542 -0
  27. package/dist/boot-host-script.js +1 -1
  28. package/dist/build/build-jobs.d.ts +2 -2
  29. package/dist/build/candidate-builder.d.ts +2 -0
  30. package/dist/build/candidate-builder.js +5 -1
  31. package/dist/build/candidate-cli.js +3 -0
  32. package/dist/build/candidate-cli.mjs +59 -21
  33. package/dist/build/job-log.d.ts +23 -0
  34. package/dist/build/job-log.js +88 -0
  35. package/dist/build/local-build.d.ts +2 -0
  36. package/dist/build/local-build.js +11 -9
  37. package/dist/cloudflare.d.ts +4 -1
  38. package/dist/cloudflare.js +1 -1
  39. package/dist/files.js +9 -8
  40. package/dist/git-admission.d.ts +3 -3
  41. package/dist/git-admission.js +4 -6
  42. package/dist/git-door.d.ts +8 -7
  43. package/dist/git-door.js +18 -17
  44. package/dist/git.d.ts +1 -1
  45. package/dist/host.d.ts +33 -40
  46. package/dist/host.js +153 -272
  47. package/dist/installation-execution.js +10 -5
  48. package/dist/installation-operations.d.ts +4 -180
  49. package/dist/installation-operations.js +1 -5
  50. package/dist/installation-store-generation.d.ts +4 -1
  51. package/dist/installation-store-generation.js +59 -6
  52. package/dist/internal/delivery.js +0 -1
  53. package/dist/internal/host-gate.d.ts +3 -2
  54. package/dist/internal/host-gate.js +5 -18
  55. package/dist/internal/invocation-timing.d.ts +16 -0
  56. package/dist/internal/invocation-timing.js +23 -0
  57. package/dist/internal/registry-installations.js +1 -0
  58. package/dist/invocation.d.ts +15 -14
  59. package/dist/invocation.js +58 -26
  60. package/dist/keys.d.ts +2 -19
  61. package/dist/keys.js +1 -37
  62. package/dist/mcp.d.ts +15 -27
  63. package/dist/mcp.js +105 -155
  64. package/dist/page/agent-browser.d.ts +15 -0
  65. package/dist/page/agent-browser.js +162 -0
  66. package/dist/page/app-permissions-port.d.ts +3 -0
  67. package/dist/page/app-permissions-port.js +43 -0
  68. package/dist/page/app-permissions.d.ts +11 -0
  69. package/dist/page/app-permissions.js +296 -0
  70. package/dist/page/isolated-page-theme.d.ts +2 -0
  71. package/dist/page/isolated-page-theme.js +11 -0
  72. package/dist/page/mount.d.ts +2 -13
  73. package/dist/page/mount.js +7 -93
  74. package/dist/page-script.d.ts +0 -3
  75. package/dist/page-script.js +3 -4
  76. package/dist/standalone/agent-archive-owner.d.ts +42 -0
  77. package/dist/standalone/agent-archive-owner.js +116 -0
  78. package/dist/standalone/agent-archive-schedules.d.ts +6 -0
  79. package/dist/standalone/agent-archive-schedules.js +76 -0
  80. package/dist/standalone/agent-archive.d.ts +31 -0
  81. package/dist/standalone/agent-archive.js +67 -0
  82. package/dist/standalone/agent-computers.d.ts +7 -6
  83. package/dist/standalone/agent-computers.js +4 -7
  84. package/dist/standalone/agent-mail.d.ts +2 -2
  85. package/dist/standalone/agents.d.ts +157 -20
  86. package/dist/standalone/agents.js +234 -30
  87. package/dist/standalone/app-builds-binding.js +1 -1
  88. package/dist/standalone/app-set.js +2 -54
  89. package/dist/standalone/app-source.d.ts +3 -4
  90. package/dist/standalone/app-source.js +12 -9
  91. package/dist/standalone/builds.d.ts +2 -14
  92. package/dist/standalone/builds.js +15 -13
  93. package/dist/standalone/computer-fleet.d.ts +4 -4
  94. package/dist/standalone/computer-fleet.js +13 -42
  95. package/dist/standalone/computer.d.ts +4 -3
  96. package/dist/standalone/computer.js +52 -53
  97. package/dist/standalone/dashboard-approval.d.ts +10 -0
  98. package/dist/standalone/dashboard-approval.js +66 -0
  99. package/dist/standalone/machine-link.d.ts +4 -221
  100. package/dist/standalone/machine-link.js +21 -15
  101. package/dist/standalone/media.d.ts +1 -0
  102. package/dist/standalone/media.js +20 -14
  103. package/dist/standalone/owner-routes.d.ts +16 -0
  104. package/dist/standalone/owner-routes.js +21 -0
  105. package/dist/standalone/permission-resources.d.ts +5 -0
  106. package/dist/standalone/permission-resources.js +31 -0
  107. package/dist/standalone/registry.d.ts +7 -0
  108. package/dist/standalone/registry.js +3 -0
  109. package/dist/standalone/tenancy.d.ts +0 -3
  110. package/dist/standalone/tenancy.js +2 -5
  111. package/dist/standalone/worker-routes.d.ts +19 -0
  112. package/dist/standalone/worker-routes.js +9 -0
  113. package/dist/standalone/worker.d.ts +1 -1
  114. package/dist/standalone/worker.js +27 -35
  115. package/dist/standalone/workflow-binding.d.ts +8 -3
  116. package/dist/standalone/workflow-binding.js +14 -5
  117. package/dist/standalone/workflow-git-capture.js +2 -1
  118. package/dist/standalone/workflow-host.d.ts +8 -103
  119. package/dist/standalone/workflow-host.js +1 -1
  120. package/dist/standalone/workflow-node-capture.js +2 -2
  121. package/dist/standalone/workflow-root-authority.d.ts +1 -1
  122. package/dist/standalone/workflow-root-authority.js +1 -1
  123. package/dist/standalone/workflow-schedules.d.ts +14 -5
  124. package/dist/standalone/workflow-schedules.js +11 -5
  125. package/dist/standalone/workflow-webhooks.d.ts +4 -18
  126. package/dist/standalone/workflow-webhooks.js +5 -5
  127. package/dist/standalone/workflows.d.ts +36 -28
  128. package/dist/standalone/workflows.js +6 -3
  129. package/dist/storage-frame.d.ts +6 -6
  130. package/dist/testing/capabilities.d.ts +7 -6
  131. package/dist/testing/capabilities.js +3 -6
  132. package/dist/testing/installation.d.ts +0 -1
  133. package/dist/testing/installation.js +2 -5
  134. package/dist/workers-git.d.ts +12 -4
  135. package/dist/workers-git.js +38 -35
  136. package/dist/workers.d.ts +9 -1
  137. package/dist/workers.js +44 -8
  138. package/dist/workflows.d.ts +2 -0
  139. package/dist/workflows.js +1 -0
  140. package/docs/api/README.md +7 -0
  141. package/docs/api/agent-schedules.md +175 -0
  142. package/docs/api/agents.md +34 -13
  143. package/docs/api/app-storage.md +1 -1
  144. package/docs/api/apps.md +323 -225
  145. package/docs/api/auth.md +0 -55
  146. package/docs/api/authorization.md +1300 -0
  147. package/docs/api/build.md +40 -37
  148. package/docs/api/cloudflare.md +3 -3
  149. package/docs/api/git.md +20 -11
  150. package/docs/api/host.md +64 -192
  151. package/docs/api/index.md +1 -1
  152. package/docs/api/invocation.md +14 -14
  153. package/docs/api/keys.md +1 -98
  154. package/docs/api/mcp.md +43 -40
  155. package/docs/api/modules.md +2 -0
  156. package/docs/api/page/mount.md +16 -19
  157. package/docs/api/workers-git.md +46 -12
  158. package/docs/api/workers.md +124 -235
  159. package/package.json +39 -20
  160. package/dist/page/computer-target.d.ts +0 -3
  161. package/dist/page/computer-target.js +0 -9
  162. package/dist/standalone/channel-session-door.d.ts +0 -4
  163. package/dist/standalone/channel-session-door.js +0 -72
package/dist/workers.d.ts CHANGED
@@ -34,6 +34,11 @@ export { r2ArtifactStore, r2FileSource, ownerKeyAuth };
34
34
  export type OysterBindingResult = Awaited<ReturnType<GitBinding[keyof GitBinding]>> | Schema.Json | undefined;
35
35
  /** Verified backend custody is captured in the frame, never in a current-context field. */
36
36
  export type OysterInvocationHost = BackgroundFrameState & Readonly<{
37
+ /** This frame's guest binding packets and the wall time they waited. */
38
+ bindingWaits: {
39
+ count: number;
40
+ ms: number;
41
+ };
37
42
  artifact: Backend;
38
43
  declaration: AppDeclaration | null;
39
44
  /** The verified declared method; opaque backend and lifecycle frames have none. */
@@ -124,10 +129,10 @@ export declare class OysterRegistry<Env extends OysterWorkerEnv = OysterWorkerEn
124
129
  readonly kind: "policy";
125
130
  } | null;
126
131
  readonly access: "write" | "external";
132
+ readonly state: "pending" | "expired" | "denied" | "applied" | "requested" | "approved" | "claimed" | "outcome_unknown";
127
133
  readonly reason: "pending" | "expired" | "not-found" | "not-eligible" | "already-answered" | "stale-revision" | "declined" | "fenced" | "not-granted" | "read-only" | "in-flight" | "outcome-unknown" | "identity-conflict" | null;
128
134
  readonly updatedAt: number;
129
135
  readonly module: string;
130
- readonly state: "pending" | "expired" | "denied" | "applied" | "requested" | "approved" | "claimed" | "outcome_unknown";
131
136
  readonly recordId: string;
132
137
  readonly authorityFence: string;
133
138
  readonly requester: {
@@ -222,6 +227,8 @@ export declare class OysterRegistry<Env extends OysterWorkerEnv = OysterWorkerEn
222
227
  get(installationId: string): Installation | null;
223
228
  /** Durable store identity, regenerated only when the store itself is replaced. */
224
229
  generation(): string;
230
+ /** Permanent audit fact for the owner Home's empty installation notice. */
231
+ installationResetAt(): number | null;
225
232
  /** Native RPC returns a closed result; callers never classify a transported Error. */
226
233
  compareAndPut(installation: Installation, expectedAuthorityVersion: number, expectedGeneration: string, tenantId?: TenantId): Promise<InstallationCommit>;
227
234
  private writeInstallation;
@@ -387,6 +394,7 @@ export declare class OysterInstance<Env extends OysterWorkerEnv = OysterWorkerEn
387
394
  /** Resolve each guest packet against its immutable frame before any host effect. */
388
395
  bindingCall(raw: FrameBindingProps, method: string, input: readonly unknown[]): Promise<FrameBindingReply<OysterBindingResult>>;
389
396
  private executeBindingCall;
397
+ private dispatchBindingCall;
390
398
  /** Last provider-accepted ref recorded by this installation's journal. */
391
399
  gitTip(installationId: string, repository: string, ref: string, tenantId?: TenantId): Promise<string | null>;
392
400
  /** Join accepted fact identity and Carrier delivery in one local transaction. */
package/dist/workers.js CHANGED
@@ -38,6 +38,7 @@ import { AppInstanceError, } from "./index.js";
38
38
  import { createCloudflareAppInstance, r2ArtifactStore, createCloudflareInvocationGate, edgeVerifiedObjectCache, decodeFrameBindingProps, captureFrameBindingReply, frameBindingEntrypoint, backgroundFrameMethods, } from "./cloudflare.js";
39
39
  import { invocationFactsSchema, assertBackgroundBinding, admitBackgroundFrame, } from "./invocation.js";
40
40
  import { deliverBackground, deliverGitPush } from "./internal/delivery.js";
41
+ import { reportSlowInvocation } from "./internal/invocation-timing.js";
41
42
  import { releaseCache } from "./internal/host-gate.js";
42
43
  import { createOyster, } from "./host.js";
43
44
  import { createGitPushJournal } from "./git-journal.js";
@@ -66,7 +67,7 @@ const approvalHomePinRow = Schema.Struct({
66
67
  });
67
68
  /** The installation registry: one SQLite-backed Durable Object per Oyster. */
68
69
  export class OysterRegistry extends DurableObject {
69
- #generation;
70
+ #installationStore;
70
71
  /** Decided once, before this version writes anything, and never revised. */
71
72
  #installationsFromOlderOyster;
72
73
  #approval;
@@ -161,7 +162,7 @@ export class OysterRegistry extends DurableObject {
161
162
  this.#installationsFromOlderOyster = installationsFromOlderOyster(ctx.storage.sql);
162
163
  ctx.storage.sql.exec("CREATE TABLE IF NOT EXISTS oyster_approval_home (id INTEGER PRIMARY KEY CHECK (id = 1), tenant_id TEXT NOT NULL, origin TEXT NOT NULL) STRICT");
163
164
  ctx.storage.sql.exec("CREATE TABLE IF NOT EXISTS installations (installation_id TEXT PRIMARY KEY, record TEXT NOT NULL) STRICT");
164
- this.#generation = createInstallationStoreGeneration(ctx.storage.sql);
165
+ this.#installationStore = createInstallationStoreGeneration(ctx.storage);
165
166
  ctx.storage.sql.exec("CREATE TABLE IF NOT EXISTS boot_capabilities (id TEXT PRIMARY KEY, token_digest TEXT NOT NULL, expires_at INTEGER NOT NULL, record TEXT NOT NULL) STRICT");
166
167
  ensureAppSourceTables(ctx.storage.sql);
167
168
  this.#installationOperations = createInstallationOperations({
@@ -376,7 +377,11 @@ export class OysterRegistry extends DurableObject {
376
377
  }
377
378
  /** Durable store identity, regenerated only when the store itself is replaced. */
378
379
  generation() {
379
- return this.#generation();
380
+ return this.#installationStore.generation();
381
+ }
382
+ /** Permanent audit fact for the owner Home's empty installation notice. */
383
+ installationResetAt() {
384
+ return this.#installationStore.resetAt();
380
385
  }
381
386
  /** Native RPC returns a closed result; callers never classify a transported Error. */
382
387
  async compareAndPut(installation, expectedAuthorityVersion, expectedGeneration, tenantId = defaultTenant) {
@@ -762,9 +767,19 @@ export class OysterInstance extends DurableObject {
762
767
  const frame = this.frames.active(props.frameId);
763
768
  if (props.instanceId !== frame.facts.instanceId)
764
769
  throw new AppInstanceError("revoked");
770
+ const started = Date.now();
771
+ try {
772
+ return await this.dispatchBindingCall(frame, props, method, input);
773
+ }
774
+ finally {
775
+ frame.host.bindingWaits.count += 1;
776
+ frame.host.bindingWaits.ms += Date.now() - started;
777
+ }
778
+ }
779
+ async dispatchBindingCall(frame, props, method, input) {
765
780
  assertBackgroundBinding(frame, props.binding);
766
781
  // A guest packet is its own entry: exactly one registry read re-admits it.
767
- await this.assertCurrent(frame);
782
+ const current = await this.assertCurrent(frame);
768
783
  const row = this.bindings[props.binding];
769
784
  const descriptor = row?.methods[method];
770
785
  // Operations declared by the verified Release; absent bindings grant nothing.
@@ -784,10 +799,14 @@ export class OysterInstance extends DurableObject {
784
799
  throw new AppInstanceError("binding_unavailable");
785
800
  }
786
801
  const args = descriptor.decodeArgs(input);
787
- if (!descriptor
788
- .requiredOperations(args)
789
- .every((operation) => granted.includes(operation)))
802
+ const required = descriptor.requiredOperations(args);
803
+ if (!required.every((operation) => granted.includes(operation)))
790
804
  throw new AppInstanceError("binding_not_granted");
805
+ if (descriptor.requestedResource !== undefined) {
806
+ const selected = approvedBindingGrants(current, frame.host.declaration ?? emptyAppDeclaration, descriptor.requestedResource(args)).find((grant) => grant.binding === props.binding)?.operations ?? [];
807
+ if (!required.every((operation) => selected.includes(operation)))
808
+ throw new AppInstanceError("binding_not_granted");
809
+ }
791
810
  const result = await row.dispatch(this.#bindingContext, frame, props, method, args);
792
811
  if (this.frames.active(props.frameId) !== frame)
793
812
  throw new AppInstanceError("revoked");
@@ -848,8 +867,10 @@ export class OysterInstance extends DurableObject {
848
867
  .find((currentGrant) => currentGrant.binding === grant.binding)
849
868
  ?.operations.includes(operation) !== true)))
850
869
  throw new AppInstanceError("revoked");
870
+ return current;
851
871
  }
852
872
  async withFrame(raw, limits, work, tenantId = defaultTenant, methodName) {
873
+ const entered = Date.now();
853
874
  this.requireTenant(tenantId);
854
875
  const facts = Schema.decodeUnknownSync(invocationFactsSchema, {
855
876
  onExcessProperty: "error",
@@ -860,6 +881,7 @@ export class OysterInstance extends DurableObject {
860
881
  throw new AppInstanceError("instance_identity_mismatch");
861
882
  const release = this.release(facts.selection.releaseId);
862
883
  const resolved = await this.backends(release);
884
+ const verified = Date.now();
863
885
  if (resolved?.digest !== facts.artifactDigest)
864
886
  throw new AppInstanceError("invalid_invocation_facts");
865
887
  if (facts.subject.kind === "call" &&
@@ -895,6 +917,7 @@ export class OysterInstance extends DurableObject {
895
917
  };
896
918
  }
897
919
  let host = {
920
+ bindingWaits: { count: 0, ms: 0 },
898
921
  artifact: { release, ...resolved },
899
922
  declaration: resolved.declaration,
900
923
  origin: "unchecked",
@@ -904,7 +927,20 @@ export class OysterInstance extends DurableObject {
904
927
  // Facts carry the authority admitted at the request's top. The Instance
905
928
  // checks them against the owner state the host applied to it, never by
906
929
  // calling back up to the registry.
907
- return this.frames.run(scoped, host, (frame) => work(this.runtimeFor(limits), frame));
930
+ let admitted = verified;
931
+ try {
932
+ return await this.frames.run(scoped, host, (frame) => {
933
+ admitted = Date.now();
934
+ return work(this.runtimeFor(limits), frame);
935
+ });
936
+ }
937
+ finally {
938
+ reportSlowInvocation(methodName ?? facts.subject.kind, host, {
939
+ entered,
940
+ verified,
941
+ admitted,
942
+ });
943
+ }
908
944
  }
909
945
  release(releaseId) {
910
946
  const row = this.ctx.storage.sql
@@ -10,6 +10,7 @@ export declare const agentWorkflowOperationSchema: z.ZodEnum<{
10
10
  catalog: "catalog";
11
11
  armSchedule: "armSchedule";
12
12
  disarmSchedule: "disarmSchedule";
13
+ pauseSchedule: "pauseSchedule";
13
14
  schedules: "schedules";
14
15
  armEventTrigger: "armEventTrigger";
15
16
  disarmEventTrigger: "disarmEventTrigger";
@@ -26,6 +27,7 @@ export declare const agentAppWorkflowRequestSchema: z.ZodObject<{
26
27
  catalog: "catalog";
27
28
  armSchedule: "armSchedule";
28
29
  disarmSchedule: "disarmSchedule";
30
+ pauseSchedule: "pauseSchedule";
29
31
  schedules: "schedules";
30
32
  armEventTrigger: "armEventTrigger";
31
33
  disarmEventTrigger: "disarmEventTrigger";
package/dist/workflows.js CHANGED
@@ -11,6 +11,7 @@ export const agentWorkflowOperationSchema = z.enum([
11
11
  "catalog",
12
12
  "schedules",
13
13
  "armSchedule",
14
+ "pauseSchedule",
14
15
  "disarmSchedule",
15
16
  "eventTriggers",
16
17
  "armEventTrigger",
@@ -36,6 +36,13 @@
36
36
  | `@fungi.computer/oyster/git` | `EventSink`, `createGitDoor`, `signStandardWebhook` | The EVENTS binding contract, the git smart-HTTP door and Standard Webhooks signing. `GitBinding` comes from `@fungi.computer/agar/git`. |
37
37
  | `@fungi.computer/oyster/workers-git` | `oysterGitRoot`, `createOysterGitWorker`, `ownerOrKeyTenancy`, `oysterWorkerGit`, `gitAdminRoutes` | One Git root whose `hostFor` serves HTTP, MCP and Instances, or `host.git` and key/webhook routes for your own host. |
38
38
 
39
+ Standalone Oyster owners can `POST /agents/:agentId/archive` and
40
+ `POST /agents/:agentId/unarchive`. `GET /agents` lists active Agents;
41
+ `GET /agents?archived=true` lists only archived Agents. Archive preserves
42
+ existing Sessions and reads but refuses new Shiitake work with
43
+ `contract/archived`. It pauses Almanac and Loop schedules; restore resumes only
44
+ schedules paused by archive. The generated Agent API is in `docs/api/agents.md`.
45
+
39
46
  The host owns admission: it decides who may apply owner state and which
40
47
  selection a request carries. Oyster owns what happens to one Instance once the
41
48
  host has that authority: owner-state replay and conflict rules, Release
@@ -0,0 +1,175 @@
1
+ <!-- Generated by Botanical API docs (TypeDoc + typedoc-plugin-markdown). Do not edit. -->
2
+
3
+ [**@fungi.computer/oyster**](README.md)
4
+
5
+ ---
6
+
7
+ [@fungi.computer/oyster](modules.md) / agent-schedules
8
+
9
+ # agent-schedules
10
+
11
+ ## Type Aliases
12
+
13
+ ### AppAgentScheduleListInput
14
+
15
+ ```ts
16
+ type AppAgentScheduleListInput = z.input<
17
+ typeof appAgentScheduleListInputSchema
18
+ >;
19
+ ```
20
+
21
+ A single bounded native read, not an all-Agent inventory grant.
22
+
23
+ ---
24
+
25
+ ### AgentScheduleTarget
26
+
27
+ ```ts
28
+ type AgentScheduleTarget = z.output<typeof agentScheduleTargetSchema>;
29
+ ```
30
+
31
+ Identity to admit before acquiring the corresponding Agent owner.
32
+
33
+ ---
34
+
35
+ ### AgentSchedulePage
36
+
37
+ ```ts
38
+ type AgentSchedulePage = typeof agentSchedulePageSchema.Type;
39
+ ```
40
+
41
+ One Agent's page, with no directory fan-out or availability policy.
42
+
43
+ ---
44
+
45
+ ### AgentScheduleControlReceipt
46
+
47
+ ```ts
48
+ type AgentScheduleControlReceipt =
49
+ typeof agentScheduleControlReceiptSchema.Type;
50
+ ```
51
+
52
+ Content-free acknowledgement of the native owner's completed transition.
53
+
54
+ ## Variables
55
+
56
+ ### appAgentScheduleListInputSchema
57
+
58
+ ```ts
59
+ const appAgentScheduleListInputSchema: ZodObject<
60
+ {
61
+ agentId: ZodString;
62
+ after: ZodOptional<
63
+ ZodObject<
64
+ {
65
+ agentId: ZodString;
66
+ kind: ZodUnion<readonly [ZodLiteral<"almanac">, ZodLiteral<"loop">]>;
67
+ after: ZodOptional<ZodString>;
68
+ },
69
+ $strict
70
+ >
71
+ >;
72
+ limit: ZodDefault<ZodNumber>;
73
+ },
74
+ $strict
75
+ >;
76
+ ```
77
+
78
+ The App selects one Agent; its host must admit that target before opening it.
79
+
80
+ ---
81
+
82
+ ### agentScheduleBindingArgs
83
+
84
+ ```ts
85
+ const agentScheduleBindingArgs: object;
86
+ ```
87
+
88
+ Both hosts decode the ordinary AGENTS packet with the native owner's grammar.
89
+
90
+ #### Type Declaration
91
+
92
+ | Name | Type | Description |
93
+ | ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
94
+ | <a id="property-schedules"></a> `schedules` | `ZodTuple`\<\[`ZodObject`\<\{ `agentId`: `ZodString`; `after`: `ZodOptional`\<`ZodObject`\<\{ `agentId`: `ZodString`; `kind`: `ZodUnion`\<readonly \[`ZodLiteral`\<...\>, `ZodLiteral`\<...\>\]\>; `after`: `ZodOptional`\<`ZodString`\>; \}, `$strict`\>\>; `limit`: `ZodDefault`\<`ZodNumber`\>; \}, `$strict`\>\], `null`\> | One bounded content-bearing read, admitted independently of manage. |
95
+ | <a id="property-pauseschedule"></a> `pauseSchedule` | `ZodTuple`\<\[`ZodDiscriminatedUnion`\<\[`ZodObject`\<\{ `kind`: `ZodLiteral`\<`"almanac"`\>; `agentId`: `ZodString`; `scheduleId`: `ZodString` & `ZodType`\<`string`, `string`, `$ZodTypeInternals`\<`string`, `string`\>\>; \}, `$strict`\>, `ZodObject`\<\{ `kind`: `ZodLiteral`\<`"loop"`\>; `agentId`: `ZodString`; `sessionId`: `ZodString` & `ZodType`\<`string`, `string`, `$ZodTypeInternals`\<`string`, `string`\>\>; `loopId`: `ZodString` & `ZodType`\<`string`, `string`, `$ZodTypeInternals`\<`string`, `string`\>\>; \}, `$strict`\>\], `"kind"`\>\], `null`\> | Pause the exact listed schedule, retaining future resume and accepted work. |
96
+ | <a id="property-deleteschedule"></a> `deleteSchedule` | `ZodTuple`\<\[`ZodDiscriminatedUnion`\<\[`ZodObject`\<\{ `kind`: `ZodLiteral`\<`"almanac"`\>; `agentId`: `ZodString`; `scheduleId`: `ZodString` & `ZodType`\<`string`, `string`, `$ZodTypeInternals`\<`string`, `string`\>\>; \}, `$strict`\>, `ZodObject`\<\{ `kind`: `ZodLiteral`\<`"loop"`\>; `agentId`: `ZodString`; `sessionId`: `ZodString` & `ZodType`\<`string`, `string`, `$ZodTypeInternals`\<`string`, `string`\>\>; `loopId`: `ZodString` & `ZodType`\<`string`, `string`, `$ZodTypeInternals`\<`string`, `string`\>\>; \}, `$strict`\>\], `"kind"`\>\], `null`\> | Cancel future occurrences of the exact identity without erasing history. |
97
+
98
+ ---
99
+
100
+ ### agentSchedulePageSchema
101
+
102
+ ```ts
103
+ const agentSchedulePageSchema: Schema.Struct<{
104
+ items: Schema.$Array<Schema.Union<readonly [Schema.Struct<{
105
+ agentId: Schema.String;
106
+ kind: Schema.Literal<"almanac">;
107
+ schedule: Schema.Struct<{
108
+ id: Schema.String;
109
+ sessionId: Schema.String;
110
+ prompt: Schema.String;
111
+ cron: Schema.NullOr<...>;
112
+ nextDueAt: Schema.Int;
113
+ state: Schema.Literals<...>;
114
+ lastCommandId: Schema.NullOr<...>;
115
+ lastError: Schema.NullOr<...>;
116
+ attempt: Schema.Int;
117
+ }>;
118
+ }>, Schema.Struct<{
119
+ agentId: Schema.String;
120
+ kind: Schema.Literal<"loop">;
121
+ schedule: Schema.Struct<{
122
+ sessionId: Schema.String;
123
+ loopId: Schema.String;
124
+ origin: Schema.Literals<...>;
125
+ expiresAt: Schema.NullOr<...>;
126
+ prompt: Schema.String;
127
+ mode: Schema.Literals<...>;
128
+ cron: Schema.NullOr<...>;
129
+ state: Schema.Literals<...>;
130
+ commandId: Schema.String;
131
+ reason: Schema.NullOr<...>;
132
+ nextDueAt: Schema.NullOr<...>;
133
+ lastError: Schema.NullOr<...>;
134
+ consecutiveFailures: Schema.Int;
135
+ }>;
136
+ }>]>>;
137
+ next: Schema.NullOr<Schema.Struct<{
138
+ agentId: Schema.String;
139
+ kind: Schema.Literals<readonly ["almanac", "loop"]>;
140
+ after: Schema.optionalKey<Schema.String>;
141
+ }>>;
142
+ }>;
143
+ ```
144
+
145
+ A bounded content-bearing page; owner failures reject rather than look empty.
146
+
147
+ ---
148
+
149
+ ### agentScheduleControlReceiptSchema
150
+
151
+ ```ts
152
+ const agentScheduleControlReceiptSchema: Schema.Union<
153
+ readonly [
154
+ Schema.Struct<{
155
+ agentId: Schema.String;
156
+ kind: Schema.Literal<"almanac">;
157
+ scheduleId: Schema.String;
158
+ state: Schema.Literals<
159
+ readonly ["active", "paused", "cancelled", "finished"]
160
+ >;
161
+ }>,
162
+ Schema.Struct<{
163
+ agentId: Schema.String;
164
+ kind: Schema.Literal<"loop">;
165
+ sessionId: Schema.String;
166
+ loopId: Schema.String;
167
+ state: Schema.Literals<
168
+ readonly ["active", "paused", "finished", "failed", "cancelled"]
169
+ >;
170
+ }>,
171
+ ]
172
+ >;
173
+ ```
174
+
175
+ Manage-only result: exact target and native state, never prompt or history.
@@ -167,6 +167,26 @@ type OysterAgents = Readonly<{
167
167
  )[];
168
168
  }>[]
169
169
  >;
170
+ setArchived: Promise<
171
+ | Readonly<{
172
+ archived: boolean;
173
+ revision: number;
174
+ }>
175
+ | Readonly<{
176
+ error:
177
+ | "not_found"
178
+ | "not_granted"
179
+ | "self"
180
+ | "not_creator"
181
+ | "running"
182
+ | "pending"
183
+ | "unreadable"
184
+ | "archived";
185
+ message?: string;
186
+ archived?: boolean;
187
+ revision?: number;
188
+ }>
189
+ >;
170
190
  create: Promise<
171
191
  Readonly<{
172
192
  agentId: string;
@@ -301,7 +321,12 @@ type OysterAgents = Readonly<{
301
321
  }>;
302
322
  ```
303
323
 
304
- Where an Oyster's agents live and run.
324
+ Where an Oyster's agents live and run. Archive is non-destructive: `list()`
325
+ hides archived agents, and `list({ archived: true })` shows only archives.
326
+ Archived agents keep existing reads, replays and settlements, but refuse new
327
+ Sessions, prompts and steers with `contract/archived`. Archive refuses non-idle
328
+ Session work or unsettled delegations; it pauses Almanac and Loop schedules and
329
+ restores only archive-paused schedules on unarchive.
305
330
 
306
331
  ---
307
332
 
@@ -358,20 +383,16 @@ optional bearer.
358
383
  ### agentCapabilities()
359
384
 
360
385
  ```ts
361
- function agentCapabilities(
362
- agents,
363
- liveKey,
364
- ): readonly Readonly<object & object>[];
386
+ function agentCapabilities(agents): readonly Readonly<object & object>[];
365
387
  ```
366
388
 
367
389
  Agent adapters admitted against each App's declared capabilities.
368
390
 
369
391
  #### Parameters
370
392
 
371
- | Parameter | Type |
372
- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
373
- | `agents` | [`OysterAgents`](#oysteragents) |
374
- | `liveKey` | (`keyId`) => `Promise`\< \| `Readonly`\<\{ `keyId`: `string`; `owner`: `string`; `grantVersion`: `number`; `grants`: readonly `Readonly`\<\{ `capability`: [`OysterKeyCapability`](keys.md#oysterkeycapability); `targets`: `GrantTargets`; \}\>[]; \}\> \| `null`\> |
393
+ | Parameter | Type |
394
+ | --------- | ------------------------------- |
395
+ | `agents` | [`OysterAgents`](#oysteragents) |
375
396
 
376
397
  #### Returns
377
398
 
@@ -382,7 +403,7 @@ readonly `Readonly`\<`object` & `object`\>[]
382
403
  ### agentApprovalRoutes()
383
404
 
384
405
  ```ts
385
- function agentApprovalRoutes(agents): Hono<OysterEnv>;
406
+ function agentApprovalRoutes(agents): Routes<OysterEnv>;
386
407
  ```
387
408
 
388
409
  Host-owned direct approval under the admitted owner; never an App capability.
@@ -395,14 +416,14 @@ Host-owned direct approval under the admitted owner; never an App capability.
395
416
 
396
417
  #### Returns
397
418
 
398
- `Hono`\<[`OysterEnv`](host.md#oysterenv)\>
419
+ [`Routes`](authorization.md#routes)\<[`OysterEnv`](host.md#oysterenv)\>
399
420
 
400
421
  ---
401
422
 
402
423
  ### agentMcpServerRoutes()
403
424
 
404
425
  ```ts
405
- function agentMcpServerRoutes(agents): Hono<OysterEnv>;
426
+ function agentMcpServerRoutes(agents): Routes<OysterEnv>;
406
427
  ```
407
428
 
408
429
  Host-owned Agent MCP server custody for the owner directly; never an App
@@ -416,4 +437,4 @@ capability. Bearer tokens go in and never come back out.
416
437
 
417
438
  #### Returns
418
439
 
419
- `Hono`\<[`OysterEnv`](host.md#oysterenv)\>
440
+ [`Routes`](authorization.md#routes)\<[`OysterEnv`](host.md#oysterenv)\>
@@ -131,7 +131,7 @@ Whether `writer` may mutate `scope`; anything else is `owner_required`.
131
131
  | Parameter | Type |
132
132
  | --------- | --------------------------------------- |
133
133
  | `writer` | [`AppStorageWriter`](#appstoragewriter) |
134
- | `scope` | `"member"` \| `"team"` |
134
+ | `scope` | `"team"` \| `"member"` |
135
135
 
136
136
  #### Returns
137
137