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/CHANGELOG.md CHANGED
@@ -4,6 +4,48 @@ All notable changes to this project are documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6
6
 
7
+ ## [4.0.0] - 2026-09-06
8
+
9
+ ### Changed
10
+ - Replaced the accumulated route/service machinery with endpoint identities, one bounded delivery ledger, one batch coordinator, and explicit Claude, Codex, and SSH destinations. All four Claude/Codex directions work locally and across configured SSH nodes.
11
+ - Both agents send with `embassy send --to <name@host>` or `--conversation <reference>`, using the inherited caller identity rather than `--from`. Receiving remains native. A bounded backlog is delivered in one wake with separately attributed messages; an active Codex operation retains its exact STEER capability until completion or its delivery deadline.
12
+ - Replies are identity-bound ledger relations that survive broker restart while retained. Remote catalogs are display caches, never routing authority; direct owner resolution admits authenticated first contact without waiting for a reverse catalog poll.
13
+ - Every new registration receives a fresh opaque endpoint ID; retirement evidence eviction cannot revive an old reply or remote reference. `retire --endpoint <public-id>` removes a stranded local endpoint even when its name is shared by exited sessions.
14
+ - Status is metadata-only: recent ledger outcomes, retirement evidence and timestamped remote catalog observations. `check` proves a broker-only round trip without contacting a model; it does not claim provider readiness.
15
+ - Breaking reset-only upgrade: private state schema 6, local control protocol 5, federation protocol 3. Stop and inspect unsettled work using the old build, preserve its state backup, and follow [the private-state reset procedure](docs/CONFIGURATION.md#private-state-reset). No automatic conversion or mixed-version federation is supported. Existing queued bodies and reply references do not cross a reset.
16
+
17
+ ### Removed
18
+ - Native Claude sending advertisements and helper processes, shell-peer user endpoints and token/await commands, automatic Codex output forwarding and synthetic reply machinery, general activity/accounting journals, persisted remote mirrors, and `watch`.
19
+ - Deprecated `reply` and `unregister-codex` spellings; use `send --conversation` and operator-authorized `retire`. Unused deduplication and delivery-notice configuration are no longer part of the runtime.
20
+ - Historical deep-import compatibility remains unsupported: the maintained package surface is the CLI, packaged skill and documented public JSON.
21
+
22
+ ### Fixed during RC verification
23
+ - The site quickstart uses the v4 sending forms. Supervision documentation distinguishes crash-signal relaunch from an operator's `kill -9`.
24
+ - Claude pre-write generation changes retry cleanly. Uncertainty follows the committed write phase, without manufacturing a terminal ambiguous result before authorization.
25
+ - Admission rejects bodies that cannot fit the escaped provenance frame. Body pruning preserves bounded receipt/reply stubs, retirement retention is independently bounded, and source-rate capacity is partitioned by host.
26
+ - Delivery status reports its actual nonterminal phase; a missing receipt is a lookup failure rather than a failed delivery. Older RC readers do not understand body-pruned stubs: use the documented reset/rollback policy when replacing RC installations.
27
+
28
+ ## [3.1.0] - 2026-09-05
29
+
30
+ ### Added
31
+ - `embassy retire --alias <local-alias>` — credential-free, same-UID operator removal of any local route (Claude session, Codex task, or shell peer) through the existing atomic removal. It settles queued and reserved work `cancelled`, armed work `ambiguous`, and accepted work `unconfirmed`, reports those counts, journals one `route_retired` event for every provider, and refuses federated mirrors with `FEDERATED_ROUTE_READ_ONLY`. No token, force, or remote option exists.
32
+ - Proven destination enqueue refusals keep their safe code across federation; transport loss and failures after admission remain unknown and are never replayed.
33
+
34
+ ### Changed
35
+ - Private control protocol 3 → 4: one new method (`retire_route`), 15 control methods, 18 CLI commands. A 3.0.0 CLI and a 3.1.0 broker refuse each other with the control mismatch code; restart the broker after upgrading.
36
+ - `EMBASSY_MAX_ROUTES` accepts 2 through 128 and fails closed at config load above that with `INVALID_GATEWAY_CONFIGURATION`. 3.0.0 accepted 129–256 at parse and then refused provider startup. The tracked advertisement-helper cap is the same number.
37
+ - Every busy-observation code on a Claude route (`CLAUDE_PEER_TARGET_UNKNOWN`, `CLAUDE_PEER_WORKSPACE_UNATTESTED`, `CLAUDE_PEER_NOT_OBSERVED`, `CLAUDE_DISCOVERY_UNAVAILABLE`) renders an operator remedy in `status`; the never-produced `CLAUDE_PEER_TARGET_STALE` and `CLAUDE_PEER_TARGET_CHANGED` codes are gone.
38
+ - An idle or stale connector renders `ok` health; a named connector fault or a real provider failure stays `degraded`.
39
+ - The supported package surface is the CLI, the skill, and the documented JSON. Deep imports of shipped `dist` declarations are unsupported; unused internal exports, dead validators, test-only runtime facades, and startup-owned route wiring were removed.
40
+ - Public docs describe advertisement as one helper per local non-Claude route (`codex-*` or `peer-*`); federated mirrors are not advertised. A test guard rejects any singleton "one `codex-*` record" phrasing.
41
+
42
+ ### Fixed
43
+ - Helper admission reserves a pending creation before forking, coalesces same-alias creation, releases a failed reservation, and joins in-flight creation on shutdown so every created client is closed.
44
+ - Federated mirror routes are no longer handed to local native advertisement (no per-reconcile refusal or `NATIVE_ADVERTISEMENT_FAILED` alert).
45
+ - Expired or unknown peer receipts return `not_found`, not `route_mismatch`; the peer-receipt fixtures no longer race a 100 ms timer on slow runners.
46
+ - A renamed Claude source carries its current alias through envelopes, terminal replies, and native replies.
47
+ - The service command's install/status/uninstall output is pinned byte-for-byte; the delivery runner's peer and provider engines are separate methods with a phase-failure characterization and no behavior change.
48
+
7
49
  ## [3.0.0] - 2026-09-03
8
50
 
9
51
  ### Added
package/CONTRIBUTING.md CHANGED
@@ -1,208 +1,100 @@
1
1
  # Contributing to Embassy
2
2
 
3
- Embassy connects two powerful local agent runtimes across evidence-gated native
4
- interfaces. Small changes can alter permission, privacy, or delivery behavior,
5
- so contributions should be narrow, testable, and explicit about boundaries.
3
+ Embassy sits on identity, process, filesystem, protocol, persistence, and
4
+ delivery-settlement boundaries. Prefer a smaller responsibility set and a
5
+ direct implementation over a reusable abstraction the product does not need.
6
6
 
7
7
  ## Development setup
8
8
 
9
- Use macOS, Node.js 20 or newer, and the npm version declared in `package.json`.
10
-
11
- ```bash
9
+ ```sh
12
10
  npm ci
13
- npm run check
11
+ TMPDIR=/tmp npm run check
14
12
  ```
15
13
 
16
- `npm run check` type-checks and runs the deterministic test suite; its `pretest`
17
- hook rebuilds `dist` first, so the suite always runs against freshly compiled
18
- output. Routine tests use fake Claude peers, fake App Server transports, and
19
- temporary directories; they must not contact Anthropic, OpenAI, SSH hosts, live
20
- provider sockets, or models.
21
-
22
- `npm run soak` is the separate deliverability gate. It drives a seeded,
23
- randomized churn of sends through scripted dispatch faults, busy/idle flips,
24
- clock jumps, and full restarts, asserting that every accepted message settles
25
- exactly once into an explicit terminal outcome. It is still deterministic and
26
- offline; run it for any change to routing, the queue, settlement, or restart
27
- recovery.
28
-
29
- ## Before opening a pull request
30
-
31
- - Run `npm run check`, and `npm run soak` as well for any delivery, queue,
32
- settlement, or restart-recovery change.
33
- - Add deterministic regression coverage for routing, protocol, persistence,
34
- permission, process-lifecycle, or redaction changes.
35
- - Keep the pull request focused and explain every security-boundary change.
36
- - For every new audit check, cite the sentence it enforces in
37
- [“What Embassy defends, and what it deliberately does not”](SECURITY.md#what-embassy-defends-and-what-it-deliberately-does-not).
38
- If no sentence supports the check, propose the doctrine change explicitly,
39
- with its product and threat-model consequence, before implementation. Do not
40
- smuggle a boundary expansion into a test, review finding, or hardening patch.
41
- - Update README and architecture documentation when public behavior changes.
42
- - Verify that public files contain no credentials, native IDs, message bodies,
43
- local state, or personal absolute paths.
44
- - Do not commit `node_modules`, `dist`, package archives, logs, environment
45
- files, or live-validation artifacts.
46
-
47
- ## Architecture rules
48
-
49
- ### Routing and identity
50
-
51
- - Codex tasks self-register through inherited `CODEX_THREAD_ID` and a
52
- `codex-*` alias. Never add a thread-ID argument or global task-history scan.
53
- - A Codex-to-Claude send installs the addressed session's route on first use;
54
- a Claude session's own route installs on its first outbound message. There is
55
- no separate grant: the permission is the OS boundary — same UID, same host or
56
- a host configured in `nodes.json` plus the exact alias, and the provenance
57
- envelope names the sender.
58
- - Claude's session UUID is its stable logical identity. Current names are a
59
- live index; do not add historical-name routing or PID/socket identity.
60
- - Preserve current-name collision refusal and exact registration fencing.
61
- - Codex registration is record-only: it changes the durable logical route and
62
- performs no provider or App Server I/O. `register-codex --succeeds` is one
63
- atomic logical replacement that settles queued/reserved work `cancelled`,
64
- armed work `ambiguous`, and accepted work `unconfirmed`; removes every
65
- incident conversation, reply, or native capability; and
66
- installs only the successor. Do not add prepared generations, re-anchoring,
67
- or recovery journals.
68
-
69
- ### Provider adapters
70
-
71
- Claude Code's cross-session feature is official. Embassy's use of its external
72
- registry and peer socket shape remains an internal adapter: require native
73
- peer protocol 1 and validate every consumed field and frame. Unknown top-level
74
- registry fields may be ignored; required and consumed fields remain strict,
75
- and rejected-record or observed-empty counts must stay loud. Embassy derives
76
- the registry and callback roots from the verified current OS user; it does not
77
- inspect a Claude launcher or configuration file. Codex registration
78
- performs no provider I/O. Its bounded observer is display-only: it may report
79
- freshness and safe codes but never authorizes, rejects, or delays a delivery.
80
- Every Codex delivery instead creates an operation-local transport,
81
- negotiates the current interface, and resumes the exact registered task with
82
- history excluded before final write authorization. Unsafe ownership, path,
83
- symlink, lease, state, or used-artifact generation evidence for Embassy-owned
84
- or executed artifacts and Embassy callback, control, or state paths still
85
- aborts startup; an unsafe Claude-owned external sessions registry root
86
- quarantines only Claude. Provider versions remain diagnostic metadata, and
87
- interface drift or an unavailable optional provider degrades only that
88
- surface. Do not widen a declared protocol without documented review and
89
- deterministic fixtures.
90
-
91
- The gateway may publish one process-owned `codex-*` peer so Claude's native
92
- `ListAgents` and `SendMessage` tools can reach Codex. It must never overwrite a
93
- foreign registry record, claim to be a Claude model session, or unlink a socket
94
- whose exact generation it no longer owns.
95
-
96
- App Server calls use a closed allowlist. Do not add a generic RPC method,
97
- approval responses, history retrieval, shell execution, settings mutation, or
98
- provider authentication. The only active-turn method is exact same-session
99
- `turn/steer` for a leading `STEER:` body on the accepted operation, capped at
100
- three and admitted only at the next tool-call boundary. Embassy never calls
101
- `turn/interrupt`. Keep `experimentalApi: true` non-configurable and limited to
102
- `thread/resume.excludeTurns: true`; every resume must require an empty
103
- `thread.turns` response.
104
-
105
- ### Permissions
106
-
107
- Embassy does not set or override a Codex task's persistent approval or sandbox
108
- policy. Registration is the gateway reachability boundary. Bounded observation
109
- may describe route and approval-waiting status, but it is never authority or a
110
- dispatch gate and must not classify policy or turn workspace/settings metadata
111
- into a second authorization gate.
112
-
113
- For Codex-to-Claude delivery, Claude's `crossSessionInbound` behavior remains
114
- native. Do not route around a hold or refusal or fabricate a successful receipt.
115
-
116
- ### Delivery and state
117
-
118
- - Reply addresses are transient. Bodies are bounded and durable: the queue and
119
- the recent-delivery ledger both persist them under bounded retention caps.
120
- - Queue while a Codex task is busy; do not interrupt an unrelated turn.
121
- - Distinguish gateway acceptance, transport progress, destination acceptance,
122
- terminal failure, ambiguity, expiry, and restart abandonment.
123
- - Never retry an ambiguous provider write. Requeue only a confirmed clean
124
- deferral that has not crossed an ambiguous mutation boundary.
125
- - The private mode-0600 v5 ledger retains bounded queued and recent bodies,
126
- opaque delivery tokens, and status. Queued or reserved work may resume once
127
- within its deadline and attempt budget against the same exact route and edge.
128
- Armed work settles `ambiguous`; accepted work settles `unconfirmed`; neither
129
- is replayed. Conversations, reply/native capabilities, raw frames, callback
130
- addresses, and socket paths remain memory-only.
131
- - Persist native route identifiers only in the closed private binding schema.
132
- Keep them out of events, snapshots, logs, errors, and CLI
133
- output. The only CLI exception is a UUID explicitly supplied by the user as a
134
- Claude selector.
135
-
136
- ### Local control surface
137
-
138
- `embassy serve` may use one private same-user control UDS and nothing else. It
139
- must not listen on TCP or HTTP, and Embassy ships no other listener. Do not add
140
- a wildcard/remote listener, external assets, service workers, telemetry, or a
141
- mutation endpoint. Keep the shipped launcher foreground, macOS-only, and
142
- local-host-only.
143
-
144
- ## Live validation
145
-
146
- Do not run a live probe merely because a test would be convenient. Live Claude
147
- registry discovery, peer connection, provider messaging, App Server turns, and
148
- SSH attachment are separate external actions.
149
-
150
- A live action requires an explicit user request that identifies its scope. For
151
- a message, confirm the exact destination and body and avoid fanout. Follow the
152
- send-failure policy below for command failures; never retry a confirmed
153
- delivery or a recipient denial. Never put real provider traffic in CI.
154
-
155
- ## Reporting security issues
156
-
157
- Follow [SECURITY.md](SECURITY.md). Use a private GitHub Security Advisory rather
158
- than a public issue, and replace sensitive local values with synthetic ones.
159
-
160
- Two platform notes: the suite binds Unix-domain sockets under `TMPDIR`, and
161
- macOS caps socket paths at ~104 bytes — keep `TMPDIR` short (CI pins
162
- `TMPDIR=/tmp`; do the same locally if the transport tests hang). On Linux,
163
- the darwin-only lease and peer-generation tests skip explicitly (the host
164
- lease spawns macOS's `/usr/bin/lockf`); macOS runs the full suite.
165
-
166
- ## Design honesty rules
167
-
168
- These outlive any visual era and bind every surface — CLI copy, site, docs:
169
-
170
- - Progress is never green. Only a terminal success state may look like one.
171
- - `delivered` means the write completed; `released` is not read; nothing may
172
- imply a model consumed, understood, or acted on a message.
173
- - Refusals are not failures: a fail-closed refusal renders as policy, not as
174
- breakage.
175
- - The brand accent is never a state color, and state colors are never
176
- decoration.
177
- - Every alert pairs its state with the exact next command, copyable.
178
-
179
- ### The declined ledger
180
-
181
- [`docs/DECLINED.md`](docs/DECLINED.md) records, per release, what we considered
182
- and chose not to build, each with a one-line reason. It is product
183
- documentation: a product that documents what it refuses to build is making the
184
- same promise its status output makes—the truth over the appearance of
185
- completeness.
186
- PRs that implement something in the ledger must address its reason.
187
-
188
- ### Why tickets are priced by the PM
189
-
190
- The level of implementation—the one-hour version versus the one-week version—
191
- is a scope decision, and scope is a product judgment. The PM prices it; the
192
- engineer builds it faithfully within budget or contests the price with reasons.
193
- Economy here never means lowering the bar on what ships: it means fewer things,
194
- done well, and being explicit about what waits.
195
-
196
- ### Send-failure policy
197
-
198
- A send or reply whose command result is an error, truncation, or ambiguity is
199
- not a delivery—it is a failed attempt to create one. Verify with read-only
200
- `status`/`delivery-status`; if no acceptance is confirmed, resend without
201
- asking, up to three attempts. Escalate to the PM only when a recipient
202
- explicitly denied the message or three resends have failed. A duplicated
203
- coordination message is a nuisance; a lost one deadlocks the pipeline, so
204
- deliverability beats ceremony. Never auto-retry a delivery the recipient's
205
- user denied: that is consent, not transport.
206
-
207
- For long messages, write the body to a file and pipe it
208
- (`embassy send --conversation ... < body.md`); never inline `printf` for prose.
14
+ Tests must use test-owned state directories, fake Claude sockets, fake App
15
+ Server transports, and fake SSH processes. Routine validation must not inspect
16
+ the live Claude registry, contact a live agent or App Server, connect an SSH
17
+ host, install a service, change global packages, or make a model request.
18
+
19
+ A live operation requires explicit user authorization for that exact operation
20
+ and must never run in CI.
21
+
22
+ ## Core shape
23
+
24
+ Keep changes inside the v4 architecture:
25
+
26
+ - `ledger.ts` owns pure synchronous state transitions;
27
+ - `owned-state.ts` owns private atomic persistence;
28
+ - `endpoint-directory.ts` owns alias lookup and exact endpoint resolution;
29
+ - `coordinator.ts` owns batching, phase transitions, and scheduling;
30
+ - Claude, Codex, and SSH each have one explicit destination adapter;
31
+ - `broker.ts` composes application operations;
32
+ - `local-control.ts` and `broker-control.ts` expose one closed private control
33
+ surface;
34
+ - `core-cli.ts` is the public command entry point.
35
+
36
+ Do not add another delivery machine, provider-independent engine, state store,
37
+ catalog authority, event journal, callback service, or migration layer unless
38
+ the product contract explicitly changes.
39
+
40
+ ## Required invariants
41
+
42
+ - Endpoint IDs are identity; aliases are current lookup indexes. Resolve a name
43
+ once and never silently retarget an admitted message.
44
+ - Validate the exact current endpoint and prepared bytes immediately before a
45
+ native write.
46
+ - Keep `queued`, `reserved`, `armed`, `accepted`, and `terminal` distinct.
47
+ Never retry an ambiguous write.
48
+ - Provider I/O never runs inside an owned-state transaction.
49
+ - A destination owns its queue; remote first contact is admitted only from an
50
+ SSH-authenticated owner assertion.
51
+ - Keep every queue, body, batch, deadline, rate, retained row, protocol frame,
52
+ and concurrent operation bounded.
53
+ - Keep native identifiers, addresses, message bodies, secrets, and raw
54
+ provider data out of public projections and errors.
55
+ - Registration, replacement, retirement, restart, expiry, and late callbacks
56
+ must settle work explicitly without moving it to another identity.
57
+ - Native receive/wake is the core behavior. CLI sending is intentional.
58
+ - STEER uses the exact accepted Codex operation at a safe boundary and never
59
+ calls `turn/interrupt`.
60
+
61
+ The governing doctrine is
62
+ [What Embassy defends, and what it deliberately does not](SECURITY.md#what-embassy-defends-and-what-it-deliberately-does-not).
63
+ A new check must cite a current doctrine sentence. If none applies, propose a
64
+ contract change instead of silently widening the boundary.
65
+
66
+ ## Testing changes
67
+
68
+ Characterize the behavior that matters at the real boundary before changing
69
+ it. Avoid a test that stubs the very loader, decoder, transport, or transaction
70
+ it claims to prove.
71
+
72
+ For delivery and persistence work, cover the failure phase, not merely the
73
+ success response: before reservation, before authorization, after arming,
74
+ after provider acceptance, after durable destination enqueue, restart, and a
75
+ late or duplicate completion. Mutation or ablation checks are useful when two
76
+ guards could mask one another.
77
+
78
+ For protocol and CLI work, pin the exact closed JSON shape, protocol number,
79
+ exit status, and stdout/stderr separation. For documentation, pin stable
80
+ commands and version facts directly rather than broad regular expressions that
81
+ unrelated prose can satisfy.
82
+
83
+ Run the full check after source or test changes. Use the soak suite when a
84
+ change affects scheduling, native transport, restart, or settlement.
85
+
86
+ ## Repository hygiene
87
+
88
+ Do not commit `node_modules`, `dist`, package archives, state, logs,
89
+ environment files, provider configuration, credentials, or live-validation
90
+ artifacts. Keep public documentation free of personal absolute paths.
91
+
92
+ Never move tags, force-push shared branches, or edit public main directly.
93
+ Release actions, live drills, service installation, and global package changes
94
+ belong to the release operator.
95
+
96
+ ## Security reports
97
+
98
+ Use the private security-reporting path. Public issues may include safe codes,
99
+ versions, and sanitized command names; they must not include message bodies,
100
+ native IDs, socket paths, credentials, histories, or raw provider output.