@junghanacs/entwurf 0.13.0 → 0.14.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 (193) hide show
  1. package/AGENTS.md +52 -17
  2. package/BASELINE.md +60 -206
  3. package/CHANGELOG.md +64 -0
  4. package/CONTRIBUTING.md +14 -10
  5. package/DELIVERY.md +118 -261
  6. package/README.md +91 -431
  7. package/VERIFY.md +74 -95
  8. package/demo/README.md +1 -1
  9. package/demo/demo-baseline.sh +1 -3
  10. package/demo/demo.sh +2 -5
  11. package/docs/acp-backend-rail.md +236 -0
  12. package/docs/external-mcp-host.md +131 -0
  13. package/docs/fresh-cut-policy.md +99 -0
  14. package/docs/setup-clean-host.md +124 -328
  15. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +160 -67
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/acp-client.js +12 -0
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +11 -10
  18. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/config.js +1 -1
  19. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/engraving.js +42 -1
  20. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +4 -4
  21. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +11 -9
  22. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-control-rpc.js +7 -5
  23. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-core.js +13 -14
  24. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-resume-args.js +45 -40
  25. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +117 -95
  26. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +23 -57
  27. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-lock.js +16 -7
  28. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +5 -53
  29. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-release.js +21 -36
  30. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-runner.js +3 -15
  31. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send-fallback.js +12 -11
  32. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send.js +2 -7
  33. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +30 -67
  34. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-visible-resume.js +256 -0
  35. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +91 -5
  36. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +258 -0
  37. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-launch.js +202 -0
  38. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-placement.js +289 -0
  39. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-resume-call.js +170 -0
  40. package/mcp/entwurf-bridge/dist/pi-extensions/lib/resume-launch-identity.js +136 -0
  41. package/mcp/entwurf-bridge/dist/pi-extensions/lib/session-id.js +8 -5
  42. package/mcp/entwurf-bridge/dist/pi-extensions/lib/socket-discovery.js +3 -3
  43. package/mcp/entwurf-bridge/dist/scripts/meta-facts.js +51 -0
  44. package/mcp/entwurf-bridge/dist/scripts/new-session-id.js +9 -4
  45. package/mcp/entwurf-bridge/src/index.ts +176 -67
  46. package/mcp/entwurf-bridge/start.sh +2 -2
  47. package/mcp/entwurf-bridge/test.sh +23 -9
  48. package/mcp/entwurf-bridge/tsconfig.build.json +11 -2
  49. package/package.json +25 -11
  50. package/pi-extensions/entwurf-control.ts +220 -71
  51. package/pi-extensions/lib/acp/acp-client.ts +22 -0
  52. package/pi-extensions/lib/acp/augment.ts +42 -3
  53. package/pi-extensions/lib/acp/backend-adapter.ts +12 -11
  54. package/pi-extensions/lib/acp/backend.ts +366 -38
  55. package/pi-extensions/lib/acp/config.ts +1 -1
  56. package/pi-extensions/lib/acp/engraving.ts +43 -1
  57. package/pi-extensions/lib/acp/event-mapper.ts +16 -13
  58. package/pi-extensions/lib/acp/models.ts +4 -4
  59. package/pi-extensions/lib/acp/overlay.ts +11 -9
  60. package/pi-extensions/lib/entwurf-control-rpc.ts +7 -5
  61. package/pi-extensions/lib/entwurf-core.ts +15 -15
  62. package/pi-extensions/lib/entwurf-resume-args.ts +41 -52
  63. package/pi-extensions/lib/entwurf-v2-contract-schema.ts +1 -1
  64. package/pi-extensions/lib/entwurf-v2-contract.ts +120 -99
  65. package/pi-extensions/lib/entwurf-v2-decider.ts +30 -91
  66. package/pi-extensions/lib/entwurf-v2-lock.ts +16 -7
  67. package/pi-extensions/lib/entwurf-v2-production.ts +4 -78
  68. package/pi-extensions/lib/entwurf-v2-release.ts +25 -49
  69. package/pi-extensions/lib/entwurf-v2-runner.ts +6 -21
  70. package/pi-extensions/lib/entwurf-v2-send-fallback.ts +12 -11
  71. package/pi-extensions/lib/entwurf-v2-send.ts +2 -7
  72. package/pi-extensions/lib/entwurf-v2-surface.ts +36 -76
  73. package/pi-extensions/lib/entwurf-v2-visible-resume.ts +370 -0
  74. package/pi-extensions/lib/meta-session.ts +93 -5
  75. package/pi-extensions/lib/mux-fresh-call.ts +328 -0
  76. package/pi-extensions/lib/mux-launch.ts +267 -0
  77. package/pi-extensions/lib/mux-placement.ts +387 -0
  78. package/pi-extensions/lib/mux-resume-call.ts +221 -0
  79. package/pi-extensions/lib/resume-launch-identity.ts +162 -0
  80. package/pi-extensions/lib/session-id.js +8 -5
  81. package/pi-extensions/lib/socket-discovery.ts +3 -3
  82. package/prompts/engraving.md +13 -5
  83. package/run.sh +688 -282
  84. package/scripts/agy-bridge-config.py +5 -1
  85. package/scripts/check-acp-backend-preflight.ts +1 -1
  86. package/scripts/check-acp-carrier-augment.ts +246 -10
  87. package/scripts/check-acp-cortex.ts +5 -5
  88. package/scripts/check-acp-overlay.ts +13 -3
  89. package/scripts/check-acp-prompt-lifecycle.ts +565 -0
  90. package/scripts/check-acp-stop-reason.ts +342 -0
  91. package/scripts/check-acp-stream-hooks.ts +504 -0
  92. package/scripts/check-elapsed.sh +25 -0
  93. package/scripts/check-entwurf-bridge-boot.ts +51 -4
  94. package/scripts/check-entwurf-bridge-pi-free.ts +6 -5
  95. package/scripts/check-entwurf-control-rpc.ts +4 -3
  96. package/scripts/check-entwurf-resume-args.ts +72 -70
  97. package/scripts/check-entwurf-session-identity.ts +14 -10
  98. package/scripts/check-entwurf-v2-contract.ts +34 -59
  99. package/scripts/check-entwurf-v2-decider.ts +17 -177
  100. package/scripts/check-entwurf-v2-lock.ts +5 -2
  101. package/scripts/check-entwurf-v2-matrix.ts +3 -53
  102. package/scripts/check-entwurf-v2-production.ts +2 -91
  103. package/scripts/check-entwurf-v2-release.ts +10 -105
  104. package/scripts/check-entwurf-v2-runner.ts +4 -85
  105. package/scripts/check-entwurf-v2-send-fallback.ts +5 -6
  106. package/scripts/check-entwurf-v2-send.ts +0 -28
  107. package/scripts/check-entwurf-v2-surface.ts +198 -128
  108. package/scripts/check-entwurf-v2-visible-resume.ts +445 -0
  109. package/scripts/check-fresh-cut-gate.sh +1 -1
  110. package/scripts/check-gate-qualification.ts +101 -7
  111. package/scripts/check-install-container.sh +10 -2
  112. package/scripts/check-install-surface.ts +1 -1
  113. package/scripts/check-keyset-overlap.py +1 -1
  114. package/scripts/check-meta-facts.ts +249 -0
  115. package/scripts/check-meta-identity-consumers.ts +1 -1
  116. package/scripts/check-meta-session.ts +169 -0
  117. package/scripts/check-mux-launch-tmux.ts +316 -0
  118. package/scripts/check-mux-launch.ts +288 -0
  119. package/scripts/check-mux-launcher-fence.ts +264 -0
  120. package/scripts/check-mux-parent-artifact.ts +195 -0
  121. package/scripts/check-mux-placement-tmux.ts +322 -0
  122. package/scripts/check-mux-placement.ts +323 -0
  123. package/scripts/check-mux-resume-call.ts +282 -0
  124. package/scripts/check-probe-cli-shim.ts +25 -22
  125. package/scripts/check-probe-ordering.ts +121 -81
  126. package/scripts/check-release-gate-outcomes.ts +452 -0
  127. package/scripts/check-resume-launch-identity.ts +244 -0
  128. package/scripts/check-socket-discovery.ts +1 -1
  129. package/scripts/fixtures/mux-parent-transcript.scrubbed.jsonl +3 -0
  130. package/scripts/inventory-verification-surface.ts +349 -0
  131. package/scripts/lib/claude-launcher-fence.ts +322 -0
  132. package/scripts/lib/live-skip.ts +33 -0
  133. package/scripts/lib/mutation-qualify.ts +109 -3
  134. package/scripts/lib/probe-acp-turn.ts +33 -12
  135. package/scripts/lib/step-outcome.sh +88 -0
  136. package/scripts/meta-bridge-doctor.sh +6 -8
  137. package/scripts/meta-facts.ts +60 -0
  138. package/scripts/mutants/acp-augment.json +106 -0
  139. package/scripts/mutants/acp-cortex.json +2 -2
  140. package/scripts/mutants/acp-overlay.json +17 -0
  141. package/scripts/mutants/acp-prompt-lifecycle.json +100 -0
  142. package/scripts/mutants/acp-stop-reason.json +80 -0
  143. package/scripts/mutants/acp-stream-hooks.json +158 -0
  144. package/scripts/mutants/bridge-boot-resume.json +45 -0
  145. package/scripts/mutants/meta-facts.json +50 -0
  146. package/scripts/mutants/meta-identity.json +36 -0
  147. package/scripts/mutants/mux-boundary.json +196 -0
  148. package/scripts/mutants/mux-fresh-call.json +185 -0
  149. package/scripts/mutants/mux-launcher-fence.json +123 -0
  150. package/scripts/mutants/mux-parent-artifact.json +39 -0
  151. package/scripts/mutants/mux-resume-call.json +148 -0
  152. package/scripts/mutants/probe-ordering.json +6 -1021
  153. package/scripts/mutants/release-gate.json +140 -0
  154. package/scripts/mutants/resume-args.json +76 -0
  155. package/scripts/mutants/resume-launch-identity.json +96 -0
  156. package/scripts/mutants/v2-surface.json +74 -23
  157. package/scripts/mutants/v2-visible-resume.json +215 -0
  158. package/scripts/new-session-id.ts +9 -4
  159. package/scripts/smoke-acp-bundled-mcp-live.ts +4 -3
  160. package/scripts/smoke-acp-carrier-augment-live.ts +2 -2
  161. package/scripts/smoke-acp-cortex-live.ts +8 -14
  162. package/scripts/smoke-acp-long-turn-live.ts +185 -0
  163. package/scripts/smoke-acp-mcp-live.ts +2 -2
  164. package/scripts/smoke-acp-memory-containment-live.ts +2 -2
  165. package/scripts/smoke-acp-ordering-probe-live.ts +2 -2
  166. package/scripts/smoke-acp-overlay-live.ts +2 -2
  167. package/scripts/smoke-acp-provider-live.ts +2 -2
  168. package/scripts/smoke-acp-raw-turn-live.ts +3 -3
  169. package/scripts/smoke-acp-session-reuse-live.ts +2 -2
  170. package/scripts/smoke-acp-skill-live.ts +2 -2
  171. package/scripts/smoke-acp-socket-citizen-live.ts +4 -3
  172. package/scripts/smoke-acp-v2-send-live.ts +4 -3
  173. package/scripts/smoke-agy-native-push-live.ts +10 -20
  174. package/scripts/smoke-claude-native-resume-live.sh +13 -3
  175. package/scripts/smoke-entwurf-chain-live.ts +352 -0
  176. package/scripts/smoke-entwurf-v2-matrix-live.ts +3 -3
  177. package/scripts/smoke-meta-honesty.sh +1 -1
  178. package/scripts/smoke-meta-install-state.sh +4 -0
  179. package/scripts/smoke-mux-fresh-call-live.ts +365 -0
  180. package/scripts/smoke-mux-lifecycle-live.ts +1136 -0
  181. package/scripts/smoke-pi-attach.ts +1 -1
  182. package/scripts/smoke-user-scope-citizen.sh +1 -1
  183. package/scripts/tsconfig.json +1 -0
  184. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-preflight.js +0 -160
  185. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn-production.js +0 -273
  186. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn.js +0 -216
  187. package/pi-extensions/lib/entwurf-v2-spawn-production.ts +0 -373
  188. package/pi-extensions/lib/entwurf-v2-spawn.ts +0 -323
  189. package/scripts/check-acp-sdk-surface.ts +0 -236
  190. package/scripts/check-entwurf-v2-spawn-production.ts +0 -551
  191. package/scripts/check-entwurf-v2-spawn.ts +0 -399
  192. package/scripts/smoke-entwurf-v2-spawn-live.ts +0 -188
  193. package/scripts/smoke-entwurf-v2-spawn-resume-live.ts +0 -469
package/CONTRIBUTING.md CHANGED
@@ -4,7 +4,7 @@ This is a daily-driver bridge. Correctness beats feature breadth. Read this befo
4
4
 
5
5
  ## What this repo is
6
6
 
7
- `entwurf` is a **garden-citizen dispatch bridge** — entwurf-core (v2 dispatch) + a meta-bridge + a pi adapter + an **ACP plugin on a two-backend adapter rail** — that lets already-running harnesses address one another by garden id; pi is one adapter, not the subject. The ACP plugin borrows the backend's identity (system prompt preset, model behavior, tool implementations) and shapes the *operating surface* — tools, MCP, skills, permissions — to match pi's own policy **wherever that backend exposes a knob for it**. Where it does not, the plugin does not fake one: a cortex session keeps its own native tool surface and receives MCP through an overlay projection, so "shaped to pi's policy" is a Claude-strength claim, not a universal one. Claude is the reference ACP backend and Snowflake Cortex Code is the second (landed 0.13.0, `cortex-` prefixed ids — [docs/acp-backend-rail.md](./docs/acp-backend-rail.md) §6/§11-8); Codex is a native garden citizen, and the Gemini path is deprecated. That is the entire scope.
7
+ `entwurf` is a **garden-citizen dispatch bridge** — entwurf-core (v2 dispatch) + a meta-bridge + a pi adapter + an **ACP plugin on a two-backend adapter rail** — that lets already-running harnesses address one another by garden id; pi is one adapter, not the subject. The ACP plugin borrows the backend's identity (system prompt preset, model behavior, tool implementations) and shapes the *operating surface* — tools, MCP, skills, permissions — to match pi's own policy **wherever that backend exposes a knob for it**. Where it does not, the plugin does not fake one: a cortex session keeps its own native tool surface and receives MCP through an overlay projection, so "shaped to pi's policy" is a Claude-strength claim, not a universal one. Claude is the reference ACP backend and Snowflake Cortex Code is the second (landed 0.13.0, `cortex-` prefixed ids — [docs/acp-backend-rail.md](./docs/acp-backend-rail.md#cortex-code-audit-d1d10)); Codex has native delivery-probe evidence but no managed citizen lane, and Gemini is not a shipped backend. That is the entire scope.
8
8
 
9
9
  **How a backend joins the rail** (the shape a PR must take): one adapter object in `pi-extensions/lib/acp/backend-adapter.ts` + its own curated rows/overlay modules + its own `check-acp-*` gate and mutant lane. Backend-specific *behavior* must stay behind the adapter, and backend-specific settings ride the opaque `adapterSettings` seam rather than growing the common config. That is not a ban on ever touching the common layer (`backend.ts`'s turn loop, `acp-client.ts`, `event-mapper.ts`, `session-store.ts`, `config.ts`) — cortex's landing did change `backend.ts` to pass the authoritative session key through the generic `ensureOverlay` seam. The rule is narrower and stricter: a common-layer change must be **backend-invariant** (it reads no backend name and branches on no backend) and **separately gated**. A common file that grows an `if (backend === …)` is the thing to reject.
10
10
 
@@ -17,7 +17,7 @@ These are enforced by code, gates, and review. Do not weaken them in a PR; if yo
17
17
  1. **Bootstrap order**: `resume > load > new`. Always.
18
18
  2. **Session persistence**: only `pi:<sessionId>` is persisted. `cwd:<cwd>` is never persisted.
19
19
  3. **MCP injection**: only via `entwurfProvider.mcpServers`. No ambient `~/.mcp.json` scanning, no `~/.claude/settings.json` MCP inheritance.
20
- 4. **Operating surface, not config inheritance**: the user's filesystem Claude Code config (`~/.claude/settings.json` hooks, env, plugins, `permissions.defaultMode`) is intentionally *not* inherited. Skills come from `skillPlugins`, permissions from `permissionAllow`, deferred-tool surface from `disallowedTools`. The `CLAUDE_CONFIG_DIR` overlay enforces this even where the SDK reads filesystem independently of `settingSources`.
20
+ 4. **Operating surface, not config inheritance**: the user's filesystem Claude Code config (`~/.claude/settings.json` hooks, env, plugins, `permissions.defaultMode`) is intentionally *not* inherited. Skills come from `skillPlugins`; callable tools are shaped by `tools` / `disallowedTools`, and `permissionAllow` still rides the inline Claude settings. The overlay authors `permissions.defaultMode: "bypassPermissions"` so an unattended ACP turn cannot suspend on an interactive prompt; this does not bypass backend authentication. `CLAUDE_CONFIG_DIR` enforces the isolation even where the SDK reads filesystem independently of `settingSources`.
21
21
  5. **Backend-specific knobs stay explicit and namespaced**: retired Codex/Gemini-era ACP knobs are not carried on the current path. A backend that needs its own knob uses the `ENTWURF_ACP_*` namespace, and invalid values must throw, never fall back — cortex followed this with `ENTWURF_ACP_CORTEX_CONNECTION` (the renamed `PI_SHELL_ACP*` legacy var), and its settings key rides `adapterSettings`, not the common config.
22
22
  6. **Bridge does not implement compaction**: When a backend compacts natively, the pi session and mapping survive that. Pi-side JSONL compaction must not be presented as backend-transcript reduction, and backend-specific compaction controls belong to the backend's own native interface. Legacy `PI_SHELL_ACP_*` compaction knobs must not reappear.
23
23
  7. **Backend coverage honesty**: changes to operating surface, session lifecycle, or persistence must state which shipped/probed backend surfaces they cover. A claim that silently drops a covered backend is a regression; if one backend is genuinely not covered, record that carve-out explicitly.
@@ -26,27 +26,31 @@ These are enforced by code, gates, and review. Do not weaken them in a PR; if yo
26
26
  ## Required gate before opening a PR
27
27
 
28
28
  ```bash
29
- pnpm check
29
+ pnpm check # everyday core (prints wall time; <=60s on the reference host)
30
+ pnpm run check:full # full deterministic floor — the required PR gate
30
31
  ```
31
32
 
32
- This wraps the entire static-quality surface (biome, tsc, all `check-*` gates including `check-dep-versions`). It is wired into the pre-commit hook (`.husky/pre-commit`), so a clean local commit is the first sign your change holds.
33
+ The deterministic floor is tiered (#70). `pnpm check` is the everyday core (biome, tsc, the vitest lanes, and the fast contract gates); `pnpm run check:full` adds the hermetic-integration and package/install tiers — all but the separately scheduled `check-gate-qualification`, which CI runs on every push and a gate-changing PR must run once itself. Exact membership is the named `check:*` scripts in `package.json`. Run `check:full` once on your frozen commit candidate — the pre-commit hook (`.husky/pre-commit`) carries only fast static checks (whitespace, lint, typecheck), not the full floor, so a green `pnpm run check:full` before commit is the evidence that your change holds (scheduling contract: AGENTS.md "Verification scheduling").
33
34
 
34
- For changes that touch backend launch, session lifecycle, or `_meta` shape, also run:
35
+ For changes that touch backend launch, session lifecycle, or `_meta` shape, also run
36
+ the live ACP smokes that cover the touched rail — at minimum:
35
37
 
36
38
  ```bash
37
- ./run.sh smoke-all /path/to/your-fixture-project
38
- ./run.sh verify-resume /path/to/your-fixture-project
39
+ LIVE=1 ./run.sh smoke-acp-provider-live
40
+ LIVE=1 ./run.sh smoke-acp-session-reuse-live
39
41
  ```
40
42
 
41
- These need a real ACP subprocess, so they stay manual the hook does not run them.
43
+ These need a real ACP subprocess plus the operator's local backend auth, so they stay
44
+ manual — the hook does not run them. The full aggregate is `LIVE=1 ./run.sh release-gate
45
+ <scratch> --cut` (see [VERIFY.md](./VERIFY.md)).
42
46
 
43
47
  ## What gets PRs rejected
44
48
 
45
49
  - adds ambient MCP discovery (project `.mcp.json`, `~/.mcp.json`, etc.) without an explicit `entwurfProvider.mcpServers` opt-in path
46
- - inherits user / project / local backend config by default (i.e. flips `settingSources` away from `[]`, drops the `CLAUDE_CONFIG_DIR` overlay, removes the codex `-c` config flags)
50
+ - inherits user / project / local backend config by default (i.e. flips `settingSources` away from `[]`, drops the `CLAUDE_CONFIG_DIR` overlay, or weakens cortex's session-scoped HOME containment)
47
51
  - weakens `resume > load > new` (e.g. silently downgrading to `new` without a logged invalidation reason)
48
52
  - introduces `console.warn` / silent fallback where the bridge should `throw` (see `AGENTS.md` "Never warn. Throw.")
49
- - changes the Claude, Codex, or Gemini operating surface (tools, skills, MCP, permissions, sandbox) without accounting for all three backends or recording an explicit carve-out
53
+ - changes a backend operating surface (tools, skills, MCP, permissions, sandbox) without accounting for both shipped backends (Claude, Cortex) or recording an explicit carve-out
50
54
  - adds a second transcript ledger, a prompt reconstruction layer, or any state that competes with pi's session as the source of truth
51
55
  - skews version pins across `package.json`, `run.sh`, and `README.md` (the `check-dep-versions` gate catches this; if it complains, fix all three)
52
56
 
package/DELIVERY.md CHANGED
@@ -1,285 +1,142 @@
1
- # DELIVERY.md — Async delivery capability levels
1
+ # Async delivery capability levels
2
2
 
3
- `DELIVERY.md` is the cross-harness yardstick for one question:
3
+ `DELIVERY.md` answers one cross-harness question:
4
4
 
5
- > Can an already-running native agent session receive an async message, without
6
- > pretending that pi owns the backend transcript?
5
+ > Can an already-running native agent session receive an asynchronous message
6
+ > without pretending that pi owns the backend transcript?
7
7
 
8
- It is **not** a product promise and not a benchmark. It is a diagnostic coordinate
9
- system. When Claude Code, Antigravity, Codex, pi-native Entwurf, or a future
10
- harness behaves differently, record the exact delivery level it reaches instead
11
- of collapsing the result into "works" / "doesn't work".
8
+ It is a diagnostic coordinate system, not a product promise or benchmark. Record
9
+ the highest demonstrated capability instead of collapsing results into “works” or
10
+ “doesn't work.” Evidence quality is tracked separately in [VERIFY.md](./VERIFY.md);
11
+ operator observations live in [BASELINE.md](./BASELINE.md).
12
12
 
13
- Companion surfaces:
13
+ ## Scope
14
14
 
15
- - [VERIFY.md](./VERIFY.md) agent-driven bridge verification and evidence quality (`L0–L5`).
16
- - [BASELINE.md](./BASELINE.md) operator-driven identity / overlay baseline interviews.
17
- - [`scripts/raw-async-delivery/`](./scripts/raw-async-delivery/) — reproducible raw delivery probes.
15
+ Qualifying delivery targets an already-running, backend-owned native session through
16
+ an official surface. It does **not** include:
18
17
 
19
- ## Scope and non-goals
18
+ - tmux/pty keystroke injection or transcript scraping;
19
+ - direct writes into backend transcripts or state databases;
20
+ - a fresh prompt/process/thread presented as continuation;
21
+ - transcript hydration or a second tool-result ledger inside entwurf.
20
22
 
21
- This document is about **native live-session delivery** on the current 0.12.x
22
- surface: a garden citizen points at a backend-owned native session, and async
23
- messages reach that session through the backend's own supported surface —
24
- mailbox wake for Claude Code, native-push for agy, or a launch-mode-specific
25
- probe rail for Codex.
26
-
27
- Non-goals:
28
-
29
- - no tmux / pty `send-keys` as evidence for native delivery;
30
- - no backend transcript hydration into pi JSONL;
31
- - no direct writes into backend transcript databases / JSONL / protobuf files;
32
- - no new prompt spawn (`claude -p`, fresh Codex thread, etc.) masquerading as
33
- delivery into an already-running subscription/native session;
34
- - no fake pi session or tool-result ledger for an external backend.
35
-
36
- A backend may use a socket, filesystem watch, JSON-RPC app server, lifecycle
37
- hook, or another official surface. The transport differs; the levels below keep
38
- the judgement comparable.
23
+ A transport may be a socket, filesystem watch, mailbox, lifecycle hook, or native
24
+ API. The levels compare capabilities, not implementation shapes.
39
25
 
40
26
  ## State vocabulary
41
27
 
42
- Use these words precisely in scripts and docs:
43
-
44
28
  | State | Meaning |
45
29
  |---|---|
46
- | `queued` | Message is durably written to a mailbox / sender queue. The backend has not necessarily seen it. |
47
- | `triggered` | A backend-supported event fired: socket RPC accepted, hook fired, file watch event observed, etc. |
48
- | `woke` | An idle interactive session started a new turn without user typing / pty injection. |
49
- | `injected` | The message or a doorbell pointing at it reached model-visible context through an official channel. |
50
- | `processed` | The turn ended or the backend acknowledged completion through a supported hook/event. |
51
- | `replied` | A result returned to the garden/pi side through an explicit reply path (MCP send, outbox, API result). |
30
+ | `queued` | A message is durable; the backend may not have seen it. |
31
+ | `triggered` | A supported event/API accepted the signal. |
32
+ | `woke` | An idle interactive session began a turn without user typing. |
33
+ | `injected` | The message reached model-visible context. |
34
+ | `processed` | A supported event says the turn completed. |
35
+ | `replied` | A result returned through an explicit garden-side path. |
52
36
 
53
- Avoid bare `delivered` unless you define it. Preferred decomposition:
54
- `queued → triggered → woke → injected → processed → replied`.
37
+ Avoid bare `delivered`; name the observed boundary.
55
38
 
56
- ## Delivery levels (D0–D8)
39
+ ## Levels (D0–D8)
57
40
 
58
- These are a separate namespace from VERIFY.md evidence levels (`L0–L5`) and
59
- BASELINE.md overlay layers (`Q-L1` etc.). Mark the highest level reached and any
60
- partial levels.
41
+ These are independent of VERIFY's `L0–L5` evidence levels and BASELINE's question
42
+ layers.
61
43
 
62
- | Level | Name | PASS criterion | Typical failure / partial |
63
- |---|---|---|---|
64
- | **D0** | Live session identity | Can identify the target live session: native id, cwd/project, backend, and enough liveness metadata to address it. | Only transcript files exist; no live-session join key. |
65
- | **D1** | Native/free continuation | Delivery targets an already-running native/subscription session; no fresh prompt spawn or metered worker is created for the message. | Uses `claude -p`, a fresh Codex thread, or a new pi child instead of the live session. |
66
- | **D2** | Receiver armed | The receiving session registers an official receive surface: hook/watch path/socket/app-server subscription. | A mailbox exists but no live session is watching or reachable. |
67
- | **D3** | Addressed enqueue | Sender can queue a message for exactly one target session id; siblings are not broadcast-woken. | Shared signal wakes every session; no per-session address. |
68
- | **D4** | Idle active wake | An idle interactive session wakes from an external signal with no user typing and no pty/tmux injection. | Piggyback only: message waits until the next human/user turn. |
69
- | **D5** | Context injection | A unique token / message body reaches model-visible context via an official hook/API path; the model can acknowledge it. | Hook logs show activity, but the model never sees the message. |
70
- | **D6** | Same session/model continuity | The response comes from the same native session/conversation and same model/subscription path. | A new conversation/process handles the message; model changed silently. |
71
- | **D7** | Completion / reply observation | Completion or reply can be observed without transcript scraping: Stop/SessionEnd/PostInvocation, outbox, MCP reply, API result, etc. | Wake and context work, but the garden side cannot know when the turn finished except by watching the UI. |
72
- | **D8** | Operational robustness | Duplicate suppression, delivery markers, loop guards, level-triggered body drain, ordering policy, stale-session handling, and crash recovery are implemented/tested. | Demo works once but can loop, duplicate, reorder, leave unread backlogs, or lose messages. |
44
+ | Level | Capability | PASS criterion |
45
+ |---|---|---|
46
+ | **D0** | Live identity | Native id, cwd/project, backend, and enough liveness data identify one target. |
47
+ | **D1** | Native continuation | The existing native/subscription session receives the message; no fresh worker/thread substitutes for it. |
48
+ | **D2** | Receiver armed | The session exposes a supported watch, hook, socket, subscription, or API route. |
49
+ | **D3** | Addressed enqueue | One target is selected; siblings are not broadcast-woken. |
50
+ | **D4** | Idle wake | An idle session wakes without user typing or pty injection. |
51
+ | **D5** | Context injection | A unique message reaches model-visible context through the supported route. |
52
+ | **D6** | Continuity | The same native session/conversation and model path responds. |
53
+ | **D7** | Completion/reply observation | Completion or reply is observable without transcript scraping. |
54
+ | **D8** | Operational robustness | Dedupe, ordering, stale handling, loop guards, and crash recovery are implemented and tested. |
73
55
 
74
- ### Script result contract
56
+ Mark partial or conditional cells explicitly. Capability and evidence are different:
57
+ a D7 claim from one direct-native run may still have only L4 evidence on one host.
75
58
 
76
- Raw probes should print a summary block that a human or later parser can compare
77
- across harnesses:
59
+ ### Probe output
60
+
61
+ Raw probes under [`scripts/raw-async-delivery/`](./scripts/raw-async-delivery/)
62
+ should print one comparable block:
78
63
 
79
64
  ```text
80
65
  DELIVERY_LEVELS:
81
- harness=claude-code
82
- transport=filechanged-watchpaths-asyncrewake
83
- D0 live_session: pass
84
- D1 native_free_continuation: pass
85
- D2 receiver_armed: pass
86
- D3 addressed_enqueue: pass
87
- D4 idle_active_wake: pass
88
- D5 context_injection: pass token=AGY-PARITY-3399
89
- D6 continuity: pass session_id=<native-id> model=claude-opus-5
90
- D7 completion_reply: partial reason="no garden outbox yet"
91
- D8 robustness: partial reason="loop guard present; crash recovery not tested"
92
- ```
93
-
94
- When a level is **not applicable** or **conditional**, say so explicitly. For
95
- example, Codex app-server delivery is conditional on a loaded thread and control
96
- socket; direct Codex TUI is a different surface.
97
-
98
- ## Current capability matrix (2026-07-22)
99
-
100
- This matrix is a snapshot of what the raw probes have established. It should be
101
- updated when a backend version changes the delivery surface.
102
-
103
- The **Status** column is the current 0.12.x release framing, kept separate from
104
- the `D0–D8` capability level:
105
-
106
- - **shipped** — a supported lane: wired, gated, and addressable through the bridge today.
107
- - **verified-probe** — async delivery proven by a raw probe, but not yet a managed supported citizen lane.
108
- - **deferred** — not addressable as-is, or needs an extra managed install / cloud surface outside the current release.
109
-
110
- | Harness / surface | Status | Highest current level | Transport | Notes |
111
- |---|---|---:|---|---|
112
- | **pi native Entwurf** | shipped | D7+ | Unix control socket + pi followUp/custom messages | Replyable pi session. This is the resident baseline, not an external meta-session. The meta-record is the sole address authority (#50 C4): a record-less control socket — live or not — is refused as `record-less-socket` (diagnostic state), never dispatched. |
113
- | **Claude Code interactive >=2.1.217** | shipped *(Linux is the only certified axis)* | D6, D7 partial, D8 partial | Exec-form global plugin: `SessionStart` arms `watchPaths`; external write triggers exec-form `FileChanged`; `asyncRewake` wakes idle session | B2 direct-native at 2.1.217 on one NixOS host proved per-element argv, no shell expansion, parent join, and exit-2 idle wake. B at 2.1.138 proved the negative: `args` discarded while Claude reported success, so installer/doctor enforce 2.1.217 and there is no shell fallback. The launcher provenance token keeps an old cached command fail-closed. Active idle wake is D6; D7/D8 remain partial as before. The Linux container's planted cache/owner/bridge are fixtures, not a second native-host proof. |
114
- | **Antigravity / agy** | shipped | D6, D7 partial | Native LS gRPC `agentapi send-message` (native-push) | `PreInvocation` automatically births/attaches by native `conversationId` and writes the record-backed pid/start-key sender marker; `entwurf_v2` fire-and-forget probes and direct-injects through the antigravity adapter with a one-shot re-probe retry. Three managed adapters own MCP+one exact permission, statusline, and hook separately. `entwurf_register_native` remains an explicit/manual fallback, not the normal birth path. Live sender→sibling→same-gid reply passed on 2026-07-13, re-verified at **agy 1.1.0** on 2026-07-14 (13/13 LIVE checks); D7 stays partial because there is no canonical transcript/content receipt owned by the smoke. |
115
- | **Codex app-server-backed TUI 0.136.0** | verified-probe | D6, D7 (status) | WebSocket-over-UDS `turn/start` into the live `threadId` | **Demonstrated, no managed standalone, no cloud.** `codex app-server --listen unix://<owned 0700 dir>` + plain `codex` auto-attach (or `--remote unix://`). Full message injection (agy-like, not a doorbell); `thread/status/changed` gives completion observation. D8 robustness (dedupe / crash recovery / ordering policy) is not tested. `turn/steer` is active-turn steering, not idle wake. |
116
- | **Codex embedded TUI 0.136.0** | deferred | D0 partial | Native state DB / rollout transcript only | Standalone Embedded TUI binds no socket; no `FileChanged`/`asyncRewake` in Codex hooks; not retrofittable. Identify-only via state DB / rollout. |
117
- | **Codex managed-daemon / remote-control 0.136.0** | deferred | D4–D6 conditional | `app-server proxy` newline JSON-RPC over the daemon control socket | Needs the managed standalone install; `remote-control` also enables the **cloud** bridge. Use the bare `--listen` path above for a purely-local setup. |
118
- | **ACP Claude / Cortex (runtime lane)** | shipped as runtime; deferred as delivery target | — | ACP (via entwurf's pi adapter) | Both ACP backends are **landed runtime lanes** (Claude the reference; Cortex since 0.13.0 under the dual-HOME containment — `docs/acp-backend-rail.md` §11-8), but **not native-async-*delivery* targets**: ACP sessions are bridge-spawned children, not already-running native sessions to wake, so they fall outside this doc's delivery question. `deferred` here means "no async-delivery lane," not "unsupported." |
119
-
120
- ## Backend notes
121
-
122
- ### Claude Code — filesystem event wake, not socket push
123
-
124
- The current launch contract is **exec-only at Claude Code >=2.1.217**. All four
125
- hook leaves run the shipped `hook-launch.sh` as `command` with the real argv in
126
- `args`; the launcher stamps non-identity launch provenance and `exec`s the payload.
127
- A hook reached through an old cached shell command still mints its record but writes
128
- no sender/receiver marker, so an upgrade mismatch is fail-closed. Reinstall the
129
- meta-bridge and restart all old Claude sessions before judging delivery.
130
-
131
- Evidence boundary: B/B2 were real Claude sessions and therefore direct-native
132
- runtime evidence, but both ran on one NixOS host. `check-hook-launch-topology` is a
133
- deterministic execution proof of the shipped argv; `check-install-container` uses a
134
- fake Claude, planted plugin cache, stand-in owner, and fake live bridge. Those fixtures
135
- prove package/oracle behavior, not actual native session wake. A claimed Linux host
136
- is accepted only when its **installed** strict doctor sees the live owner join and
137
- exits 0; missing evidence is `NOT CERTIFIED`, not a partial delivery PASS. macOS is
138
- not yet verified/certified for this repair cut: install refuses Darwin, doctor stays
139
- nonzero, and only the uninstaller keeps Darwin support so an older managed install
140
- can be removed. Future native validation may reopen that lane.
141
-
142
- A missing local listening socket does **not** imply idle wake is impossible.
143
- Claude Code interactive can be woken by a supported filesystem-event path:
144
-
145
- 1. a plugin or settings hook runs at `SessionStart`;
146
- 2. it emits `watchPaths` for a per-session signal file;
147
- 3. an external sender writes a per-session message and pokes that signal;
148
- 4. `FileChanged` fires while the session is idle;
149
- 5. the hook exits with `asyncRewake` and writes the doorbell to **stderr**;
150
- 6. the same session/model wakes and self-fetches the message body.
151
-
152
- #### D8 partial — signal/body separation is level-triggered
153
-
154
- Claude's `FileChanged` signal is an edge: rapid signal writes may coalesce, and a
155
- true missed edge can leave an idle session with unread mail until another wake or
156
- backstop occurs. The body is not carried in that edge. Bodies are durable mailbox
157
- files (`*.msg` before the doorbell, `*.msg.delivered` after the doorbell), and
158
- `entwurf_inbox_read` drains the whole unread set in one read and archives them as
159
- `*.read`. Therefore a coalesced doorbell does not drop message bodies: once the
160
- receiver self-fetches, it consumes all queued bodies, not "one event = one body".
161
-
162
- Deterministic gates: `check-meta-session` asserts mixed fresh/delivered bodies are
163
- drained together and re-read is empty; `smoke-meta-honesty` asserts the doorbell's
164
- unread count matches what the inbox reader will drain. Remaining D8 work is still
165
- honest/open in #34: empirical FileChanged coalescing bounds, active-turn arrival,
166
- watchPath edge cases, compact-window re-arm gaps, and a heartbeat/re-poke backstop
167
- for live sessions with unread mail.
168
-
169
- Important gotchas live in [`scripts/raw-async-delivery/README.md`](./scripts/raw-async-delivery/README.md):
170
- `Stop` hooks do not wake idle sessions, bare skills cannot arm startup watches,
171
- plugins can, and imperatives in injected text can be flagged as prompt injection.
172
-
173
- ### Antigravity / agy — native push
174
-
175
- Antigravity reaches the same delivery levels through a different transport:
176
- `agy agentapi send-message` over the native LS gRPC surface. This is not a reason
177
- to make the garden layer backend-specific; it is exactly why the adapter contract
178
- must describe capability (`D0–D8`) separately from transport.
179
-
180
- The raw probe (`scripts/raw-async-delivery/raw-agy-send.sh` — the Live-SSOT method
181
- `pgrep -x agy` + an LS socket that answers `get-conversation-metadata`) is now
182
- productionized as the **native-push rail**: `pi-extensions/lib/native-push/adapter.ts`
183
- (full pid/LS scan, volatile route, 1-shot re-probe retry in the executor hand),
184
- `registerNativeConversation` (bind an already-running conversation as a garden
185
- citizen; no spawn), the `entwurf_v2` `native-push` transport (post-probe reject
186
- taxonomy: `native-push-target-dead` / `-probe-indeterminate` / `-no-resume-authority`),
187
- and the `install-agy-bridge` install adapter. agy is a `native-push` domain, distinct
188
- from the pi control-socket liveness domain and from the Claude mailbox self-fetch domain.
189
-
190
- #### agy ambient-status axis (install surface, orthogonal to D0–D8)
191
-
192
- Beyond delivery, agy carries two more entwurf-owned install surfaces: **ambient
193
- garden identity in the native statusline** (`entwurf-agy-statusline`) and the
194
- **`PreInvocation` birth/sender imprint** (`entwurf-agy-imprint`). These are not
195
- delivery levels — they are install-surface ownership axes with the same discipline
196
- the delivery rail uses: bare stable bins only (never repo/checkout paths),
197
- state-backed install/uninstall, element-level adopt-and-preserve with honest
198
- inverse, symlink refusal, fail-loud doctors, and an honest `?` before identity
199
- exists.
200
-
201
- Identity authority is the native `conversationId` looked up against meta-record
202
- **bodies**. No cwd back-match, filename-derived identity, or gid invention. agy
203
- has no `SessionStart`; the earliest hook is `PreInvocation`, so a new conversation
204
- may briefly render `🪛 ? agy`. On the first invocation the installed hook reads
205
- `conversationId` + `workspacePaths`, calls `upsertMetaSession` idempotently, and
206
- writes a sender marker only after the record exists. It always returns the neutral
207
- `{"injectSteps":[]}` response so identity bookkeeping cannot block the agy loop.
208
-
209
- The marker is keyed by the shared host pid + process start-key and is revalidated
210
- against the record body. Replyability is `recordBacked ∧ probeAlive`, never
211
- mailbox `watchArmed`. This supports separate agy processes (measured: three pids,
212
- three markers) but **not** simultaneous model invocation by two conversations
213
- under one agy pid: one marker file would be last-writer-wins, so that concurrency
214
- is explicitly unsupported.
215
-
216
- Current deterministic floor: `smoke-agy-install-state` 167 checks,
217
- `smoke-agy-statusline-state` 69, `smoke-agy-hooks-state` 44,
218
- `check-agy-sender-identity` 28, plus the shared self-address/native-push gates.
219
- The bridge installer owns one narrow rule per normal-path tool
220
- (`entwurf_v2`, `entwurf_peers`, `entwurf_self`) in `permissions.allow`;
221
- broad YOLO policy stays operator-owned. Live 2026-07-13
222
- (agy 1.0.x): automatic birth → gid/statusline → record-backed sender → sibling
223
- delivery → same-gid native-push reply passed. Live 2026-07-14 (**agy 1.1.0**):
224
- re-verified on the new minor — `entwurf_self` answered without a permission
225
- prompt under the operator's broad allow (gid `20260714T101829-e7fccd`, native
226
- conversation `21266946-64a6-4a35-a7e5-fc84f0a7f250`), bidirectional native-push
227
- reply arrived on the same gid, and `LIVE=1 smoke-agy-native-push-live` passed
228
- 13/13; the drift-sentinel agy pin moved to the 1.1 line on this evidence.
229
-
230
- ### Codex — split by launch mode, not by "Codex"
231
-
232
- > **Version verdict (2026-07-14, 0.12.7 cut):** the installed codex is **0.144.1**;
233
- > every claim in this section was measured at **0.136.0** and has **NOT been
234
- > re-verified** since. Codex is not a shipped native-citizen lane in 0.12.x, so the
235
- > drift-sentinel pin moved to the 0.144 line with this explicit non-reverification
236
- > verdict instead of a fresh probe run. Re-run the raw probes (and re-date the matrix
237
- > rows) before building any codex adapter on the new line.
238
-
239
- Do not describe "Codex" as one delivery shape. The split is the TUI's launch mode:
240
-
241
- - **standalone Embedded TUI**: binds no socket, no `FileChanged`/`asyncRewake` in
242
- Codex hooks, decision fixed at `run_main` → not addressable, not retrofittable;
243
- - **app-server-backed TUI**: idle-wake **works**. Run a bare
244
- `codex app-server --listen unix://$HOME/.codex/app-server-control/app-server-control.sock`
245
- (no managed standalone, no cloud — only the official daemon path needs the
246
- managed install). Plain `codex` (no `-c`) auto-attaches to that default socket;
247
- an external WebSocket-over-UDS client sends `turn/start` to the live `threadId`.
248
- Measured: idle thread woke with zero typing, body injected, model replied,
249
- completion observed via `thread/status/changed`.
250
-
251
- Sender: `raw-codex-ws-turn-start.py` → bare `--listen` socket (WebSocket, no managed
252
- standalone, no cloud). A second surface exists but is out of scope here — the managed
253
- **daemon** control socket (via `codex app-server proxy`) needs the managed standalone
254
- install, and `remote-control` enables the cloud bridge; we ship only the bare-local
255
- path. Per-folder `config.toml` `[projects."<path>"]` trust gates project-hook loading,
256
- not addressability.
257
-
258
- A Codex adapter must declare which launch mode + which socket it targets.
259
-
260
- ## How to use this in the current 0.12.x design
261
-
262
- For meta-sessions, peer records should expose capability rather than hiding
263
- backend differences:
264
-
265
- ```ts
266
- type WakeMode = "socket" | "file-watch" | "native-push" | "app-server" | "piggyback" | "none";
267
-
268
- type DeliveryPeer = {
269
- sessionId: string; // garden id
270
- kind: "pi-session" | "meta-session";
271
- backend: "pi" | "claude-code" | "antigravity" | "codex" | string;
272
- replyable: boolean;
273
- wakeMode: WakeMode;
274
- deliveryLevel: "D0" | "D1" | "D2" | "D3" | "D4" | "D5" | "D6" | "D7" | "D8";
275
- };
66
+ harness=<name>
67
+ transport=<official surface>
68
+ D0 live_identity: pass
69
+ D1 native_continuation: pass
70
+ ...
71
+ D7 completion_reply: partial reason="..."
72
+ D8 robustness: partial reason="..."
276
73
  ```
277
74
 
278
- MVP rule of thumb:
75
+ ## Current matrix
279
76
 
280
- - expose what is proven;
281
- - mark partial/conditional honestly;
282
- - keep transcript ownership native;
283
- - treat liveness as best-effort hint (`last_seen` + native presence), not as a
284
- single authoritative socket/WAL/file check;
285
- - keep lookup authority in the meta-record scan, not a derived index.
77
+ | Harness / surface | Product status | Capability | Transport and boundary |
78
+ |---|---|---|---|
79
+ | **pi native Entwurf** | shipped | D7; D8 partial | Record-addressed Unix control socket. A record-less socket is diagnostic only and never dispatched. |
80
+ | **Claude Code interactive `>=2.1.217`** | shipped; Linux certified | D6; D7/D8 partial | Per-session mailbox + exec-form `FileChanged`/`asyncRewake`. B2 proved idle wake and same-session continuity on one NixOS host. |
81
+ | **Antigravity / agy** | shipped | D6; D7 partial | Record-backed native-push through LS gRPC `agentapi send-message`; no mailbox or receiver marker. |
82
+ | **Codex app-server-backed TUI** | verified probe | D7; D8 unproven | WebSocket-over-UDS `turn/start` into a live `threadId`; status events expose completion. No managed citizen lane yet. |
83
+ | **Codex embedded TUI** | deferred | D0 partial | No supported receive socket/hook on the measured standalone shape. |
84
+ | **ACP Claude / Cortex** | shipped runtime, outside this matrix | — | ACP sessions are children launched by entwurf's pi adapter, not already-running native sessions to wake. |
85
+
86
+ “Verified probe” means the transport worked in a reproducible raw probe but entwurf
87
+ does not yet own lifecycle, installation, doctors, or release acceptance for it.
88
+ Re-audit backend versions before turning probe evidence into a shipped adapter.
89
+
90
+ ## Rail notes
91
+
92
+ ### Claude Code: durable body, edge-triggered wake
93
+
94
+ Claude's hook contract is exec-only at `>=2.1.217`. `SessionStart` arms a per-session
95
+ watch path; the sender writes durable `*.msg` bodies before poking the signal;
96
+ `FileChanged` emits a doorbell and `asyncRewake` wakes the idle session. The receiver
97
+ then calls `entwurf_inbox_read`, which drains all unread bodies and archives them as
98
+ `*.read`.
99
+
100
+ The signal is edge-triggered and may coalesce, but the message body is level-triggered:
101
+ one successful wake drains the backlog. D8 remains partial until active-turn arrival,
102
+ coalescing bounds, re-arm gaps, and crash/re-poke behavior are measured. A synthetic
103
+ container doctor proves package/oracle shape, not a real Claude wake; a claimed host
104
+ needs the installed strict doctor against a new native session.
105
+
106
+ ### Antigravity: native push
107
+
108
+ `PreInvocation` births or reattaches a citizen by native `conversationId` and writes a
109
+ record-backed sender marker. `entwurf_v2` probes the live conversation and injects
110
+ directly through the native adapter, with one bounded re-probe retry. Replyability is
111
+ `record-backed identity ∧ probe-alive`; mailbox state does not exist on this rail, and no
112
+ rail has resume authority since the visible-first cut.
113
+
114
+ The managed bridge, statusline, and hook installers own separate configuration atoms.
115
+ Same-pid concurrent model invocation by multiple conversations is not claimed because
116
+ the pid/start-key sender marker would be last-writer-wins. Current operator checks are
117
+ in [BASELINE.md](./BASELINE.md); deterministic ownership and sender gates run in
118
+ `pnpm run check:full`.
119
+
120
+ ### Codex: launch mode is part of the capability
121
+
122
+ Do not describe “Codex” as one delivery shape. The measured app-server-backed TUI can
123
+ accept `turn/start` for a live thread and report completion; the standalone embedded
124
+ TUI exposed no equivalent receive route. This remains archived method evidence, not a
125
+ shipping commitment: GLG closed the managed native Codex lane on 2026-08-01 because pi
126
+ already supplies the official GPT provider path. Entwurf will not duplicate it as a
127
+ native citizen or ACP backend. `turn/steer` is active-turn steering, not idle wake.
128
+
129
+ ## Recording a new claim
130
+
131
+ For every matrix change, record:
132
+
133
+ 1. backend version and launch mode;
134
+ 2. native session identifier and liveness join;
135
+ 3. exact official transport;
136
+ 4. highest D-level plus every partial boundary;
137
+ 5. evidence level and artifact/log location;
138
+ 6. what remains outside entwurf ownership.
139
+
140
+ Keep transcript ownership native, lookup authority in the meta-record, and transport
141
+ asymmetry explicit. Historical probes and per-version chronology belong in CHANGELOG,
142
+ issues, and git history rather than this standing capability contract.