agent-embassy 3.0.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/CONTRIBUTING.md +92 -200
  3. package/README.md +159 -138
  4. package/SECURITY.md +191 -335
  5. package/dist/src/gateway/broker-check.d.ts +26 -0
  6. package/dist/src/gateway/broker-check.js +89 -0
  7. package/dist/src/gateway/broker-check.js.map +1 -0
  8. package/dist/src/gateway/broker-control.d.ts +72 -0
  9. package/dist/src/gateway/broker-control.js +164 -0
  10. package/dist/src/gateway/broker-control.js.map +1 -0
  11. package/dist/src/gateway/broker.d.ts +117 -0
  12. package/dist/src/gateway/broker.js +186 -0
  13. package/dist/src/gateway/broker.js.map +1 -0
  14. package/dist/src/gateway/claude-peer.d.ts +1 -124
  15. package/dist/src/gateway/claude-peer.js +62 -1053
  16. package/dist/src/gateway/claude-peer.js.map +1 -1
  17. package/dist/src/gateway/codex-stateless-transport.d.ts +0 -12
  18. package/dist/src/gateway/codex-stateless-transport.js +8 -142
  19. package/dist/src/gateway/codex-stateless-transport.js.map +1 -1
  20. package/dist/src/gateway/config.d.ts +2 -6
  21. package/dist/src/gateway/config.js +17 -27
  22. package/dist/src/gateway/config.js.map +1 -1
  23. package/dist/src/gateway/coordinator.d.ts +57 -0
  24. package/dist/src/gateway/coordinator.js +217 -0
  25. package/dist/src/gateway/coordinator.js.map +1 -0
  26. package/dist/src/gateway/core-cli.d.ts +15 -0
  27. package/dist/src/gateway/core-cli.js +282 -0
  28. package/dist/src/gateway/core-cli.js.map +1 -0
  29. package/dist/src/gateway/core-service-command.d.ts +16 -0
  30. package/dist/src/gateway/core-service-command.js +71 -0
  31. package/dist/src/gateway/core-service-command.js.map +1 -0
  32. package/dist/src/gateway/endpoint-directory.d.ts +33 -0
  33. package/dist/src/gateway/endpoint-directory.js +223 -0
  34. package/dist/src/gateway/endpoint-directory.js.map +1 -0
  35. package/dist/src/gateway/federation.d.ts +89 -0
  36. package/dist/src/gateway/federation.js +632 -0
  37. package/dist/src/gateway/federation.js.map +1 -0
  38. package/dist/src/gateway/ledger-codec.d.ts +3 -0
  39. package/dist/src/gateway/ledger-codec.js +159 -0
  40. package/dist/src/gateway/ledger-codec.js.map +1 -0
  41. package/dist/src/gateway/ledger.d.ts +138 -0
  42. package/dist/src/gateway/ledger.js +319 -0
  43. package/dist/src/gateway/ledger.js.map +1 -0
  44. package/dist/src/gateway/local-control.d.ts +23 -0
  45. package/dist/src/gateway/local-control.js +489 -0
  46. package/dist/src/gateway/local-control.js.map +1 -0
  47. package/dist/src/gateway/native-destinations.d.ts +34 -0
  48. package/dist/src/gateway/native-destinations.js +272 -0
  49. package/dist/src/gateway/native-destinations.js.map +1 -0
  50. package/dist/src/gateway/owned-state.d.ts +57 -0
  51. package/dist/src/gateway/owned-state.js +398 -0
  52. package/dist/src/gateway/owned-state.js.map +1 -0
  53. package/dist/src/gateway/provenance-envelope.d.ts +3 -3
  54. package/dist/src/gateway/provenance-envelope.js +3 -23
  55. package/dist/src/gateway/provenance-envelope.js.map +1 -1
  56. package/dist/src/gateway/runtime.d.ts +41 -0
  57. package/dist/src/gateway/runtime.js +175 -0
  58. package/dist/src/gateway/runtime.js.map +1 -0
  59. package/docs/CONFIGURATION.md +178 -266
  60. package/docs/DELIVERY.md +133 -82
  61. package/docs/GATEWAY-ARCHITECTURE.md +276 -943
  62. package/package.json +5 -5
  63. package/skills/embassy-peer/SKILL.md +38 -194
  64. package/skills/embassy-peer/agents/openai.yaml +2 -2
  65. package/dist/src/gateway/claude-helper-client.d.ts +0 -2
  66. package/dist/src/gateway/claude-helper-client.js +0 -2
  67. package/dist/src/gateway/claude-helper-client.js.map +0 -1
  68. package/dist/src/gateway/claude-helper-protocol.d.ts +0 -117
  69. package/dist/src/gateway/claude-helper-protocol.js +0 -122
  70. package/dist/src/gateway/claude-helper-protocol.js.map +0 -1
  71. package/dist/src/gateway/claude-helper-supervisor.d.ts +0 -87
  72. package/dist/src/gateway/claude-helper-supervisor.js +0 -347
  73. package/dist/src/gateway/claude-helper-supervisor.js.map +0 -1
  74. package/dist/src/gateway/claude-helper.d.ts +0 -1
  75. package/dist/src/gateway/claude-helper.js +0 -252
  76. package/dist/src/gateway/claude-helper.js.map +0 -1
  77. package/dist/src/gateway/cli.d.ts +0 -57
  78. package/dist/src/gateway/cli.js +0 -1503
  79. package/dist/src/gateway/cli.js.map +0 -1
  80. package/dist/src/gateway/codex-socket-holder.d.ts +0 -26
  81. package/dist/src/gateway/codex-socket-holder.js +0 -76
  82. package/dist/src/gateway/codex-socket-holder.js.map +0 -1
  83. package/dist/src/gateway/control.d.ts +0 -261
  84. package/dist/src/gateway/control.js +0 -903
  85. package/dist/src/gateway/control.js.map +0 -1
  86. package/dist/src/gateway/peer-client.d.ts +0 -58
  87. package/dist/src/gateway/peer-client.js +0 -217
  88. package/dist/src/gateway/peer-client.js.map +0 -1
  89. package/dist/src/gateway/peer-mailbox.d.ts +0 -78
  90. package/dist/src/gateway/peer-mailbox.js +0 -168
  91. package/dist/src/gateway/peer-mailbox.js.map +0 -1
  92. package/dist/src/gateway/peer-protocol.d.ts +0 -105
  93. package/dist/src/gateway/peer-protocol.js +0 -70
  94. package/dist/src/gateway/peer-protocol.js.map +0 -1
  95. package/dist/src/gateway/peer-stdio.d.ts +0 -23
  96. package/dist/src/gateway/peer-stdio.js +0 -100
  97. package/dist/src/gateway/peer-stdio.js.map +0 -1
  98. package/dist/src/gateway/providers.d.ts +0 -163
  99. package/dist/src/gateway/providers.js +0 -972
  100. package/dist/src/gateway/providers.js.map +0 -1
  101. package/dist/src/gateway/server.d.ts +0 -47
  102. package/dist/src/gateway/server.js +0 -219
  103. package/dist/src/gateway/server.js.map +0 -1
  104. package/dist/src/gateway/service.d.ts +0 -373
  105. package/dist/src/gateway/service.js +0 -2274
  106. package/dist/src/gateway/service.js.map +0 -1
  107. package/dist/src/gateway/status-view.d.ts +0 -167
  108. package/dist/src/gateway/status-view.js +0 -488
  109. package/dist/src/gateway/status-view.js.map +0 -1
  110. package/dist/src/gateway/store.d.ts +0 -185
  111. package/dist/src/gateway/store.js +0 -2359
  112. package/dist/src/gateway/store.js.map +0 -1
  113. package/dist/src/gateway/types.d.ts +0 -528
  114. package/dist/src/gateway/types.js +0 -341
  115. package/dist/src/gateway/types.js.map +0 -1
package/docs/DELIVERY.md CHANGED
@@ -1,86 +1,137 @@
1
1
  # Delivery semantics
2
2
 
3
- Embassy tracks every accepted message from CLI acceptance through terminal
4
- settlement. This document collects the delivery model in one place: queue
5
- behavior, evidence states, failure handling, retry policy, and the delivery
6
- tokens that let a sender follow a message to settlement. The material is the
7
- authoritative reference for what "delivered" does and does not mean inside
8
- Embassy.
9
-
10
- ---
11
-
12
- - **Timing is directional.** After routing and pre-write checks, a Claude-bound body is written immediately to Claude's native mailbox regardless of its observed busy or idle state. Claude being busy is never a reason to hold that write in Embassy's queue. A Codex-bound ordinary body instead waits for the task to become available. An exact leading `STEER:` body from Claude to Codex may be admitted to the active turn at its next tool-call boundary. Embassy never interrupts or injects text mid-generation; a cleanly unavailable boundary falls back to the normal queue. At most three steering messages remain queued per route, with the oldest settled as `cancelled/STEER_QUEUE_SUPERSEDED` when a fourth is accepted.
13
-
14
- - **Acceptance is not completion.** Initial CLI acceptance returns a conversation token and a delivery token. For Claude-bound delivery, `transport_written` means the native mailbox write completed and is the terminal `delivered` boundary; Embassy does not wait for evidence that Claude later read or consumed the body. Toward Codex, `delivered` means the App Server accepted the turn. Neither boundary means a model read, understood, or completed the work.
15
-
16
- - **Shell peers acknowledge stdout.** A `peer-*` delivery requires a live `embassy await` waiter. With none, dispatch defers cleanly as `PEER_NOT_AWAITING`. Embassy arms the exact prepared frame, hands it to the waiter, and settles `delivered` only after the CLI has flushed that complete frame to stdout and returned the private receipt. A lost receipt is `unconfirmed`; uncertainty after arming is `ambiguous`. One waiter is allowed per registration and 16 globally; waiter, receipt, and duplicate-ack tombstone state is memory-only.
17
-
18
- - **Recipients get provenance and a reply path.** Immediately before the provider write, Embassy puts every routed body inside one broker-owned `<cross-session-message>` textual frame. Its first element is an `<embassy-reply-hint>` with the full conversation token, the recipient's exact alias, and the corresponding `embassy send --conversation` command. A recipient may continue with that exact token, but caller identity, conversation membership, and current route policy are rechecked at reply time.
19
-
20
- - **Evidence has three shapes.** `delivered` means the direction's terminal provider boundary was observed. A confirmed Claude mailbox write reaches that boundary immediately. `unconfirmed` means Embassy cannot prove the required terminal boundary despite partial dispatch evidence; it is not a later downgrade from a confirmed Claude mailbox write. `ambiguous` means the write outcome itself is unknown. All three are terminal, and neither `unconfirmed` nor `ambiguous` is a retry authorization — inspect the recipient instead, because a resend can duplicate the message.
21
-
22
- - **Native failures.** A Claude-originated route or delivery failure settles as native `expired`; its native acknowledgement always retains the normalized safe code in the reason field. The default `merged` notice mode keeps the early stall frame but suppresses the duplicate terminal `<gateway-delivery-diagnostic>` user frame. `verbose` restores that readable diagnostic frame; `quiet` suppresses all gateway-authored user-frame notices, including stalls, while native status remains truthful. No notice contains a path, native identifier, exception, or message body. `denied` is reserved for a real user or policy refusal and is not authored by Embassy. `held` and transport-written are progress, never success.
23
- - **Native held is attempt-then-ack.** For Claude→Codex ingress, Embassy first attempts the exact immediate dispatch. A terminal result observed before the one-second prompt boundary produces only its terminal acknowledgement. Native `held` is sent only when the body actually remains queued (including a busy route or clean provider deferral) or dispatch is still nonterminal at that boundary; the terminal acknowledgement follows later. Claude's rendered “approved and released” notice means only that the gateway accepted and released the body to the recipient queue. It does not mean a model read it, and it does not imply human approval.
24
-
25
- - **Retries are conservative.** Undispatched Codex-bound messages remain queued while the task is busy or temporarily unavailable. Each attempt opens a fresh App Server transport; registration and connector observation never certify reachability. A clean pre-write deferral may return reserved work to the queue. Once the body write is armed, uncertainty is terminal and never replayed. A Claude-bound body may remain queued only for a pre-write route failure or temporary unavailability, never merely because Claude is observed busy. A confirmed delivery failure settles; an ambiguous write is never retried automatically.
26
-
27
- - **Bounded by design.** Bodies, queues, rate windows, deduplication tables, deadlines, and transient conversations all have fixed limits.
28
-
29
- - **A displaced route's work settles `cancelled` with `ENDPOINT_RETIRED`.** A Claude session's route is installed on first use and belongs to one (host, session UUID) identity. When a different session claims a name that a route already holds, the broker retires the displaced route: its queued and reserved work settles `cancelled` with the safe code `ENDPOINT_RETIRED`, armed work settles `ambiguous`, and provider-accepted work settles `unconfirmed`. Nothing is replayed against the new session, and the retirement is journaled so `embassy status` shows it.
30
- - **Restarts keep clean work only.** Queued and reserved bodies persist under bounded retention and may resume once against the same logical route. Armed or accepted work at crash settles ambiguous or unconfirmed and is never replayed. Each retained message keeps its opaque delivery token and status in the private v5 state, so the sender can continue checking that exact attempt after restart. No pending waiter, shell receipt, reply, or conversation capability survives.
31
-
32
- Accepted messages are tracked toward terminal delivery while the broker and provider connections remain healthy. `embassy status` distinguishes acceptance, progress, delivery, expiry, failure, ambiguity, and abandonment.
33
-
34
- ## Provenance framing and recipient replies
35
-
36
- The store, queue, classification, deduplication, rate limiting, and 16 KiB
37
- acceptance limit all operate on the raw body. At the last provider
38
- boundary, Embassy deterministically composes exactly one authoritative textual
39
- frame:
40
-
41
- - Toward Codex, the outer `cross-session-message` carries the exact verified
42
- source alias in `from-name` and the full token in `conversation`.
43
- - Toward Claude, the outer frame uses only Claude Code's canonical bounded
44
- `from-name`. A source alias longer than 64 characters gets a deterministic
45
- 64-character display label; the first reply hint retains the exact alias in
46
- `from-alias`. Claude's outer frame does not carry `conversation` because that
47
- attribute is not part of its canonical parser.
48
- - In both directions, the first `embassy-reply-hint` carries `conversation`,
49
- `reply-as`, and the exact stdin-based reply command. `reply-as` is the
50
- recipient's alias, never the sender's. The hint states that caller,
51
- conversation, and route policy are rechecked.
52
-
53
- The full `conv_` conversation token is a transient participant-scoped locator,
54
- not enough authority by itself. The recipient can use the delivered full token, while the
55
- broker still validates inherited caller identity, current conversation
56
- membership, and current route policy. Never reconstruct a token from
57
- the suffix exposed by metadata-only views.
58
-
59
- This is Claude-compatible textual framing, not general XML, a cryptographic
60
- signature, or proof that the body is safe. Embassy composes the genuine outer
61
- frame and hint from validated broker metadata. In the untrusted raw body only,
62
- it case-insensitively neutralizes boundary-shaped opening or closing occurrences
63
- of all three reserved tags — `cross-session-message`, `embassy-reply-hint`, and
64
- `embassy-queued-ahead` — by inserting `\` immediately
65
- after their leading `<`. The rest of the body remains byte-for-byte text.
66
- Native Claude wrappers received inside a body are therefore untrusted nested
67
- text beneath Embassy's single authoritative outer frame.
68
-
69
- The full conversation token travels only in the accepted control result and
70
- transient provider payload; the composed envelope itself is payload-only.
71
- Aliases retain their existing sanitized public-metadata behavior. The full
72
- token is never persisted, journaled, logged, snapshotted, or placed in a
73
- receipt. A framing, metadata, or size failure happens
74
- before the provider write and settles as a clean failure; it is never
75
- classified as an ambiguous write or replayed.
76
-
77
- ## Delivery tokens
78
-
79
- Every accepted `send`, whether addressed by route or by conversation, returns a delivery token: `dlv_` followed by exactly 24 base64url characters. It addresses one bounded private v5 message/status row and is not a provider receipt handle. The token is persisted only in the mode-0600 broker state; it never enters a public snapshot, normal log, or provider receipt.
80
-
81
- ```bash
82
- embassy delivery-status --token dlv_<token>
83
- embassy wait-delivery --token dlv_<token>
3
+ Embassy gives a sender a durable broker receipt. It does not claim that a model
4
+ understood or acted on the message.
5
+
6
+ ## Identity and admission
7
+
8
+ An endpoint is identified by the tuple `(opaque endpoint ID, host, provider)`.
9
+ Its `name@host` alias is a lookup index and display label. A send by name
10
+ resolves once, before admission. Every later transition and reply uses the
11
+ endpoint tuple; a rename or replacement cannot retarget old work.
12
+
13
+ Codex callers must already be registered. A Claude caller is derived from its
14
+ inherited native socket and recorded under the exact discovered session UUID.
15
+ The caller never supplies `--from`. A remote source is supplied by the trusted
16
+ SSH peer. Its claimed host must be in `nodes.json`, and the message's source
17
+ host must match that claim. The destination does not wait for a catalog poll
18
+ before accepting first contact.
19
+
20
+ Admission validates the body, deadline, route capacity, byte capacity, rate
21
+ limit, and exact local endpoint identities in one state transaction. It returns
22
+ a private delivery token and a conversation reference. A repeated federated
23
+ message ID is idempotent only when every identity and message field matches;
24
+ two deliberate sends with equal bodies remain two messages.
25
+
26
+ ## One wake, several messages
27
+
28
+ For one exact destination and delivery class, the coordinator freezes the
29
+ oldest bounded FIFO prefix into one native wake. Each enclosed message keeps a
30
+ separate provenance envelope, conversation, deadline, and terminal result. A
31
+ busy endpoint therefore catches up in one wake instead of requiring one agent
32
+ turn per queued message.
33
+
34
+ The batch is bounded by message count, raw queue bytes, framed wake bytes, and
35
+ the adapter's operation limit. A message that expires or cannot fit reports its
36
+ own result; it does not erase or silently merge another message.
37
+
38
+ ## Durable phases
39
+
40
+ Each delivery has exactly one of these phases:
41
+
42
+ 1. `queued` durably admitted, no operation owns it.
43
+ 2. `reserved` a specific attempt owns a fixed batch, but no write is
44
+ authorized.
45
+ 3. `armed` the exact prepared bytes and identities were revalidated and the
46
+ provider may be written.
47
+ 4. `accepted` the provider accepted the operation; Embassy continues to
48
+ track its lifetime.
49
+ 5. `terminal` `delivered`, `failed`, `cancelled`, `expired`, `ambiguous`, or
50
+ `unconfirmed` with a safe code.
51
+
52
+ Only an adapter's positive proof that it wrote nothing may return reserved or
53
+ armed work to `queued`. Loss before authorization may retry within the deadline
54
+ and attempt budget. Loss after an armed write is `ambiguous`; loss after
55
+ provider acceptance is the adapter's recorded `ambiguous` or `unconfirmed`
56
+ outcome. Neither is replayed.
57
+
58
+ On broker restart, queued work remains eligible, reserved work returns to the
59
+ queue, armed work becomes `ambiguous`, and accepted work becomes its stored
60
+ uncertain outcome. A terminal result is first-wins, including late or duplicate
61
+ provider callbacks.
62
+
63
+ ## Native adapters
64
+
65
+ ### Claude destination
66
+
67
+ The broker discovers the exact compatible live session, verifies its private
68
+ socket and workspace boundary, composes the complete bounded provenance batch,
69
+ then revalidates the same endpoint immediately before the peer-protocol write.
70
+ The receiving Claude session wakes through its native socket.
71
+
72
+ ### Codex destination
73
+
74
+ The broker creates a fresh bounded App Server operation, resumes the exact
75
+ registered task without retaining returned history, prepares the input, then
76
+ revalidates the registration and operation immediately before the write. The
77
+ accepted operation remains attached until its terminal lifetime event so an
78
+ active-turn STEER has a valid target.
79
+
80
+ An exact leading `STEER:` is special only from Claude to Codex. It is delivered
81
+ through that exact accepted operation's `turn/steer` capability at the next
82
+ safe tool-call boundary. It never invokes `turn/interrupt` or injects during a
83
+ generation. A cleanly unavailable boundary returns the message to the ordinary
84
+ bounded queue. At most three queued STEER messages target one route.
85
+
86
+ ### SSH destination
87
+
88
+ The source gateway resolves the exact endpoint at its owner, prepares one
89
+ bounded handoff, and writes it once through the authenticated SSH peer. The
90
+ destination checks the configured claimed host and source consistency, persists its queue,
91
+ then returns acceptance. A proven pre-enqueue refusal is
92
+ reported precisely; process loss, malformed response, or failure after the
93
+ commit boundary is uncertain and never retried automatically.
94
+
95
+ ## Provenance and replies
96
+
97
+ Every native wake contains one `<cross-session-message>` envelope per message.
98
+ Reserved tag prefixes in user text are neutralized before framing. Public
99
+ metadata contains aliases, providers, and a conversation reference, never a
100
+ native session/task ID or socket path.
101
+
102
+ The enclosed reply hint is:
103
+
104
+ ```sh
105
+ embassy send --conversation <reference>
84
106
  ```
85
107
 
86
- `delivery-status` reads the retained status once. `wait-delivery` polls until the message is terminal or the delivery deadline passes. It exits `0` only for `delivered`, `6` for any other terminal state (`unconfirmed`, `expired`, `failed`, `ambiguous`, or `cancelled`), `3` for an unknown token, and `4` for a local wait timeout — which is not a terminal state and does not authorize a resend. A retained pre-restart token continues to resolve after restart; `found: false` means that exact token is not present in the bounded state, for example after terminal retention eviction.
108
+ The caller is inferred again. The ledger accepts the reply only from one exact
109
+ participant and targets the other exact participant. A reference can survive a
110
+ broker restart while its bounded retained row and both endpoint identities are
111
+ still valid. Retirement, replacement, retention expiry, eviction, or state
112
+ reset makes it unavailable. Conversation references are intentionally not
113
+ stable across a reset.
114
+
115
+ ## Receipts and retirement
116
+
117
+ `embassy delivery-status --token <token>` is a one-shot read.
118
+ `embassy wait-delivery --token <token>` polls the private broker control socket
119
+ until that delivery becomes terminal or its bounded wait ends. Delivery tokens
120
+ are opaque capabilities and must not be put in logs or provider messages.
121
+ Both status and delivery-status report the actual nonterminal phase: queued,
122
+ reserved, armed, or accepted. A missing/evicted receipt returns `found:false`;
123
+ wait-delivery exits 3 for that lookup failure, not the terminal-delivery-failure
124
+ exit 6. Receipt retention is bounded and never promises indefinite lookup.
125
+ The default receipt bounds are 500 terminal rows and 24 hours. The 1 MiB
126
+ retained-body budget removes old bodies, not their receipt/outcome or reply
127
+ identity; a hash retains exact duplicate-message checking after body removal.
128
+ Retirement evidence has a separate 500-row bound and the same time window.
129
+
130
+ `embassy retire --alias <local-name>` removes the resolved local endpoint in
131
+ one transaction. Incident queued/reserved work becomes `cancelled`; armed work
132
+ becomes `ambiguous`; accepted work becomes `unconfirmed`. Recent retirement
133
+ evidence remains bounded. Remote routes are read-only and must be retired on
134
+ their owner. No pending message is moved to another identity.
135
+ For a colliding name, use `embassy retire --endpoint <public-id>` with the
136
+ opaque ID from status. It removes only that exact local row; `--alias` and
137
+ `--endpoint` are mutually exclusive. This also works after both sessions exit.