@junghanacs/entwurf 0.15.1 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +229 -0
- package/DELIVERY.md +3 -2
- package/README.md +70 -87
- package/VERIFY.md +4 -1
- package/docs/acp-backend-rail.md +1 -1
- package/docs/external-mcp-host.md +147 -9
- package/docs/setup-clean-host.md +105 -0
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +65 -20
- package/mcp/entwurf-bridge/dist/pi-extensions/entwurf-capabilities.json +1 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +17 -6
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +1 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +172 -5
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +152 -17
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/omp-fresh-preflight.js +271 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-omp.js +988 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-receive-omp.js +574 -0
- package/mcp/entwurf-bridge/dist/scripts/omp-receive-facts.js +84 -0
- package/mcp/entwurf-bridge/src/index.ts +65 -19
- package/mcp/entwurf-bridge/tsconfig.build.json +19 -3
- package/mcp/tsconfig.json +10 -0
- package/package.json +13 -3
- package/pi/entwurf-capabilities.json +1 -0
- package/pi/meta-bridge-omp/entwurf-meta-omp/package.json +7 -0
- package/pi/omp-receive/entwurf-receive-omp/package.json +7 -0
- package/pi-extensions/entwurf-control.ts +12 -9
- package/pi-extensions/lib/entwurf-self-address.ts +18 -7
- package/pi-extensions/lib/meta-sender-identity.ts +1 -1
- package/pi-extensions/lib/meta-session.ts +219 -5
- package/pi-extensions/lib/mux-fresh-call.ts +171 -17
- package/pi-extensions/lib/omp-fresh-preflight.ts +275 -0
- package/pi-extensions/meta-bridge-omp.ts +1244 -0
- package/pi-extensions/meta-bridge-receive-omp.ts +666 -0
- package/run.sh +296 -4
- package/scripts/check-entwurf-self-address.ts +31 -0
- package/scripts/check-gate-qualification.ts +4 -1
- package/scripts/check-harness-admission-parity.ts +143 -0
- package/scripts/check-meta-doctor-oracle.sh +20 -0
- package/scripts/check-omp-birth-hook.ts +1049 -0
- package/scripts/check-omp-fresh-preflight.ts +181 -0
- package/scripts/check-omp-receive-arm.ts +516 -0
- package/scripts/inventory-verification-surface.ts +1 -1
- package/scripts/meta-bridge-hook-log.sh +9 -1
- package/scripts/mutants/copilot-birth.json +7 -5
- package/scripts/mutants/mux-fresh-call.json +22 -22
- package/scripts/mutants/omp-birth.json +173 -0
- package/scripts/mutants/omp-fresh.json +300 -0
- package/scripts/mutants/omp-receive.json +135 -0
- package/scripts/mutants/self-address.json +34 -0
- package/scripts/omp-bridge-doctor.sh +315 -0
- package/scripts/omp-bridge-install.sh +221 -0
- package/scripts/omp-bridge-oracle.sh +154 -0
- package/scripts/omp-bridge-uninstall.sh +57 -0
- package/scripts/omp-mcp-bridge.sh +320 -0
- package/scripts/omp-mcp-config.py +392 -0
- package/scripts/omp-receive-doctor.sh +246 -0
- package/scripts/omp-receive-facts.ts +106 -0
- package/scripts/omp-receive-install.sh +228 -0
- package/scripts/omp-receive-uninstall.sh +60 -0
- package/scripts/omp-tool-surface.py +349 -0
- package/scripts/raw-omp-measure/README.md +420 -0
- package/scripts/raw-omp-measure/probe-extension.ts +76 -0
- package/scripts/raw-omp-measure/probe-receive-surface.ts +250 -0
- package/scripts/raw-omp-measure/source-audit.md +414 -0
- package/scripts/smoke-omp-bridge-state.sh +221 -0
- package/scripts/smoke-omp-fresh-live.ts +497 -0
- package/scripts/smoke-omp-mcp-state.sh +327 -0
- package/scripts/smoke-omp-receive-live.ts +340 -0
- package/scripts/smoke-omp-receive-state.sh +196 -0
- package/scripts/tsconfig.json +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,235 @@ All notable changes to this project will be documented here. Format follows [Kee
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.16.0 - 2026-08-31
|
|
8
|
+
|
|
9
|
+
This release admits **OMP (`omp`) as the fifth garden backend** and closes the admission
|
|
10
|
+
contract that let a citizen ship without the legs that make it reachable. Bundles A, B and C
|
|
11
|
+
are one arc — birth and identity, addressed receive, visible fresh — and the durable half is
|
|
12
|
+
the general rule they forced: from OMP onward, the FIRST release of a harness admitted under
|
|
13
|
+
the #82 contract owes its clause 7 visible-fresh receipt as a release-gate MUST step, its
|
|
14
|
+
citizen↔fresh parity edge inside `pnpm run check:full`, and two cross-harness dispatch
|
|
15
|
+
receipts. Every OMP LIVE claim below is one Linux host, one model, one accepted run; that
|
|
16
|
+
limit is stated once in Notes and is not softened anywhere above it. (#87)
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **OMP is an addressable garden citizen.** `omp` enters the backend registry (`wakeMode`
|
|
21
|
+
`self-fetch`, `deliveryLevel` `D6`, `nativeIdLabel` `sessionId`) and
|
|
22
|
+
`pi-extensions/meta-bridge-omp.ts` mints it: an omp hook IS an in-process extension, so
|
|
23
|
+
birth, the scope fence, the status line and the sender marker are one module. Both birth
|
|
24
|
+
edges are bound — `session_switch` is where `/new`, fork and in-TUI resume re-fire — and
|
|
25
|
+
every mode but `mode === "tui"` is refused before any write. The fence is the vendor's own
|
|
26
|
+
mode and nothing else: `hasUI` is true under rpc/rpc-ui/ACP, so a fence built on it would
|
|
27
|
+
admit exactly the sessions this refuses. A task subagent mints nothing. The step-6 join is
|
|
28
|
+
one process, so the marker is keyed to `process.pid`, never `process.ppid`. Gates:
|
|
29
|
+
`check-omp-birth-hook`, `smoke-omp-bridge-state`, `scripts/mutants/omp-birth.json`. (#87)
|
|
30
|
+
- **An omp-native MCP hand that shadows the borrowed Claude import.** The writer targets omp's
|
|
31
|
+
own `<omp agent dir>/mcp.json` in the vendor's own writer shape, and the server key is a
|
|
32
|
+
PINNED LITERAL `entwurf-bridge` — that pin is the entire mechanism. On a host that ever used
|
|
33
|
+
Claude Code, omp already imports an `entwurf-bridge` server labeled
|
|
34
|
+
`external-mcp/claude-code`; native provider priority beats the import and dedupe is
|
|
35
|
+
first-wins on the key with `equivalent()` never consulted, so a byte-identical key suppresses
|
|
36
|
+
the import while a different key would load BOTH and one of them would keep introducing an
|
|
37
|
+
omp session as Claude Code. `disabledServers` is never the hide-import tool — suppression is
|
|
38
|
+
by name and a suppressed item still claims the key — so the writer refuses to install under a
|
|
39
|
+
denylist of its own key and the doctor is red while one exists. `doctor-omp-mcp` adds an
|
|
40
|
+
EFFECTIVE-source read (native-wins / import-wins / both-suppressed / no-entry) and labels it
|
|
41
|
+
what it is: a configuration read of vendor precedence, never a runtime receipt. Gate:
|
|
42
|
+
`smoke-omp-mcp-state`. (#87)
|
|
43
|
+
- **OMP receives addressed messages — the garden is no longer one-way for it.**
|
|
44
|
+
`pi-extensions/meta-bridge-receive-omp.ts` joins the citizen in the SAME process, holds an
|
|
45
|
+
`fs.watch` on its mailbox signal, and rings an announce-only doorbell through the vendor's
|
|
46
|
+
`pi.sendUserMessage` — measured to live on the factory object rather than the event ctx, and
|
|
47
|
+
measured to start a turn on an idle host with zero typing. The model drains with
|
|
48
|
+
`entwurf_inbox_read`, and that read is the receipt. The `/new` unarm is rail-specific: the
|
|
49
|
+
watch lives inside the operator's TUI, where pid plus start-key cannot see a citizen change
|
|
50
|
+
underneath a living process, so the old garden id is explicitly unarmed and the replacement
|
|
51
|
+
armed. Bounded arm defer, watch-error, vanished-signal and overlapping-edge paths are all
|
|
52
|
+
fail-closed. Install, uninstall and doctor surfaces ship with it, plus
|
|
53
|
+
`check-omp-receive-arm` with `scripts/mutants/omp-receive.json`, `smoke-omp-receive-state`
|
|
54
|
+
and `smoke-omp-receive-live`. (#87)
|
|
55
|
+
- **`entwurf_fresh_call` opens omp on all three public surfaces.** A five-axis pre-mutation
|
|
56
|
+
preflight decides the launch before the tmux window exists, so a missing prerequisite is a
|
|
57
|
+
named refusal instead of a dead window; the fifth axis is omp-specific (`tools.xdev !==
|
|
58
|
+
true`). There is NO positional prompt. The fixed registered flag `--entwurf-bootstrap`
|
|
59
|
+
carries a closed `{v,target,nonce,task}` grammar — an unknown key is a refusal — and the
|
|
60
|
+
installed birth extension runs a two-stage bootstrap: bounded readiness polling over both
|
|
61
|
+
public tool snapshots, a callback-ONLY prompt, then the task released only by the exact
|
|
62
|
+
successful `tool_result` (stored `toolCallId`, tool name, target, nonce and
|
|
63
|
+
`isError === false` all matching) and delivered at that same session's next `turn_end`. That
|
|
64
|
+
shape is a measurement, not a preference: the positional candidate opened its window, minted
|
|
65
|
+
its citizen, received the framing byte-identical, and answered the literal text `ACK` with
|
|
66
|
+
zero tool calls — the vendor's interactive UI defers MCP discovery while the positional
|
|
67
|
+
`initialMessage` prompts straight after `mode.init()`, so the turn began roughly 830ms before
|
|
68
|
+
the tool it was told to call existed. (#87)
|
|
69
|
+
- **`check-harness-admission-parity` — the missing edge between two closed loops.** Every
|
|
70
|
+
backend in `META_CITIZEN_BACKENDS` must appear in `FRESH_CALL_BACKENDS` or be a declared
|
|
71
|
+
pre-#82 legacy admission whose exception a reader can find in `DELIVERY.md`. Registry↔citizens
|
|
72
|
+
and surfaces↔fresh-set each already had a guard, but no file imported both constants, which is
|
|
73
|
+
how omp could pass the entire floor as a D6 citizen that `entwurf_fresh_call` cannot open. The
|
|
74
|
+
gate went red on `Unaccounted: omp` the moment it was added and green when Bundle C closed it.
|
|
75
|
+
It runs inside `check:contracts`, and therefore inside `pnpm run check:full`. (#87)
|
|
76
|
+
- **Two OMP LIVE steps in the release-gate MUST tier.** `smoke-omp-fresh-live` is clause 7's
|
|
77
|
+
worked instance. `smoke-omp-receive-live` reads the capability registry and decides its own
|
|
78
|
+
outcome — no drainable mailbox is a protocol SKIP, which `--cut` reads as red; a registry
|
|
79
|
+
claiming a receive rail with no acceptance body here is a FAIL. Neither is a hardcoded pass,
|
|
80
|
+
and the receive step was wired while omp was still outbound-only, so the one-way boundary
|
|
81
|
+
stopped being prose a cut could pass over in silence. (#87)
|
|
82
|
+
- **`docs/adding-a-harness.md` gains the shipped map and the release stop.** A comparative table
|
|
83
|
+
of the five admitted backends — lineage, receive rail, callback dialect, fresh launch form —
|
|
84
|
+
sits at the top so the variety is expected rather than re-derived at each admission. It pins
|
|
85
|
+
two lessons: lineage does not choose the rail (omp is pi underneath and rides Claude's mailbox
|
|
86
|
+
shape, because the rail follows the measured wake surface; what ancestry does instead is
|
|
87
|
+
concentrate the danger, since a shared env vocabulary is exactly where a fork splits a store),
|
|
88
|
+
and the doorbell doctrine — a hard bridge of measured dialects, explicit doorbells and honest
|
|
89
|
+
rejects is what makes the thing on the other side a peer rather than a disposable worker. The
|
|
90
|
+
release stop then states both executable halves of the admission rule plus the cross-harness
|
|
91
|
+
leg. (#87)
|
|
92
|
+
|
|
93
|
+
### Changed
|
|
94
|
+
|
|
95
|
+
- **`setup` is the install story on all three entry shapes.** npm global, npm project-local and
|
|
96
|
+
source clone now lead with `entwurf setup <project>`; `entwurf install <project>` is stated as
|
|
97
|
+
the narrower pi-wiring repair leaf that composes no harness. The 14-line native-harness paste
|
|
98
|
+
that read as the install recipe is now "repair and doctors" — one paragraph plus the command
|
|
99
|
+
names, with every per-unit installer, doctor and inverse retained, because a single broken unit
|
|
100
|
+
must still be redoable alone. The user-scope ownership matrix and the manual MCP registration
|
|
101
|
+
paths moved to the documents that already own them. Stale live claim corrected: after an
|
|
102
|
+
upgrade the operator was told to rerun every owned installer; `setup` re-composes them.
|
|
103
|
+
`package.json` gains the `copilot` keyword, shipped since 0.15.0 but unlisted. (#86)
|
|
104
|
+
- **OMP meta roots resolve as one indivisible bundle, never through `piAgentDir()`.** omp is a pi
|
|
105
|
+
fork and inherits pi's env vocabulary, so `PI_CODING_AGENT_DIR` means "pi's persistence root"
|
|
106
|
+
to entwurf and "my agent dir" to the vendor — a plain `omp --profile work` sets it. One pure
|
|
107
|
+
resolver leaf now serves both consumers, the in-process birth extension and the omp-labeled
|
|
108
|
+
bridge child, so agreement is by construction rather than two places computing the same thing.
|
|
109
|
+
A relative override fails closed instead of letting cwd become an authority: measured, the same
|
|
110
|
+
relative value resolved to two different stores because the extension's cwd is wherever the
|
|
111
|
+
operator launched omp while the doctor's is the repository. Installers refuse rather than guess
|
|
112
|
+
under an inherited `PI_CODING_AGENT_DIR` / `PI_CONFIG_DIR` / `PI_PROFILE`. (#87)
|
|
113
|
+
- **`PI_SESSION_ID` and `PI_AGENT_ID` are scrubbed at the launch seam for every backend.**
|
|
114
|
+
Measured on the operator host: a tmux server env carrying `PI_SESSION_ID` was inherited
|
|
115
|
+
verbatim by a new pane, so a sibling's bridge child could phone home under another citizen's
|
|
116
|
+
identity. The scrub is at the seam, not per backend. (#87)
|
|
117
|
+
- **The deterministic floor composes the omp gates.** `check:hermetic` gains
|
|
118
|
+
`smoke-omp-bridge-state`, `smoke-omp-mcp-state`, `smoke-omp-receive-state`,
|
|
119
|
+
`check-omp-receive-arm` and `check-omp-fresh-preflight`; `check:contracts` gains
|
|
120
|
+
`check-harness-admission-parity`. Both tiers still exclude the separately scheduled
|
|
121
|
+
`check-gate-qualification`, and `setup` still does not compose omp. (#87)
|
|
122
|
+
- **`docs/adding-a-harness.md` step 5 now says to measure the invocation FORM, not only the tool
|
|
123
|
+
name.** omp mounts MCP tools as `xd://` virtual devices by default (`tools.xdev`), so a correct
|
|
124
|
+
tool NAME is still not a callable function: the model must read the device for a schema that
|
|
125
|
+
`tools.xdevDocs` keeps off-prompt, then write JSON to the same path to execute. Measured on omp
|
|
126
|
+
18.0.0, a plain send under that default listed peers and then reported delivery with nothing
|
|
127
|
+
enqueued, and the mount also hid omp's own lsp, debug, browser and ast_edit — 11 devices in
|
|
128
|
+
all. `tools.xdev: false` restores every enabled tool top-level and leaves plan mode's
|
|
129
|
+
`xd://propose` finalization intact. (#87)
|
|
130
|
+
|
|
131
|
+
### Fixed
|
|
132
|
+
|
|
133
|
+
- **The bridge boot entry was in no typecheck program.** `mcp/tsconfig.json` extended the root
|
|
134
|
+
config without re-declaring `exclude`, so the inherited `"mcp"` resolved to `<repo>/mcp` and
|
|
135
|
+
filtered out everything its own `include` added; `mcp/entwurf-bridge/src/index.ts` — the
|
|
136
|
+
785-line bridge boot entry — was the only tracked `.ts` in the repo in no `tsc --noEmit`
|
|
137
|
+
program at all, and nothing imports it, so nothing rescued it through the import graph. Orphan
|
|
138
|
+
census 1 line before, 0 after; the mcp program's repo-file count moved 27 → 54, all product
|
|
139
|
+
sources. The emit path is untouched, so there is no product runtime change.
|
|
140
|
+
- **`entwurf_self` stopped rendering a mailbox nothing drains.** `metaDeliveryDomain` was derived
|
|
141
|
+
as native-push or self-fetch, so an omp citizen was handed a `mailboxPath` with no drainer. It
|
|
142
|
+
now has three values: `nativePushSupported` → native-push, else the decider's mailbox seam →
|
|
143
|
+
self-fetch, else none. Dispatch and `wakeMode` are untouched. (#87)
|
|
144
|
+
- **`doctor-omp-mcp` reads `tools.xdev` on the runtime axis.** An absent file or key applies the
|
|
145
|
+
vendor default (xdev on, empty inline allowlist) and is RED while the native hand is the
|
|
146
|
+
effective source; `xdev: false` is ok and a covering `xdevInlineDevices` glob is
|
|
147
|
+
ok-with-note. Ownership stays a separate question, and the smoke never touches the host
|
|
148
|
+
`config.yml`. (#87)
|
|
149
|
+
- **The bootstrap epoch now ends before the birth edge can bail.** Epoch termination depended on
|
|
150
|
+
reaching `startOmpBootstrap`, so a later birth edge that bailed early — a refused envelope or a
|
|
151
|
+
throwing upsert — skipped the invalidation, and on a same-id resume both handler fences still
|
|
152
|
+
passed, leaving the earlier defect shape alive in a narrow window. One rule, one owner:
|
|
153
|
+
`endBootstrapEpochOnLaterEdge` runs right after the mode fence, before the envelope is read,
|
|
154
|
+
and the consumed branch delegates to the same helper. Zero new state, zero new exports. (#87)
|
|
155
|
+
- **The omp-fresh qualification manifests were settled by measurement.** The first standalone
|
|
156
|
+
qualification run on the Bundle C bytes caught what static exactness could not: four mutants
|
|
157
|
+
whose claim and signature named different cells, one QK token minted twice in its gate source,
|
|
158
|
+
twelve find hunks left stale by the bundle's own refactor and the amendment's rewiring, and one
|
|
159
|
+
kill-site guess that died at an anonymous cell. Every repair was adjudicated by
|
|
160
|
+
apply/gate/revert measurement rather than by guess, and kill sites the floor disputed were
|
|
161
|
+
moved to where the kill actually lands. Separately, two mutants had been added to the
|
|
162
|
+
self-address lane without extending `EXPECTED_LANE_MUTANTS` — exactly the drift that assertion
|
|
163
|
+
exists to catch; the declared contract now says 5. (#87)
|
|
164
|
+
- **Two packaging omissions in the omp units.** `pi/meta-bridge-omp/entwurf-meta-omp/package.json`
|
|
165
|
+
and `pi/omp-receive/entwurf-receive-omp/package.json` were absent from `files[]`, so
|
|
166
|
+
`install-omp-receive` died in the installed package while passing from a checkout. (#87)
|
|
167
|
+
- **`check-pack-install` pins the transitive `@earendil-works/pi-telemetry` to 0.84.3.** Upstream
|
|
168
|
+
published the 0.84.4 family on 2026-08-28; `pi-agent-core@0.84.3` and `pi-ai@0.84.3` both carry
|
|
169
|
+
a `^0.84.3` caret on it, so the lockfile-less fresh-temp install floated to 0.84.4 and the leak
|
|
170
|
+
assertion failed closed in the `install-surface` CI job. The pin keeps the verified 0.84.3
|
|
171
|
+
constellation ours to hold; the leak assertion still guards every other pi package and any
|
|
172
|
+
future closure growth. The 0.84.4 bump itself remains a separate hard-cut lane.
|
|
173
|
+
- **The omp doctor treated Bundle C's empty tmux scrub as inherited identity.** `tmux -e NAME=`
|
|
174
|
+
writes `PI_SESSION_ID=` / `PI_AGENT_ID=` present-but-empty; authoritative readers trim and
|
|
175
|
+
require truthy values, so empty and absent are the same answer. The doctor was presence-testing
|
|
176
|
+
those names, which turned `check:full` red whenever a visible fresh omp citizen was alive.
|
|
177
|
+
It now flags only a nonblank value, and the hermetic smoke hands it fixture pids rather than
|
|
178
|
+
the host `pgrep`. (#87)
|
|
179
|
+
|
|
180
|
+
### Verification
|
|
181
|
+
|
|
182
|
+
Each receipt carries its own scope; none of them is transferable to another commit or host.
|
|
183
|
+
|
|
184
|
+
- **`./run.sh check-gate-qualification`** — **324/324 KILLED, NOT KILLED 0**, standalone on the
|
|
185
|
+
Bundle C candidate (`fd5e462`), independently re-verified by a second model on the gate
|
|
186
|
+
predicate plus a full-lane rescan and a 3/3 sample re-kill.
|
|
187
|
+
- **`pnpm run check:full`** — exit 0 in 430s on that same candidate, after the `build-bridge`
|
|
188
|
+
refresh the stale-dist tripwire demanded.
|
|
189
|
+
- **Clause 7 LIVE** — `smoke-omp-fresh-live` green 2026-08-30, 21 assertions, oracle / omp 18.0.0
|
|
190
|
+
/ `openai-codex/gpt-5.6-sol`. The sibling's garden `20260830T192913-df52b9` came from the
|
|
191
|
+
CALLBACK's sender envelope and never from the launch receipt; exactly one new citizen;
|
|
192
|
+
`lastEnqueuedAt 10:29:19.179Z` / `lastReadAt 10:29:24.673Z`, with the drain visible in that
|
|
193
|
+
session's own transcript for its own garden id. It took two runs: the first went red on
|
|
194
|
+
stage-two delivery alone, which is the argument for making it a MUST.
|
|
195
|
+
- **Receive acceptance (D6)** — 2026-08-30, oracle, omp 18.0.0: garden `20260830T140819-116f6a`,
|
|
196
|
+
`lastEnqueuedAt 05:08:20.555Z` / `lastReadAt 05:08:23.958Z`. D3 isolation is PROVEN, not
|
|
197
|
+
pending: with two live armed omp citizens, one addressed enqueue rang exactly one doorbell
|
|
198
|
+
while the sibling persisted no transcript and kept an empty mailbox.
|
|
199
|
+
- **Cross-harness leg** — 2026-08-31, the first bidirectional live-turn roundtrip on the committed
|
|
200
|
+
bytes: a claude-code citizen opened a fresh omp sibling through the public surface (callback
|
|
201
|
+
sender garden `20260831T124226-eac41a`), dispatched an addressed `entwurf_v2` into it, and the
|
|
202
|
+
omp citizen's own live turn drained the doorbell and replied into the claude mailbox.
|
|
203
|
+
- **`LIVE=1 ./run.sh release-gate <scratch> --cut`** — **MUST PASS=23 FAIL=0 SKIP=0,
|
|
204
|
+
BEHAVIOR PASS=1 FAIL=0 SKIP=0, `cut: OK`.** `check-gate-qualification` inside the gate
|
|
205
|
+
killed **325/325** mutants across 36 lanes. Log:
|
|
206
|
+
`/tmp/entwurf-release-gate-0.16.0.run2.DfMtRj/release-gate.log` (SHA-256
|
|
207
|
+
`2df4f6d4bddd563431ca41d2a43074f2cb6ccf9926ec6e8c7323de1a6ddf8192`).
|
|
208
|
+
A first attempt on the same versioned tree (scratch `.../entwurf-release-gate-0.16.0.AyHcIJ`)
|
|
209
|
+
hit one MUST FAIL in `smoke-entwurf-v2-matrix-live` C1b: the hidden-store resident did not
|
|
210
|
+
birth a record inside the 30s boot window. The same smoke rerun standalone passed 17 checks
|
|
211
|
+
in 4.9s; the rerun cut above is the acceptance. `pnpm run check:full` on the versioned tree
|
|
212
|
+
was exit 0 in 432s before P5.
|
|
213
|
+
|
|
214
|
+
### Notes
|
|
215
|
+
|
|
216
|
+
- **Evidence limit.** Every OMP LIVE claim above is one Linux host (oracle, ARM), one model, one
|
|
217
|
+
accepted run. Multi-host, multi-model and repeated fresh calls inside one process are not
|
|
218
|
+
claimed and are not evidenced here.
|
|
219
|
+
- **Operator prerequisite.** `tools: xdev: false` in `~/.omp/agent/config.yml`. Under the vendor
|
|
220
|
+
default the doorbell would name a tool the model cannot call, so both the fresh preflight and
|
|
221
|
+
the LIVE smokes check it as a precondition. `setup` does not compose omp.
|
|
222
|
+
- Measured against **omp 18.0.0** while the vendor announces 18.0.11. The `mode === "tui"`
|
|
223
|
+
discriminator, the `xd://` behaviour and the five measurement cells recorded in
|
|
224
|
+
`scripts/raw-omp-measure/README.md` §M7 are re-measurement targets on upgrade.
|
|
225
|
+
- Copilot's operator-metered clause 7 exception is preserved, not reopened. The release stop
|
|
226
|
+
applies from OMP onward, forward-only.
|
|
227
|
+
- The cross-harness leg's deterministic half — every post-contract citizen backend having a wired
|
|
228
|
+
cross-harness LIVE step or a declared metered exception — is an owed follow-up. Until that gate
|
|
229
|
+
lands the rule is prose, and `docs/adding-a-harness.md` says so in place.
|
|
230
|
+
- Pi `0.84.4` remains a separate hard-cut lane.
|
|
231
|
+
- #90 is measured but unfixed: installed Claude Code sends `model` as a STRING on the interactive
|
|
232
|
+
`SessionStart` envelope and omits it entirely in print mode, while the reader accepts only the
|
|
233
|
+
object shape, so claude-code records carry no model. Widening the reader and pinning both shapes
|
|
234
|
+
in a fixture is a separate lane.
|
|
235
|
+
|
|
7
236
|
## 0.15.1 — 2026-08-27
|
|
8
237
|
|
|
9
238
|
This patch is the Linux install-honesty floor for #86: Entwurf installs itself only,
|
package/DELIVERY.md
CHANGED
|
@@ -84,11 +84,12 @@ can be owned without being supported; a supported harness still has to walk
|
|
|
84
84
|
|---|---|---|---|
|
|
85
85
|
| **pi native Entwurf** | shipped | D7; D8 partial | Record-addressed Unix control socket. A record-less socket is diagnostic only and never dispatched. |
|
|
86
86
|
| **Claude Code interactive `>=2.1.217`** | shipped; Linux certified | D6; D7/D8 partial | Per-session mailbox + exec-form `FileChanged`/`asyncRewake`. B2 proved idle wake and same-session continuity on one NixOS host. |
|
|
87
|
-
| **Antigravity / agy** | shipped | D6; D7 partial | Record-backed native-push through LS gRPC `agentapi send-message`; no mailbox or receiver marker. |
|
|
87
|
+
| **Antigravity / agy** | shipped | D6; D7 partial | Record-backed native-push through LS gRPC `agentapi send-message`; no mailbox or receiver marker. Admitted before the #82 step 9 contract and not re-evaluated under it, so it is legacy citizen evidence, not a step-9 supported harness: `entwurf_fresh_call` cannot open an agy sibling, and nothing here should be read as claiming visible lifecycle parity. |
|
|
88
88
|
| **Codex app-server-backed TUI** | verified probe | D7; D8 unproven | WebSocket-over-UDS `turn/start` into a live `threadId`; status events expose completion. No owned native-citizen install/invocation lane. |
|
|
89
89
|
| **Codex embedded TUI** | deferred | D0 partial | No supported receive socket/hook on the measured standalone shape. |
|
|
90
90
|
| **Copilot CLI first-party extension** | raw transport probe; superseded by the owned product unit | D7 path observed; D3 control receipt incomplete; D8 unproven | CLI-spawned extension over stdio JSON-RPC; `joinSession()` + documented `fs.watch` → `session.send({mode:"enqueue"})`. Idle wake, exact-marker reply, and completion passed on 2026-08-23 (CLI 1.0.80, L4, one Linux host). Two-process isolation was observed but its decisive B log was not preserved. Kept as the transport receipt the owned receive unit was built on; the shipped unit differs deliberately — it announces the inbox instead of injecting the body. |
|
|
91
91
|
| **Copilot CLI garden citizen** | shipped in 0.15.0; send + receive + visible fresh accepted on one host | D6; D7 partial; D3 pending; D8 unproven | Birth, garden id, MCP hand and record-backed sender identity are accepted; the RECEIVER is an installed first-party extension that binds to the V3 record, writes a receiver marker owned by the WATCHER pid, and rings a doorbell the model drains with `entwurf_inbox_read`. `wakeMode` is `self-fetch`, so dispatch reaches the mailbox rail: armed → delivered, unarmed/stale → the honest `mailbox-undeliverable` refusal. **D6 is the owned-invocation LIVE acceptance of 2026-08-23** — garden `20260823T181316-d9f6ba`, native `20fe30c8-b2bc-4600-91a0-8a409131be51`, CLI 1.0.80: receive log `joined`→`armed`→`doorbell fresh=1`→`rang`, mailbox `lastEnqueuedAt 09:23:41.235Z` / `lastReadAt 09:23:56.480Z`, and a model reply on the same record/native/gid chain. **Visible fresh (step 9 clause 7) is a separate LIVE, 2026-08-25** — launch window `@89`/`%89` nonce `mux-fresh-call-690529ae99f99faa2252aefb`; exact-callback garden `20260825T085721-f68be0`; one `entwurf_v2` → `meta-mailbox → enqueued`; same garden `lastReadAt 2026-08-24T23:57:47.784Z` plus same-gid reply; GLG saw footer garden id and a healthy multi-turn window. Those rows stay unmerged. D7 is PARTIAL: reply and read receipt were observed, the completion taxonomy and long-haul operation were not. D3 (second-session isolation of an owned invocation) is PENDING — observed once, decisive log lost to scratch cleanup. Evidence level L4: one host. Launch through the owned invocation `entwurf copilot`, which sets `COPILOT_CLI_ENABLED_FEATURE_FLAGS=EXTENSIONS` for that one process; `doctor-copilot-receive` reads live CLI environments because a session launched without it is silently inert. Visible fresh is operator-metered and is not a release-gate MUST. |
|
|
92
|
+
| **OMP (`omp`) garden citizen** | shipped in 0.16.0; send + receive + visible fresh accepted on one host | D6; D3 proven; D7 partial; D8 partial | Two in-process extensions in the operator's own TUI: birth mints the `mode === "tui"` host (subagents mint nothing) and names it as sender; the RECEIVER unit joins that citizen in the SAME process, holds an `fs.watch` on its mailbox signal, and rings an announce-only doorbell through the vendor's `pi.sendUserMessage` — measured to be on the FACTORY object, not the event ctx, and measured to start a turn on an idle host with zero typing (`agent_start` +31ms). `wakeMode` is `self-fetch`: the model drains with `entwurf_inbox_read` and THAT read is the receipt. **D6 is the LIVE acceptance of 2026-08-30** (oracle, omp 18.0.0) — garden `20260830T140819-116f6a`, `lastEnqueuedAt 05:08:20.555Z` / `lastReadAt 05:08:23.958Z`, and the citizen's own transcript carrying `mcp__entwurf_bridge_entwurf_inbox_read` for its own garden id. **D3 is PROVEN, not pending**: with two live omp citizens armed, one addressed enqueue rang exactly one doorbell and the sibling persisted no transcript and kept an empty mailbox. D7 is PARTIAL (`lastReadAt` needs no scraping; the reply does). D8 is PARTIAL — dedupe and every stale-handling path are implemented and hermetically pinned, ordering/loop-guard/crash-recovery are not. The `/new` unarm is the rail-specific one: the watch lives in the operator's TUI, so pid + start-key cannot see a citizen change underneath a living process, and without an explicit unarm the previous garden id would keep reading deliverable. Requires `tools: xdev: false` in `~/.omp/agent/config.yml` — the vendor default hides MCP tool schemas from the prompt, so the doorbell would name a tool the model cannot call. The decisive receipt lines — the ordering probe, the D6 chain, the D3 isolation and the `/new` unarm — are pasted into `scripts/raw-omp-measure/README.md` §M7 rather than left in a host-local `/tmp` path. Evidence level L4: one Linux host, ARM. **Visible fresh (step 9) is ACCEPTED — the clause 7 LIVE went green on 2026-08-30:** `entwurf_fresh_call` opens omp on all three public surfaces through the bare `omp` runtime with an explicit `--approval-mode yolo` width and the `mcp__entwurf_bridge_entwurf_v` callback name, behind a five-axis pre-mutation preflight whose fifth axis is omp-specific (`tools.xdev !== true`, without which the model cannot call the callback tool at all). **The first turn is a TWO-STAGE BOOTSTRAP rather than a positional prompt, and that is a measured correction, not a preference.** `[LIVE 2026-08-30]` the positional-prompt candidate opened its window and minted its citizen (garden `20260830T181342-452167`, native `01a051f2-3107-7147-8806-fa2a6f527610`), delivered the byte-identical framing as a user message at `09:13:42.413Z`, and the model answered the literal text `ACK` at `09:13:47.105Z` with ZERO tool calls; the caller timed out at 240s. `[source]` the interactive UI defers MCP discovery (`sdk.ts:1847-1855`, `:1881-1905`) while the positional `initialMessage` prompts straight after `mode.init()` (`main.ts:540-565`), and `[측정]` an observer on the same runtime saw `turn_start` at +654ms with the entwurf tools absent and the callback tool present only at +1484ms. So the launcher now carries `{v,target,nonce,task}` on the fixed registered flag `--entwurf-bootstrap`, and the in-process birth extension polls `getAllTools`(`source:"mcp"`) AND `getActiveTools` for the exact callback name, sends a callback-ONLY prompt, arms the task only on a `tool_result` whose stored `toolCallId`, tool name, target, nonce and `isError === false` all match, and DELIVERS it at the next `turn_end` of that same session. `[LIVE 2026-08-30]` that last boundary is itself a measured correction: a first attempt sent the task from inside the `tool_result` handler with an explicit `deliverAs: "followUp"`, the hook log showed the full chain (`bootstrap-armed` → `bootstrap-ready` +440ms → `bootstrap-callback-observed` → `bootstrap-released`), and the task still never appeared in the session — `[source]` an explicit `deliverAs` queues without starting a turn in either state, while the omitted form starts one when idle (`agent-session.ts:6511-6513`), which the same transcript confirmed three seconds later when the Bundle B doorbell's omitted-option send landed and started a turn. `[측정 2026-08-30]` the callback-only half is what was proven to work: model `openai-codex/gpt-5.6-sol`, tool live at +1105ms, prompt injected at +1107ms, and the sibling calling `mcp__entwurf_bridge_entwurf_v` with the exact nonce (`omp-cb-btkvva4r87` → `20260830T184054-1aa1f2`, `meta-mailbox → enqueued`). **The clause 7 acceptance, `smoke-omp-fresh-live` (release-gate MUST), 2026-08-30, 21 assertions, omp 18.0.0 / `openai-codex/gpt-5.6-sol`:** launch through `tools/call entwurf_fresh_call` with nonce `mux-fresh-call-34faea228f3c3638684b40ff`; sibling garden `20260830T192913-df52b9` taken from the CALLBACK's sender envelope and never from the launch receipt; exactly one new citizen (§3.5); addressed `entwurf_v2` → `meta-mailbox → enqueued`; `lastEnqueuedAt 10:29:19.179Z` / `lastReadAt 10:29:24.673Z`; the drain visible in that session's own transcript for its own garden id. **Both bootstrap stages are in that transcript in order** — the callback-only prompt at offset 970, the caller's task at 4732, no four-backend positional framing anywhere, and an assistant message after the task proving it started a turn rather than sitting in a queue. The unit's own log carries the state machine: `bootstrap-armed 10:29:13.399Z` → `bootstrap-ready 10:29:13.819Z` (+420ms) → `bootstrap-callback-observed 10:29:18.663Z` (`toolCallId=call_KZJtkxfzy1IEE4ejKutCPWcm|fc_0858…`) → `bootstrap-released 10:29:18.731Z` → `bootstrap-task-sent 10:29:18.759Z`. Evidence level L4: one Linux host, ARM, one run. `check-harness-admission-parity` keeps the deterministic half of the admission from being a matter of memory. What this does NOT establish: multi-host, multi-model, or repeated fresh calls in one process. **Cross-harness leg, 2026-08-31 (first bidirectional live-turn roundtrip on the committed bytes + operator redeploy):** a claude-code citizen (`20260831T090152-f998ac`) opened a fresh omp sibling through the public surface (nonce `mux-fresh-call-807cb693b1913ce98ffdbfd1`, callback sender garden `20260831T124226-eac41a`), dispatched an addressed `entwurf_v2` → `meta-mailbox → enqueued`, and the omp citizen's own live turn drained and replied into the claude mailbox — its self-report (doorbell → `entwurf_inbox_read`; callback-only first user message, task second) agrees with every receipt on the chain. |
|
|
92
93
|
| **Copilot CLI TUI+server** — *withdrawn lane, kept as evidence* | rejected | D7; D8 unproven | Older official-SDK probe over hidden `--ui-server`; idle enqueue worked, but loopback RPC authentication was not established. The bundled extension supersedes this candidate without reviving it. |
|
|
93
94
|
| **ACP Claude / Cortex** | shipped runtime, outside this matrix | — | ACP sessions are children launched by entwurf's pi adapter, not already-running native sessions to wake. |
|
|
94
95
|
|
|
@@ -137,7 +138,7 @@ native citizen or ACP backend. `turn/steer` is active-turn steering, not idle wa
|
|
|
137
138
|
|
|
138
139
|
### Copilot CLI: one citizen, two rails, one pending receipt
|
|
139
140
|
|
|
140
|
-
The
|
|
141
|
+
The shipped product owns the native citizen's birth, garden id, statusline, MCP hand,
|
|
141
142
|
outbound sender identity — and, since RAIL 5, the receiver. A real Copilot CLI 1.0.80
|
|
142
143
|
session minted a V3 record and sent under that record-backed garden id on 2026-08-21.
|
|
143
144
|
That proved who SENDS. Whether a reply LANDS is a different fact on a different process,
|
package/README.md
CHANGED
|
@@ -10,10 +10,10 @@ npm package: <https://www.npmjs.com/package/@junghanacs/entwurf>
|
|
|
10
10
|
|
|
11
11
|
Legacy package: [`@junghanacs/pi-shell-acp`](https://www.npmjs.com/package/@junghanacs/pi-shell-acp). `entwurf` is its 0.12+ successor line: the same work renamed around the garden-citizen dispatch substrate rather than the pi adapter.
|
|
12
12
|
|
|
13
|
-
> **Repository shape.** This repo is **entwurf-core (v2 dispatch) + native-harness bridges + a pi adapter + an ACP plugin**. Pi is one supported harness adapter — important because it supplies control sockets and hosts the ACP plugin today — but it is not the project subject. Claude Code and GitHub Copilot CLI are shipped as mailbox-backed self-fetch meta-sessions; Antigravity (`agy`) is shipped as a native-push citizen with automatic `PreInvocation` birth, ambient garden-id status, and a managed MCP/permission install surface. Codex has a launch-mode-specific verified delivery probe documented in [DELIVERY.md](./DELIVERY.md), but no managed native-citizen install lane yet. The ACP plugin ships two backends through one adapter rail: Claude (the reference) and Snowflake Cortex Code (landed in 0.13.0 under the measured contract in [docs/acp-backend-rail.md](./docs/acp-backend-rail.md#cortex-code-audit-d1d10)).
|
|
13
|
+
> **Repository shape.** This repo is **entwurf-core (v2 dispatch) + native-harness bridges + a pi adapter + an ACP plugin**. Pi is one supported harness adapter — important because it supplies control sockets and hosts the ACP plugin today — but it is not the project subject. Claude Code and GitHub Copilot CLI are shipped as mailbox-backed self-fetch meta-sessions; Antigravity (`agy`) is shipped as a native-push citizen with automatic `PreInvocation` birth, ambient garden-id status, and a managed MCP/permission install surface. OMP (`omp`) is a self-fetch citizen on the same rail as Claude and Copilot, opened by `entwurf_fresh_call` and accepted under the step 9 visible-fresh contract on 2026-08-30 — its first turn is a two-stage in-process bootstrap rather than an argv prompt, because the vendor connects its MCP tools in the background after the session starts. Codex has a launch-mode-specific verified delivery probe documented in [DELIVERY.md](./DELIVERY.md), but no managed native-citizen install lane yet. The ACP plugin ships two backends through one adapter rail: Claude (the reference) and Snowflake Cortex Code (landed in 0.13.0 under the measured contract in [docs/acp-backend-rail.md](./docs/acp-backend-rail.md#cortex-code-audit-d1d10)).
|
|
14
14
|
|
|
15
15
|
```text
|
|
16
|
-
Claude Code / Copilot / Codex / agy / pi
|
|
16
|
+
Claude Code / Copilot / Codex / agy / omp / pi
|
|
17
17
|
→ garden id
|
|
18
18
|
→ entwurf_v2
|
|
19
19
|
→ control-socket | meta-mailbox | native-push
|
|
@@ -59,10 +59,11 @@ native Antigravity / agy
|
|
|
59
59
|
↔ entwurf_v2 native-push
|
|
60
60
|
```
|
|
61
61
|
|
|
62
|
-
Claude's `install-meta-bridge`, Copilot's four `install-copilot-*` surfaces,
|
|
63
|
-
`install-agy-{bridge,statusline,hooks}`
|
|
64
|
-
|
|
65
|
-
native-citizen
|
|
62
|
+
Claude's `install-meta-bridge`, Copilot's four `install-copilot-*` surfaces, agy's
|
|
63
|
+
`install-agy-{bridge,statusline,hooks}` and OMP's three `install-omp-{bridge,mcp,receive}` units
|
|
64
|
+
(each with its own `doctor-omp-*`) are distinct because their lifecycle and delivery transports are
|
|
65
|
+
genuinely different. Codex remains verified probe evidence, not a shipped managed native-citizen
|
|
66
|
+
lane; see [DELIVERY.md](./DELIVERY.md).
|
|
66
67
|
|
|
67
68
|
> **Direction.** Inverse of [`pi-acp`](https://github.com/svkozak/pi-acp). `pi-acp` lets external ACP clients talk *to* pi; `entwurf` lets garden citizens talk across harness boundaries — with pi as one adapter, not the center.
|
|
68
69
|
|
|
@@ -71,17 +72,20 @@ native-citizen lane; see [DELIVERY.md](./DELIVERY.md).
|
|
|
71
72
|
A few words that look unusual for a coding tool.
|
|
72
73
|
|
|
73
74
|
- **Entwurf** (기투, projection-of-self) — sibling sessions with their own runtime boundary. Not "delegate," not "worker," not "sub-agent." Opening a visible sibling (`entwurf_fresh_call`), live peer messaging (`entwurf_v2`) and reopening a dormant one (`entwurf_resume_call`) are first-class; the hidden background resume that preceded the last of those was withdrawn under the visible-first rule.
|
|
74
|
-
- **Garden / garden id** — the garden is the shared address space where independent harness sessions become citizens without losing their own runtime or transcript. A garden id is the stable address of one such citizen (for pi, a garden-native session id like `YYYYMMDDTHHMMSS-<6hex>`; for native harnesses, a meta-session id minted from an authoritative lifecycle hook — Claude `SessionStart`, Copilot's first-prompt birth hook, agy `PreInvocation`). It is not a worker name and not proof that pi owns the session. The same-looking id may name a live control socket, a dormant pi record, a mailbox-backed native session, or a native-push conversation, so callers discover facts with `entwurf_peers` and deliver with `entwurf_v2` instead of choosing a transport by hand.
|
|
75
|
+
- **Garden / garden id** — the garden is the shared address space where independent harness sessions become citizens without losing their own runtime or transcript. A garden id is the stable address of one such citizen (for pi, a garden-native session id like `YYYYMMDDTHHMMSS-<6hex>`; for native harnesses, a meta-session id minted from an authoritative lifecycle hook — Claude `SessionStart`, Copilot's first-prompt birth hook, agy `PreInvocation`, and for OMP an in-process extension bound to both session edges that mints only the visible `mode === "tui"` host). It is not a worker name and not proof that pi owns the session. The same-looking id may name a live control socket, a dormant pi record, a mailbox-backed native session, or a native-push conversation, so callers discover facts with `entwurf_peers` and deliver with `entwurf_v2` instead of choosing a transport by hand.
|
|
75
76
|
- **Engraving** — optional short operator text delivered through each backend's native identity carrier. Not a giant hidden prompt, not a tool catalog.
|
|
76
|
-
- **MCP** — in this repo, MCP is just the transport by which ACP-backed sessions receive pi capabilities that native pi exposes directly as extensions. It is not a general MCP platform. Explicit `entwurfProvider.mcpServers` only; no ambient `~/.mcp.json` scanning, no automatic retrieval. The same `entwurf-bridge` entry can also be wired into another host's MCP catalog (Claude Code, Copilot, Codex, Antigravity, …) when the operator chooses. `entwurf_self` returns an authoritative pi-session or trusted meta-session identity envelope; `entwurf_v2` requires an authoritative sender by default (#50 C4) — a plain external MCP host with no identity lane is refused unless the operator explicitly wires the documented anonymous hatch, and even then it is never replyable.
|
|
77
|
+
- **MCP** — in this repo, MCP is just the transport by which ACP-backed sessions receive pi capabilities that native pi exposes directly as extensions. It is not a general MCP platform. Explicit `entwurfProvider.mcpServers` only; no ambient `~/.mcp.json` scanning, no automatic retrieval. The same `entwurf-bridge` entry can also be wired into another host's MCP catalog (Claude Code, Copilot, Codex, Antigravity, OMP, …) when the operator chooses. `entwurf_self` returns an authoritative pi-session or trusted meta-session identity envelope; `entwurf_v2` requires an authoritative sender by default (#50 C4) — a plain external MCP host with no identity lane is refused unless the operator explicitly wires the documented anonymous hatch, and even then it is never replyable.
|
|
77
78
|
- **Session persistence** — re-attaches pi to the same remote ACP session. Does not hydrate backend transcripts into pi history.
|
|
78
79
|
|
|
79
80
|
## Install
|
|
80
81
|
|
|
81
|
-
`entwurf` is a neutral npm package first.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
`entwurf` is a neutral npm package first. Get the package, then run **`entwurf setup
|
|
83
|
+
<project>`** — one command, the same front door from an npm global install, an npm
|
|
84
|
+
project-local install, or a source checkout. It composes every harness it finds on the
|
|
85
|
+
host and reports each one PASS / SKIP / FAIL. You are not meant to assemble the parts by
|
|
86
|
+
hand; the per-harness installers further down are the repair surface for when one unit
|
|
87
|
+
needs to be redone alone. Pi is still the adapter that hosts the ACP plugin and live
|
|
88
|
+
control-socket surface, but the base install is **not** `pi install npm:...` anymore.
|
|
85
89
|
|
|
86
90
|
The package exposes six bins:
|
|
87
91
|
|
|
@@ -95,7 +99,7 @@ The package exposes six bins:
|
|
|
95
99
|
The bridge/renderers/hook use stable bin names so package upgrades do not bake versioned package-store paths into native-harness settings.
|
|
96
100
|
|
|
97
101
|
Installing Entwurf installs **Entwurf only**: its package bytes, six bins, bridge, and
|
|
98
|
-
integration artifacts. It does not install `pi`, Claude Code, Copilot CLI, Codex, agy, Cortex,
|
|
102
|
+
integration artifacts. It does not install `pi`, Claude Code, Copilot CLI, Codex, agy, omp, Cortex,
|
|
99
103
|
or any other harness runtime. Those are operator choices and may all be absent. The bridge also
|
|
100
104
|
does not provide credentials, tokens, subscription access, or an auth bypass; whatever an
|
|
101
105
|
operator-installed harness already trusts is what Entwurf can use. `setup` is composition, not
|
|
@@ -107,15 +111,12 @@ look complete.
|
|
|
107
111
|
```bash
|
|
108
112
|
npm install -g @junghanacs/entwurf
|
|
109
113
|
|
|
110
|
-
|
|
111
|
-
cd /path/to/your-project
|
|
112
|
-
entwurf install .
|
|
114
|
+
entwurf setup /path/to/your-project
|
|
113
115
|
entwurf check-bridge
|
|
114
116
|
```
|
|
115
117
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
link is gone — #50 C3; nothing reads it.) The global install is the easiest path when
|
|
118
|
+
`setup` wires the target project for the pi adapter / ACP plugin lane and composes
|
|
119
|
+
whatever native harnesses are present. The global install is the easiest path when
|
|
119
120
|
Claude Code's USER-scope MCP registration should work from every cwd.
|
|
120
121
|
|
|
121
122
|
### From npm — project-local install
|
|
@@ -124,27 +125,25 @@ Claude Code's USER-scope MCP registration should work from every cwd.
|
|
|
124
125
|
cd /path/to/your-project
|
|
125
126
|
npm install --save-dev @junghanacs/entwurf
|
|
126
127
|
|
|
127
|
-
npx entwurf
|
|
128
|
+
npx entwurf setup .
|
|
128
129
|
npx entwurf check-bridge
|
|
129
130
|
```
|
|
130
131
|
|
|
131
|
-
For an npm upgrade, rerun
|
|
132
|
+
For an npm upgrade, rerun `setup` in the same scope (use
|
|
132
133
|
`@junghanacs/entwurf@latest` when you want the registry's stable line explicitly),
|
|
133
134
|
then make the first check from that same scope: `entwurf check-bridge` for a global
|
|
134
135
|
install or `npx entwurf check-bridge` for a project-local install. Native-harness
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
For manual MCP registration from a project-local install, point the host at:
|
|
138
|
-
|
|
139
|
-
```text
|
|
140
|
-
/path/to/your-project/node_modules/.bin/entwurf-bridge
|
|
141
|
-
```
|
|
136
|
+
repair and process restarts remain a separate post-upgrade step below.
|
|
142
137
|
|
|
143
|
-
|
|
138
|
+
`entwurf install <project>` is the narrower repair leaf: it writes only
|
|
139
|
+
`.pi/settings.json` in the target project, with the absolute path to the installed
|
|
140
|
+
`entwurf-bridge` launcher, and composes no harness. Reach for it when the pi wiring
|
|
141
|
+
alone needs redoing. (The old `~/.pi/agent/` target-registry link is gone — #50 C3;
|
|
142
|
+
nothing reads it.)
|
|
144
143
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
144
|
+
To register the bridge in an MCP host by hand from a project-local install, point it at
|
|
145
|
+
`node_modules/.bin/entwurf-bridge` — see
|
|
146
|
+
[External MCP registration](#external-mcp-registration).
|
|
148
147
|
|
|
149
148
|
### From source — development clone
|
|
150
149
|
|
|
@@ -164,29 +163,19 @@ and a detected harness that cannot be completed (including a below-floor `pi`) i
|
|
|
164
163
|
that makes setup exit nonzero. `setup` never installs a harness binary or touches a credential
|
|
165
164
|
store. It also exposes stable commands under `~/.local/bin`, including `entwurf` → this
|
|
166
165
|
checkout's `run.sh`, so managed Copilot fresh does not depend on an unrelated global npm/pnpm
|
|
167
|
-
installation. A detected `copilot` composes all four native units (birth → MCP →
|
|
168
|
-
visible footer)
|
|
169
|
-
per-unit repair and inverse path. Package consumers
|
|
166
|
+
installation. A detected `copilot` composes all four of its native units (birth → MCP →
|
|
167
|
+
receiver → visible footer) in one go. Package consumers
|
|
170
168
|
run the same `entwurf setup <project>` through their npm-provided bin: installed mode is decided
|
|
171
169
|
by name first, skips the source-only pnpm bootstrap entirely, and reports the stable commands as
|
|
172
|
-
already provided by npm bin linking
|
|
173
|
-
leaf.
|
|
170
|
+
already provided by npm bin linking.
|
|
174
171
|
|
|
175
172
|
The pi user-scope registration is ONE shared entry with a recorded owner (#86 C2): installing
|
|
176
173
|
from a second checkout or npm root does not silently steal it — normal `install`/`setup` refuse
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
package and provider halves (read-only preflights first — a refusal on one side writes nothing
|
|
183
|
-
on the other); a takeover over an operator's provider override reports a split verdict (package
|
|
184
|
-
moved, override preserved unowned) and a legacy unattributed provider state must be adopted by
|
|
185
|
-
a same-root `setup`/`install` before it can be removed. Both halves' install-states also record
|
|
186
|
-
exactly WHICH settings file they manage (`managedSettingsPath`): an operation targeting a
|
|
187
|
-
different, symlinked or unparseable file is a zero-write refusal before either half goes green,
|
|
188
|
-
and the owned/orphan inverse removes only the recorded owner's exact `packages[]` entry —
|
|
189
|
-
0 or 2+ exact entries refuse, so an npm spec or another `.../entwurf` path is never collateral.
|
|
174
|
+
with zero settings bytes written, `entwurf takeover-user-scope` is the operator-explicit move,
|
|
175
|
+
`entwurf doctor-pi-package` names the ownership verdict, and `entwurf remove-user-scope` is
|
|
176
|
+
same-owner-only. The full contract — atomicity across the package and provider halves, the
|
|
177
|
+
split verdict over an operator's own override, legacy adoption, and the `managedSettingsPath`
|
|
178
|
+
binding — is [docs/setup-clean-host.md §1.1](./docs/setup-clean-host.md#11-user-scope-ownership-one-shared-registration-one-recorded-owner).
|
|
190
179
|
|
|
191
180
|
A development clone runs the bridge source through Node's strip-types path;
|
|
192
181
|
an npm-installed package runs the prebuilt JS under `mcp/entwurf-bridge/dist/`
|
|
@@ -214,41 +203,30 @@ For daily operator sessions, launch pi with `--entwurf-control` — no id
|
|
|
214
203
|
injection; the meta-record mints the garden address (see [Garden launcher](#garden-launcher)). Older pi
|
|
215
204
|
versions may silently miss the provider/extension surface, so treat the pi floor
|
|
216
205
|
as release-critical for the ACP/plugin lane. A host that only uses
|
|
217
|
-
`entwurf-bridge` from Claude Code / Copilot / Codex / Antigravity does not need pi at all for
|
|
218
|
-
delivery: no `entwurf_v2` rail launches a pi process.
|
|
206
|
+
`entwurf-bridge` from Claude Code / Copilot / Codex / Antigravity / OMP does not need pi at all for
|
|
207
|
+
delivery: no `entwurf_v2` rail launches a pi process. OMP is a pi fork, but it is its own binary and
|
|
208
|
+
resolves its own agent directory, so that lineage does not reintroduce a `pi` requirement either. That external-only shape works with the same
|
|
219
209
|
`setup` command: pi is optional-by-presence there, so a pi-less host simply gets an explicit pi
|
|
220
210
|
SKIP while the detected harnesses are composed.
|
|
221
211
|
|
|
222
|
-
### Native harness
|
|
212
|
+
### Native harness repair and doctors
|
|
223
213
|
|
|
224
214
|
A plain MCP registration exposes the bridge tools; a **garden-native** session also
|
|
225
|
-
needs entwurf's lifecycle hook and identity marker.
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
entwurf install-
|
|
236
|
-
entwurf install-
|
|
237
|
-
|
|
238
|
-
entwurf doctor-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
# GitHub Copilot CLI — four independent surfaces, four independent failure modes
|
|
242
|
-
# (`setup` composes all four when `copilot` is on PATH; these remain the per-unit repair/inverse surfaces)
|
|
243
|
-
entwurf install-copilot-bridge # birth: garden id + who-sent, on the first prompt (owns an install-state; inverse: uninstall-copilot-bridge)
|
|
244
|
-
entwurf install-copilot-mcp # the entwurf tool hand (entwurf_inbox_read lives here)
|
|
245
|
-
entwurf install-copilot-receive # the receiver extension: doorbell + receiver marker
|
|
246
|
-
entwurf install-copilot-statusline # optional for a manual citizen; required for supported fresh
|
|
247
|
-
entwurf doctor-copilot-bridge
|
|
248
|
-
entwurf doctor-copilot-mcp
|
|
249
|
-
entwurf doctor-copilot-receive
|
|
250
|
-
entwurf doctor-copilot-statusline
|
|
251
|
-
```
|
|
215
|
+
needs entwurf's lifecycle hook and identity marker. `setup` already composes all of that
|
|
216
|
+
for every harness it detects — you do not paste this list to install. OMP is the one
|
|
217
|
+
exception and it is deliberate: its units are operator-selectable installs that `setup`
|
|
218
|
+
does not compose, so the three `install-omp-*` commands below are how an omp host gets
|
|
219
|
+
wired. Otherwise this is the repair surface: each unit has its own installer, its own
|
|
220
|
+
doctor with a named refusal, and its own inverse, so a single broken unit can be redone
|
|
221
|
+
without touching the rest.
|
|
222
|
+
|
|
223
|
+
- **Claude Code** (Linux-certified axis) — `install-meta-bridge`, `doctor-meta-bridge`.
|
|
224
|
+
- **Antigravity / agy** — `install-agy-bridge`, `install-agy-statusline`, `install-agy-hooks`, each with a matching `doctor-agy-*`.
|
|
225
|
+
- **GitHub Copilot CLI** — four independent units, four independent failure modes: `install-copilot-bridge` (birth: garden id + who-sent, on the first prompt), `install-copilot-mcp` (the entwurf tool hand, where `entwurf_inbox_read` lives), `install-copilot-receive` (the receiver extension: doorbell + receiver marker), `install-copilot-statusline` (optional for a manual citizen, required for supported fresh) — each with a matching `doctor-copilot-*` and `uninstall-copilot-*`.
|
|
226
|
+
- **OMP (`omp`)** — three units, all in-process extensions rather than launchers: `install-omp-bridge` (birth: the `mode === "tui"` visible host, its garden id on the status line, and who-sent), `install-omp-mcp` (the omp-native `entwurf-bridge` entry), `install-omp-receive` (the receiver extension: mailbox watch + announce-only doorbell) — each with a matching `doctor-omp-*` and `uninstall-omp-*`. One OPERATOR setting sits beside them and is not ours to write: `tools: xdev: false` in the omp agent config, without which the vendor mounts MCP tools as `xd://` devices the model cannot call.
|
|
227
|
+
|
|
228
|
+
Run them as `entwurf <command>`. Which unit a doctor's refusal names, and the clean-host
|
|
229
|
+
walk-through for each harness, live in [docs/setup-clean-host.md](./docs/setup-clean-host.md).
|
|
252
230
|
|
|
253
231
|
#### Launching Copilot as a garden citizen — `entwurf copilot`
|
|
254
232
|
|
|
@@ -294,8 +272,10 @@ the default permission prompts — which an idle, unattended session is not ther
|
|
|
294
272
|
|
|
295
273
|
Claude Code uses the supported floor `>=2.1.217`; older versions silently discard the
|
|
296
274
|
exec-hook `args`, so install and doctor fail loud rather than falling back. After any
|
|
297
|
-
upgrade, rerun
|
|
298
|
-
|
|
275
|
+
upgrade, rerun `entwurf setup <project>` — it re-composes every detected harness, all four
|
|
276
|
+
Copilot units included — and restart its existing processes; reach for a single
|
|
277
|
+
`install-*` only when one unit needs repair on its own. A claimed Claude host is certified
|
|
278
|
+
only when a **new** session using the
|
|
299
279
|
installed artifact makes `doctor-meta-bridge` exit 0 with the live owner join.
|
|
300
280
|
|
|
301
281
|
Linux is the only currently certified Claude meta-bridge axis. New macOS wiring is
|
|
@@ -409,7 +389,7 @@ Reference shape lives in [`pi/settings.reference.json`](./pi/settings.reference.
|
|
|
409
389
|
### External MCP registration
|
|
410
390
|
|
|
411
391
|
`entwurf-bridge` can also be registered in a separate MCP-aware harness (Claude Code,
|
|
412
|
-
Copilot CLI, Codex CLI, Antigravity). Two shapes exist and they are not interchangeable:
|
|
392
|
+
Copilot CLI, Codex CLI, Antigravity, OMP). Two shapes exist and they are not interchangeable:
|
|
413
393
|
|
|
414
394
|
- **plain external MCP host** — no garden meta-record or sender marker. It can read the
|
|
415
395
|
surfaces, but `entwurf_v2` is **refused by default**: there is no authoritative sender.
|
|
@@ -421,7 +401,10 @@ claude mcp add --scope user entwurf-bridge entwurf-bridge
|
|
|
421
401
|
```
|
|
422
402
|
|
|
423
403
|
Per-harness registration (Claude Code `~/.mcp.json`, Codex `~/.codex/config.toml`, the
|
|
424
|
-
managed `install-agy-*` surfaces
|
|
404
|
+
managed `install-agy-*` surfaces, and OMP's managed `install-omp-mcp` into `<omp agent dir>/mcp.json`
|
|
405
|
+
— whose pinned server key is what shadows a borrowed Claude import, see
|
|
406
|
+
[docs/external-mcp-host.md](./docs/external-mcp-host.md) §OMP), the PATH/env boundary for
|
|
407
|
+
GUI-launched MCP servers, the
|
|
425
408
|
anonymous-sender hatch, and the full external/meta-session semantics are in
|
|
426
409
|
[docs/external-mcp-host.md](./docs/external-mcp-host.md).
|
|
427
410
|
For the maintained multi-harness setup and skill/command packaging details, see `agent-config`. See also the MCP entry in [Concept primer](#concept-primer), the sender envelope contract in [AGENTS.md](./AGENTS.md), and [Custom skills](#custom-skills) for the in-pi ACP skill surface.
|
|
@@ -527,7 +510,7 @@ A two-pane recording covers the pre-0.12 v1 surface end-to-end — sibling resum
|
|
|
527
510
|
|
|
528
511
|
Live peer messaging carries a sender envelope `{ sessionId, agentId, cwd, timestamp, origin?, replyable? }`; `entwurf_self` returns that authoritative envelope for the current pi session or trusted meta-session. Plain external MCP hosts are non-replyable. A garden-native meta-session carries a trusted `meta-session` envelope, but **`replyable` is a fact its own rail decides, not a consequence of being trusted** — a self-fetch citizen needs a live armed receiver, a native-push citizen needs an alive adapter probe, and a pi session needs its control socket. `entwurf_self` also reports which rail a meta-session reply would ride, because a native-push citizen has no mailbox to name. `wants_reply` is an etiquette marker rendered as a `(wants reply)` badge — not a transport contract, no wait, no polling. **v2 never gates on it:** a `wants_reply` from an external/non-replyable caller is passed through and surfaced honestly beside that sender's `replyable: false`, not rejected — the decider routes on target + intent, never on sender replyability. (The retired v1 `entwurf_send` did reject it; that behaviour went with the verb.)
|
|
529
512
|
|
|
530
|
-
In ACP-backed and external native-harness sessions, `entwurf-bridge` exposes seven tools: `entwurf_v2`, `entwurf_peers`, `entwurf_fresh_call`, `entwurf_resume_call`, `entwurf_self`, `entwurf_inbox_read`, and the explicit/manual `entwurf_register_native` fallback. Native pi exposes the shared capability directly through the extension surface (`entwurf_v2`, `entwurf_peers`, `entwurf_fresh_call`, `entwurf_resume_call` tools; the socket-scan `/entwurf-sessions` command is gone — #50 C4). **For garden-id delivery/reply use `entwurf_v2`** — the canonical surface that classifies the target and routes to live-pi /
|
|
513
|
+
In ACP-backed and external native-harness sessions, `entwurf-bridge` exposes seven tools: `entwurf_v2`, `entwurf_peers`, `entwurf_fresh_call`, `entwurf_resume_call`, `entwurf_self`, `entwurf_inbox_read`, and the explicit/manual `entwurf_register_native` fallback. Native pi exposes the shared capability directly through the extension surface (`entwurf_v2`, `entwurf_peers`, `entwurf_fresh_call`, `entwurf_resume_call` tools; the socket-scan `/entwurf-sessions` command is gone — #50 C4). **For garden-id delivery/reply use `entwurf_v2`** — the canonical surface that classifies the target and routes to live-pi / self-fetch meta-mailbox (Claude Code, Copilot, OMP) / Antigravity-native-push, and refuses a dormant target instead of waking it. **To open a sibling that does not exist yet use `entwurf_fresh_call`** — it launches one fixed backend (`pi`, `claude-code`, `copilot`, or `omp`) as a visible window in the operator's own tmux session, requires an explicit model, accepts one optional literal absolute `cwd` (omit it or pass `""` to use the caller's cwd), passes the model and selected directory through the runtime's visible launch path, and hands it a first task; a `copilot` launch goes through entwurf's own managed invocation and is refused before any window opens if this host lacks the Copilot birth, MCP, receiver or visible-footer units, and an `omp` launch carries its task in the `--entwurf-bootstrap` payload instead of an argv prompt because that vendor connects its MCP tools after the session has already started. The sibling's first action is a nonce callback whose sender envelope carries its garden id. The launch receipt records the requested model/cwd plus tmux coordinates and never claims that the runtime accepted them or completed delivery. (The v1 verbs `entwurf` / `entwurf_resume` / `entwurf_send` are gone.) Garden-native operator commands require `--entwurf-control`. There is no spawn target allowlist — the target registry is gone (#50 C3): `entwurf_v2` and `entwurf_resume_call` address an existing record-backed citizen, while `entwurf_fresh_call` takes its explicit backend/model/task and optional cwd directly rather than resolving a model tuple from a registry file. **To reopen a DORMANT pi citizen use `entwurf_resume_call {target}`** — the record supplies transcript, model, provider and cwd, so it takes no prompt, no task and no model override; it runs no turn, returns a LAUNCH receipt and a separate OBSERVATION receipt (only the second says the citizen is back), refuses a non-pi target as `target-not-pi`, and on an unobserved socket leaves the visible window open and releases its lock rather than retrying.
|
|
531
514
|
|
|
532
515
|
### `entwurf_v2` — canonical dispatch verb
|
|
533
516
|
|
|
@@ -544,9 +527,9 @@ In ACP-backed and external native-harness sessions, `entwurf-bridge` exposes sev
|
|
|
544
527
|
| dead / indeterminate native-push conversation | fire-and-forget | **reject** (`native-push-target-dead` / `native-push-probe-indeterminate`) |
|
|
545
528
|
| record-less control socket (no meta-record) | any | **reject** (`record-less-socket` — pre-probe; diagnostic state, #50 C4) |
|
|
546
529
|
|
|
547
|
-
**`entwurf_v2` is the canonical surface for garden-id delivery.** When you have a garden id and want to reach whoever it names — message, reply, or hand-off — `entwurf_v2` is the one surface that reads whether the target is live pi, dormant pi, mailbox-backed Claude Code or
|
|
530
|
+
**`entwurf_v2` is the canonical surface for garden-id delivery.** When you have a garden id and want to reach whoever it names — message, reply, or hand-off — `entwurf_v2` is the one surface that reads whether the target is live pi, dormant pi, mailbox-backed Claude Code, Copilot or OMP, or native-push Antigravity and routes correctly; *when unsure which transport, use `entwurf_v2`*. This prevents callers from guessing a rail from the shape of an id.
|
|
548
531
|
|
|
549
|
-
What v2 provides is a **deterministic dispatch substrate** that moves the "which transport?" decision out of the fallible caller/model and into the decider, with transport-appropriate locking and an honest reject (no `✓ delivered`, no `.msg` garbage) when a target cannot receive. It still does **not** mint siblings, and it does not relaunch one either: every row above either reaches a citizen that is already running or refuses. Reopening a dormant pi citizen is `entwurf_resume_call`, a separate lifecycle verb that never routes through this decider. Fresh creation is the separate `entwurf_fresh_call` verb. It opens one fixed Pi, Claude Code, or
|
|
532
|
+
What v2 provides is a **deterministic dispatch substrate** that moves the "which transport?" decision out of the fallible caller/model and into the decider, with transport-appropriate locking and an honest reject (no `✓ delivered`, no `.msg` garbage) when a target cannot receive. It still does **not** mint siblings, and it does not relaunch one either: every row above either reaches a citizen that is already running or refuses. Reopening a dormant pi citizen is `entwurf_resume_call`, a separate lifecycle verb that never routes through this decider. Fresh creation is the separate `entwurf_fresh_call` verb. It opens one fixed Pi, Claude Code, Copilot or OMP runtime visibly in the caller's tmux session with a required explicit model passed in that runtime's measured CLI dialect and one optional literal absolute `cwd`; omitted or `""` means the caller's cwd. Copilot opens through `entwurf copilot`, never the bare vendor; OMP is the opposite — the bare `omp` runtime with no positional prompt at all, because that vendor connects its MCP tools after the session has started, so the task rides a two-stage `--entwurf-bootstrap` payload the installed birth extension releases once the callback tool has actually answered. It returns only a synchronous launch receipt and lets the sibling report its new address asynchronously through the sender envelope of a nonce callback. Use this cwd input for a new cross-repository sibling; do not resume a dormant citizen as a cwd substitute. The meta-mailbox row requires an **active** self-fetch receiver; native-push requires a record-backed, probe-alive native conversation and never borrows mailbox state. The [mux launch lane](./docs/mux-launch-rail.md) owns placement, fixed-runtime launch, and the two narrow compositions above it (fresh-call and resume-call placement); delivery does not import launch, and mux is not a delivery transport.
|
|
550
533
|
|
|
551
534
|
A live pi target is *reached* over its control socket, but the socket is dispatch-internal transport, never identity (#50 C4). A control socket that no meta-record claims — a pre-record-era resident, an unreadable store, or a stale/planted file — is refused for **every** intent as `record-less-socket`, and the reject names the fix (restart the resident so `session_start` births its record, or quiesce and run the fresh-cut). `entwurf_peers` reports the same state as an aggregated `record-less-socket` diagnostic rather than a peer row.
|
|
552
535
|
|