@junghanacs/entwurf 0.40.0 → 0.41.1
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 +4 -2
- package/BASELINE.md +55 -2
- package/CHANGELOG.md +562 -0
- package/CONTRIBUTING.md +1 -1
- package/DELIVERY.md +18 -2
- package/FAQ.md +8 -4
- package/README.md +60 -45
- package/VERIFY.md +14 -11
- package/demo/README.md +1 -1
- package/docs/acp-backend-rail.md +6 -2
- package/docs/external-mcp-host.md +8 -6
- package/docs/fresh-cut-policy.md +9 -1
- package/docs/setup-clean-host.md +76 -20
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +81 -19
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/cc-retire-pidfd.py +236 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/cc-retire-request.js +473 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/control-retire.js +125 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-retire-production.js +149 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-retire.js +158 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +2 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-visible-resume.js +283 -20
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +7 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-dispatch.js +47 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-fresh-call.js +3 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +96 -16
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +5 -29
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-launch.js +28 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-resume-call.js +26 -11
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-retire-request.js +76 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/resume-launch-identity.js +67 -17
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/retirement-event.js +211 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook.js +124 -10
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-pi-durable.js +53 -2
- package/mcp/entwurf-bridge/dist/scripts/meta-facts.js +1 -1
- package/mcp/entwurf-bridge/dist/scripts/probe-bridge-command.js +1 -0
- package/mcp/entwurf-bridge/src/index.ts +93 -19
- package/mcp/entwurf-bridge/test.sh +2 -2
- package/mcp/entwurf-bridge/tsconfig.build.json +10 -1
- package/package.json +15 -14
- package/pi/meta-bridge/entwurf-meta-receive/scripts/hook-launch.sh +3 -3
- package/pi/pi-durable/carrier/tui.js +18 -3
- package/pi/pi-durable/overlay/upstream-pin.json +12 -12
- package/pi-extensions/entwurf-control.ts +55 -20
- package/pi-extensions/lib/acp/backend-adapter.ts +5 -3
- package/pi-extensions/lib/acp/backend.ts +12 -9
- package/pi-extensions/lib/cc-retire-pidfd.py +236 -0
- package/pi-extensions/lib/cc-retire-request.ts +553 -0
- package/pi-extensions/lib/control-retire.ts +195 -0
- package/pi-extensions/lib/entwurf-control-rpc.ts +17 -1
- package/pi-extensions/lib/entwurf-v2-retire-production.ts +227 -0
- package/pi-extensions/lib/entwurf-v2-retire.ts +269 -0
- package/pi-extensions/lib/entwurf-v2-surface.ts +2 -1
- package/pi-extensions/lib/entwurf-v2-visible-resume.ts +390 -36
- package/pi-extensions/lib/fresh-call-composition.ts +15 -0
- package/pi-extensions/lib/fresh-call-dispatch.ts +45 -4
- package/pi-extensions/lib/herdr-fresh-call.ts +5 -0
- package/pi-extensions/lib/meta-session.ts +140 -16
- package/pi-extensions/lib/mux-fresh-call.ts +7 -27
- package/pi-extensions/lib/mux-launch.ts +29 -0
- package/pi-extensions/lib/mux-resume-call.ts +33 -12
- package/pi-extensions/lib/pi-retire-request.ts +111 -0
- package/pi-extensions/lib/resume-launch-identity.ts +104 -18
- package/pi-extensions/lib/retirement-event.ts +253 -0
- package/pi-extensions/meta-bridge-hook.ts +142 -13
- package/pi-extensions/meta-bridge-pi-durable.ts +57 -3
- package/run.sh +123 -34
- package/scripts/agy-bridge-config.py +4 -1
- package/scripts/build-bridge.sh +14 -0
- package/scripts/check-capability-bundle-reach.ts +135 -2
- package/scripts/check-entwurf-bridge-boot.ts +2 -1
- package/scripts/check-entwurf-fact-provider.ts +1 -0
- package/scripts/check-entwurf-v2-production.ts +2 -0
- package/scripts/check-entwurf-v2-surface.ts +7 -0
- package/scripts/check-gate-qualification.ts +14 -8
- package/scripts/check-herdr-activation.ts +2 -2
- package/scripts/check-herdr-placement.ts +1 -0
- package/scripts/check-hook-launch-topology.ts +6 -15
- package/scripts/check-install-container.sh +2 -2
- package/scripts/check-meta-doctor-oracle.sh +27 -1
- package/scripts/check-meta-facts.ts +8 -3
- package/scripts/check-meta-hook-session-switch.ts +230 -13
- package/scripts/check-meta-identity-consumers.ts +1 -0
- package/scripts/check-meta-listing.ts +1 -0
- package/scripts/check-meta-manifest-schema.py +1 -1
- package/scripts/check-meta-session.ts +31 -0
- package/scripts/check-meta-v3-record.ts +55 -1
- package/scripts/check-mux-resume-call.ts +35 -9
- package/scripts/check-peer-facts.ts +1 -0
- package/scripts/check-pi-durable-contact.ts +3 -1
- package/scripts/check-pi-durable-send.ts +4 -2
- package/scripts/check-pi-mcp-bridge.ts +1 -0
- package/scripts/check-resume-launch-identity.ts +62 -23
- package/scripts/lib/codex-fresh-live-protocol.ts +3 -2
- package/scripts/lib/meta-hook-bundle.ts +72 -0
- package/scripts/meta-bridge-claude-floor.sh +13 -9
- package/scripts/meta-bridge-doctor.sh +17 -0
- package/scripts/meta-bridge-install.sh +6 -0
- package/scripts/meta-facts.ts +1 -1
- package/scripts/mutants/bridge-boot-resume.json +5 -2
- package/scripts/mutants/cc-retire-pidfd.json +129 -0
- package/scripts/mutants/cc-retire-request.json +171 -0
- package/scripts/mutants/control-retire.json +105 -0
- package/scripts/mutants/control-send-receipt.json +1 -1
- package/scripts/mutants/copilot-receive.json +2 -6
- package/scripts/mutants/entwurf-v2-retire.json +476 -0
- package/scripts/mutants/fresh-call-dispatch.json +37 -0
- package/scripts/mutants/meta-hook-session-switch.json +88 -0
- package/scripts/mutants/meta-identity.json +57 -0
- package/scripts/mutants/mux-fresh-call.json +1 -1
- package/scripts/mutants/mux-resume-call.json +40 -4
- package/scripts/mutants/pack-install.json +4 -4
- package/scripts/mutants/pi-durable.json +139 -0
- package/scripts/mutants/pi-floor.json +5 -5
- package/scripts/mutants/pi-retire-request.json +72 -0
- package/scripts/mutants/resume-launch-identity.json +35 -8
- package/scripts/mutants/retirement-event.json +195 -0
- package/scripts/mutants/v2-surface.json +16 -0
- package/scripts/mutants/v2-visible-resume.json +283 -13
- package/scripts/probe-bridge-command.ts +1 -0
- package/scripts/smoke-agy-install-state.sh +2 -2
- package/scripts/smoke-codex-fresh-live.ts +2 -1
- package/scripts/smoke-copilot-mcp-state.sh +1 -1
- package/scripts/smoke-herdr-raw-install-live.sh +15 -7
- package/scripts/smoke-meta-install-state.sh +4 -4
- package/scripts/smoke-mux-lifecycle-live.ts +10 -10
- package/scripts/smoke-omp-mcp-state.sh +1 -1
- package/scripts/smoke-pi-durable-fresh-live.ts +5 -3
- package/scripts/smoke-pi-provider-state.sh +3 -3
package/FAQ.md
CHANGED
|
@@ -8,7 +8,7 @@ No. Entwurf is closer to a workshop than a factory: it connects independently ow
|
|
|
8
8
|
|
|
9
9
|
## What does Entwurf do?
|
|
10
10
|
|
|
11
|
-
It opens, reopens and messages visible sibling sessions across independent harnesses, each under a stable **garden id**. `entwurf_fresh_call` opens a new sibling in the caller's Herdr workspace or tmux session by default, `entwurf_resume_call` reopens a dormant pi sibling under the same id, and `entwurf_v2` delivers a message, reply or hand-off to an existing one through the rail it actually supports. It does not reconstruct prompts, hydrate transcripts, manage credentials, or emulate another harness.
|
|
11
|
+
It opens, reopens and messages visible sibling sessions across independent harnesses, each under a stable **garden id**. `entwurf_fresh_call` opens a new sibling in the caller's Herdr workspace or tmux session by default, `entwurf_resume_call` reopens a dormant pi or Claude Code sibling under the same id, and `entwurf_v2` delivers a message, reply or hand-off to an existing one through the rail it actually supports. It does not reconstruct prompts, hydrate transcripts, manage credentials, or emulate another harness.
|
|
12
12
|
|
|
13
13
|
## What is a garden id?
|
|
14
14
|
|
|
@@ -24,15 +24,19 @@ The visible top-level session is the garden principal. Internal children remain
|
|
|
24
24
|
|
|
25
25
|
## Does sending a message start a process?
|
|
26
26
|
|
|
27
|
-
No. [`entwurf_v2`](./README.md#entwurf_v2--canonical-dispatch-verb) only addresses an existing garden citizen and selects its supported delivery rail. `entwurf_fresh_call` opens a new visible sibling; `entwurf_resume_call` reopens a dormant pi citizen under the same id.
|
|
27
|
+
No. [`entwurf_v2`](./README.md#entwurf_v2--canonical-dispatch-verb) only addresses an existing garden citizen and selects its supported delivery rail. `entwurf_fresh_call` opens a new visible sibling; `entwurf_resume_call` reopens a dormant pi or Claude Code citizen under the same id.
|
|
28
|
+
|
|
29
|
+
## Can an agent retire a sibling on its own?
|
|
30
|
+
|
|
31
|
+
No. `entwurf_retire_call` (new in 0.41.0) attempts retirement of one Pi or Claude Code sibling, and only one the human operator explicitly requested. Seeing the tool, a coordinator role or the caller's identity is not permission; where a host provides an approval step it applies too, and Pi and pi-durable 1.3.0 have none by default. The configured Claude ACP child is also [set to run without per-call permission prompts](./docs/acp-backend-rail.md#configured-claude-acp-permissions); that is source configuration, not measured ACP retirement. The record stays, so `entwurf_resume_call` can reopen the same id, and an unknown result is never a reason to retry.
|
|
28
32
|
|
|
29
33
|
## Where do visible siblings open?
|
|
30
34
|
|
|
31
|
-
Inside Herdr, Entwurf opens a new unfocused tab in the caller's workspace and currently admits pi and Claude Code. Outside Herdr, it opens one of the fixed pi, pi-durable, Claude Code, Copilot, OMP, or Codex runtimes in a new window of the caller's tmux session, or of an existing session the caller names; without an explicit tmux placement, a Codex caller opens beside its own TUI pane. A dormant pi sibling reopens under the same id in a visible tmux window. The runtime keeps its own model, tools, authentication, and transcript.
|
|
35
|
+
Inside Herdr, Entwurf opens a new unfocused tab in the caller's workspace and currently admits pi and Claude Code. Outside Herdr, it opens one of the fixed pi, pi-durable, Claude Code, Copilot, OMP, or Codex runtimes in a new window of the caller's tmux session, or of an existing session the caller names; without an explicit tmux placement, a Codex caller opens beside its own TUI pane. A dormant pi or Claude Code sibling reopens under the same id in a visible tmux window. The runtime keeps its own model, tools, authentication, and transcript.
|
|
32
36
|
|
|
33
37
|
## Does Entwurf replace Herdr or tmux?
|
|
34
38
|
|
|
35
|
-
No. Herdr and tmux provide visible seats. Entwurf opens siblings into them, reopens dormant pi siblings, and carries identity, delivery, and receipts across independent harness sessions. A pane or tmux session is a location for a sibling, never its address or liveness proof.
|
|
39
|
+
No. Herdr and tmux provide visible seats. Entwurf opens siblings into them, reopens dormant pi or Claude Code siblings, and carries identity, delivery, and receipts across independent harness sessions. A pane or tmux session is a location for a sibling, never its address or liveness proof.
|
|
36
40
|
|
|
37
41
|
## How do I install it?
|
|
38
42
|
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# entwurf
|
|
2
2
|
|
|
3
3
|
`entwurf` connects independent agent harnesses as visible siblings: open a new session,
|
|
4
|
-
reopen a dormant
|
|
4
|
+
reopen a supported dormant sibling in tmux, or reach an existing sibling by **garden id**. Fresh
|
|
5
5
|
sessions open in the caller's Herdr workspace or tmux session by default; explicit tmux
|
|
6
6
|
placement can name another existing session. Each harness keeps its own runtime,
|
|
7
7
|
authentication, tools and transcript.
|
|
@@ -26,7 +26,8 @@ Git branches, worktrees, file isolation and internal delegation remain their con
|
|
|
26
26
|
| Verb | Tool | Where it lands | Harnesses |
|
|
27
27
|
|---|---|---|---|
|
|
28
28
|
| **Open** a new sibling | `entwurf_fresh_call` | Herdr: a new unfocused tab in the caller's workspace. tmux: a new window in the caller's session, or an existing session named by `placement.tmuxSession`; without an explicit tmux placement, a Codex caller opens beside its own TUI pane | Herdr: pi, Claude Code. tmux: pi, pi-durable, Claude Code, Copilot, OMP, Codex |
|
|
29
|
-
| **Reopen** a dormant sibling | `entwurf_resume_call` | A visible tmux window under the same garden id, with the transcript
|
|
29
|
+
| **Reopen** a dormant sibling | `entwurf_resume_call` | A visible tmux window under the same garden id, with its record selecting the native session (Pi: identity-checked recorded transcript supplies launch metadata; Claude Code: `claude --resume <session id>` at the record cwd); the verb submits no prompt | pi, Claude Code |
|
|
30
|
+
| **Retire** one sibling the human operator explicitly requested | `entwurf_retire_call` | One guarded attempt on that target: a Pi shutdown request or Claude Code fd-pinned process termination. Refused/unknown outcomes remain possible; the record stays for guarded same-id return. Not a grant, a roster cleanup or an automatic retry | pi, Claude Code |
|
|
30
31
|
| **Message** an existing sibling | `entwurf_v2` | Its own rail: control socket, self-fetch mailbox or native push; delivery starts no process | pi, pi-durable, Claude Code, Copilot, OMP, Antigravity, Codex |
|
|
31
32
|
|
|
32
33
|
Antigravity is message-only: an existing conversation registers itself, and Entwurf never
|
|
@@ -53,15 +54,26 @@ ownership of the harness.
|
|
|
53
54
|
|
|
54
55
|
Prerequisites: **Node >=24.0.0**, Python 3 for `setup`, and any harnesses you choose
|
|
55
56
|
to use, already installed and authenticated. Pi is optional-by-presence, supported
|
|
56
|
-
range `>=1.
|
|
57
|
+
range `>=1.4.0 <1.5`; Claude Code supported floor `>=2.1.306` is required for its
|
|
57
58
|
managed exec-hook lifecycle. pnpm is needed only for source-checkout setup.
|
|
58
59
|
|
|
60
|
+
**Release state.** The Pi range above belongs to this source candidate, which moves the Pi SDK
|
|
61
|
+
set to 1.4.0 and is **not published to npm yet**. The newest published package, `0.41.0`,
|
|
62
|
+
ships the Pi 1.3.0 SDK set and requires Pi 1.3.x; the README inside that tarball and the Herdr
|
|
63
|
+
snapshot `v2026.10.22-herdr.0.41.0` are its contract. Pick the path that matches the Pi you run.
|
|
64
|
+
|
|
65
|
+
The published package (Pi 1.3.x):
|
|
66
|
+
|
|
59
67
|
```bash
|
|
60
|
-
npm install -g @junghanacs/entwurf
|
|
68
|
+
npm install -g @junghanacs/entwurf@0.41.0
|
|
61
69
|
entwurf setup /path/to/your-project
|
|
62
70
|
entwurf check-bridge
|
|
63
71
|
```
|
|
64
72
|
|
|
73
|
+
This candidate (Pi 1.4): a source checkout of this commit, set up with `./run.sh setup` as
|
|
74
|
+
[Clean-host setup](./docs/setup-clean-host.md) describes. It has no npm install command until it
|
|
75
|
+
is released.
|
|
76
|
+
|
|
65
77
|
`setup` composes each harness it finds and reports PASS / SKIP / FAIL. An absent
|
|
66
78
|
harness is an explicit SKIP; a detected incomplete/below-floor integration is a
|
|
67
79
|
named FAIL with nonzero exit, not a false green. `check-bridge` proves the installed
|
|
@@ -75,27 +87,18 @@ consent: [the operator steps](./docs/setup-clean-host.md#three-operator-decision
|
|
|
75
87
|
Plain MCP registration alone does not make a garden citizen.
|
|
76
88
|
|
|
77
89
|
**Platform bounds:** Linux is the certified harness-rail axis. macOS Entwurf-only
|
|
78
|
-
installation is **CERTIFIED (CI)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
0.39.0 (published to npm); 0.38.1 and earlier carry no Windows addon. On a GitHub Actions
|
|
86
|
-
`windows-2025` x64 runner with Node 24.18.1 and Pi 1.3.0, a CI-built artifact was installed,
|
|
87
|
-
wired with `pi install`, birthed two Pi citizens and
|
|
88
|
-
delivered one garden-id `entwurf_v2` message between them, with an offline scripted model
|
|
89
|
-
and no vendor turn. Every other native-Windows surface (other harnesses, `setup` and the
|
|
90
|
-
`.sh` bins, fresh/resume, mux/Herdr/ACP, physical machines) is **not declared**; the
|
|
91
|
-
measured scope and its named gaps are in [BASELINE](./BASELINE.md#release-host-baseline).
|
|
92
|
-
The package has no npm `os` restriction; that is not certification of every platform's
|
|
93
|
-
harness rails.
|
|
90
|
+
installation is **CERTIFIED (CI)**; native harness rails, ACP and mux remain
|
|
91
|
+
**NOT CERTIFIED — pending physical host**, so detected wiring can still leave setup non-green.
|
|
92
|
+
WSL2 and native Windows have **experimental CI previews**, not general or physical-host support.
|
|
93
|
+
The native-Windows preview covers Pi citizens and offline scripted delivery, not vendor turns,
|
|
94
|
+
other harnesses, shell entrypoints, fresh/resume, mux, Herdr or ACP.
|
|
95
|
+
[BASELINE](./BASELINE.md#release-host-baseline) owns the version-specific receipts and gaps;
|
|
96
|
+
an npm package without an `os` restriction is not an all-platform certification.
|
|
94
97
|
|
|
95
98
|
### Native durable (pi-durable)
|
|
96
99
|
|
|
97
|
-
**
|
|
98
|
-
members
|
|
100
|
+
**This candidate's package supplies Entwurf's owned app/TUI carrier and nine exact Pi 1.4.0 SDK
|
|
101
|
+
members** (unpublished; the published 0.41.0 supplies the 1.3.0 set). No separate runtime checkout, patch, build or ordinary Pi CLI is needed.
|
|
99
102
|
The launch verifies carrier integrity and every reachable SDK edge's name/version;
|
|
100
103
|
incomplete, drifted or mixed supply refuses by name.
|
|
101
104
|
|
|
@@ -105,7 +108,7 @@ entwurf pi-durable --continue
|
|
|
105
108
|
entwurf pi-durable --resume
|
|
106
109
|
```
|
|
107
110
|
|
|
108
|
-
`--continue` opens this directory's
|
|
111
|
+
`--continue` opens this directory's latest-created durable session. `--resume` lists its
|
|
109
112
|
sessions, most recently written first, by creation time, garden id and last write, and
|
|
110
113
|
reopens the one you choose as it was saved; a cancelled choice opens nothing.
|
|
111
114
|
|
|
@@ -116,20 +119,23 @@ SQLite, transcripts and recovery remain the upstream SDK's:
|
|
|
116
119
|
|
|
117
120
|
Optional `--native-module <absolute file>` initializes trusted ESM before runtime/TUI
|
|
118
121
|
imports, then installs its default native Extension after the contact.
|
|
119
|
-
`--native-module-dir <absolute directory>`
|
|
120
|
-
|
|
121
|
-
background-task badge on screen at any terminal size. No automatic module discovery or
|
|
122
|
+
`--native-module-dir <absolute directory>` loads that named directory's top-level
|
|
123
|
+
`*.extension.mjs` files in byte-wise order instead. No automatic module discovery or
|
|
122
124
|
classic Pi API shim; guards are not a sandbox or rollback.
|
|
123
|
-
Ordinary Pi's known `peerDependencies` warning reflects the separate native SDK supply.
|
|
124
125
|
[Native setup](./docs/setup-clean-host.md#2b-optional-native-durable-pi-durable)
|
|
125
126
|
owns flags, refusals and the extension contract.
|
|
126
127
|
|
|
127
128
|
### Herdr workbench
|
|
128
129
|
|
|
129
130
|
```bash
|
|
130
|
-
herdr plugin install junghan0611/entwurf/plugins/herdr --yes
|
|
131
|
+
herdr plugin install junghan0611/entwurf/plugins/herdr --ref "$CANDIDATE_REF" --yes
|
|
131
132
|
```
|
|
132
133
|
|
|
134
|
+
Set `CANDIDATE_REF` explicitly to a published branch or tag that carries the runtime you mean;
|
|
135
|
+
these examples do not select a candidate from Herdr's default ref. A validation branch is not a
|
|
136
|
+
release acceptance. The [Herdr guide](./plugins/herdr/README.md#from-a-raw-linux-box-in-nine-steps)
|
|
137
|
+
says which runtime each ref installs.
|
|
138
|
+
|
|
133
139
|
This separate path activates Herdr-integrated **pi and Claude Code** with an
|
|
134
140
|
independently locked runtime and an observation pane; it puts no Entwurf bins on PATH.
|
|
135
141
|
An Entwurf release does not automatically re-pin that runtime.
|
|
@@ -168,9 +174,11 @@ In that **harness session**, ask the agent to:
|
|
|
168
174
|
```
|
|
169
175
|
|
|
170
176
|
These are tools, not shell subcommands. Pi calls
|
|
171
|
-
`mcp__entwurf_bridge__<verb>` through Pi's built-in MCP. The
|
|
172
|
-
verbs; a pi citizen has **
|
|
177
|
+
`mcp__entwurf_bridge__<verb>` through Pi's built-in MCP. The bridge exposes **nine**
|
|
178
|
+
verbs; a pi citizen has **seven active + two hidden** (`entwurf_inbox_read` and
|
|
173
179
|
`entwurf_register_native`), since it has no mailbox and its own extension births it.
|
|
180
|
+
Those counts describe the source; a running host offers what its already-loaded bridge
|
|
181
|
+
listed, so see [applying new source to a running host](./docs/setup-clean-host.md#applying-new-source-to-a-running-host).
|
|
174
182
|
The server key stays `entwurf-bridge`. An operator/trusted-project MCP entry with
|
|
175
183
|
that normalized namespace can replace the registration by Pi's own precedence;
|
|
176
184
|
`/mcp` shows it, and Entwurf does not scan or fight that choice.
|
|
@@ -195,7 +203,16 @@ pi / pi-durable / Claude Code / Copilot / OMP / Antigravity / Codex
|
|
|
195
203
|
|---|---|---|
|
|
196
204
|
| Message, reply or hand off to an existing garden id | `entwurf_v2 {target, intent:"fire-and-forget", message}` | Receiver acceptance boundary, mailbox enqueue or native injection; not completion |
|
|
197
205
|
| Open a new visible sibling | `entwurf_fresh_call {backend, model, task, cwd?}` | Launch receipt only; the sibling's nonce callback envelope supplies its new garden id |
|
|
198
|
-
| Reopen a dormant pi citizen under its own id | `entwurf_resume_call {target}` | Separate LAUNCH and
|
|
206
|
+
| Reopen a dormant pi or Claude Code citizen under its own id | `entwurf_resume_call {target}` | Separate LAUNCH and OBSERVATION receipts (pi: same-id socket; Claude Code: a new live receiver marker in the opened pane, bound to the record); the verb submits no prompt |
|
|
207
|
+
| Attempt retirement of one explicitly requested Pi or Claude Code target | `entwurf_retire_call {target}` | Separate action, append-only record and lock-release results. Pi ACK is request-only; CC exit is that fd-pinned process only |
|
|
208
|
+
|
|
209
|
+
**Retirement is never autonomous.** It requires the human operator's explicit target/action;
|
|
210
|
+
a role, caller identity or tool annotation grants no permission. Host approval applies where
|
|
211
|
+
provided or configured. No roster expansion, timer or retry of an unknown/cancelled/lost result;
|
|
212
|
+
an absent event is unknown, not proof that no action occurred.
|
|
213
|
+
[DELIVERY](./DELIVERY.md#candidate-lifecycle-commands-are-not-delivery-boundaries-147)
|
|
214
|
+
owns the lifecycle boundaries; [BASELINE](./BASELINE.md#147-native-round-trip-2026-10-22-n1)
|
|
215
|
+
keeps dated native evidence separate from release and rollout acceptance.
|
|
199
216
|
|
|
200
217
|
**Delivery starts no process.** A live pi receives over its record-addressed control
|
|
201
218
|
address (a Unix socket; on the experimental native-Windows Pi preview, a named pipe);
|
|
@@ -214,20 +231,18 @@ is a live rail fact, not merely a consequence of trusted identity.
|
|
|
214
231
|
|
|
215
232
|
**One declared remote pair (opt-in, #107).** The operator places an `entwurf-remote-pair.json` on each of two hosts. Then `entwurf_v2` to the declared remote garden id runs the other host's `entwurf remote-pair-receive` once over the operator's own SSH, and that host checks the pair and dispatches locally. The trust is the same operator's SSH account. It makes one attempt with no retry, and it uses no relay or listener. [DELIVERY](./DELIVERY.md#remote-pair-107-one-declared-pair-across-two-hosts) owns the contract; [setup](./docs/setup-clean-host.md#2c-optional-remote-pair-between-two-hosts-107) covers the operator steps.
|
|
216
233
|
|
|
217
|
-
**Mux launches; it never delivers.**
|
|
218
|
-
in the
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
tmux
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
Exact boundaries: [tmux launch](https://github.com/junghan0611/entwurf/blob/main/docs/mux-launch-rail.md)
|
|
230
|
-
and [Herdr launch](https://github.com/junghan0611/entwurf/blob/main/docs/herdr-launch-rail.md).
|
|
234
|
+
**Mux launches; it never delivers.** Fresh uses the caller's Herdr workspace or tmux server,
|
|
235
|
+
within the harness limits in the table above. The model is required; optional `cwd` is a literal
|
|
236
|
+
absolute directory (omitted or empty means caller cwd). `placement.tmuxSession` names an
|
|
237
|
+
existing tmux session, never a new session or a cwd lookup, and is refused inside Herdr.
|
|
238
|
+
Without that override, a Codex caller opens beside its thread-id-matched TUI pane;
|
|
239
|
+
other callers use their own session. Missing or ambiguous context refuses without fallback.
|
|
240
|
+
Resume is tmux-only for pi and Claude Code, selected by the record, with no submitted prompt.
|
|
241
|
+
Claude Code dormancy covers only attaches its hook committed, not every possible session holder;
|
|
242
|
+
[V3 arm binding](./docs/adding-a-harness.md#arm-binding-within-v3) is not occupancy or permission.
|
|
243
|
+
An unobserved window stays visible without retry. Address liveness alone is not conversation recall.
|
|
244
|
+
Exact argv, identity checks and limits belong to [tmux launch](./docs/mux-launch-rail.md)
|
|
245
|
+
and [Herdr launch](./docs/herdr-launch-rail.md).
|
|
231
246
|
|
|
232
247
|
## Concepts
|
|
233
248
|
|
package/VERIFY.md
CHANGED
|
@@ -5,7 +5,7 @@ invariants live in gates; this file defines evidence strength, release acceptanc
|
|
|
5
5
|
and the manual judgements a gate cannot make.
|
|
6
6
|
|
|
7
7
|
> **Current surface.** `entwurf-bridge` exposes `entwurf_v2`, `entwurf_peers`,
|
|
8
|
-
> `entwurf_fresh_call`, `entwurf_resume_call`, `entwurf_callback`, `entwurf_self`, `entwurf_inbox_read`, and `entwurf_register_native
|
|
8
|
+
> `entwurf_fresh_call`, `entwurf_resume_call`, `entwurf_retire_call` (0.41.0; operator-requested target only), `entwurf_callback`, `entwurf_self`, `entwurf_inbox_read`, and `entwurf_register_native` — nine; a pi citizen offers seven with two hidden, the pi-durable contact eight. The ACP
|
|
9
9
|
> backends are Claude and Snowflake Cortex Code. Antigravity is a separate shipped
|
|
10
10
|
> native-push citizen lane. Codex is a native-push citizen supported in 0.21.0, whose birth hook is
|
|
11
11
|
> operator-owned and gated on one vendor trust receipt, with strict request-scoped identity and
|
|
@@ -105,7 +105,7 @@ that moved out of `scripts/` and into a file beside its subject would otherwise
|
|
|
105
105
|
|
|
106
106
|
> **The herdr rail is an on-demand axis until it has run.** `smoke-herdr-fresh-call-live` opens a real caller inside a real herdr pane, has it invoke the PUBLIC `entwurf_fresh_call`, and reads the child's nonce callback — the one axis no deterministic gate reaches, since the rail is selected from the caller's own process environment. **The release aggregate does not yet require the herdr rail**: herdr is optional (a cut on a host without it must not block), and first evidence precedes promotion — a rail whose first acceptance run is days old has not earned a place in the gate that blocks every cut. Run it directly with `LIVE=1 ./run.sh smoke-herdr-fresh-call-live` whenever a cut changes herdr rail code, and promote it to a MUST only after the axis has a run history to point at. Without `LIVE=1`, or without herdr/pi/claude on PATH, it reports protocol SKIP — never a pass.
|
|
107
107
|
|
|
108
|
-
> **The plugin's FIRST USER PATH is its own on-demand axis, and an npm acquisition receipt holds only for the ref it ran on (#118 홉 1).** Every other herdr gate proves the plugin against a source this repository controls: `check-herdr-plugin-build` drives a stub, and `smoke-herdr-plugin-build-live` redirects the product remote to a local bare clone with git `insteadOf` and asserts `identity.kind === "herdr-checkout"`. npm has been the production authority class since `dd84ac0`; the 0.30.0 follow-up re-pinned `@junghanacs/entwurf@0.30.0` with its published sha512 after the candidate windows rode `herdr-checkout` (`8b92e09`), and the 0.30.1 preparation rode that closed verification carrier again without inventing a registry integrity. The plugin snapshot `v2026.10.9-herdr.0.34.0` pinned the published `@junghanacs/entwurf@0.34.0` with its measured sha512 (#132); 0.31–0.33 were never pinned. The 0.34.1 preparation rode the closed `herdr-checkout` verification carrier again without inventing a registry integrity, and the snapshot `v2026.10.9-herdr.0.34.1` re-pins the published `@junghanacs/entwurf@0.34.1` with its measured sha512 (#135). The 0.34.2 preparation rode the same carrier, and the snapshot `v2026.10.11-herdr.0.34.2` re-pins the published `@junghanacs/entwurf@0.34.2` with its measured sha512 (#136). The source re-proof has separate dated npm rows: 2026-09-23 public `main=113ca53`, plugin 0.5.0, runtime 0.25.0 (CHANGELOG 0.25.1), and the 0.30.0 re-pin accepted at public `506c46f` in the [#126 thread](https://github.com/junghan0611/entwurf/issues/126). Neither certifies the 0.34.0 registry acquisition. That pin's real-npm swap / torn-swap recovery was measured locally on 2026-10-09 by driving the registry-shipped `scripts/herdr-runtime.mjs` (byte-equal to this checkout's) with its own npm acquisition: a 0.33.0 → 0.34.0 swap, and the same upgrade torn between its two renames then resumed, where the last-good 0.33.0 tree was restored before 0.34.0 was acquired again. Both ended `runtime-ready` at observed digest `sha256-e9d995ff…`, the accepted 0.34.0 artifact. That local receipt is recorded in the [#132 thread](https://github.com/junghan0611/entwurf/issues/132); it covers runtime recovery, not this smoke's cells. This smoke's public-ref acceptance of the 0.34.0 pin was measured locally at `--ref main`: PASS at resolved `b5d15d8` and again at the docs follow-up `8ed4d1a`, each acquiring `kind=npm @junghanacs/entwurf@0.34.0` — a main-ref receipt, not a tag-ref, native or full-Herdr claim. The 0.34.1 re-pin's npm-source rows — swap / torn-swap recovery, this smoke at a public ref, and the package consumer — are its own, recorded with that pin and never inherited from 0.34.0; checkout candidate evidence does not transfer. The 0.36.0 re-pin's public-ref row was measured on Herdr 0.9.4 at `--ref main`: PASS at resolved `9f33dd1`, acquiring `kind=npm @junghanacs/entwurf@0.36.0` at the accepted digest — a main-ref receipt, not a tag-ref claim. Its version-changing cross-ref reinstall (`herdr plugin install … --ref main` over the `v2026.10.13-herdr.0.35.1` installation) across a pinned Pi upgrade was a driver-level journey recorded in that snapshot's release notes, not a row of this smoke; `herdr plugin update` there was measured only as a same-ref already-up-to-date no-op. `LIVE=1 ./run.sh smoke-herdr-raw-install-live [--ref <REF>]` fills that row in a clean `node:24` container with no socket, config, cache or repo mounted, no `insteadOf`, the public remote spelled as a user would type it, and pi / herdr / Claude Code installed in the IMAGE BUILD as scaffolding (Hard Rule 17 — the product face begins at `herdr integration install pi`). herdr itself comes from `scripts/install-herdr-ci.sh` against `scripts/fixtures/herdr-supply.json`, so no version or digest lives here. `--ref` defaults to `main` rather than a pinned SHA because receipt (a) is defined as what a user gets today; the resolved commit is printed, so the receipt stays exact. It takes a REMOTE REF and not an arbitrary commit — measured on herdr 0.9.1, `--ref <sha>` fails as `couldn't find remote ref`, because the checkout fetches by name — so a candidate is addressed by its branch and pinned by the resolved commit the gate prints. **Its first question is a measurement, not an assumption:** herdr registers a plugin through a running server and falls back to `persist_plugin_offline` only on a connection error (`src/cli/plugin.rs:914-981,1016-1021` @ `c77af189`, 0.9.0 source), and a container has no server. The 2026-09-23 PASS installed with no server on the 0.9.1 binary `113ca53`'s `herdr-supply.json` pins, so that install path worked on 0.9.1 — inferred from the PASS, not a direct observation of the fallback branch; a later "no" on another herdr is #118 investigation output rather than a completion. `--yes` is always passed so a non-interactive exit 2 (`:189`) can never be misread as a missing server. **At a ref whose lock names `herdr-checkout` the acquisition axis reports a NAMED SKIP rather than a red, and the rest of the journey still runs.** That lock is the candidate carrier a cut legitimately sits on — 0.23.0 was tagged that way and `dd84ac0` pinned npm afterwards — so a red there would report a broken install when what is true is that the ref does not lock npm. What is asserted at BOTH lock kinds is that the runtime came from the source the ref locks, and the package name is read from the checkout manifest rather than the lock, because a `herdr-checkout` lock carries no `name` (`herdr-runtime.mjs:317-328`) and joining `undefined` throws instead of failing an assertion. **Cells [6]–[9] carry it past the install into the USE path (#118 H1-4/H1-5).** An install is not a use, so the same container then runs what those bytes became: the compiled bridge entry, the three `REQUIRED_BINS` as executables, and a real `entwurf check-bridge` printing
|
|
108
|
+
> **The plugin's FIRST USER PATH is its own on-demand axis, and an npm acquisition receipt holds only for the ref it ran on (#118 홉 1).** Every other herdr gate proves the plugin against a source this repository controls: `check-herdr-plugin-build` drives a stub, and `smoke-herdr-plugin-build-live` redirects the product remote to a local bare clone with git `insteadOf` and asserts `identity.kind === "herdr-checkout"`. npm has been the production authority class since `dd84ac0`; the 0.30.0 follow-up re-pinned `@junghanacs/entwurf@0.30.0` with its published sha512 after the candidate windows rode `herdr-checkout` (`8b92e09`), and the 0.30.1 preparation rode that closed verification carrier again without inventing a registry integrity. The plugin snapshot `v2026.10.9-herdr.0.34.0` pinned the published `@junghanacs/entwurf@0.34.0` with its measured sha512 (#132); 0.31–0.33 were never pinned. The 0.34.1 preparation rode the closed `herdr-checkout` verification carrier again without inventing a registry integrity, and the snapshot `v2026.10.9-herdr.0.34.1` re-pins the published `@junghanacs/entwurf@0.34.1` with its measured sha512 (#135). The 0.34.2 preparation rode the same carrier, and the snapshot `v2026.10.11-herdr.0.34.2` re-pins the published `@junghanacs/entwurf@0.34.2` with its measured sha512 (#136). The source re-proof has separate dated npm rows: 2026-09-23 public `main=113ca53`, plugin 0.5.0, runtime 0.25.0 (CHANGELOG 0.25.1), and the 0.30.0 re-pin accepted at public `506c46f` in the [#126 thread](https://github.com/junghan0611/entwurf/issues/126). Neither certifies the 0.34.0 registry acquisition. That pin's real-npm swap / torn-swap recovery was measured locally on 2026-10-09 by driving the registry-shipped `scripts/herdr-runtime.mjs` (byte-equal to this checkout's) with its own npm acquisition: a 0.33.0 → 0.34.0 swap, and the same upgrade torn between its two renames then resumed, where the last-good 0.33.0 tree was restored before 0.34.0 was acquired again. Both ended `runtime-ready` at observed digest `sha256-e9d995ff…`, the accepted 0.34.0 artifact. That local receipt is recorded in the [#132 thread](https://github.com/junghan0611/entwurf/issues/132); it covers runtime recovery, not this smoke's cells. This smoke's public-ref acceptance of the 0.34.0 pin was measured locally at `--ref main`: PASS at resolved `b5d15d8` and again at the docs follow-up `8ed4d1a`, each acquiring `kind=npm @junghanacs/entwurf@0.34.0` — a main-ref receipt, not a tag-ref, native or full-Herdr claim. The 0.34.1 re-pin's npm-source rows — swap / torn-swap recovery, this smoke at a public ref, and the package consumer — are its own, recorded with that pin and never inherited from 0.34.0; checkout candidate evidence does not transfer. The 0.36.0 re-pin's public-ref row was measured on Herdr 0.9.4 at `--ref main`: PASS at resolved `9f33dd1`, acquiring `kind=npm @junghanacs/entwurf@0.36.0` at the accepted digest — a main-ref receipt, not a tag-ref claim. Its version-changing cross-ref reinstall (`herdr plugin install … --ref main` over the `v2026.10.13-herdr.0.35.1` installation) across a pinned Pi upgrade was a driver-level journey recorded in that snapshot's release notes, not a row of this smoke; `herdr plugin update` there was measured only as a same-ref already-up-to-date no-op. `LIVE=1 ./run.sh smoke-herdr-raw-install-live [--ref <REF>]` fills that row in a clean `node:24` container with no socket, config, cache or repo mounted, no `insteadOf`, the public remote spelled as a user would type it, and pi / herdr / Claude Code installed in the IMAGE BUILD as scaffolding (Hard Rule 17 — the product face begins at `herdr integration install pi`). herdr itself comes from `scripts/install-herdr-ci.sh` against `scripts/fixtures/herdr-supply.json`, so no version or digest lives here. `--ref` defaults to `main` rather than a pinned SHA because receipt (a) is defined as what a user gets today; the resolved commit is printed, so the receipt stays exact. It takes a REMOTE REF and not an arbitrary commit — measured on herdr 0.9.1, `--ref <sha>` fails as `couldn't find remote ref`, because the checkout fetches by name — so a candidate is addressed by its branch and pinned by the resolved commit the gate prints. **Its first question is a measurement, not an assumption:** herdr registers a plugin through a running server and falls back to `persist_plugin_offline` only on a connection error (`src/cli/plugin.rs:914-981,1016-1021` @ `c77af189`, 0.9.0 source), and a container has no server. The 2026-09-23 PASS installed with no server on the 0.9.1 binary `113ca53`'s `herdr-supply.json` pins, so that install path worked on 0.9.1 — inferred from the PASS, not a direct observation of the fallback branch; a later "no" on another herdr is #118 investigation output rather than a completion. `--yes` is always passed so a non-interactive exit 2 (`:189`) can never be misread as a missing server. **At a ref whose lock names `herdr-checkout` the acquisition axis reports a NAMED SKIP rather than a red, and the rest of the journey still runs.** That lock is the candidate carrier a cut legitimately sits on — 0.23.0 was tagged that way and `dd84ac0` pinned npm afterwards — so a red there would report a broken install when what is true is that the ref does not lock npm. What is asserted at BOTH lock kinds is that the runtime came from the source the ref locks, and the package name is read from the checkout manifest rather than the lock, because a `herdr-checkout` lock carries no `name` (`herdr-runtime.mjs:317-328`) and joining `undefined` throws instead of failing an assertion. **Cells [6]–[9] carry it past the install into the USE path (#118 H1-4/H1-5).** An install is not a use, so the same container then runs what those bytes became: the compiled bridge entry, the three `REQUIRED_BINS` as executables, and a real `entwurf check-bridge` printing the exact verb set the installed bridge declares (nine since 0.41.0; each earlier recorded PASS printed its own date's set, and none of them is a nine-verb LIVE receipt) — the installed-runtime row below, measured rather than inferred from the bootstrap's refusal to install without them. Then the pi that this plugin WIRED is started with no `-e` and no `--no-extensions`, because the subject is the wiring and not this checkout: one `get_state` in `--mode rpc` costs zero tokens and needs no provider argument (a bogus `--provider` exits 1 before session_start; omitting the pair lets pi resolve the default the extension itself registers), and while that session is alive the cell reads its V3 record, its gardenId-keyed control socket, and the installed `entwurf peer-facts` reporting it `alive`. The plugin's own status fan is then driven with NEITHER side stubbed, in both states a user can be in: with no herdr server it must name `herdr-agent-list-failed` and go red rather than draw an empty table, and under a headless `herdr server` — scaffolding for that second read only, stopped again before the teardown — it exits 0 and COUNTS the citizen as `unobserved` instead of dropping it. Last, the shipped `entwurf herdr-plugin-deactivate` runs from the installed bin, deletes the runtime it is executing from, and the plugin reinstalls onto the host it fully left — the deactivation row, on the npm source. **What these cells still do not close:** swap / torn-swap recovery on the npm source, the package-consumer proof, and the fan drawing a citizen as a ROW — that needs `placement.kind === "herdr-pane"`, so the pi session must live in a herdr pane a session reference joins, and a headless container has no panes. **This smoke carries no test beside behavior and no mutant**, and that is a property of its class rather than an omission: it is a real-live container journey whose oracle is the container's own end state, so there is no pure seam to assert against and nothing a source mutation could kill deterministically. Like the other two herdr LIVE lanes it is **on-demand and not an aggregate MUST** — herdr is optional, a cut on a host without it must not block, and first evidence precedes promotion. Without `LIVE=1`, or without a usable Docker daemon, it reports a named SKIP; `ENTWURF_REQUIRE_DOCKER=1` turns the Docker absence red. Neither skip is a pass.
|
|
109
109
|
|
|
110
110
|
> **The Herdr plugin's install-time build has two axes, and one of them needs the network (#116 M3-b3).** `check-herdr-plugin-build` is deterministic and rides `check:hermetic`: the listing reaches the runner through its own spawn seam (there is no fake `herdr` binary in this repo), and the one cell that drives the REAL binary reports a named SKIP on a host without it — `ENTWURF_REQUIRE_HERDR=1` makes that absence red. What it cannot have is the real acquisition: `npm pack git+https://github.com/junghan0611/entwurf.git#<full sha>` builds the bridge through `prepare`, which installs devDependencies from the registry. So `LIVE=1 ./run.sh smoke-herdr-plugin-build-live` owns that axis, and its cells are **two kinds of evidence, labelled as such**: three are the real Herdr journey — a real `herdr plugin install` driving the real `[[build]]`, with the UNCHANGED product remote redirected to a local bare clone by git `insteadOf` (the one substitution, which is what makes an unpushed candidate testable) — covering remote-commit available, the `{pi}` → `{pi, claude-code}` reinstall with OpenCode as a zero-write negative control and exactly ONE counted vendor MCP owner entry, and the post-build Herdr-commit gap (where the ledger has already rebound to the gap commit, so the honest assertion is that transition and not unchanged bytes). The fourth cell — remote-commit **unavailable** — calls the shipped runtime leaf directly with the fixed product argv and is therefore **acquisition-leaf evidence, not a journey**; routing it through Herdr would add a second explanation for one red. Its oracle is the honest one too: active runtime, ledger and harness bytes preserved, while the journal is left as the certified `installing` retry authority the transaction deliberately writes before acquiring, and a normal install afterwards is green. Its Claude cell is where the vendor question the deterministic gates refuse to claim gets answered — whether Claude Code accepts an ABSOLUTE executable as an MCP command — and it reports a named skip on a host without `claude`, never a pass. Like the herdr fresh-call rail, this smoke is **on-demand and not an aggregate MUST**. The release aggregate does not require the plugin build smoke: herdr is optional, a cut on a host without it must not block, and first evidence precedes promotion.
|
|
111
111
|
|
|
@@ -115,7 +115,7 @@ that moved out of `scripts/` and into a file beside its subject would otherwise
|
|
|
115
115
|
>
|
|
116
116
|
> A cut that touches the prompt-lifecycle contract (no wall clock on a running turn) owes one long-turn acceptance the aggregate floor is too short to carry: `LIVE=1 ./run.sh smoke-acp-long-turn-live` drives a real turn whose tool work outlasts the retired 600s cutoff and requires exactly one cold ACP bootstrap in the transcript. It takes >12 minutes by construction and is on-demand, not part of `release-gate`.
|
|
117
117
|
>
|
|
118
|
-
> **The integrated mux lifecycle IS a release-gate MUST.** `LIVE=1 ./run.sh smoke-mux-lifecycle-live` enters through a real MCP `tools/call` on the shipped bridge launcher and follows one citizen the whole way: fresh-call launch receipt, the sibling's own nonce callback whose SENDER ENVELOPE is the address, an `entwurf_v2` control-socket send that lands in the sibling's own transcript, `entwurf_resume_call` REFUSED while that citizen is live, a stable-handle close proving pane and socket gone with the record preserved, delivery to the dormant citizen refused honestly, then the public `entwurf_resume_call` — whose LAUNCH and OBSERVATION receipts stay apart — and finally an `entwurf_v2` send the resumed session answers with a fact it was told BEFORE the window closed. That last step is the point: a socket answering under the same garden id proves a process stood up at that address, and only the recall proves the same conversation came back. Both pi provider shapes are driven to it (native `openai-codex/gpt-6.1-sol:low` and recorded-ACP `entwurf/claude-sonnet-5-5`, the only shape that re-injects a bridge extension), and the Claude Code cell
|
|
118
|
+
> **The integrated mux lifecycle IS a release-gate MUST.** `LIVE=1 ./run.sh smoke-mux-lifecycle-live` enters through a real MCP `tools/call` on the shipped bridge launcher and follows one citizen the whole way: fresh-call launch receipt, the sibling's own nonce callback whose SENDER ENVELOPE is the address, an `entwurf_v2` control-socket send that lands in the sibling's own transcript, `entwurf_resume_call` REFUSED while that citizen is live, a stable-handle close proving pane and socket gone with the record preserved, delivery to the dormant citizen refused honestly, then the public `entwurf_resume_call` — whose LAUNCH and OBSERVATION receipts stay apart — and finally an `entwurf_v2` send the resumed session answers with a fact it was told BEFORE the window closed. That last step is the point: a socket answering under the same garden id proves a process stood up at that address, and only the recall proves the same conversation came back. Both pi provider shapes are driven to it (native `openai-codex/gpt-6.1-sol:low` and recorded-ACP `entwurf/claude-sonnet-5-5`, the only shape that re-injects a bridge extension), and the Claude Code cell, whose sibling is still live at that point, has its resume refused as `target-live` with no window opened and no lock residue (the per-gid coordination lock is released). Claude Code's dormant same-id resume (#147 L2) is certified deterministically; its LIVE dormant→resume leg is not in this MUST yet. One test-owned retire→resume round trip outside this gate is recorded as dated n=1 evidence in [BASELINE](./BASELINE.md#147-native-round-trip-2026-10-22-n1); it is not this MUST.
|
|
119
119
|
>
|
|
120
120
|
> One cell cannot be fully fenced, and that is recorded rather than glossed: the recorded-ACP pi cell runs under the operator's REAL home, because its provider spawns `claude` as a child that authenticates from there — measured, a fenced HOME kills that turn with `Authentication required` before the model is ever reached, and `CLAUDE_CONFIG_DIR` alone does not fix it. That is the same trade `smoke-acp-bundled-mcp-live` already makes. While that cell runs, its citizen's control socket and per-gid lock exist under the operator's own `~/.pi/entwurf-control` and `~/.pi/entwurf-v2-locks`; its meta store stays fixture, so no garden record is minted outside the fixture, and the run ends by proving all six real roots hold the entry sets they started with, with no fixture garden id and no leftover lock.
|
|
121
121
|
>
|
|
@@ -285,7 +285,7 @@ caller/target/cross-harness LIVE are owed by `smoke-pi-durable-fresh-live`, a re
|
|
|
285
285
|
| Packed install | `check-pack-install` | Real tarball, but checkout-visible. |
|
|
286
286
|
| Linux artifact consumer | required `check-install-container` CI job against one preserved candidate | Fixtures prove package/oracle shape, not a real Claude lifecycle. |
|
|
287
287
|
| Exact release commit | the exact SHA's push run: all four required CI jobs green (the qualification body is not read, #144) | A different green SHA is not transferable evidence. |
|
|
288
|
-
| macOS Entwurf-only install | required `macos-install-surface` CI job at the exact release SHA | Shape-only, CERTIFIED (CI): certifies the Entwurf-only install path on macOS only — never Claude/Copilot/OMP/agy wiring, the pi rail, ACP or mux. Promoted from non-voting (`continue-on-error`) to required in 0.20.0 after its first CERTIFIED (CI) green on a GitHub Actions `macos-latest` runner (not a physical host): run 34303884286 @ `70eda03` (2026-09-09), 65s, all 10 steps success — the packed candidate installed clean, `entwurf --help` and `entwurf check-bridge` ran (the latter listing the seven `entwurf-bridge` MCP tools of that date;
|
|
288
|
+
| macOS Entwurf-only install | required `macos-install-surface` CI job at the exact release SHA | Shape-only, CERTIFIED (CI): certifies the Entwurf-only install path on macOS only — never Claude/Copilot/OMP/agy wiring, the pi rail, ACP or mux. Promoted from non-voting (`continue-on-error`) to required in 0.20.0 after its first CERTIFIED (CI) green on a GitHub Actions `macos-latest` runner (not a physical host): run 34303884286 @ `70eda03` (2026-09-09), 65s, all 10 steps success — the packed candidate installed clean, `entwurf --help` and `entwurf check-bridge` ran (the latter listing the seven `entwurf-bridge` MCP tools of that date; 0.41.0 declares nine, unmeasured on that runner), an all-harness-absent `entwurf setup` reached `result: green` across the five documented SKIP probes (`pi`/`claude`/`agy`/`copilot`/`omp`), and five checked paths (`.pi`, `settings.json`, `.gemini`, `.copilot`, `auth.json.bak`) plus a byte-identical `auth.json` proved zero harness/credential writes. A macOS runner failure now blocks every release cut, the same as any other required job. |
|
|
289
289
|
| Native-Windows carrier (carrier-bearing release, from 0.39.0) | one `windows-native-preview.yml` dispatch at the exact prepared SHA after its four `ci.yml` jobs are green: accepted build receipt (two byte-identical MSVC builds, exact import set), `pack` printing `present`, eight Windows addon/citizen cells on the installed tarball; that run's `win32-preview-tgz` is the release candidate, retrieved (never packed locally) with its `SHA256SUMS`, the Windows-printed install hash and the downloaded hash equal, then accepted by the Linux `check-install-container` unchanged (release skill M3w) | Experimental, shape-only, non-voting for `ci.yml`: no vendor turn, x64 runner only, named gaps in BASELINE. The four `ci.yml` jobs (incl. macOS) saw an addon-less pack, so the carrier-bearing tarball's macOS install is unmeasured. Artifacts expire after 14 days; the preserved copy is the durable one. |
|
|
290
290
|
| LIVE runtime | `LIVE=1 ./run.sh release-gate <scratch> --cut` plus any shipped on-demand backend axis | `--cut` enforces `SKIP=0`; a red wired gate blocks the cut. |
|
|
291
291
|
| Native Claude host | installed strict doctor against a new real session | Missing live join is `NOT CERTIFIED`, not a fixture PASS. |
|
|
@@ -293,7 +293,10 @@ caller/target/cross-harness LIVE are owed by `smoke-pi-durable-fresh-live`, a re
|
|
|
293
293
|
| Native Codex host | caller-seat topology accepted 2026-09-16 (56 assertions, exit 0); caller-DIRECTORY axis accepted the same day (65 assertions, exit 0) | Operator-owned birth/MCP/statusline/terminal-title atoms and the on-demand four-coordinate chain are measured on Linux at Codex 0.153.4: the app-server alone in session A (`$30/@41/%45`, pid 737636), and initial Pi / omitted-placement fresh Codex / Codex-opened outbound Pi all in a different session S (`$2`, `@46`/`@47`/`@48`; `@58`/`@59`/`@61` in the lane C run); exact callbacks and addressed delivery both ways. A ≠ S is the load-bearing half — the app-server's inherited `TMUX` names A, so the outbound Pi landing in S can only have come from the caller's own pane title, and its receipt records `seat-source=codex-title-anchor`. **#95 lane C added the second axis to the same card: WHERE the sibling starts.** Hop 1 joins four authorities that cannot borrow from each other — the pane's `#{pane_current_path}`, the vendor rollout's `session_meta.cwd`, the Entwurf record and the requested scratch — and hop 1's leg requests a cwd while hop 2 requests NONE, so hop 2's directory can only come from the Codex caller's own record; both are asserted different from the app-server's live `/proc/<pid>/cwd`. 65 and 56 are different contracts, not a regression. The 2026-09-12 fixed-home chain is PAST CONTRACT (#95 D1); `DELIVERY.md` owns every receipt and digest. Placement beside a TUI whose thread nobody named is unsupported and unclaimed. |
|
|
294
294
|
|
|
295
295
|
The repo-local `entwurf-release` skill owns the `land → prepare → make → publish`
|
|
296
|
-
state machine. Each mode is a separate GLG authorization.
|
|
296
|
+
state machine. Each mode is a separate GLG authorization. A narrower host restriction may
|
|
297
|
+
block a mode; it never waives a release-acceptance axis below. Feature-branch CI is not a
|
|
298
|
+
substitute for a forbidden local/LIVE floor: keep make blocked until the named cut has the
|
|
299
|
+
required execution authority and evidence. Preserve one candidate
|
|
297
300
|
(for a carrier-bearing release, the one retrieved from the preview run, never a local
|
|
298
301
|
pack), accept and publish those exact bytes without repacking, and record its digest and
|
|
299
302
|
consumer image outside this standing protocol.
|
|
@@ -344,7 +347,7 @@ every focused gate green at the time:
|
|
|
344
347
|
|
|
345
348
|
### Wording — avoid safety-interpretation contamination
|
|
346
349
|
|
|
347
|
-
When injecting a fact for a continuity check, use **plaintext that does not trigger model safety interpretation**. Avoid `secret token`, `password`, `API key`, `credential`, and meta-directives like "do not leak" — such wording makes the model treat the prompt as an exfiltration attempt and refuse, which makes **continuity look broken even when it is alive** (this happened once with `test-token-123`, misdiagnosed as a delegation failure). Instead: `The
|
|
350
|
+
When injecting a fact for a continuity check, use **plaintext that does not trigger model safety interpretation**. Avoid `secret token`, `password`, `API key`, `credential`, and meta-directives like "do not leak" — such wording makes the model treat the prompt as an exfiltration attempt and refuse, which makes **continuity look broken even when it is alive** (this happened once with `test-token-123`, misdiagnosed as a delegation failure). Instead: `The code word is owl → reply in one word → owl`; code names / colors / animal names. Do not mix continuity and safety-behavior verification in one prompt.
|
|
348
351
|
|
|
349
352
|
### bridge continuity vs semantic continuity
|
|
350
353
|
|
|
@@ -371,7 +374,7 @@ The goal is not merely "invoke Claude Code." We want:
|
|
|
371
374
|
**One install command to remember: `./run.sh setup <project>`.** It is idempotent — re-run the exact same command whenever anything looks wrong. There is no second install surface to juggle: from a clone `setup` runs the whole floor in order.
|
|
372
375
|
|
|
373
376
|
1. `pnpm install` — installs the pinned development dependencies and builds the bridge (source-checkout bootstrap only; an installed package never runs npm/pnpm inside `node_modules`)
|
|
374
|
-
2. pi wiring → `<project>/.pi/settings.json` + user-scope registration — only when a `pi` inside the supported range (`>=1.
|
|
377
|
+
2. pi wiring → `<project>/.pi/settings.json` + user-scope registration — only when a `pi` inside the supported range (`>=1.4.0 <1.5`) is on PATH; absent pi is an explicit zero-state SKIP, a below-floor pi is a detected FAIL. The user-scope entry is owner-recorded (#86 C2): another root's live-or-missing ownership makes this step a zero-write refusal (setup: pi FAIL) that names `takeover-user-scope`; the install-states bind the exact managed settings path (a drifted/symlinked/corrupt target is a zero-write refusal) and the inverse removes only the recorded owner's exact entry; `doctor-pi-package` reports the verdict
|
|
375
378
|
3. Claude meta-bridge global plugin — only when `claude` is on PATH; otherwise skipped cleanly
|
|
376
379
|
4. source stable-bin exposure — including certified `entwurf` → this checkout's `run.sh`, the managed runtime Copilot fresh resolves; helper units are attempted independently and a foreign helper is a named FAIL
|
|
377
380
|
5. agy bridge + exact permission + statusline + `PreInvocation` hook — only when `agy` is on PATH; each adapter is idempotent and independently doctorable
|
|
@@ -438,7 +441,7 @@ mailbox with `origin=pi-session`, `replyable=true`).
|
|
|
438
441
|
|
|
439
442
|
### 1.4 Cross-install / cross-backend parity (optional, high-value)
|
|
440
443
|
|
|
441
|
-
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 pi citizen reaches the compiled `entwurf-bridge` through Pi's built-in MCP (`mcp__entwurf_bridge__<verb>`,
|
|
444
|
+
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 pi citizen reaches the compiled `entwurf-bridge` through Pi's built-in MCP (`mcp__entwurf_bridge__<verb>`, seven active tools and two hidden in the 0.41.0 source; installed/live offering requires its own receipt), while the ACP backend reaches that bridge through the explicit `entwurfProvider.mcpServers` projection in its own callable dialect (see §2.1). Compare the actual ingress provenance and backend-native tools, not an assumed absence of MCP on pi; receive to the pi citizen remains its record-addressed control address (a Unix socket; a named pipe on the experimental native-Windows Pi preview). Honest "I cannot tell" hedging is preferable to inventing provenance. This is the current #125 comparison criterion, not a newly measured parity receipt. agy is graded by its native-citizen checklist, not by pretending it has an ACP overlay.
|
|
442
445
|
|
|
443
446
|
**Cortex on axis 3.** A cortex session must expose the same garden capability
|
|
444
447
|
while keeping cortex's own native tool surface. Its callable MCP identifier shape is
|
|
@@ -468,7 +471,7 @@ Pass (carrier honesty): the subject distinguishes engraving from pi-context-augm
|
|
|
468
471
|
|
|
469
472
|
- **Layer 0 — self-awareness:** ask environment self-awareness / MCP visibility / upstream-instruction awareness, guessing prohibited. Pass: recognizes native tool family, says "I don't know" honestly, answers MCP visibility only as configured, describes upstream instruction type without reproducing internal prompts. Fail: claims a nonexistent tool, conflates pi-custom and native tools, hallucinates MCP visibility, or conflates the two carriers (§1A.0).
|
|
470
473
|
- **Layer 1 — native tool use:** throw file-reading / structure-analysis / regression-hunting tasks. Pass: Read/Edit/Bash/Grep/Glob selection is natural; no detour through MCP or recursive `pi`. Fail: strange detours for simple reads; speaks from memory without reading.
|
|
471
|
-
- **Layer 2 — MCP boundary:** by default the
|
|
474
|
+
- **Layer 2 — MCP boundary:** by default the entwurf MCP tools are not visible (they appear only when `entwurf-bridge` is registered). Pass: says invisible tools are not visible; explains the native-vs-MCP boundary; treats `entwurf_register_native` as binding an already-running conversation, never as fresh spawn. Fail: pretends to use an unseen tool; mimics entwurf via recursive `pi`.
|
|
472
475
|
- **Layer 3 — focus across turns:** inject a fact, then accumulate turns mixing retrieval/exploration. Pass (post-0.4.1): after **8 turns** holds **3+ early facts** incl. **one verbatim string injected before turn 5**; no repeated exploration, no self-contradiction, no tool-strategy drift. Fail: forgets early reads; paraphrases instead of returning the verbatim string. Note: entwurf exposes no user-facing compaction; use the backend's `usage_update` footer as an overflow-risk signal (it follows the ACP backend's `used/size`, not pi's visible-transcript estimate).
|
|
473
476
|
- **Layer 4 — vs direct Claude Code:** requires a verifier holding **both** the `entwurf` and a direct path (human-in-loop, or both transport handles). Compare latency / native tool accuracy / detours / boundary confusion / quality around turns 10–15. Repeated tool confusion, long-turn forgetting, or boundary workarounds are a fail.
|
|
474
477
|
|
|
@@ -540,7 +543,7 @@ The minimum passing bar:
|
|
|
540
543
|
2. **All four required CI jobs green on the exact release commit:** `check`, `install-surface`, the required Linux `artifact-consumer`, and `macos-install-surface` — promoted from non-voting to required in 0.20.0 (see the release acceptance axes table above for what its green run does and does not certify); preserve the Linux artifact-consumer's tarball digest and image identity. For a carrier-bearing release those CI tarballs are addon-less and are NOT the release candidate: the exact release bytes are the M3w-retrieved preview tarball, accepted separately by the eight Windows cells and the Linux container (axes row "Native-Windows carrier"). The four-job floor, macOS included, is unchanged. A macOS runner failure now blocks the cut like any other required job.
|
|
541
544
|
3. **Live floor MUST green:** `LIVE=1 ./run.sh release-gate <dir> --cut` exits 0 reporting `MUST PASS=N FAIL=0 SKIP=0`; with `--cut` a single SKIP is red, so the exit code itself now carries this condition. A BEHAVIOR FAIL is advisory, not blocking.
|
|
542
545
|
4. **Native-host doctor green where the Claude meta-bridge is claimed:** a new post-install Claude session exists, live evidence is present, and the installed `doctor-meta-bridge` exits 0. `NOT CERTIFIED` is a release failure for that host, not a skip.
|
|
543
|
-
5. **Honest self-recognition:** the bridged model identifies its actual harness/backend, lists `entwurf-bridge` as the single MCP server with its
|
|
546
|
+
5. **Honest self-recognition:** the bridged model identifies its actual harness/backend, lists `entwurf-bridge` as the single MCP server with the tools its loaded bridge actually lists (the current source lists nine; a pi citizen offers seven with two hidden, the pi-durable contact eight), and presents a backend-native (not normalized) tool surface.
|
|
544
547
|
6. **Carrier separation honored:** engraving vs pi-context-augment kept distinct (§1A.0); no bridge-identity narrative attributed to the engraving carrier.
|
|
545
548
|
7. **agy shipped lane accepted:** all three agy doctors are green; automatic birth/statusline/sender identity and same-gid native-push reply are confirmed in a fresh conversation. `agentId=meta-session/antigravity` is correct; model display is not part of that contract. Same-pid concurrent conversation invocation is not claimed.
|
|
546
549
|
8. **Codex caller-seat topology accepted:** its birth/MCP/status-line/terminal-title doctors are green and the on-demand real visible `Pi → Codex → Pi` cell records four coordinates: the operator-owned app-server in its own session A; initial Pi, omitted-placement fresh Codex, and Codex-opened outbound Pi all in a DIFFERENT session S; exact callbacks and addressed delivery succeed both ways. A ≠ S is a precondition, not a preference — the app-server's inherited environment names A, so an outbound Pi in S can only have come from the caller's own pane title, and the receipt must name `codex-title-anchor` as the rule that chose it. 0 or 2+ matching panes, and a caller whose `[tui].terminal_title` lacks `thread-id`, reject without mutation. Entwurf neither creates nor supervises the app-server, infers attached-TUI panes, nor claims placement beside a TUI whose thread nobody named. (The 2026-09-12 fixed-`codex`-home acceptance this condition replaced stays recorded in `DELIVERY.md` as history; #95 D1 retired that room.) Codex remains outside ACP and has no resume claim.
|
|
@@ -558,7 +561,7 @@ Passing establishes a **release verification floor**, not an 8-hour/day operatio
|
|
|
558
561
|
|
|
559
562
|
- **ACP turn evidence.** The ACP path writes no `[entwurf:*]` stderr markers, and `ENTWURF_CHILD_STDERR_LOG` is not an ACP observation surface (its mirror in `pi-extensions/lib/entwurf-core.ts` belongs to the retired child-pi spawn and has no caller). Read three things instead: the lifecycle notices the backend writes into the assistant text (`[acp: preparing …]` / `[acp: reusing live session]`), the turn's typed `stopReason` (an ACP `cancelled` ending maps to `aborted`, `pi-extensions/lib/acp/backend.ts:865-866`), and the identity (pid + starttime) of the launcher and of any process the turn started.
|
|
560
563
|
- **Retired dedicated smokes, live code invariants** (manual/troubleshooting only — *not* part of the release floor):
|
|
561
|
-
- *
|
|
564
|
+
- *ACP-boundary model guard* — a session using the `entwurf` provider keeps its starting model: `pi-extensions/model-lock.ts` reverts set/cycle transitions touching that provider (native-to-native switching is free). This is an after-event revert, not a transcript-clean refusal. Separately, `session-store.ts` `SessionModelLockedError` refuses a persisted-record model mismatch at `decideBootstrap`. Gate: `check-model-lock` (core tier); the dedicated live `smoke-model-switch` was retired in v2. This is not a lifetime model pin on every garden citizen.
|
|
562
565
|
- *Cancel / abort cleanup* — an abort sends ACP `session/cancel` and lets the agent end its own turn (`awaitAcpPromptTurn`, `pi-extensions/lib/acp/backend.ts:762-801`); process-group teardown follows only after a bounded grace. A cancelled reuse turn keeps its live session; a cancelled first turn is not retained (`backend.ts:1861`), so the next turn bootstraps a new one. Dedicated `smoke-cancel` retired; invariant in code.
|
|
563
566
|
|
|
564
567
|
### Evidence preservation when a problem occurs
|
package/demo/README.md
CHANGED
|
@@ -24,7 +24,7 @@ takes/helpers/tests are maintainer tooling and are deliberately excluded from th
|
|
|
24
24
|
|
|
25
25
|
- Node at the `package.json#engines.node` floor; the checkout's pinned dependencies and
|
|
26
26
|
current compiled bridge. After a source/bootstrap change, build with `pnpm run build-bridge`.
|
|
27
|
-
- Pi at the checkout's supported floor (**current floor 1.
|
|
27
|
+
- Pi at the checkout's supported floor (**current floor 1.4.0**); `entwurf` on PATH must be
|
|
28
28
|
the intended source stable-bin. Source evidence is not registry-package acceptance.
|
|
29
29
|
- `herdr` on PATH at exactly `scripts/fixtures/herdr-supply.json#version`; `asciinema` v3.
|
|
30
30
|
- Herdr's existing Pi integration at
|
package/docs/acp-backend-rail.md
CHANGED
|
@@ -135,12 +135,12 @@ Dep bump ledger. 0.38.0 (#145) changes only the pi SDK set; the ACP rows are unc
|
|
|
135
135
|
| Surface | Declaration | Class | What a green actually says |
|
|
136
136
|
|---|---|---|---|
|
|
137
137
|
| Entwurf package | `package.json` `version` | checkout declaration, not a release receipt | names the package label these rows sit beside; whether that label shipped, and with which rows, is CHANGELOG's record |
|
|
138
|
-
| pi runtime | SDK exact `1.
|
|
138
|
+
| pi runtime | SDK exact `1.4.0`, host `>=1.4.0 <1.5` | **exact** oracle + **closed range** | the SDK set this checkout builds, gates and (since #130) ships as exact production dependencies; an ordinary Pi host inside the range is accepted, and the ceiling moves only on measurement. The published 0.36.0 through 0.37.1 shipped the 1.2.0 set (#141); 0.38.0 (#145) is the first to carry 1.3.0. Historical: the published 0.33.0 through 0.35.1 ship SDK exact 1.1.0, 0.32.0 ships SDK exact 1.0.4 with the next-minor ceiling (ROADMAP's 2026-10-07 bump entry), and 0.31.0 declared the earlier peer floor 1.0.2 |
|
|
139
139
|
| ACP wire SDK | `@agentclientprotocol/sdk 1.8.0` | **exact** | the shared wire oracle both adapters speak |
|
|
140
140
|
| Claude ACP adapter | `@agentclientprotocol/claude-agent-acp 0.90.0` | **exact**, bundled | shipped since 0.36.1; resolved before any PATH fallback; declaration is not compatibility evidence |
|
|
141
141
|
| Claude Agent SDK | `0.3.296` (transitive) | **exact** oracle | the runtime risk surface behind the adapter |
|
|
142
142
|
| Anthropic SDK | `0.100.1` | **exact**, peer-resolution only | satisfies the Agent SDK peer floor (0.93.0+); never an API client here (gate L4) |
|
|
143
|
-
| Claude Code runtime | `>=2.1.
|
|
143
|
+
| Claude Code runtime | `>=2.1.306` (`entwurf.claudeCodeFloor`) | **floor** | below it, hook args are silently dropped; entwurf enforces this itself |
|
|
144
144
|
| Node | `>=24` (`engines.node`) | **floor** | single axis, derived everywhere else |
|
|
145
145
|
| Cortex Code | operator-installed CLI | **on-demand**, external | NOT a pinned dependency. Each LIVE record must name the exact CLI version it measured |
|
|
146
146
|
|
|
@@ -419,6 +419,10 @@ Otherwise record and defer. Every certification separates declared pins, determi
|
|
|
419
419
|
evidence, Claude LIVE aggregate evidence, and Cortex direct on-demand evidence (with its CLI
|
|
420
420
|
version). Per-bump measurements live in the ROADMAP **Dep bump(별도 트랙)** ledger.
|
|
421
421
|
|
|
422
|
+
### Configured Claude ACP permissions
|
|
423
|
+
|
|
424
|
+
Source configuration, not a retirement LIVE receipt: `pi-extensions/lib/acp/overlay.ts` sets `permissions.defaultMode: "bypassPermissions"`, and `config.ts` includes `mcp__*` in the default `permissionAllow`. The configured Claude ACP child therefore does not supply a per-call permission prompt; these settings do not widen the explicit callable tool surface. `enrichMcpServersWithEnvelope` in `config.ts` injects the host Pi session's `PI_SESSION_ID` and the ACP agent label into the explicit entwurf-bridge stdio entry. If that bridge exposes `entwurf_retire_call`, a promptless call attributed to the host Pi citizen is consequently possible by source inference — ACP retirement through this path is unmeasured, not part of the ordinary Native Pi/Claude Code n=1 round trips. Neither those settings, annotations nor caller attribution is an operator grant: an explicit human request for that target/action and agent operating policy are still required. This describes existing configuration, not a new ACP retirement ban or permission mechanism.
|
|
425
|
+
|
|
422
426
|
### Bridge reachability is part of the contract
|
|
423
427
|
|
|
424
428
|
Explicit entwurf-bridge connectivity inside an ACP turn is core value, so it is measured rather than
|
|
@@ -11,7 +11,7 @@ the one-line registration; everything an operator needs to actually wire a host
|
|
|
11
11
|
|
|
12
12
|
**Being garden-native is not the same as being replyable, and Copilot is the case that separates them.** Its hook writes a sender marker, so an `entwurf_v2` send carries its own garden id and the receiver learns who wrote — measured 2026-08-21 on Copilot CLI 1.0.80, where a live send arrived under its own garden id with `origin: "meta-session"` and `replyable: false`. Replyability arrived later and through a different process: a first-party extension (`run.sh install-copilot-receive`) that the CLI forks, which binds to the same V3 record and writes a receiver marker owned by its own pid (#82 RAIL 5). So a Copilot citizen is `replyable: true` exactly while that extension is armed for it, and `replyable: false` — honestly, with a real garden identity — when it is not installed, not launched with `COPILOT_CLI_ENABLED_FEATURE_FLAGS=EXTENSIONS` (which is what `entwurf copilot` sets for one invocation), not yet born, or gone. Read the two facts off different rails: the sender marker answers *who sent this*; the receiver marker answers *can a reply land*. The onboarding obligations are in [`adding-a-harness.md`](./adding-a-harness.md) step 7, and the evidence boundary — the managed LIVE acceptance that moved receive to D6, and what D7-partial / D3-pending still exclude — is in [`DELIVERY.md`](../DELIVERY.md).
|
|
13
13
|
|
|
14
|
-
**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, a mailbox-backed self-fetch citizen (Claude Code, Copilot, OMP), or native-push Antigravity/Codex 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. Open a NEW sibling with **`entwurf_fresh_call {backend, model, task, cwd?, placement?}`**, and reopen a DORMANT pi citizen under the same id with **`entwurf_resume_call {target}`**.
|
|
14
|
+
**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, a mailbox-backed self-fetch citizen (Claude Code, Copilot, OMP), or native-push Antigravity/Codex 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. Open a NEW sibling with **`entwurf_fresh_call {backend, model, task, cwd?, placement?}`**, and reopen a DORMANT pi or Claude Code citizen under the same id with **`entwurf_resume_call {target}`**. **`entwurf_retire_call {target}`** (new in 0.41.0) attempts retirement of exactly one target, and only one the human operator explicitly requested; mounting or seeing the tool, a coordinator role or caller identity is not permission, and an unknown result is not a reason to replay.
|
|
15
15
|
|
|
16
16
|
Observed: Claude Code, Codex CLI, Antigravity CLI, GitHub Copilot CLI and OMP all reach this MCP bridge. Claude, Copilot and OMP become symmetric/replyable through mailbox-backed meta-sessions; agy and Codex use native-push. Codex's identity is request-scoped `_meta.threadId`, and its replyability requires that exact record plus a loaded app-server thread. Plain external hosts still need an identity lane to send.
|
|
17
17
|
|
|
@@ -90,7 +90,7 @@ External/meta-session semantics:
|
|
|
90
90
|
#### Claude Code
|
|
91
91
|
|
|
92
92
|
Plain MCP registration works independently of the native lifecycle. A garden-native
|
|
93
|
-
mailbox citizen requires Claude Code >=2.1.
|
|
93
|
+
mailbox citizen requires Claude Code >=2.1.306 plus the managed meta-bridge installer;
|
|
94
94
|
older versions silently drop exec-hook arguments and are refused.
|
|
95
95
|
|
|
96
96
|
Claude Code supports both CLI registration and a separated global MCP config. The separated file is recommended for dotfile / `agent-config` workflows because `~/.claude.json` also carries OAuth-bearing state.
|
|
@@ -185,7 +185,7 @@ entwurf doctor-agy-hooks
|
|
|
185
185
|
|
|
186
186
|
The three adapters deliberately own different atoms:
|
|
187
187
|
|
|
188
|
-
- 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), neither is the manual `entwurf_register_native` fallback,
|
|
188
|
+
- 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), neither is the manual `entwurf_register_native` fallback, neither are `entwurf_fresh_call` / `entwurf_resume_call` (both launch into the caller's own tmux server, which an agy conversation has none of), and `entwurf_retire_call` stays at agy's default Ask (a retirement is one operator-requested action, never a standing grant);
|
|
189
189
|
- statusline: the complete `statusLine` subtree pointing at the bare stable bin `entwurf-agy-statusline`;
|
|
190
190
|
- hooks: one named `PreInvocation` hook pointing at the bare stable bin `entwurf-agy-imprint`.
|
|
191
191
|
|
|
@@ -253,8 +253,10 @@ spawned. The installer refuses to write into a config that denylists its own key
|
|
|
253
253
|
**The tool names are omp's dialect, not Claude's.** omp mints `mcp__<server>_<tool>` after
|
|
254
254
|
lowercasing and replacing every `[^a-z_]+` run with `_`, collapsing runs and trimming edges,
|
|
255
255
|
so `entwurf_v2` surfaces as `mcp__entwurf_bridge_entwurf_v` — the trailing digit is eaten by
|
|
256
|
-
the charset, not by the length cap. The live tool list is the acceptance oracle
|
|
257
|
-
|
|
256
|
+
the charset, not by the length cap. The live tool list is the acceptance oracle. The recorded
|
|
257
|
+
observation mounted eight tools; the 0.41.0 bridge has nine, and that expanded OMP
|
|
258
|
+
live offering needs its own receipt. Retirement remains explicitly operator-requested, not
|
|
259
|
+
auto-granted by mounting the tool.
|
|
258
260
|
|
|
259
261
|
**And the NAME is not the invocation. Under omp's default settings an MCP tool is not a
|
|
260
262
|
function the model calls — it is a virtual file it writes to.** `tools.xdev` (boolean,
|
|
@@ -273,7 +275,7 @@ top-level (`Tool web_search not found`, upstream #5973), fixed by pinning it via
|
|
|
273
275
|
|
|
274
276
|
`read xd://` reports exactly what the default hides. `[측정]` on a host with only this
|
|
275
277
|
bridge registered, **11 devices**: omp's own `ast_edit`, `debug`, `lsp`, `browser`, plus all
|
|
276
|
-
seven `entwurf_*` (as reported in that earlier measurement; the current bridge declares
|
|
278
|
+
seven `entwurf_*` (as reported in that earlier measurement; the current source bridge declares nine). So the default does not merely wrap entwurf — it wraps omp's own LSP and
|
|
277
279
|
debugger too.
|
|
278
280
|
|
|
279
281
|
**`entwurf setup` writes this for a detected omp host, and `entwurf install-omp-config` is
|
package/docs/fresh-cut-policy.md
CHANGED
|
@@ -84,7 +84,15 @@ entwurf meta-bridge-fresh-cut && entwurf setup /path/to/project
|
|
|
84
84
|
## Upgrade order
|
|
85
85
|
|
|
86
86
|
A checkout-backed host can begin running new code immediately after `git pull`, so
|
|
87
|
-
make the boundary explicit:
|
|
87
|
+
make the boundary explicit. First distinguish an unreadable generation from a stale reader:
|
|
88
|
+
a known V3 schema extension (such as `attachIncarnation`) or newly admitted backend rejected
|
|
89
|
+
by an older strict reader is **reader-version skew, not a generation change**. Preserve the
|
|
90
|
+
records and native identity, roll every participating source/compiled/installed reader and
|
|
91
|
+
external mirror forward to the owning contract, then verify each active rail. Do not delete
|
|
92
|
+
fields, invent bindings, rewrite ids or execute an old reader's fresh-cut prescription merely
|
|
93
|
+
to silence that skew. Unmeasured readers remain an open rollout axis, not a pass.
|
|
94
|
+
|
|
95
|
+
For an actual generation transition, the order remains:
|
|
88
96
|
|
|
89
97
|
```text
|
|
90
98
|
quiesce sessions → update package/checkout → fresh-cut if prescribed → reinstall/setup → reopen
|