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.
- package/README.ja.md +492 -30
- package/README.md +522 -109
- package/dist/cli/dist/accept.d.ts +13 -0
- package/dist/cli/dist/accept.js +115 -0
- package/dist/cli/dist/accept.js.map +1 -0
- package/dist/cli/dist/approval-summary.d.ts +1 -1
- package/dist/cli/dist/board.d.ts +10 -9
- package/dist/cli/dist/board.js +62 -31
- package/dist/cli/dist/board.js.map +1 -1
- package/dist/cli/dist/command-identity.d.ts +6 -0
- package/dist/cli/dist/command-identity.js +13 -0
- package/dist/cli/dist/command-identity.js.map +1 -0
- package/dist/cli/dist/config.d.ts +3 -0
- package/dist/cli/dist/config.js +29 -0
- package/dist/cli/dist/config.js.map +1 -0
- package/dist/cli/dist/connections.d.ts +15 -0
- package/dist/cli/dist/connections.js +191 -0
- package/dist/cli/dist/connections.js.map +1 -0
- package/dist/cli/dist/contacts.d.ts +4 -3
- package/dist/cli/dist/contacts.js +39 -28
- package/dist/cli/dist/contacts.js.map +1 -1
- package/dist/cli/dist/doctor.d.ts +9 -0
- package/dist/cli/dist/doctor.js +46 -5
- package/dist/cli/dist/doctor.js.map +1 -1
- package/dist/cli/dist/error-messages.js +22 -0
- package/dist/cli/dist/error-messages.js.map +1 -1
- package/dist/cli/dist/index.js +44 -6
- package/dist/cli/dist/index.js.map +1 -1
- package/dist/cli/dist/invite-output.d.ts +14 -0
- package/dist/cli/dist/invite-output.js +66 -0
- package/dist/cli/dist/invite-output.js.map +1 -0
- package/dist/cli/dist/invite-share.d.ts +6 -3
- package/dist/cli/dist/invite-share.js +40 -15
- package/dist/cli/dist/invite-share.js.map +1 -1
- package/dist/cli/dist/invites-migrate.d.ts +3 -0
- package/dist/cli/dist/invites-migrate.js +33 -0
- package/dist/cli/dist/invites-migrate.js.map +1 -0
- package/dist/cli/dist/mcp.d.ts +7 -5
- package/dist/cli/dist/mcp.js +23 -18
- package/dist/cli/dist/mcp.js.map +1 -1
- package/dist/cli/dist/network.d.ts +11 -1
- package/dist/cli/dist/network.js +150 -87
- package/dist/cli/dist/network.js.map +1 -1
- package/dist/cli/dist/pending.d.ts +8 -0
- package/dist/cli/dist/pending.js +50 -0
- package/dist/cli/dist/pending.js.map +1 -0
- package/dist/cli/dist/public-settings.d.ts +5 -4
- package/dist/cli/dist/public-settings.js +13 -15
- package/dist/cli/dist/public-settings.js.map +1 -1
- package/dist/cli/dist/receipt.d.ts +1 -1
- package/dist/cli/dist/relay-auth.d.ts +3 -0
- package/dist/cli/dist/relay-auth.js +23 -0
- package/dist/cli/dist/relay-auth.js.map +1 -0
- package/dist/cli/dist/requests.d.ts +10 -0
- package/dist/cli/dist/requests.js +91 -0
- package/dist/cli/dist/requests.js.map +1 -0
- package/dist/cli/dist/sdk.d.ts +10 -0
- package/dist/cli/dist/sdk.js +7 -0
- package/dist/cli/dist/sdk.js.map +1 -0
- package/dist/cli/dist/setup-files.d.ts +24 -0
- package/dist/cli/dist/setup-files.js +190 -0
- package/dist/cli/dist/setup-files.js.map +1 -0
- package/dist/cli/dist/setup-hosts.d.ts +29 -0
- package/dist/cli/dist/setup-hosts.js +75 -0
- package/dist/cli/dist/setup-hosts.js.map +1 -0
- package/dist/cli/dist/setup.d.ts +61 -0
- package/dist/cli/dist/setup.js +243 -0
- package/dist/cli/dist/setup.js.map +1 -0
- package/dist/cli/dist/task-input.d.ts +1 -1
- package/dist/cli/dist/wake-hook.d.ts +1 -1
- package/dist/cli/dist/worker-json.d.ts +4 -0
- package/dist/cli/dist/worker-json.js +87 -0
- package/dist/cli/dist/worker-json.js.map +1 -0
- package/dist/examples/two-owner-demo/dist/run-demo.d.ts +13 -13
- package/dist/package.json +1 -1
- package/dist/packages/adapters/dist/command.d.ts +2 -2
- package/dist/packages/adapters/dist/credential-proxy.d.ts +2 -2
- package/dist/packages/adapters/dist/index.d.ts +1 -1
- package/dist/packages/adapters/dist/mcp.d.ts +2 -2
- package/dist/packages/adapters/dist/openai.d.ts +2 -2
- package/dist/packages/adapters/dist/sandbox.d.ts +2 -2
- package/dist/packages/core/dist/connection.d.ts +58 -0
- package/dist/packages/core/dist/connection.js +132 -0
- package/dist/packages/core/dist/connection.js.map +1 -0
- package/dist/packages/core/dist/delivery-status.d.ts +22 -0
- package/dist/packages/core/dist/delivery-status.js +53 -0
- package/dist/packages/core/dist/delivery-status.js.map +1 -0
- package/dist/packages/core/dist/discovery.d.ts +7 -6
- package/dist/packages/core/dist/discovery.js +19 -20
- package/dist/packages/core/dist/discovery.js.map +1 -1
- package/dist/packages/core/dist/edge.d.ts +1 -0
- package/dist/packages/core/dist/edge.js +1 -0
- package/dist/packages/core/dist/edge.js.map +1 -1
- package/dist/packages/core/dist/index.d.ts +3 -0
- package/dist/packages/core/dist/index.js +3 -0
- package/dist/packages/core/dist/index.js.map +1 -1
- package/dist/packages/core/dist/protocol.d.ts +24 -0
- package/dist/packages/core/dist/protocol.js +54 -0
- package/dist/packages/core/dist/protocol.js.map +1 -0
- package/dist/packages/core/dist/receipts.d.ts +1 -0
- package/dist/packages/core/dist/receipts.js +1 -1
- package/dist/packages/core/dist/receipts.js.map +1 -1
- package/dist/packages/core/dist/schema.d.ts +1 -0
- package/dist/packages/core/dist/schema.js +13 -2
- package/dist/packages/core/dist/schema.js.map +1 -1
- package/dist/packages/ledger/dist/index.d.ts +1 -1
- package/dist/packages/relay/dist/admission.d.ts +14 -0
- package/dist/packages/relay/dist/admission.js +70 -0
- package/dist/packages/relay/dist/admission.js.map +1 -0
- package/dist/packages/relay/dist/fetch.d.ts +8 -2
- package/dist/packages/relay/dist/fetch.js +41 -12
- package/dist/packages/relay/dist/fetch.js.map +1 -1
- package/dist/packages/relay/dist/index.d.ts +23 -12
- package/dist/packages/relay/dist/index.js +130 -78
- package/dist/packages/relay/dist/index.js.map +1 -1
- package/dist/packages/relay/dist/journal.d.ts +1 -1
- package/dist/packages/relay/dist/notifications.d.ts +1 -1
- package/dist/packages/relay/dist/retry.d.ts +23 -0
- package/dist/packages/relay/dist/retry.js +43 -1
- package/dist/packages/relay/dist/retry.js.map +1 -1
- package/dist/packages/relay/dist/ssrf.d.ts +3 -2
- package/dist/packages/relay/dist/ssrf.js.map +1 -1
- package/dist/packages/relay/dist/worker.js +1 -1
- package/dist/packages/relay/dist/worker.js.map +1 -1
- package/dist/packages/runtime/dist/a2a.d.ts +1 -1
- package/dist/packages/runtime/dist/a2a.js +1 -1
- package/dist/packages/runtime/dist/adapter.d.ts +2 -2
- package/dist/packages/runtime/dist/application-config.d.ts +20 -0
- package/dist/packages/runtime/dist/application-config.js +218 -0
- package/dist/packages/runtime/dist/application-config.js.map +1 -0
- package/dist/packages/runtime/dist/approval-providers.d.ts +24 -3
- package/dist/packages/runtime/dist/approval-providers.js +79 -3
- package/dist/packages/runtime/dist/approval-providers.js.map +1 -1
- package/dist/packages/runtime/dist/connection-admission-review.d.ts +39 -0
- package/dist/packages/runtime/dist/connection-admission-review.js +86 -0
- package/dist/packages/runtime/dist/connection-admission-review.js.map +1 -0
- package/dist/packages/runtime/dist/connection-persistence.d.ts +35 -0
- package/dist/packages/runtime/dist/connection-persistence.js +181 -0
- package/dist/packages/runtime/dist/connection-persistence.js.map +1 -0
- package/dist/packages/runtime/dist/connection-records.d.ts +167 -0
- package/dist/packages/runtime/dist/connection-records.js +132 -0
- package/dist/packages/runtime/dist/connection-records.js.map +1 -0
- package/dist/packages/runtime/dist/connection-router.d.ts +45 -0
- package/dist/packages/runtime/dist/connection-router.js +130 -0
- package/dist/packages/runtime/dist/connection-router.js.map +1 -0
- package/dist/packages/runtime/dist/connection-service.d.ts +159 -0
- package/dist/packages/runtime/dist/connection-service.js +239 -0
- package/dist/packages/runtime/dist/connection-service.js.map +1 -0
- package/dist/packages/runtime/dist/connection-transport.d.ts +14 -0
- package/dist/packages/runtime/dist/connection-transport.js +89 -0
- package/dist/packages/runtime/dist/connection-transport.js.map +1 -0
- package/dist/packages/runtime/dist/delivery-records.d.ts +180 -0
- package/dist/packages/runtime/dist/delivery-records.js +205 -0
- package/dist/packages/runtime/dist/delivery-records.js.map +1 -0
- package/dist/packages/runtime/dist/delivery-status-router.d.ts +27 -0
- package/dist/packages/runtime/dist/delivery-status-router.js +150 -0
- package/dist/packages/runtime/dist/delivery-status-router.js.map +1 -0
- package/dist/packages/runtime/dist/delivery-status.d.ts +43 -0
- package/dist/packages/runtime/dist/delivery-status.js +193 -0
- package/dist/packages/runtime/dist/delivery-status.js.map +1 -0
- package/dist/packages/runtime/dist/delivery-store.d.ts +125 -0
- package/dist/packages/runtime/dist/delivery-store.js +1047 -0
- package/dist/packages/runtime/dist/delivery-store.js.map +1 -0
- package/dist/packages/runtime/dist/gateway.d.ts +4 -3
- package/dist/packages/runtime/dist/gateway.js.map +1 -1
- package/dist/packages/runtime/dist/held-request-review.d.ts +49 -0
- package/dist/packages/runtime/dist/held-request-review.js +122 -0
- package/dist/packages/runtime/dist/held-request-review.js.map +1 -0
- package/dist/packages/runtime/dist/held-request-store.d.ts +112 -0
- package/dist/packages/runtime/dist/held-request-store.js +290 -0
- package/dist/packages/runtime/dist/held-request-store.js.map +1 -0
- package/dist/packages/runtime/dist/idempotency-store.d.ts +53 -0
- package/dist/packages/runtime/dist/idempotency-store.js +331 -0
- package/dist/packages/runtime/dist/idempotency-store.js.map +1 -0
- package/dist/packages/runtime/dist/inbox.d.ts +1 -1
- package/dist/packages/runtime/dist/index.d.ts +27 -1
- package/dist/packages/runtime/dist/index.js +26 -0
- package/dist/packages/runtime/dist/index.js.map +1 -1
- package/dist/packages/runtime/dist/invite-store.d.ts +76 -0
- package/dist/packages/runtime/dist/invite-store.js +337 -0
- package/dist/packages/runtime/dist/invite-store.js.map +1 -0
- package/dist/packages/runtime/dist/key-store.d.ts +77 -0
- package/dist/packages/runtime/dist/key-store.js +226 -0
- package/dist/packages/runtime/dist/key-store.js.map +1 -0
- package/dist/packages/runtime/dist/local-identity.d.ts +33 -0
- package/dist/packages/runtime/dist/local-identity.js +279 -0
- package/dist/packages/runtime/dist/local-identity.js.map +1 -0
- package/dist/packages/runtime/dist/mcp-rpc.d.ts +19 -0
- package/dist/packages/runtime/dist/mcp-rpc.js +175 -0
- package/dist/packages/runtime/dist/mcp-rpc.js.map +1 -0
- package/dist/packages/runtime/dist/mcp-server.d.ts +46 -19
- package/dist/packages/runtime/dist/mcp-server.js +427 -184
- package/dist/packages/runtime/dist/mcp-server.js.map +1 -1
- package/dist/packages/runtime/dist/mcp-tool-catalog.d.ts +1 -1
- package/dist/packages/runtime/dist/mcp-tool-catalog.js +172 -13
- package/dist/packages/runtime/dist/mcp-tool-catalog.js.map +1 -1
- package/dist/packages/runtime/dist/mcp.d.ts +2 -2
- package/dist/packages/runtime/dist/message-status.d.ts +32 -0
- package/dist/packages/runtime/dist/message-status.js +29 -0
- package/dist/packages/runtime/dist/message-status.js.map +1 -0
- package/dist/packages/runtime/dist/outbox.d.ts +91 -0
- package/dist/packages/runtime/dist/outbox.js +462 -0
- package/dist/packages/runtime/dist/outbox.js.map +1 -0
- package/dist/packages/runtime/dist/policy.d.ts +1 -1
- package/dist/packages/runtime/dist/protocol-peer-store.d.ts +40 -0
- package/dist/packages/runtime/dist/protocol-peer-store.js +176 -0
- package/dist/packages/runtime/dist/protocol-peer-store.js.map +1 -0
- package/dist/packages/runtime/dist/protocol-release.d.ts +26 -0
- package/dist/packages/runtime/dist/protocol-release.js +76 -0
- package/dist/packages/runtime/dist/protocol-release.js.map +1 -0
- package/dist/packages/runtime/dist/quota.d.ts +1 -1
- package/dist/packages/runtime/dist/relay-selection.d.ts +20 -0
- package/dist/packages/runtime/dist/relay-selection.js +34 -0
- package/dist/packages/runtime/dist/relay-selection.js.map +1 -0
- package/dist/packages/runtime/dist/requester-pending-store.d.ts +59 -0
- package/dist/packages/runtime/dist/requester-pending-store.js +266 -0
- package/dist/packages/runtime/dist/requester-pending-store.js.map +1 -0
- package/dist/packages/runtime/dist/secret-store.d.ts +19 -0
- package/dist/packages/runtime/dist/secret-store.js +51 -0
- package/dist/packages/runtime/dist/secret-store.js.map +1 -0
- package/dist/packages/runtime/dist/session-audit.d.ts +29 -7
- package/dist/packages/runtime/dist/session-audit.js +149 -29
- package/dist/packages/runtime/dist/session-audit.js.map +1 -1
- package/dist/packages/runtime/dist/session.d.ts +101 -9
- package/dist/packages/runtime/dist/session.js +696 -96
- package/dist/packages/runtime/dist/session.js.map +1 -1
- package/dist/packages/runtime/dist/task-journal.d.ts +18 -3
- package/dist/packages/runtime/dist/task-journal.js +271 -18
- package/dist/packages/runtime/dist/task-journal.js.map +1 -1
- package/dist/packages/runtime/dist/verifier.d.ts +3 -2
- package/dist/packages/runtime/dist/verifier.js +1 -0
- package/dist/packages/runtime/dist/verifier.js.map +1 -1
- package/dist/packages/runtime/dist/worker-trust-store.d.ts +111 -0
- package/dist/packages/runtime/dist/worker-trust-store.js +592 -0
- package/dist/packages/runtime/dist/worker-trust-store.js.map +1 -0
- package/dist/packages/sandbox/dist/container.d.ts +1 -1
- package/dist/packages/sandbox/dist/index.d.ts +1 -1
- package/dist/spec/README.ja.md +21 -1
- package/dist/spec/README.md +20 -1
- package/dist/spec/agent-card.schema.json +11 -1
- package/dist/spec/delivery-status.schema.json +106 -0
- package/dist/spec/examples/protocol-versions/sample-agent-card.json +35 -0
- package/dist/spec/examples/sample-delivery-status.json +21 -0
- package/dist/spec/examples/sample-task-manifest.0.1.0.json +173 -0
- package/dist/spec/examples/sample-task-manifest.0.2.0.json +173 -0
- package/dist/spec/task-manifest.0.1.0.schema.json +422 -0
- package/dist/spec/task-manifest.0.2.0.schema.json +422 -0
- package/dist/spec/task-manifest.schema.json +9 -418
- package/docs/sdk.ja.md +133 -0
- package/docs/sdk.md +138 -0
- 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
|
|
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
|
|
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
|
-
|
|
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)
|
|
44
48
|
[](https://x.com/takapon01234)
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
[](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
|
-
|
|
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
|
-
"
|
|
71
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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;
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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 --
|
|
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
|
|
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` |
|
|
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`
|
|
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
|
-
###
|
|
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
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
invite
|
|
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
|
-
|
|
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
|
|
507
|
-
sealbridge
|
|
508
|
-
sealbridge
|
|
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
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
`
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
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).
|