sealbridge 0.2.2 → 0.3.1

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 (251) hide show
  1. package/README.ja.md +492 -30
  2. package/README.md +522 -109
  3. package/dist/cli/dist/accept.d.ts +13 -0
  4. package/dist/cli/dist/accept.js +115 -0
  5. package/dist/cli/dist/accept.js.map +1 -0
  6. package/dist/cli/dist/approval-summary.d.ts +1 -1
  7. package/dist/cli/dist/board.d.ts +10 -9
  8. package/dist/cli/dist/board.js +62 -31
  9. package/dist/cli/dist/board.js.map +1 -1
  10. package/dist/cli/dist/command-identity.d.ts +6 -0
  11. package/dist/cli/dist/command-identity.js +13 -0
  12. package/dist/cli/dist/command-identity.js.map +1 -0
  13. package/dist/cli/dist/config.d.ts +3 -0
  14. package/dist/cli/dist/config.js +29 -0
  15. package/dist/cli/dist/config.js.map +1 -0
  16. package/dist/cli/dist/connections.d.ts +15 -0
  17. package/dist/cli/dist/connections.js +191 -0
  18. package/dist/cli/dist/connections.js.map +1 -0
  19. package/dist/cli/dist/contacts.d.ts +4 -3
  20. package/dist/cli/dist/contacts.js +39 -28
  21. package/dist/cli/dist/contacts.js.map +1 -1
  22. package/dist/cli/dist/doctor.d.ts +9 -0
  23. package/dist/cli/dist/doctor.js +46 -5
  24. package/dist/cli/dist/doctor.js.map +1 -1
  25. package/dist/cli/dist/error-messages.js +22 -0
  26. package/dist/cli/dist/error-messages.js.map +1 -1
  27. package/dist/cli/dist/index.js +44 -6
  28. package/dist/cli/dist/index.js.map +1 -1
  29. package/dist/cli/dist/invite-output.d.ts +14 -0
  30. package/dist/cli/dist/invite-output.js +66 -0
  31. package/dist/cli/dist/invite-output.js.map +1 -0
  32. package/dist/cli/dist/invite-share.d.ts +6 -3
  33. package/dist/cli/dist/invite-share.js +40 -15
  34. package/dist/cli/dist/invite-share.js.map +1 -1
  35. package/dist/cli/dist/invites-migrate.d.ts +3 -0
  36. package/dist/cli/dist/invites-migrate.js +33 -0
  37. package/dist/cli/dist/invites-migrate.js.map +1 -0
  38. package/dist/cli/dist/mcp.d.ts +7 -5
  39. package/dist/cli/dist/mcp.js +23 -18
  40. package/dist/cli/dist/mcp.js.map +1 -1
  41. package/dist/cli/dist/network.d.ts +11 -1
  42. package/dist/cli/dist/network.js +150 -87
  43. package/dist/cli/dist/network.js.map +1 -1
  44. package/dist/cli/dist/pending.d.ts +8 -0
  45. package/dist/cli/dist/pending.js +50 -0
  46. package/dist/cli/dist/pending.js.map +1 -0
  47. package/dist/cli/dist/public-settings.d.ts +5 -4
  48. package/dist/cli/dist/public-settings.js +13 -15
  49. package/dist/cli/dist/public-settings.js.map +1 -1
  50. package/dist/cli/dist/receipt.d.ts +1 -1
  51. package/dist/cli/dist/relay-auth.d.ts +3 -0
  52. package/dist/cli/dist/relay-auth.js +23 -0
  53. package/dist/cli/dist/relay-auth.js.map +1 -0
  54. package/dist/cli/dist/requests.d.ts +10 -0
  55. package/dist/cli/dist/requests.js +91 -0
  56. package/dist/cli/dist/requests.js.map +1 -0
  57. package/dist/cli/dist/sdk.d.ts +10 -0
  58. package/dist/cli/dist/sdk.js +7 -0
  59. package/dist/cli/dist/sdk.js.map +1 -0
  60. package/dist/cli/dist/setup-files.d.ts +24 -0
  61. package/dist/cli/dist/setup-files.js +190 -0
  62. package/dist/cli/dist/setup-files.js.map +1 -0
  63. package/dist/cli/dist/setup-hosts.d.ts +29 -0
  64. package/dist/cli/dist/setup-hosts.js +75 -0
  65. package/dist/cli/dist/setup-hosts.js.map +1 -0
  66. package/dist/cli/dist/setup.d.ts +61 -0
  67. package/dist/cli/dist/setup.js +243 -0
  68. package/dist/cli/dist/setup.js.map +1 -0
  69. package/dist/cli/dist/task-input.d.ts +1 -1
  70. package/dist/cli/dist/wake-hook.d.ts +1 -1
  71. package/dist/cli/dist/worker-json.d.ts +4 -0
  72. package/dist/cli/dist/worker-json.js +87 -0
  73. package/dist/cli/dist/worker-json.js.map +1 -0
  74. package/dist/examples/two-owner-demo/dist/run-demo.d.ts +13 -13
  75. package/dist/package.json +1 -1
  76. package/dist/packages/adapters/dist/command.d.ts +2 -2
  77. package/dist/packages/adapters/dist/credential-proxy.d.ts +2 -2
  78. package/dist/packages/adapters/dist/index.d.ts +1 -1
  79. package/dist/packages/adapters/dist/mcp.d.ts +2 -2
  80. package/dist/packages/adapters/dist/openai.d.ts +2 -2
  81. package/dist/packages/adapters/dist/sandbox.d.ts +2 -2
  82. package/dist/packages/core/dist/connection.d.ts +58 -0
  83. package/dist/packages/core/dist/connection.js +132 -0
  84. package/dist/packages/core/dist/connection.js.map +1 -0
  85. package/dist/packages/core/dist/delivery-status.d.ts +22 -0
  86. package/dist/packages/core/dist/delivery-status.js +53 -0
  87. package/dist/packages/core/dist/delivery-status.js.map +1 -0
  88. package/dist/packages/core/dist/discovery.d.ts +7 -6
  89. package/dist/packages/core/dist/discovery.js +19 -20
  90. package/dist/packages/core/dist/discovery.js.map +1 -1
  91. package/dist/packages/core/dist/edge.d.ts +1 -0
  92. package/dist/packages/core/dist/edge.js +1 -0
  93. package/dist/packages/core/dist/edge.js.map +1 -1
  94. package/dist/packages/core/dist/index.d.ts +3 -0
  95. package/dist/packages/core/dist/index.js +3 -0
  96. package/dist/packages/core/dist/index.js.map +1 -1
  97. package/dist/packages/core/dist/protocol.d.ts +24 -0
  98. package/dist/packages/core/dist/protocol.js +54 -0
  99. package/dist/packages/core/dist/protocol.js.map +1 -0
  100. package/dist/packages/core/dist/receipts.d.ts +1 -0
  101. package/dist/packages/core/dist/receipts.js +1 -1
  102. package/dist/packages/core/dist/receipts.js.map +1 -1
  103. package/dist/packages/core/dist/schema.d.ts +1 -0
  104. package/dist/packages/core/dist/schema.js +13 -2
  105. package/dist/packages/core/dist/schema.js.map +1 -1
  106. package/dist/packages/ledger/dist/index.d.ts +1 -1
  107. package/dist/packages/relay/dist/admission.d.ts +14 -0
  108. package/dist/packages/relay/dist/admission.js +70 -0
  109. package/dist/packages/relay/dist/admission.js.map +1 -0
  110. package/dist/packages/relay/dist/fetch.d.ts +8 -2
  111. package/dist/packages/relay/dist/fetch.js +41 -12
  112. package/dist/packages/relay/dist/fetch.js.map +1 -1
  113. package/dist/packages/relay/dist/index.d.ts +23 -12
  114. package/dist/packages/relay/dist/index.js +130 -78
  115. package/dist/packages/relay/dist/index.js.map +1 -1
  116. package/dist/packages/relay/dist/journal.d.ts +1 -1
  117. package/dist/packages/relay/dist/notifications.d.ts +1 -1
  118. package/dist/packages/relay/dist/retry.d.ts +23 -0
  119. package/dist/packages/relay/dist/retry.js +43 -1
  120. package/dist/packages/relay/dist/retry.js.map +1 -1
  121. package/dist/packages/relay/dist/ssrf.d.ts +3 -2
  122. package/dist/packages/relay/dist/ssrf.js.map +1 -1
  123. package/dist/packages/relay/dist/worker.js +1 -1
  124. package/dist/packages/relay/dist/worker.js.map +1 -1
  125. package/dist/packages/runtime/dist/a2a.d.ts +1 -1
  126. package/dist/packages/runtime/dist/a2a.js +1 -1
  127. package/dist/packages/runtime/dist/adapter.d.ts +2 -2
  128. package/dist/packages/runtime/dist/application-config.d.ts +20 -0
  129. package/dist/packages/runtime/dist/application-config.js +218 -0
  130. package/dist/packages/runtime/dist/application-config.js.map +1 -0
  131. package/dist/packages/runtime/dist/approval-providers.d.ts +24 -3
  132. package/dist/packages/runtime/dist/approval-providers.js +79 -3
  133. package/dist/packages/runtime/dist/approval-providers.js.map +1 -1
  134. package/dist/packages/runtime/dist/connection-admission-review.d.ts +39 -0
  135. package/dist/packages/runtime/dist/connection-admission-review.js +86 -0
  136. package/dist/packages/runtime/dist/connection-admission-review.js.map +1 -0
  137. package/dist/packages/runtime/dist/connection-persistence.d.ts +35 -0
  138. package/dist/packages/runtime/dist/connection-persistence.js +181 -0
  139. package/dist/packages/runtime/dist/connection-persistence.js.map +1 -0
  140. package/dist/packages/runtime/dist/connection-records.d.ts +167 -0
  141. package/dist/packages/runtime/dist/connection-records.js +132 -0
  142. package/dist/packages/runtime/dist/connection-records.js.map +1 -0
  143. package/dist/packages/runtime/dist/connection-router.d.ts +45 -0
  144. package/dist/packages/runtime/dist/connection-router.js +130 -0
  145. package/dist/packages/runtime/dist/connection-router.js.map +1 -0
  146. package/dist/packages/runtime/dist/connection-service.d.ts +159 -0
  147. package/dist/packages/runtime/dist/connection-service.js +239 -0
  148. package/dist/packages/runtime/dist/connection-service.js.map +1 -0
  149. package/dist/packages/runtime/dist/connection-transport.d.ts +14 -0
  150. package/dist/packages/runtime/dist/connection-transport.js +89 -0
  151. package/dist/packages/runtime/dist/connection-transport.js.map +1 -0
  152. package/dist/packages/runtime/dist/delivery-records.d.ts +180 -0
  153. package/dist/packages/runtime/dist/delivery-records.js +205 -0
  154. package/dist/packages/runtime/dist/delivery-records.js.map +1 -0
  155. package/dist/packages/runtime/dist/delivery-status-router.d.ts +27 -0
  156. package/dist/packages/runtime/dist/delivery-status-router.js +150 -0
  157. package/dist/packages/runtime/dist/delivery-status-router.js.map +1 -0
  158. package/dist/packages/runtime/dist/delivery-status.d.ts +43 -0
  159. package/dist/packages/runtime/dist/delivery-status.js +193 -0
  160. package/dist/packages/runtime/dist/delivery-status.js.map +1 -0
  161. package/dist/packages/runtime/dist/delivery-store.d.ts +125 -0
  162. package/dist/packages/runtime/dist/delivery-store.js +1047 -0
  163. package/dist/packages/runtime/dist/delivery-store.js.map +1 -0
  164. package/dist/packages/runtime/dist/gateway.d.ts +4 -3
  165. package/dist/packages/runtime/dist/gateway.js.map +1 -1
  166. package/dist/packages/runtime/dist/held-request-review.d.ts +49 -0
  167. package/dist/packages/runtime/dist/held-request-review.js +122 -0
  168. package/dist/packages/runtime/dist/held-request-review.js.map +1 -0
  169. package/dist/packages/runtime/dist/held-request-store.d.ts +112 -0
  170. package/dist/packages/runtime/dist/held-request-store.js +290 -0
  171. package/dist/packages/runtime/dist/held-request-store.js.map +1 -0
  172. package/dist/packages/runtime/dist/idempotency-store.d.ts +53 -0
  173. package/dist/packages/runtime/dist/idempotency-store.js +331 -0
  174. package/dist/packages/runtime/dist/idempotency-store.js.map +1 -0
  175. package/dist/packages/runtime/dist/inbox.d.ts +1 -1
  176. package/dist/packages/runtime/dist/index.d.ts +27 -1
  177. package/dist/packages/runtime/dist/index.js +26 -0
  178. package/dist/packages/runtime/dist/index.js.map +1 -1
  179. package/dist/packages/runtime/dist/invite-store.d.ts +76 -0
  180. package/dist/packages/runtime/dist/invite-store.js +337 -0
  181. package/dist/packages/runtime/dist/invite-store.js.map +1 -0
  182. package/dist/packages/runtime/dist/key-store.d.ts +77 -0
  183. package/dist/packages/runtime/dist/key-store.js +226 -0
  184. package/dist/packages/runtime/dist/key-store.js.map +1 -0
  185. package/dist/packages/runtime/dist/local-identity.d.ts +33 -0
  186. package/dist/packages/runtime/dist/local-identity.js +279 -0
  187. package/dist/packages/runtime/dist/local-identity.js.map +1 -0
  188. package/dist/packages/runtime/dist/mcp-rpc.d.ts +19 -0
  189. package/dist/packages/runtime/dist/mcp-rpc.js +175 -0
  190. package/dist/packages/runtime/dist/mcp-rpc.js.map +1 -0
  191. package/dist/packages/runtime/dist/mcp-server.d.ts +46 -19
  192. package/dist/packages/runtime/dist/mcp-server.js +427 -184
  193. package/dist/packages/runtime/dist/mcp-server.js.map +1 -1
  194. package/dist/packages/runtime/dist/mcp-tool-catalog.d.ts +1 -1
  195. package/dist/packages/runtime/dist/mcp-tool-catalog.js +172 -13
  196. package/dist/packages/runtime/dist/mcp-tool-catalog.js.map +1 -1
  197. package/dist/packages/runtime/dist/mcp.d.ts +2 -2
  198. package/dist/packages/runtime/dist/message-status.d.ts +32 -0
  199. package/dist/packages/runtime/dist/message-status.js +29 -0
  200. package/dist/packages/runtime/dist/message-status.js.map +1 -0
  201. package/dist/packages/runtime/dist/outbox.d.ts +91 -0
  202. package/dist/packages/runtime/dist/outbox.js +462 -0
  203. package/dist/packages/runtime/dist/outbox.js.map +1 -0
  204. package/dist/packages/runtime/dist/policy.d.ts +1 -1
  205. package/dist/packages/runtime/dist/protocol-peer-store.d.ts +40 -0
  206. package/dist/packages/runtime/dist/protocol-peer-store.js +176 -0
  207. package/dist/packages/runtime/dist/protocol-peer-store.js.map +1 -0
  208. package/dist/packages/runtime/dist/protocol-release.d.ts +26 -0
  209. package/dist/packages/runtime/dist/protocol-release.js +76 -0
  210. package/dist/packages/runtime/dist/protocol-release.js.map +1 -0
  211. package/dist/packages/runtime/dist/quota.d.ts +1 -1
  212. package/dist/packages/runtime/dist/relay-selection.d.ts +20 -0
  213. package/dist/packages/runtime/dist/relay-selection.js +34 -0
  214. package/dist/packages/runtime/dist/relay-selection.js.map +1 -0
  215. package/dist/packages/runtime/dist/requester-pending-store.d.ts +59 -0
  216. package/dist/packages/runtime/dist/requester-pending-store.js +266 -0
  217. package/dist/packages/runtime/dist/requester-pending-store.js.map +1 -0
  218. package/dist/packages/runtime/dist/secret-store.d.ts +19 -0
  219. package/dist/packages/runtime/dist/secret-store.js +51 -0
  220. package/dist/packages/runtime/dist/secret-store.js.map +1 -0
  221. package/dist/packages/runtime/dist/session-audit.d.ts +29 -7
  222. package/dist/packages/runtime/dist/session-audit.js +149 -29
  223. package/dist/packages/runtime/dist/session-audit.js.map +1 -1
  224. package/dist/packages/runtime/dist/session.d.ts +101 -9
  225. package/dist/packages/runtime/dist/session.js +696 -96
  226. package/dist/packages/runtime/dist/session.js.map +1 -1
  227. package/dist/packages/runtime/dist/task-journal.d.ts +18 -3
  228. package/dist/packages/runtime/dist/task-journal.js +271 -18
  229. package/dist/packages/runtime/dist/task-journal.js.map +1 -1
  230. package/dist/packages/runtime/dist/verifier.d.ts +3 -2
  231. package/dist/packages/runtime/dist/verifier.js +1 -0
  232. package/dist/packages/runtime/dist/verifier.js.map +1 -1
  233. package/dist/packages/runtime/dist/worker-trust-store.d.ts +111 -0
  234. package/dist/packages/runtime/dist/worker-trust-store.js +592 -0
  235. package/dist/packages/runtime/dist/worker-trust-store.js.map +1 -0
  236. package/dist/packages/sandbox/dist/container.d.ts +1 -1
  237. package/dist/packages/sandbox/dist/index.d.ts +1 -1
  238. package/dist/spec/README.ja.md +21 -1
  239. package/dist/spec/README.md +20 -1
  240. package/dist/spec/agent-card.schema.json +11 -1
  241. package/dist/spec/delivery-status.schema.json +106 -0
  242. package/dist/spec/examples/protocol-versions/sample-agent-card.json +35 -0
  243. package/dist/spec/examples/sample-delivery-status.json +21 -0
  244. package/dist/spec/examples/sample-task-manifest.0.1.0.json +173 -0
  245. package/dist/spec/examples/sample-task-manifest.0.2.0.json +173 -0
  246. package/dist/spec/task-manifest.0.1.0.schema.json +422 -0
  247. package/dist/spec/task-manifest.0.2.0.schema.json +422 -0
  248. package/dist/spec/task-manifest.schema.json +9 -418
  249. package/docs/sdk.ja.md +133 -0
  250. package/docs/sdk.md +138 -0
  251. package/package.json +15 -3
package/README.md CHANGED
@@ -14,11 +14,15 @@ Windows PowerShell:
14
14
  irm https://sealbridge.dev/install.ps1 | iex
15
15
  ```
16
16
 
17
- The installers pin the current release, sealbridge 0.2.1, which is published on npm. With Node 22+, you can also use `npm i -g sealbridge` or `npx sealbridge@latest`.
17
+ The installers pin sealbridge 0.3.1, pending publication on npm. Deploy the updated installers only after sealbridge@0.3.1 is on npm. With Node 22+, you can also use `npm i -g sealbridge` or `npx sealbridge@latest`.
18
18
 
19
- The installer uses a user-local directory, verifies the official Node 22.22.0 archive checksum when Node is needed, and asks for no secrets. No telemetry, sudo, Git or pnpm is required. On macOS/Linux open a new terminal or run `. "$HOME/.profile"` after installing; a piped shell cannot change its parent shell's PATH. Windows updates the current session and user PATH. Run `sealbridge doctor`, then `sealbridge demo`. Doctor makes one relay health request; offline warnings do not undo installation.
19
+ The installer reuses Node 22 or newer only when its co-installed npm runs successfully; otherwise it installs Node with bundled npm in a user-local directory without changing the existing Node. It verifies the official Node 22.22.0 archive checksum when Node is needed, and asks for no secrets. No telemetry, sudo, Git or pnpm is required. On macOS/Linux open a new terminal or run `. "$HOME/.profile"` after installing; a piped shell cannot change its parent shell's PATH. Windows updates the current session and user PATH. Run `sealbridge doctor`, then `sealbridge demo`. Doctor makes one relay health request; offline warnings do not undo installation.
20
20
 
21
- The installer and `sealbridge doctor` report the Node executable's resolved path and version. On Windows, the installer checks the Node used by the npm shim in its install prefix: a `node.exe` beside the shim takes precedence over PATH. On macOS/Linux, the launcher uses Node from PATH. Doctor reports its own running Node, so changing PATH later can change the reported runtime. Successful checks use short `(OK)` lines; only `(WARN)` lines include fix hints. A missing worker key is optional; before receiving tasks, create the `.acp` directory and run `sealbridge keygen "$HOME/.acp/worker.private.json"`, or select an existing key with `--key`.
21
+ Release note: The following are available from sealbridge npm package 0.3.0;
22
+ they are not supported in CLI 0.2.2 and earlier:
23
+ `doctor --offline`.
24
+
25
+ The installer and `sealbridge doctor` report the Node executable's resolved path and version. On Windows, npm must be installed beside the resolved Node; on macOS/Linux, the npm launcher beside the resolved Node must point to npm's JavaScript entry point (symlinks are supported). The installer runs npm with that exact Node. Windows command and PowerShell shims pin the selected runtime; macOS/Linux shims use the selected Node first on PATH. Doctor reports its own running Node, so changing PATH later on macOS/Linux can change the reported runtime. Successful checks use short `(OK)` lines; only `(WARN)` lines include fix hints. Identity files are created on first use; installers and doctor do not generate them. Use `sealbridge doctor --offline` to inspect local configuration without a relay request.
22
26
 
23
27
  To uninstall, download the same script and run `sh install.sh --uninstall` or `& ./install.ps1 -Uninstall` (PowerShell spelling of --uninstall). Keys are retained. Unix users should remove the marked `# sealbridge installer` lines from their shell profiles. npm-only installs use `npm uninstall -g sealbridge`. Installer locations: `~/.local/share/sealbridge` and `%LOCALAPPDATA%\Sealbridge`.
24
28
 
@@ -43,8 +47,12 @@ To uninstall, download the same script and run `sh install.sh --uninstall` or `&
43
47
  [![License](https://img.shields.io/badge/License-Apache_2.0_%2F_MIT-blue.svg)](./LICENSE)
44
48
  [![X (@takapon01234)](https://img.shields.io/badge/X-%40takapon01234-000000?logo=x)](https://x.com/takapon01234)
45
49
 
46
- > **Status**: Sealbridge `v0.2.1` is the latest release, published on npm as `sealbridge`. The earlier `v1.0.0` label refers to the legacy pre-Sealbridge ACP / agent-collab-platform release, not a Sealbridge npm release.
47
- > **Target**: An open-source protocol and reference implementation that lets autonomous agents owned by different people split, delegate, run, verify, and accept work without trusting each other's runtimes or credentials.
50
+ [![Sealbridge demo: install, delegate a code review, receive a signed result, and inspect the audit log (English captions)](docs/media/sealbridge-demo.gif)](docs/media/sealbridge-demo.mp4)
51
+
52
+ 30-second demo, no audio — [watch the MP4](docs/media/sealbridge-demo.mp4).
53
+
54
+ > **Status**: Sealbridge `v0.3.1` is being prepared for release on npm as `sealbridge`; publication is pending. Sealbridge `v0.3.0` was published on npm as `sealbridge` on 2026-11-03 UTC. The earlier `v1.0.0` label refers to the legacy pre-Sealbridge ACP / agent-collab-platform release, not a Sealbridge npm release.
55
+ > **Target**: An open-source protocol and reference implementation that lets autonomous agents owned by different people split, delegate, run, verify, and accept work without trusting each other's runtimes or credentials.
48
56
  > **Author**: [@takapon01234](https://x.com/takapon01234)
49
57
 
50
58
  - CI runs 967 automated unit/integration/conformance tests (`pnpm test`) plus the adversarial security test suite (`pnpm test:security-proof`).
@@ -63,26 +71,89 @@ Run the full 4-scenario zero-trust collaboration & red-team tamper defense demo
63
71
  git clone https://github.com/sealbridge/sealbridge.git && cd sealbridge && pnpm install --frozen-lockfile && pnpm build && pnpm sealbridge demo
64
72
  ```
65
73
 
66
- Or add **`sealbridge mcp-server`** directly to **Claude Desktop**, **Cursor**, **Codex**, or **Grok Bot** (`mcpServers` config):
74
+ ### Local host setup
75
+
76
+ Release note: The following are available from sealbridge npm package 0.3.0;
77
+ they are not supported in CLI 0.2.2 and earlier:
78
+ `setup`, `accept`.
79
+
80
+ With CLI 0.3.0 or later, check `sealbridge setup --help`, then run
81
+ `sealbridge setup --host cursor` or `sealbridge setup --host claude-desktop`
82
+ (macOS/Windows). Plain `setup` selects a single detected user host or offers a
83
+ terminal choice. Repeat `--host` or use `--all-detected`; Claude Code requires
84
+ `--host claude-code --project` with an absolute project path. `--dry-run` plans
85
+ and `--print` prints proposed entries; both validate without writing. A source
86
+ checkout must be built first and run via `node cli/dist/index.js setup`.
87
+
88
+ Setup locally creates/reuses requester identity, optionally worker with
89
+ `--worker`, records the existing `config.json` relay-list contract, and registers
90
+ absolute Node/CLI paths for `mcp-server --require-approval`. This requests host
91
+ form elicitation before sending and for final verification. Host support cannot
92
+ be detected offline; hosts without forms return `APPROVAL_CHANNEL_UNAVAILABLE`
93
+ before sending. Explicit `--no-require-approval` registers plain `mcp-server`:
94
+ the host can send without per-request confirmation and accept final results
95
+ automatically. Apply, `--dry-run`, and `--print` label each entry's approval mode. Setup sends
96
+ nothing to the network and starts no process. `--relay URL` records a fallback
97
+ and refuses a differing saved default. Existing entries must match exactly;
98
+ an entry in the other approval mode returns `SETUP_APPROVAL_MODE_CONFLICT`
99
+ without changes. Review with `--update-existing --dry-run` or
100
+ `--update-existing --print`, then use `--update-existing` to replace only the
101
+ Sealbridge entry. To keep a previous plain entry, use `--no-require-approval`.
102
+ Close host settings before applying; changed files get exact backups under
103
+ `<data-root>/setup/backups`. Backups may contain host credentials. Multiple files
104
+ are not an atomic transaction; inspect partial results and rerun after fixing
105
+ the cause. Reload the host and check its tools separately. Registration does
106
+ not grant task approval or prove host readiness. Existing configs remain
107
+ untouched unless setup is run; rerunning with matching options changes nothing.
108
+
109
+ Follow the [agent-readable instructions](sites/connect-agent.txt) for human-run
110
+ `sealbridge accept --paste` and `acp_list_invites`/`workerRef`, or open-worker
111
+ `acp_discover_workers` then `acp_delegate_task` with returned `workerDid` and
112
+ `relayUrl`. Invitation import and open discovery require sealbridge 0.3.0
113
+ (CLI 0.3.0 and later); check help and the tool catalog before use. Setup supports
114
+ strict JSON host configs only; TOML/JSONC adapters are deferred.
115
+
116
+ `sealbridge mcp-server`, `delegate`, `worker start`, `discover`, and `invite create` need no `--key` or `--relay`. The application uses `https://relay.sealbridge.dev` by default. MCP initialization and tool listing make no network request. Discovery reads the relay directory; delegation sends encrypted task payloads and routing metadata is visible to the relay. Invite creation only signs locally and does not start a worker.
117
+
118
+ Identities persist at `<data-root>/identities/requester.private.json` and `worker.private.json`. MCP delegation and CLI delegation use requester; worker startup and CLI invite creation use worker. MCP signing tools use the server requester identity (or its explicit owner key). MCP loads them lazily, so scanning does not require a writable home. The data root is `SEALBRIDGE_DATA_DIR`, then `ACP_DATA_DIR` (absolute paths only), otherwise `%LOCALAPPDATA%\Sealbridge` on Windows (home/AppData/Local fallback), `~/Library/Application Support/Sealbridge` on macOS, or `$XDG_DATA_HOME/sealbridge` on Linux (`~/.local/share/sealbridge` fallback).
119
+
120
+ POSIX application directories use 0700 and keys use 0600, with ownership/type/mode checks. Windows files inherit the per-user LOCALAPPDATA tree's DACL; Node mode bits do not establish a user-only DACL and this release does not verify ACLs. Overrides inherit their parent's access and require user management. Detectable links and non-files are rejected, except macOS’s root-owned `/var` and `/tmp` aliases to their corresponding `/private` directories. First-use publication requires same-directory hard links; unsupported filesystems return `IDENTITY_CREATION_UNSUPPORTED`.
121
+
122
+ Existing role-matched `~/.acp/{requester,worker}.private.json` keys and the old contacts-root `owner.private.json` (requester only) are reused in place when the canonical key is absent. Conflicting legacy requester identities return `IDENTITY_SELECTION_REQUIRED`; select one with `--key`. Existing canonical keys take precedence. Invalid or unreadable files return an error and are never replaced. `keygen <path>` still creates only an explicit, previously unused path.
123
+
124
+ Release note: The following are available from sealbridge npm package 0.3.0;
125
+ they are not supported in CLI 0.2.2 and earlier:
126
+ `config key-store`, `doctor --offline`.
127
+
128
+ Private-key storage defaults to files. `sealbridge config key-store` reports the effective backend and source; `sealbridge config key-store file|keychain` persists `"keyStore"` in version-1 `<data-root>/config.json` alongside relays. Precedence is programmatic option > `SEALBRIDGE_KEY_STORE` > config > default file. `--key <path>` always selects a file. Setting the backend checks availability and reports identities in the other backend without moving, creating, or deleting keys. Other config fields are retained; setting the same value preserves existing bytes. An environment override still applies after setting the config.
129
+
130
+ Without `--key`, board post/serve/dispatch use requester and board claim uses worker; contacts, invite open, and invite request-reissue use requester; invite reissue uses worker. Existing explicit-file readers and MCP tool names are unchanged. Board listing, contacts listing, and MCP listing do not create identities. Contacts and default reciprocal invite outputs keep their existing directory locations. Invite open reuses the role identity (including existing legacy requester files); first use follows the selected store. File output includes `local.keyFile`; keychain output includes `local.keyStore` and `local.role` instead of a file path. `invite share` does not access identity storage.
131
+
132
+ The keychain backend dynamically imports optional [`@napi-rs/keyring`](https://github.com/Brooooooklyn/keyring-node) (MIT license; 2.x, >=2.1.2). Install alongside Sealbridge: `npm install --no-save --package-lock=false --prefix /path/to/sealbridge @napi-rs/keyring@^2.1.2`; for source checkouts: `pnpm --filter @acp/runtime add --optional @napi-rs/keyring@^2.1.2`. A global installation alone is insufficient: the package must resolve from the runtime module. Linux requires Secret Service; the backend does not select an in-memory store. Native distributions include third-party license notices.
133
+
134
+ Entries hold private Ed25519 JWK JSON with the DID in `kid`. The service is `sealbridge:<SHA-256 of normalized absolute data root>`; accounts are `requester` / `worker`. Creation writes no identity file and uses a temporary `.keychain-<role>.lock` in the data root containing no key material. Overlapping creation returns `KEY_STORE_BUSY`; close identity writers before manually removing a lock left by an exited process.
135
+
136
+ An unavailable explicitly selected keychain returns `KEY_STORE_UNAVAILABLE` without file fallback. Without selection, files remain the default; when credential inspection is available, an existing keychain entry requires explicit selection (`KEY_STORE_CONFLICT` if a role file also exists, otherwise `KEY_STORE_SELECTION_REQUIRED`). Explicit selection leaves both identities in place. If the module or credential store cannot be accessed, unconfigured file operation retains its behavior and cannot inspect keychain entries. There is no automatic migration. `sealbridge doctor --offline` reports backend, selection source (`option`, `env`, `config`, or `default`), location, and presence without creating keys or contacting the relay; OS credential access UI may appear.
137
+
138
+ Embedders can implement runtime `KeyStore` (`load`, `createIfMissing`, `exists`, `describe`) and pass `identityOptions: { keyStore: myStore }` to `AcpMcpServer`, or `{ keyStore: myStore }` to `resolveStoredIdentity` / `inspectStoredIdentity`. Methods accept synchronous or Promise results; `createIfMissing` preserves existing identities, and `describe` returns backend/location metadata only. `FileKeyStore` wraps the unchanged file implementation. Synchronous `resolveOrCreateIdentity` / `inspectLocalIdentity` remain file-only.
139
+
140
+ Explicit `--key` selects an existing identity. An explicit `--relay` pins routing; without a pin, a verified invite's relay takes precedence over the public fallback. Explicit worker/relay allowlists, including empty programmatic lists, remain authoritative. Injected transports remain authoritative for embedded callers. Loopback relays still require `--allow-private-relay`.
141
+
142
+ Application relay defaults can be stored in `<data-root>/config.json`:
67
143
 
68
144
  ```json
69
145
  {
70
- "mcpServers": {
71
- "sealbridge": {
72
- "command": "node",
73
- "args": [
74
- "/path/to/sealbridge/cli/dist/index.js",
75
- "mcp-server",
76
- "--key",
77
- "/tmp/alice.private.json",
78
- "--relay",
79
- "https://relay.sealbridge.dev"
80
- ]
81
- }
82
- }
146
+ "version": 1,
147
+ "relays": ["https://relay.sealbridge.dev", "https://relay.example"]
83
148
  }
84
149
  ```
85
150
 
151
+ Without this file, the in-memory default is `{ "version": 1, "relays": ["https://relay.sealbridge.dev"] }`. Reads create no files or identities. CLI network operations and MCP relay operations load this file; MCP initialization and tool listing do not load it. Use the same directory and file permissions as the identity store (0700/0600 on POSIX).
152
+
153
+ Only the first local fallback is active. Additional entries are stored candidates: they are never contacted, registered with, or tried after an error, including HTTP 401. There is no failover, fan-out, parallel discovery, or automatic resend to another relay. Selection remains injected transport, explicit/configured pin, verified invite, first local fallback, then the built-in default. An invite may select a relay outside the candidates; existing allowlists still apply and are never expanded by this file. Cards, invites, manifests, discovery output, and audit routing retain one relay URL.
154
+
155
+ Candidate URLs are normalized to origin plus pathname without a trailing slash and deduplicated in order. The entire list is validated locally before use. Invalid or unreadable configuration stops the operation. The compatibility form `{ "version": 1, "relay": "https://relay.example" }` is accepted as a singleton without rewriting the file; contradictory scalar/list forms are rejected. Existing CLI `--relay`, MCP `relayUrl`, and constructor `relay` remain scalar. This version adds no config-management command or MCP argument.
156
+
86
157
  An MCP host can pass untrusted tool arguments. Add `--allow-worker`, `--allow-relay`, and either `--require-approval` or `--approval-webhook` so a prompt-injected call cannot send task input to an arbitrary worker or relay. The MCP section below lists those flags.
87
158
 
88
159
  ## One-screen summary
@@ -151,7 +222,7 @@ pnpm build
151
222
 
152
223
  **Public relay (cross-machine default)**
153
224
 
154
- Cross-machine collaboration uses the hosted Cloudflare Blind Relay at `https://relay.sealbridge.dev`. Both owners connect immediately with `--relay https://relay.sealbridge.dev`. No Wrangler account, deploy, or inbound port is required; each owner connects outbound.
225
+ Cross-machine collaboration uses the hosted Cloudflare Blind Relay at `https://relay.sealbridge.dev`. Both owners connect immediately using the default relay; `--relay` selects an explicit relay. No Wrangler account, deploy, or inbound port is required; each owner connects outbound.
155
226
 
156
227
  ```sh
157
228
  --relay https://relay.sealbridge.dev
@@ -159,16 +230,16 @@ Cross-machine collaboration uses the hosted Cloudflare Blind Relay at `https://r
159
230
 
160
231
  The public relay is untrusted transport. Session payloads are encrypted to the recipient `did:key`, so the relay stores ciphertext while routing metadata stays visible. `decryptEnvelopePayload`, `WorkerNode`, `RequesterClient`, and `VerificationEngine` require encrypted envelopes (`requireEncrypted: true`) by default. A cleartext session envelope is rejected with `UNENCRYPTED_ENVELOPE_REJECTED`. `{ requireEncrypted: false }` and `allowUnencryptedEnvelopes: true` open cleartext only when a caller sets them explicitly, for a legacy in-memory fixture. To run your own relay, copy `packages/relay/wrangler.toml.example` to `packages/relay/wrangler.toml` and deploy it with your Wrangler account. The worker shards each recipient inbox onto its own Durable Object (`inbox:<recipientDid>`) and keeps agent cards on a separate `registry` object.
161
232
 
162
- Queued envelopes expire after 10 minutes. Replay cache entries and agent cards expire after 1 hour. Each inbox accepts at most 256 envelopes, 256 KiB each, and 4 MiB total. `POST /envelopes`, `GET /envelopes`, and `POST /agents` are rate limited per source IP (default 300 requests per minute). Exceeding the byte budget or the rate limit returns HTTP 429. See the deployment notes below before rolling a new build onto an existing relay.
233
+ Newly admitted envelopes expire after 24 hours by default (`ACP_ENVELOPE_TTL_MS` or local `--envelope-ttl-ms`). Existing stored expiries are preserved on upgrade. Replay cache entries and agent cards expire after 1 hour; an ID still queued is also rejected after replay-cache expiry or turnover. Replay history is bounded after both records are gone. Each inbox accepts at most 256 envelopes, 256 KiB each, and 4 MiB total, including leased envelopes. Sender occupancy defaults to 256 per recipient. Queue/global capacity or sender occupancy refusal returns HTTP 429 with `{"error":"RELAY_RETRY_LATER","retryable":true,"retryAfterMs":60000}` and `Retry-After: 60`; the refused envelope is not stored. An envelope exceeding a configured single-envelope or recipient byte cap is a permanent HTTP 400 error. Existing clients surface `RELAY_REJECTED: 429` without automatic send retries. See [retention and admission configuration](docs/relay-reliability.md#retention-and-admission). `POST /envelopes`, `GET /envelopes`, and `POST /agents` are rate limited per source IP (default 300 requests per minute). Rate limiting retains its existing HTTP 429 response. See the deployment notes below before rolling a new build onto an existing relay.
163
234
 
164
235
  **Self-hosted relay deployment**
165
236
 
166
- Do not deploy this change onto a live relay until in-flight traffic has drained. The previous build stored every queue and the agent registry in one Durable Object named `acp-relay`, as a single JSON snapshot. This build does not read that object.
237
+ The hosted relay needs an operator-controlled Worker deployment/config update for these defaults and admission responses to take effect; this change does not deploy it. Local and embedded relays use the new default when upgraded. Current sharded inboxes keep their stored expiries, class name and migration tag. If replacing a pre-sharding build, drain in-flight traffic first: that build used one `acp-relay` object, which the sharded worker does not read.
167
238
 
168
- 1. Stop senders, or wait at least 15 minutes so queued envelopes expire and recipients retry.
239
+ 1. For a pre-sharding relay, stop senders and drain queued envelopes, or wait through its configured retention interval. Confirm the old queues are empty before switching layouts.
169
240
  2. Copy `packages/relay/wrangler.toml.example` to `packages/relay/wrangler.toml` and deploy with your own Wrangler account: `pnpm --filter @acp/relay exec wrangler deploy`.
170
- 3. Agents register again on their next startup. Undelivered envelopes from the old object are not migrated; clients retry them.
171
- 4. Optional environment variables on the Worker: `ACP_RATE_LIMIT_MAX`, `ACP_RATE_LIMIT_WINDOW_MS`, `ACP_MAX_ENVELOPE_BYTES`, `ACP_MAX_QUEUE_SIZE`, `ACP_MAX_QUEUE_BYTES`, `ACP_ENVELOPE_TTL_MS`, `ACP_SEEN_TTL_MS`, `ACP_AGENT_CARD_TTL_MS`. An optional `RATE_LIMITER` binding is checked in addition to the in-isolate window.
241
+ 3. Agents register again on their next startup. Undelivered envelopes from the old object are not migrated; callers must explicitly retry if needed.
242
+ 4. Optional environment variables on the Worker: `ACP_RATE_LIMIT_MAX`, `ACP_RATE_LIMIT_WINDOW_MS`, `ACP_MAX_ENVELOPE_BYTES`, `ACP_MAX_QUEUE_SIZE`, `ACP_MAX_QUEUE_BYTES`, `ACP_MAX_ENVELOPES_PER_SENDER`, `ACP_ENVELOPE_TTL_MS`, `ACP_SEEN_TTL_MS`, `ACP_AGENT_CARD_TTL_MS`. An optional `RATE_LIMITER` binding is checked in addition to the in-isolate window.
172
243
 
173
244
  The Durable Object class name is unchanged, so the existing `v1` migration in the example stays valid. New object names are different instances of that class. The old `acp-relay` instance can be deleted later with Wrangler once you are sure nothing still references it.
174
245
 
@@ -195,6 +266,33 @@ Copy the printed `acp-invite:...` line. This local example echoes the JSON input
195
266
 
196
267
  `sealbridge worker` does not register its AgentCard in the public relay directory unless you pass `--publish`. Share the invite directly. `sealbridge discover` lists only workers that opted in with `--publish`.
197
268
 
269
+ Worker startup keeps its existing stdout format: token on the first line, HTTPS
270
+ invite link on the second. Use `--invite-output none` to suppress both, or
271
+ `--invite-output file:/absolute/path/invite.txt` / `--invite-output fd:3` to deliver
272
+ only the token plus a newline out of band, with no stdout copy. Files are created
273
+ exclusively with mode `0600`; the parent directory must already exist, be owned by
274
+ the current user and have no group/other permissions on POSIX (typically `0700`).
275
+ Existing files and detectable links are rejected. Windows inherits directory ACLs;
276
+ ACLs are not verified. `fd:<n>` is POSIX-only: Windows rejects it with
277
+ `INVITE_OUTPUT_FD_UNSUPPORTED_PLATFORM` during argument parsing, before identity
278
+ creation, relay registration, or listener startup. Node's inherited extra stdio
279
+ pipes on Windows are not plain filesystem descriptors usable with synchronous
280
+ filesystem writes. Use `file:<path>` for separate invitation output on Windows.
281
+ Inherited descriptors must be above 2 and refer to a
282
+ pipe, socket, or file; files must be owned by the current user with no
283
+ group/other permissions. The parent controls descriptor routing and lifetime;
284
+ the worker leaves the descriptor open. Delivery failure returns
285
+ `INVITE_OUTPUT_UNAVAILABLE` without printing the invitation or starting the listener.
286
+
287
+ Every mode adds an `invite_ready` JSON line on stderr after invitation delivery
288
+ (or suppression), before the worker listener starts. Its fields are `event`,
289
+ `inviteDigest` (`sha256:` plus the full hex digest of the token), `expiresAt`
290
+ (ISO timestamp), `workerDid`, and `relay`. It contains no token or invitation link;
291
+ readiness does not confirm relay connectivity. Status/event JSON uses a shared
292
+ field projection, retaining diagnostic keys and digests while replacing
293
+ unrecognized free-form values with `[redacted]`. Approval prompts and opt-in
294
+ inbox/receive-hook records retain their existing content.
295
+
198
296
  Offline wake notifications are available through an operator-configured relay `--wake-command` and recipient `--wake-channel default`; both default to off. Wakes are signed and contain only routing identifiers. Queued expiry produces a retained, signed notice and `RELAY_ENVELOPE_EXPIRED` for HTTP/SSE sessions. See [offline wake, expiry notices, and option defaults](docs/relay-reliability.md#offline-wake-notifications).
199
297
 
200
298
  Add `--on-receive 'node /path/to/notify.cjs'` alongside `--inbox` to launch a
@@ -258,10 +356,16 @@ Worker listeners recover dropped relay connections with jittered backoff and rep
258
356
 
259
357
  `--max-input-tokens`, `--max-output-tokens`, `--max-tool-invocations`, and `--max-wall-clock-seconds` cap the contract a worker will accept. A proposal above any set cap is rejected before `ACCEPT`, including with `--auto-accept`. `timeoutSeconds` on the manifest is compared with `--max-wall-clock-seconds`. `--max-concurrent-tasks` limits in-flight tasks (default 8). `--max-requests-per-minute` limits proposals from one requester DID.
260
358
 
261
- `--allow-requester <did>` is repeatable and also accepts a comma-separated list. `--allow-any-requester` opts in to every requester. For `--adapter claude`, `codex`, or `openai`, `--auto-accept` (and the `--auto-approve` / `--yes` aliases) refuses to start unless one of those allow flags is present, so a discovered worker cannot spend the owner API key for arbitrary callers. The sandbox example above does not need an allowlist.
359
+ `--allow-requester <did>` is repeatable and constrains peers without granting trust. Connections require inspection and owner opening for every adapter. Explicit CLI contact trust remains independent. See [connections admission](docs/connections/admission.md).
262
360
 
263
361
  **Terminal 3 — Alice, the requester**
264
362
 
363
+ With the default unavailable inspection provider, this example returns terminal
364
+ `PENDING_OWNER_APPROVAL` (exit 3). It produces no deliverable or settled audit.
365
+ Do not retry automatically. Completion requires a configured inspection provider
366
+ and owner opening on a fresh task after connection review. `--auto-accept` does
367
+ not replace those steps.
368
+
265
369
  ```sh
266
370
  pnpm sealbridge keygen /tmp/alice.private.json
267
371
  # Paste Bob's complete token when prompted
@@ -275,7 +379,7 @@ pnpm sealbridge audit-verify /tmp/alice-audit.jsonl
275
379
  pnpm sealbridge discover --relay http://127.0.0.1:8787 --allow-private-relay
276
380
  ```
277
381
 
278
- Expected: `SETTLED`, a JSON deliverable, and `"valid":true` with `"status":"VALID"` on both owners. Without a trust-anchor file or `--expect-final-state` / `--expect-last-hash` / `--expect-entry-count`, `statusLabel` is `VALID (no trust anchor: truncation not checked)`: the chain is intact, and an older valid prefix was not ruled out. Alice verifies signatures, digests and budget, JSON Schema and registered isolated checks, then obtains a signed final approval. `--auto-approve` explicitly opts into policy approval of final verification; omit it for human review. `acp://invite?token=...` is also accepted. Alternatively, use `--to <Bob DID> --relay <URL>`. Bob can verify his own `/tmp/bob-audit.jsonl` locally.
382
+ After those admission and opening steps: `SETTLED`, a JSON deliverable, and `"valid":true` with `"status":"VALID"` on both owners. Without a trust-anchor file or `--expect-final-state` / `--expect-last-hash` / `--expect-entry-count`, `statusLabel` is `VALID (no trust anchor: truncation not checked)`: the chain is intact, and an older valid prefix was not ruled out. Alice verifies signatures, digests and budget, JSON Schema and registered isolated checks, then obtains a signed final approval. `--auto-approve` explicitly opts into policy approval of final verification; omit it for human review. `acp://invite?token=...` is also accepted. Alternatively, use `--to <Bob DID> --relay <URL>`. Bob can verify his own `/tmp/bob-audit.jsonl` locally.
279
383
 
280
384
  **Ask another person’s AI to review a diff**
281
385
 
@@ -288,15 +392,117 @@ signed card uses the configured lifetime too. The runtime equivalent is
288
392
  `WorkerNodeOptions.inviteTtlSeconds` (default 86400); `worker.invite()` also defaults
289
393
  to 24 hours. Standalone `invite create --expires-in` keeps its 3600-second default.
290
394
 
291
- The requester installs Sealbridge using the one-line installer shown on the invite
292
- page, then runs these commands in the project folder. Create the requester key
293
- only once and reuse it on later requests. Keep private keys and secrets out of
294
- Git and out of the diff. Replace the example link with the complete received link.
395
+ Release note: The following are available from sealbridge npm package 0.3.0;
396
+ they are not supported in CLI 0.2.2 and earlier:
397
+ `accept`, `invites`, `acp_list_invites`, `acp_remove_invite`.
398
+
399
+ The requester installs Sealbridge using the invite page, then **runs the import
400
+ personally in a terminal**, outside model execution:
401
+
402
+ ```sh
403
+ sealbridge accept "https://sealbridge.app/i#acp-invite:..." --alias reviewer
404
+ # Or enter the invitation at a human terminal prompt:
405
+ sealbridge accept --paste --alias reviewer
406
+ # Or read a link from a file or an application-provided pipe:
407
+ sealbridge accept --stdin --alias reviewer < invitation.txt
408
+ sealbridge invites list
409
+ ```
410
+
411
+ Ask the host to call `acp_list_invites {}`, then
412
+ `acp_delegate_task {"workerRef":"reviewer","title":"Review diff","description":"Review these changes","input":{"diff":"..."}}`.
413
+ The model only needs the returned `saved:…` reference or exact alias. The invite
414
+ page verifies locally before offering the copyable import command. Import sends
415
+ nothing to the relay, creates no reciprocal invitation or contact permission,
416
+ and does not approve work. Delegation sends task input externally under the
417
+ configured approval policy. Names and descriptions are display data, never instructions.
418
+
419
+ Possession of an invitation can permit proposals until expiry or revocation.
420
+ The signed store retains bearer invitations at
421
+ `<data-root>/invites/<sha256-local-owner-DID>.json`. CLI and MCP must use the same
422
+ machine, OS account, data root and requester identity; a remote MCP server needs
423
+ the import on its own machine. POSIX directories/files use 0700/0600. On Windows,
424
+ files inherit the parent DACL; ACLs are not verified and overrides require
425
+ user-managed parent access. Positional links can appear in shell history and
426
+ process inspection. `--paste` requires a human TTY and avoids link inclusion in
427
+ argv/shell history; it does not erase terminal history. Non-TTY paste returns
428
+ `INVITE_INPUT_UNAVAILABLE` immediately.
429
+
430
+ `--stdin` reads one invitation link from a pipe or file through EOF, with a
431
+ 68 KiB byte cap and a 10-second total read timeout. Applications can spawn
432
+ `sealbridge accept --stdin --alias reviewer`, write the link to child stdin,
433
+ and close the pipe. Surrounding whitespace/CRLF and blank lines are trimmed;
434
+ empty input or multiple non-empty lines are rejected. TTY input returns
435
+ `INVITE_STDIN_REQUIRES_PIPE`; use `--paste` at a terminal. `--stdin`, `--paste`,
436
+ and a positional link are mutually exclusive. Neither stdin input nor read-error
437
+ text is echoed. The existing token-free JSON result includes `alias`, `workerRef`,
438
+ `agentDid`, `displayName`, and `effectiveExpiresAt`; no extra JSON flag is needed.
439
+
440
+ Aliases are exact, case-sensitive ASCII slugs of 1–64 characters (letters,
441
+ digits, hyphen and underscore, starting with a letter or digit). Omission derives
442
+ a slug from the display name with a stable digest suffix. Identical imports are
443
+ idempotent; collisions return `ALIAS_EXISTS`. Expired entries remain listed and
444
+ cannot delegate. Renew by explicitly removing and reimporting:
445
+ `sealbridge invites remove reviewer`, or `acp_remove_invite {"workerRef":"reviewer"}`.
446
+ Removal is local, idempotent, and does not revoke issuer authorization or alter
447
+ worker admission. Mutations take an exclusive lock and atomically replace the
448
+ signed store. `INVITE_STORE_BUSY` never removes an existing lock; after checking
449
+ that no writer is alive, the user can explicitly remove the corresponding
450
+ `<store-file>.lock` and retry the local mutation.
451
+
452
+ Imported invitation tokens follow the shared key-store selection (option, environment,
453
+ config, then file). File selection retains the existing signed JSON format and bytes.
454
+ With keychain selection, new entries retain signed metadata, an `inviteSecret` reference,
455
+ and a `tokenDigest`; the token is held in the same data-root-scoped keychain service,
456
+ under account `invite:<entry id>`. Existing inline entries remain readable without
457
+ migration. Stored references continue to resolve through keychain after selecting file;
458
+ new imports then use inline file storage. Listing and MCP results omit tokens.
459
+ Unavailable keychain access returns `KEY_STORE_UNAVAILABLE`; missing or differing
460
+ strings return `INVITE_SECRET_MISSING` or `INVITE_SECRET_MISMATCH`, with no file fallback.
461
+ Removal deletes and checks the referenced string before publishing metadata removal.
462
+ `INVITE_SECRET_DELETE_FAILED` leaves the metadata in place: retry the same alias/reference
463
+ with `remove`, `invites remove`, or `acp_remove_invite`. If publication fails after deletion,
464
+ resolution reports `INVITE_SECRET_MISSING`; removal can still finish without the string.
465
+
466
+ Move existing inline tokens explicitly, using the existing requester identity:
467
+
468
+ ```sh
469
+ sealbridge invites migrate --to keychain --dry-run
470
+ sealbridge invites migrate --to keychain
471
+ # Select an existing requester file when needed:
472
+ sealbridge invites migrate --to keychain --key /path/to/requester.private.json
473
+ ```
474
+
475
+ Dry run reports the number of inline entries without writes. Apply writes and reads
476
+ back every string before atomically publishing signed metadata without inline tokens.
477
+ A failure leaves the original metadata file unchanged; strings written before a failure
478
+ may remain and are reused on retry. Migration neither changes the selected backend nor
479
+ moves the requester identity. Existing references, aliases and import times are retained.
480
+ Embedders can inject synchronous `SecretStore.get/set/delete` via
481
+ `InviteStoreOptions.secretStore` or MCP `identityOptions.secretStore`. Use
482
+ `await InviteStore.open(owner, options)` to load the configured native backend;
483
+ `new InviteStore(owner, options)` retains the synchronous file/injected-store API.
484
+ An injected identity `KeyStore` alone retains inline token storage; pass `secretStore`
485
+ separately to use external strings. Explicit identity file paths select only the signer;
486
+ invitation storage still follows the shared selection.
487
+
488
+ Embedders can opt into recoverable pending imports with
489
+ `store.import(link, alias, { pendingConfirmation: true })`. `SavedInvite.importState`
490
+ is then `unconfirmed`; `listUnconfirmed()` returns token-free metadata, and
491
+ `removeUnconfirmed({ olderThan: timestamp })` returns `{ removed }` for marked imports
492
+ strictly older than that timestamp. Use `retain(workerRef)` to save one before use;
493
+ `resolve` returns `INVITE_CONFIRMATION_REQUIRED` until retention. Ordinary import
494
+ (including a duplicate) retains the entry, and pending reimport never demotes an
495
+ existing save. `connections confirm-invite` retains before attempting confirmation,
496
+ including when that attempt is rejected or interrupted; its owner consent prompt
497
+ remains separate. Existing entries without the marker are excluded from cleanup.
498
+ These methods perform no network operations; see [invite lifecycle](docs/connections/invite-lifecycle.md)
499
+ for retry behavior and the embedding contract.
500
+
501
+ Direct CLI delegation remains available with the complete invitation:
295
502
 
296
503
  ```sh
297
- sealbridge keygen requester.private.json
298
504
  git diff > code.diff
299
- sealbridge delegate --key requester.private.json --to "https://sealbridge.app/i#acp-invite:..." --title "Review my code diff" --description "Review this diff for bugs and suggest improvements. Return a JSON review." --input-file code.diff --out review.json
505
+ sealbridge delegate --to "https://sealbridge.app/i#acp-invite:..." --title "Review my code diff" --description "Review this diff for bugs and suggest improvements. Return a JSON review." --input-file code.diff --out review.json
300
506
  ```
301
507
 
302
508
  `--input-file <path>` parses a JSON object as task input; other text (including a
@@ -365,23 +571,50 @@ DIDs, allowlists, and invitations.
365
571
  ## MCP, live progress, revocation, and quorum
366
572
 
367
573
  ```sh
368
- pnpm sealbridge mcp-server --key /tmp/alice.private.json --relay https://relay.sealbridge.dev
574
+ pnpm sealbridge mcp-server
369
575
  ```
370
576
 
577
+ Release note: The following are available from sealbridge npm package 0.3.0;
578
+ they are not supported in CLI 0.2.2 and earlier:
579
+ `acp_list_invites`, `acp_remove_invite`, `acp_list_pending_requests`, `acp_resubmit_pending_request`.
580
+
371
581
  `sealbridge mcp-server` is a dependency-free JSON-RPC 2.0 MCP server on stdio. It accepts newline-delimited JSON and `Content-Length` frames. Hosts such as Claude Code, Cursor, Codex, and Grok Bot can call:
372
582
 
373
583
  | Tool | Result |
374
584
  | -------------------------- | ----------------------------------------------------------------------------------------------- |
585
+ | `acp_list_invites` | Local saved references, aliases, public metadata and expiry status |
586
+ | `acp_remove_invite` | Local removal result; does not revoke the issuer invitation |
375
587
  | `acp_delegate_task` | Verified deliverable, `taskId`, status, and audit summary |
376
588
  | `acp_delegate_multi` | `race` or `quorum` delegation across workers |
377
589
  | `acp_verify_audit_bundle` | Cryptographic verification report, including whether a trust anchor checked truncation |
378
590
  | `acp_create_invite` | Signed `acp-invite` token |
379
591
  | `acp_revoke_token` | Signed `RevocationNotice` stored in this process |
380
- | `acp_discover_workers` | Signed agent cards registered on the relay |
592
+ | `acp_discover_workers` | Current published open worker cards by default |
381
593
  | `acp_inspect_revocations` | Revocation notices recorded in this server process |
594
+ | `acp_message_status` | Current sender-local delivery status; no transmission, refresh or polling |
595
+ | `acp_list_pending_requests` | Local held-request observations without task content or invitation material |
596
+ | `acp_resubmit_pending_request` | Explicit fresh delegation after worker owner review, with current checks |
382
597
 
383
598
  `initialize` returns server `instructions` that name this workflow. `AcpMcpServer` in `@acp/runtime` is the same server for tests and embedded hosts. The server key signs requester approvals for the tools it runs. `acp_discover_workers` is a read-only directory fetch: it uses the same relay allowlist and `validateRelayEndpointUrl` before `GET /agents`, and it does not send task input. `acp_inspect_revocations` reads the in-memory registry and does not contact a worker.
384
599
 
600
+ With an unflagged `sealbridge mcp-server`, call `acp_discover_workers {}` to list published workers on `https://relay.sealbridge.dev`. Select a result and pass its `workerDid` and `relayUrl` unchanged:
601
+
602
+ ```json
603
+ {
604
+ "workerDid": "<workerDid from discovery>",
605
+ "relayUrl": "<relayUrl from discovery>",
606
+ "title": "Echo JSON",
607
+ "description": "Return the supplied JSON",
608
+ "input": { "hello": "world" }
609
+ }
610
+ ```
611
+
612
+ Call `acp_delegate_task` with those arguments. An omitted single-worker description defaults to the title. No worker allowlist is required by default; an explicitly configured allowlist still restricts delegation.
613
+
614
+ MCP discovery lists every current verified published card. Filter by `skillId` or `taskType`; the removed `accessMode` argument returns JSON-RPC -32602. Results preserve the complete signed card, accepted `protocolVersions`, skills, routing and `acceptance: "worker_decides"`, without operational mode fields. An empty result has `count: 0, workers: []` and the queried `relayUrl`.
615
+
616
+ Publication is controlled by `--publish` and conveys no admission consent. Unconnected requests are held with `PENDING_OWNER_APPROVAL` and `retryable:false`; do not retry automatically or switch workers on refusal. See [owner workflows](docs/connections/admission.md).
617
+
385
618
  `acp_delegate_task` and `acp_delegate_multi` transmit task input to the target worker over the relay. Restrict that path when the host might supply the arguments:
386
619
 
387
620
  ```sh
@@ -395,7 +628,11 @@ pnpm sealbridge mcp-server \
395
628
 
396
629
  `--allow-worker <did>` and `--allow-relay <url>` are repeatable and comma-separated. With `--allow-worker`, a plain worker DID must be listed. An invite is allowed when either its `agentDid` or its `ownerDid` is listed. Any other target fails with `MCP_WORKER_NOT_ALLOWED` before the server dials. With `--allow-relay`, every relay URL is normalized to origin plus pathname with no trailing slash. The configured `--relay`, a tool `relayUrl`, and any relay URL embedded in an invite must all match, or the call fails with `MCP_RELAY_NOT_ALLOWED`. A tool call or invite that selects a relay other than `--relay` is rejected unless that URL is allowlisted. Programmatic hosts can set `allowAnyRelay: true` to accept another relay when no allowlist is configured. An allowlist still applies when it is set. Configured relay URLs are checked with `validateRelayEndpointUrl`.
397
630
 
398
- `--require-approval` uses `InteractiveCliApprovalProvider` and asks on stdin before input is sent, then again for final verification. `--approval-webhook <url>` uses `WebhookApprovalProvider` in owner-decision mode. It POSTs `{ taskId, summaryHash, reason, approverDid }` and continues only when the response is HTTP 2xx and `{ approved: true }`. `{ approved: false }` or a non-2xx response throws `APPROVAL_REJECTED` and nothing is sent. Pass `approvalProvider` on `AcpMcpServer` for a custom provider. Allowlist checks and this approval run before `delegate` / `delegateMulti` write task input to the relay. `conformance/p1-7-mcp-outbound-policy.test.ts` locks the behavior.
631
+ `--require-approval` (programmatically, `requireInteractiveApproval: true`) requests MCP form elicitation before task transmission and again for final verification. The host must advertise form support and negotiate protocol `2025-06-18`; empty legacy `elicitation: {}` capabilities also indicate form support, while URL-only capabilities do not. Only an accepted form with boolean `approved: true` approves. Each form expires after at most 60 seconds or the remaining task deadline. Multi-worker calls review each recipient separately and disclose the total recipient count. Reviews include the resolved task and input, or the deliverable and its signed metadata; oversized reviews fail with `APPROVAL_REVIEW_TOO_LARGE`.
632
+
633
+ A host without form support receives `APPROVAL_CHANNEL_UNAVAILABLE` before any task transmission. Use a host that supports elicitation, or configure `--approval-webhook`. Approval never writes terminal prompts to stdout or reads MCP stdin, even when it is a TTY. Ordinary CLI worker/delegate terminal approval is unchanged. Host elicitation relies on the host to display the form and return the user's decision.
634
+
635
+ Without `--require-approval` or explicit webhook/provider configuration, the existing policy-auto behavior is unchanged. `--approval-webhook <url>` retains owner-decision mode: it POSTs `{ taskId, summaryHash, reason, approverDid }` and continues only for HTTP 2xx with `{ approved: true }`. Denial or non-2xx returns `APPROVAL_REJECTED`. Pass `approvalProvider` on `AcpMcpServer` for an explicit custom provider. Allowlist checks precede delegation, and configured outbound approval reviews the frozen resolved manifest, destination and input before transmission. Final-verification failures can occur after transmission; they do not imply that no task was sent. Offline coverage is in `conformance/mcp-host-approval.test.ts`, `conformance/mcp-approval-session.test.ts`, and `conformance/p1-7-mcp-outbound-policy.test.ts`.
399
636
 
400
637
  A worker reports `PROGRESS` (`percent`, `step`, `message`, and intermediate token or tool metrics) through the same encrypted, countersigned session log. `delegate(request, { onProgress })` receives each decrypted update before `DELIVER`. Reported metrics are charged against `QuotaMeter`.
401
638
 
@@ -423,6 +660,12 @@ A fully automated **separate-process command-adapter demo** is also available:
423
660
  node examples/network-collab/run.mjs
424
661
  ```
425
662
 
663
+ ## Manifest protocol versions
664
+
665
+ Library APIs validate manifest protocols 0.1.0 and 0.2.0 and provide explicit compatibility policy.
666
+ Live sending selects the newest common version, preferring 0.2.0. The configured release clock is described in [protocol versions](docs/connections/protocol-versions.md).
667
+ See [protocol versions](docs/connections/protocol-versions.md) for schemas, policy and peer observations.
668
+
426
669
  ## Five design principles
427
670
 
428
671
  1. **Zero shared credentials.** The requester never hands the worker an API key or raw credential. Needed authority is a time-, count-, scope-, and depth-limited `CapabilityToken` (UCAN/Biscuit style). The requester Gateway verifies it by proxy.
@@ -431,6 +674,19 @@ node examples/network-collab/run.mjs
431
674
  4. **BYOK and signed usage receipts.** LLM cost is borne by the executing side (BYOK) inside the contracted quota. The worker runtime meters usage and signs a `UsageReceipt`. Payment stays out of the core and can be plugged in later.
432
675
  5. **Untrusted input and a bilateral audit.** Data from another owner is `untrusted` and runs in a sandbox. Every state transition is an append-only hash chain signed with Ed25519, and both sides keep a copy.
433
676
 
677
+ ### Connection state persistence
678
+
679
+ `@acp/runtime` provides owner-local connection lifecycle and persistence APIs.
680
+ Connected state projects to limited without expiry and is used by live admission.
681
+ Connection metadata includes optional `peerDisplayName`, retained from a verified invite or
682
+ agent card. `listConnections()`, `connections list`, `connectionStatus()`,
683
+ `connections status`, the MCP connection lists and prior-approved metadata return it when known, even after invite removal. Names are
684
+ informational data only; DIDs remain authoritative for identity and consent. Equal
685
+ names can belong to different owner DIDs. Older records and peers without a known
686
+ card may omit the field; reading does not rewrite them. No wire change is required.
687
+
688
+ See [connection state persistence](docs/connections/connection-state.md) for API and store compatibility details.
689
+
434
690
  ## Documents
435
691
 
436
692
  | File | Contents |
@@ -445,6 +701,21 @@ node examples/network-collab/run.mjs
445
701
  | [`AGENTS.md`](AGENTS.md) | Autonomous Worker/Requester playbook |
446
702
  | [`SKILL.md`](SKILL.md) | Portable agent skill |
447
703
 
704
+ ### Connection exchange library
705
+
706
+ The library exports signed request, acceptance and ACK helpers plus an injected `ConnectionService`.
707
+ Runtime, CLI, MCP and board now attach this exchange through owner-local persistence and held-content review.
708
+ Connection offer timestamps and their default 14-day expiry use one clock snapshot. Worker and CLI-issued card lifetimes also use one snapshot, including the 30-day maximum.
709
+ See [connection exchange](docs/connections/connection-exchange.md) for the control profile and integration requirements.
710
+
711
+ Embedders can explicitly use `ConnectionAdmissionReview` to list held inbound
712
+ connection metadata and call `approve(id)` (limited consent) or `reject(id)` after
713
+ an owner action. The opt-in CLI is `connections review list|approve ID|reject ID`;
714
+ decisions still require human confirmation. Built-in inspection covers connection
715
+ metadata only. Default inbound and task inspection remain `unavailable`; no task
716
+ is opened. See [admission review](docs/connections/admission.md#owner-admission-review).
717
+
718
+
448
719
  ## Local M0–M1 implementation
449
720
 
450
721
  Node.js 22 LTS and pnpm 10 are required. WP-1 through WP-6 are implemented as `@acp/core`, `@acp/ledger`, `@acp/sandbox`, `@acp/runtime`, `@acp/relay`, `@acp/cli` and `@acp/two-owner-demo`.
@@ -486,94 +757,236 @@ The built CLI is also available as `node cli/dist/index.js <command>` and its wo
486
757
 
487
758
  Read the [demo walkthrough](examples/two-owner-demo/README.md), [wire rules](spec/README.md), [conformance suite](conformance/README.md), [M1 security model](docs/security-model.md), and the [adversarial security test suite](SECURITY_PROOF.md). M1 uses signed relay envelopes and the restricted JavaScript subprocess driver. M2/M3 adds optional hardened OCI execution and end-to-end payload encryption. The root code is Apache-2.0; adapted DelegateOS portions retain MIT attribution in [NOTICE](NOTICE).
488
759
 
760
+ ## Embedding SDK
761
+
762
+ Use the typed ESM entry point `sealbridge/sdk` for supported embedding APIs, including
763
+ saved invitations, identity/secret stores, connection review and MCP hosting.
764
+ Available from 0.3.0; not supported in CLI 0.2.2 and earlier. Existing CLI and deep paths remain usable.
765
+ See the [SDK surface and compatibility contract](docs/sdk.md).
766
+
767
+ ## Held-content library
768
+
769
+ `@acp/runtime` provides encrypted request storage and an injected inspection provider.
770
+ Content display requires a completed inspection receipt; the default provider leaves content held.
771
+ See the [held-content library contract](docs/connections/held-content.md) for APIs and host responsibilities.
772
+
489
773
  ## Author & Community
490
774
 
491
775
  - **Author**: [@takapon01234](https://x.com/takapon01234) on X (Twitter)
492
776
  - **Repository**: [sealbridge/sealbridge](https://github.com/sealbridge/sealbridge)
493
777
  - **Public Blind Relay**: `https://relay.sealbridge.dev`
494
778
 
495
- ### Invite-less open task collaboration
779
+ ### Connections admission
780
+
781
+ [日本語](docs/connections/admission.ja.md)
782
+
783
+ Release note: The following are available from sealbridge npm package 0.3.0;
784
+ they are not supported in CLI 0.2.2 and earlier:
785
+ `requests`, `accept`, `connections`, `pending`, `worker start --allow-task-type`,
786
+ `acp_list_connections`, `acp_list_connection_requests`.
787
+
788
+ Workers use four owner-local states: `none`, `pending`, `connected`, and `blocked`.
789
+ Connected means limited consent with no expiry. Every limited task requires a
790
+ completed inspection and a separate human opening before acceptance, for every
791
+ adapter. Automatic contract policy does not replace that opening. The default
792
+ inspection provider reports `unavailable`, so content remains held. An inspection
793
+ provider is required before public release.
496
794
 
497
- Workers started through the CLI default to `--access-mode invite-only`. They
498
- require a valid worker invite or a requester owner DID listed with
499
- `--allow-requester`. An invite remains a bearer invitation; an explicit
500
- allowlist still restricts its use. `--allow-any-requester` does not bypass the
501
- invite requirement in this mode.
795
+ Valid requests from unconnected peers are held as encrypted envelopes for at most
796
+ 24 hours or the task deadline. They return terminal `PENDING_OWNER_APPROVAL`,
797
+ `retryable:false`, CLI exit 3. Do not retry automatically. Schema, signature,
798
+ capability, declared budget, advertised skill and operator perimeter checks precede
799
+ holding or invite redemption. New intake metadata has no title or description
800
+ preview. `requests show` returns `INSPECTION_INCOMPLETE` until inspection completes.
801
+ Plaintext inbox files and receive hooks run only after inspection and opening.
502
802
 
503
- To advertise availability for invite-less tasks:
803
+ ```sh
804
+ sealbridge worker start --adapter sandbox --publish --allow-task-type json --max-input-tokens 50000
805
+ sealbridge discover --skill json-task
806
+ sealbridge requests list
807
+ sealbridge requests show REQUEST_ID
808
+ sealbridge requests approve REQUEST_ID
809
+ sealbridge requests discard REQUEST_ID
810
+ sealbridge requests deny REQUEST_ID
811
+ ```
812
+
813
+ Publication only adds the signed card to the directory. Unpublished workers use the
814
+ same admission rules. `--allow-requester` constrains peers; it grants no trust.
815
+ General budgets use `--max-input-tokens`, `--max-output-tokens`,
816
+ `--max-tool-invocations`, `--max-wall-clock-seconds`; rate uses
817
+ `--max-requests-per-minute`. Settings `public` controls publication only and
818
+ `alwaysAsk:false` returns `CONNECTION_OPENING_REQUIRED`.
819
+
820
+ An invitation records inviter consent and binds to the first authenticated owner DID
821
+ that uses it. A different owner using the same valid token is held. Binding is
822
+ retained through token expiry after disconnect. Expired, mismatched or revoked
823
+ tokens remain errors before mutation. Established connections survive invitation
824
+ expiry/revocation; use verified peer DID routing without the retired token for
825
+ subsequent tasks. A saved `workerRef` still selects its saved invitation and checks
826
+ that invitation on every use. Importing or previewing never connects either role.
504
827
 
505
828
  ```sh
506
- sealbridge worker start --key worker.private.json --relay https://relay.sealbridge.dev --adapter sandbox --access-mode open --publish --skill json-task --task-type json
507
- sealbridge discover --relay https://relay.sealbridge.dev --skill json-task
508
- sealbridge delegate --key requester.private.json --relay https://relay.sealbridge.dev --discover json-task --title Echo --description Echo --input '{"hello":"world"}'
829
+ sealbridge accept --paste --alias reviewer
830
+ sealbridge connections confirm-invite reviewer --role requester
831
+ sealbridge connections request --to PEER_DID --relay https://relay.sealbridge.dev --role worker
832
+ sealbridge connections list --role worker
833
+ sealbridge connections approve REQUEST_ID --role worker
834
+ sealbridge connections reject REQUEST_ID
835
+ sealbridge connections withdraw REQUEST_ID
836
+ sealbridge connections disconnect PEER_DID
837
+ sealbridge connections block PEER_DID
838
+ sealbridge connections unblock PEER_DID
839
+ sealbridge connections prior-approved
840
+ sealbridge connections connect-prior PEER_DID --relay https://relay.sealbridge.dev
841
+ sealbridge connections sync --role requester --relay https://relay.sealbridge.dev --once
842
+ sealbridge connections status reviewer --role requester
509
843
  ```
510
844
 
511
- `--open` aliases `--access-mode open`. Publishing still requires `--publish`.
512
- `--open-allow-task-type <types>` accepts comma-separated or repeated task types,
513
- trims whitespace, removes duplicates, and advertises the list on every worker
514
- skill. Empty entries are invalid. An explicit `--task-type` must belong to this
515
- list. Non-matching proposal task types receive `TASK_SCOPE_REJECTED` with
516
- structured `detail`; direct delegation omitting both skill and task type retains
517
- its existing compatibility behavior.
518
- `--open-rate-limit-per-did <count/window>` accepts a positive safe integer alone
519
- (per minute), or `/m`, `/min`, or `/60s`, for example `10/min`. Other windows and
520
- invalid counts fail with `INVALID_OPEN_RATE_LIMIT_PER_DID`. It configures
521
- `maxTasksPerRequesterPerMinute`; when `--max-requests-per-minute` is also set,
522
- the stricter limit wins. Both new options require open mode.
523
- Open workers can advertise signed budget ceilings with `--open-max-input-tokens`,
524
- `--open-max-output-tokens`, `--open-max-tool-calls`, and `--open-max-wall-seconds`.
525
- Each accepts a positive safe integer and requires open mode. The corresponding
526
- optional `WorkerNodeOptions.openPolicy` / `AgentCard.openPolicy` fields are
527
- `maxInputTokens`, `maxOutputTokens`, `maxToolInvocations`, and `maxWallClockSeconds`.
528
- Workers reject proposals exceeding these ceilings before contract acceptance;
529
- stricter existing acceptance limits still apply. When discovering an open card,
530
- requesters cap only unspecified default budget fields, never increase defaults,
531
- and preserve explicit budgets and custom manifests for worker validation.
532
- Omitted policy fields impose no additional ceiling. Starting an open worker with
533
- `--yes` (or another automatic approval flag) and no requester allowlist prints
534
- an `[Sealbridge WARNING]` line to stderr.
535
-
536
- Discovery also supports `--task-type <type>` and `--did <did>`; delegation
537
- supports `--task-type <type>` or the existing `--to <did>`. Skill selection
538
- uses only current, verified cards explicitly advertising `open`, with stable
539
- agent-DID ordering. A DID plus a discovery filter restricts selection to that
540
- identity. Skills and task types describe advertised abilities, not permissions.
541
-
542
- Open admission does not automatically approve contracts or grant tools. Existing
543
- approval gates, requester allowlists, quotas, encrypted transport, task-bound
544
- capabilities, expiry, and revocation checks continue to apply. CLI LLM automatic
545
- acceptance still requires its existing explicit requester policy.
546
-
547
- Programmatic callers can set `WorkerNodeOptions.accessMode` and
548
- `RequesterClient.delegate({ to: '', discover: { skillId, taskType }, ... })`.
549
- Omitting `accessMode` in the runtime API defaults to invite-only protection.
550
- Direct DID callers need an open worker or an explicit requester allowlist. Older signed
551
- AgentCards remain valid but are not selected for open skill discovery.
552
-
553
- Open workers enforce signed manifest `task.skillId` and `task.taskType` against
554
- their advertised skills before acceptance. Selecting a skill that advertises task
555
- types requires a matching type; discovery binds the selected type into the manifest.
556
- Direct proposals may omit both fields. Open workers ignore cryptographically valid
557
- expired invites (`INVITE_EXPIRED`); malformed invites and live invites for a different
558
- worker still fail. Invite-only workers continue to require an active invite or allowlist.
559
-
560
- Signed, encrypted ERROR frames may include `detail: { field, expected, actual, hint }`.
561
- Scope and advertised-budget diagnostics use fixed field names and hints; `expected`
562
- and `actual` contain SHA-256 digests, never the compared payload values.
563
- Requester failures expose `PeerRejectedError.code` and optional `.detail` while
564
- preserving the `PEER_REJECTED` message prefix. Worker `onEvent(event, taskId, error)`
565
- receives the same code and detail, and CLI event lines include both. When an audit
566
- path is configured, local rejection records are owner-signed and appended to
567
- `<auditPath>.errors.jsonl`. This diagnostic sidecar is separate from the bilateral
568
- hash-chain ledger and is not a settled or countersigned audit bundle. Verified
569
- rejections retain their task IDs; trailing ERROR frames do not create empty-ID events.
570
-
571
- Capability signatures and task bindings are also verified before `ACCEPT`.
572
- `conformance/open-task-adversarial-security.test.ts` covers admission bypass,
573
- card spoofing, scope and budget escalation, cross-task replay, and envelope tampering.
845
+ After confirmation, run `sync --once` and query `connections status reviewer`
846
+ (or a saved workerRef / peer owner DID). Status defaults to the requester role and
847
+ reads local records without sending or creating an identity. `pending_peer` means
848
+ no peer acceptance has been applied locally; `connected` reports the local limited
849
+ connection, with `acknowledgementPending` when retained exchange evidence exists.
850
+ `WorkerTrustStore.connectionStatus(peerOwnerDid)` provides the same projection.
851
+ Other statuses are `none`, `pending_owner`, `inactive`, `expired`, and `blocked`.
852
+ Remote rejection is not reported by this protocol. Expired offer details remain
853
+ queryable only until existing store pruning; established connections survive expiry.
854
+ See [connection status semantics](docs/connections/connection-exchange.md#querying-connection-status).
855
+
856
+ All decisions require a human TTY or an injected human review provider. There is no
857
+ `--yes` connection decision. Confirm the exact local role/DID and peer owner DID;
858
+ requester and worker default identities are separate. An outgoing offer persists
859
+ sender consent before transmission and expires after 14 days. Reject starts a
860
+ seven-day offer cooldown; tasks can still be held. Discard removes content only;
861
+ `requests deny` retains its block meaning. Block is one-sided and silent. Disconnect
862
+ and block affect subsequent admission; accepted work continues unless cancelled.
863
+ Mutual requests derive one connection ID from the two DIDs in ascending order.
864
+ Control acceptance and ACK state commit before relay acknowledgement. Sync never
865
+ resubmits tasks. Held content expires independently of outgoing consent.
866
+
867
+ Task approval and connection consent are separate decisions. An interactive CLI or
868
+ MCP form may ask sequentially; without explicit connection consent no request is
869
+ attached. A held task without sender connection consent can initiate an outgoing
870
+ offer when reviewed; local approval cannot infer the remote owner's consent.
871
+ After connection review the requester owner explicitly starts a fresh task (or
872
+ `pending resubmit` with fresh audit/output paths), with new inspection and opening.
873
+
874
+ Legacy signed intake and invite files remain readable. Reads/listing do not rewrite
875
+ or migrate bytes. Finite grants from earlier releases do not skip holding or become
876
+ connections. Retained approval evidence appears under `prior-approved` and needs a
877
+ new owner action and remote consent. Historical denials remain blocks. Explicit CLI
878
+ contacts stay independent. `requests approve ID --trust trusted` is a separate
879
+ legacy 24-hour grant command; connection commands never create trusted authority.
880
+ Back up v1 intake before the first mutation if rollback is needed; old binaries do
881
+ not read v2. Do not run old and new writers concurrently. Connection and protocol
882
+ stores retain the 1,000-record / 1 MiB bounds and do not evict established records.
883
+
884
+ Retired CLI `--open`, `--access-mode`, `--open-*`, `--allow-any-requester` and JS
885
+ `accessMode`, `openPolicy`, `allowAnyRequester` options return `ACCESS_MODE_REMOVED`
886
+ with migration guidance. Use host budget/type/rate flags above. MCP discovery's
887
+ removed `accessMode` argument returns JSON-RPC -32602. Discovery returns all current
888
+ verified published cards, including legacy cards, without operational mode fields;
889
+ original signed cards remain intact. `acp_list_connections {}` and
890
+ `acp_list_connection_requests {}` read local metadata for the server signer without
891
+ creating an identity. Owner decisions stay in the human CLI.
892
+
893
+ Board claims and dispatch require the selected poster identity's current local
894
+ connection (`CONNECTION_REQUIRED` otherwise). A connection does not approve a task
895
+ or lease. Dispatch checks connection and protocol before lease consumption, then
896
+ consumes before transmission. A committed task envelope retries with the same
897
+ signed bytes and ID until admission or its original deadline, consuming no second lease.
898
+ One-time task tickets and a separate application queue are deferred.
899
+
900
+ The release clock is documented in [protocol versions](docs/connections/protocol-versions.md).
574
901
 
575
902
  ## Official sites and relay URL
576
903
 
577
904
  The official site targets https://sealbridge.dev and the invite receiver targets `https://sealbridge.app/i#<invite>`. See [site operations](docs/sites.md) for source, build and deployment instructions. Adding these files does not deploy either site.
578
905
 
579
906
  Use `https://relay.sealbridge.dev` as the recommended relay. The legacy `https://acp-relay.agent-collab.workers.dev` continues to work against the same relay. Existing signed invitations remain usable; do not edit their relay field. Update MCP relay allowlists when switching hosts.
907
+
908
+ ## Persistent pending sends
909
+
910
+ CLI worker/delegate, board and MCP hosts persist approved task envelopes under
911
+ `<data-root>/delivery/<sha256-local-signer-DID>/`. An event and its audit entry
912
+ are committed together before either is sent. Transient send failures retry the
913
+ same signed ciphertext and envelope ID after 1 minute, 5 minutes, 15 minutes,
914
+ then 1 hour repeatedly, stopping at relay admission or the original task deadline.
915
+ A validated relay retry hint can delay an attempt further. Relay admission means
916
+ queue acceptance; it does not mean owner opening, agent execution or settlement.
917
+ `PENDING_OWNER_APPROVAL` remains terminal and requires explicit fresh resubmission.
918
+
919
+ Pending sends resume when the gateway next starts with the same signer and data
920
+ root. A stopped gateway performs no retries. Transport recovery does not restore
921
+ an arbitrary bilateral session or rerun an adapter. The default worker task journal
922
+ and recipient receipts prevent a repeated proposal from rerunning recorded work;
923
+ explicit inbox/audit journal paths retain precedence. Heartbeats and the separate
924
+ connection-consent outbox retain their existing behavior. Concurrent delegations keep
925
+ their own task and relay bindings while sharing the signer’s delivery store.
926
+
927
+ C1 persistence covers gateway process restart: completed writes and atomic replacement precede transmission or acknowledgement. Envelope records, receipts and the default task journal do not fsync files or directories; power-loss persistence is not guaranteed. Lease, retry and relay-admission bookkeeping may replay the same envelope ID after interruption. Explicit inbox/audit task journals retain their existing flush policy. Unchanged records and directory inventories reuse validation. Gateway index refresh, recovery scans and scheduled record cleanup yield between batches or records.
928
+
929
+ Session sends and processed receipts write unique temporary files asynchronously without acquiring the signer lock for preparation. Handles close before atomic publication; independent tasks sharing a signer and relay can write concurrently. Publication rechecks capacity and receipt state under the signer lock, without filesystem retry sleeps. The default task journal reuses its append handle and unchanged validated checkpoints; compaction and worker shutdown close the handle.
930
+
931
+ POSIX delivery directories/files use 0700/0600; Windows inherits the parent DACL.
932
+ Live sends remove completed batch ciphertext after consuming admission results.
933
+ Maintenance closes expired pending batches before pruning message metadata, and
934
+ removes remaining completed or closed batches.
935
+ Content-free message records and receipt deduplication persist until seven days
936
+ after `max(createdAt, original deliveryDeadline)`, without extending that horizon
937
+ on reads or retries. Maintenance runs at startup and every minute while active;
938
+ an inactive store may retain expired bytes until its next maintenance pass.
939
+ Local bounds are 1,024 pending envelopes, 32 MiB of envelope JSON, 256 KiB per
940
+ wire envelope and 10,000 retained messages/receipts per kind; a full or unwritable
941
+ store reports a fixed error before an unrecorded send and does not evict live work.
942
+
943
+ Embedders can inject `deliveryService` or `deliveryOptions` and explicitly call
944
+ `startDelivery()`/`stopDelivery()`. A custom transport needs a stable relay URL and
945
+ resolver for restart behavior; anonymous injected transports remain ephemeral.
946
+ Initialization, tool listing and local reads do not start delivery or create keys.
947
+ Direct transport `send()` remains a single attempt. No relay deployment is needed
948
+ for this gateway behavior; existing relay retention still governs admitted frames.
949
+ See [relay reliability](docs/relay-reliability.md).
950
+
951
+
952
+ The three MCP send tools (`acp_delegate_task`, `acp_delegate_multi`,
953
+ `acp_resubmit_pending_request`) accept optional `idempotencyKey`, an exact Unicode
954
+ string of 1–200 UTF-8 bytes, e.g. `"idempotencyKey":"review-2026-11-02"`.
955
+ The same signer/tool/key and content return the first stored result across restarts,
956
+ without another send or approval; changed content returns `IDEMPOTENCY_CONFLICT`
957
+ and requires a new key. Keys/results expire seven days after the original deadline
958
+ (latest child deadline for multi). Cached holds never resubmit or increment attempts.
959
+ Another server may return `IDEMPOTENCY_IN_PROGRESS`; interruption returns
960
+ `APPROVAL_INTERRUPTED` or `IDEMPOTENCY_RESULT_UNAVAILABLE` without repeating a prompt
961
+ or execution. Final verification stays separate, and calls without keys are unchanged.
962
+ See [relay reliability](docs/relay-reliability.md) for retention, runtime hooks and recovery.
963
+ No relay deployment is needed.
964
+
965
+ ### Recipient delivery status
966
+
967
+ Recipient-signed `DeliveryStatus` for validated 0.2.0 tasks records content-free
968
+ held/opened/adapter-handoff/closed observations separately from task sequences and
969
+ bilateral audit. Unknown peers get only `received_held` and `closed`; later connection
970
+ approval does not release that task's history. Inspection/display alone does not open
971
+ a task, and successful result cleanup does not close it. Queued detail is suppressed
972
+ on disconnect; blocking suppresses all queued status. Legacy peers without version
973
+ declarations retain 0.1.0 behavior. Status records use the fixed delivery deadline plus
974
+ seven days; active maintenance deletes expired bytes. A handoff does not prove reading
975
+ or execution. Both gateways need support; no relay deployment is required.
976
+ See [relay reliability](docs/relay-reliability.md) for status sources, retention and lifecycle behavior.
977
+
978
+ ### Local message status
979
+
980
+ A send with `idempotencyKey` keeps its original message and task IDs on cached retries.
981
+ This lookup reads the current retained observations for those IDs, independently of
982
+ the cached send result.
983
+
984
+ `acp_message_status {"messageId":"<original PROPOSE UUID>"}` or
985
+ `acp_message_status {"taskId":"<original task ID>"}` reads sender-local status without
986
+ sending, refreshing, polling or cleanup. Use exactly one selector; ambiguous task IDs
987
+ require `messageId`. Records expire seven days after the original deadline (or creation
988
+ time if later); absent, foreign and expired IDs return `found:false`. Initially unknown
989
+ peers disclose only `received_held`/`closed`. Recipient claims are separate from bilateral
990
+ audit; handoff does not prove reading or execution. This read is distinct from a cached
991
+ delegation result and explicit pending resubmission. No relay deployment is required;
992
+ richer observations require C4 peers. See [relay reliability](docs/relay-reliability.md).