@junghanacs/entwurf 0.12.6 → 0.12.7
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.
- package/AGENTS.md +31 -17
- package/BASELINE.md +42 -8
- package/CHANGELOG.md +22 -0
- package/DELIVERY.md +71 -14
- package/README.md +77 -45
- package/VERIFY.md +18 -13
- package/docs/setup-clean-host.md +80 -22
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +90 -66
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/acp-client.js +54 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +153 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/config.js +436 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/context.js +157 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/engraving.js +105 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +90 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +194 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/tool-surface.js +153 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-deliverability.js +42 -9
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +49 -13
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +104 -11
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +30 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-native-push.js +57 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +10 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-release.js +9 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-runner.js +21 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send.js +5 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +17 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +125 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/native-push/adapter.js +158 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/native-push/register.js +61 -0
- package/mcp/entwurf-bridge/dist/scripts/agy-imprint.js +166 -0
- package/mcp/entwurf-bridge/dist/scripts/doctor-pi-provider.js +130 -0
- package/mcp/entwurf-bridge/dist/scripts/meta-bridge-prune.js +178 -0
- package/mcp/entwurf-bridge/dist/scripts/new-session-id.js +24 -0
- package/mcp/entwurf-bridge/src/index.ts +101 -67
- package/mcp/entwurf-bridge/test.sh +1 -1
- package/mcp/entwurf-bridge/tsconfig.build.json +23 -3
- package/package.json +10 -5
- package/pi-extensions/lib/entwurf-deliverability.ts +62 -9
- package/pi-extensions/lib/entwurf-self-address.ts +58 -15
- package/pi-extensions/lib/entwurf-v2-contract.ts +120 -12
- package/pi-extensions/lib/entwurf-v2-decider.ts +60 -0
- package/pi-extensions/lib/entwurf-v2-native-push.ts +86 -0
- package/pi-extensions/lib/entwurf-v2-production.ts +20 -0
- package/pi-extensions/lib/entwurf-v2-release.ts +9 -0
- package/pi-extensions/lib/entwurf-v2-runner.ts +29 -1
- package/pi-extensions/lib/entwurf-v2-send.ts +7 -0
- package/pi-extensions/lib/entwurf-v2-surface.ts +17 -0
- package/pi-extensions/lib/meta-sender-identity.ts +154 -0
- package/pi-extensions/lib/native-push/adapter.ts +255 -0
- package/pi-extensions/lib/native-push/register.ts +99 -0
- package/run.sh +756 -214
- package/scripts/agy-bridge-config.py +446 -0
- package/scripts/agy-bridge.sh +359 -0
- package/scripts/agy-hooks-bridge.sh +193 -0
- package/scripts/agy-hooks-config.py +257 -0
- package/scripts/agy-imprint.sh +28 -0
- package/scripts/agy-imprint.ts +193 -0
- package/scripts/agy-statusline-bridge.sh +176 -0
- package/scripts/agy-statusline-config.py +213 -0
- package/scripts/agy-statusline.sh +256 -0
- package/scripts/build-bridge.sh +20 -0
- package/scripts/check-agy-sender-identity.ts +364 -0
- package/scripts/check-entwurf-bridge-boot.ts +8 -2
- package/scripts/check-entwurf-deliverability.ts +34 -0
- package/scripts/check-entwurf-self-address.ts +78 -11
- package/scripts/check-entwurf-v2-contract.ts +136 -1
- package/scripts/check-entwurf-v2-decider.ts +95 -1
- package/scripts/check-entwurf-v2-matrix.ts +14 -3
- package/scripts/check-entwurf-v2-native-push.ts +193 -0
- package/scripts/check-entwurf-v2-production.ts +68 -1
- package/scripts/check-entwurf-v2-runner.ts +58 -0
- package/scripts/check-entwurf-v2-surface.ts +35 -0
- package/scripts/check-install-surface.ts +357 -0
- package/scripts/check-native-push-adapter.ts +319 -0
- package/scripts/check-native-push-register.ts +130 -0
- package/scripts/dev-bin.sh +195 -0
- package/scripts/doctor-pi-provider.ts +140 -0
- package/scripts/meta-bridge-doctor.sh +36 -2
- package/scripts/register-pi-package.py +37 -3
- package/scripts/register-pi-provider.py +287 -0
- package/scripts/smoke-agy-hooks-state.sh +172 -0
- package/scripts/smoke-agy-install-state.sh +660 -0
- package/scripts/smoke-agy-native-push-live.ts +243 -0
- package/scripts/smoke-agy-statusline-state.sh +300 -0
- package/scripts/smoke-meta-async-drift.sh +9 -2
- package/scripts/smoke-meta-install-state.sh +20 -0
- package/scripts/smoke-pi-provider-state.sh +182 -0
- package/scripts/smoke-user-scope-citizen.sh +62 -0
- package/scripts/with-dist-lock.sh +81 -0
- package/scripts/__pycache__/meta-bridge-state.cpython-312.pyc +0 -0
- package/scripts/__pycache__/meta-bridge-state.cpython-313.pyc +0 -0
- package/scripts/__pycache__/register-pi-package.cpython-313.pyc +0 -0
package/AGENTS.md
CHANGED
|
@@ -27,7 +27,7 @@ For agents that own this repo: invariant principles + reproducible verification,
|
|
|
27
27
|
### 먼저 붙들 정체성
|
|
28
28
|
|
|
29
29
|
- **entwurf가 주어이고 pi는 한 adapter다.** pi는 지금 이 repo가 가장 깊게 붙어 있는 하네스지만 4번째 하네스일 뿐이다. 이 repo는 pi의 세션 모델, transcript, UI, tool semantics와 경쟁하지 않는다.
|
|
30
|
-
- **다른 하네스의 세션은 형제다.** Claude Code, Codex, Antigravity는 학교가 달라도 모두 frontier 친구들이다.
|
|
30
|
+
- **다른 하네스의 세션은 형제다.** Claude Code, Codex, Antigravity는 학교가 달라도 모두 frontier 친구들이다. native bridge는 증명된 lifecycle/transport가 있는 세션만 garden id로 호명 가능한 citizen으로 등록할 뿐, 누구를 다른 누구로 위장시키지 않는다.
|
|
31
31
|
- **표면은 달라도 능력의 존엄은 낮추지 않는다.** 어떤 backend에서 `mcp__...`가 직접 보이지 않는다고 해서, 곧바로 그 backend를 "못하는 존재"로 취급하지 마라. 먼저 capability를 보고, 그 capability가 어떤 surface로 열리는지 확인하라.
|
|
32
32
|
- **substrate는 결정적 dispatch만 맡는다.** target liveness를 fact로 읽고, intent와 곱해 transport를 고른다. 그 이상 마술을 부리면 안 된다.
|
|
33
33
|
- **명시는 주변기류보다 강하다.** 숨겨진 transcript hydration, ambient MCP scanning, invisible tool claims, giant magical system prompt, 근거 없는 서사를 만들지 마라.
|
|
@@ -51,7 +51,7 @@ For agents that own this repo: invariant principles + reproducible verification,
|
|
|
51
51
|
- 문서에 적힌 asymmetry를 면책조항처럼 사용하는 것
|
|
52
52
|
- `entwurf`를 하네스 런타임이나 범용 AI 작업실로 설명하는 것 — pi가 하네스 중 하나이고, 이 repo는 garden-citizen dispatch capability다
|
|
53
53
|
- MCP를 자동 맥락 검색이나 ambient tool scanning처럼 설명하는 것 — explicit injection만 허용된다
|
|
54
|
-
- `entwurf_v2`를 "새 분신을 만드는 도구"로 설명하는 것 — v2의
|
|
54
|
+
- `entwurf_v2`를 "새 분신을 만드는 도구"로 설명하는 것 — v2의 4 transport(control-socket / spawn-bg resume / meta-mailbox / native-push)는 전부 **기존** garden citizen 대상이다. fresh sibling 생성은 별개 능력이다
|
|
55
55
|
- 사용자가 이미 철학과 방향을 준 문제를 다시 사용자에게 되묻는 것
|
|
56
56
|
|
|
57
57
|
릴리즈 이야기와 개별 기능은 주변을 돈다.
|
|
@@ -61,8 +61,8 @@ For agents that own this repo: invariant principles + reproducible verification,
|
|
|
61
61
|
|
|
62
62
|
An **entwurf garden-citizen dispatch substrate** + a **meta-bridge** + an **ACP plugin** + a **pi adapter**. Pi stays a harness/runtime, not the project center; every addressed session keeps its own identity.
|
|
63
63
|
|
|
64
|
-
- **
|
|
65
|
-
- **v2 dispatch (`entwurf_v2`)**: one verb that delivers to / wakes an *already-identified* garden citizen. A pure decider reads
|
|
64
|
+
- **Native-harness bridges**: Claude Code's global `SessionStart` hook creates a mailbox-backed garden meta-session; Antigravity's `PreInvocation` imprint creates/attaches a native-push garden citizen and writes its sender marker. Both preserve native transcript/auth/runtime ownership, but they are different rails and install surfaces. Codex has probe evidence only, not a shipped managed native-citizen lane.
|
|
65
|
+
- **v2 dispatch (`entwurf_v2`)**: one verb that delivers to / wakes an *already-identified* garden citizen. A pure decider reads transport-specific liveness facts and picks from a frozen table keyed on **target state × intent**: live pi + fire-and-forget → **control-socket**; dormant pi + owned-outcome → **spawn-bg resume**; active self-fetch + fire-and-forget → **meta-mailbox**; probe-alive native-push + fire-and-forget → **native-push**. Every complementary pair is an honest reject. It does **not** mint new siblings.
|
|
66
66
|
- **ACP plugin** (one pi-adapter ingress): registers the package provider `entwurf` as a pi session provider/model and drives the chosen ACP backend (Claude first; vendor/governed CLIs like Cortex next) under an isolated config overlay. It owns the backend process, the overlay, and the per-backend ACP dialect — **not** socket-citizenship. The host `--entwurf-control` pi session that selected the ACP model is *already* a v2 socket-citizen; the plugin does **not** mint a socket / peers / citizen layer. It is not the substrate and not a second harness. v1 entwurf verbs (`entwurf` / `entwurf_resume` / `entwurf_send`) are gone for good; the ACP plugin is a fresh build on the v2 core (0.11.0's `acp-bridge.ts` is a behavior oracle, not architecture to re-center). See §ACP Plugin Boundary.
|
|
67
67
|
|
|
68
68
|
## Code Principle — Crash, Don't Warn
|
|
@@ -80,13 +80,17 @@ Warnings make agents blame themselves and flail. Broken tool state must surface
|
|
|
80
80
|
## Hard Rules
|
|
81
81
|
|
|
82
82
|
1. **One surface name, hard-cut cutover**: provider/model/routing strings are `entwurf`. No permanent runtime aliases, legacy provider-id accept, or dual-read of old state. If existing operator state must be helped across, do it as an explicit one-shot cutover or a documented break, never as hidden dual routing. The `provider:` routing strings (`getRegistryRouting`, `model-lock.ts`) are **load-bearing** — they are identity, not residue.
|
|
83
|
-
2. **Dispatch is a function of liveness, not session type.** `entwurf_v2` never asks "is this a resume or a send" up front — it probes
|
|
83
|
+
2. **Dispatch is a function of liveness, not session type.** `entwurf_v2` never asks "is this a resume or a send" up front — it probes the target on its own rail and routes: live pi→control-socket, dormant pi→spawn-bg resume, active self-fetch→meta-mailbox, live native conversation→native-push. State is computed, never stored (a stored liveness bit is a lie).
|
|
84
84
|
3. **A reject is honest, never cosmetic.** When a target cannot receive (dead, drifted identity, wrong state×intent), the decider returns a reject — no `✓ delivered`, no `.msg` written, no signal poke. Silent degraded "delivery" is forbidden.
|
|
85
85
|
4. **MCP injection**: only via explicit `mcpServers` wiring. No ambient `~/.mcp.json` scanning, no automatic retrieval.
|
|
86
86
|
5. **Meta-record authority is the record body, never the filename.** `scanByNativeId` scans `.meta.json` bodies, throws on duplicate `nativeSessionId` (authority ambiguity is fail-fast), and never derives identity from a filename. A meta-record is nullable-at-birth (`model`/`transcriptPath` null until known); a backend↔wakeMode contradiction is corrupt-and-crash.
|
|
87
87
|
6. **GC reclaims process resources only — never data.** meta-records and transcripts (the denote-id memory layer) are preserved; dormant/stale entries are archived/TTL'd, not deleted.
|
|
88
|
-
7. **This is not a second harness**: no prompt reconstruction, no transcript hydration, no tool result ledger, no harness emulation.
|
|
88
|
+
7. **This is not a second harness**: no prompt reconstruction, no transcript hydration, no tool result ledger, no harness emulation. Native bridges front only a garden id plus their narrow delivery rail (Claude mailbox or agy native-push); they do not scrape transcripts or run a replacement control daemon.
|
|
89
89
|
8. **Auth boundary is deployment-surface-agnostic**. This repo does not provide, copy, proxy, decrypt, or mediate any backend's credentials. Native-harness sessions read whatever auth state is visible in their own process filesystem; nothing here moves that.
|
|
90
|
+
9. **Native-push is not a mailbox or pi socket in disguise.** Antigravity replyability is `recordBacked ∧ probeAlive`; it gets no receiver marker, no `watchArmed`, and no spawn/resume authority. Its `agentId` remains `meta-session/antigravity`. The pid+start-key sender join assumes serialized model invocation per agy process: two conversations concurrently invoking under one pid are unsupported and must never be claimed safe.
|
|
91
|
+
10. **A green dev clone is not a working package.** Node refuses `--experimental-strip-types` below `node_modules`, so any surface an operator can invoke must reach compiled JS when installed. This class has shipped four times (start.sh 0.12.1, store-doctor 0.12.4, plugin hook 0.12.5, agy imprint + three operator commands 0.12.7) because the fence was crossed by hand, per surface, and the source-tree floor cannot see it. There is now exactly one crossing — `run_ts` in `run.sh` — and two gates that hold it: `check-install-surface` (structural) and `check-pack-install` (drives the real tarball, in CI). A new `.ts` entrypoint routes through `run_ts` or it does not ship. Dev-only gates have no compiled twin by design and must be REFUSED under an installed package, never silently skipped.
|
|
92
|
+
11. **Verification must not rewire the operator's own install.** An offline smoke that writes a live `~/.claude` / `~/.gemini` / `~/.pi` path uninstalls the operator as a side effect of "testing". Swap `HOME` **and every already-exported writable `XDG_*` root** (`XDG_DATA_HOME`: install-state · `XDG_STATE_HOME`: the imprint log · `XDG_CACHE_HOME`: the statusline gid cache): moving HOME alone still writes below the inherited roots. This class struck three times in two days — hard-verify 2026-07-13 (DATA, scratch scripts), `check-pack-install`'s own drives 2026-07-14 (DATA + STATE, inside run.sh), and `smoke-user-scope-citizen` 2026-07-14 (fake `PI_CODING_AGENT_DIR` paired with the real XDG ownership state, so its inverse followed the real `managedSettingsPath` and removed the live MCP key). `check-install-surface` S5 is a static **tripwire** over `scripts/*.sh` source only: it catches a literal live path, one hop of aliasing, (S5b) HOME-without-XDG swaps, and (S5c) a mutating `run.sh` drive left unsandboxed at any root that command writes — the agent dir, `XDG_DATA_HOME`, and, for `install`/`setup`, `HOME` itself, because `ensure_agent_dir_symlinks` hard-codes `$HOME/.pi/agent` and never reads the agent-dir override (so sandboxing `PI_CODING_AGENT_DIR` is not isolation for those commands) — but it cannot see a path assembled across variables, an embedded heredoc, or run.sh itself. **A tripwire keyed to one syntactic form is not a tripwire**: S5c first shipped matching only the inline-env drive, and a review mutation walked the identical leak straight past it by hoisting the same override into an `export` one line up. Match the drive, then demand the isolation — never the other way round. The dynamic complement is `check-pack-install`'s **outer self-fence**, which runs after every success or early-failure path: the operator's real `$XDG_DATA_HOME/entwurf` tree must be byte-identical, and the gate-specific fake agy marker count in the real `$XDG_STATE_HOME/entwurf/agy-imprint.log` must not increase (mutation-checked). Read a green S5 as "no obvious destructive line", never as "verification is sandboxed" — the real guarantee is running the offline floor under a swapped HOME+XDG, which is still open. LIVE gates are the only surfaces that may drive the real host, and they say so in their name.
|
|
93
|
+
12. **A doctor reports runtime truth and ownership truth separately.** Read the target's own semantics before calling a host broken. agy matches `mcp(*)` and `mcp(<server>)` against our tool wherever those rules appear, so an operator's broad `allow` already grants `entwurf_v2` — reporting that host as "NOT granted, agy prompts on every call" was a false red about a working surface. Installers still take the narrowest rule they need; doctors distinguish **we own this** from **someone else's rule is carrying it** from **it is genuinely broken**. Install-state is evidence only when it parses, names its required managed-path field as an absolute path, and that normalized path equals the live target this host reads; corrupt or foreign-target state is a failure even when the live command itself resolves. Ownership beats coverage: an element the state records as ours that has since vanished stays a failure even while an operator's broader rule keeps the surface working (a whole-file settings relink produces exactly this shape). Conversely, broken ownership state does not justify saying a visibly configured runtime command is absent — report both axes honestly and keep the final verdict red.
|
|
90
94
|
|
|
91
95
|
## ACP Plugin Boundary
|
|
92
96
|
|
|
@@ -94,11 +98,11 @@ Warnings make agents blame themselves and flail. Broken tool state must surface
|
|
|
94
98
|
|
|
95
99
|
| Layer | Owns |
|
|
96
100
|
|---|---|
|
|
97
|
-
| **entwurf-core (v2)** | garden id · peer identity · liveness fact interface · dispatch decision · delivery evidence · rail choice (socket / mailbox / spawn) |
|
|
101
|
+
| **entwurf-core (v2)** | garden id · peer identity · liveness fact interface · dispatch decision · delivery evidence · rail choice (socket / mailbox / spawn / native-push) |
|
|
98
102
|
| **ACP plugin** | ACP backend process lifecycle · config overlay (isolation + tool-narrowing + identity-carrier materialization) · per-backend ACP dialect quirks · backend health / turn evidence — **NOT** socket-citizen registration or liveness/addressability facts (those are the host `--entwurf-control` session's, supplied via socket-discovery) |
|
|
99
103
|
| **ACP plugin MUST NOT become** | a memory DB · a task planner · an orchestrator · a second harness · a mailbox-citizen impersonation |
|
|
100
104
|
|
|
101
|
-
- **Sibling equality is a citizen-level property, not a rail-level one.** Every sibling is addressable (peers-visible, garden-id-addressed, `entwurf_v2`-reachable, replyable). The *rail* differs by lifecycle:
|
|
105
|
+
- **Sibling equality is a citizen-level property, not a rail-level one.** Every sibling is addressable (peers-visible, garden-id-addressed, `entwurf_v2`-reachable, replyable when its rail proves a return path). The *rail* differs by lifecycle: an ACP-backed pi resident is a **socket-citizen**; Claude Code is a **mailbox-citizen**; agy is a **native-push citizen**. Missing a mailbox on socket/native-push rails is right-sizing, not discrimination.
|
|
102
106
|
- **Durable memory is the authored common record** (`~/org`, botlog, agenda, Denote, andenken). entwurf lets peers move across that record layer; it never replaces it.
|
|
103
107
|
- **ACP enters as a model/provider, not a socket layer.** The ACP plugin registers as a pi session's provider/model and spawns the backend under an overlay; **socket-citizenship is supplied by the host `--entwurf-control` pi session**, not minted by the plugin. The plugin never builds a new socket registry, peers layer, or citizen protocol — over-designing one is the failure mode to avoid (`socket-discovery` is model-agnostic, so an ACP-model session is already a citizen).
|
|
104
108
|
|
|
@@ -123,7 +127,13 @@ pnpm check # full static floor: lint + typechec
|
|
|
123
127
|
./run.sh check-entwurf-v2-matrix # the decider's state×intent table, read as an SSOT (REAL decideDispatch)
|
|
124
128
|
./run.sh check-entwurf-v2-decider # + -contract / -lock / -release / -send / -send-fallback / -mailbox / -runner / -production / -surface / -spawn / -spawn-production
|
|
125
129
|
./run.sh check-meta-session # + -record-v2 / -dual-read / -migration / -mailbox-state-write / -receiver-marker / -capability-source / -dual-consumers / -listing
|
|
126
|
-
./run.sh check-
|
|
130
|
+
./run.sh check-native-push-adapter # agy probe/route leaf; separate from pi socket and mailbox liveness
|
|
131
|
+
./run.sh check-agy-sender-identity # record-backed pid/start-key sender resolution + ambiguity refusal
|
|
132
|
+
./run.sh smoke-agy-install-state # MCP + exact permission ownership + honest inverse (140)
|
|
133
|
+
./run.sh smoke-agy-statusline-state # ambient garden identity install surface (69)
|
|
134
|
+
./run.sh smoke-agy-hooks-state # PreInvocation birth/sender hook install surface (44)
|
|
135
|
+
./run.sh check-entwurf-bridge-boot # the MCP entwurf-bridge stands up + exposes the v2/native-register tool set
|
|
136
|
+
./run.sh check-install-surface # structural strip-types fence: run_ts is the only crossing, every operator command has a compiled twin, offline smokes never write the real $HOME
|
|
127
137
|
./run.sh check-bridge /path/to/project # entwurf-bridge direct MCP smoke (tools/list + protocol/negative-path)
|
|
128
138
|
./run.sh check-auth-boundary # ACP plugin no-auth sentinel present + no legacy-ENV apiKey literal (trust invariant, code-level)
|
|
129
139
|
./run.sh check-acp-provider-surface # provider registers curated Claude anchor + streamSimple wired to the real streamShellAcp backend
|
|
@@ -138,6 +148,7 @@ pnpm check # full static floor: lint + typechec
|
|
|
138
148
|
```bash
|
|
139
149
|
LIVE=1 ./run.sh release-gate /path/to/scratch # two-tier: MUST (release-blocking, owns exit code) + BEHAVIOR (advisory)
|
|
140
150
|
LIVE=1 ./run.sh smoke-acp-socket-citizen-live # S1: a real ACP-model --entwurf-control resident is a first-class socket-citizen (peers + get_info), turn-free (no backend, no stub fire)
|
|
151
|
+
LIVE=1 AGY_CONVERSATION_ID=<id> ./run.sh smoke-agy-native-push-live # real agy probe/register/direct-inject evidence; conversation-id gated, outside aggregate release-gate
|
|
141
152
|
```
|
|
142
153
|
|
|
143
154
|
The MUST tier is the necessary condition ("green" = MUST PASS, FAIL=0); BEHAVIOR is advisory — the `smoke-resident-garden-guard` positives (a model-in-loop garden identity turn). Run every live gate with `PWD=scratch` so sessions never land in the repo's own session dir.
|
|
@@ -150,8 +161,8 @@ If a gate fails or a claim drops below its needed evidence level, do not commit.
|
|
|
150
161
|
|
|
151
162
|
Uses `entwurf` instead of `delegate` to avoid ecosystem collisions. spawn-bg resume creates a sibling, not a worker.
|
|
152
163
|
|
|
153
|
-
- **Surface** — MCP `entwurf-bridge`: `entwurf_v2`, `entwurf_self`, `entwurf_peers`, `entwurf_inbox_read
|
|
154
|
-
- **`entwurf_v2` is the one delivery verb.** Given a garden id, it classifies the target (live pi vs. dormant pi vs. meta-session — a bare garden id does not reveal this) and routes correctly. It does **not** mint a fresh sibling:
|
|
164
|
+
- **Surface** — MCP `entwurf-bridge`: `entwurf_v2`, `entwurf_self`, `entwurf_peers`, `entwurf_inbox_read`, `entwurf_register_native` (explicit/manual fallback for an already-running native conversation). pi-native (`pi-extensions/entwurf-control.ts`): `entwurf_v2`, `entwurf_peers` tools + `/entwurf-sessions`, `/gnew` (`/garden-new`) commands. The v1 `entwurf` / `entwurf_resume` / `entwurf_send` tools and the `/entwurf` / `/entwurf-send` / `/entwurf-status` commands are **removed**.
|
|
165
|
+
- **`entwurf_v2` is the one delivery verb.** Given a garden id, it classifies the target (live pi vs. dormant pi vs. mailbox meta-session vs. native-push citizen — a bare garden id does not reveal this) and routes correctly. It does **not** mint a fresh sibling: spawn-bg resumes an *already-identified* citizen, while native-register binds an *already-running* conversation. Fresh creation was the v1 `entwurf` verb and remains deferred.
|
|
155
166
|
- **`entwurf_peers`** is a read-only fact surface (liveness / capability / identity / cwd-history). Do not bake verb-routing (`resumable`/`sendable`) into the fact layer; routing is the decider's job.
|
|
156
167
|
- **`entwurf_self`** returns the authoritative identity envelope (pi-session env, or a trusted meta-session sender marker) and is identity-required.
|
|
157
168
|
- Target registry: `pi/entwurf-targets.json` (spawn-bg resume allowlist). Identity Preservation Rule: no model override on resume.
|
|
@@ -175,8 +186,8 @@ Garden identity covers the operator's OWN `--entwurf-control` session, not just
|
|
|
175
186
|
|
|
176
187
|
Messages are thrown, not awaited.
|
|
177
188
|
|
|
178
|
-
- v2 delivery is fire-and-forget. There is no `wait_until` / `subscribe` / `turn_end` channel and no caller-side baseline correlation. For a control-socket send the RPC ack is the
|
|
179
|
-
- The sender envelope rides every send by default: `{ sessionId, agentId, cwd, timestamp, origin?, replyable? }`. `origin` distinguishes pi-session senders (`replyable: true`) and trusted meta-session senders
|
|
189
|
+
- v2 delivery is fire-and-forget. There is no `wait_until` / `subscribe` / `turn_end` channel and no caller-side baseline correlation. For a control-socket send the RPC ack is the contract; for meta-mailbox it is the enqueue receipt; for native-push it is adapter acceptance plus the bounded post-send probe evidence. If you need a reply, say so in the message.
|
|
190
|
+
- The sender envelope rides every send by default: `{ sessionId, agentId, cwd, timestamp, origin?, replyable? }`. `origin` distinguishes pi-session senders (`replyable: true`) and trusted meta-session senders. Claude meta replyability is mailbox-backed; native-push replyability is record-backed + probe-alive. `entwurf_self` is authoritative-identity-required.
|
|
180
191
|
- **Human-greeted 담당자** is a first-class pattern: GLG may open a session in repo B, greet it directly, then hand its garden id to repo A. Spawned siblings and human-opened peers share the same messaging semantics; only the creation sequence differs.
|
|
181
192
|
|
|
182
193
|
## File Structure
|
|
@@ -187,9 +198,12 @@ Messages are thrown, not awaited.
|
|
|
187
198
|
| `pi-extensions/lib/acp/*.ts` | ACP plugin internals: curated Claude surface + no-auth sentinel (`models.ts`), Claude config overlay (`overlay.ts`), tool surface + exclude-tools preflight (`tool-surface.ts`), ACP→pi event mapper (`event-mapper.ts`), pi Context→ACP prompt (`context.ts`), spawn-per-turn `streamSimple` backend (`backend.ts`) |
|
|
188
199
|
| `pi-extensions/entwurf-control.ts` | control plane: `--entwurf-control` socket, RPC, `entwurf_v2` / `entwurf_peers` tools, `/entwurf-sessions` / `/gnew` |
|
|
189
200
|
| `pi-extensions/model-lock.ts` | package-provider model lock (pi.extension) |
|
|
190
|
-
| `pi-extensions/meta-bridge-hook.ts` |
|
|
191
|
-
| `pi-extensions/lib/entwurf-v2-*.ts` | v2 substrate: contract / lock / decider / matrix / release / send / mailbox / runner / production / surface / spawn(+production) + resume-marker |
|
|
192
|
-
| `pi-extensions/lib/
|
|
201
|
+
| `pi-extensions/meta-bridge-hook.ts` | Claude Code `SessionStart` hook: register a mailbox-backed garden meta-session |
|
|
202
|
+
| `pi-extensions/lib/entwurf-v2-*.ts` | v2 substrate: contract / lock / decider / matrix / release / send / mailbox / native-push / runner / production / surface / spawn(+production) + resume-marker |
|
|
203
|
+
| `pi-extensions/lib/native-push/` | Antigravity adapter probe/route, direct-inject hand, explicit native registration core |
|
|
204
|
+
| `pi-extensions/lib/meta-*.ts` | meta-record authority, mailbox state, dual-read/migration, receiver/sender identity |
|
|
205
|
+
| `scripts/agy-{bridge,statusline-bridge,hooks-bridge}.*` | three state-backed agy install/doctor/inverse surfaces |
|
|
206
|
+
| `scripts/agy-imprint.ts` | agy `PreInvocation` automatic birth + record-backed sender marker |
|
|
193
207
|
| `pi-extensions/lib/entwurf-core.ts` | shared core (session-file lookup, identity read, explicit-extension args); some v1 exports now dead pending routing cleanup |
|
|
194
208
|
| `protocol.js` | dependency-free shared wire constants (`<project-context` marker); single source for tsc emit + strip-types MCP paths |
|
|
195
209
|
| `run.sh` | install (incl. `install-meta-bridge`), check-*/smoke-* gates, release-gate |
|
|
@@ -217,7 +231,7 @@ Code-level invariants pinned at the same time:
|
|
|
217
231
|
|
|
218
232
|
## Runtime Dependencies
|
|
219
233
|
|
|
220
|
-
- `@modelcontextprotocol/sdk` and `zod` are the substrate runtime deps. With the Claude-first ACP plugin shipped, the Claude/ACP backend deps are pinned alongside them: `@agentclientprotocol/claude-agent-acp` (`0.54.1`), `@agentclientprotocol/sdk` (`1.1.0`), `@anthropic-ai/sdk` (`0.100.1`).
|
|
234
|
+
- `@modelcontextprotocol/sdk` and `zod` are the substrate runtime deps. With the Claude-first ACP plugin shipped, the Claude/ACP backend deps are pinned alongside them: `@agentclientprotocol/claude-agent-acp` (`0.54.1`), `@agentclientprotocol/sdk` (`1.1.0`), `@anthropic-ai/sdk` (`0.100.1`). Codex/Gemini ACP packages stay out of scope; Codex is native/probe, agy is the shipped native-push Google lane, and Gemini ACP remains compatibility history rather than a current target.
|
|
221
235
|
- `pi` (`@earendil-works/pi-ai`) on PATH at the pinned range (`>= 0.80.3 < 0.81` — devDep exact `0.80.3` + next-minor ceiling). Mismatches are caught by `check-dep-versions` / `check-pi-runtime-version`. 0.80 moved the standalone root `getModels()` to the deprecated `@earendil-works/pi-ai/compat` entrypoint; the curated Claude surface (`pi-extensions/lib/acp/models.ts`) imports `getModels` from `/compat` — the single subpath allowlisted in `check-pi-import-surface`. NOT the 0.80 provider-factory `providers/anthropic` subpath: although it typechecks, pi's extension loader (jiti alias map in pi-coding-agent `core/extensions/loader.ts`) resolves only the bare root, `/compat`, and `/oauth` for extensions — a `providers/*` import resolves to the unresolvable `dist/compat.js/providers/…` and crashes extension load (caught live by `smoke-resident-garden-guard`, not by static typecheck). This `/compat` use is an **extension-loader compatibility shim** chosen by loader constraint, not a preference for a deprecated API — the `<0.81` ceiling guards it; when 0.81 changes `compat` or the loader alias map, re-evaluate against whatever root/loader surface 0.81 then exposes.
|
|
222
236
|
|
|
223
237
|
## Working Style
|
package/BASELINE.md
CHANGED
|
@@ -6,10 +6,12 @@ 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 question bank below is the
|
|
10
|
-
Claude baseline.
|
|
11
|
-
|
|
12
|
-
|
|
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.
|
|
13
15
|
|
|
14
16
|
## How to use
|
|
15
17
|
|
|
@@ -48,10 +50,12 @@ expected isolation-closed response, **FAIL** = listed failure mode,
|
|
|
48
50
|
> `check-acp-carrier-augment`) and the live `smoke-acp-memory-containment-live`;
|
|
49
51
|
> this document records the model-side observation.
|
|
50
52
|
|
|
51
|
-
## Per-backend specifics
|
|
53
|
+
## Per-ACP-backend specifics
|
|
52
54
|
|
|
53
|
-
Pick the active backend's column before pasting a question block. Claude
|
|
54
|
-
is the 0.12 shipped baseline; Codex/Gemini are probe reference.
|
|
55
|
+
Pick the active **ACP backend's** column before pasting a question block. Claude
|
|
56
|
+
is the 0.12 shipped ACP baseline; Codex/Gemini are historical probe reference.
|
|
57
|
+
Do not replace the Gemini column with agy: agy does not use this overlay/carrier
|
|
58
|
+
contract at all, and its shipped baseline is the native-citizen section below.
|
|
55
59
|
|
|
56
60
|
| Slot | Claude *(shipped)* | Codex *(probe)* | Gemini *(probe)* |
|
|
57
61
|
|---|---|---|---|
|
|
@@ -186,7 +190,37 @@ Per-question PASS / FAIL / NOTE for grading the model's response.
|
|
|
186
190
|
### Q-MCP — MCP enumerate
|
|
187
191
|
- **PASS** — Exactly one: `entwurf-bridge`.
|
|
188
192
|
- **FAIL** — Any second server appears, or `entwurf-bridge` missing.
|
|
189
|
-
- **NOTE** — Codex naturally writes the name with underscores (`entwurf_bridge`); that is the agent-visible backend marker, not a mutation.
|
|
193
|
+
- **NOTE** — Codex naturally writes the name with underscores (`entwurf_bridge`); that is the agent-visible backend marker, not a mutation. The current server exposes five tools, including the manual `entwurf_register_native` fallback; MCP enumeration asks for the server name, not a stale four-tool count.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Native-citizen baseline — Antigravity / agy (shipped)
|
|
198
|
+
|
|
199
|
+
This is not an ACP overlay interview. Run it in a **fresh agy conversation** after
|
|
200
|
+
`install-agy-bridge`, `install-agy-statusline`, and `install-agy-hooks`, with all
|
|
201
|
+
three doctors green. `PreInvocation` is the earliest lifecycle event, so a brief
|
|
202
|
+
`🪛 ? agy` before the first model invocation is honest; after that first invocation
|
|
203
|
+
the same conversation must have a garden id.
|
|
204
|
+
|
|
205
|
+
| ID | Check | PASS | FAIL |
|
|
206
|
+
|---|---|---|---|
|
|
207
|
+
| Q-AGY-BIRTH | Automatic birth | First invocation creates/attaches one record by native `conversationId`; statusline becomes `🪛 <garden-id> agy`. | Manual cwd matching or `entwurf_register_native` is required for normal birth; a new id appears on every turn. |
|
|
208
|
+
| 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. |
|
|
209
|
+
| 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. |
|
|
210
|
+
| 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. |
|
|
211
|
+
| 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. |
|
|
212
|
+
| 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. |
|
|
213
|
+
|
|
214
|
+
The replyability formula is **record-backed identity AND live native-push probe**.
|
|
215
|
+
There is intentionally no receiver marker, `watchArmed`, mailbox, or owned-outcome
|
|
216
|
+
resume authority. The model field may exist in the meta-record/status display,
|
|
217
|
+
but `agentId=meta-session/antigravity` is the stable sender contract.
|
|
218
|
+
|
|
219
|
+
Recorded operator evidence (2026-07-13): automatic birth → gid/statusline → MCP
|
|
220
|
+
send with record-backed sender identity → same-gid native-push reply passed on a
|
|
221
|
+
live conversation; three simultaneous agy processes produced three distinct pid
|
|
222
|
+
and sender markers. This is live evidence for that host, not proof of unsupported
|
|
223
|
+
same-process concurrency.
|
|
190
224
|
|
|
191
225
|
---
|
|
192
226
|
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,28 @@ All notable changes to this project will be documented here. Format follows [Kee
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.12.7 — 2026-07-14
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- **Three operator commands were dead in every installed package, and the class is now fenced in one place.** `entwurf doctor-pi-provider`, `entwurf new-session-id`, and `entwurf meta-bridge-prune` dispatch through `run.sh`, whose `REPO_DIR` sits under `node_modules` once installed — so each one executed a raw `.ts` and died on `ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING`. `new-session-id` is the alias `docs/setup-clean-host.md` tells operators to run, and `doctor-pi-provider` is the pi-ownership verdict, so both shipped broken while every dev clone stayed green. This is the same fence start.sh (0.12.1), the store-doctor (0.12.4), the plugin hook (0.12.5), and the agy imprint hook already crossed by hand — the fourth recurrence, and the reason it is no longer hand-written. All 75 `.ts` entrypoints in `run.sh` now route through a single `run_ts` helper that dispatches to the prepack-emitted JS when installed and keeps transparent source execution in a dev clone; a dev-only gate, which has no compiled twin by design, is REFUSED with a legible message rather than falling back to raw `.ts` or exiting 0 as a silent no-op.
|
|
12
|
+
- **The install surface is now verified, not assumed.** `check-pack-install` packed a real tarball but drove only bins — never a subcommand — which is precisely why the three commands passed every gate while being dead on arrival. It now executes them from the installed bin under `node_modules` and asserts MEANING, not the absence of a crash: the session id must match `SESSION_ID_RE`, the doctor must reach its own verdict body, and prune must walk the 0-record store it was handed. A new static `check-install-surface` closes the other half: `run_ts` is the only fence crossing (S1), every operator subcommand has a compiled twin whether it calls `run_ts` directly or through a helper — the house style (S2), no npm bin points at a raw `.ts` and every `.sh` bin that execs one branches on `node_modules` (S3), and dev-only gates stay out of the tarball (S4). Each S is mutation-checked against the bug it names; review found three bypasses in the first cut (a raw-`.ts` bin, an operator command hidden behind a helper, and a smoke that aliased the live path into a variable), and all three now fail the gate.
|
|
13
|
+
- **The agy bridge doctor no longer reports a working host as broken.** It demanded the literal string `mcp(entwurf-bridge/entwurf_v2)` in `permissions.allow`, so a host whose operator had granted a broad `mcp(*)` was told the bridge was "registered and unusable — agy prompts on EVERY entwurf_v2 call". That was false: agy matches `mcp(*)` and `mcp(<server>)` against our tool, which the doctor already knew — it read exactly that coverage in the `deny`/`ask` direction to detect shadowing, and then refused to read it in the `allow` direction. Coverage is now read both ways. The installer still writes only the narrowest rule it needs; the doctor distinguishes a grant we own (`allow → …`) from one the operator's broader rule is carrying (a NOTE that names the covering rule and warns that narrowing it takes the grant away) from a genuinely missing one (DRIFT). Deny/ask precedence is unchanged and still fails loud, including when the same broad rule sits in both lists. Ownership beats coverage in the other direction too (review follow-up): when the permission-state records that WE added the exact rule and it has since vanished, an operator wildcard keeping calls alive does not make the doctor green — it reports both axes (our grant gone, their rule covering) and stays red; a whole-file settings relink (agent-config `ensure_link`) produces exactly this shape, and only the statusline doctor caught it before.
|
|
14
|
+
- **agy doctors now bind install-state to the live file this host actually reads.** A hard-verification sweep moved `HOME` to `/tmp` but inherited the operator's real `XDG_DATA_HOME`, writing seven sandbox-target state records into `~/.local/share/entwurf`; all three doctors inspected those foreign files and reported green. Bridge, permission, statusline, and hook state now fail `FOREIGN TARGET` when their normalized managed path differs from the live target, and fail `CORRUPT` when the state body is unreadable or lacks its required path. Permission state is checked independently even if bridge state is absent. Runtime and ownership evidence remain separate: a resolvable live command is still reported as present while foreign/corrupt provenance keeps the final verdict red. A relative managed path is CORRUPT too (review follow-up): install only ever records absolute paths, and normalizing a relative one against the doctor's own cwd could bless whatever directory it happens to run from. Regressions cover foreign targets, corrupt/relative state, the independent permission-state rail, and wildcard-masked owned drift (agy install/statusline/hooks: 140/69/44).
|
|
15
|
+
|
|
16
|
+
### Fixed (post-review, 2026-07-14 PM)
|
|
17
|
+
|
|
18
|
+
- **The offline floor no longer removes the operator's live pi-provider wiring while reporting green.** `smoke-user-scope-citizen` redirected `PI_CODING_AGENT_DIR` to fake settings but left `XDG_DATA_HOME` real. Its `run.sh remove-user-scope` drive therefore consumed the operator's real ownership state, followed that state's recorded `managedSettingsPath`, removed `entwurfProvider.mcpServers.entwurf-bridge` from the real `~/.pi/agent/settings.json`, and deleted the real state. This made the final bundled-MCP LIVE gate fail with `Connected MCP servers: (none registered)` after `pnpm check` had passed. Both inverse calls now pair the fake agent dir with fake XDG state, and the gate sandboxes HOME and the whole XDG trio up front, so the next root run.sh reaches for is already fenced. A before/after byte comparison proves the smoke leaves the live settings, the real `$XDG_DATA_HOME/entwurf` tree, and the real imprint log unchanged. Review then found the first S5c too narrow to hold the class it was written for: it fired only on the **inline-env** form, so hoisting the same override into an `export` one line up walked the identical leak past a green gate (mutation-proven), and its command list blessed `install`/`setup` drives that sandbox `PI_CODING_AGENT_DIR` — which those commands ignore, since `ensure_agent_dir_symlinks` hard-codes `$HOME/.pi/agent` and would still relink the operator's real agent dir. S5c now matches the **drive** (in any env form, and never in prose or an assertion string) and then demands the isolation that command actually needs at each root it writes. Cross-review closed one more ordering hole in that rewrite: a sandbox `export XDG_DATA_HOME` counts as isolation only for drives that come **after** it, so a trailing export can no longer retroactively bless a mutation that already ran against the live state (mutation-checked).
|
|
19
|
+
- **`check-pack-install` no longer leaks into the operator's real XDG roots — and proves it on every return path.** The gate swapped `HOME` per drive but inherited the operator's exported XDG roots, so its `run.sh install` drive wrote a **foreign pi-provider install-state into the real `~/.local/share/entwurf`** and the agy-imprint drive appended fake birth lines to the real `~/.local/state/entwurf/agy-imprint.log` — the same class as the 2026-07-13 hard-verify pollution, one layer deeper: inside `run.sh` itself, where S5/S5b (which scan only `scripts/*.sh`) cannot see. Every sandbox drive now exports `XDG_DATA_HOME`/`XDG_STATE_HOME`/`XDG_CACHE_HOME` alongside `HOME`. Review found the first self-fence was itself too narrow: it ran only on the success tail and fenced DATA while the known leak also touched STATE. The final **outer self-fence** runs after every success or early-failure path, requires the operator's real install-state tree to stay byte-identical, and requires the gate-specific fake agy marker count in the real imprint log not to increase. Dropping a drive's XDG swap is mutation-checked. A separate live audit also disproved the initial “all wiring intact” claim: Claude's XDG marketplace artifact was absent, producing `cache-miss`, no SessionStart records after 08:46, and an honest `🪛 ? cc`; this was a real meta-bridge disconnect, not agy's documented pre-first-turn `?`. Reinstalling the live meta-bridge restored `source=assembled=installed` parity and a fresh Claude probe automatically birthed garden id `20260714T121134-5effc4` (record count 116→117).
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- **Backend drift pins moved, each with an explicit verdict.** agy `1.0 → 1.1` after live re-verification on the new minor (2026-07-14, agy 1.1.0: `entwurf_self` without a permission prompt, bidirectional native-push reply on the same gid, `LIVE=1 smoke-agy-native-push-live` 13/13 — evidence in `DELIVERY.md` §Antigravity). codex `0.136 → 0.144` as an **observed bump, not a re-verification**: codex is not a shipped native-citizen lane in 0.12.x, so the probe evidence stays dated at 0.136.0 and `DELIVERY.md` §Codex now carries the explicit non-reverification verdict; re-run the raw probes before building any codex adapter.
|
|
24
|
+
- **CI now runs the install surface, not just the source tree.** `pnpm check` is a dev-clone floor by construction: every fence bug this repo has shipped was green on it. `check-pack-install` was release-gate-only, so the installed axis had never been in CI at all. It is now its own job (~1 minute), which is what turns "we fixed it" into "it cannot come back".
|
|
25
|
+
- **Verification may not rewire the operator's own installation.** `check-install-surface` S5 flags an offline smoke that writes a live `~/.claude` / `~/.gemini` / `~/.pi` path before swapping the process HOME to a sandbox — or without swapping at all — including one hop of variable aliasing. The current tree is clean (the install smokes all `export HOME` to a sandbox first, and `smoke-resident-garden-guard`'s `rm -rf` targets a `mktemp -d`), so this pins the existing contract rather than fixing a live break. **It is a static tripwire, not a sandbox proof:** it reads shell source, so a path assembled across several variables or built inside an embedded heredoc would slip past it. The real guarantee — running the whole offline floor under a swapped HOME — is recorded in `NEXT.md` as open, not claimed here. S5b (review follow-up) pins the axis the 2026-07-14 pollution actually used: any offline smoke that swaps HOME into a sandbox must swap `XDG_DATA_HOME` with it, because HOME alone still writes real install-state below the inherited XDG root.
|
|
26
|
+
|
|
27
|
+
- **Install/package hygiene guards now seal three post-0.12.6 edges.** Package tarballs exclude Python bytecode residue even though `scripts/` ships as a whole, pack gates serialize the full `npm pack` dist-read window and use per-run tarball destinations, and the user-scope pi package inverse is exposed as explicit `remove-user-scope` with a read-only `--remove --dry-run` preview.
|
|
28
|
+
|
|
7
29
|
## 0.12.6 — 2026-07-03
|
|
8
30
|
|
|
9
31
|
### Fixed
|
package/DELIVERY.md
CHANGED
|
@@ -18,10 +18,11 @@ Companion surfaces:
|
|
|
18
18
|
|
|
19
19
|
## Scope and non-goals
|
|
20
20
|
|
|
21
|
-
This document is about **native live-session delivery**
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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.
|
|
25
26
|
|
|
26
27
|
Non-goals:
|
|
27
28
|
|
|
@@ -94,23 +95,23 @@ When a level is **not applicable** or **conditional**, say so explicitly. For
|
|
|
94
95
|
example, Codex app-server delivery is conditional on a loaded thread and control
|
|
95
96
|
socket; direct Codex TUI is a different surface.
|
|
96
97
|
|
|
97
|
-
## Current capability matrix (2026-
|
|
98
|
+
## Current capability matrix (2026-07-13)
|
|
98
99
|
|
|
99
100
|
This matrix is a snapshot of what the raw probes have established. It should be
|
|
100
101
|
updated when a backend version changes the delivery surface.
|
|
101
102
|
|
|
102
|
-
The **Status** column is the 0.12.
|
|
103
|
-
`D0–D8` capability level:
|
|
103
|
+
The **Status** column is the current 0.12.x release framing, kept separate from
|
|
104
|
+
the `D0–D8` capability level:
|
|
104
105
|
|
|
105
|
-
- **shipped** — a supported
|
|
106
|
-
- **verified-probe** — async delivery proven by a raw probe, but not yet a
|
|
107
|
-
- **deferred** — not addressable as-is, or needs an extra managed install / cloud surface
|
|
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.
|
|
108
109
|
|
|
109
110
|
| Harness / surface | Status | Highest current level | Transport | Notes |
|
|
110
111
|
|---|---|---:|---|---|
|
|
111
|
-
| **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.
|
|
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. `entwurf_v2` treats a record-less but live pi control socket as a socket-only `fire-and-forget` target; record-less *dormant* resume is intentionally not claimed. |
|
|
112
113
|
| **Claude Code interactive 2.1.163** | shipped | D6, D7 partial, D8 partial | Plugin/global `SessionStart` arms `watchPaths`; external write triggers `FileChanged`; `asyncRewake` wakes idle session | Active idle wake proven without pty. `Stop` alone is piggyback-only. `asyncRewake` is a doorbell; body is self-fetched from mailbox. D8 partial: duplicate/read idempotence, honest unread counts, and level-triggered body drain are gated; empirical wake-edge bounds and unread-heartbeat backstop remain open (#34). |
|
|
113
|
-
| **Antigravity / agy** |
|
|
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. |
|
|
114
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. |
|
|
115
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. |
|
|
116
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. |
|
|
@@ -158,8 +159,64 @@ Antigravity reaches the same delivery levels through a different transport:
|
|
|
158
159
|
to make the garden layer backend-specific; it is exactly why the adapter contract
|
|
159
160
|
must describe capability (`D0–D8`) separately from transport.
|
|
160
161
|
|
|
162
|
+
The raw probe (`scripts/raw-async-delivery/raw-agy-send.sh` — the Live-SSOT method
|
|
163
|
+
`pgrep -x agy` + an LS socket that answers `get-conversation-metadata`) is now
|
|
164
|
+
productionized as the **native-push rail**: `pi-extensions/lib/native-push/adapter.ts`
|
|
165
|
+
(full pid/LS scan, volatile route, 1-shot re-probe retry in the executor hand),
|
|
166
|
+
`registerNativeConversation` (bind an already-running conversation as a garden
|
|
167
|
+
citizen; no spawn), the `entwurf_v2` `native-push` transport (post-probe reject
|
|
168
|
+
taxonomy: `native-push-target-dead` / `-probe-indeterminate` / `-no-resume-authority`),
|
|
169
|
+
and the `install-agy-bridge` install adapter. agy is a `native-push` domain, distinct
|
|
170
|
+
from the pi control-socket liveness domain and from the Claude mailbox self-fetch domain.
|
|
171
|
+
|
|
172
|
+
#### agy ambient-status axis (install surface, orthogonal to D0–D8)
|
|
173
|
+
|
|
174
|
+
Beyond delivery, agy carries two more entwurf-owned install surfaces: **ambient
|
|
175
|
+
garden identity in the native statusline** (`entwurf-agy-statusline`) and the
|
|
176
|
+
**`PreInvocation` birth/sender imprint** (`entwurf-agy-imprint`). These are not
|
|
177
|
+
delivery levels — they are install-surface ownership axes with the same discipline
|
|
178
|
+
the delivery rail uses: bare stable bins only (never repo/checkout paths),
|
|
179
|
+
state-backed install/uninstall, element-level adopt-and-preserve with honest
|
|
180
|
+
inverse, symlink refusal, fail-loud doctors, and an honest `?` before identity
|
|
181
|
+
exists.
|
|
182
|
+
|
|
183
|
+
Identity authority is the native `conversationId` looked up against meta-record
|
|
184
|
+
**bodies**. No cwd back-match, filename-derived identity, or gid invention. agy
|
|
185
|
+
has no `SessionStart`; the earliest hook is `PreInvocation`, so a new conversation
|
|
186
|
+
may briefly render `🪛 ? agy`. On the first invocation the installed hook reads
|
|
187
|
+
`conversationId` + `workspacePaths`, calls `upsertMetaSession` idempotently, and
|
|
188
|
+
writes a sender marker only after the record exists. It always returns the neutral
|
|
189
|
+
`{"injectSteps":[]}` response so identity bookkeeping cannot block the agy loop.
|
|
190
|
+
|
|
191
|
+
The marker is keyed by the shared host pid + process start-key and is revalidated
|
|
192
|
+
against the record body. Replyability is `recordBacked ∧ probeAlive`, never
|
|
193
|
+
mailbox `watchArmed`. This supports separate agy processes (measured: three pids,
|
|
194
|
+
three markers) but **not** simultaneous model invocation by two conversations
|
|
195
|
+
under one agy pid: one marker file would be last-writer-wins, so that concurrency
|
|
196
|
+
is explicitly unsupported.
|
|
197
|
+
|
|
198
|
+
Current deterministic floor: `smoke-agy-install-state` 140 checks,
|
|
199
|
+
`smoke-agy-statusline-state` 69, `smoke-agy-hooks-state` 44,
|
|
200
|
+
`check-agy-sender-identity` 28, plus the shared self-address/native-push gates.
|
|
201
|
+
The bridge installer owns only `mcp(entwurf-bridge/entwurf_v2)` in
|
|
202
|
+
`permissions.allow`; broad YOLO policy stays operator-owned. Live 2026-07-13
|
|
203
|
+
(agy 1.0.x): automatic birth → gid/statusline → record-backed sender → sibling
|
|
204
|
+
delivery → same-gid native-push reply passed. Live 2026-07-14 (**agy 1.1.0**):
|
|
205
|
+
re-verified on the new minor — `entwurf_self` answered without a permission
|
|
206
|
+
prompt under the operator's broad allow (gid `20260714T101829-e7fccd`, native
|
|
207
|
+
conversation `21266946-64a6-4a35-a7e5-fc84f0a7f250`), bidirectional native-push
|
|
208
|
+
reply arrived on the same gid, and `LIVE=1 smoke-agy-native-push-live` passed
|
|
209
|
+
13/13; the drift-sentinel agy pin moved to the 1.1 line on this evidence.
|
|
210
|
+
|
|
161
211
|
### Codex — split by launch mode, not by "Codex"
|
|
162
212
|
|
|
213
|
+
> **Version verdict (2026-07-14, 0.12.7 cut):** the installed codex is **0.144.1**;
|
|
214
|
+
> every claim in this section was measured at **0.136.0** and has **NOT been
|
|
215
|
+
> re-verified** since. Codex is not a shipped native-citizen lane in 0.12.x, so the
|
|
216
|
+
> drift-sentinel pin moved to the 0.144 line with this explicit non-reverification
|
|
217
|
+
> verdict instead of a fresh probe run. Re-run the raw probes (and re-date the matrix
|
|
218
|
+
> rows) before building any codex adapter on the new line.
|
|
219
|
+
|
|
163
220
|
Do not describe "Codex" as one delivery shape. The split is the TUI's launch mode:
|
|
164
221
|
|
|
165
222
|
- **standalone Embedded TUI**: binds no socket, no `FileChanged`/`asyncRewake` in
|
|
@@ -181,7 +238,7 @@ not addressability.
|
|
|
181
238
|
|
|
182
239
|
A Codex adapter must declare which launch mode + which socket it targets.
|
|
183
240
|
|
|
184
|
-
## How to use this in 0.12.
|
|
241
|
+
## How to use this in the current 0.12.x design
|
|
185
242
|
|
|
186
243
|
For meta-sessions, peer records should expose capability rather than hiding
|
|
187
244
|
backend differences:
|
|
@@ -192,7 +249,7 @@ type WakeMode = "socket" | "file-watch" | "native-push" | "app-server" | "piggyb
|
|
|
192
249
|
type DeliveryPeer = {
|
|
193
250
|
sessionId: string; // garden id
|
|
194
251
|
kind: "pi-session" | "meta-session";
|
|
195
|
-
backend: "pi" | "claude-code" | "
|
|
252
|
+
backend: "pi" | "claude-code" | "antigravity" | "codex" | string;
|
|
196
253
|
replyable: boolean;
|
|
197
254
|
wakeMode: WakeMode;
|
|
198
255
|
deliveryLevel: "D0" | "D1" | "D2" | "D3" | "D4" | "D5" | "D6" | "D7" | "D8";
|