agent-embassy 2.0.1 → 3.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 (144) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/CONTRIBUTING.md +19 -34
  3. package/README.md +110 -228
  4. package/SECURITY.md +55 -89
  5. package/dist/src/errors.d.ts +10 -1
  6. package/dist/src/errors.js +3 -1
  7. package/dist/src/errors.js.map +1 -1
  8. package/dist/src/gateway/claude-helper-protocol.d.ts +8 -11
  9. package/dist/src/gateway/claude-helper-protocol.js +12 -11
  10. package/dist/src/gateway/claude-helper-protocol.js.map +1 -1
  11. package/dist/src/gateway/claude-helper-supervisor.d.ts +1 -5
  12. package/dist/src/gateway/claude-helper-supervisor.js +10 -9
  13. package/dist/src/gateway/claude-helper-supervisor.js.map +1 -1
  14. package/dist/src/gateway/claude-helper.js +6 -6
  15. package/dist/src/gateway/claude-helper.js.map +1 -1
  16. package/dist/src/gateway/claude-peer.d.ts +0 -3
  17. package/dist/src/gateway/claude-peer.js +6 -18
  18. package/dist/src/gateway/claude-peer.js.map +1 -1
  19. package/dist/src/gateway/cli.d.ts +17 -6
  20. package/dist/src/gateway/cli.js +912 -261
  21. package/dist/src/gateway/cli.js.map +1 -1
  22. package/dist/src/gateway/codex-socket-holder.d.ts +26 -0
  23. package/dist/src/gateway/codex-socket-holder.js +76 -0
  24. package/dist/src/gateway/codex-socket-holder.js.map +1 -0
  25. package/dist/src/gateway/codex-stateless-transport.js +1 -1
  26. package/dist/src/gateway/codex-stateless-transport.js.map +1 -1
  27. package/dist/src/gateway/config.d.ts +1 -10
  28. package/dist/src/gateway/config.js +4 -10
  29. package/dist/src/gateway/config.js.map +1 -1
  30. package/dist/src/gateway/control.d.ts +45 -77
  31. package/dist/src/gateway/control.js +56 -141
  32. package/dist/src/gateway/control.js.map +1 -1
  33. package/dist/src/gateway/federation-nodes.d.ts +29 -2
  34. package/dist/src/gateway/federation-nodes.js +177 -7
  35. package/dist/src/gateway/federation-nodes.js.map +1 -1
  36. package/dist/src/gateway/peer-client.d.ts +4 -3
  37. package/dist/src/gateway/peer-client.js +22 -13
  38. package/dist/src/gateway/peer-client.js.map +1 -1
  39. package/dist/src/gateway/peer-protocol.d.ts +8 -11
  40. package/dist/src/gateway/peer-protocol.js +5 -12
  41. package/dist/src/gateway/peer-protocol.js.map +1 -1
  42. package/dist/src/gateway/provenance-envelope.d.ts +0 -1
  43. package/dist/src/gateway/provenance-envelope.js +4 -19
  44. package/dist/src/gateway/provenance-envelope.js.map +1 -1
  45. package/dist/src/gateway/providers.d.ts +7 -4
  46. package/dist/src/gateway/providers.js +16 -20
  47. package/dist/src/gateway/providers.js.map +1 -1
  48. package/dist/src/gateway/server.d.ts +3 -12
  49. package/dist/src/gateway/server.js +31 -50
  50. package/dist/src/gateway/server.js.map +1 -1
  51. package/dist/src/gateway/service-agent.d.ts +187 -0
  52. package/dist/src/gateway/service-agent.js +758 -0
  53. package/dist/src/gateway/service-agent.js.map +1 -0
  54. package/dist/src/gateway/service.d.ts +114 -31
  55. package/dist/src/gateway/service.js +461 -566
  56. package/dist/src/gateway/service.js.map +1 -1
  57. package/dist/src/gateway/status-view.d.ts +167 -0
  58. package/dist/src/gateway/status-view.js +488 -0
  59. package/dist/src/gateway/status-view.js.map +1 -0
  60. package/dist/src/gateway/store.d.ts +103 -21
  61. package/dist/src/gateway/store.js +454 -529
  62. package/dist/src/gateway/store.js.map +1 -1
  63. package/dist/src/gateway/types.d.ts +48 -99
  64. package/dist/src/gateway/types.js +15 -52
  65. package/dist/src/gateway/types.js.map +1 -1
  66. package/docs/CONFIGURATION.md +173 -44
  67. package/docs/DELIVERY.md +11 -11
  68. package/docs/GATEWAY-ARCHITECTURE.md +277 -375
  69. package/package.json +4 -12
  70. package/skills/embassy-peer/SKILL.md +65 -90
  71. package/skills/embassy-peer/agents/openai.yaml +1 -1
  72. package/README.zh-CN.md +0 -275
  73. package/assets/live-dashboard/app.css +0 -1619
  74. package/assets/vendor/react/LICENSE +0 -21
  75. package/assets/vendor/react/react-dom.production.min.js +0 -267
  76. package/assets/vendor/react/react.production.min.js +0 -31
  77. package/dist/src/gateway/acp-client.d.ts +0 -110
  78. package/dist/src/gateway/acp-client.js +0 -407
  79. package/dist/src/gateway/acp-client.js.map +0 -1
  80. package/dist/src/gateway/acp-provider.d.ts +0 -66
  81. package/dist/src/gateway/acp-provider.js +0 -275
  82. package/dist/src/gateway/acp-provider.js.map +0 -1
  83. package/dist/src/gateway/cli-copy.d.ts +0 -8
  84. package/dist/src/gateway/cli-copy.en.d.ts +0 -22
  85. package/dist/src/gateway/cli-copy.en.js +0 -62
  86. package/dist/src/gateway/cli-copy.en.js.map +0 -1
  87. package/dist/src/gateway/cli-copy.js +0 -27
  88. package/dist/src/gateway/cli-copy.js.map +0 -1
  89. package/dist/src/gateway/cli-copy.zh-CN.d.ts +0 -22
  90. package/dist/src/gateway/cli-copy.zh-CN.js +0 -62
  91. package/dist/src/gateway/cli-copy.zh-CN.js.map +0 -1
  92. package/dist/src/gateway/codex-doctor.d.ts +0 -36
  93. package/dist/src/gateway/codex-doctor.js +0 -127
  94. package/dist/src/gateway/codex-doctor.js.map +0 -1
  95. package/dist/src/gateway/dashboard-copy.d.ts +0 -7
  96. package/dist/src/gateway/dashboard-copy.en.d.ts +0 -504
  97. package/dist/src/gateway/dashboard-copy.en.js +0 -505
  98. package/dist/src/gateway/dashboard-copy.en.js.map +0 -1
  99. package/dist/src/gateway/dashboard-copy.js +0 -514
  100. package/dist/src/gateway/dashboard-copy.js.map +0 -1
  101. package/dist/src/gateway/dashboard-copy.zh-CN.d.ts +0 -504
  102. package/dist/src/gateway/dashboard-copy.zh-CN.js +0 -505
  103. package/dist/src/gateway/dashboard-copy.zh-CN.js.map +0 -1
  104. package/dist/src/gateway/dashboard-model.d.ts +0 -343
  105. package/dist/src/gateway/dashboard-model.js +0 -1061
  106. package/dist/src/gateway/dashboard-model.js.map +0 -1
  107. package/dist/src/gateway/dashboard.d.ts +0 -20
  108. package/dist/src/gateway/dashboard.js +0 -874
  109. package/dist/src/gateway/dashboard.js.map +0 -1
  110. package/dist/src/gateway/deepseek-detect.d.ts +0 -14
  111. package/dist/src/gateway/deepseek-detect.js +0 -41
  112. package/dist/src/gateway/deepseek-detect.js.map +0 -1
  113. package/dist/src/gateway/live-dashboard-app/app.js +0 -2385
  114. package/dist/src/gateway/live-dashboard-assets.d.ts +0 -10
  115. package/dist/src/gateway/live-dashboard-assets.js +0 -74
  116. package/dist/src/gateway/live-dashboard-assets.js.map +0 -1
  117. package/dist/src/gateway/live-dashboard-command.d.ts +0 -60
  118. package/dist/src/gateway/live-dashboard-command.js +0 -334
  119. package/dist/src/gateway/live-dashboard-command.js.map +0 -1
  120. package/dist/src/gateway/live-dashboard-http.d.ts +0 -39
  121. package/dist/src/gateway/live-dashboard-http.js +0 -383
  122. package/dist/src/gateway/live-dashboard-http.js.map +0 -1
  123. package/dist/src/gateway/live-dashboard-protocol.d.ts +0 -34
  124. package/dist/src/gateway/live-dashboard-protocol.js +0 -114
  125. package/dist/src/gateway/live-dashboard-protocol.js.map +0 -1
  126. package/dist/src/gateway/live-dashboard-server.d.ts +0 -33
  127. package/dist/src/gateway/live-dashboard-server.js +0 -144
  128. package/dist/src/gateway/live-dashboard-server.js.map +0 -1
  129. package/dist/src/gateway/live-dashboard-stream.d.ts +0 -46
  130. package/dist/src/gateway/live-dashboard-stream.js +0 -234
  131. package/dist/src/gateway/live-dashboard-stream.js.map +0 -1
  132. package/dist/src/gateway/live-dashboard.d.ts +0 -28
  133. package/dist/src/gateway/live-dashboard.js +0 -154
  134. package/dist/src/gateway/live-dashboard.js.map +0 -1
  135. package/dist/src/gateway/locale.d.ts +0 -4
  136. package/dist/src/gateway/locale.js +0 -10
  137. package/dist/src/gateway/locale.js.map +0 -1
  138. package/dist/src/gateway/progress-watch-machine.d.ts +0 -45
  139. package/dist/src/gateway/progress-watch-machine.js +0 -70
  140. package/dist/src/gateway/progress-watch-machine.js.map +0 -1
  141. package/docs/CONFIGURATION.zh-CN.md +0 -97
  142. package/docs/DASHBOARD.md +0 -98
  143. package/docs/DASHBOARD.zh-CN.md +0 -49
  144. package/docs/DELIVERY.zh-CN.md +0 -55
package/README.md CHANGED
@@ -1,7 +1,5 @@
1
- [English](README.md) · [简体中文](README.zh-CN.md)
2
-
3
1
  <p align="center">
4
- <img src="https://raw.githubusercontent.com/YuanpingSong/embassy/main/assets/social-preview.png" alt="Embassy — a local gateway for bidirectional messaging between Claude Code sessions and Codex desktop tasks" width="720">
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">
5
3
  </p>
6
4
 
7
5
  # Embassy
@@ -12,294 +10,178 @@
12
10
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
13
11
  [![Node ≥ 20](https://img.shields.io/badge/node-%E2%89%A520-43853d)](package.json)
14
12
 
15
- Your [Claude Code](https://code.claude.com) sessions, [Codex](https://chatgpt.com/codex) desktop tasks, local DeepSeek Harness, Grok Build agent, and shell harnesses do not share one routing surface. Embassy is a small local broker that gives all five providers named routes and explicit consent edgesno plugins, no API keys handled by Embassy, and no cloud relay.
16
-
17
- ```bash
18
- npm install -g agent-embassy
19
- ```
20
-
21
- Prerequisites, stated honestly: Claude routes require a live same-user Claude
22
- Code session with peer protocol 1. Embassy derives the external registry and
23
- peer-socket roots from the current OS user; it does not inspect Claude's
24
- launcher or configuration. Codex routes require **a managed Codex App Server
25
- standalone install** (created by the ChatGPT desktop app, or by the official
26
- installer `curl -fsSL
27
- https://chatgpt.com/codex/install.sh | sh` followed by `codex app-server
28
- daemon start` — the daemon alone does not provision the layout). A missing
29
- Claude registry degrades only Claude while the broker and other providers stay
30
- available. pnpm users: pin the version (`pnpm install -g
31
- agent-embassy@latest` can resolve stale metadata; prefer an explicit
32
- version) and ensure `PNPM_HOME/bin` is on PATH in non-interactive shells.
33
-
34
- ```bash
35
- embassy serve
36
- ```
37
-
38
- Or from source: `git clone https://github.com/YuanpingSong/embassy && cd embassy && npm ci && npm run build && npm link`.
39
-
40
- Embassy is built for one person, one macOS account, and agents you already trust to run as that user. It is an unofficial community project and is not affiliated with or endorsed by Anthropic or OpenAI.
41
-
42
- ## Quickstart
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.
43
14
 
44
- **Requirements:** macOS and Node.js 20+. Claude routes require peer protocol 1; Codex routes use Codex CLI tasks with the managed standalone App Server. DeepSeek is optional and launches from `DSH_HOME` (default `~/.dsh`) through the checkout's `demo:acp` script; Grok Build is optional and launches the release-pinned ACP package. A shell peer needs only the local CLI and its one-time token. The release-owned [support matrix](support/provider-support-matrix.json) records the exact tested provider artifacts and capabilities; it is release evidence, never a runtime allowlist:
15
+ ## Install
45
16
 
46
17
  ```bash
47
- codex app-server daemon start
18
+ npm install -g agent-embassy
19
+ embassy service install
48
20
  ```
49
21
 
50
- Run the managed daemon from a normal terminal and use Codex CLI as the supported task host. Desktop's `CODEX_APP_SERVER_USE_LOCAL_DAEMON` attachment is broken in Desktop 26.820 and later ([openai/codex#41112](https://github.com/openai/codex/issues/41112)), so it is not a supported setup. If `CALLER_IDENTITY_CONFLICT` reports both identities, strip only the unwanted inherited identity at the call site: use `env -u CLAUDE_CODE_MESSAGING_SOCKET embassy …` for a Codex-side call, or `env -u CODEX_THREAD_ID embassy …` for a Claude-side call. The Claude destination needs [`crossSessionInbound`](docs/CONFIGURATION.md) enabled.
51
-
52
- Runtime delivery is best effort. Version and build strings are unverified metadata and never grant or withhold routing authority. Consent plus exact logical route/session identity authorizes an attempt; the current per-operation transport and correlated evidence determine its honest result. Unsupported or changed interfaces therefore fail with provider-local safe codes instead of an online compatibility tier. Embassy still validates the trust boundary: exact owned or executed artifacts and state paths, generations of artifacts it actually uses, strict consumed protocol fields, Claude peer protocol 1, bounded queues, and no replay after an ambiguous write.
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`.
53
23
 
54
- > **Known limitation:** Embassy can reach Codex tasks only while Desktop uses the managed standalone App Server. In that mode, tasks currently cannot connect to Desktop's built-in in-app browser (`@Browser` loads but does not attach). Switching Desktop back to its default private App Server restores the built-in browser immediately but makes those tasks unreachable by Embassy. No other capability regressions have been identified, though this was not an exhaustive parity test.
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.
55
25
 
56
- ### 1. Start Embassy
26
+ ## Your first message in four commands
57
27
 
58
- After creating the mandatory private `nodes.json` described in [Configuration](docs/CONFIGURATION.md), run the foreground broker under the same OS account as Claude Code and Codex:
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`.
59
29
 
60
30
  ```bash
61
- embassy serve
31
+ embassy register-codex --alias codex-reviewer@your-host
62
32
  ```
63
33
 
64
- You should see `"status":"ready"`. In another terminal:
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.
65
35
 
66
36
  ```bash
67
- embassy health
68
37
  embassy status
69
38
  ```
70
39
 
71
- `status` lists `availablePeers` the live Claude sessions you can select. If
72
- that list is empty, start a Claude Code session and run
73
- `embassy refresh-dashboard`, which refreshes discovery; the next `status`
74
- should show it.
75
-
76
- ### 2. Register the Codex task
77
-
78
- Ask your Codex agent to run this as a shell step in its current turn — the command must run inside the task so it inherits the task's identity:
79
-
80
- ```bash
81
- embassy register-codex --alias codex-reviewer@this-mac
82
- ```
83
-
84
- You should see `"accepted":true`. The `codex-` prefix is required for Claude discovery. To retire the task later, run `embassy unregister-codex --alias codex-reviewer@this-mac` from inside that same task.
85
-
86
- Registration records the exact inherited task identity and performs no App Server I/O. Every delivery opens a fresh attested local transport, initializes it, resumes that exact task with history excluded, and authorizes the body write once. App Server and Desktop restarts therefore do not require re-registration or re-anchoring; a current unavailable or unobservable task keeps the logical route and consent edge while the attempt reports an exact safe code. Embassy never retargets by alias or replays an ambiguously written body.
87
-
88
- ### Optional: register a universal shell peer
89
-
90
- A local shell harness can join as a `peer-*` route without a plugin, stable shell, daemon, PID binding, token file, or Keychain entry:
91
-
92
- When native Codex inbound dispatch is unavailable, this shell-peer mailbox is the supported fallback channel: register once, keep its token only in agent memory, and receive with bounded `await` calls.
93
-
94
- ```bash
95
- embassy register-peer --alias peer-reviewer@this-mac
96
- ```
97
-
98
- Registration prints the `peer_` token exactly once. Keep it in the agent's context and provide it on the first stdin line of every authenticated peer command; when a command also carries a message body, the remaining stdin bytes are the body. Never put the token in argv. For example, wait for inbound mail:
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.
99
41
 
100
42
  ```bash
101
- embassy await --alias peer-reviewer@this-mac --token-stdin <<'TOKEN'
102
- peer_<32-character-token>
103
- TOKEN
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
104
46
  ```
105
47
 
106
- `await` performs bounded 30-second long polls until mail arrives or the caller stops it. Each registration may have one waiter and the broker permits 16 in total. Embassy writes the complete framed message to stdout, waits for stdout to flush, and only then acknowledges its private receipt. A missing receipt is `unconfirmed`; uncertainty after write authorization is `ambiguous`, and neither is replayed after restart. `register-peer --emit-env` is an optional convenience for harnesses that really do retain one stable shell; stdin is the universal path.
107
-
108
- ### 3. Select a Claude destination
109
-
110
- Pick one name from `availablePeers`:
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.
111
49
 
112
50
  ```bash
113
- embassy select-claude --alias advisor@this-mac
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
114
54
  ```
115
55
 
116
- Run this from any same-UID process that can reach the private control socket. `embassy select-claude --session <uuid>` selects the same session by its native UUID.
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.
117
57
 
118
- You should see `"accepted":true`. Selection creates no permission edge. Create the user-chosen edge explicitly:
58
+ ## After any Claude Code or Codex CLI update
119
59
 
120
60
  ```bash
121
- embassy pair --from codex-reviewer@this-mac --to advisor@this-mac
61
+ embassy check
122
62
  ```
123
63
 
124
- Conversely, `unselect-claude` removes the selected route, removes its incident consent edges, and settles their in-flight work from the durable attempt phase.
125
-
126
- To connect any two routes from different providers, name both ends explicitly with `embassy pair --from <alias> --to <alias>`; many edges can coexist. Same-UID access to the private control socket authorizes the command, and agents must create only the edge the user chose. The live dashboard offers the same bounded, confirmed operation.
127
-
128
- ### 4. Send a message
129
-
130
- From the registered Codex task, send via stdin:
131
-
132
- ```bash
133
- embassy send \
134
- --from codex-reviewer@this-mac \
135
- --to advisor@this-mac \
136
- --expects-reply <<'MSG'
137
- Please review the current approach and identify the main risk.
138
- MSG
139
- ```
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.
140
65
 
141
- You should see a `conv_` conversation token and a `dlv_` delivery token. Because this send requested a reply, Claude's response is automatically routed back to the Codex task. In the other direction, a compatible Claude session uses its native `ListAgents` and `SendMessage` tools to contact `codex-reviewer` — no Embassy command needed.
66
+ ```text
67
+ embassy check 50066f60 → codex-reviewer@this-mac
142
68
 
143
- The same command runs in the other direction from a Claude session and inherits that session's reply identity:
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
144
74
 
145
- ```bash
146
- embassy send \
147
- --from advisor@this-mac \
148
- --to codex-reviewer@this-mac \
149
- --expects-reply <<'MSG'
150
- Summarize the migration risks you found.
151
- MSG
75
+ check passed
152
76
  ```
153
77
 
154
- ### 5. Follow up
155
-
156
- Either participant can continue the conversation with `reply`. The initiating
157
- CLI receives the full `conv_` token in its accepted result; the recipient gets
158
- the same token and an exact reply command in the broker-owned message marker:
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:
159
79
 
160
80
  ```bash
161
- embassy reply \
162
- --conversation conv_<token> \
163
- --alias codex-reviewer@this-mac <<'MSG'
164
- Please expand on the migration risk.
165
- MSG
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/
166
83
  ```
167
84
 
168
- Every routed body reaches either product inside one broker-owned
169
- `<cross-session-message>` textual frame. It identifies the verified sender
170
- alias and begins with an `<embassy-reply-hint>` containing the full conversation
171
- token, the recipient's exact alias, and the corresponding `embassy reply`
172
- command. Use only that delivered full token and alias; never guess one from a
173
- suffix or substitute the sender's alias. The CLI still rechecks the caller,
174
- conversation membership, and current route policy, so the hint is
175
- not a permission bypass.
85
+ ## Shell-peer fallback
176
86
 
177
- The frame is a clear provenance marker, not a cryptographic signature or a
178
- claim that the body is trustworthy. Embassy neutralizes nested occurrences of
179
- its reserved framing tags in the untrusted body before provider delivery;
180
- arbitrary same-user code and all message text remain untrusted input.
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.
181
88
 
182
- ### See it live
89
+ ## Federation
183
90
 
184
- `embassy dashboard --live` opens a five-tab streaming view in the browser
185
- (overview, deliveries, routes, activity, diagnostics) at
186
- `http://127.0.0.1:41961/` by default. To choose another stable port for that
187
- invocation, run `embassy dashboard --live --port <n>` with an integer from 1024
188
- through 65535. Up to four concurrent live views — across windows, tabs, or
189
- browsers — can use that URL while the foreground companion runs; a fifth stream
190
- is refused until one closes. If the port is occupied, startup fails explicitly,
191
- points to `--port`, and never falls back to another port. See
192
- [Dashboard](docs/DASHBOARD.md) for details.
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).
193
92
 
194
- The live dashboard can remove any named Codex registration after an explicit confirmation. The confirmation names the consequence: the broker deletes that registration's consent edges, cancels queued or reserved work, settles armed work ambiguous and accepted work unconfirmed, and never replays either uncertain class.
93
+ ## Observability
195
94
 
196
- The broker also publishes mode-0600 static snapshots as `gateway-dashboard.html` and `gateway-dashboard.zh-CN.html`. The live dashboard has no login, token, cookie, or per-browser session: it assumes a trusted single-user machine, and local software that can reach or spoof loopback can read it and invoke its bounded actions. The server still requires the exact Host header on every request and the exact Origin plus `X-Embassy-Request` on every POST; it sends no CORS headers and does not accept `OPTIONS`.
197
-
198
- ## How it works
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.
199
96
 
200
97
  ```text
201
- Claude Code sessions Codex desktop task
202
- (native ListAgents / (native App Server,
203
- SendMessage tools) existing task policy)
204
- │ │
205
- ▼ ▼
206
- ┌──────────────────── Embassy ─────────────────────────────┐
207
- │ explicit routes │ Codex busy queue │ receipts │ dashboard │
208
- └───────────────────────────────────────────────────────────┘
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.
209
121
  ```
210
122
 
211
- Embassy publishes each registered Codex task into Claude Code's live-session registry as its own `codex-*` peer. Claude sessions discover those tasks through `ListAgents`; Codex uses its managed App Server. DeepSeek and Grok Build are boot-registered ACP routes whose owned subprocess and one route-local session start lazily on first dispatch. Universal shell peers use `peer-*` aliases and a pull mailbox authenticated by an alias plus one-time-minted token.
212
-
213
- A pair is one explicit permission edge between two named routes from different providers, bounded at 128 edges by default. Every edge is created explicitly with generic `pair --from/--to`; the same-UID private control socket is the command's authority, while agents are instructed to create only user-chosen edges. Selection is separate and implies no consent. Without an edge, a sender settles terminally as `SENDER_NOT_PAIRED`. `embassy serve --inbound open` is the explicit opt-out for supported native inbound senders.
214
-
215
- Delivery timing is directional. Once routing and pre-write checks pass, every Claude-bound body is written immediately to Claude's native mailbox regardless of its observed busy or idle state. `transport_written` records that mailbox write and is the Claude-bound terminal `delivered` boundary; it does not mean Claude read or consumed the body. Codex-bound ordinary bodies instead queue while the task is busy and start a turn when it goes idle. In the Claude-to-Codex direction only, a body with an exact leading `STEER:` prefix may enter the active turn at the App Server's next tool-call boundary; if that boundary is unavailable, the message returns to the normal queue.
216
-
217
- Immediately before the provider write, Embassy gives every routed body one
218
- broker-owned cross-session marker containing the verified sender alias and a
219
- recipient reply hint. The full conversation token travels only in the
220
- initiator's accepted result and the recipient's transient message payload; it
221
- never enters the dashboard, public snapshot, journal, receipt, or log.
222
-
223
- Every settled message produces a receipt. `delivered` means the direction's terminal provider boundary was observed — toward Codex, the App Server accepted the turn; toward Claude, the native mailbox write completed. Neither means the model read or acted on it. `unconfirmed` and `ambiguous` mean the required evidence is missing; they are terminal states and never auto-retried. See [Delivery](docs/DELIVERY.md) for the full semantics.
224
-
225
- ## The vocabulary
226
-
227
- Four embassy terms name real features:
228
-
229
- - **Registration and pairing** are the permission model: a Codex task is explicitly registered, and each pair is one explicit Claude↔Codex edge — only paired ends exchange messages, and many edges can coexist. No edge means `SENDER_NOT_PAIRED`; nothing is ever implicit.
230
- - **The ledger** is the delivery record: a receipt for every settled message, and a metadata-only dashboard.
231
- - **The pouch** is transit and the archive: bounded bodies, retained under bounded limits, private to your OS account — sealed against other users, not against you.
232
- - **Consulates** are configured Embassy nodes: brokers federate over attach-only SSH and keep destination-owned delivery and consent authority.
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:
233
124
 
234
- ## For agents
235
-
236
- Embassy's operators are often agents themselves: `register-codex` runs inside the Codex task, and the Claude side is driven entirely through native tools. The repo ships [`skills/embassy-peer/SKILL.md`](skills/embassy-peer/SKILL.md) — point your agent at it rather than paraphrasing this README.
237
-
238
- The skill ships in the npm package; install it where each agent discovers skills:
239
-
240
- ```bash
241
- cp -R "$(npm root -g)/agent-embassy/skills/embassy-peer" ~/.codex/skills/
242
- cp -R "$(npm root -g)/agent-embassy/skills/embassy-peer" ~/.claude/skills/
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.
243
158
  ```
244
159
 
245
- Codex tasks can then be prompted with `$embassy-peer`; Claude Code discovers it as a user skill.
246
-
247
- ## Commands
248
-
249
- | Command | Run by | Purpose |
250
- | --- | --- | --- |
251
- | `serve` | operator | Start the foreground broker and dashboard |
252
- | `health` / `status` | operator | Check liveness and inspect the sanitized snapshot |
253
- | `refresh-dashboard` | operator | Refresh provider discovery and regenerate both static dashboard files |
254
- | `dashboard --live [--lang en\|zh-CN] [--port <n>]` | operator | Start the live dashboard companion with bounded route-consent actions; requires a running `embassy serve` |
255
- | `delivery-status` | either provider | Read one delivery tracker with `embassy delivery-status --token dlv_<token>` |
256
- | `wait-delivery` | either provider | Wait for that tracker to settle, up to the delivery deadline |
257
- | `untrack` | either provider | Close one active progress watch: `embassy untrack --conversation conv_<token>` |
258
- | `register-codex` / `unregister-codex` | Codex task | Advertise or retire that exact task; both take `--alias <codex-alias>`, and `embassy register-codex --alias codex-successor@this-mac --succeeds codex-reviewer@this-mac` hands the registration to a different task |
259
- | `register-peer` / `unregister-peer` | shell harness | Register or retire a `peer-*` route; registration emits its raw token once, while authenticated calls use `--token-stdin` (or the optional stable-shell env form) |
260
- | `await` | registered shell peer | Long-poll the peer mailbox in bounded 30-second iterations; one waiter per route, 16 globally, with acknowledgement only after stdout flush |
261
- | `pair` / `unpair` | same-UID control client | Add or remove one user-chosen cross-provider edge by naming both ends: `embassy pair --from advisor@this-mac --to grok-main@this-mac` |
262
- | `select-claude` / `unselect-claude` | same-UID control client | Select or remove one Claude route using `--alias <name@host>` or `--session <uuid>`; selection creates no permission edge |
263
- | `send` | registered Codex task, Claude session, or shell peer | Send one bounded stdin message between paired routes: `--from <alias> --to <alias>`, optional `--expects-reply` and `--track [--idle-minutes <n>]`; the broker derives direction from the resolved providers |
264
- | `reply` | conversation-token holder | Continue an active conversation with the full token returned to the initiator or delivered in the recipient's broker-owned reply hint: `--conversation conv_<token> --alias <your-alias>`, body on stdin, optional `--track [--idle-minutes <n>]` |
265
-
266
- Version 2.0 accepts only fresh private state. Follow the
267
- [reset-only state runbook](docs/CONFIGURATION.md#private-state-reset) before
268
- starting it over an older installation.
269
-
270
- `--track` opens a progress watch over the conversation; `--idle-minutes <n>`
271
- sets the idle interval for bounded liveness nudges (1–1440, default 5, rejected
272
- without `--track`). If the watch ultimately times out, Embassy records it only
273
- in watch history and emits no runtime stall alert. Close a watch with `untrack`,
274
- or by replying with a leading `DONE:`. See [Delivery](docs/DELIVERY.md).
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.
275
161
 
276
162
  ## Safety in one minute
277
163
 
278
- - **Local broker, stable loopback dashboard.** `embassy serve` listens on private Unix-domain sockets and makes no provider API call. The opt-in `embassy dashboard --live` companion is a separate process and the only listener Embassy can create, bound to exact `127.0.0.1` on stable port `41961` by default (or the per-invocation `--port <n>`). It is deliberately unauthenticated local HTTP for a trusted single-user machine; Host, Origin, and sentinel checks constrain browser-origin requests but do not authenticate local processes or OS users.
279
- - **Same-UID containment, not authentication.** Caller identity is inherited from the local process environment. Route ownership and per-operation artifact checks reduce mistakes, but are not a defense against code already running as your OS user.
280
- - **Compatibility is tested offline; runtime is best effort.** The release-owned support matrix records exact tested artifacts, protocols, capabilities, stop fidelity, limitations, and test dates. Runtime never imports that matrix and never turns a version fact into authority. It validates exact owned boundaries and protocol facts, attempts the current operation, and reports provider-local health and safe codes without replaying uncertainty.
281
- - **Native permissions stay native.** Embassy sends no Codex approval or sandbox overrides and answers no approval request. `crossSessionInbound` remains Claude's own control; Embassy cannot override it.
282
- - **Provenance is marked, not authenticated.** Routed bodies carry one broker-owned cross-session marker with the verified sender alias; it distinguishes the transport path for the receiving model but cannot make untrusted text safe or authenticate against code already running as your OS user.
283
- - **Bodies and delivery status stored, bounded, and yours.** Message bodies and their opaque delivery token/status persist in the broker's private mode-0600 v4 state under bounded retention; queued or reserved work may resume once after restart, while armed or provider-accepted work is never replayed. A delivery token never enters a public snapshot, normal log, provider receipt, or dashboard. Raw provider frames stay memory-only. The static dashboard files remain metadata-only; the live dashboard shows retained bodies.
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.
168
+
169
+ See [SECURITY.md](SECURITY.md) for the boundary in depth and how to report a vulnerability.
284
170
 
285
- See [SECURITY.md](SECURITY.md) for the full boundary and vulnerability-reporting process.
171
+ <!-- tested-with: filled by the PM after the cutover drill -->
286
172
 
287
- ## What Embassy is not
173
+ ## Upgrading from 2.x
288
174
 
289
- - **Not an orchestrator.** It does not spawn agents or manage their work. Codex-bound ordinary messages start one turn apiece as the task becomes idle; Claude-bound messages enter Claude's mailbox without waiting for idle.
290
- - **Not a hosted service.** Personal, same-machine, same-OS-account software.
291
- - **Not a permission bypass — but it is a new path.** Neither agent gains a tool it did not already have, and Embassy grants, relaxes, and answers nothing. It does, however, connect two products that previously could not exchange text at all. That path is the product; treat it with the respect you would give any new input channel.
292
- - **Not official.** Not affiliated with or endorsed by Anthropic or OpenAI.
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).
293
176
 
294
177
  ## Documentation
295
178
 
296
179
  | Document | What it covers |
297
180
  | --- | --- |
298
- | [Architecture](docs/GATEWAY-ARCHITECTURE.md) | The full design: topology, adapters, control plane, threat model, and the paired-consent inbound model |
181
+ | [Architecture](docs/GATEWAY-ARCHITECTURE.md) | Topology, adapters, control plane, federation, protocol versions, and the OS-boundary permission model |
299
182
  | [Delivery](docs/DELIVERY.md) | Delivery semantics, tokens, settlement states, and retry rules |
300
- | [Configuration](docs/CONFIGURATION.md) | Environment variables, provider contracts, and addressing rules |
301
- | [Dashboard](docs/DASHBOARD.md) | Static and live dashboard setup, security model, and mutation actions |
302
- | [Security policy](SECURITY.md) | How to report a vulnerability, and the boundary in depth |
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 |
303
185
  | [Contributing](CONTRIBUTING.md) | Where changes go, and how to run the deterministic suite |
304
186
  | [Changelog](CHANGELOG.md) | What each release contains |
305
187
  | [Agent skill](skills/embassy-peer/SKILL.md) | The workflow an agent follows to operate Embassy |