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/README.md CHANGED
@@ -1,191 +1,212 @@
1
- <p align="center">
2
- <img src="https://raw.githubusercontent.com/YuanpingSong/embassy/main/assets/social-preview.png" alt="Embassy — a local gateway for messaging between Claude Code sessions and Codex CLI tasks" width="720">
3
- </p>
4
-
5
1
  # Embassy
6
2
 
7
- **A local embassy for your AI agents.**
3
+ Embassy lets live Claude Code sessions and Codex CLI tasks message one another
4
+ by name, on one Mac or across user-owned Macs reached through SSH. The broker
5
+ wakes the receiving agent through its native interface; agents do not poll.
6
+ Claude→Claude, Claude→Codex, Codex→Claude, and Codex→Codex all use the same
7
+ command and receipt model.
8
+
9
+ The core is deliberately small: one private ledger, one delivery coordinator,
10
+ and three write adapters (Claude socket, Codex App Server operation, and SSH
11
+ handoff). Aliases are lookup names. Opaque endpoint IDs are the routing
12
+ identity, so a rename or replacement never silently retargets queued work.
8
13
 
9
- [![CI](https://github.com/YuanpingSong/embassy/actions/workflows/ci.yml/badge.svg)](https://github.com/YuanpingSong/embassy/actions/workflows/ci.yml)
10
- [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
11
- [![Node ≥ 20](https://img.shields.io/badge/node-%E2%89%A520-43853d)](package.json)
14
+ ## Requirements
12
15
 
13
- Embassy is a small local broker that lets a [Claude Code](https://code.claude.com) session and a [Codex](https://chatgpt.com/codex) CLI task on the same Mac message each other by name, with a receipt for every delivery. It is personal software — one person, one macOS account, agents you already trust to run as that user — and an unofficial project, not affiliated with or endorsed by Anthropic or OpenAI.
16
+ - macOS and Node.js 20 or newer.
17
+ - Claude Code and/or Codex CLI installed for the agents you use.
18
+ - A private `nodes.json` when choosing an explicit host name or federating;
19
+ first single-machine boot creates one from the short hostname.
20
+ - Key-based, non-interactive SSH between configured machines when federating.
14
21
 
15
- ## Install
22
+ Install one copy with one package manager and verify what the shell resolves:
16
23
 
17
- ```bash
24
+ ```sh
18
25
  npm install -g agent-embassy
19
- embassy service install
26
+ which -a embassy
27
+ embassy --version
20
28
  ```
21
29
 
22
- `service install` runs the broker as your user's launchd agent: it starts at login, restarts after a crash, and logs to `~/Library/Logs/agent-embassy/broker.log`. Prefer a process you start by hand? Run `embassy serve` in a terminal and leave it running instead. You need macOS, Node.js 20+, Claude Code (with its [`crossSessionInbound`](docs/CONFIGURATION.md#claude-codes-own-setting-crosssessioninbound) setting enabled on any session that should receive mail), and Codex CLI with the managed standalone App Server — the official installer `curl -fsSL https://chatgpt.com/codex/install.sh | sh`, then `codex app-server daemon start`. From source: `git clone https://github.com/YuanpingSong/embassy && cd embassy && npm ci && npm run build && npm link`.
30
+ The launchd service records the absolute installation path used by
31
+ `embassy service install`. After replacing or removing that installation, run
32
+ the install command again.
23
33
 
24
- Every alias below ends in `@your-host`. Replace `your-host` with this machine's host the `hostId` on the broker's ready line (in the log, under launchd); name the wrong host and the CLI says which one this machine uses.
34
+ The agent starts at login and uses launchd's crash-only keepalive policy. A
35
+ verified `SIGABRT` crash relaunches it. A clean exit, boot refusal, `SIGTERM`,
36
+ or deliberate `kill -9` leaves it stopped; inspect `embassy service status`
37
+ and install/start it deliberately rather than assuming every signal restarts it.
25
38
 
26
- ## Your first message in four commands
39
+ ## Quickstart
27
40
 
28
- **1. Register the Codex task.** Ask your Codex agent to run this as a shell step in its current turn; it must run inside the task so it inherits the task's identity. You should see `"accepted":true`.
41
+ For an explicit host name or federation, create `nodes.json` before starting
42
+ the broker. `host` is this machine's name; `nodes` lists directly reachable
43
+ Embassy hosts.
29
44
 
30
- ```bash
31
- embassy register-codex --alias codex-reviewer@your-host
45
+ ```json
46
+ {"version":1,"host":"studio","nodes":[]}
32
47
  ```
33
48
 
34
- **2. Read what the broker sees.** The `sessions` block lists your live Claude Code sessions by name. If it is empty, start a Claude Code session and run `embassy refresh`, then look again.
35
-
36
- ```bash
37
- embassy status
38
- ```
49
+ The file lives at
50
+ `$XDG_STATE_HOME/agent-embassy/nodes.json`, or
51
+ `~/.local/state/agent-embassy/nodes.json` when `XDG_STATE_HOME` is unset. It
52
+ must be owned by the current user, mode 0600, inside the private mode-0700 state
53
+ directory. If it is absent on first single-machine boot, Embassy derives a
54
+ lower-case name from the short hostname and atomically writes the equivalent
55
+ empty-node file. It never rewrites a present inventory.
39
56
 
40
- **3. Send.** From the Codex task, body on stdin, to the name `status` showed. The session's route installs on its first use — there is no step between reading a name and messaging it. You get a `conv_` conversation token and a `dlv_` delivery token back.
57
+ Install the supervised broker:
41
58
 
42
- ```bash
43
- embassy send --from codex-reviewer@your-host --to advisor@your-host --expects-reply <<'MSG'
44
- Please review the current approach and identify the main risk.
45
- MSG
59
+ ```sh
60
+ embassy service install
61
+ embassy health
46
62
  ```
47
63
 
48
- **4. Answer by conversation.** Every delivered body arrives inside one broker-owned `<cross-session-message>` frame naming the attested sender (on a federated hop, the sender is named by the sending node — see [SECURITY.md](SECURITY.md)), and its first `<embassy-reply-hint>` carries the full `conv_` token and this exact command; the recipient runs it with the answer on stdin.
64
+ A Codex task registers itself from that task's inherited identity. Embassy
65
+ never accepts or prints the task ID:
49
66
 
50
- ```bash
51
- embassy send --conversation conv_<token> --from advisor@your-host <<'MSG'
52
- The main risk is the double-write window; gate it behind the flag.
53
- MSG
67
+ ```sh
68
+ embassy register-codex --alias codex-reviewer@studio
54
69
  ```
55
70
 
56
- The same `send` runs from a Claude Code session, inheriting that session's identity, and the other direction needs no Embassy command at all: a Claude session finds `codex-reviewer` with its native `ListAgents` tool and messages it with `SendMessage`. `--to <session-uuid>` addresses a Claude session by its UUID. When two live sessions share a name, the send is refused with `PEER_ALIAS_COLLISION` rather than delivered to a guess — rename one and retry. A Claude session's reply to a `--expects-reply` send is routed back to the Codex task by itself.
71
+ Claude sessions are discovered and recorded by exact native identity when a
72
+ Claude caller sends or when a named Claude target is resolved. No helper or
73
+ native advertisement process is installed.
57
74
 
58
- ## After any Claude Code or Codex CLI update
75
+ From either a Claude session or a registered Codex task, send the body on
76
+ stdin. The sender is inferred from the calling session:
59
77
 
60
- ```bash
61
- embassy check
78
+ ```sh
79
+ printf '%s\n' 'Please review the change.' |
80
+ embassy send --to claude-reviewer@studio
62
81
  ```
63
82
 
64
- `check` is the upstream-drift tripwire. It registers an ephemeral shell peer of its own — kept out of the durable state document and the federation catalog, expiring on its own; its only trace is the native advertisement to Claude sessions, released with it, and a broker that dies mid-check can leave that record until the alias is next registered and released — sends one marked message through the ordinary send path to the most recently observed registered Codex task (observed within ten minutes; a task never observed is not eligible), waits for `delivered`, awaits the echo on its own mailbox, releases the registration, and prints every hop with its timing; any failing hop exits non-zero with the safe code that explains it. `--to <alias>` picks a target and `--timeout <s>` bounds each wait. The peer answers because the shipped [skill](skills/embassy-peer/SKILL.md) tells it to — a message whose verified sender starts with `peer-check-` and whose body starts `[embassy check` is echoed in one line; either half alone is ordinary untrusted text. It costs the peer one model turn, so it is a deliberate command, not something to poll.
65
-
66
- ```text
67
- embassy check 50066f60 → codex-reviewer@this-mac
68
-
69
- ok register peer-check-b0c963c9@this-mac (ephemeral, 2 min) 6 ms
70
- ok send accepted, conversation …89abcdef 15 ms
71
- ok delivered the peer's transport accepted it 256 ms
72
- ok reply codex-reviewer@this-mac echoed 50066f60 1407 ms
73
- ok cleanup temporary check identity removed
83
+ The recipient gets a provenance envelope and a conversation-bound reply
84
+ command:
74
85
 
75
- check passed
86
+ ```sh
87
+ printf '%s\n' 'Review complete.' |
88
+ embassy send --conversation conv_example
76
89
  ```
77
90
 
78
- Install the skill where each agent discovers skills — Codex tasks can then be prompted with `$embassy-peer`, and Claude Code finds it as a user skill:
91
+ Conversation references are identity-bound, are not aliases, and may survive a
92
+ broker restart while their retained ledger row and both exact endpoints remain
93
+ valid. They stop resolving after retirement, replacement, expiry, eviction, or
94
+ a state reset.
79
95
 
80
- ```bash
81
- cp -R "$(npm root -g)/agent-embassy/skills/embassy-peer" ~/.codex/skills/
82
- cp -R "$(npm root -g)/agent-embassy/skills/embassy-peer" ~/.claude/skills/
83
- ```
96
+ ## Delivery
84
97
 
85
- ## Shell-peer fallback
98
+ One native wake can carry a bounded FIFO batch, so a busy recipient catches up
99
+ without one wake per queued message. Every message keeps its own source,
100
+ destination, conversation, deadline, and receipt. Capacity and expiry remain
101
+ visible per message.
86
102
 
87
- Any local harness that can run the CLI can join as a `peer-*` route — no plugin, daemon, PID binding, token file, or Keychain entry — and it is the supported fallback channel when native Codex delivery is unavailable. `embassy register-peer --alias peer-reviewer@your-host` prints a `peer_` token exactly once; keep it in the agent's context, never in argv, and pass it as the first stdin line of every later peer command with `--token-stdin` (the remaining stdin bytes are the body; `--emit-env` exists only for a harness that really does keep one stable shell). `embassy await --alias peer-reviewer@your-host --token-stdin` long-polls the mailbox in bounded 30-second iterations — one waiter per route, 16 in total — writes the complete framed message to stdout, and acknowledges only after stdout has flushed. A missing acknowledgement settles `unconfirmed`; uncertainty after the write was armed settles `ambiguous`; neither is replayed.
103
+ The durable write phases are `queued`, `reserved`, `armed`, `accepted`, and
104
+ `terminal`. Work known not to have been written may return to the queue. An
105
+ uncertain armed or accepted write is never replayed.
88
106
 
89
- ## Federation
107
+ An exact leading `STEER:` from Claude to Codex targets the active accepted
108
+ Codex operation at its next safe tool-call boundary. It never interrupts a
109
+ generation. If that boundary is cleanly unavailable, the message remains in
110
+ the ordinary bounded queue. The global kill switch is
111
+ `EMBASSY_STEERING_ENABLED=0`.
90
112
 
91
- `nodes.json` in the state directory is optional. The broker writes it on first boot, naming this machine by its own hostname with an empty peer list, and from then on that file — not the hostname — is the broker's durable identity. To reach a second machine, add its OpenSSH `Host` alias to `nodes`, keep `host` exactly as written, and restart: the brokers exchange body-free route catalogs and destination-owned handoffs over `ssh <node> embassy peer-stdio`, your SSH configuration owns keys and users, and Embassy opens no listener. Remote routes appear as `alias@host` mirrors. Details in [Configuration](docs/CONFIGURATION.md).
113
+ See [Delivery semantics](docs/DELIVERY.md) for the phase and receipt contract.
92
114
 
93
- ## Observability
115
+ ## Multiple machines
94
116
 
95
- `embassy status` is the one command for "what is going on". It is read-only — it never rescans; `embassy refresh` does — and prints prose in a terminal but the unchanged JSON snapshot when piped or with `--json`, so `embassy status --json | jq .routes` and every script keep working. `--recent <n>` (1–100, default 10) sizes the message list.
117
+ List direct peers in each machine's `nodes.json`. The local broker launches:
96
118
 
97
119
  ```text
98
- embassy 3.0.0 broker ok · pid 41213 · snapshot just now
99
- state dir /Users/you/.local/state/agent-embassy
100
- sessions scanned 3s ago
101
-
102
- connectors
103
- claude ok
104
- codex ok
105
-
106
- sessions
107
- session state route last seen
108
- advisor@this-mac busy routed 3s ago
109
-
110
- routes
111
- alias provider state queue last seen
112
- advisor@this-mac claude busy 2 discovered 3s
113
- codex-reviewer@this-mac codex idle 0 12s ago
114
-
115
- recent (3 of 3)
116
- 12s ago advisor@this-mac → codex-reviewer@this-mac queued
117
- 2m ago codex-reviewer@this-mac → advisor@this-mac delivered 210 ms
118
- The risk is the double-write window; I would gate it behind…
119
- 5m ago advisor@this-mac → codex-reviewer@this-mac delivered 61 ms
120
- Please review the migration risk before the freeze.
120
+ /usr/bin/ssh <node> embassy peer-stdio
121
121
  ```
122
122
 
123
- When something is wrong it says the safe code **and** what to do about it, and one quiet corner never makes the whole broker look broken:
124
-
125
- ```text
126
- embassy 3.0.0 broker degraded · pid 41213 · snapshot just now
127
- state dir /Users/you/.local/state/agent-embassy
128
- sessions scanned 3s ago
129
-
130
- connectors
131
- claude ok
132
- codex degraded MANAGED_CODEX_UNAVAILABLE
133
- Either a process outside Embassy holds the managed Codex control socket — quit it — or the managed App Server standalone layout is missing, which starting the daemon alone does not create: follow the Codex prerequisite in the README (the official installer, then the daemon).
134
- peer-release@this-mac stale (token or await loop gone)
135
- 2 message(s) waiting: run `embassy await --alias peer-release@this-mac --token-stdin` in the shell holding its token, or `embassy unregister-peer --alias peer-release@this-mac --token-stdin`.
136
-
137
- sessions
138
- session state route last seen
139
- advisor@this-mac busy routed 3s ago
140
-
141
- routes
142
- alias provider state queue last seen
143
- advisor@this-mac claude busy 2 discovered 3s
144
- codex-reviewer@this-mac codex stale 1 30m ago
145
- peer-release@this-mac peer idle 2 never
146
- codex-reviewer@this-mac: That Codex task is gone. Run `embassy register-codex --alias <new-alias> --succeeds <this alias>` from the new task, or `embassy unregister-codex --alias <this alias>` from the old one.
147
-
148
- recent (3 of 3)
149
- 12s ago advisor@this-mac → codex-reviewer@this-mac queued
150
- 2m ago codex-reviewer@this-mac advisor@this-mac delivered 210 ms
151
- The risk is the double-write window; I would gate it behind…
152
- 5m ago advisor@this-mac → codex-reviewer@this-mac delivered 61 ms
153
- Please review the migration risk before the freeze.
154
-
155
- alerts
156
- PEER_TUNNEL_UNAVAILABLE studio 45s ago
157
- The SSH tunnel to that node is down; check the node is reachable and its broker is running.
123
+ The plain same-user SSH login is the trust boundary. The peer's claimed host
124
+ must be listed in the destination's `nodes.json`; that claim is trusted, not
125
+ independently bound to a physical machine. No forced command or dedicated
126
+ per-node key is required. Configure each node's host label accurately.
127
+ Federation has no listener or multi-hop routing. The destination owns the
128
+ queue and trusts the peer's source identity, so first contact does not wait
129
+ for a destination catalog poll. Catalogs are bounded memory-only observations,
130
+ never routing authority.
131
+
132
+ `embassy refresh` observes local Claude sessions and every configured SSH
133
+ catalog in parallel. `status` performs no provider or network I/O: it shows the
134
+ last per-node catalog rows and observation time, retains the last rows when a
135
+ later refresh fails, and labels that node `PEER_TUNNEL_UNAVAILABLE`. At most 128
136
+ remote rows are displayed; truncation is explicit. Named and exact sends still
137
+ ask the owner directly.
138
+
139
+ ## Operations
140
+
141
+ ```sh
142
+ embassy status
143
+ embassy status --json
144
+ embassy refresh
145
+ embassy delivery-status --token dlv_example
146
+ embassy wait-delivery --token dlv_example
147
+ embassy retire --alias codex-reviewer@studio
148
+ embassy check
149
+ embassy service status
150
+ embassy serve # foreground alternative
158
151
  ```
159
152
 
160
- `embassy watch` tails the broker until Ctrl-C: each new message and each settlement at most once (`accepted → delivered (61 ms)`), stamped with the local time, plus route installs and retirements as a secondary line; `--json` streams the same events as JSONL. At most once, not exactly once — a transition that passes entirely between two one-second polls is never seen, and rows that left the retained window before the tail reached them are announced as a one-line note. `embassy --help` lists all seventeen commands.
153
+ `status` reports the broker ledger, queue depth, recent message outcomes,
154
+ retirements, each local route's last native operation, and the last bounded SSH
155
+ catalog observation. It does not claim that an idle provider is ready.
156
+
157
+ Machine output is one closed JSON line shaped as
158
+ `{"ok":true,"command":"status","result":{...}}`; route rows are therefore at
159
+ `.result.routes`. A terminal `embassy status` renders the same body for a
160
+ person, while `--json` keeps the envelope.
161
161
 
162
- ## Safety in one minute
162
+ `check` is a broker-only loopback through the real ledger and coordinator. It
163
+ proves local control, persistence, routing, and receipt handling without
164
+ contacting a live Claude or Codex agent. It is not a provider-readiness test.
163
165
 
164
- - **The OS boundary is the permission.** Reaching the same-UID private control socket on this host — or on a host in your `nodes.json` plus an exact alias is what lets a process message. There is no separate grant to hand out or revoke, because none could stop code already running as your user; a Claude session's route installs on its first use, and a Codex task registers explicitly only because Embassy must record its inherited identity. `embassy serve` binds no TCP port and serves no HTTP.
165
- - **Every routed body carries the provenance envelope naming the sender.** It is a marker for the receiving model, not a signature: treat every delivered body as untrusted input. Native permissions stay native — Embassy answers no Codex approval and cannot override Claude's `crossSessionInbound`.
166
- - **Bounded by design.** Queues, bodies (16 KiB), conversations, rate windows, and deadlines are bounded, and an ambiguous write is never replayed. `delivered` means the provider boundary was crossed — toward Codex the App Server accepted the turn; toward Claude the native mailbox write completed (`transport_written`) — never that a model read it; `unconfirmed` and `ambiguous` mean the evidence is missing and are terminal. Claude-bound bodies are written immediately, busy or idle; Codex-bound bodies queue until the task is idle, and only an exact leading `STEER:` from Claude may enter the active turn at its next tool-call boundary.
167
- - **Bodies are retained locally and yours.** Message bodies and their opaque delivery token/status persist in the broker's private mode-0600 state under bounded retention, and what `status` prints is a status snapshot that includes retained message bodies: `embassy status` shows retained bodies; treat its output as sensitive as the messages themselves.
166
+ `retire` removes one local endpoint identity. Queued and reserved work is
167
+ cancelled, armed work becomes ambiguous, and accepted work becomes unconfirmed.
168
+ Remote endpoints must be retired on their owning host.
169
+ If departed sessions share a name, retire one exactly with
170
+ `embassy retire --endpoint <public-id>` using its opaque ID from status.
168
171
 
169
- See [SECURITY.md](SECURITY.md) for the boundary in depth and how to report a vulnerability.
172
+ ## Safety
170
173
 
171
- <!-- tested-with: filled by the PM after the cutover drill -->
174
+ - The broker uses one private Unix socket and mode-0600 state inside a
175
+ mode-0700 directory. It does not listen on TCP or HTTP.
176
+ - Native task/session IDs, socket paths, credentials, transcripts, and raw
177
+ provider frames never appear in public output.
178
+ - Every native write is authorized against the exact current endpoint after
179
+ preparation. Names are never silently resolved again during an attempt.
180
+ - SSH uses the fixed system binary, batch mode, no forwarding, and no shell.
181
+ - `health` and `check` describe broker infrastructure, not model readiness or
182
+ comprehension.
172
183
 
173
- ## Upgrading from 2.x
184
+ See [Security](SECURITY.md), [Configuration](docs/CONFIGURATION.md), and
185
+ [Architecture](docs/GATEWAY-ARCHITECTURE.md).
174
186
 
175
- Version 3 accepts only fresh private state. Stop Embassy, move `gateway-state.json` aside, start 3.0, and re-register Codex tasks; Claude routes reinstall themselves on first use, and `nodes.json` is written for you if absent. The full [private state reset](docs/CONFIGURATION.md#private-state-reset) and every change are in the [changelog](CHANGELOG.md).
187
+ ## Upgrading to 4.x
176
188
 
177
- ## Documentation
189
+ Version 4 accepts only fresh private state schema 6 and private control
190
+ protocol 5. It does not migrate or read v3 state. Before upgrading, use the old
191
+ binary to inspect and settle work, stop the broker, preserve a backup of the
192
+ old state, then reset `gateway-state.json`. Keep `nodes.json`.
193
+
194
+ The rollback boundary is the preserved old state plus its matching old binary.
195
+ Do not point an old binary at schema-6 state or a v4 binary at old state.
196
+
197
+ ## Development
198
+
199
+ Routine tests use test-owned directories, fake Claude sockets, fake App Server
200
+ transports, and fake SSH processes:
201
+
202
+ ```sh
203
+ npm ci
204
+ TMPDIR=/tmp npm run check
205
+ ```
178
206
 
179
- | Document | What it covers |
180
- | --- | --- |
181
- | [Architecture](docs/GATEWAY-ARCHITECTURE.md) | Topology, adapters, control plane, federation, protocol versions, and the OS-boundary permission model |
182
- | [Delivery](docs/DELIVERY.md) | Delivery semantics, tokens, settlement states, and retry rules |
183
- | [Configuration](docs/CONFIGURATION.md) | Environment variables, `nodes.json`, the launchd service, and addressing |
184
- | [Security policy](SECURITY.md) | The boundary in depth, and how to report a vulnerability |
185
- | [Contributing](CONTRIBUTING.md) | Where changes go, and how to run the deterministic suite |
186
- | [Changelog](CHANGELOG.md) | What each release contains |
187
- | [Agent skill](skills/embassy-peer/SKILL.md) | The workflow an agent follows to operate Embassy |
207
+ No routine test connects a live provider or SSH host. See
208
+ [CONTRIBUTING.md](CONTRIBUTING.md).
188
209
 
189
210
  ## License
190
211
 
191
- [MIT](LICENSE)
212
+ MIT