agent-embassy 1.4.0 → 1.5.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 (82) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/CONTRIBUTING.md +61 -6
  3. package/README.md +6 -5
  4. package/README.zh-CN.md +4 -4
  5. package/SECURITY.md +128 -24
  6. package/dist/src/gateway/claude-peer.d.ts +8 -5
  7. package/dist/src/gateway/claude-peer.js +81 -36
  8. package/dist/src/gateway/claude-peer.js.map +1 -1
  9. package/dist/src/gateway/claude-runtime.d.ts +4 -0
  10. package/dist/src/gateway/claude-runtime.js +50 -39
  11. package/dist/src/gateway/claude-runtime.js.map +1 -1
  12. package/dist/src/gateway/cli-copy.d.ts +1 -1
  13. package/dist/src/gateway/cli-copy.en.d.ts +1 -1
  14. package/dist/src/gateway/cli-copy.en.js +1 -1
  15. package/dist/src/gateway/cli-copy.en.js.map +1 -1
  16. package/dist/src/gateway/cli-copy.js +1 -1
  17. package/dist/src/gateway/cli-copy.js.map +1 -1
  18. package/dist/src/gateway/cli-copy.zh-CN.d.ts +1 -1
  19. package/dist/src/gateway/cli-copy.zh-CN.js +1 -1
  20. package/dist/src/gateway/cli-copy.zh-CN.js.map +1 -1
  21. package/dist/src/gateway/cli.d.ts +1 -1
  22. package/dist/src/gateway/cli.js +3 -7
  23. package/dist/src/gateway/cli.js.map +1 -1
  24. package/dist/src/gateway/codex-app-server.d.ts +2 -1
  25. package/dist/src/gateway/codex-app-server.js +1 -1
  26. package/dist/src/gateway/codex-app-server.js.map +1 -1
  27. package/dist/src/gateway/codex-local-transport.d.ts +10 -6
  28. package/dist/src/gateway/codex-local-transport.js +101 -56
  29. package/dist/src/gateway/codex-local-transport.js.map +1 -1
  30. package/dist/src/gateway/compatibility.d.ts +11 -0
  31. package/dist/src/gateway/compatibility.js +104 -22
  32. package/dist/src/gateway/compatibility.js.map +1 -1
  33. package/dist/src/gateway/control.js +28 -30
  34. package/dist/src/gateway/control.js.map +1 -1
  35. package/dist/src/gateway/dashboard-copy.d.ts +1 -1
  36. package/dist/src/gateway/dashboard-copy.en.d.ts +36 -17
  37. package/dist/src/gateway/dashboard-copy.en.js +50 -31
  38. package/dist/src/gateway/dashboard-copy.en.js.map +1 -1
  39. package/dist/src/gateway/dashboard-copy.js +36 -17
  40. package/dist/src/gateway/dashboard-copy.js.map +1 -1
  41. package/dist/src/gateway/dashboard-copy.zh-CN.d.ts +36 -17
  42. package/dist/src/gateway/dashboard-copy.zh-CN.js +50 -31
  43. package/dist/src/gateway/dashboard-copy.zh-CN.js.map +1 -1
  44. package/dist/src/gateway/dashboard-model.d.ts +176 -8
  45. package/dist/src/gateway/dashboard-model.js +420 -70
  46. package/dist/src/gateway/dashboard-model.js.map +1 -1
  47. package/dist/src/gateway/dashboard.js +48 -135
  48. package/dist/src/gateway/dashboard.js.map +1 -1
  49. package/dist/src/gateway/live-dashboard-app/app.js +148 -247
  50. package/dist/src/gateway/live-dashboard-assets.js +2 -1
  51. package/dist/src/gateway/live-dashboard-assets.js.map +1 -1
  52. package/dist/src/gateway/live-dashboard-stream.d.ts +2 -2
  53. package/dist/src/gateway/live-dashboard-stream.js +2 -2
  54. package/dist/src/gateway/live-dashboard-stream.js.map +1 -1
  55. package/dist/src/gateway/progress-watch-machine.d.ts +50 -64
  56. package/dist/src/gateway/progress-watch-machine.js +42 -133
  57. package/dist/src/gateway/progress-watch-machine.js.map +1 -1
  58. package/dist/src/gateway/provenance-envelope.d.ts +2 -0
  59. package/dist/src/gateway/provenance-envelope.js +13 -3
  60. package/dist/src/gateway/provenance-envelope.js.map +1 -1
  61. package/dist/src/gateway/providers.d.ts +69 -15
  62. package/dist/src/gateway/providers.js +456 -109
  63. package/dist/src/gateway/providers.js.map +1 -1
  64. package/dist/src/gateway/server.d.ts +8 -5
  65. package/dist/src/gateway/server.js +94 -13
  66. package/dist/src/gateway/server.js.map +1 -1
  67. package/dist/src/gateway/service.d.ts +25 -1
  68. package/dist/src/gateway/service.js +252 -69
  69. package/dist/src/gateway/service.js.map +1 -1
  70. package/dist/src/gateway/store.d.ts +23 -28
  71. package/dist/src/gateway/store.js +479 -467
  72. package/dist/src/gateway/store.js.map +1 -1
  73. package/dist/src/gateway/types.d.ts +38 -11
  74. package/dist/src/gateway/types.js +141 -3
  75. package/dist/src/gateway/types.js.map +1 -1
  76. package/docs/CONFIGURATION.md +8 -8
  77. package/docs/CONFIGURATION.zh-CN.md +8 -8
  78. package/docs/DASHBOARD.md +29 -6
  79. package/docs/DASHBOARD.zh-CN.md +1 -1
  80. package/docs/GATEWAY-ARCHITECTURE.md +143 -57
  81. package/package.json +1 -1
  82. package/skills/embassy-peer/SKILL.md +2 -2
package/CHANGELOG.md CHANGED
@@ -6,6 +6,38 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [1.5.0] - 2026-08-11
10
+
11
+ ### Changed
12
+
13
+ - Provider versions now follow one evidence ladder: certified same-major builds are writable; same-major builds with fully passing bounded probes are `schema_attested` and writable only when those probes cover the write path. Claude's probes cover its native write path, while untested Codex 0.x remains monitor-only pending a certified `turn/start` write schema. Failed probes, a different major, or version evidence that cannot establish a safe major leave only that provider degraded, monitor-only, and write-fenced while the broker, control socket, dashboards, and other provider keep running. Probes never promote across a major or compensate for unknown major evidence. An exact official launcher target may supply separate bounded major evidence even when its version banner is unparseable. Different-major guidance names the observed and tested versions plus the supported major and says that a supporting Embassy release is required. Exact OS ownership, path, symlink, lease, state, and generation failures still refuse broker startup.
14
+ - The progress watch keeps its six promises — visible to both parties, one per consent edge, closed by `DONE:` from either side with attribution, idle nudges, restart survival, attributed history — with a third of the machinery. Settlement is absence plus history; the journal vocabulary is exactly `opened`, `replaced`, `settled`, each row carrying a strict actor and reason; every journal write flows through one guarded batch append site. Upgrading from v1.4 settles each live watch once with a journaled row, and migration never consults today's configuration: history a past broker legitimately wrote loads to the immutable hard bound regardless of current depth settings.
15
+ - The static and live dashboards render one shared semantic vocabulary from `dashboard-model`, shipped to the live app inside its boot payload and compiler-linked through source-level type declarations verified against a never-built checkout. The surfaces keep deliberately different prose and CSS but can no longer disagree about what a state means. The static view model cannot materialize message bodies at all, proven by a sentinel test.
16
+ - A Claude route's endpoint generation is a named constant: broker restarts and upgrades no longer cycle Claude routes through stale and reobservation when the session is unchanged. Old hashed rows load untouched and heal exactly once through the existing session-identity rebind.
17
+
18
+ ### Added
19
+
20
+ - A `STEER:` message delivered to Codex carries one broker-owned line naming how many earlier accepted messages are queued on that route, counted read-only at injection and omitted when zero. The stalled-queue attention item carries the live queue depth for a busy Codex route, and the dashboard states the dynamic plainly: queued mail reaches the recipient when its current turn ends; end the turn if you control it.
21
+ - `docs/DECLINED.md`, the declined ledger: what Embassy considered and chose not to build, each with its reason. AGENTS.md and CONTRIBUTING.md carry the two-axis ticket system (effort budgets and blast-radius ratings) this release was built under.
22
+
23
+ ### Fixed
24
+
25
+ - A monitor-only Codex route renders as needing attention with a plain-language explanation on both dashboard surfaces — never as a ready exchange with a ready pair. A quarantined provider owns its recovery guidance: discovery, restore, and registration suggestions that cannot change compatibility evidence are suppressed; observation commands remain. Unsupported-major guidance stands alone without adjacent restart noise.
26
+ - A Claude registry record whose peer protocol is not 1 is rejected per record and included in bounded rejection evidence without stopping the broker.
27
+ - Claude registry parsing remains strict for every required and consumed field while tolerating unknown top-level fields. Optional bounded evidence on the existing Claude connector row carries scanned/parseable-required-field totals, whether such a record has appeared since broker start, and rejected-record counts by safe code. Status and both dashboards surface that evidence so an observed-empty registry stays loud; if Claude is running, its registry layout may have changed.
28
+ - Bounded `claude --version` observation tolerates suffixes and stderr notices and reports an unparseable banner without turning it into a misleading patch-drift failure.
29
+ - Dashboard guidance no longer claims a broker restart abandons queued mail — the durable queue re-sends exactly once, and only a write in flight at the moment of a crash settles ambiguous. The live view's privacy footnote says which rows carry no bodies and which show retained bodies by design. The static snapshot tells a dead-broker reader to run `embassy serve`. The native stall notice names the one-hop remedy for a busy recipient. A message over the 16 KiB acceptance cap gets a hint naming the cap and the remedy.
30
+
31
+ ## [1.4.1] - 2026-08-11
32
+
33
+ ### Changed
34
+
35
+ - Claude Code compatibility pin moved to **2.1.227** / peer protocol 1. Claude Code 2.1.227 auto-updated onto supported machines and the exact-version launcher gate stopped `embassy serve` from starting at all. The upgrade was verified before the pin moved, not assumed: a live 2.1.227 registry record carries the same closed field set and `peerProtocol: 1`, publishes the same `/tmp/cc-socks/<pid>.sock` 0600 socket under a 0700 directory, and the 2.1.227 build's registry writer/reader, newline-delimited JSON framing, user-frame acceptance, and `peer_message_status` frame shape are unchanged from 2.1.226 apart from minifier renames. Still-running 2.1.224–2.1.226 sessions remain discoverable during the patch-upgrade overlap.
36
+
37
+ ### Fixed
38
+
39
+ - The Claude version-drift message no longer promises that updating Embassy will fix the problem. `npm update -g agent-embassy` does nothing when no published Embassy supports the installed Claude Code yet — the exact case a maintainer hits first — so the copy now names both outcomes, tells the operator how to tell them apart, and stops asserting the installed build is "newer" when the pin is an exact match in either direction. Both locales.
40
+
9
41
  ## [1.4.0] - 2026-08-11
10
42
 
11
43
  ### Fixed
package/CONTRIBUTING.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Contributing to Embassy
2
2
 
3
- Embassy connects two powerful local agent runtimes across version-pinned native
3
+ Embassy connects two powerful local agent runtimes across evidence-gated native
4
4
  interfaces. Small changes can alter permission, privacy, or delivery behavior,
5
5
  so contributions should be narrow, testable, and explicit about boundaries.
6
6
 
@@ -33,6 +33,11 @@ recovery.
33
33
  - Add deterministic regression coverage for routing, protocol, persistence,
34
34
  permission, process-lifecycle, or redaction changes.
35
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.
36
41
  - Update README and architecture documentation when public behavior changes.
37
42
  - Verify that public files contain no credentials, native IDs, message bodies,
38
43
  local state, or personal absolute paths.
@@ -59,9 +64,28 @@ recovery.
59
64
  ### Provider adapters
60
65
 
61
66
  Claude Code's cross-session feature is official. Embassy's use of its external
62
- registry and peer socket shape is an internal, version-pinned adapter. Codex App
63
- Server is likewise version-pinned. Do not widen either compatibility range
64
- without a documented review and deterministic fixtures for the new version.
67
+ registry and peer socket shape remains an internal adapter: require the
68
+ native peer protocol 1 and bounded live-schema probes while
69
+ validating every consumed field and frame. Unknown top-level registry fields
70
+ may be ignored; required and consumed fields remain strict, and rejection or
71
+ observed-empty counts must stay loud. A certified same-major build is writable;
72
+ a same-major build whose probes all pass is `schema_attested`, but it is
73
+ writable only when those probes cover the write path. Claude's probes do.
74
+ Codex's bounded pre-write reads may include `initialize`, `thread/loaded/list`,
75
+ and registration-time `thread/resume`, but never `turn/start`; untested Codex
76
+ 0.x therefore remains monitor-only pending a certified write schema. Failed
77
+ probes, a different major, or version evidence that cannot establish a safe
78
+ major leave only that
79
+ provider degraded, monitor-only, and write-fenced while the broker,
80
+ control/dashboard surfaces, and other provider remain available; probes can
81
+ never promote across a major or unknown version. Unsafe ownership, path,
82
+ symlink, lease, state, or generation evidence for Embassy-owned or executed
83
+ artifacts and Embassy callback, control, or state paths still aborts startup;
84
+ an unsafe Claude-owned external sessions registry root quarantines only Claude.
85
+ Do not widen a supported major or declared protocol without a
86
+ documented review and deterministic fixtures. Different-major guidance must
87
+ safely name the observed/tested versions and supported major, say that a
88
+ supporting Embassy release is required, and never prescribe `embassy health`.
65
89
 
66
90
  The gateway may publish one process-owned `codex-*` peer so Claude's native
67
91
  `ListAgents` and `SendMessage` tools can reach Codex. It must never overwrite a
@@ -127,8 +151,9 @@ registry discovery, peer connection, provider messaging, App Server turns, and
127
151
  SSH attachment are separate external actions.
128
152
 
129
153
  A live action requires an explicit user request that identifies its scope. For
130
- a message, confirm the exact destination and body, send only once, avoid fanout,
131
- and do not retry an ambiguous result. Never put real provider traffic in CI.
154
+ a message, confirm the exact destination and body and avoid fanout. Follow the
155
+ send-failure policy below for command failures; never retry a confirmed
156
+ delivery or a recipient denial. Never put real provider traffic in CI.
132
157
 
133
158
  ## Reporting security issues
134
159
 
@@ -154,3 +179,33 @@ site, docs, in both languages:
154
179
  - The brand accent is never a state color, and state colors are never
155
180
  decoration.
156
181
  - Every alert pairs its state with the exact next command, copyable.
182
+
183
+ ### The declined ledger
184
+
185
+ [`docs/DECLINED.md`](docs/DECLINED.md) records, per release, what we considered
186
+ and chose not to build, each with a one-line reason. It is product
187
+ documentation: a product that documents what it refuses to build is making the
188
+ same promise the dashboard makes—the truth over the appearance of completeness.
189
+ PRs that implement something in the ledger must address its reason.
190
+
191
+ ### Why tickets are priced by the PM
192
+
193
+ The level of implementation—the one-hour version versus the one-week version—
194
+ is a scope decision, and scope is a product judgment. The PM prices it; the
195
+ engineer builds it faithfully within budget or contests the price with reasons.
196
+ Economy here never means lowering the bar on what ships: it means fewer things,
197
+ done well, and being explicit about what waits.
198
+
199
+ ### Send-failure policy
200
+
201
+ A send or reply whose command result is an error, truncation, or ambiguity is
202
+ not a delivery—it is a failed attempt to create one. Verify with read-only
203
+ `status`/`delivery-status`; if no acceptance is confirmed, resend without
204
+ asking, up to three attempts. Escalate to the PM only when a recipient
205
+ explicitly denied the message or three resends have failed. A duplicated
206
+ coordination message is a nuisance; a lost one deadlocks the pipeline, so
207
+ deliverability beats ceremony. Never auto-retry a delivery the recipient's
208
+ user denied: that is consent, not transport.
209
+
210
+ For long messages, write the body to a file and pipe it
211
+ (`embassy reply ... < body.md`); never inline `printf` for prose.
package/README.md CHANGED
@@ -25,7 +25,7 @@ Embassy is built for one person, one macOS account, and agents you already trust
25
25
 
26
26
  ## Quickstart
27
27
 
28
- **Requirements:** macOS, Node.js 20+, Claude Code 2.1.226 (still-running 2.1.224–2.1.225 sessions remain discoverable), and Codex desktop configured to use the managed standalone App Server 0.147.0:
28
+ **Requirements:** macOS, Node.js 20+, Claude Code on the supported 2.x major with peer protocol 1, and Codex desktop configured to use its managed standalone App Server. Embassy was last live-tested with Claude Code 2.1.227 and Codex App Server 0.147.0; those patch versions are evidence, not startup pins:
29
29
 
30
30
  ```bash
31
31
  ~/.codex/packages/standalone/current/codex app-server daemon start
@@ -34,7 +34,7 @@ Embassy is built for one person, one macOS account, and agents you already trust
34
34
 
35
35
  The first command starts the managed daemon if it is not already running (`restart` and `stop` also exist); the second launches the ChatGPT desktop app pointed at it. `CODEX_APP_SERVER_USE_LOCAL_DAEMON` is not documented by OpenAI; it is observed to work with this Desktop build and may change. Run the daemon command from a normal terminal, never from inside an agent session: Codex tasks inherit the daemon's environment, so a daemon started inside a Claude Code session leaks that session's identity into every task and registration fails closed with `CALLER_IDENTITY_CONFLICT` — fix it from a normal terminal with `codex app-server daemon restart`. The Claude session you select as a destination needs [`crossSessionInbound`](docs/CONFIGURATION.md) enabled — that is Claude Code's own setting, configured in Claude Code, not in Embassy.
36
36
 
37
- Provider compatibility needs no separate operator step. `embassy serve` automatically validates the release's exact Claude and Codex version pins and fails closed on unknown versions or required protocol shapes.
37
+ Provider compatibility needs no separate operator step. `embassy serve` attests the resolved installations and applies one evidence ladder to both providers. A certified same-major build is writable; a same-major build outside this release's tested inventory is shown as `schema_attested` when every bounded live-schema probe passes and is writable only when those probes cover its write path. Claude's probes cover its native write path. Codex's bounded pre-write reads may include `initialize`, `thread/loaded/list`, and registration-time `thread/resume`, but never `turn/start`; untested Codex 0.x therefore stays monitor-only pending a certified write schema. Failed probes, a different major, or version evidence that cannot establish a safe major leave only that provider degraded, monitor-only, and write-fenced. Probes never promote across a major or compensate for unknown major evidence; a different-major alert names the observed/tested versions and supported major and says that an Embassy release supporting the observed major is required. In every degraded case, the broker, control/dashboard surfaces, and other provider keep running. Only unsafe OS evidence for Embassy-owned or executed artifacts and Embassy callback, control, or state paths refuses broker startup; unsafe UID or mode evidence on Claude's external sessions registry root quarantines only Claude. A Claude session record whose peer protocol is not 1 is rejected in isolation and counted.
38
38
 
39
39
  > **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.
40
40
 
@@ -222,15 +222,16 @@ Codex tasks can then be prompted with `$embassy-peer`; Claude Code discovers it
222
222
  | `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>]` |
223
223
 
224
224
  `--track` opens a progress watch over the conversation; `--idle-minutes <n>`
225
- sets how long the watched thread may idle before the watch reports a stall
226
- (1–1440, default 5, rejected without `--track`). Close a watch with `untrack`,
225
+ sets the idle interval for bounded liveness nudges (1–1440, default 5, rejected
226
+ without `--track`). If the watch ultimately times out, Embassy records it only
227
+ in watch history and emits no runtime stall alert. Close a watch with `untrack`,
227
228
  or by replying with a leading `DONE:`. See [Delivery](docs/DELIVERY.md).
228
229
 
229
230
  ## Safety in one minute
230
231
 
231
232
  - **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.
232
233
  - **Same-UID containment, not authentication.** Caller identity is inherited from the local process environment. Route ownership and generation checks reduce mistakes, but are not a defense against code already running as your OS user.
233
- - **Compatibility is automatic and exact-pinned.** Broker/provider startup validates only the release's reviewed versions and protocol shapes. Every replacement App Server endpoint generation gets a fresh monitor-only check before route re-anchoring; unknown versions and malformed generations stay write-disabled.
234
+ - **Compatibility follows evidence, not patch pins.** Broker/provider startup attests exact filesystem ownership and paths, then applies the evidence ladder. Certified same-major builds are writable; fully probed same-major builds are `schema_attested` and writable only when the probes cover writes. Codex's bounded pre-write reads may include `initialize`, `thread/loaded/list`, and registration-time `thread/resume`, but never `turn/start`; untested Codex 0.x therefore remains monitor-only. Failed probes, a different major, or unknown version evidence fence only that provider while the broker and other provider keep running. Probes never promote across a major or unknown version. Unsafe Embassy-owned/executed artifacts and Embassy callback/control/state paths still refuse startup; an unsafe Claude-owned sessions registry root quarantines only Claude.
234
235
  - **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.
235
236
  - **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.
236
237
  - **Bodies stored, bounded, and yours.** Message bodies persist in the broker's private mode-0600 state under bounded retention so the ledger can show you the mail itself; queued mail survives a broker restart and re-sends exactly once. Raw provider frames stay memory-only. The static dashboard files remain metadata-only; the live dashboard shows retained bodies.
package/README.zh-CN.md CHANGED
@@ -25,7 +25,7 @@ Embassy 专为单人、单一 macOS 账户以及你已信任以该用户身份
25
25
 
26
26
  ## 快速开始
27
27
 
28
- **前置要求:** macOS、Node.js 20+、Claude Code 2.1.226(仍在运行的 2.1.224–2.1.225 会话保持可发现),以及配置为使用托管独立 App Server 0.147.0 的 Codex 桌面应用:
28
+ **前置要求:** macOS、Node.js 20+、使用已支持 2.x 主版本且对等协议为 1 的 Claude Code,以及配置为使用托管独立 App Server 的 Codex 桌面应用。Embassy 最近完成实机测试的版本是 Claude Code 2.1.227 Codex App Server 0.147.0;这些补丁版本是测试证据,而非启动固定值:
29
29
 
30
30
  ```bash
31
31
  ~/.codex/packages/standalone/current/codex app-server daemon start
@@ -34,7 +34,7 @@ Embassy 专为单人、单一 macOS 账户以及你已信任以该用户身份
34
34
 
35
35
  第一条命令在托管守护进程未运行时启动它(也提供 `restart` 与 `stop` 子命令);第二条以指向该守护进程的方式启动 ChatGPT 桌面应用。`CODEX_APP_SERVER_USE_LOCAL_DAEMON` 未见于 OpenAI 文档;它经验证适用于当前 Desktop 构建,未来可能变化。请在普通终端中运行守护进程命令,切勿在代理会话内运行:Codex 任务会继承守护进程的环境,因此在 Claude Code 会话内启动的守护进程会把该会话的身份泄漏到每个任务中,注册将以 `CALLER_IDENTITY_CONFLICT` 关闭失败——请在普通终端执行 `codex app-server daemon restart` 修复。你选择作为目的地的 Claude 会话需要启用 [`crossSessionInbound`](docs/CONFIGURATION.zh-CN.md)——这是 Claude Code 自身的设置,在 Claude Code 中配置,而非在 Embassy 中。
36
36
 
37
- 提供方兼容性无需操作员执行额外步骤。`embassy serve` 会自动验证本发布版精确固定的 Claude Codex 版本,并在遇到未知版本或必需协议结构时关闭失败。
37
+ 提供方兼容性无需操作员执行额外步骤。`embassy serve` 会验证解析到的安装边界,并对两种提供方应用同一套证据阶梯:同主版本且在已认证清单中的构建可写;同主版本但不在本发布版已测清单中的构建,在全部有界实时结构探测通过后显示为 `schema_attested`,但只有探测覆盖写入路径时才可写。Claude 探测覆盖原生写入路径。Codex 的有界写入前读取可能包括 `initialize`、`thread/loaded/list` 与注册时的 `thread/resume`,但绝不包括 `turn/start`;因此未测试的 Codex 0.x 在认证写入结构出现前保持仅监控。探测失败、主版本不同或版本证据无法建立安全主版本时,只有该提供方保持降级、仅监控并禁止写入,代理、控制面/仪表盘和另一提供方继续运行。探测绝不能跨主版本或未知主版本提升权限。主版本不同的告警会列出已观测/已测版本和支持主版本,并说明必须使用支持已观测主版本的 Embassy 发布版。只有 Embassy 自有或执行的构件及其回调、控制与状态路径出现不安全 OS 证据时才会拒绝代理启动;Claude 外部会话注册表根目录的 UID 或模式不安全时,只隔离 Claude。对等协议不是 1 的 Claude 会话记录会单独被拒绝并计数。
38
38
 
39
39
  > **已知限制:** 仅当 Desktop 使用托管独立 App Server 时,Embassy 才能访问 Codex 任务。在该模式下,任务目前无法连接 Desktop 内置的应用内浏览器(`@Browser` 可加载但无法附着)。将 Desktop 切换回其默认的私有 App Server 会立即恢复内置浏览器——但会使这些任务对 Embassy 不可达。目前未发现其他能力回退,但这并非穷尽的能力对比测试。
40
40
 
@@ -196,13 +196,13 @@ cp -R "$(npm root -g)/agent-embassy/skills/embassy-peer" ~/.claude/skills/
196
196
  | `send-to-codex` | Claude 会话 | 标志与正文输入方式相同,使用继承的原生回复标识 |
197
197
  | `reply` | 对话令牌持有方 | 使用初始发送时返回或随入站来源提示收到的完整令牌继续一个活跃对话:`--conversation conv_<token> --alias <你的别名>`,正文从标准输入读取,可选 `--track [--idle-minutes <n>]`;调用方、对话参与关系和路由会重新检查 |
198
198
 
199
- `--track` 会为该对话开启一个进度监视;`--idle-minutes <n>` 设置被监视线程在监视报告停滞前可以空闲多久(1–1440,默认 5,未加 `--track` 时会被拒绝)。用 `untrack` 关闭监视,或在回复正文开头使用 `DONE:` 关闭。详见[投递](docs/DELIVERY.zh-CN.md)。
199
+ `--track` 会为该对话开启一个进度监视;`--idle-minutes <n>` 设置有界活跃提醒的空闲间隔(1–1440,默认 5,未加 `--track` 时会被拒绝)。如果监视最终超时,Embassy 只在监视历史中记录该结算,不会发出运行时停滞告警。用 `untrack` 关闭监视,或在回复正文开头使用 `DONE:` 关闭。详见[投递](docs/DELIVERY.zh-CN.md)。
200
200
 
201
201
  ## 一分钟了解安全性
202
202
 
203
203
  - **本地代理,稳定的 loopback 仪表盘。** `embassy serve` 仅监听私有 Unix 域套接字,不发起任何提供商 API 调用。可选启用的 `embassy dashboard --live` 组件是一个独立进程,也是 Embassy 能创建的唯一监听器;它精确绑定 `127.0.0.1`,默认使用稳定端口 `41961`(也可为本次启动传入 `--port <n>`)。它是在可信单用户机器上有意不设身份认证的本地 HTTP;Host、Origin 与哨兵检查约束浏览器来源的请求,但不认证本地进程或 OS 用户。
204
204
  - **同 UID 隔离,而非身份认证。** 调用者身份继承自本地进程环境。路由所有权和生成号检查能减少误操作,但不是对已以你的 OS 用户身份运行的代码的防御。
205
- - **兼容性检查自动执行并精确固定版本。** 代理/提供方启动只验证本发布版已审查的版本和协议结构。每个替代 App Server 端点代际都必须先通过新的仅监控检查才能重新锚定路由;未知版本与结构异常的代际保持禁止写入。
205
+ - **兼容性依据证据,而非固定补丁版本。** 代理/提供方启动先验证精确的 OS 边界,再应用证据阶梯。同主版本的已认证构建可写;全部探测通过的同主版本构建显示为 `schema_attested`,且仅在探测覆盖写入时可写。Codex 的有界写入前读取可能包括 `initialize`、`thread/loaded/list` 与注册时的 `thread/resume`,但绝不包括 `turn/start`;因此未测试的 Codex 0.x 保持仅监控。探测失败、主版本不同或版本证据未知时,只封锁该提供方,代理和另一提供方继续运行。探测绝不能跨主版本或未知版本提升权限。Embassy 自有或执行的构件及其回调、控制与状态路径不安全时仍拒绝启动;Claude 外部会话注册表根目录不安全时只隔离 Claude。
206
206
  - **来源标记是提示,不是签名。** Embassy 在提供方写入边界生成跨会话来源封装,让接收模型能够区分代理路由消息及其已验证发送方别名;这不是密码学证明,也不会把不可信正文变成可信指令。
207
207
  - **原生权限保持原生。** Embassy 不发送任何 Codex 审批或沙盒覆盖,也不应答任何审批请求。`crossSessionInbound` 仍是 Claude 自身的控制机制;Embassy 无法覆盖它。
208
208
  - **消息体有界保存,属于你。** 消息体以有界保留策略持久化在 broker 的私有 mode-0600 状态中,让台账能够展示邮件本身;排队中的邮件在 broker 重启后幸存并恰好重发一次。原始提供方帧仍仅存于内存。静态仪表盘文件保持仅元数据;实时仪表盘展示保留的正文。
package/SECURITY.md CHANGED
@@ -49,6 +49,71 @@ against other processes running as the same OS user.
49
49
  environment or socket capabilities. Embassy is not a sandbox for untrusted
50
50
  same-user code.
51
51
 
52
+ ## What Embassy defends, and what it deliberately does not
53
+
54
+ Embassy's security boundary is intentionally narrower than “protect this user
55
+ from every process this user runs.” The boundary below governs implementation,
56
+ review, and audit work.
57
+
58
+ ### What Embassy defends
59
+
60
+ - **The same-UID OS and artifact boundary for anything Embassy executes or
61
+ treats as identity evidence.** Embassy validates canonical paths, ownership,
62
+ symlink policy, modes, approved version-directory containment, its own state
63
+ and sockets, and the generation of artifacts it owns. Before acting on an
64
+ identity-bearing input—such as an inherited task identity, provider record,
65
+ endpoint binding, route, or reply request—it validates the input's bounded
66
+ shape and its current ownership, correlation, and generation. Unsafe
67
+ controller-wide evidence is fatal; this class comprises Embassy-owned or
68
+ executed artifacts and Embassy callback, control, and state paths. The
69
+ Claude-owned external sessions registry root is instead a read-side identity
70
+ source: unsafe UID or mode evidence quarantines and write-fences only Claude,
71
+ with a loud observation, while the broker and other provider stay available.
72
+ A bad provider record, endpoint, or acted-on input is rejected or fenced at
73
+ that artifact rather than accepted on a best-effort basis.
74
+ - **Honest provenance at the message boundary.** The broker creates the outer
75
+ `cross-session-message` frame and first-child reply hint from validated route
76
+ metadata, and neutralizes body text shaped like its reserved framing tags
77
+ before composition. Those marks tell the receiver which transport path and
78
+ sender alias Embassy observed. They are not a signature, and every delivered
79
+ body remains untrusted input whose claims and requested actions require the
80
+ receiver's normal judgment, sandbox, and approval policy.
81
+ - **Anti-runaway containment.** Queue counts and bytes, message and frame sizes,
82
+ callbacks, conversations, retained bodies, deduplication records, rate
83
+ windows, and deadlines are bounded. Exhaustion rejects, expires, or fences
84
+ work with an explicit result; a bound never creates permission or justifies
85
+ replaying an ambiguous write.
86
+
87
+ ### What Embassy deliberately does not defend
88
+
89
+ - **Other local software already running as the same user.** Embassy provides
90
+ no local-process authentication and no capability or local-user consent
91
+ boundary against software already operating under that UID. Pair edges encode
92
+ routing consent between agent endpoints; aliases, conversation tokens,
93
+ inherited environment values, private sockets, and same-user file modes do
94
+ not authenticate one same-user process from another.
95
+ - **Local software through browser-origin checks.** Exact Host, Origin, the
96
+ `X-Embassy-Request` sentinel, and same-origin response policy constrain what a
97
+ browser can issue or read across origins. They do not authenticate a loopback
98
+ caller, its process, or its UID; the live dashboard assumes a trusted
99
+ single-user machine.
100
+ - **Predictions based on version strings.** A version string is a compatibility
101
+ observation, never security evidence or attack detection. Directly observed
102
+ path, ownership, protocol, schema, and generation facts outrank prediction
103
+ from a version string. Within the security boundary, boot refusal is reserved
104
+ for an unsafe or lost singleton lease, corrupt controller state, or unsafe
105
+ OS-boundary attestation. Version drift, an unparseable version, failed probes,
106
+ or one incompatible provider degrades and write-fences that surface; it does
107
+ not take down the broker or the other provider.
108
+
109
+ ### Audit rule
110
+
111
+ Every new audit check must cite the sentence in this doctrine that it enforces.
112
+ If the proposed check has no supporting sentence here, raise it explicitly as
113
+ a doctrine-change proposal, including the product and threat-model consequence,
114
+ before adding the check. A test, review finding, or “hardening” patch must not
115
+ silently expand Embassy's claimed boundary.
116
+
52
117
  ## Routing and consent
53
118
 
54
119
  - A Codex task must explicitly self-register with a `codex-*` alias before it
@@ -107,16 +172,34 @@ broker.
107
172
  only listeners are private Unix-domain sockets. The opt-in
108
173
  `embassy dashboard --live` companion is a separate process with its own
109
174
  loopback HTTP listener — see "Live companion boundary" below.
110
- - Provider protocols are exact-version-pinned. Provider startup automatically
111
- validates the release's reviewed Claude launcher/runtime, Claude peer-version
112
- inventory and protocol, and Codex App Server version. Unknown versions or
113
- required schemas fail closed. Every replacement Codex endpoint generation
114
- starts monitor-only and remains write-fenced until its fresh initialize and
115
- exact-task listing checks pass and the controller activates it.
116
- - Embassy publishes at most one visibly prefixed, process-owned `codex-*`
117
- record in Claude's registry. It creates one callback socket and removes only
118
- exact-owned artifacts whose generation still matches during graceful
119
- shutdown.
175
+ - Provider compatibility is evidence-gated rather than patch-version-pinned.
176
+ Provider startup first validates exact OS ownership, path, symlink, lease,
177
+ state, and generation evidence. Unsafe evidence for Embassy-owned or executed
178
+ artifacts and Embassy callback, control, or state paths refuses broker
179
+ startup; unsafe UID or mode evidence for Claude's external sessions registry
180
+ root quarantines and write-fences only Claude.
181
+ A certified same-major provider build is writable. A same-major build whose
182
+ bounded live-schema probes all pass is `schema_attested` and writable only
183
+ when those probes cover the write path. Claude's probes cover its native
184
+ write path. Codex's bounded pre-write reads may include `initialize`,
185
+ `thread/loaded/list`, and registration-time `thread/resume`, but never
186
+ `turn/start`; untested Codex 0.x therefore stays monitor-only pending a
187
+ certified write schema. Failed
188
+ probes, a different major, or version evidence that cannot establish a safe
189
+ major leave only that
190
+ provider degraded, monitor-only, and write-fenced while the broker,
191
+ control/dashboard surfaces, and other provider remain available; probes
192
+ never promote across a major or unknown version. A Claude
193
+ session record whose peer protocol is not 1 is rejected in isolation and
194
+ included in bounded rejection evidence. Every replacement Codex endpoint
195
+ generation remains write-fenced until its fresh initialize and exact-task
196
+ listing checks pass and the controller activates it.
197
+ - Embassy publishes at most one process-owned `codex-*` record in Claude's
198
+ registry with the supported explicit versioned Embassy-advertisement marker.
199
+ The prefix is a visible alias convention, not the discriminator: an unmarked
200
+ genuine Claude session named `codex-*` remains discoverable. Embassy creates
201
+ one callback socket and removes only exact-owned artifacts whose generation
202
+ still matches during graceful shutdown.
120
203
  - App Server methods are allowlisted. Embassy exposes no archive, deletion,
121
204
  shell, configuration, authentication, plugin, history, approval-response, or
122
205
  generic RPC method.
@@ -127,7 +210,7 @@ broker.
127
210
  retains at most three steers per route. The environment kill switch defaults
128
211
  on and can disable this classification globally. Interrupt remains limited to
129
212
  an exact turn started and positively observed by the same connector.
130
- - Exact App Server 0.147.0 initialization enables `experimentalApi: true`
213
+ - The tested App Server 0.147.0 initialization enables `experimentalApi: true`
131
214
  solely for `thread/resume.excludeTurns: true`. It adds no general
132
215
  experimental method or authority. Missing, malformed, or nonempty returned
133
216
  turns fail closed and are never retained.
@@ -163,7 +246,7 @@ kernel lock.
163
246
  Embassy's provider-facing access is intentionally enumerable:
164
247
 
165
248
  - read and execute the configured Claude launcher only for bounded automatic
166
- exact-version validation;
249
+ path, version-banner, and compatibility observation;
167
250
  - read the live Claude session registry and connect validated peer sockets;
168
251
  - create and later remove its one callback socket and one registry record;
169
252
  - resolve the managed Codex installation and attach to the already-running
@@ -171,10 +254,13 @@ Embassy's provider-facing access is intentionally enumerable:
171
254
  - inspect canonical filesystem metadata needed to validate provider-advertised
172
255
  endpoints and generations.
173
256
 
174
- Claude-owned registry files and peer sockets are accepted according to actual
175
- filesystem accessibility plus bounded schema, type, PID/path correlation,
176
- liveness, and generation checks. Embassy does not treat provider-owned Unix
177
- owner or mode bits as an additional routing policy.
257
+ The Claude-owned external sessions registry root must be owned by the current
258
+ UID with exact mode 0700 before Embassy enumerates it; failure quarantines and
259
+ write-fences only Claude. Within an admitted root, individual registry records
260
+ and peer sockets retain their bounded schema, file/socket type, PID/path and
261
+ allowed-root correlation, accessibility, liveness, and generation checks.
262
+ Embassy invents no additional owner or mode rule for those individual
263
+ provider-owned artifacts.
178
264
 
179
265
  Embassy does not need or intentionally read credentials, Keychain items,
180
266
  Claude project history, Codex or Claude transcripts, shell history, or provider
@@ -253,14 +339,32 @@ because this surface intentionally has no such authentication boundary.
253
339
  Routine tests use temporary directories, fake peers, and fake App Server
254
340
  transports. They do not inspect live provider state or contact a model.
255
341
 
256
- Compatibility admission is automatic and exact-pinned. Broker/provider startup
257
- owns the bounded read-only validation of the configured installations, exact
258
- versions, protocol constants, and required schemas; an unknown same-major build
259
- is not admitted. These checks do not route a user message or start a model
260
- turn. A replacement Codex endpoint generation receives its own fresh
261
- monitor-only initialize and exact-task listing check, while the write gate
262
- stays closed until controller activation. Runtime record, frame, response,
263
- identity, generation, and deadline checks remain mandatory after admission.
342
+ Compatibility admission is automatic and evidence-gated. Broker/provider
343
+ startup owns bounded read-only validation of the configured installations,
344
+ exact OS boundaries, provider majors, declared protocol constants, and live
345
+ schemas. Unsafe Embassy-owned/executed artifacts or Embassy callback, control,
346
+ or state paths remain startup-fatal; unsafe UID or mode evidence on Claude's
347
+ external sessions registry root quarantines only that provider. Certified
348
+ same-major builds are writable. Fully probed same-major
349
+ builds are `schema_attested` and writable only where the probes cover writes.
350
+ Codex's bounded pre-write reads may include `initialize`, `thread/loaded/list`,
351
+ and registration-time `thread/resume`, but never `turn/start`; untested Codex
352
+ 0.x therefore remains monitor-only. Failed
353
+ probes, different majors, and
354
+ version evidence that cannot establish a safe major remain provider-local
355
+ monitor-only states; the
356
+ broker and other provider stay available, and no probe can promote across a
357
+ major or unknown version. Different-major guidance
358
+ names the observed/tested versions and supported major and requires an Embassy
359
+ release supporting the observed major. These checks do not route a user
360
+ message or start a model turn. Claude
361
+ registry parsing remains strict for every required and consumed field while
362
+ ignoring unknown top-level fields; bounded rejected-record counts and an
363
+ observed-empty registry are surfaced instead of hidden. A replacement Codex
364
+ endpoint generation receives its own fresh monitor-only initialize and
365
+ exact-task listing check, while the write gate stays closed until controller
366
+ activation. Runtime record, frame, response, identity, generation, and
367
+ deadline checks remain mandatory after admission.
264
368
 
265
369
  Passive live discovery, a live provider connection, a native message, and an
266
370
  App Server turn are distinct authorization gates. Each requires an explicit
@@ -7,12 +7,10 @@ import { type DashboardLocale } from "./locale.js";
7
7
  * registry and NDJSON formats are not a stable public integration contract.
8
8
  */
9
9
  export declare const CLAUDE_PEER_COMPATIBILITY: Readonly<{
10
- claudeCodeVersion: "2.1.226";
10
+ claudeCodeVersion: "2.1.227";
11
11
  peerProtocol: 1;
12
12
  messageVersion: 1;
13
13
  }>;
14
- /** Live peer records may outlive a same-protocol Claude Code upgrade. */
15
- export declare const CLAUDE_PEER_COMPATIBLE_SESSION_VERSIONS: readonly ["2.1.224", "2.1.225", "2.1.226"];
16
14
  export declare const claudePeerStatuses: readonly ["busy", "shell", "idle", "waiting"];
17
15
  export type ClaudePeerStatus = (typeof claudePeerStatuses)[number];
18
16
  export declare const claudePeerKinds: readonly ["interactive", "bg", "daemon", "daemon-worker"];
@@ -33,7 +31,7 @@ export type ClaudePeerDiscovery = {
33
31
  truncated: boolean;
34
32
  /** Bounded registry entries examined, including safely skipped records. */
35
33
  entriesScanned: number;
36
- /** Records whose closed wire schema parsed before later liveness checks. */
34
+ /** Records whose required known fields parsed before later liveness checks. */
37
35
  parseableRecords: number;
38
36
  };
39
37
  export type ClaudePeerTransportStatus = "connecting" | "write_started" | "transport_written" | "ambiguous" | "not_written";
@@ -88,7 +86,7 @@ export type ClaudePeerConnect = (socketPath: string) => Socket;
88
86
  export type ClaudePeerAdapterOptions = {
89
87
  sessionsDir: string;
90
88
  socketDir: string;
91
- /** Exact version attested by the trusted launcher, never user input. */
89
+ /** Bounded version evidence attested by the trusted launcher, never user input. */
92
90
  attestedClaudeCodeVersion: string;
93
91
  /** Locale for bounded user-visible gateway notices written to Claude. */
94
92
  locale?: DashboardLocale;
@@ -107,6 +105,8 @@ export type ClaudePeerAdapterOptions = {
107
105
  };
108
106
  /** Dependency seams for deterministic tests; never populate from config. */
109
107
  export type ClaudePeerAdapterTestOverrides = {
108
+ /** Deterministic owner-mismatch seam; production always uses process.getuid(). */
109
+ expectedUid?: number;
110
110
  processInspector?: ClaudeProcessInspector;
111
111
  connect?: ClaudePeerConnect;
112
112
  now?: () => number;
@@ -122,6 +122,7 @@ export type ClaudePeerAdapterTestOverrides = {
122
122
  userHome?: string;
123
123
  tempRoots?: readonly string[];
124
124
  registryPublicationHook?: (stage: "before_rename" | "after_rename") => void | Promise<void>;
125
+ postBindHook?: (socketPath: string) => void | Promise<void>;
125
126
  };
126
127
  export type ClaudePeerRegistryPublicationOutcome = "published" | "not_published" | "unknown";
127
128
  export type ClaudePeerListenerOptions = {
@@ -159,6 +160,7 @@ type ParsedRegistryRecord = {
159
160
  messagingSocketPath: string;
160
161
  name: string;
161
162
  status: ClaudePeerStatus;
163
+ embassyAdvertisement: boolean;
162
164
  };
163
165
  type TargetBinding = {
164
166
  targetId: string;
@@ -230,6 +232,7 @@ type ListenerCreateOptions = {
230
232
  runRegistryMutation: <T>(operation: () => Promise<T>) => Promise<T>;
231
233
  preparedGeneration?: string;
232
234
  registryPublicationHook?: (stage: "before_rename" | "after_rename") => void | Promise<void>;
235
+ postBindHook: ClaudePeerAdapterTestOverrides["postBindHook"];
233
236
  onClosed: () => void;
234
237
  };
235
238
  export declare class ClaudePeerListener {