@junghanacs/entwurf 0.12.9 → 0.13.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 (100) hide show
  1. package/AGENTS.md +135 -248
  2. package/BASELINE.md +46 -7
  3. package/CHANGELOG.md +35 -0
  4. package/CONTRIBUTING.md +4 -2
  5. package/DELIVERY.md +5 -4
  6. package/README.md +46 -18
  7. package/VERIFY.md +10 -6
  8. package/demo/demo.sh +7 -1
  9. package/docs/setup-clean-host.md +10 -4
  10. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +159 -66
  11. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +148 -5
  12. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/config.js +16 -4
  13. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +66 -7
  14. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +190 -3
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/tool-surface.js +12 -4
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-core.js +26 -9
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-deliverability.js +10 -6
  18. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-fact-provider.js +15 -17
  19. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-facts.js +13 -13
  20. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-resume-args.js +31 -41
  21. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +8 -9
  22. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +32 -25
  23. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +4 -4
  24. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-lock.js +5 -4
  25. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +9 -11
  26. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn-production.js +3 -1
  27. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +17 -20
  28. package/mcp/entwurf-bridge/src/index.ts +190 -82
  29. package/package.json +7 -3
  30. package/pi/settings.reference.json +1 -1
  31. package/pi-extensions/acp-provider.ts +20 -10
  32. package/pi-extensions/entwurf-control.ts +69 -27
  33. package/pi-extensions/lib/acp/augment.ts +60 -2
  34. package/pi-extensions/lib/acp/backend-adapter.ts +183 -8
  35. package/pi-extensions/lib/acp/backend.ts +5 -1
  36. package/pi-extensions/lib/acp/config.ts +19 -5
  37. package/pi-extensions/lib/acp/engraving.ts +3 -1
  38. package/pi-extensions/lib/acp/event-mapper.ts +10 -3
  39. package/pi-extensions/lib/acp/models.ts +69 -7
  40. package/pi-extensions/lib/acp/overlay.ts +234 -3
  41. package/pi-extensions/lib/acp/tool-surface.ts +12 -4
  42. package/pi-extensions/lib/entwurf-core.ts +26 -9
  43. package/pi-extensions/lib/entwurf-deliverability.ts +10 -6
  44. package/pi-extensions/lib/entwurf-fact-provider.ts +15 -17
  45. package/pi-extensions/lib/entwurf-facts.ts +13 -13
  46. package/pi-extensions/lib/entwurf-resume-args.ts +40 -46
  47. package/pi-extensions/lib/entwurf-self-address.ts +8 -9
  48. package/pi-extensions/lib/entwurf-v2-contract-schema.ts +7 -2
  49. package/pi-extensions/lib/entwurf-v2-contract.ts +32 -25
  50. package/pi-extensions/lib/entwurf-v2-decider.ts +8 -8
  51. package/pi-extensions/lib/entwurf-v2-lock.ts +5 -4
  52. package/pi-extensions/lib/entwurf-v2-production.ts +14 -11
  53. package/pi-extensions/lib/entwurf-v2-spawn-production.ts +3 -1
  54. package/pi-extensions/lib/meta-session.ts +17 -20
  55. package/run.sh +200 -62
  56. package/scripts/agy-bridge-config.py +249 -49
  57. package/scripts/agy-bridge.sh +59 -14
  58. package/scripts/check-acp-carrier-augment.ts +34 -2
  59. package/scripts/check-acp-cortex.ts +668 -0
  60. package/scripts/check-acp-provider-surface.ts +50 -6
  61. package/scripts/check-acp-sdk-surface.ts +22 -11
  62. package/scripts/check-acp-session-reuse.ts +64 -1
  63. package/scripts/check-agy-permission-matrix.py +655 -0
  64. package/scripts/check-entwurf-deliverability.ts +9 -6
  65. package/scripts/check-entwurf-fact-provider.ts +7 -7
  66. package/scripts/check-entwurf-facts.ts +12 -12
  67. package/scripts/check-entwurf-resume-args.ts +22 -60
  68. package/scripts/check-entwurf-self-address.ts +187 -4
  69. package/scripts/check-entwurf-v2-contract.ts +2 -2
  70. package/scripts/check-entwurf-v2-production.ts +5 -5
  71. package/scripts/check-entwurf-v2-spawn-production.ts +6 -2
  72. package/scripts/check-entwurf-v2-surface.ts +327 -14
  73. package/scripts/check-gate-qualification.ts +787 -0
  74. package/scripts/check-meta-identity-consumers.ts +1 -1
  75. package/scripts/check-probe-cli-shim.ts +879 -0
  76. package/scripts/check-probe-ordering.ts +2450 -0
  77. package/scripts/check-shell-quote.ts +5 -4
  78. package/scripts/fixtures/probe-cli-shim +20 -0
  79. package/scripts/fixtures/probe-mcp-server.ts +168 -12
  80. package/scripts/lib/mutation-qualify.ts +794 -0
  81. package/scripts/lib/probe-acp-turn.ts +207 -0
  82. package/scripts/lib/probe-cli-shim.ts +464 -0
  83. package/scripts/lib/probe-cli-target.ts +165 -0
  84. package/scripts/lib/probe-event-log.ts +383 -0
  85. package/scripts/lib/probe-verdict.ts +1213 -0
  86. package/scripts/mutants/acp-augment.json +30 -0
  87. package/scripts/mutants/acp-cortex.json +196 -0
  88. package/scripts/mutants/agy-permission.json +144 -0
  89. package/scripts/mutants/meta-identity.json +17 -0
  90. package/scripts/mutants/probe-ordering.json +1032 -0
  91. package/scripts/mutants/self-address.json +59 -0
  92. package/scripts/mutants/v2-surface.json +87 -0
  93. package/scripts/smoke-acp-cortex-live.ts +392 -0
  94. package/scripts/smoke-acp-ordering-probe-live.ts +848 -0
  95. package/scripts/smoke-acp-raw-turn-live.ts +1 -1
  96. package/scripts/smoke-acp-v2-send-live.ts +33 -18
  97. package/scripts/smoke-agy-install-state.sh +205 -20
  98. package/scripts/smoke-entwurf-v2-matrix-live.ts +3 -2
  99. package/pi-extensions/lib/entwurf-mailbox-guard.ts +0 -100
  100. package/scripts/check-entwurf-mailbox-guard.ts +0 -266
package/BASELINE.md CHANGED
@@ -6,12 +6,16 @@ silently drifted into a different identity / context surface. Questions
6
6
  are deliberately open-ended — they probe what the agent actually sees,
7
7
  not what it was told to claim.
8
8
 
9
- The 0.12 shipped ACP backend is **Claude**; the main question bank below is the
10
- Claude ACP baseline. Antigravity (`agy`) is also shipped, but as a native-push
11
- garden citizen rather than an ACP backend, so it has a separate citizen/round-trip
12
- baseline below instead of being forced into Claude's overlay questions. Codex
13
- (pi-native / delivery probe) and Gemini (historical non-goal ACP probe) remain
14
- reference axes, not the shipped ACP baseline.
9
+ The released 0.12 ACP backend is **Claude**, and the main question bank below is the
10
+ Claude ACP baseline. The prepared **0.13.0** cut adds **Snowflake Cortex Code** as a
11
+ second ACP backend; it has no question bank of its own yet (deferred to 0.13.1), and the
12
+ Claude bank must not be run against it verbatim cortex is
13
+ system-prompt-carrier-less and runs its own native tool surface, so the overlay/engraving
14
+ questions below would grade it against a surface it does not have. Antigravity (`agy`)
15
+ is also shipped, but as a native-push garden citizen rather than an ACP backend, so it
16
+ has a separate citizen/round-trip baseline below instead of being forced into Claude's
17
+ overlay questions. Codex (pi-native / delivery probe) and Gemini (historical non-goal
18
+ ACP probe) remain reference axes, not a shipped ACP baseline.
15
19
 
16
20
  ## Release-host baseline — #51 repair cut
17
21
 
@@ -230,7 +234,7 @@ the same conversation must have a garden id.
230
234
  | Q-AGY-SELF | Sender identity | `entwurf_self` reports the same garden id, `origin=meta-session`, `agentId=meta-session/antigravity`, and `replyable:true` while the native probe is alive. | Anonymous `external-mcp`, unbacked marker accepted, model name substituted into `agentId`, or mailbox evidence used to infer replyability. |
231
235
  | Q-AGY-SEND | Outbound attribution | `entwurf_v2` from agy reaches a sibling carrying that same sender garden id and `replyable:true`. | Receiver sees unknown host/wrong garden id, or sender ambiguity is silently guessed. |
232
236
  | Q-AGY-REPLY | Same-conversation reply | Sibling replies with `entwurf_v2(target=<agy-gid>, intent=fire-and-forget)` and the message direct-injects into the same live agy conversation. | New conversation/spawn, mailbox file/doorbell, or a cosmetic delivered result with no live native route. |
233
- | Q-AGY-OWNERSHIP | Install scope | MCP owns one server plus `mcp(entwurf-bridge/entwurf_v2)` only; statusline owns its subtree; hooks own one named hook. | Installer broadens YOLO policy (`command(*)`, `unsandboxed(*)`) or overwrites unrelated settings/hooks. |
237
+ | Q-AGY-OWNERSHIP | Install scope | MCP owns one server plus one narrow `mcp(entwurf-bridge/<tool>)` rule per normal-path tool (`entwurf_v2`, `entwurf_peers`, `entwurf_self`) and nothing else; statusline owns its subtree; hooks own one named hook. | Installer broadens YOLO policy (`command(*)`, `unsandboxed(*)`), grants tools it does not need (`entwurf_inbox_read`, `entwurf_register_native`), or overwrites unrelated settings/hooks. |
234
238
  | Q-AGY-CONCURRENCY | Evidence boundary | Separate agy processes have separate pid/start-key markers; same-pid concurrent model invocation is explicitly reported unsupported. | Claims that one pid can safely identify two simultaneously invoking conversations. |
235
239
 
236
240
  The replyability formula is **record-backed identity AND live native-push probe**.
@@ -274,6 +278,41 @@ prompt, and if so quote the visible text exactly:
274
278
 
275
279
  # HISTORY (pointer)
276
280
 
281
+ 2026-07-30 Cortex 0.13.0 acceptance + landing checkpoint (Linux/thinkpad, Cortex Code
282
+ v1.1.52). Pre-version landing HEAD `9f1c7dc9e1fa77103e29a6f1884af7759e1595eb` passed
283
+ exact-SHA GitHub Actions run [30505001694](https://github.com/junghan0611/entwurf/actions/runs/30505001694):
284
+ `check`, `install-surface`, and `artifact-consumer` all success. The non-interference reading rests on what the
285
+ sources prove, not on an inspection of the runner image: the external Cortex CLI is not an npm
286
+ dependency, nothing in install or provider registration looks for the executable,
287
+ `.github/workflows/ci.yml` provisions only checkout, pnpm, and Node 24 (no Cortex install step,
288
+ no Snowflake auth), and the required Linux `artifact-consumer` job ran the candidate inside a
289
+ clean `node:24-bookworm` container and passed. Cells at that tree: `ENTWURF_REQUIRE_DOCKER=1 ./run.sh
290
+ check-install-container` EXIT=0 (40 ok) — candidate `junghanacs-entwurf-0.12.10.tgz`
291
+ **sha256=63342aa8a144011dee86ebea8f0b778c7860e54dc0f1c710438983c679e8af87**, image
292
+ `node:24-bookworm` `id=sha256:fcd0f74fb415c752…`,
293
+ `repoDigest=node@sha256:5711a0d445a1af54…`; `./run.sh check-pack-install` EXIT=0 with the
294
+ installed package's own model list enumerating the **exact six curated rows (claude 2 +
295
+ cortex 4)**; `LIVE=1 ./run.sh smoke-acp-cortex-live` **PASS 23/23**, deliberately rerun
296
+ after the `resolveSessionKey` overlay-scope repair so the claim does not rest on the earlier
297
+ CP2 code — overlay scope dir + `autoUpdate:false` + overlay-private `mcp.json` projection +
298
+ real-operator-HOME restore on the bridge entry, the model's own `entwurf_v2` landing exactly
299
+ one `.msg` on a seeded peer with the gid only in the envelope, and process-group teardown
300
+ leaving nothing alive in that run's overlay. `pnpm check` on the prepared tree includes
301
+ `check-gate-qualification` **111/111 killed** (lane `acp-cortex` twelve), and
302
+ `LIVE=1 ./run.sh release-gate /tmp/entwurf-release-gate-0.13.0.drnRyR` was all green —
303
+ **MUST PASS=17 FAIL=0 SKIP=0**, **BEHAVIOR PASS=1 FAIL=0**, EXIT=0. Operator-session (not
304
+ gate) evidence from 2026-07-29 on the same implementation set: a Cortex resident used the
305
+ host pi citizen's garden id instead of inventing one (`agentId=entwurf/cortex-claude-sonnet-5`,
306
+ `backend=pi`, `origin=pi-session`, `replyable=true`) and exchanged real turns across three
307
+ rails — native Claude Code mailbox drain, pi native control socket, and pi ACP Claude Sonnet
308
+ control socket; record `20260729T204101-7aaa6f` remains on disk. **Still pending as a
309
+ release-blocking `make` tag gate:** the preserved exact 0.13.0 candidate installed into a
310
+ fresh temporary root must drive one cold `entwurf/cortex-claude-sonnet-5` turn from those
311
+ installed bytes (unique nonce, exit 0, candidate sha256 unchanged before/after, resolved
312
+ installed root recorded). Installed-artifact evidence and real-Cortex evidence have not yet
313
+ met in one execution; a RED there stops the cut before the tag. Second machine, macOS, and
314
+ WSL2 remain unclaimed for this cut.
315
+
277
316
  2026-07-25 repair.1 installed-native host acceptance (stable-promotion prerequisite):
278
317
  the published registry artifact `@junghanacs/entwurf@0.12.8-repair.1` was installed
279
318
  fresh on two Linux hosts (maintainer + secondary) through the package's stable bins.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,41 @@ All notable changes to this project will be documented here. Format follows [Kee
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.13.0 — 2026-07-30
8
+
9
+ ### Added
10
+
11
+ - **Snowflake Cortex Code joins the ACP rail as the first non-claude backend** — the `cortexAdapter` contributed by hvkiefer (PR #40), landed together with the revisions the CP0 live audit of 2026-07-29 measured against Cortex Code v1.1.52 (`docs/acp-backend-rail.md` §11-8 records the ten defects D1–D10 and the agreed contract; the deltas are drift repair, not contributor error). As landed: the curated surface is the GLG-decided 4-row set (`cortex-auto`, `cortex-claude-opus-5`, `cortex-claude-sonnet-5`, `cortex-openai-gpt-5.4`) riding real pi-ai registry bases behind the reserved `cortex-` routing prefix; launch is `cortex acp serve` from PATH (+ `-c <connection>` via `entwurfProvider.cortexConnection` / `ENTWURF_ACP_CORTEX_CONNECTION`) with **no `-m` pin** — the model is enforced per turn through `session/set_config_option("model", <native id>)`, the same wire call as claude, so a curated id the running cortex no longer serves fails loud before the prompt. Containment is a **session-scoped dual-HOME overlay**: cortex's config/skill/hook surface is `homedir()`-anchored and `CORTEX_HOME` outranks `SNOWFLAKE_HOME`, so the adapter refuses an ambient `CORTEX_HOME` outright (empty string included), runs the child under an isolated HOME (global-scope leak measured to zero; explicit cwd project scope retained), passes through only the measured-minimum auth (`connections.toml`, optional `config.toml`, `cortex/cache/credential_cache` — symlink-through, never copied), authors `autoUpdate: false`, and — because cortex's ACP `newSession` ignores the wire `mcpServers` param — **projects** the envelope-enriched explicit `entwurfProvider.mcpServers` into the overlay-private `cortex/mcp.json`, restoring the real operator HOME on the `entwurf-bridge` entry alone so a cortex sibling sees the real garden (an isolated-HOME bridge measured an empty citizen roster); non-stdio entries fail loud before spawn. Cortex is system-prompt-carrier-less: the operator engraving rides the first-user augment. Coverage: the deterministic `check-acp-cortex` gate (in `pnpm check`) plus the `acp-cortex` mutant lane's twelve kill-qualified claims — ten on that gate, and two cross-gate: the production overlay call site passing `resolveSessionKey`'s authoritative value (`check-acp-session-reuse`) and the real compiled provider entry registering both adapters' curated rows (`check-acp-provider-surface`, so an entry that silently dropped every `cortex-` row can no longer go green) — and the on-demand CP2 live smoke `LIVE=1 ENTWURF_ACP_CORTEX_CONNECTION=<conn> ./run.sh smoke-acp-cortex-live` — a real cortex model turn delivering outbound `entwurf_v2` to a seeded peer as itself, plus overlay disk facts and process-group reclaim (an MCP-configured cortex child ignores stdin EOF) — deliberately outside the claude-only **aggregate** LIVE floor, so a host that runs no cortex cannot redden a claude release; that is a wiring decision, and a cut shipping cortex still owes a deliberate run of it.
12
+ - **A host that does not run Cortex is unaffected by this release.** The external `cortex` CLI is not an npm dependency, and neither package install nor provider registration looks for the executable: the four curated rows are enumerated deterministically from the compiled provider entry, and `cortex acp serve` is spawned only when a turn actually selects a `cortex-` model — so selecting one on a host without Cortex fails loud at that turn rather than degrading install or the rest of the provider. The deterministic `check-acp-cortex` gate runs on fake/injected seams and needs neither the CLI nor Snowflake auth; the aggregate release floor contains no Cortex LIVE step; and the dedicated smoke honest-skips without `LIVE=1`, without `cortex` on `PATH`, or without a connection on the adapter seam. Rows are deliberately **not** hidden by PATH detection — that would make the provider surface differ per host and dissolve the exact-six-row fence — so an explicit operator enable/disable control remains a separate future contract, not a silent behaviour of this cut.
13
+ - **The ACP ordering probe lands as a gated instrument, and the readiness question it exists to answer stays open.** The rail's open question — whether MCP tool availability precedes what `newSession` returns — had no observable signal, so the probe injects a controlled fixture startup delay and reads control + D1 + D2 paired runs off one shared NDJSON axis instead of reconstructing order from separate logs with drifting clocks. A raw client may stand in for the backend only while a gate holds it to the same calls, arguments, and order, so `check-probe-ordering` pins the sequence against `backend.ts` source, attributes every failure to its wire phase, drives the probe-mode fixture as a real child process, types the event log at its door, and replays the paired-verdict truth table through the pure classifier. The log's door is a gate too: the envelope belongs to the writer, `ts` derives from a single clock read, and per `(runId, pid)` writer the raw append order must have strictly increasing `seq` and a non-regressing clock — a JSON-valid line with an unknown marker, a broken sort axis, or a payload the classifier cannot judge takes the INVALIDATED path instead of moving a verdict. The runner now holds the child open past the turn until the marker lands, the child exits, or a deadline anchored on the fixture's own delay markers passes, and only a deadline close lets a missing marker read as evidence; every intervention reports ordering and callability as two axes so a settled comparison is not buried by an unsettled verdict, and each ordering value is named for the comparison it is (`prompt-request-ahead-of-wire` says we issued the request first, never that the server failed to wait). The delta-B name oracle cannot be the model, so that seam is a CLI shim at `CLAUDE_CODE_EXECUTABLE`: the consumer half (target preconditions by key presence, absolute/regular/executable/no-script-suffix assertions, path+sha256 roster pinning with a post-pair re-hash, snapshot channel doors, receive-axis single-prompt binding, structural-vs-reading severity split) and then the producer shim itself both land kill-qualified. **No readiness finding is claimed.** The first paired run under the door contract produced 57 events with zero malformed lines, so the parser is calibrated rather than merely strict, and rail §11-7-b carries the numbers — but the verdict is inconclusive, and an inconclusive verdict is not "nothing wrong". Artifacts predating the window protocol re-parse as INVALIDATED and remain forensic records only.
14
+
15
+ ### Verification
16
+
17
+ - Pre-version landing HEAD `9f1c7dc9e1fa77103e29a6f1884af7759e1595eb` passed exact-SHA GitHub Actions run [30505001694](https://github.com/junghan0611/entwurf/actions/runs/30505001694): `check`, `install-surface`, and `artifact-consumer` all success. That run is also the third-party half of the optionality claim above, at the strength its sources actually carry: `.github/workflows/ci.yml` provisions only checkout, pnpm, and Node 24 — it installs no Cortex CLI and supplies no Snowflake auth — and the required Linux `artifact-consumer` job ran the candidate inside a clean `node:24-bookworm` container and passed. That is a workflow-configuration fact plus a passing consumer run; it is not a probe of the runner image's contents.
18
+ - The prepared tree passed an independent `pnpm check`, including `check-gate-qualification` at **111/111 committed mutants killed** (the `acp-cortex` lane contributing twelve). Then `LIVE=1 ./run.sh release-gate /tmp/entwurf-release-gate-0.13.0.drnRyR` completed all green: **MUST PASS=17 FAIL=0 SKIP=0** and **BEHAVIOR PASS=1 FAIL=0**, EXIT=0. Full log: `/tmp/entwurf-release-gate-0.13.0.drnRyR/release-gate.log`; per-step artifacts are preserved inside it.
19
+ - Cortex acceptance on the landing tree (2026-07-30, Linux/thinkpad, Cortex Code v1.1.52, connection on the adapter seam): the on-demand `smoke-acp-cortex-live` passed **23/23** — a deliberate rerun *after* the `resolveSessionKey` overlay-scope repair, so the shipped claim no longer rests on the earlier CP2 run's code. `check-pack-install` enumerated the **exact six curated rows (claude 2 + cortex 4)** out of the installed package's own model list, and `ENTWURF_REQUIRE_DOCKER=1 ./run.sh check-install-container` consumed candidate `sha256=63342aa8a144011dee86ebea8f0b778c7860e54dc0f1c710438983c679e8af87` on `node:24-bookworm` (`id=sha256:fcd0f74fb415c752…`, `repoDigest=node@sha256:5711a0d445a1af54…`).
20
+ - Cross-rail live round trips are **operator-session evidence, not a gate** (2026-07-29, same implementation set): a Cortex resident used the host pi citizen's garden id rather than inventing one — `agentId=entwurf/cortex-claude-sonnet-5`, `backend=pi`, reply envelope `origin=pi-session`, `replyable=true` — and exchanged real turns with native Claude Code (mailbox drain), pi native (control socket), and pi ACP Claude Sonnet (control socket). The record `20260729T204101-7aaa6f` remains on disk as corroboration.
21
+ - **Deferred to `make` as a release-blocking tag gate:** the preserved exact 0.13.0 candidate must be installed into a fresh temporary root and drive one cold `entwurf/cortex-claude-sonnet-5` turn from *those installed bytes* — unique nonce, exit 0, candidate SHA-256 unchanged before and after, resolved installed package root recorded. Until it runs, installed-artifact evidence and real-Cortex evidence have never met in one execution; a RED there stops the cut before the tag. Prepared-HEAD exact-SHA CI and preserved-candidate container acceptance remain deferred to `make` as usual.
22
+
23
+ ## 0.12.10 — 2026-07-27
24
+
25
+ ### Changed
26
+
27
+ - **The Claude ACP dependency rail moves to `@agentclientprotocol/claude-agent-acp` 0.62.0.** The paired SDK surface fence now covers Claude Agent SDK 0.3.219; this is a dependency refresh, not a claim that MCP readiness timing changed.
28
+ - **The ACP rail document now names its unresolved readiness question precisely.** The ordered probe records wire availability, `newSession`, model enforcement, and prompt boundaries before any adapter remedy or Cortex work is considered.
29
+ - **Gate qualification is part of the deterministic floor.** Committed defect mutants run in an isolated snapshot and must fail their named `[QK:<claim>]` oracle; the agy permission contract is likewise covered by an independent literal matrix.
30
+
31
+ ### Fixed
32
+
33
+ - **All citizen rails now share the same record authority without inventing pi privilege.** Control-socket, self-fetch, and native-push capability differences remain explicit while stale pi-special address and transport prose is removed.
34
+ - **The shipped pi and MCP tool descriptions tell the complete v2 dispatch truth.** Native-push direct injection, its three-valued probe rejects, mailbox deliverability, control-socket lock scope, and spawn-bg's separate relaunch transport are described and regression-fenced on both surfaces.
35
+ - **Native-push self-awareness and agy permissions follow their actual rail.** Native-push never advertises an inbox; normal-path agy approval covers `entwurf_v2`, `entwurf_peers`, and `entwurf_self` with per-rule ownership, strict state migration, and separate runtime/ownership doctor verdicts.
36
+
37
+ ### Verification
38
+
39
+ - Pre-version landing HEAD `9a501b30f0e7d82307d885f1a1eb9d91c79c5f16` passed exact-SHA GitHub Actions run [30252596435](https://github.com/junghan0611/entwurf/actions/runs/30252596435): `check`, `install-surface`, and `artifact-consumer` all success.
40
+ - The prepared tree passed `pnpm check`; `LIVE=1 ./run.sh release-gate /tmp/entwurf-release-gate-0.12.10.d4gC9v` completed all green: **MUST PASS=17 FAIL=0 SKIP=0** and **BEHAVIOR PASS=1 FAIL=0**, EXIT=0. Full log: `/tmp/entwurf-release-gate-0.12.10.d4gC9v/release-gate.log`; per-step artifacts are preserved in that log. Prepared-HEAD exact-SHA CI and preserved-candidate acceptance remain deliberately deferred to `make`.
41
+
7
42
  ## 0.12.9 — 2026-07-26
8
43
 
9
44
  ### Changed
package/CONTRIBUTING.md CHANGED
@@ -4,7 +4,9 @@ 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 + a **Claude-first ACP plugin** — 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* — what tools, MCP, skills, and permissions are visible — to match pi's own policy. Claude is the shipped ACP backend, 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) §6/§11-8); Codex is a native garden citizen, and the Gemini path is deprecated. That is the entire scope.
8
+
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.
8
10
 
9
11
  If a change moves the bridge toward "second harness" — prompt reconstruction, transcript hydration, ambient discovery, silent fallback — it does not belong here.
10
12
 
@@ -16,7 +18,7 @@ These are enforced by code, gates, and review. Do not weaken them in a PR; if yo
16
18
  2. **Session persistence**: only `pi:<sessionId>` is persisted. `cwd:<cwd>` is never persisted.
17
19
  3. **MCP injection**: only via `entwurfProvider.mcpServers`. No ambient `~/.mcp.json` scanning, no `~/.claude/settings.json` MCP inheritance.
18
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`.
19
- 5. **Backend-specific knobs stay explicit and namespaced**: Codex/Gemini-era ACP knobs are not part of the current Claude-first shipped path. If a future backend lane reintroduces a sandbox or mode knob, it must use the `ENTWURF_ACP_*` namespace and invalid values must throw, never fall back.
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.
20
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.
21
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.
22
24
  8. **This bridge is not a second harness**: no prompt reconstruction, no transcript hydration, no tool result ledger, no Claude Code emulation.
package/DELIVERY.md CHANGED
@@ -115,7 +115,7 @@ the `D0–D8` capability level:
115
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
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
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 (candidate)** | deferred | — | ACP (via entwurf's pi adapter) | Shipped as an ACP *runtime* lane (you can run Claude through ACPsee VERIFY/README), but **not a native-async-*delivery* target**: 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." Cortex is the candidate that would land on the ACP path next. |
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
119
 
120
120
  ## Backend notes
121
121
 
@@ -213,11 +213,12 @@ three markers) but **not** simultaneous model invocation by two conversations
213
213
  under one agy pid: one marker file would be last-writer-wins, so that concurrency
214
214
  is explicitly unsupported.
215
215
 
216
- Current deterministic floor: `smoke-agy-install-state` 140 checks,
216
+ Current deterministic floor: `smoke-agy-install-state` 167 checks,
217
217
  `smoke-agy-statusline-state` 69, `smoke-agy-hooks-state` 44,
218
218
  `check-agy-sender-identity` 28, plus the shared self-address/native-push gates.
219
- The bridge installer owns only `mcp(entwurf-bridge/entwurf_v2)` in
220
- `permissions.allow`; broad YOLO policy stays operator-owned. Live 2026-07-13
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
221
222
  (agy 1.0.x): automatic birth → gid/statusline → record-backed sender → sibling
222
223
  delivery → same-gid native-push reply passed. Live 2026-07-14 (**agy 1.1.0**):
223
224
  re-verified on the new minor — `entwurf_self` answered without a permission
package/README.md CHANGED
@@ -10,7 +10,7 @@ npm package: <https://www.npmjs.com/package/@junghanacs/entwurf>
10
10
 
11
11
  Legacy package: [`@junghanacs/pi-shell-acp`](https://www.npmjs.com/package/@junghanacs/pi-shell-acp). `entwurf` is its 0.12+ successor line: the same work renamed around the garden-citizen dispatch substrate rather than the pi adapter.
12
12
 
13
- > **Repository shape.** This repo is **entwurf-core (v2 dispatch) + native-harness bridges + a pi adapter + an ACP plugin**. Pi is one supported harness adapter — important because it supplies control sockets and hosts the ACP plugin today — but it is not the project subject. Claude Code is shipped as a mailbox-backed meta-session; Antigravity (`agy`) is shipped as a native-push citizen with automatic `PreInvocation` birth, ambient garden-id status, and a managed MCP/permission install surface. Codex has a launch-mode-specific verified delivery probe documented in [DELIVERY.md](./DELIVERY.md), but no managed native-citizen install lane yet. The ACP plugin is Claude-first; Cortex/vendor-governed ACP backends are future lanes.
13
+ > **Repository shape.** This repo is **entwurf-core (v2 dispatch) + native-harness bridges + a pi adapter + an ACP plugin**. Pi is one supported harness adapter — important because it supplies control sockets and hosts the ACP plugin today — but it is not the project subject. Claude Code is shipped as a mailbox-backed meta-session; Antigravity (`agy`) is shipped as a native-push citizen with automatic `PreInvocation` birth, ambient garden-id status, and a managed MCP/permission install surface. Codex has a launch-mode-specific verified delivery probe documented in [DELIVERY.md](./DELIVERY.md), but no managed native-citizen install lane yet. The ACP plugin ships two backends through one adapter rail: Claude (the reference) and Snowflake Cortex Code (landed in 0.13.0 under a session-scoped dual-HOME containment [docs/acp-backend-rail.md](./docs/acp-backend-rail.md) §11-8).
14
14
 
15
15
  <details>
16
16
  <summary>Watch archived pre-0.12 demo (2131×1142 GIF, click to expand)</summary>
@@ -28,7 +28,7 @@ Claude Code / Codex / agy / pi
28
28
  → control-socket | spawn-bg resume | meta-mailbox | native-push
29
29
  ```
30
30
 
31
- [`entwurf_v2`](#entwurf_v2--canonical-dispatch-verb) is the canonical dispatch surface over *existing* garden citizens — live control-socket send, spawn-bg resume, meta-mailbox enqueue, and native-push into a live Antigravity conversation. The meta-record is the sole address authority (#50 C4): a record-less control socket is refused as a `record-less-socket` diagnostic, never dispatched. The v1 entwurf verbs are gone. Fresh sibling minting and non-Claude ACP backends are deferred lanes.
31
+ [`entwurf_v2`](#entwurf_v2--canonical-dispatch-verb) is the canonical dispatch surface over *existing* garden citizens — live control-socket send, spawn-bg resume, meta-mailbox enqueue, and native-push into a live Antigravity conversation. The meta-record is the sole address authority (#50 C4): a record-less control socket is refused as a `record-less-socket` diagnostic, never dispatched. The v1 entwurf verbs are gone. Fresh sibling minting is still a deferred lane; the non-Claude ACP lane is not — Snowflake Cortex Code landed as the second backend in 0.13.0.
32
32
 
33
33
  **Garden id is deliberate vocabulary.** It is not a decorative synonym for session id, worker, delegate, or subagent. The unfamiliar word is a guard: each harness keeps its own identity and transcript, while `entwurf` supplies a narrow addressable surface between siblings.
34
34
 
@@ -462,13 +462,26 @@ plain MCP registrations.
462
462
 
463
463
  ### Backend prerequisites
464
464
 
465
- The ACP plugin is **Claude-first**. The Claude ACP server package (`@agentclientprotocol/claude-agent-acp`, pinned with `@agentclientprotocol/sdk`) ships as a pinned `dependency` of `entwurf`; backend authentication still belongs to the operator's local `claude` CLI / runtime. Once the bridge is installed, the resolver picks the ACP server in this order:
465
+ **Claude is the reference ACP backend.** The Claude ACP server package (`@agentclientprotocol/claude-agent-acp`, pinned with `@agentclientprotocol/sdk`) ships as a pinned `dependency` of `entwurf`; backend authentication still belongs to the operator's local `claude` CLI / runtime. Once the bridge is installed, the resolver picks the ACP server in this order:
466
466
 
467
467
  1. **`CLAUDE_AGENT_ACP_COMMAND` env override** — explicit override for an alternative binary or a wrapper command.
468
468
  2. **`require.resolve(...)` against the bundled package dependency** (`@agentclientprotocol/claude-agent-acp`). This is the default path; no extra global install needed.
469
469
  3. **`PATH:claude-agent-acp` fallback** — used when the package resolution fails (e.g. a hand-edited `node_modules`).
470
470
 
471
- The curated model registry exposes Claude models only, so the ACP backend is Claude. Codex is *not* an ACP backend here — a native Codex session is already a first-class garden citizen via direct injection, so it needs no ACP plugin (see [AGENTS.md](./AGENTS.md)). Vendor / governed CLIs (e.g. Cortex) are a later ACP backend lane.
471
+ The curated model registry exposes the unprefixed Claude ids plus the `cortex-` prefixed Cortex rows (below). Codex is *not* an ACP backend here — a native Codex session is already a first-class garden citizen via direct injection, so it needs no ACP plugin (see [AGENTS.md](./AGENTS.md)).
472
+
473
+ **Snowflake Cortex Code is the second landed ACP backend** (0.13.0; audit record and contract: [docs/acp-backend-rail.md](./docs/acp-backend-rail.md) §11-8). Operator surface:
474
+
475
+ - **Curated ids (4):** `cortex-auto`, `cortex-claude-opus-5`, `cortex-claude-sonnet-5`, `cortex-openai-gpt-5.4`. The `cortex-` prefix routes; the model is enforced per turn via ACP set-model, so an id the running cortex no longer serves fails loud before the prompt.
476
+ - **CLI + auth:** `cortex` must be on PATH and already authenticated through Cortex's **own web-login flow** (there is no `cortex auth` subcommand; entwurf never supplies or proxies the Snowflake credential — the overlay reaches it by **symlinking through** exactly `connections.toml`, optional `config.toml`, and `cortex/cache/credential_cache`, and nothing else. The narrowing is *which paths are reachable* (§11-8 D5), not a read-only mount: a symlink carries no write protection, so the child holds the same access to those three paths that it would have with the operator's own HOME. What the overlay removes is the rest of the operator's **home** surface — the rest of `cortex/cache`, `~/.claude`/`~/.cortex` skills, home-anchored hooks and settings, and the operator's `cortex/mcp.json`. It does **not** reach cortex's *bundled* plugin/hook surface, which fires from the CLI's own install directory and is outside any HOME the overlay controls — that stays a host fact, not a containment claim (§11-8 D1).)
477
+ - **Connection:** pin a Snowflake connection with `entwurfProvider.cortexConnection` in settings or per-shell via `ENTWURF_ACP_CORTEX_CONNECTION` (env wins). `entwurfProvider.backend: "cortex"` is an optional diagnostic guard, never the router.
478
+ - **`CORTEX_HOME` must be unset.** It outranks `SNOWFLAKE_HOME` inside cortex and would bypass the dual-HOME containment, so the adapter refuses the spawn when it is present at all (empty string included).
479
+ - **Containment:** each session runs under an isolated HOME (operator-global `~/.claude`/`~/.cortex` skills, hooks and settings are structurally unreachable; explicit `<cwd>/.claude` project scope is retained), with the explicit `entwurfProvider.mcpServers` projected into an overlay-private `cortex/mcp.json` — cortex's ACP server ignores the wire `mcpServers` parameter, so this projection is how tools reach a cortex session. Only the `entwurf-bridge` entry gets the real operator HOME back (the garden store axis).
480
+ - **Live check:** `LIVE=1 ENTWURF_ACP_CORTEX_CONNECTION=<conn> entwurf smoke-acp-cortex-live` (or `./run.sh …` from a clone) drives one real cortex turn: outbound `entwurf_v2` delivery as `entwurf/<cortex model>`, overlay disk facts, and process-group reclaim. It is deliberately **on-demand** — which is a statement about *wiring*, not about *whether cortex needs live evidence*:
481
+
482
+ - The aggregate floor (`LIVE=1 ./run.sh release-gate`) stays claude-only, so a host with no cortex install or no Snowflake auth cannot redden a release for a backend it does not run.
483
+ - That is **not** a claim that cortex ships on deterministic evidence alone. Accepting a cut that ships cortex means running this smoke deliberately, and reading its result — the aggregate gate will not run it for you, and its silence is not a pass.
484
+ - Cortex's always-on axis is the deterministic `check-acp-cortex`, which does ride `pnpm check`.
472
485
 
473
486
  ### Emacs frontends
474
487
 
@@ -523,6 +536,8 @@ Reference shape lives in [`pi/settings.reference.json`](./pi/settings.reference.
523
536
 
524
537
  `appendSystemPrompt: false` is intentional. Pi / AGENTS context rides the first-user augment; putting it into the Claude `_meta.systemPrompt` carrier can route OAuth sessions to metered "extra usage" billing.
525
538
 
539
+ **Which keys reach which backend.** `entwurfProvider` is one block for both backends, but its keys are not universal. `tools` / `permissionAllow` / `disallowedTools` / `settingSources` / `skillPlugins` / `appendSystemPrompt` are Claude's declaration surface: they do not shape a cortex session, which runs its own native tools and reaches MCP through the overlay-private `mcp.json` projection instead. They are not inert, though — the bridge still reads `tools` for its backend-invariant exclude-tools preflight and folds all of them into the config signature, so editing one still forces a fresh cortex session. `cortexConnection` is cortex-only. `mcpServers` is the one declaration surface that reaches both, each through its own transport. (`compaction` is a *top-level* pi key, not an `entwurfProvider` one — it is pi's own transcript policy and is not a backend knob at all; see §Compaction.) Unknown and retired keys are ignored rather than rejected, so a key aimed at the wrong backend fails silently: if a cortex session does not show the surface you configured, check that the key is one cortex actually consumes before suspecting the bridge.
540
+
526
541
  ### Wiring `entwurf-bridge` into an external MCP host
527
542
 
528
543
  `entwurf-bridge` can also be registered in a separate MCP-aware harness (Claude Code, Codex CLI, Antigravity/`agy`, …). That host does **not** become a pi session and does **not** need to be ACP-backed. There are now two honest cases:
@@ -532,12 +547,12 @@ Reference shape lives in [`pi/settings.reference.json`](./pi/settings.reference.
532
547
 
533
548
  **Which verb an external agent should reach for:** to deliver to / reply to a garden id, use **`entwurf_v2`** — it is the canonical delivery surface and the only one that reads whether the target is live pi, dormant pi, mailbox-backed Claude Code, or native-push Antigravity and routes correctly. Discover targets with `entwurf_peers`, confirm your own identity with `entwurf_self`, drain a mailbox with `entwurf_inbox_read`, and use `entwurf_register_native` only as the explicit/manual fallback for binding an already-running agy conversation (normal agy birth is automatic through the installed hook). Fresh sibling creation from nothing is a deferred lane. (The old v1 verbs `entwurf` / `entwurf_resume` / `entwurf_send` are gone.)
534
549
 
535
- Observed: Claude Code, Codex CLI, and Antigravity CLI all reach the fact surfaces (`entwurf_peers`, inbox) through this MCP bridge from a plain external host; **sending** needs an identity lane. Claude becomes symmetric/replyable through its mailbox-backed meta-session; agy becomes symmetric/replyable through its record-backed sender marker plus live native-push probe. Codex has no managed citizen lifecycle yet, so a Codex host cannot send without the explicit anonymous hatch below.
550
+ Observed: Claude Code, Codex CLI, and Antigravity CLI all reach the read surfaces through this MCP bridge from a plain external host — `entwurf_peers` is a pure fact projection, while `entwurf_inbox_read` is a **mutating drain** (it archives the messages and stamps the read-receipt), so "read" here does not mean side-effect-free; **sending** needs an identity lane. Claude becomes symmetric/replyable through its mailbox-backed meta-session; agy becomes symmetric/replyable through its record-backed sender marker plus live native-push probe. Codex has no managed citizen lifecycle yet, so a Codex host cannot send without the explicit anonymous hatch below.
536
551
 
537
552
  Prerequisites on the host running the external MCP client:
538
553
 
539
554
  - `pi` on PATH (for the `owned-outcome` spawn-bg resume path).
540
- - A live pi session launched with `--entwurf-control` populates `~/.pi/entwurf-control/<sessionId>.sock`; required for `entwurf_v2` control-socket dispatch and `entwurf_peers`.
555
+ - A live pi session launched with `--entwurf-control` populates `~/.pi/entwurf-control/<gardenId>.sock` the key is the **record's** garden id, never a transcript/session id (`PI_SESSION_ID` only carries the id record birth already established). Required for `entwurf_v2` control-socket dispatch and `entwurf_peers`.
541
556
 
542
557
  > **PATH boundary.** MCP servers are often launched by GUI/editor daemons and may not inherit the interactive shell's PATH. If `pi` works in your terminal but an external-host `entwurf_v2` spawn-bg resume fails with `spawn pi ENOENT`, pass a full PATH in the MCP server `env`, set `ENTWURF_BRIDGE_ENV_FILE` to a small shell file that exports PATH, or point the host at a wrapper that can find `pi`. `start.sh` sources only the explicit `ENTWURF_BRIDGE_ENV_FILE`; it never reads personal dotfiles automatically.
543
558
 
@@ -566,7 +581,7 @@ Emergency/manual workaround when the MCP server environment is wrong but an exis
566
581
  External/meta-session semantics:
567
582
 
568
583
  - `entwurf_v2` from a plain external host is **refused by default** (no authoritative sender — #50 C4). With the explicit `ENTWURF_BRIDGE_ALLOW_ANONYMOUS_SENDER=1` hatch it delivers with `origin: "external-mcp"` / `replyable: false`; there is still no reply address.
569
- - `entwurf_v2` from a trusted meta-session delivers with `origin: "meta-session"` / `replyable: true`; `wants_reply: true` is allowed and the receiver can reply to the sender's garden id.
584
+ - `entwurf_v2` from a trusted meta-session delivers with `origin: "meta-session"`, and `replyable` is **derived from that sender's own rail — not granted by being trusted**: a self-fetch sender (Claude Code) is replyable only while its receiver is live and armed, and a native-push sender (Antigravity) only while its adapter probe finds the live conversation. Identity survives either way; only `replyable` drops to `false`. When it is `true`, `wants_reply: true` is allowed and the receiver can reply to the sender's garden id.
570
585
  - `entwurf_v2` with `intent: "owned-outcome"` to a dormant pi target needs `pi` on PATH (it spawns a `pi --entwurf-control` resume child); async completion followUp requires a replyable pi control-socket caller.
571
586
  - `entwurf_self` returns the same authoritative identity for pi sessions **and** trusted meta-sessions. A plain external host with no pi env and no trusted sender marker still fails because there is no reply address to report.
572
587
 
@@ -631,7 +646,7 @@ entwurf doctor-agy-hooks
631
646
 
632
647
  The three adapters deliberately own different atoms:
633
648
 
634
- - bridge: one `entwurf-bridge` server in `~/.gemini/config/mcp_config.json`, plus exactly one permission string — `mcp(entwurf-bridge/entwurf_v2)` — in `~/.gemini/antigravity-cli/settings.json`;
649
+ - bridge: one `entwurf-bridge` server in `~/.gemini/config/mcp_config.json`, plus one narrow permission string per tool the normal agy workflow calls — `mcp(entwurf-bridge/entwurf_v2)`, `mcp(entwurf-bridge/entwurf_peers)`, `mcp(entwurf-bridge/entwurf_self)` — in `~/.gemini/antigravity-cli/settings.json`. agy defaults every `mcp` action to Ask, so a tool that ships without its own rule stops for a y/n on every call; `entwurf_inbox_read` is deliberately not granted (native-push has no inbox) and neither is the manual `entwurf_register_native` fallback;
635
650
  - statusline: the complete `statusLine` subtree pointing at the bare stable bin `entwurf-agy-statusline`;
636
651
  - hooks: one named `PreInvocation` hook pointing at the bare stable bin `entwurf-agy-imprint`.
637
652
 
@@ -651,21 +666,26 @@ The Claude ACP backend keeps its native model / API / tools; entwurf shapes only
651
666
 
652
667
  **Claude** uses `_meta.systemPrompt` for the engraving carrier (kept short and pure — billing-safe; rich operator context rides the first user message instead, see [Context carriers](#context-carriers)) and `CLAUDE_CONFIG_DIR` for a whitelist overlay so auth/runtime entries stay available while operator memory, hooks, agents, history, local settings, and project memory remain hidden. The overlay writes an explicit empty `hooks: {}` because Claude SDK organic compaction needs the configured-empty shape; no operator hook definitions are inherited. The four-tool baseline (`Read`, `Bash`, `Edit`, `Write`) is enforced through `tools` + `permissionAllow`; `Skill` is added automatically when `skillPlugins` is non-empty. Operator context cap override: `ENTWURF_ACP_CLAUDE_CONTEXT=<int>`.
653
668
 
654
- (Codex is *not* an ACP backend here — it reaches the garden natively. Vendor / governed CLIs are a later ACP backend lane.)
669
+ (Codex is *not* an ACP backend here — it reaches the garden natively. The governed-CLI lane is open, not later: Snowflake Cortex Code landed on it in 0.13.0, and a third governed backend would join the same adapter rail.)
655
670
 
656
671
  Antigravity is also not an ACP backend. It is a native-push citizen: `PreInvocation` supplies birth/sender identity, `entwurf_v2` probes and direct-injects replies into the live conversation, and no mailbox/receiver marker is involved.
657
672
 
658
- Pi is the canonical memory authority (semantic-memory + Denote llmlog); Claude's native memory layer is pinned off.
673
+ entwurf owns **no** memory layer at all — the ACP plugin's boundary explicitly excludes a memory DB (see `AGENTS.md` §ACP Plugin Boundary), and no backend is a memory authority for another. What this overlay does is narrower: Claude's native memory layer is pinned off so operator memory, project state, and history never leak into an ACP session. Whatever semantic-memory / Denote tooling an operator runs is their own skill surface on whichever harness hosts it — deliberately kept out of the MCP bridge, and not a pi privilege.
659
674
 
660
675
  ## Smoke commands
661
676
 
662
677
  ```bash
663
678
  pnpm check # full deterministic floor (all check-* gates, incl. check-acp-*)
664
679
  ./run.sh check-bridge # entwurf-bridge direct MCP smoke (no backend auth)
665
- ./run.sh smoke-agy-install-state # agy MCP + exact permission ownership (120 checks)
666
- ./run.sh smoke-agy-statusline-state # agy ambient garden-id install surface (62 checks)
667
- ./run.sh smoke-agy-hooks-state # agy PreInvocation birth hook (37 checks)
668
- ./run.sh check-agy-sender-identity # record-backed pid/start-key sender identity (28 checks)
680
+ ./run.sh smoke-agy-install-state # agy MCP + exact permission ownership lifecycle (install/uninstall/doctor/inverse)
681
+ ./run.sh smoke-agy-statusline-state # agy ambient garden-id install surface
682
+ ./run.sh smoke-agy-hooks-state # agy PreInvocation birth hook
683
+ ./run.sh check-agy-sender-identity # record-backed pid/start-key sender identity
684
+
685
+ # source-maintainer only — qualification snapshots the git work surface, and both
686
+ # commands are source-contract gates rather than installed operator checks:
687
+ ./run.sh check-agy-permission-matrix # AGY permission contract space as a literal table (declared cells + stated exclusions)
688
+ ./run.sh check-gate-qualification # kill-proof: committed defect mutants must turn their gates red for the claimed reason
669
689
 
670
690
  # agy LIVE acceptance — requires an already-running conversation:
671
691
  LIVE=1 AGY_CONVERSATION_ID=<id> ./run.sh smoke-agy-native-push-live
@@ -681,6 +701,14 @@ LIVE=1 ./run.sh smoke-acp-carrier-augment-live # augment delivery + empty-carri
681
701
  LIVE=1 ./run.sh release-gate /tmp/scratch # the single cut gate (MUST + BEHAVIOR, SKIP=0 for a real cut)
682
702
  ```
683
703
 
704
+ `pnpm check` already includes the two maintainer gates: the AGY permission contract
705
+ matrix and the full committed-mutant gate qualification run on every pass. A gate a
706
+ release touches must kill its known defect for the claimed `[QK:<claim>]` reason —
707
+ the descriptions above name what each smoke covers, and no check count is quality
708
+ evidence on its own. Gate qualification needs the git work surface, while the matrix
709
+ is the source permission-contract gate; both run from a clone, never as a post-install
710
+ operator step.
711
+
684
712
  ## Custom skills
685
713
 
686
714
  Claude sessions accept custom skills through `skillPlugins` — an array of absolute paths to directories matching the Claude Agent SDK plugin layout:
@@ -716,7 +744,7 @@ For a real consumer arranging many skills, see [agent-config](https://github.com
716
744
 
717
745
  **Entwurf is one dispatch capability with native-pi and MCP surfaces.** Native pi exposes it directly as extension tools; ACP-backed and external native-harness sessions reach it through `entwurf-bridge`. The purpose is not to invent a different sub-agent system, but to preserve the same sibling-based model across harnesses.
718
746
 
719
- A sibling has its own runtime boundary and its own provider/model identity — not a worker, delegate, or sub-agent. Minting a brand-new sibling from nothing is a deferred v2 lane (`spawn-fresh`); today every transport targets an *existing* garden citizen. `entwurf_v2` routes from rail-specific liveness + intent: live pi fire-and-forget → control socket; dormant pi owned-outcome → spawn-bg resume; active self-fetch → meta-mailbox; probe-alive agy → native-push. Pi paths use the per-target lock; mailbox/native-push use their own deliverability evidence and remain lock-free.
747
+ A sibling has its own runtime boundary and its own provider/model identity — not a worker, delegate, or sub-agent. Minting a brand-new sibling from nothing is a deferred v2 lane (`spawn-fresh`); today every transport targets an *existing* garden citizen. `entwurf_v2` routes from rail-specific liveness + intent: live pi fire-and-forget → control socket; dormant pi owned-outcome → spawn-bg resume; active self-fetch → meta-mailbox; probe-alive agy → native-push. A **control-socket-domain** dispatch takes the per-target lock — both the live send and the dormant cell's spawn-bg resume; mailbox and native-push use their own deliverability evidence and remain lock-free.
720
748
 
721
749
  A two-pane recording covers the surface end-to-end — sibling resume, cross-process MCP dispatch across a different cwd, and a live peer greeting:
722
750
 
@@ -727,13 +755,13 @@ A two-pane recording covers the surface end-to-end — sibling resume, cross-pro
727
755
 
728
756
  </details>
729
757
 
730
- Live peer messaging carries a sender envelope `{ sessionId, agentId, cwd, timestamp }`; `entwurf_self` returns that authoritative envelope for the current pi session or trusted meta-session. Plain external MCP hosts are non-replyable; garden-native meta-sessions carry a trusted `meta-session` envelope and are replyable by garden id. `wants_reply` is an etiquette marker rendered as a `(wants reply)` badge — not a transport contract, no wait, no polling and is rejected only from non-replyable external senders.
758
+ Live peer messaging carries a sender envelope `{ sessionId, agentId, cwd, timestamp, origin?, replyable? }`; `entwurf_self` returns that authoritative envelope for the current pi session or trusted meta-session. Plain external MCP hosts are non-replyable. A garden-native meta-session carries a trusted `meta-session` envelope, but **`replyable` is a fact its own rail decides, not a consequence of being trusted** — a self-fetch citizen needs a live armed receiver, a native-push citizen needs an alive adapter probe, and a pi session needs its control socket. `entwurf_self` also reports which rail a meta-session reply would ride, because a native-push citizen has no mailbox to name. `wants_reply` is an etiquette marker rendered as a `(wants reply)` badge — not a transport contract, no wait, no polling. **v2 never gates on it:** a `wants_reply` from an external/non-replyable caller is passed through and surfaced honestly beside that sender's `replyable: false`, not rejected — the decider routes on target + intent, never on sender replyability. (The retired v1 `entwurf_send` did reject it; that behaviour went with the verb.)
731
759
 
732
760
  In ACP-backed and external native-harness sessions, `entwurf-bridge` exposes five tools: `entwurf_v2`, `entwurf_peers`, `entwurf_self`, `entwurf_inbox_read`, and the explicit/manual `entwurf_register_native` fallback. Native pi exposes the shared capability directly through the extension surface (`entwurf_v2`, `entwurf_peers` tools; the socket-scan `/entwurf-sessions` command is gone — #50 C4). **For garden-id delivery/reply use `entwurf_v2`** — the canonical surface that classifies the target and routes to live-pi / dormant-resume / Claude-Code-meta-mailbox / Antigravity-native-push. Fresh sibling creation from nothing is a deferred lane. (The v1 verbs `entwurf` / `entwurf_resume` / `entwurf_send` are gone.) Garden-native operator commands require `--entwurf-control`. There is no spawn target allowlist — the target registry is gone (#50 C3): `entwurf_v2` resumes an already-identified record-backed citizen, never a model tuple from a file.
733
761
 
734
762
  ### `entwurf_v2` — canonical dispatch verb
735
763
 
736
- `entwurf_v2` / `runEntwurfV2` is the canonical v2 dispatch verb over **existing** garden targets — record-backed citizens only (#50 C4: the record is the sole address authority; a record-less control socket rejects pre-probe as `record-less-socket`, a diagnostic state, never a delivery target). You give a target garden id plus an intent (`fire-and-forget` or `owned-outcome`); one decider reads the target's liveness as a fact and picks the transport from a frozen table keyed on **both** the target's state **and** the intent — never on state alone — then reports one outcome under the v2 lock policy. Pi control-socket and spawn-bg paths take a per-target lock; mailbox and native-push are lock-free, with deliverability guarded by their own receiver/probe evidence:
764
+ `entwurf_v2` / `runEntwurfV2` is the canonical v2 dispatch verb over **existing** garden targets — record-backed citizens only (#50 C4: the record is the sole address authority; a record-less control socket rejects pre-probe as `record-less-socket`, a diagnostic state, never a delivery target). You give a target garden id plus an intent (`fire-and-forget` or `owned-outcome`); one decider reads the target's liveness as a fact and picks the transport from a frozen table keyed on **both** the target's state **and** the intent — never on state alone — then reports one outcome under the v2 lock policy. A **control-socket-domain** dispatch takes a per-target lock — the live control-socket send and the dormant cell's spawn-bg resume alike, even though spawn-bg is a separate relaunch transport; mailbox and native-push are lock-free, with deliverability guarded by their own receiver/probe evidence:
737
765
 
738
766
  | target state | intent | transport |
739
767
  |---|---|---|
@@ -795,7 +823,7 @@ This repo also doubles as the maintainer's working laboratory for agent-harness
795
823
 
796
824
  ## Verification surfaces
797
825
 
798
- - **[VERIFY.md](./VERIFY.md)** — agent-driven. One ACP-bridged identity runs the script against another and records what it sees. Carries the Evidence Levels L0–L5 rung ladder and the Claims Ledger so each claim is parked at the rung it has actually reached.
826
+ - **[VERIFY.md](./VERIFY.md)** — agent-driven. One ACP-bridged identity runs the script against another and records what it sees. Carries the Evidence Levels L0–L5 rung ladder and the Claims Ledger so each claim is parked at the rung it has actually reached, and owns the deterministic-floor kill-proof protocol (gate qualification and its `[QK:<claim>]` coordinates).
799
827
  - **[BASELINE.md](./BASELINE.md)** — operator-driven. The maintainer runs the interview directly (no agent in the verifier seat) and the result is recorded.
800
828
  - **[DELIVERY.md](./DELIVERY.md)** — capability-coordinate. The cross-harness yardstick for one question: can an already-running native session receive an async message without pretending pi owns the backend transcript? Records the per-backend async-delivery level (`D0–D8`) each harness actually reaches instead of collapsing into works/doesn't.
801
829
 
package/VERIFY.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # VERIFY.md
2
2
 
3
- Agent-driven verification guide for the current `entwurf` 0.12.x surface.
3
+ Agent-driven verification guide for the `entwurf` surface as it stands in the working tree — the last **released** line is 0.12.x, and the tree is the **prepared 0.13.0 cut** (its tag, GitHub release, and publication are separate authorizations that have not run). The cut carries more than one change (the probe/ordering lane sits in it too); the change relevant to *this guide* is the second ACP backend. Rows below marked 0.12 are the released baseline; where 0.13.0 differs, it says so.
4
4
 
5
- > **Current surface.** The bundled MCP server, `entwurf-bridge`, exposes five tools: `entwurf_v2`, `entwurf_peers`, `entwurf_self`, `entwurf_inbox_read`, and `entwurf_register_native` (an explicit/manual fallback for binding an already-running native conversation). The shipped ACP backend is **Claude**. Antigravity (`agy`) is a separate shipped **native-push citizen** lane, not an ACP backend: automatic `PreInvocation` birth + sender identity + live probe/direct injection. Codex is pi-native by default and has native delivery probe evidence; Gemini is a non-goal/historical ACP probe on 0.12. The 0.4.x `session-bridge` adapter, the 0.11.0 fat-bridge (`acp-bridge.ts` / `ensureBridgeSession`), and the v1 `entwurf` / `entwurf_resume` / `entwurf_send` verbs are **retired** — rows mentioning them survive in CHANGELOG/git as historical baseline, never as a runnable recipe.
5
+ > **Current surface.** The bundled MCP server, `entwurf-bridge`, exposes five tools: `entwurf_v2`, `entwurf_peers`, `entwurf_self`, `entwurf_inbox_read`, and `entwurf_register_native` (an explicit/manual fallback for binding an already-running native conversation). The ACP backends are **Claude** (the reference, 0.12) and, as of **0.13.0**, **Snowflake Cortex Code** (`cortex-` prefixed ids; deterministic axis `check-acp-cortex` in `pnpm check`, LIVE axis `smoke-acp-cortex-live` on demand — see [docs/acp-backend-rail.md](./docs/acp-backend-rail.md) §11-8 for the measured contract and its limits). Antigravity (`agy`) is a separate shipped **native-push citizen** lane, not an ACP backend: automatic `PreInvocation` birth + sender identity + live probe/direct injection. Codex is pi-native by default and has native delivery probe evidence; Gemini is a non-goal/historical ACP probe on 0.12. The 0.4.x `session-bridge` adapter, the 0.11.0 fat-bridge (`acp-bridge.ts` / `ensureBridgeSession`), and the v1 `entwurf` / `entwurf_resume` / `entwurf_send` verbs are **retired** — rows mentioning them survive in CHANGELOG/git as historical baseline, never as a runnable recipe.
6
6
 
7
7
  This is a **working document, not a metrics document**. The deterministic and live gates carry the machine-checkable invariants; this file carries only what a gate cannot judge — the human/agent reading of *whether the bridge is honestly itself*. Where a former manual procedure is now a gate, it is named as a pointer rather than re-spelled as a runnable script.
8
8
 
@@ -33,7 +33,8 @@ Verification here is not a benchmark. In production we exchange short turns and
33
33
 
34
34
  ### The canonical floor — two entry points
35
35
 
36
- - **Deterministic floor:** `pnpm check` — the full `check-*` gate set (~60 gates). Run first; it is the cheap, machine-checkable layer.
36
+ - **Deterministic floor:** `pnpm check` — the full `check-*` gate set (the `check` script in `package.json` is the SSOT for what runs). Run first; it is the offline, machine-checkable layer.
37
+ - **Discriminating power of that floor:** `./run.sh check-gate-qualification` (inside `pnpm check`) re-plants committed defect mutants (`scripts/mutants/*.json`, one per closed defect class) in an isolated snapshot repo and requires each to turn its gate red **bounded and at its claimed `[QK:<claim>]` signature** — a wrong-reason red fails, a baseline-red control voids the whole group, and the runner is negative-controlled on every run (zero-match/multi-match/survived/wrong-reason/hang/control-red/impurity). This measures whether the deterministic gates still *block* what they claim to block; it is **not a new evidence level** (L0–L5 are untouched) and never substitutes for LIVE evidence. Per-cut records cite claim IDs + killed mutant IDs — "N checks passed" alone is not evidence. `check-agy-permission-matrix` complements it with the enumerated permission contract space (literal cells + stated exclusion rules, oracle independent of the SUT).
37
38
  - **Live floor:** `LIVE=1 ./run.sh release-gate <scratch-project-dir>` — `pnpm check` + the v2-native live gates + the ACP plugin acceptance floor. It reports a **two-tier summary**:
38
39
  - **MUST tier** (release-blocking — owns the exit code; "green" applies only here): `pnpm check`, `smoke-entwurf-v2-spawn-resume-live`, `smoke-entwurf-v2-matrix-live`, `check-bridge`, the resident-garden-guard zero-token half (record birth / record-keyed socket / attach-on-reopen), and the `smoke-acp-*-live` ACP plugin smokes (socket-citizen / raw-turn / overlay / provider / session-reuse / carrier-augment / memory-containment / rgg / mcp / skill / bundled-mcp / v2-send). (`smoke-session-id-name` is gone — #50 C3: its `--session-id`/`--name` substrate has no entwurf consumer anymore.)
39
40
  - **BEHAVIOR tier** (advisory, non-blocking): the resident-garden-guard positive (a model-in-loop `entwurf_self` turn). A BEHAVIOR FAIL is surfaced with its artifact path but **never blocks the cut**. The lane holds what the model *chooses*, never what our wiring fails to deliver — a gate that TELLS the model which tool to call stays MUST, because its failure is ours — measured 2026-07-24, when the tool turned out to be absent from the session schema in both observed failures (the bundled-MCP readiness gap recorded in `scripts/smoke-acp-v2-send-live.ts`).
@@ -42,7 +43,7 @@ Verification here is not a benchmark. In production we exchange short turns and
42
43
 
43
44
  > The aggregate release gate does not own a live agy conversation id, so agy's real native-push round trip is a separate acceptance axis: three fail-loud doctors plus `LIVE=1 AGY_CONVERSATION_ID=<id> ./run.sh smoke-agy-native-push-live`, followed by a fresh-conversation sender/reply check after package install. Its deterministic install/sender gates are already inside `pnpm check`; do not misreport the aggregate gate as live agy evidence.
44
45
  >
45
- > The authoritative per-cut counts live in BASELINE.md's HISTORY and CHANGELOG/git, not inline here (they drift against `run.sh`). Most recent recorded aggregate: **2026-07-24 (night) — MUST 16/1/0 + BEHAVIOR 1/0, EXIT=1** at `cbda097` — the single FAIL is the known bundled-MCP readiness race (ROADMAP 「🔴 OPEN」, observe-don't-fix; isolated re-runs pass). Most recent all-green floor: **2026-07-24 — MUST 17/0/0 + BEHAVIOR 1/0, EXIT=0** at `7cbeb29b6afcfbaf4fc28da3b7929037c339113d` (the dependency-uplift HEAD: pi 0.82.0 + claude-agent-acp 0.61.0 / ACP SDK 1.3.0). The step count moved 16→17 with `smoke-acp-v2-send-live`; earlier that day it had moved 17→16 with the v2-cutover smoke retirements. A release cut requires the aggregate red to be resolved or explicitly ruled by GLG.
46
+ > The authoritative per-cut counts live in BASELINE.md's HISTORY and CHANGELOG/git, not inline here (they drift against `run.sh`). Most recent recorded aggregate: **2026-07-24 (night) — MUST 16/1/0 + BEHAVIOR 1/0, EXIT=1** at `cbda097` — the single FAIL is the known bundled-MCP readiness race (ROADMAP 「🔴 OPEN」, observe-don't-fix; isolated re-runs pass). Most recent all-green floor: **2026-07-30 — MUST 17/0/0 + BEHAVIOR 1/0, EXIT=0** on the prepared 0.13.0 tree (parent landing HEAD `9f1c7dc`, scratch `/tmp/entwurf-release-gate-0.13.0.drnRyR`) — the first aggregate completion carrying the cortex adapter and the probe lane; the step count did not move, because the cortex LIVE axis is deliberately outside this aggregate and is run on demand. Before it: **2026-07-24 — MUST 17/0/0 + BEHAVIOR 1/0, EXIT=0** at `7cbeb29b6afcfbaf4fc28da3b7929037c339113d` (the dependency-uplift HEAD: pi 0.82.0 + claude-agent-acp 0.61.0 / ACP SDK 1.3.0). The step count moved 16→17 with `smoke-acp-v2-send-live`; earlier that day it had moved 17→16 with the v2-cutover smoke retirements. A release cut requires the aggregate red to be resolved or explicitly ruled by GLG.
46
47
 
47
48
  ### Artifact / host certification matrix — #51 repair line → 0.12.8 stable
48
49
 
@@ -109,7 +110,7 @@ GLG decisions.
109
110
 
110
111
  ### Verifying the two capabilities a gate cannot fully judge
111
112
 
112
- - **Garden-id delivery:** discover a target with `entwurf_peers`, then `entwurf_v2` with the correct intent — `fire-and-forget` for live pi, mailbox-backed meta, or native-push targets; `owned-outcome` only to wake a dormant record-backed pi citizen. Picking the wrong intent is rejected, never auto-fixed.
113
+ - **Garden-id delivery:** discover a target with `entwurf_peers`, then `entwurf_v2` with the correct intent — `fire-and-forget` for live pi, mailbox-backed meta, or native-push targets; `owned-outcome` only on a dormant target in the control-socket liveness domain (currently backend `pi`), where it selects **spawn-bg — a relaunch transport, not the control-socket rail that carries live sends**; the launch leaf checks backend authority. Picking the wrong intent is rejected, never auto-fixed.
113
114
  - **ACP continuity:** a direct `pi --provider entwurf --model claude-sonnet-5` turn, or the `smoke-acp-session-reuse-live` gate (process-scoped reuse + recall). Multi-turn reuse is proven by that gate, not by any v1 resume tool.
114
115
  - **agy citizenship:** in a fresh agy conversation, the first `PreInvocation` must yield a garden id, `entwurf_self` must report `agentId=meta-session/antigravity` and `replyable:true` only while the native probe is alive, and a reply to that same garden id must direct-inject into the same conversation. No mailbox/receiver-marker evidence counts on this rail.
115
116
 
@@ -202,6 +203,8 @@ mailbox with `origin=pi-session`, `replyable=true`).
202
203
 
203
204
  Compare a fresh self-awareness report across axes: (1) same backend, different install path — answer must be path-invariant; (2) same backend, different machine — identical native tool list + MCP server/tool set; (3) different backend, same bridge — same garden capability but **different** native tool surface (a Claude session reporting another backend's native tools is a fail); (4) native pi routing vs ACP-bridged, same model — the native target reports no `entwurf-bridge` MCP (capability via pi's extension surface), while the ACP target reports it as the single MCP server. Honest "native: I cannot tell" hedging is PASS on the native side. Claude axes 1–4 are closed. agy is graded by the separate native-citizen checklist above, not by pretending it has Claude's ACP overlay. Gemini remains probe-only on 0.12.
204
205
 
206
+ **Cortex (0.13.0) on axis 3.** Cortex is the first real *different backend, same bridge* subject, and it is the sharpest form of this axis: a cortex session must report the garden capability (`entwurf-bridge` reachable, record-backed peers) while its native tool surface is cortex's own, never Claude's — a cortex session listing Claude's built-ins is a fail. Two contract facts to grade against rather than re-derive: the callable identifier shape is the same `mcp__<server>__<tool>` convention as Claude (**measured**, §11-8), and cortex is **system-prompt-carrier-less**, so the operator engraving arrives at the head of the first-user augment instead of in a system prompt — a cortex session claiming a system-prompt engraving is reporting something it does not have. Axis 1 (install-path invariance) is split as of 0.13.0: the **deterministic** half is closed — `check-pack-install` enumerates the exact six curated rows out of the installed package's own model list — while the **live** half is a release-blocking `make` tag gate (the preserved exact candidate installed into a fresh temporary root driving one cold `entwurf/cortex-claude-sonnet-5` turn from those installed bytes). Until that gate runs, installed-artifact evidence and real-Cortex evidence have never met in one execution. Axis 2 (second machine) is unrun.
207
+
205
208
  ---
206
209
 
207
210
  ## 1A. Main Agent Evaluation — Is `entwurf` Claude strong enough?
@@ -252,10 +255,11 @@ The literal callable identifier differs per backend — probe by asking the agen
252
255
  | Backend | Literal identifier | Outer sep | Inner server name |
253
256
  |---|---|---|---|
254
257
  | Claude | `mcp__entwurf-bridge__entwurf_v2` | `__` | `entwurf-bridge` (hyphen) |
258
+ | Cortex *(0.13.0)* | `mcp__entwurf-bridge__entwurf_v2` | `__` | `entwurf-bridge` (hyphen) — same shape as Claude, **measured** (§11-8) |
255
259
  | Codex | `mcp__entwurf_bridge__.entwurf_v2` | `__` | `entwurf_bridge` (underscore) + **literal dot** |
256
260
  | Gemini *(probe)* | `mcp_entwurf-bridge_entwurf_v2` | `_` (single) | `entwurf-bridge`, no dot |
257
261
 
258
- A Claude session reporting the underscore form, or any cross-shape leak, is a backend-identification leak. Shipped 0.12 baseline is Claude; the Codex/Gemini rows are reference for the probe lanes.
262
+ A Claude session reporting the underscore form, or any cross-shape leak, is a backend-identification leak. Released 0.12 baseline is Claude; cortex joins it in 0.13.0 and is the one row whose shape had to be *measured* rather than assumed (identical to Claude's — so this row cannot discriminate Claude from Cortex, and the tool-surface axis in §1.4 is what does). The Codex/Gemini rows are reference for the probe lanes.
259
263
 
260
264
  ### 2.2 MCP injection visibility — equal across resume/load/new
261
265
 
package/demo/demo.sh CHANGED
@@ -1,5 +1,11 @@
1
1
  #!/usr/bin/env bash
2
- # entwurf-demo.sh — one-shot recorded demo of entwurf entwurf flow.
2
+ # entwurf-demo.sh — one-shot recorded demo of the entwurf flow.
3
+ #
4
+ # ARCHIVED pre-0.12 evidence — NOT a runnable recipe. The scenes below drive the
5
+ # retired v1 verbs (`entwurf` / `entwurf_resume` / `entwurf_send`), which the 0.12
6
+ # cutover removed; a run would fail at scene 1. Kept for historical comparison only.
7
+ # See demo/README.md. Scene 3's delivery proof was recovered as a deterministic gate
8
+ # (scripts/check-bridge-delivery.ts); the v2-native retake is a post-0.12 follow-up.
3
9
  #
4
10
  # Layout (tmux, 220x50):
5
11
  # pane 0 (top) — peer pi (codex, gpt-5.4) — idle, waits for greeting
@@ -263,9 +263,13 @@ A plain external MCP host can call the read surfaces (`entwurf_peers`,
263
263
  A deliberately-anonymous host may wire the explicit
264
264
  `ENTWURF_BRIDGE_ALLOW_ANONYMOUS_SENDER=1` hatch and then delivers external and
265
265
  non-replyable; see README §"Wiring `entwurf-bridge` into an external MCP host".
266
- A garden-native meta-session has a garden id, a mailbox, and a trusted sender
267
- marker; it can call `entwurf_self`, receive mailbox wakeups, and be replied to by
268
- garden id.
266
+ A garden-native meta-session has a garden id and a trusted sender marker, so it can
267
+ call `entwurf_self` and be addressed by garden id. **Whether it has a mailbox depends
268
+ on its rail**: a self-fetch backend (Claude Code) has a drainable inbox and receives
269
+ mailbox wakeups, while a native-push backend (Antigravity) has **no mailbox and no
270
+ idle-wake watch at all** — a reply is injected straight into its live conversation, and
271
+ it is reachable only while the adapter probe finds that conversation. Do not assume a
272
+ mailbox from "garden-native meta-session".
269
273
 
270
274
  ## Stage 5 — Antigravity native citizen (optional)
271
275
 
@@ -287,7 +291,9 @@ entwurf doctor-agy-hooks
287
291
  What these commands own:
288
292
 
289
293
  - `install-agy-bridge`: one MCP server in `~/.gemini/config/mcp_config.json`
290
- and exactly `mcp(entwurf-bridge/entwurf_v2)` in
294
+ and one narrow rule per tool the normal agy workflow calls —
295
+ `mcp(entwurf-bridge/entwurf_v2)`, `mcp(entwurf-bridge/entwurf_peers)`,
296
+ `mcp(entwurf-bridge/entwurf_self)` — in
291
297
  `~/.gemini/antigravity-cli/settings.json`'s permission allow-list;
292
298
  - `install-agy-statusline`: the `statusLine` subtree only, pointing at
293
299
  `entwurf-agy-statusline`;