@agentorg/cli 0.0.3 → 0.0.4

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 (153) hide show
  1. package/README.md +14 -10
  2. package/dist/bundled/index.json +4 -4
  3. package/dist/bundled/{sha256-87e121cbe58279f3a633e61c9773b61fc17fd53eac3d7c6f037925cbfd5d5384.agentorg → sha256-01d69bc3888c2a53963f4413d47de909d129ad27c78e9af6d830bb50c3478419.agentorg} +0 -0
  4. package/dist/bundled/{sha256-51ecf151e590f5e57f28229d4cb36e4932a2f1670e50ddf1a3ccf335a1ee146d.agentorg → sha256-84165e3be5c904fc971d983dab31102e07cca725d8629a6fd7d118fa3a0a88b8.agentorg} +0 -0
  5. package/dist/bundled/sha256-ade9132b3f34b4c39db92adeadc7e540dc745e4a81b5b54f5d45bf9ec92bca75.agentorg +0 -0
  6. package/dist/bundled/{sha256-b76ec31282e5b863ee9569dfd9d50b283a21101cbe1b3fac23d1cbcf16b9a408.agentorg → sha256-f4330f5987f37d8cf3aeb44d2f831b573641a87186daa2f811f0c35ba04804f0.agentorg} +0 -0
  7. package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/build.d.ts +2 -2
  8. package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/build.js +14 -4
  9. package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/hub-actor.js +8 -0
  10. package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/index.d.ts +1 -1
  11. package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/index.js +1 -1
  12. package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/router.js +40 -16
  13. package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/state.d.ts +63 -0
  14. package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/state.js +177 -36
  15. package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/storage.d.ts +2 -1
  16. package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/storage.js +3 -2
  17. package/{node_modules → dist/node_modules}/@agentorg/hub/package.json +3 -0
  18. package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/hub.d.ts +43 -3
  19. package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/hub.js +40 -3
  20. package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/index.d.ts +1 -0
  21. package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/index.js +1 -0
  22. package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/installer.d.ts +37 -0
  23. package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/installer.js +34 -3
  24. package/dist/node_modules/@agentorg/interfaces/dist/src/rules.d.ts +35 -0
  25. package/dist/node_modules/@agentorg/interfaces/dist/src/rules.js +37 -0
  26. package/dist/node_modules/@agentorg/kit/dist/src/chat.d.ts +37 -0
  27. package/dist/node_modules/@agentorg/kit/dist/src/chat.js +131 -0
  28. package/dist/node_modules/@agentorg/kit/dist/src/components.d.ts +94 -0
  29. package/dist/node_modules/@agentorg/kit/dist/src/components.js +66 -0
  30. package/dist/node_modules/@agentorg/kit/dist/src/icons.d.ts +17 -0
  31. package/dist/node_modules/@agentorg/kit/dist/src/icons.js +30 -0
  32. package/dist/node_modules/@agentorg/kit/dist/src/index.d.ts +6 -0
  33. package/dist/node_modules/@agentorg/kit/dist/src/index.js +10 -0
  34. package/dist/node_modules/@agentorg/kit/dist/src/markdown.d.ts +9 -0
  35. package/dist/node_modules/@agentorg/kit/dist/src/markdown.js +14 -0
  36. package/dist/node_modules/@agentorg/kit/dist/src/resizable.d.ts +5 -0
  37. package/dist/node_modules/@agentorg/kit/dist/src/resizable.js +8 -0
  38. package/dist/node_modules/@agentorg/kit/dist/src/styles.d.ts +11 -0
  39. package/dist/node_modules/@agentorg/kit/dist/src/styles.js +166 -0
  40. package/dist/node_modules/@agentorg/kit/package.json +44 -0
  41. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/frame/runtime.js +172 -17
  42. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/host/runner.js +168 -11
  43. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/client.d.ts +18 -0
  44. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/client.js +24 -3
  45. package/dist/node_modules/@agentorg/sdk/dist/src/frame-base.d.ts +8 -0
  46. package/dist/node_modules/@agentorg/sdk/dist/src/frame-base.js +64 -0
  47. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-entry.js +4 -4
  48. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-host.d.ts +1 -10
  49. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-host.js +0 -23
  50. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-protocol.d.ts +0 -8
  51. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame.d.ts +0 -2
  52. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame.js +0 -8
  53. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/host.js +5 -0
  54. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/index.d.ts +1 -1
  55. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/module-host.d.ts +6 -1
  56. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/module-host.js +24 -1
  57. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/module.d.ts +30 -1
  58. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/package.js +111 -6
  59. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/runtime.d.ts +22 -1
  60. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/runtime.js +114 -0
  61. package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/testing.d.ts +14 -2
  62. package/dist/node_modules/@agentorg/sdk/dist/src/testing.js +89 -0
  63. package/{node_modules → dist/node_modules}/@agentorg/shell/dist/app.css +27 -144
  64. package/dist/node_modules/@agentorg/shell/dist/app.js +219 -0
  65. package/{node_modules → dist/node_modules}/@agentorg/shell/package.json +1 -0
  66. package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/index.d.ts +1 -1
  67. package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/ops.d.ts +14 -1
  68. package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/ops.js +22 -2
  69. package/dist/src/cli.js +23 -0
  70. package/dist/src/gateway.js +42 -1
  71. package/dist/src/rules.d.ts +71 -0
  72. package/dist/src/rules.js +157 -0
  73. package/package.json +13 -16
  74. package/dist/bundled/sha256-e4c0e857cea3a721998effe2ca859c4011978b9bc36e63c058bfc17c27a1772e.agentorg +0 -0
  75. package/node_modules/@agentorg/sdk/dist/src/testing.js +0 -51
  76. package/node_modules/@agentorg/shell/dist/app.js +0 -9
  77. /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/hub-actor.d.ts +0 -0
  78. /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/logs.d.ts +0 -0
  79. /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/logs.js +0 -0
  80. /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/net.d.ts +0 -0
  81. /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/net.js +0 -0
  82. /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/processes.d.ts +0 -0
  83. /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/processes.js +0 -0
  84. /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/router.d.ts +0 -0
  85. /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/server.d.ts +0 -0
  86. /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/server.js +0 -0
  87. /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/validate-worker.d.ts +0 -0
  88. /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/validate-worker.js +0 -0
  89. /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/validate.d.ts +0 -0
  90. /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/validate.js +0 -0
  91. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/account-login.d.ts +0 -0
  92. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/account-login.js +0 -0
  93. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/chat.d.ts +0 -0
  94. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/chat.js +0 -0
  95. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/http-egress.d.ts +0 -0
  96. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/http-egress.js +0 -0
  97. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/kv.d.ts +0 -0
  98. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/kv.js +0 -0
  99. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/layout.d.ts +0 -0
  100. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/layout.js +0 -0
  101. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/llm-session.d.ts +0 -0
  102. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/llm-session.js +0 -0
  103. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/storage-admin.d.ts +0 -0
  104. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/storage-admin.js +0 -0
  105. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/ui-shell.d.ts +0 -0
  106. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/ui-shell.js +0 -0
  107. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/ui-view.d.ts +0 -0
  108. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/ui-view.js +0 -0
  109. /package/{node_modules → dist/node_modules}/@agentorg/interfaces/package.json +0 -0
  110. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/build.d.ts +0 -0
  111. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/build.js +0 -0
  112. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/canonical.d.ts +0 -0
  113. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/canonical.js +0 -0
  114. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/cli.d.ts +0 -0
  115. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/cli.js +0 -0
  116. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/client-http.d.ts +0 -0
  117. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/client-http.js +0 -0
  118. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/describe.d.ts +0 -0
  119. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/describe.js +0 -0
  120. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/errors.d.ts +0 -0
  121. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/errors.js +0 -0
  122. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-entry.d.ts +0 -0
  123. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-protocol.js +0 -0
  124. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/host-main.d.ts +0 -0
  125. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/host-main.js +0 -0
  126. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/host.d.ts +0 -0
  127. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/index.js +0 -0
  128. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/interface.d.ts +0 -0
  129. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/interface.js +0 -0
  130. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/manifest-api.d.ts +0 -0
  131. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/manifest-api.js +0 -0
  132. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/manifest.d.ts +0 -0
  133. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/manifest.js +0 -0
  134. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/module.js +0 -0
  135. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/package.d.ts +0 -0
  136. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/person-commands.d.ts +0 -0
  137. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/person-commands.js +0 -0
  138. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/tar.d.ts +0 -0
  139. /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/tar.js +0 -0
  140. /package/{node_modules → dist/node_modules}/@agentorg/sdk/package.json +0 -0
  141. /package/{node_modules → dist/node_modules}/@agentorg/shell/dist/agent-bindings.js +0 -0
  142. /package/{node_modules → dist/node_modules}/@agentorg/shell/dist/index.html +0 -0
  143. /package/{node_modules → dist/node_modules}/@agentorg/shell/src/agent-bindings.ts +0 -0
  144. /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/bytes.d.ts +0 -0
  145. /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/bytes.js +0 -0
  146. /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/frames.d.ts +0 -0
  147. /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/frames.js +0 -0
  148. /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/index.js +0 -0
  149. /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/transports.d.ts +0 -0
  150. /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/transports.js +0 -0
  151. /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/yamux.d.ts +0 -0
  152. /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/yamux.js +0 -0
  153. /package/{node_modules → dist/node_modules}/@agentorg/wire/package.json +0 -0
package/README.md CHANGED
@@ -12,14 +12,15 @@ AgentOrg as a dynamic system: Actors and widgets are modules in content-addresse
12
12
 
13
13
  ## Packages
14
14
 
15
- - `@agentorg/sdk`: `defineInterface` (with `method` and `event`) for `rpc`, `stream` and `http` interfaces; `defineActor` for host modules and `defineWidget` for view modules, with typed slot and export handles; the errors `NotConnected`, `Refused` and `OutcomeUnknown`; and `createTestContext` (`@agentorg/sdk/testing`), which runs a module without a Hub. An `rpc` handler gets its input and `{ caller }`, the calling Actor as the Hub names it, and `emit(event, payload, { to })` sends an event only to the subscriptions of the Actor `to` names, so a provider serving several consumers keeps each one's events its own. In `createTestContext`, `call` takes the caller as a fourth argument (the module's own Actor by default) and `emitted` records each event's `to`. `@agentorg/sdk/client` connects a program outside the Hub as an Actor: `connect({hubUrl, actorId, credential, slots, exports})` gives the same handles as a module's context, on the same runtime, with slots bound as the Hub's notices say and `exports.add`/`withdraw()` over the channel; As in a module, implement in `start` (run before the channel opens) and use slots from `onBind`, which runs when a slot becomes usable: bound, or its provider back. `openChannel` is the wire layer beneath it, without local checks. `http` slots `fetch` and `http` exports `serve` over the Hub's stream (HTTP/1.1, one request per stream, `node:http` loaded only when used). The request line carries the consumer's absolute URL, so a handler's `request.url` is exactly the URL the consumer fetched, scheme included; a request line that isn't absolute, or whose host isn't the `Host` header's, is answered 400. A handler that throws `Refused`, `NotConnected` or `OutcomeUnknown` reaches the consumer's `fetch` as that same error (carried as a 502 with an `agentorg-error` header); any other throw is a plain 500 response. `@agentorg/sdk/host` runs a package Actor's host modules in one process, on the same runtime: `runHost({packageDir, actorId, channel, log})` imports each `host` module's bundle, runs every `start`, then says hello over the channel, with each module's slots and exports named `<module>.<name>`. The program the Hub runs is `@agentorg/sdk/host/runner.js`, one self-contained file: it takes `<packageDir> <actorId>`, uses fd 3 as the channel, writes `ctx.log` as JSON lines on stderr, and exits non-zero if a `start` throws or an exception goes uncaught. The SDK's errors keep their class and code between a package's bundle and the runner, though each carries its own copy of the SDK. It reads only itself and the package's folder, so it runs under Node's permission model with exactly those two paths allowed (as real paths: the allow list doesn't follow symlinks).
15
+ - `@agentorg/sdk`: `defineInterface` (with `method` and `event`) for `rpc`, `stream` and `http` interfaces; `defineActor` for host modules and `defineWidget` for view modules, with typed slot and export handles; the errors `NotConnected`, `Refused` and `OutcomeUnknown`; and `createTestContext` (`@agentorg/sdk/testing`), which runs a module without a Hub. An `rpc` handler gets its input and `{ caller }`, the calling Actor as the Hub names it, and `emit(event, payload, { to })` sends an event only to the subscriptions of the Actor `to` names, so a provider serving several consumers keeps each one's events its own. In `createTestContext`, `call` takes the caller as a fourth argument (the module's own Actor by default) and `emitted` records each event's `to`. `@agentorg/sdk/client` connects a program outside the Hub as an Actor: `connect({hubUrl, actorId, credential, slots, exports})` gives the same handles as a module's context, on the same runtime, with slots bound as the Hub's notices say and `exports.add`/`withdraw()` over the channel; As in a module, implement in `start` (run before the channel opens) and use slots from `onBind`, which runs when a slot becomes usable: bound, or its provider back. `openChannel` is the wire layer beneath it, without local checks. `http` slots `fetch` and `http` exports `serve` over the Hub's stream (HTTP/1.1, one request per stream, `node:http` loaded only when used). The request line carries the consumer's absolute URL, so a handler's `request.url` is exactly the URL the consumer fetched, scheme included; a request line that isn't absolute, or whose host isn't the `Host` header's, is answered 400. A handler that throws `Refused`, `NotConnected` or `OutcomeUnknown` reaches the consumer's `fetch` as that same error (carried as a 502 with an `agentorg-error` header); any other throw is a plain 500 response. `@agentorg/sdk/host` runs a package Actor's host modules in one process, on the same runtime: `runHost({packageDir, actorId, channel, log})` imports each `host` module's bundle, runs every `start`, then says hello over the channel, with each module's slots and exports named `<module>.<name>`. The program the Hub runs is `@agentorg/sdk/host/runner.js`, one self-contained file: it takes `<packageDir> <actorId>`, uses fd 3 as the channel, writes `ctx.log` as JSON lines on stderr, and exits non-zero if a `start` throws or an exception goes uncaught. The SDK's errors keep their class and code between a package's bundle and the runner, though each carries its own copy of the SDK. It reads only itself and the package's folder, so it runs under Node's permission model with exactly those two paths allowed (as real paths: the allow list doesn't follow symlinks). A slot made at run time, another Actor's export exposed to this Actor rather than declared by its package, isn't in `ctx.slots`: `ctx.exposed()` lists those bound now, each as `{slot, described, provider: {actor, export}, call, on}`, with `described` the export's JSON Schemas and `call` one function per method, its values checked by the Hub rather than locally; `ctx.onExposed(fn)` runs after one comes or goes. Every host module of the Actor sees them, under the Actor's slot name; a view module sees none. The Hub's `slot` notice carries such a slot's `exposed` (the export's described interface and its provider) while it is bound, one notice each, including right after hello, which names them among `bound`; `createTestContext` fakes one with `expose(slot, iface, handlers)` and `unexpose(slot)`.
16
16
  - `@agentorg/interfaces`: the standard interfaces `kv@1`, `ui.view@1`, `chat@1` (a conversation with an agent; a `tool` message may carry the call it stands for, its name, `running`/`done`/`refused`, input and output, sent as `running` when it starts and again under the same id when it ends), `llm.session@1` (stateless model inference, with function tools), `account.login@1` (signing in to an outside account, driven by a person or a program), `http.egress@1` (HTTPS to the public internet), `storage.admin@1` (seeding a new Actor's empty stores), `layout@1` (the person's dashboard), `installer@1` (planning and installing a package) and `ui.shell@1` (what the shell offers a view in its frame: opening an https address and starting sign-in), and the Hub's management interfaces `hub.packages@1`, `hub.actors@1`, `hub.grants@1`, `hub.bindings@1`, `hub.exports@1` and `hub.audit@1`.
17
+ - `@agentorg/kit`: the shell's own components, for the shell and for any view, drawn in the theme's tokens by the kit's styles (`KIT_CSS`, every class `kit-`, put first in the document's head when the kit is imported, so a view's own styles win). Accessible primitives on Radix: `Dialog` (focus held inside; Escape and a click outside close it), `Menu` with `MenuItem`, `Switch` and `Tabs`; plain elements for the rest: `Button` (`primary`, `quiet`), `IconButton` (its label is its name), `Field`, `Select` (the browser's own), `Card`, `List`, `Table`, `Meter` and `Actions`; layout pieces that fill and adapt: `Stack`, `Row`, `Fill`, `Scroll`, and `ResizableGroup`, `ResizablePanel` and `ResizeHandle` from react-resizable-panels. `Markdown` renders an agent's GitHub-flavored markdown with react-markdown, safe as it streams: remend first closes what's still open, and raw HTML is shown as text. `Chat` is a conversation on assistant-ui's primitives over an external store: the caller keeps the messages (`ChatEntry`, as `chat@1` has them) and runs the turns (`onSend`, `onCancel`, `onRetry`, `onEarlier`). The person's messages, each run of replies and tool messages as one reply in markdown, a tool message as a card (its name, how it ended, what went in and came back) when it says which tool ran and as its line otherwise; Enter sends, never mid-composition or during a turn, when Send is Stop; a refused send puts the text back; it fills its parent and goes compact below 460 px wide. Its tests run on happy-dom.
17
18
  - `@agentorg/wire`: the channel: yamux streams, length-prefixed JSON frames, stream headers and transports.
18
- - `installer`: a bundled host package that turns packages into working Actors, exporting `installer@1`. Bound to the Hub's management (`hub.packages`, `hub.actors`, `hub.grants`, `hub.exports` and `hub.bindings`, which makes it the person's delegated manager) and to `storage.admin@1`, it proposes and installs. `plan({package})` lists each slot the package doesn't wire itself, with the exports that could serve it now: exactly its interface and schema hash, on Actors that aren't stopped or closed. `install({package, name, connections, start?})` makes the Actor with exactly those connections, all or none. It grants nothing its caller couldn't: each connection's export side must be the caller's (the provider, bound to that export, or a manager), else the whole install is refused (`forbidden`, listing every such connection) and nothing is made. It seeds each store bound to `storage.kv` from the package's `seed` (an object of key to value per `module.slot`), starts the Actor if asked (a seed or start that fails closes it), and lists the slots left unbound and the seeds that couldn't land (`unseeded`). It never picks a connection itself. Bound to the person's `layout@1` too, it carries a system between homes as data: `exportSystem()`, for a manager only (it lists every binding and the person's layout; any other caller is refused `forbidden`), gives an `agentorg.system/1` composition (every package Actor that isn't closed, by a name of its own, with its package as `name@version#hash` and whether it runs; the connections among them and to the built-in Actors, as `{consumer, slot, provider, export}` by names; and the layout's placements), never credentials, tokens, stores or logs, and lists what it leaves out (external Actors and what connects to them). `importSystem({composition})` makes it again with the caller's authority (connecting the new Actors to each other takes a manager): it creates the Actors whose packages are here (a taken name gets a suffix), binds the connections, seeds, starts what ran and places the layout, all or nothing, and lists what it couldn't: a package that isn't here or is another version (whoever holds the composition's folder adds its archives first) and what depends on it, an Actor that needs a sign-in, a seed that can't land, and the placements unless the caller holds the person's layout. The exporting home's installer stays out: every home has its own. An import never grants management: a connection to `hub` or to `storage.admin` is recorded by an export but never made by an import, even a manager's (a composition may come from anyone); it comes back in `ungranted`, for the person to grant one by one.
19
- - `@agentorg/hub`: the core. Its state, in `node:sqlite` in a private home: Actors, a verified package store (`hub.packages.add` takes an archive by path; `hub.packages.build` takes a package's source as data, `package.json` and files under `src/` up to 768 KiB, builds it as `agentorg build` does, but reading no tsconfig, in a scratch folder of the home that is always removed: its files import only `@agentorg/sdk`, `@agentorg/interfaces` and `zod` by name, nothing outside the package's folder, and nothing by a pattern; at most 16 modules, 16 MiB built and 60 s; one build per caller at a time; and it adds the result. Reading each module's definition runs the source's code, so the Hub runs it in the same OS sandbox as host processes, and where those can't start, `build` is refused `unsupported` with the same reason. A failed build is `Refused("build")` with the build's message, which names no path outside the package), what each Actor takes and offers, bindings, binding requests and an audit trail. A binding is the grant, and it needs both ends: the export side (the provider, an Actor already bound to that export, or a manager) and the slot side (the consumer itself, or a manager). Through `hub.grants@1`, a caller with both ends binds; one with a single end approves the other end's open request or asks that end's approvers; one with neither is refused. A decision goes to the request's approvers and its requester, which can also read its requests' outcomes with `mine`. A manager is any Actor bound to `hub.bindings@1`. `hub.actors.create` can bind the new Actor's slots at once, with the creator's export side. The router serves it over WebSocket (`listen`), one yamux channel per Actor: a client's first stream is `hello` with its credential, then every `call`, `subscribe`, `open` and `http` stream is resolved through its binding, validated against the interface's JSON Schemas in both directions (ajv, 2020-12, in a pool of worker threads, each check under a time budget, since schemas come from Actors), forwarded to the provider with the caller named, and audited. A provider accepts or refuses an `open` or `http` stream with one body before any raw bytes. An Actor offers and withdraws exports at run time on its own channel (`offer`, `withdraw`). An Actor learns which of its slots are bound from hello's result, then from a `slot` notice on each change. A pipe the Hub makes for a package Actor's process says hello as that Actor without a credential (the pipe is the proof) and declares nothing (the manifest does). Every `serve` stream names the caller and the caller's slot, so a provider can keep state per consumer slot. `hub.actors.start` runs a package Actor's host modules in their own process: `node` under its permission model (reading only the runner and the package's folder, no child processes or workers), with an empty environment, a 256 MB heap and the channel on fd 3, inside the OS sandbox (`sandbox-exec` on macOS, a user, network and PID namespace with `unshare` on Linux), so it has no network, no DNS and no other process to signal. The Actor is running once its process says hello, within 30 s. `stop` sends SIGTERM, then SIGKILL after 5 s. A process that exits otherwise has crashed: it is restarted after a backoff from 1 s doubling to 60 s (starting over after 10 minutes up), and `hub.actors.get` counts `restarts` and keeps the `lastExit`. Every Actor's record in `hub.actors` says whether it is `connected`, holding a channel to the Hub now: an external Actor while its program is connected (the person while the app runs: its gateway holds the person's channel), a package Actor while its process is, so a running one isn't while its process starts or restarts; the built-in Actors are the Hub itself and have none. `hub.actors`' `changed` event names an Actor whose record may differ: made, started, stopped, closed, its process exited, or connected or gone; the audit trail records no connections. Actors running when the Hub stopped are started again when it opens. Where the sandbox can't run (stock Ubuntu restricts unprivileged user namespaces), `start` is refused with `unsupported` and every package Actor's `host` says why and what to change; the Hub probes again at each start. `hub.actors.logs` reads an Actor's log lines: its `ctx.log` entries and anything else its process writes (stdout as `info`, stderr as `error`). For the person's shell, `Hub.viewCall` and `Hub.viewSubscribe` run a package Actor's view module's calls and events in the Hub's process, as that Actor, through `<module>.<slot>`, and `Hub.viewSlots` tells the gateway a view module's slots: those bound now, then each change, and each bound again when it is usable again: its provider's channel comes back, or its Actor's own, since a view calls only while its Actor runs; `hub.actors.get` lists a package Actor's `views`. `Hub.viewLog` writes a view module's log line to its Actor's log, marked with the module; the Hub bounds each line itself (a known level, 4 KiB of text, 16 fields of 1 KiB) and rotates each Actor's log once at 1 MiB. The built-in `storage` Actor exports `kv@1`: one store per consumer slot (keyed by the consumer and slot the router names), in `<home>/storage.db`; values up to 256 KiB and 64 MiB per Actor, past which `Refused("quota")`; stores outlive unbinding and go when their Actor is closed. Its `admin` export (`storage.admin@1`, bound only to the installer) seeds a new Actor's store from its package's `seed`: all entries or none, into an empty store only, within the same limits, and audited as `storage.seed` with the consumer, the slot and how many entries. The built-in `net` Actor exports `egress` (`http.egress@1`): a consumer's request, made from the Hub's process to the public internet over HTTPS only. Its host is resolved and every address checked (loopback, private, shared, link-local including the cloud metadata address, multicast, reserved and documentation ranges, and their IPv4-mapped forms are refused), and the connection goes to the checked address with the name for SNI and the certificate, so a second resolution can't move it. Plain `http:`, a refused address and a name that resolves to one throw `Refused("forbidden")` at the consumer's `fetch`; a host that can't be reached before anything is sent throws `Refused("unreachable")`, and a failure after, or 5 minutes without a byte, throws `OutcomeUnknown`. Redirects come back as they are. Each request's method, host and status are audited as `net`'s; paths, queries and bodies never are. The `hub` Actor's six exports are served through the same path.
19
+ - `installer`: a bundled host package that turns packages into working Actors, exporting `installer@1`. Bound to the Hub's management (`hub.packages`, `hub.actors`, `hub.grants`, `hub.exports` and `hub.bindings`, which makes it the person's delegated manager) and to `storage.admin@1`, it proposes and installs. `plan({package})` lists each slot the package doesn't wire itself, with the exports that could serve it now: exactly its interface and schema hash, on Actors that aren't stopped or closed. `install({package, name, connections, start?})` makes the Actor with exactly those connections, all or none. It grants nothing its caller couldn't: each connection's export side must be the caller's (the provider, bound to that export, or a manager), else the whole install is refused (`forbidden`, listing every such connection) and nothing is made. It seeds each store bound to `storage.kv` from the package's `seed` (an object of key to value per `module.slot`), starts the Actor if asked (a seed or start that fails closes it), and lists the slots left unbound and the seeds that couldn't land (`unseeded`). It never picks a connection itself. `install` records the new Actor as made for its caller (`installedFor`, which grants nothing), and takes `expose: [{export, to}]`: the new Actor's exports to expose, each to one Actor, all or none like the connections. A manager's are made at once (`granted`, with the slot); one to the caller itself is left for the caller to file, its result giving the exact `hub.grants.expose` call, which makes it the caller's own request (`request`); any other is refused `forbidden`, saying a manager could, and nothing is created. Only `rpc` exports of the package's host modules can be listed, and the Hub's own Actors take no slots. `plan({package, expose})` lists each entry with how it would settle, and refuses one `install` would refuse. Nothing is exposed that isn't listed. Bound to the person's `layout@1` too, it carries a system between homes as data: `exportSystem()`, for a manager only (it lists every binding and the person's layout; any other caller is refused `forbidden`), gives an `agentorg.system/1` composition (every package Actor that isn't closed, by a name of its own, with its package as `name@version#hash` and whether it runs; the connections among them and to the built-in Actors, as `{consumer, slot, provider, export}` by names; and the layout's placements), never credentials, tokens, stores or logs, and lists what it leaves out (external Actors and what connects to them). `importSystem({composition})` makes it again with the caller's authority (connecting the new Actors to each other takes a manager): it creates the Actors whose packages are here (a taken name gets a suffix), binds the connections, seeds, starts what ran and places the layout, all or nothing, and lists what it couldn't: a package that isn't here or is another version (whoever holds the composition's folder adds its archives first) and what depends on it, an Actor that needs a sign-in, a seed that can't land, and the placements unless the caller holds the person's layout. The exporting home's installer stays out: every home has its own. An import never grants management: a connection to `hub` or to `storage.admin` is recorded by an export but never made by an import, even a manager's (a composition may come from anyone); it comes back in `ungranted`, for the person to grant one by one.
20
+ - `@agentorg/hub`: the core. Its state, in `node:sqlite` in a private home: Actors, a verified package store (`hub.packages.add` takes an archive by path; `hub.packages.build` takes a package's source as data, `package.json` and files under `src/` up to 768 KiB, builds it as `agentorg build` does, but reading no tsconfig, in a scratch folder of the home that is always removed: its files import only `@agentorg/sdk`, `@agentorg/interfaces`, `zod`, and for views `react`, `react-dom` and `@agentorg/kit` (JSX compiles to `react/jsx-runtime`), by name, each only within its own package, nothing outside the package's folder, and nothing by a pattern; a library's own imports are its own, and only the files resolved for it are read; a library's wrapped modules are named in the bundle by their library and version (`agentorg-library:react@19.3.1/cjs/react.production.js`), never by where it is installed, in `agentorg build` and Hub builds alike, so a package names no machine's folders and builds the same on any install; a Hub build resolves each allowed package's entry file from the Hub's own install, so in that file esbuild omits Node's ESM-to-CommonJS interop flag, which `agentorg build` keeps: no package allowed now behaves differently for it, but a Hub build's bytes can differ from `agentorg build`'s for packages that use them; at most 16 modules, 16 MiB built and 60 s; one build per caller at a time; and it adds the result. Reading each module's definition runs the source's code, so the Hub runs it in the same OS sandbox as host processes, and where those can't start, `build` is refused `unsupported` with the same reason. A failed build is `Refused("build")` with the build's message, which names no path outside the package), what each Actor takes and offers, bindings, binding requests and an audit trail. A binding is the grant, and it needs both ends: the export side (the provider, an Actor already bound to that export, or a manager) and the slot side (the consumer itself, or a manager). Through `hub.grants@1`, a caller with both ends binds; one with a single end approves the other end's open request or asks that end's approvers; one with neither is refused. `hub.grants.expose({provider, export, to, as?})` exposes an `rpc` export to one Actor: a slot made on `to` at run time, typed by the export's interface and bound to it in one step, named `as` (one word of at most 48 characters) or by default the provider's name camelCased, `_` and the export's last part (`Pocket Side Quests`' `logic.quests` is `pocketSideQuests_quests`), made unique on `to` with `_2`, `_3`…. Its authority is a binding's, `to` being the consumer: with both ends it is made; with one it is a request (`exposed: true` on the request, its `slot` the name it will have), which the other end approves by calling `expose` with the request's fields; with neither it is refused, naming who could. Exposing the same export to the same Actor again gives its slot back. A request reserves no name: the first exposure made under it has it, and the requests it settles close; one Actor has at most 32 exposure requests open toward another. An Actor that declares a slot of its own under an exposed slot's name takes the name, and the exposure goes. The slot goes with its binding: `unexpose({to, slot})`, `unbind`, the export withdrawn or either end closed; `hub.bindings` marks such a binding `exposed: true`. The Hub's own Actors take no slots. A manager creating an Actor for another (the installer, for its caller) passes `for`, shown as `installedFor` on the Actor: provenance only, from which the Hub grants nothing. A decision goes to the request's approvers and its requester, which can also read its requests' outcomes with `mine`. A manager is any Actor bound to `hub.bindings@1`. `hub.actors.create` can bind the new Actor's slots at once, with the creator's export side. The router serves it over WebSocket (`listen`), one yamux channel per Actor: a client's first stream is `hello` with its credential, then every `call`, `subscribe`, `open` and `http` stream is resolved through its binding, validated against the interface's JSON Schemas in both directions (ajv, 2020-12, in a pool of worker threads, each check under a time budget, since schemas come from Actors), forwarded to the provider with the caller named, and audited. A provider accepts or refuses an `open` or `http` stream with one body before any raw bytes. An Actor offers and withdraws exports at run time on its own channel (`offer`, `withdraw`). An Actor learns which of its slots are bound from hello's result, then from a `slot` notice on each change. A pipe the Hub makes for a package Actor's process says hello as that Actor without a credential (the pipe is the proof) and declares nothing (the manifest does). Every `serve` stream names the caller and the caller's slot, so a provider can keep state per consumer slot. `hub.actors.start` runs a package Actor's host modules in their own process: `node` under its permission model (reading only the runner and the package's folder, no child processes or workers), with an empty environment, a 256 MB heap and the channel on fd 3, inside the OS sandbox (`sandbox-exec` on macOS, a user, network and PID namespace with `unshare` on Linux), so it has no network, no DNS and no other process to signal. The Actor is running once its process says hello, within 30 s. `stop` sends SIGTERM, then SIGKILL after 5 s. A process that exits otherwise has crashed: it is restarted after a backoff from 1 s doubling to 60 s (starting over after 10 minutes up), and `hub.actors.get` counts `restarts` and keeps the `lastExit`. Every Actor's record in `hub.actors` says whether it is `connected`, holding a channel to the Hub now: an external Actor while its program is connected (the person while the app runs: its gateway holds the person's channel), a package Actor while its process is, so a running one isn't while its process starts or restarts; the built-in Actors are the Hub itself and have none. `hub.actors`' `changed` event names an Actor whose record may differ: made, started, stopped, closed, its process exited, or connected or gone; the audit trail records no connections. Actors running when the Hub stopped are started again when it opens. Where the sandbox can't run (stock Ubuntu restricts unprivileged user namespaces), `start` is refused with `unsupported` and every package Actor's `host` says why and what to change; the Hub probes again at each start. `hub.actors.logs` reads an Actor's log lines: its `ctx.log` entries and anything else its process writes (stdout as `info`, stderr as `error`). For the person's shell, `Hub.viewCall` and `Hub.viewSubscribe` run a package Actor's view module's calls and events in the Hub's process, as that Actor, through `<module>.<slot>`, and `Hub.viewSlots` tells the gateway a view module's slots: those bound now, then each change, and each bound again when it is usable again: its provider's channel comes back, or its Actor's own, since a view calls only while its Actor runs; `hub.actors.get` lists a package Actor's `views`. `Hub.viewLog` writes a view module's log line to its Actor's log, marked with the module; the Hub bounds each line itself (a known level, 4 KiB of text, 16 fields of 1 KiB) and rotates each Actor's log once at 1 MiB. The built-in `storage` Actor exports `kv@1`: one store per consumer slot (keyed by the consumer and slot the router names), in `<home>/storage.db`; values up to 256 KiB and 64 MiB per Actor, past which `Refused("quota")`; stores outlive unbinding and go when their Actor is closed. Its `admin` export (`storage.admin@1`, bound only to the installer) seeds a new Actor's store from its package's `seed`: all entries or none, into an empty store only, within the same limits, and audited as `storage.seed` with the consumer, the slot and how many entries. The built-in `net` Actor exports `egress` (`http.egress@1`): a consumer's request, made from the Hub's process to the public internet over HTTPS only. Its host is resolved and every address checked (loopback, private, shared, link-local including the cloud metadata address, multicast, reserved and documentation ranges, and their IPv4-mapped forms are refused), and the connection goes to the checked address with the name for SNI and the certificate, so a second resolution can't move it. Plain `http:`, a refused address and a name that resolves to one throw `Refused("forbidden")` at the consumer's `fetch`; a host that can't be reached before anything is sent throws `Refused("unreachable")`, and a failure after, or 5 minutes without a byte, throws `OutcomeUnknown`. Redirects come back as they are. Each request's method, host and status are audited as `net`'s; paths, queries and bodies never are. The `hub` Actor's six exports are served through the same path. A refusal that names an Actor names it as "Name (id)", and says what the caller can do instead: who could grant it, what to call, or what to do first.
20
21
  - `@agentorg/cli`: AgentOrg as one app. `agentorg` runs a Hub, the person's gateway and the shell on loopback; see "The app: the person's gateway".
21
22
  - `chatgpt`: the model Actor, a package with one host module. It signs in with ChatGPT for the person's plan (`account.login@1`: OpenAI's OAuth for open-source apps, with dynamic registration, PKCE and a verified id_token; refresh tokens rotate, one refresh at a time) and serves `llm.session@1` on that plan through the Responses API, streamed and stored nowhere. Its whole network is its `web: http.egress@1` slot and its sign-in lives in its `store: kv@1` slot; the tokens never leave it except to that store: never in a reply, an event, a log or a refusal. It never uses an API key or API billing: a usage limit is refused `usage_limit`, with where to manage it. Its tests run against an in-process fake of OpenAI, so none reaches OpenAI.
22
- - `assistant`: an agent, a package whose host module `logic` exports `chat@1` and runs the agent loop itself, with the model behind its `model: llm.session@1` slot. Its tools are its other bound slots (`layout`, `packages`, `actors`, `grants`, `exports` and `installer`): each method becomes a function tool named `<slot>__<method>` with the method's input JSON Schema, so it can do exactly what it is connected to, and a call runs through the slot, checked and audited by the Hub. With `packages` and `installer: installer@1` bound, it can extend the system: its instructions then give the package format, with a whole counter package as the example (`EXAMPLE` in `src/logic.ts`, built by its tests as the Hub builds), and the steps: `packages__build` with the files, fixing errors from the build's message; `installer__plan`; `installer__install` with explicit connections (a store to `storage.kv`); then `layout__place` with the new Actor's view. A turn makes at most 20 tool calls, and a function's output is cut at 16 KiB. Its chat is kept in its `store: kv@1` slot: each message once, its text and a call's arguments cut to fit a stored value, and the newest 2,000 messages (16 MiB) kept. The model is sent the newest whole exchanges that fit 400 KB of JSON (instructions and tool schemas aside), and always the latest one; if that alone is over, its oldest function outputs are left out, each call keeping an output. Its view module `chat` is the chat itself: the messages as they stream and a composer, with "Using ChatGPT plan" and "Manage usage" beside it, and the action each refusal calls for (Manage usage, Continue with ChatGPT, Retry), which it asks of the shell through its `shell: ui.shell@1` slot.
23
+ - `assistant`: an agent, a package whose host module `logic` exports `chat@1` and runs the agent loop itself, with the model behind its `model: llm.session@1` slot. Its tools are its other bound slots (`layout`, `packages`, `actors`, `grants`, `exports` and `installer`), and every slot exposed to it at run time (`ctx.exposed()`): each method becomes a function tool named `<slot>__<method>` (a dot in the slot's name as `_`; a name past 64 characters is left out) with the method's input JSON Schema, so it can do exactly what it is connected to, and a call runs through the slot, checked and audited by the Hub. With `packages` and `installer: installer@1` bound, it can extend the system: its instructions then give the package format (views may use React and `@agentorg/kit`'s components), with a whole counter package and a view on the kit as the examples (`EXAMPLE` in `src/logic.ts`, built by its tests as the Hub builds), and the steps: `packages__build` with the files, fixing errors from the build's message; `installer__plan`; `installer__install` with explicit connections (a store to `storage.kv`); then `layout__place` with the new Actor's view. A turn makes at most 20 tool calls, and a function's output is cut at 16 KiB. Its chat is kept in its `store: kv@1` slot: each message once, its text and a call's arguments cut to fit a stored value, and the newest 2,000 messages (16 MiB) kept. The model is sent the newest whole exchanges that fit 400 KB of JSON (instructions and tool schemas aside), and always the latest one; if that alone is over, its oldest function outputs are left out, each call keeping an output. Its view module `chat` is the chat itself, the kit's `Chat` over its `chat: chat@1` slot: the record (the newest 100, earlier pages on request), the replies as they stream, in markdown, and a composer, with "Using ChatGPT plan" and "Manage usage" beside it, Retry under the last reply, and the action each refusal calls for (Manage usage, Continue with ChatGPT, Retry), which it asks of the shell through its `shell: ui.shell@1` slot.
23
24
 
24
25
  ### Why `ui.view@1` is different
25
26
 
@@ -34,9 +35,9 @@ A shell runs each view module in its own sandboxed frame, with an opaque origin
34
35
  - **`ui.view@1`:** the shell drives `mount`, `resize` and `unmount`. At mount, the theme's CSS variables (names starting `--`) are set on the frame's document.
35
36
  - **`ui.shell@1`:** the shell's own interface, the mirror of `ui.view@1`. A view's slot of it is bound by the frame runtime itself, never by the Hub, so it is always bound. `openExternal({url})` takes only an `https:` URL, which the host checks; the shell's handler must open it in a new tab with no opener (`noopener`). `signIn()` starts the shell's own sign-in. Each method has one call in flight at a time. A frame can't open windows itself.
36
37
  - **Logs:** the view's `ctx.log` and any error it doesn't catch go to the shell, for its Actor's log.
37
- - **Height:** while the view is mounted, the frame runtime tells the shell its content's height (the frame's body, which sets no height of its own) each time it changes. It's the frame runtime's own message, not part of `ui.view@1`, and a shell may size the frame to it.
38
+ - **Size and base styles:** the placement decides a frame's size, never its content: the view learns it from `mount` and `resize`. Before the view loads, the frame runtime puts a base stylesheet first in the document (`FRAME_BASE`): the document and body fill the frame on a transparent background, content that grows scrolls inside with no visible scrollbar, and plain HTML (text, headings, lists, buttons, inputs, checkboxes, tables, code) is drawn in the theme's tokens. Every rule is in `:where()`, so any rule the view writes outranks it.
38
39
 
39
- The frame isn't trusted: `FrameHost` checks every message, drops what doesn't fit, and refuses what it can't serve. A frame holds one subscription per slot and event, 64 at most, and 64 calls in flight, past which a call is refused `busy`; its log lines are cut, their fields rebuilt as a small fresh object, and past 50 lines in 10 s the rest are dropped. A height reaches the shell's `size` handler only as a finite number, clamped to 120–2,000 px, and at most once per 100 ms, the latest one winning.
40
+ The frame isn't trusted: `FrameHost` checks every message, drops what doesn't fit, and refuses what it can't serve. A frame holds one subscription per slot and event, 64 at most, and 64 calls in flight, past which a call is refused `busy`; its log lines are cut, their fields rebuilt as a small fresh object, and past 50 lines in 10 s the rest are dropped.
40
41
 
41
42
  ## Building a package
42
43
 
@@ -54,11 +55,11 @@ A package's `package.json` names its modules, its own wiring and any seed state:
54
55
 
55
56
  `agentorg build [dir]` (from `@agentorg/sdk`; `buildPackage` in `@agentorg/sdk/build`) then:
56
57
 
57
- - bundles each module, with every library it uses, into one ESM file, `dist/<module>.js`, with no imports at run time and no Node built-ins;
58
+ - bundles each module, with every library it uses, into one ESM file, `dist/<module>.js`, with no imports at run time and no Node built-ins. JSX uses the automatic runtime (no file needs React in scope), and `process.env.NODE_ENV` is `"production"`, so a view built with React and the kit runs in a frame, which has no `process`;
58
59
  - reads each module's definition from its code and writes `agentorg.json`: each module's placement, slots and exports, every interface's JSON Schemas and hash, the package's `connections` and `seed`;
59
60
  - hashes the tree, `agentorg.json` and `dist/`, as SHA-256 over the canonical list of each file's path and SHA-256, and archives it as `<hash>.agentorg`, a deterministic tar. The tree goes to `agentorg-build/package/` and the archive beside it.
60
61
 
61
- It finds `@agentorg/sdk`, `@agentorg/interfaces` and `zod` from the package's own folder, so it works in a checkout of this repository, where they are. With `agentorg` installed from npm, build through the running app instead: `agentorg call packages build '{"files": {"package.json": "…", "src/logic.ts": "…"}}'` is the Hub's build (`hub.packages.build`), which takes the source as data, builds it as above against the SDK, the interfaces and zod it ships with, and adds the package.
62
+ It finds `@agentorg/sdk`, `@agentorg/interfaces` and `zod` from the package's own folder, so it works in a checkout of this repository, where they are. With `agentorg` installed from npm, build through the running app instead: `agentorg call packages build '{"files": {"package.json": "…", "src/logic.ts": "…"}}'` is the Hub's build (`hub.packages.build`), which takes the source as data, builds it as above against the SDK, the interfaces, zod, React, react-dom and the kit it ships with, and adds the package.
62
63
 
63
64
  A signature is detached: a file named `agentorg.sig` beside the package, signing the package hash, so it is never inside what it signs. The manifest has no signature field.
64
65
 
@@ -85,6 +86,7 @@ To read a module's definition, the build runs the module's code in a separate No
85
86
  `@agentorg/cli` provides `agentorg`.
86
87
 
87
88
  - **`agentorg`**, with no command, runs AgentOrg: a Hub in its home, the person's gateway and the shell, on `127.0.0.1` (`--port N`, else any free port). It opens the browser already signed in, and prints only its address, never a sign-in code. `--no-open` doesn't open a browser. The code is in the address it hands the system's opener; on Linux, other local users can see that program's arguments for the moment it runs, and the code works for 60 s.
89
+ - **`agentorg --version`** prints the version. An option the command doesn't know is refused with the usage (exit 2); it never starts the app.
88
90
  - **`agentorg open`** signs a browser in to the running app again.
89
91
  - **`agentorg build [dir]`** builds a package, as the SDK's build does, in a checkout of this repository. Installed from npm, build with `agentorg call packages build '{"files": {…}}'`, the Hub's build.
90
92
  - **`agentorg hub [--port N]`** runs a bare Hub in its home, without the gateway or the shell, serving WebSocket on loopback, and writes the address to `<home>/url`.
@@ -137,6 +139,8 @@ From a clone, after `npm ci` and `npm run build`, with `agentorg` being `node pa
137
139
 
138
140
  It records the Actors it made, and the bundled assistant's hash, in the person's store (`app/first-run`), and trusts only those, never an Actor because of the name its package gives itself. Each step reads what is there first, so a restart, or a first run that stopped half way, converges and makes nothing twice: a recorded Actor that lost one of its slots' bindings gets it again (of the slots its package declares), and one of an older build is kept. A recorded Actor that was closed is made again. A step that fails is logged and tried again at the next start.
139
141
  - **`/oauth/chatgpt`:** where ChatGPT sends the browser back after sign-in. It takes `GET` only and hands the whole address, which holds the sign-in's code, to `login.complete`. Then it sends the tab on (303) to `/oauth/chatgpt?result=<outcome>`, so the code leaves the tab's address and history; that page says how it went and links back to the shell. The code is never logged or shown, and no referrer is sent.
142
+ - **Named rules, `app.rules@1`:** conveniences the person turns on, served by the gateway on `/api` as `rules` (`list`, `set`, and `changed`). Each is named and off until the person turns it on, and the ones that are on are kept in the person's store under `app/rules`. The gateway acts on a rule that is on as the person, a manager, so only within what the person could grant: it hears each request through `grants.requested`, and goes through the open ones at start and whenever a rule is turned on. It approves a match the way an approver does, with the call the request asked for, and never declines; whatever no rule matches stays for the person.
143
+ - **"Let an agent use what it installs"** (`agents-use-what-they-install`) approves a request to expose an Actor's export to the agent it was installed for (its `installedFor`), while the Actor isn't closed. `installedFor` is provenance only: nothing but a rule that is on acts on it.
140
144
  - **`layout@1`:** the person exports it, so a program bound to it places a view as the person does. Each placement records `by`, the Actor that placed it, from the call's caller as the Hub names it (the person, through `/api`); no input sets it. The layout is kept in the person's `store` slot (`kv@1`) under the key `layout`, and the app binds that slot to the built-in `storage` where there is one.
141
145
  - `place` takes only a `view` module of a package Actor, with no `after` meaning last.
142
146
  - `move` with no `after` means first.
@@ -150,8 +154,8 @@ From a clone, after `npm ci` and `npm run build`, with `agentorg` being `node pa
150
154
  - The person's `installer` slot, bound by the app's first run, serves both.
151
155
  - **`/frames/`:** a view's frame, its runtime and its bundle, for `view` modules only, and only by package hash. Every response's policy is `sandbox allow-scripts`, so whatever loads there runs on an opaque origin, even opened as a top page, and never as the shell's origin, where the session is. It allows scripts only from the gateway's `/frames/`, inline styles, and no fetches, forms or windows. The frame's origin is opaque, so its module scripts are CORS requests from `Origin: null`: only those are answered `Access-Control-Allow-Origin: null`, and nothing there reads or needs the session.
152
156
  - **The app's own pages** carry a policy of their own: scripts and styles from the app only, framed by nothing.
153
- - **The shell,** `@agentorg/shell`, is what the gateway serves at `/`: one socket to `/api`, and nothing it decides on its own.
154
- - **Agents** are the package Actors with a `chat` view. Selecting one mounts that view in the main container, with the placements beside it whose `actor` is that agent or whose `by` is. Between them, a handle (dragged, or the arrow keys) sets that column's width, from 280 to 640 px and at most half the stage, kept in this browser; an agent with nothing beside it has no column, and its chat takes the width. A placed view, beside an agent or on Home, takes the height its frame reports; one that reports none keeps the default.
157
+ - **The shell,** `@agentorg/shell`, is what the gateway serves at `/`: one socket to `/api`, and nothing it decides on its own. It is built on `@agentorg/kit`: its dialogs, menus, switches, tabs, icons and the column's handle are the kit's.
158
+ - **Agents** are the package Actors with a `chat` view. Selecting one mounts that view in the main container, with the placements beside it whose `actor` is that agent or whose `by` is. Between them, a handle (dragged, or the arrow keys) sets that column's width, from 280 to 640 px and at most half the stage, kept in this browser; an agent with nothing beside it has no column, and its chat takes the width. A placed view's frame fills its placement, whatever it draws: beside an agent, the column's height is shared among its placements, each at least 220 px (the column scrolls past that), and on Home each placement is 300 px high. The handle is react-resizable-panels', through the kit; while it's dragged, frames take no pointer events, so a drag over a view keeps going.
155
159
  - **Home** shows the open grant requests, with Allow and Decline, then every placement of `layout@1`, in order. Each event (`layout` `changed`, `grants` `requested` and `decided`, `actors` `changed`, and the audit's package and binding entries) reads its part again. A subscription the gateway ends is made again after a wait (1 s, growing to 30 s while it keeps ending), and what it says is read again then; a view's own subscriptions end in its frame instead.
156
160
  - **Settings** reads the Actors, packages and connections through `hub.*`, and the ChatGPT account through `login` when it's bound; the person is "you". An external Actor, the person included, shows whether it's connected; a package Actor its process state; a built-in one runs inside the Hub. **Packages** downloads each archive (`GET /packages/<hash>.agentorg`) and installs one from a file: uploaded to `POST /packages`, then `installer.plan` shows each slot's candidates (a slot's only one preselected), `installer.install` makes it with the person's picks (a connection the person can't grant is named, to leave unconnected), and its views can be placed on home; slots left unconnected and seeds that didn't land are listed. **System** exports the system as one file (`GET /system`), listing what it leaves out, and imports one (`POST /system`): what it made, what isn't as it was, and each management connection, for the person to grant one by one.
157
161
  - **New agent** is offered once the first run has recorded the app's assistant, by hash, in the person's store (`app/first-run`), never a package found by its name. It is `installer.install` of that package with step 5's connections plus `logic.installer` to the installer, less the grants switched off, started, all or nothing; then it opens. The ChatGPT and installer it connects to are the ones the person's `login` and `installer` are bound to. `installAgent` in `@agentorg/shell/agent-bindings` makes that call, for a test too, and returns the installer's answer. "install Actors" needs "create and run Actors": with that off, it is off too and can't be switched on. A refusal is said plainly in the dialog, in room kept for it: a grant that isn't the person's to give, by name, or that AgentOrg isn't set up yet. A grant left on that the installer didn't connect, or a seed that didn't land, is listed before the agent opens.
@@ -1,6 +1,6 @@
1
1
  {
2
- "installer": "sha256-51ecf151e590f5e57f28229d4cb36e4932a2f1670e50ddf1a3ccf335a1ee146d.agentorg",
3
- "chatgpt": "sha256-b76ec31282e5b863ee9569dfd9d50b283a21101cbe1b3fac23d1cbcf16b9a408.agentorg",
4
- "assistant": "sha256-e4c0e857cea3a721998effe2ca859c4011978b9bc36e63c058bfc17c27a1772e.agentorg",
5
- "board": "sha256-87e121cbe58279f3a633e61c9773b61fc17fd53eac3d7c6f037925cbfd5d5384.agentorg"
2
+ "installer": "sha256-84165e3be5c904fc971d983dab31102e07cca725d8629a6fd7d118fa3a0a88b8.agentorg",
3
+ "chatgpt": "sha256-f4330f5987f37d8cf3aeb44d2f831b573641a87186daa2f811f0c35ba04804f0.agentorg",
4
+ "assistant": "sha256-ade9132b3f34b4c39db92adeadc7e540dc745e4a81b5b54f5d45bf9ec92bca75.agentorg",
5
+ "board": "sha256-01d69bc3888c2a53963f4413d47de909d129ad27c78e9af6d830bb50c3478419.agentorg"
6
6
  }
@@ -7,8 +7,8 @@ export declare const MAX_SOURCE: number;
7
7
  export declare function checkSource(files: unknown): [string, string][];
8
8
  /**
9
9
  * Build a package from its source, given as data, and add it with `add`: the files are written to
10
- * a fresh folder in the home, built as `agentorg build` builds (importing only the SDK, the
11
- * interfaces and zod by name, and nothing outside the folder; reading no tsconfig; at most 16
10
+ * a fresh folder in the home, built as `agentorg build` builds (importing by name only the SDK,
11
+ * the interfaces, zod, React, react-dom and the kit, and nothing outside the folder; reading no tsconfig; at most 16
12
12
  * modules and 16 MiB built), and the folder is gone after, whatever happened. A build that fails
13
13
  * is `Refused("build")` with the build's message, which names no path outside the package.
14
14
  */
@@ -8,8 +8,18 @@ import { BuildError, buildPackage } from "@agentorg/sdk/build";
8
8
  export const MAX_SOURCE = 768 * 1024;
9
9
  /** Files one package's source may have. */
10
10
  const MAX_FILES = 256;
11
- /** What a package built by the Hub may import by name. */
12
- const ALLOWED = ["@agentorg/sdk", "@agentorg/interfaces", "zod"];
11
+ /**
12
+ * What a package built by the Hub may import by name: the SDK, the interfaces, zod, and React and
13
+ * the kit for views (`react/jsx-runtime`, which JSX compiles to, is React's).
14
+ */
15
+ const ALLOWED = [
16
+ "@agentorg/sdk",
17
+ "@agentorg/interfaces",
18
+ "zod",
19
+ "react",
20
+ "react-dom",
21
+ "@agentorg/kit",
22
+ ];
13
23
  /** Where those are found: this package's own folder (dist/src/build.js → the package). */
14
24
  const FROM = fileURLToPath(new URL("../..", import.meta.url));
15
25
  /** A source path: `package.json`, or a source file under `src/` named plainly. */
@@ -68,8 +78,8 @@ function told(message, source, home) {
68
78
  }
69
79
  /**
70
80
  * Build a package from its source, given as data, and add it with `add`: the files are written to
71
- * a fresh folder in the home, built as `agentorg build` builds (importing only the SDK, the
72
- * interfaces and zod by name, and nothing outside the folder; reading no tsconfig; at most 16
81
+ * a fresh folder in the home, built as `agentorg build` builds (importing by name only the SDK,
82
+ * the interfaces, zod, React, react-dom and the kit, and nothing outside the folder; reading no tsconfig; at most 16
73
83
  * modules and 16 MiB built), and the folder is gone after, whatever happened. A build that fails
74
84
  * is `Refused("build")` with the build's message, which names no path outside the package.
75
85
  */
@@ -85,6 +85,7 @@ export class HubActor {
85
85
  ...(Array.isArray(input.bindings)
86
86
  ? { bindings: input.bindings }
87
87
  : {}),
88
+ ...(typeof input.for === "string" ? { for: input.for } : {}),
88
89
  }),
89
90
  list: () => ({ actors: state.actors().map(recordOf) }),
90
91
  get: (_, input) => recordOf(state.actor(String(input.actorId))),
@@ -125,6 +126,13 @@ export class HubActor {
125
126
  grants: {
126
127
  bind: (caller, input) => state.bind(caller, wiring(input)),
127
128
  unbind: (caller, input) => state.unbind(caller, String(input.consumer), String(input.slot)),
129
+ expose: (caller, input) => state.expose(caller, {
130
+ provider: String(input.provider),
131
+ export: String(input.export),
132
+ to: String(input.to),
133
+ ...(typeof input.as === "string" ? { as: input.as } : {}),
134
+ }),
135
+ unexpose: (caller, input) => state.unexpose(caller, String(input.to), String(input.slot)),
128
136
  request: (caller, input) => ({
129
137
  requestId: state.request(caller, wiring(input), String(input.reason)).requestId,
130
138
  }),
@@ -2,5 +2,5 @@ export { HubActor } from "./hub-actor.js";
2
2
  export { blockedAddresses, isPublicAddress, type NetOptions } from "./net.js";
3
3
  export { type ChannelHandle, Hub, type HubOptions } from "./router.js";
4
4
  export { type Listener, listen } from "./server.js";
5
- export { type ActorRecord, type ActorState, type AuditRecord, type BindingRecord, type CallOutcome, type Decision, type Declaration, type Exit, HUB, HubState, NET, PERSON, type RequestRecord, type Side, STORAGE, type StateEvents, type Wiring, } from "./state.js";
5
+ export { type ActorRecord, type ActorState, type AuditRecord, type BindingRecord, type CallOutcome, type Decision, type Declaration, type Exit, exposedName, HUB, HubState, NET, PERSON, type RequestRecord, type Side, STORAGE, type StateEvents, type Wiring, } from "./state.js";
6
6
  export { STORAGE_LIMITS, type StorageLimits } from "./storage.js";
@@ -2,5 +2,5 @@ export { HubActor } from "./hub-actor.js";
2
2
  export { blockedAddresses, isPublicAddress } from "./net.js";
3
3
  export { Hub } from "./router.js";
4
4
  export { listen } from "./server.js";
5
- export { HUB, HubState, NET, PERSON, STORAGE, } from "./state.js";
5
+ export { exposedName, HUB, HubState, NET, PERSON, STORAGE, } from "./state.js";
6
6
  export { STORAGE_LIMITS } from "./storage.js";
@@ -191,7 +191,7 @@ export class Hub {
191
191
  if (admitted) {
192
192
  const actor = this.state.actor(admitted.actorId);
193
193
  if (actor.package === "external" || actor.package === "builtin" || actor.state === "closed")
194
- throw new Refused("state", `${actor.actorId} isn't a live package Actor.`);
194
+ throw new Refused("state", `${this.state.named(actor.actorId)} isn't a live package Actor.`);
195
195
  }
196
196
  let conn;
197
197
  let admit;
@@ -216,11 +216,11 @@ export class Hub {
216
216
  // Closed while its hello was on the way (a pipe made before a close, or declares
217
217
  // being checked): a closed Actor is never admitted.
218
218
  if (this.state.actor(actorId).state === "closed")
219
- throw new Refused("state", `${actorId} is closed.`);
219
+ throw new Refused("state", `${this.state.named(actorId)} is closed for good; make another.`);
220
220
  // Checked again as the channel is admitted: one may have connected while declares
221
221
  // were checked.
222
222
  if (replace === false && this.#connections.has(actorId))
223
- throw new Refused("connected", `${actorId} already has a channel to this Hub.`);
223
+ throw new Refused("connected", `${this.state.named(actorId)} already has a channel to this Hub; close that one first.`);
224
224
  conn = this.#admit(actorId, session);
225
225
  admit();
226
226
  options.maxStreams = MAX_STREAMS;
@@ -361,12 +361,12 @@ export class Hub {
361
361
  #viewModule(actorId, module, options) {
362
362
  const actor = this.state.actor(actorId);
363
363
  if (actor.package === "external" || actor.package === "builtin")
364
- throw new Refused("forbidden", `${actorId} has no package, so no views.`);
364
+ throw new Refused("forbidden", `${this.state.named(actorId)} has no package, so no views.`);
365
365
  if (options.running && actor.state !== "running")
366
- throw new Refused("state", `${actorId} isn't running.`);
366
+ throw new Refused("state", `${this.state.named(actorId)} is ${actor.state}${actor.state === "closed" ? "" : "; start it with hub.actors.start"}.`);
367
367
  const { manifest } = this.state.package(actor.package);
368
368
  if (!Object.hasOwn(manifest.modules, module) || manifest.modules[module]?.placement !== "view")
369
- throw new Refused("forbidden", `${module} isn't a view module of ${actorId}'s package.`);
369
+ throw new Refused("forbidden", `${module} isn't a view module of ${this.state.named(actorId)}'s package; hub.actors.get lists its views.`);
370
370
  }
371
371
  /**
372
372
  * A line a view module logged, into its Actor's log, marked with the module. The Hub bounds it
@@ -438,7 +438,7 @@ export class Hub {
438
438
  if (pipe) {
439
439
  // The pipe is the proof: it was made for this one Actor's process.
440
440
  if (header.actorId !== pipe.actorId)
441
- throw new Refused("forbidden", `This channel is ${pipe.actorId}'s.`);
441
+ throw new Refused("forbidden", `This channel is ${this.state.named(pipe.actorId)}'s.`);
442
442
  if (header.declares !== undefined)
443
443
  throw new Refused("invalid", "A package Actor declares through its manifest.");
444
444
  }
@@ -446,16 +446,19 @@ export class Hub {
446
446
  !this.state.authenticate(header.actorId, header.credential))
447
447
  throw new Refused("forbidden", "No such Actor, or the credential is wrong.");
448
448
  if (header.replace === false && this.#connections.has(header.actorId))
449
- throw new Refused("connected", `${header.actorId} already has a channel to this Hub.`);
449
+ throw new Refused("connected", `${this.state.named(header.actorId)} already has a channel to this Hub; close that one first.`);
450
450
  if (header.declares !== undefined)
451
451
  this.state.declareExternal(header.actorId, await this.#declares(header.actorId, header.declares));
452
452
  admit(header.actorId, header.replace);
453
453
  // Taken as the channel is admitted: every change after it reaches the channel as a notice.
454
- const bound = this.state
455
- .bindings(header.actorId)
456
- .filter((b) => b.consumer === header.actorId)
457
- .map((b) => b.slot);
454
+ const mine = this.state.bindings(header.actorId).filter((b) => b.consumer === header.actorId);
455
+ const bound = mine.map((b) => b.slot);
458
456
  await answer(writer, result({ actorId: header.actorId, bound }));
457
+ // Each slot made at run time follows as its own notice, with its interface: one frame
458
+ // each, however many there are.
459
+ for (const b of mine)
460
+ if (b.exposed)
461
+ this.#notify(header.actorId, b.slot, true);
459
462
  }
460
463
  catch (error) {
461
464
  await answer(writer, errorBody(error));
@@ -463,6 +466,13 @@ export class Hub {
463
466
  }
464
467
  }
465
468
  /** Tell an Actor's channel and its views' listeners that one of its slots was bound or unbound. */
469
+ /** A slot made at run time, as its consumer is told of it: the export's interface, and whose it is. */
470
+ #exposure(binding) {
471
+ return {
472
+ interface: this.state.declaration(binding.consumer, "slot", binding.slot)?.iface,
473
+ provider: { actor: binding.provider, export: binding.export },
474
+ };
475
+ }
466
476
  #notify(actorId, slot, bound) {
467
477
  this.#notifyViews(actorId, slot, bound);
468
478
  const conn = this.#connections.get(actorId);
@@ -470,12 +480,26 @@ export class Hub {
470
480
  return;
471
481
  if (conn.notices >= this.state.slotCount(actorId) + MAX_OPEN_NOTICES)
472
482
  return conn.session.close(GO_AWAY.protocolError);
483
+ // A slot made at run time carries its exposure while bound; unbound, it is gone.
484
+ const binding = bound ? this.state.binding(actorId, slot) : undefined;
485
+ // Gone before it could be told: its unbinding is told instead.
486
+ if (bound && !binding)
487
+ return;
488
+ const exposed = binding?.exposed ? { exposed: this.#exposure(binding) } : {};
489
+ let frame;
490
+ try {
491
+ frame = encodeFrame({ op: "slot", name: slot, bound, ...exposed });
492
+ }
493
+ catch {
494
+ // An interface offered in one frame fits one; nothing else here can be too large.
495
+ return;
496
+ }
473
497
  try {
474
498
  const stream = conn.session.open();
475
499
  conn.notices++;
476
500
  const writer = stream.writable.getWriter();
477
501
  void writer
478
- .write(encodeFrame({ op: "slot", name: slot, bound }))
502
+ .write(frame)
479
503
  .then(() => writer.close())
480
504
  .catch(() => { });
481
505
  // Nothing comes back; the Actor closing its side ends the read and frees the notice.
@@ -657,12 +681,12 @@ export class Hub {
657
681
  if (method !== "seed")
658
682
  throw new Refused("unimplemented", `storage.admin@1 has no method ${method}.`);
659
683
  if (this.state.actor(input.consumer).state === "closed")
660
- throw new Refused("state", `${input.consumer} is closed.`);
684
+ throw new Refused("state", `${this.state.named(input.consumer)} is closed for good.`);
661
685
  // Only a store the consumer can reach: its slot, bound to storage's kv.
662
686
  const bound = this.state.binding(input.consumer, input.slot);
663
687
  if (bound?.provider !== STORAGE || bound.export !== "kv")
664
- throw new Refused("invalid", `${input.consumer}.${input.slot} isn't a slot bound to storage.kv.`);
665
- this.#storage.seed(input.consumer, input.slot, input.entries);
688
+ throw new Refused("invalid", `${this.state.named(input.consumer)}'s ${input.slot} isn't a slot bound to storage.kv; bind it there first.`);
689
+ this.#storage.seed(input.consumer, input.slot, input.entries, this.state.named(input.consumer));
666
690
  // The seed is done; an audit that fails now (the Hub closing) doesn't undo or hide it.
667
691
  try {
668
692
  this.state.auditHub("storage.seed", { consumer: input.consumer, slot: input.slot, entries: input.entries.length }, caller);
@@ -44,6 +44,7 @@ declare const HUB_EXPORTS: {
44
44
  create: import("@agentorg/sdk").MethodSpec<import("zod").ZodObject<{
45
45
  name: import("zod").ZodString;
46
46
  package: import("zod").ZodOptional<import("zod").ZodString>;
47
+ for: import("zod").ZodOptional<import("zod").ZodString>;
47
48
  bindings: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
48
49
  slot: import("zod").ZodString;
49
50
  provider: import("zod").ZodString;
@@ -76,6 +77,7 @@ declare const HUB_EXPORTS: {
76
77
  reason: import("zod").ZodOptional<import("zod").ZodString>;
77
78
  }, import("zod/v4/core").$strip>>;
78
79
  views: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
80
+ installedFor: import("zod").ZodOptional<import("zod").ZodString>;
79
81
  }, import("zod/v4/core").$strip>>;
80
82
  }, import("zod/v4/core").$strip>>;
81
83
  get: import("@agentorg/sdk").MethodSpec<import("zod").ZodObject<{
@@ -102,6 +104,7 @@ declare const HUB_EXPORTS: {
102
104
  reason: import("zod").ZodOptional<import("zod").ZodString>;
103
105
  }, import("zod/v4/core").$strip>>;
104
106
  views: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
107
+ installedFor: import("zod").ZodOptional<import("zod").ZodString>;
105
108
  }, import("zod/v4/core").$strip>>;
106
109
  start: import("@agentorg/sdk").MethodSpec<import("zod").ZodObject<{
107
110
  actorId: import("zod").ZodString;
@@ -145,6 +148,7 @@ declare const HUB_EXPORTS: {
145
148
  interface: import("zod").ZodString;
146
149
  madeBy: import("zod").ZodString;
147
150
  at: import("zod").ZodString;
151
+ exposed: import("zod").ZodOptional<import("zod").ZodLiteral<true>>;
148
152
  }, import("zod/v4/core").$strip>>;
149
153
  }, import("zod/v4/core").$strip>>;
150
154
  }, {}, 1>;
@@ -164,6 +168,23 @@ declare const HUB_EXPORTS: {
164
168
  consumer: import("zod").ZodString;
165
169
  slot: import("zod").ZodString;
166
170
  }, import("zod/v4/core").$strip>, import("zod").ZodObject<{}, import("zod/v4/core").$strip>>;
171
+ expose: import("@agentorg/sdk").MethodSpec<import("zod").ZodObject<{
172
+ provider: import("zod").ZodString;
173
+ export: import("zod").ZodString;
174
+ to: import("zod").ZodString;
175
+ as: import("zod").ZodOptional<import("zod").ZodString>;
176
+ }, import("zod/v4/core").$strip>, import("zod").ZodUnion<readonly [import("zod").ZodObject<{
177
+ exposed: import("zod").ZodLiteral<true>;
178
+ slot: import("zod").ZodString;
179
+ }, import("zod/v4/core").$strip>, import("zod").ZodObject<{
180
+ exposed: import("zod").ZodLiteral<false>;
181
+ slot: import("zod").ZodString;
182
+ requestId: import("zod").ZodString;
183
+ }, import("zod/v4/core").$strip>]>>;
184
+ unexpose: import("@agentorg/sdk").MethodSpec<import("zod").ZodObject<{
185
+ to: import("zod").ZodString;
186
+ slot: import("zod").ZodString;
187
+ }, import("zod/v4/core").$strip>, import("zod").ZodObject<{}, import("zod/v4/core").$strip>>;
167
188
  request: import("@agentorg/sdk").MethodSpec<import("zod").ZodObject<{
168
189
  consumer: import("zod").ZodString;
169
190
  slot: import("zod").ZodString;
@@ -187,6 +208,7 @@ declare const HUB_EXPORTS: {
187
208
  reason: import("zod").ZodString;
188
209
  requestedBy: import("zod").ZodString;
189
210
  at: import("zod").ZodString;
211
+ exposed: import("zod").ZodOptional<import("zod").ZodLiteral<true>>;
190
212
  }, import("zod/v4/core").$strip>>;
191
213
  }, import("zod/v4/core").$strip>>;
192
214
  decline: import("@agentorg/sdk").MethodSpec<import("zod").ZodObject<{
@@ -208,6 +230,7 @@ declare const HUB_EXPORTS: {
208
230
  reason: import("zod").ZodString;
209
231
  requestedBy: import("zod").ZodString;
210
232
  at: import("zod").ZodString;
233
+ exposed: import("zod").ZodOptional<import("zod").ZodLiteral<true>>;
211
234
  status: import("zod").ZodEnum<{
212
235
  approved: "approved";
213
236
  closed: "closed";
@@ -230,6 +253,7 @@ declare const HUB_EXPORTS: {
230
253
  reason: import("zod").ZodString;
231
254
  requestedBy: import("zod").ZodString;
232
255
  at: import("zod").ZodString;
256
+ exposed: import("zod").ZodOptional<import("zod").ZodLiteral<true>>;
233
257
  }, import("zod/v4/core").$strip>>;
234
258
  decided: import("@agentorg/sdk").EventSpec<import("zod").ZodObject<{
235
259
  request: import("zod").ZodObject<{
@@ -245,6 +269,7 @@ declare const HUB_EXPORTS: {
245
269
  reason: import("zod").ZodString;
246
270
  requestedBy: import("zod").ZodString;
247
271
  at: import("zod").ZodString;
272
+ exposed: import("zod").ZodOptional<import("zod").ZodLiteral<true>>;
248
273
  }, import("zod/v4/core").$strip>;
249
274
  status: import("zod").ZodEnum<{
250
275
  approved: "approved";
@@ -310,6 +335,8 @@ export interface ActorRecord {
310
335
  /** Times its process was restarted after a crash. */
311
336
  restarts: number;
312
337
  lastExit?: Exit;
338
+ /** The Actor a manager made it for: provenance, never authority. */
339
+ installedFor?: string;
313
340
  }
314
341
  export interface Wiring {
315
342
  consumer: string;
@@ -321,6 +348,8 @@ export interface BindingRecord extends Wiring {
321
348
  interface: string;
322
349
  madeBy: string;
323
350
  at: string;
351
+ /** Its slot was made at run time by `expose`, and goes with it. */
352
+ exposed?: true;
324
353
  }
325
354
  /** The two ends of a binding: the export side gives the export, the slot side takes it. */
326
355
  export type Side = "export" | "slot";
@@ -336,6 +365,8 @@ export interface RequestRecord extends Wiring {
336
365
  reason: string;
337
366
  requestedBy: string;
338
367
  at: string;
368
+ /** A request to expose: `slot` is made on `consumer` when it is approved. */
369
+ exposed?: true;
339
370
  }
340
371
  export interface AuditRecord {
341
372
  seq: number;
@@ -374,6 +405,12 @@ export interface StateEvents {
374
405
  closed?(actorId: string): void;
375
406
  audited?(entry: AuditRecord): void;
376
407
  }
408
+ /**
409
+ * The default name of a slot exposing `exportName` of the Actor named `providerName`: the name's
410
+ * ASCII words camelCased, `_`, and the export's last part; the export's part alone when the name
411
+ * has no ASCII letters.
412
+ */
413
+ export declare function exposedName(providerName: string, exportName: string): string;
377
414
  /**
378
415
  * The core's state in its home folder: Actors, packages, declarations, bindings, binding requests
379
416
  * and the audit trail, in `node:sqlite`. Every method that changes something takes its caller, and
@@ -402,6 +439,8 @@ export declare class HubState {
402
439
  method?: string;
403
440
  outcome: CallOutcome;
404
441
  }): void;
442
+ /** An Actor as a refusal names it: "Name (id)", or the id alone when there's no such Actor. */
443
+ named(actorId: string): string;
405
444
  actor(actorId: string): ActorRecord;
406
445
  /** The host sandbox's status changed: every package Actor's record (its `host`) differs. */
407
446
  hostChanged(): void;
@@ -418,6 +457,8 @@ export declare class HubState {
418
457
  * export's interface, and its hello must declare it the same way to keep it.
419
458
  */
420
459
  bindings?: Omit<Wiring, "consumer">[];
460
+ /** The Actor it is made for: given only by a manager, recorded as provenance. */
461
+ for?: string;
421
462
  }): {
422
463
  actorId: string;
423
464
  credential?: string;
@@ -508,6 +549,28 @@ export declare class HubState {
508
549
  };
509
550
  /** Unbind a slot: its consumer, its provider or a manager may. */
510
551
  unbind(caller: string, consumer: string, slot: string): void;
552
+ /**
553
+ * Expose an export to one Actor: a slot made on `to` at run time, typed by the export's
554
+ * interface and bound to it, in one step. The authority is a binding's, with `to` as the
555
+ * consumer: with both ends it is made (approving any open request for it); with one, it is a
556
+ * request to the other end's approvers, who approve by exposing the same; with neither, it is
557
+ * refused. The same export already exposed to `to` gives that slot back.
558
+ */
559
+ expose(caller: string, input: {
560
+ provider: string;
561
+ export: string;
562
+ to: string;
563
+ as?: string;
564
+ }): {
565
+ exposed: true;
566
+ slot: string;
567
+ } | {
568
+ exposed: false;
569
+ slot: string;
570
+ requestId: string;
571
+ };
572
+ /** Remove a slot made by `expose`, with its binding: its consumer, its provider or a manager may. */
573
+ unexpose(caller: string, to: string, slot: string): void;
511
574
  /**
512
575
  * Ask for a binding the caller holds one end of; it goes to the other end's approvers. Asking
513
576
  * again for the same wiring while a request is open returns that request.