@junghanacs/entwurf 0.15.0 → 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/AGENTS.md +1 -0
- package/CHANGELOG.md +299 -0
- package/DELIVERY.md +4 -3
- package/README.md +99 -67
- package/VERIFY.md +13 -7
- package/docs/acp-backend-rail.md +1 -1
- package/docs/external-mcp-host.md +147 -9
- package/docs/setup-clean-host.md +221 -16
- 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 +14 -4
- 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 +1041 -174
- package/scripts/agy-bridge.sh +4 -2
- package/scripts/check-copilot-birth-hook.ts +700 -23
- package/scripts/check-entwurf-self-address.ts +31 -0
- package/scripts/check-fresh-cut-gate.sh +12 -4
- package/scripts/check-gate-qualification.ts +8 -2
- 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/check-setup-qualification.sh +126 -0
- package/scripts/copilot-bridge-doctor.sh +104 -71
- package/scripts/copilot-bridge-install.sh +180 -20
- package/scripts/copilot-bridge-oracle.sh +223 -0
- package/scripts/copilot-bridge-uninstall.sh +137 -0
- package/scripts/dev-bin.sh +50 -9
- package/scripts/fake-copilot-vendor.sh +67 -0
- package/scripts/inventory-verification-surface.ts +1 -1
- package/scripts/meta-bridge-hook-log.sh +9 -1
- package/scripts/mutants/copilot-birth.json +96 -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/pi-package-ownership.json +92 -0
- package/scripts/mutants/self-address.json +34 -0
- package/scripts/mutants/setup-verdict.json +148 -0
- package/scripts/mutants/source-install.json +32 -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/pi_settings_io.py +22 -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/register-pi-package.py +525 -7
- package/scripts/register-pi-provider.py +162 -12
- package/scripts/smoke-agy-install-state.sh +86 -30
- package/scripts/smoke-agy-statusline-state.sh +9 -6
- 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/smoke-setup-verdict.sh +291 -0
- package/scripts/smoke-user-scope-citizen.sh +388 -1
- package/scripts/tsconfig.json +2 -0
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
# Wiring `entwurf-bridge` into an external MCP host
|
|
2
2
|
|
|
3
|
-
Per-harness registration for Claude Code, Codex CLI,
|
|
4
|
-
PATH/env boundary and the external vs garden-native semantics. `README.md` keeps only
|
|
3
|
+
Per-harness registration for Claude Code, Codex CLI, Antigravity, GitHub Copilot CLI and OMP,
|
|
4
|
+
plus the PATH/env boundary and the external vs garden-native semantics. `README.md` keeps only
|
|
5
5
|
the one-line registration; everything an operator needs to actually wire a host is here.
|
|
6
6
|
|
|
7
|
-
`entwurf-bridge` can also be registered in a separate MCP-aware harness (Claude Code, Codex CLI, Antigravity/`agy`, …). That host does **not** become a pi session and does **not** need to be ACP-backed. There are now two honest cases:
|
|
7
|
+
`entwurf-bridge` can also be registered in a separate MCP-aware harness (Claude Code, Codex CLI, Antigravity/`agy`, GitHub Copilot CLI, OMP, …). That host does **not** become a pi session and does **not** need to be ACP-backed. There are now two honest cases:
|
|
8
8
|
|
|
9
9
|
- **plain external MCP host**: no garden meta-record / sender marker. It can call the read surfaces (`entwurf_peers`, `entwurf_inbox_read`), but `entwurf_v2` sends are **refused by default** (#50 C4: "if we don't know who sent it, we don't send it"). The operator may wire the explicit hatch below; the send then goes out external/non-replyable.
|
|
10
|
-
- **garden-native native session**: a trusted lifecycle hook minted a garden id and sender marker — `SessionStart` for Claude Code, `PreInvocation` for agy, `userPromptSubmitted`/`sessionStart` for GitHub Copilot CLI. It is not a pi control-socket session, but it can be replyable by garden id when its own mailbox/probe rail says so.
|
|
10
|
+
- **garden-native native session**: a trusted lifecycle hook minted a garden id and sender marker — `SessionStart` for Claude Code, `PreInvocation` for agy, `userPromptSubmitted`/`sessionStart` for GitHub Copilot CLI, and for OMP an in-process extension on `session_start`/`session_switch` that mints only a `mode === "tui"` host. It is not a pi control-socket session, but it can be replyable by garden id when its own mailbox/probe rail says so.
|
|
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, mailbox-backed Claude Code, or native-push Antigravity and routes correctly. Discover targets with `entwurf_peers`, confirm your own identity with `entwurf_self`, drain a mailbox with `entwurf_inbox_read`, and use `entwurf_register_native` only as the explicit/manual fallback for binding an already-running agy conversation (normal agy birth is automatic through the installed hook). Open a NEW sibling with **`entwurf_fresh_call {backend, model, task, cwd?}`**, and reopen a DORMANT pi citizen under its own garden id with **`entwurf_resume_call {target}`**. Fresh call accepts one optional literal absolute `cwd`: omit it or pass `""` for the caller's cwd; otherwise it must name an existing directory and may not contain `#`. Use that input for a new cross-repository sibling — resume preserves a dormant Pi citizen's recorded continuity and is not a cwd substitute. Fresh call needs its selected runtime on the server's PATH (`pi`, `claude`, or `
|
|
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 and routes correctly. Discover targets with `entwurf_peers`, confirm your own identity with `entwurf_self`, drain a mailbox with `entwurf_inbox_read`, and use `entwurf_register_native` only as the explicit/manual fallback for binding an already-running agy conversation (normal agy birth is automatic through the installed hook). Open a NEW sibling with **`entwurf_fresh_call {backend, model, task, cwd?}`**, and reopen a DORMANT pi citizen under its own garden id with **`entwurf_resume_call {target}`**. Fresh call accepts one optional literal absolute `cwd`: omit it or pass `""` for the caller's cwd; otherwise it must name an existing directory and may not contain `#`. Use that input for a new cross-repository sibling — resume preserves a dormant Pi citizen's recorded continuity and is not a cwd substitute. Fresh call needs its selected runtime on the server's PATH (`pi`, `claude`, `entwurf` or `omp` — Copilot opens through the managed `entwurf copilot` invocation, never the bare vendor, while OMP is opened as the bare `omp` runtime); resume call always needs `pi`. Both start a runtime, while delivery does not. (The old v1 verbs `entwurf` / `entwurf_resume` / `entwurf_send` are gone.)
|
|
15
15
|
|
|
16
|
-
Observed: Claude Code, Codex CLI, Antigravity CLI
|
|
16
|
+
Observed: Claude Code, Codex CLI, Antigravity CLI, GitHub Copilot CLI and OMP all reach the read surfaces through this MCP bridge from a plain external host — `entwurf_peers` is a pure fact projection, while `entwurf_inbox_read` is a **mutating drain** (it archives the messages and stamps the read-receipt), so "read" here does not mean side-effect-free; **sending** needs an identity lane. Claude, Copilot and OMP become symmetric/replyable through a mailbox-backed meta-session — Claude's watch armed by its own hook, Copilot's by the forked extension it installs, OMP's by an extension running inside the operator's own TUI process; agy becomes symmetric/replyable through its record-backed sender marker plus live native-push probe. Codex has no managed citizen lifecycle yet, so a Codex host cannot send without the explicit anonymous hatch below.
|
|
17
17
|
|
|
18
18
|
Prerequisites on the host running the external MCP client:
|
|
19
19
|
|
|
20
20
|
- A live pi session launched with `--entwurf-control` populates `~/.pi/entwurf-control/<gardenId>.sock` — the key is the **record's** garden id, never a transcript/session id (`PI_SESSION_ID` only carries the id record birth already established). Required for `entwurf_v2` control-socket dispatch and `entwurf_peers`.
|
|
21
21
|
|
|
22
|
-
> **PATH boundary.** MCP servers are often launched by GUI/editor daemons and may not inherit the interactive shell's PATH. No `entwurf_v2` rail launches a process, so this does not affect delivery — but `entwurf_fresh_call` and `entwurf_resume_call` do open a fixed runtime. If that runtime works in your terminal but an external-host call fails with `spawn pi ENOENT`, `spawn claude ENOENT`, or `spawn
|
|
22
|
+
> **PATH boundary.** MCP servers are often launched by GUI/editor daemons and may not inherit the interactive shell's PATH. No `entwurf_v2` rail launches a process, so this does not affect delivery — but `entwurf_fresh_call` and `entwurf_resume_call` do open a fixed runtime. If that runtime works in your terminal but an external-host call fails with `spawn pi ENOENT`, `spawn claude ENOENT`, `spawn entwurf ENOENT`, or `spawn omp ENOENT`, pass a full PATH in the MCP server `env`, set `ENTWURF_BRIDGE_ENV_FILE` to a small shell file that exports PATH, or point the host at a wrapper that can find the runtime. `start.sh` sources only the explicit `ENTWURF_BRIDGE_ENV_FILE`; it never reads personal dotfiles automatically.
|
|
23
23
|
|
|
24
24
|
> **Identity-carrier boundary.** A complete `PI_SESSION_ID` + `PI_AGENT_ID` pair wins before a
|
|
25
25
|
> native sender marker in the bridge's authoritative-self resolution. Those variables are correct
|
|
@@ -40,6 +40,22 @@ Prerequisites on the host running the external MCP client:
|
|
|
40
40
|
> and still speak under the parent's garden id, so the flag verdict must not absorb it. The other
|
|
41
41
|
> native launchers have NOT been certified against this failure mode; do not read Copilot's cells
|
|
42
42
|
> as coverage for them.
|
|
43
|
+
>
|
|
44
|
+
> **OMP has both halves, and the strip one is not an omp launcher** (#87 Bundle C). entwurf still
|
|
45
|
+
> owns no managed omp invocation — the bare vendor runtime IS this harness's clause 1 answer, and
|
|
46
|
+
> nothing here argues for a wrapper. The strip sits one level up instead, at the shared launch seam
|
|
47
|
+
> every `entwurf_fresh_call` backend passes through: `SCRUBBED_INHERITED_ENV` empties
|
|
48
|
+
> `PI_SESSION_ID` and `PI_AGENT_ID` on the `new-window` argv itself
|
|
49
|
+
> (`pi-extensions/lib/mux-fresh-call.ts:402`), for all four backends rather than only the one whose
|
|
50
|
+
> measurement surfaced it, because the leak is a property of tmux and not of a vendor. `-e VAR=`
|
|
51
|
+
> sets the variable empty rather than unsetting it — tmux has no per-window unset — and every
|
|
52
|
+
> carrier reader trims and tests truthiness, so empty and absent are the same answer by
|
|
53
|
+
> construction. Pinned by `[QK:FRESHCALL-IDENTITY-SCRUB]` in the `check-mux-fresh-call` vitest lane,
|
|
54
|
+
> inside `check:full`. The DETECT half is unchanged and still load-bearing, because a seam covers
|
|
55
|
+
> only the launches that pass through it: `doctor-omp-bridge` reads `/proc/<pid>/environ` for every
|
|
56
|
+
> live `omp` process and goes RED on its own axis when one carries either carrier. An omp the
|
|
57
|
+
> operator started from a pi citizen's bash never touched the seam and is still unsupported, exactly
|
|
58
|
+
> as this boundary says.
|
|
43
59
|
|
|
44
60
|
Example env file:
|
|
45
61
|
|
|
@@ -66,7 +82,7 @@ Emergency/manual workaround when the MCP server environment is wrong but an exis
|
|
|
66
82
|
External/meta-session semantics:
|
|
67
83
|
|
|
68
84
|
- `entwurf_v2` from a plain external host is **refused by default** (no authoritative sender — #50 C4). With the explicit `ENTWURF_BRIDGE_ALLOW_ANONYMOUS_SENDER=1` hatch it delivers with `origin: "external-mcp"` / `replyable: false`; there is still no reply address.
|
|
69
|
-
- `entwurf_v2` from a trusted meta-session delivers with `origin: "meta-session"`, and `replyable` is **derived from that sender's own rail — not granted by being trusted**: a self-fetch sender (Claude Code) is replyable only while its receiver is live and armed, and a native-push sender (Antigravity) only while its adapter probe finds the live conversation. Identity survives either way; only `replyable` drops to `false`. When it is `true`, `wants_reply: true` is allowed and the receiver can reply to the sender's garden id.
|
|
85
|
+
- `entwurf_v2` from a trusted meta-session delivers with `origin: "meta-session"`, and `replyable` is **derived from that sender's own rail — not granted by being trusted**: a self-fetch sender (Claude Code, Copilot, OMP) is replyable only while its receiver is live and armed, and a native-push sender (Antigravity) only while its adapter probe finds the live conversation. Identity survives either way; only `replyable` drops to `false`. When it is `true`, `wants_reply: true` is allowed and the receiver can reply to the sender's garden id.
|
|
70
86
|
- `entwurf_v2` never launches a process, so no delivery path needs `pi` on PATH. A dormant pi target is refused as `dormant-fire-forget-unsupported`: the hidden background resume that used to answer there was withdrawn under the visible-first rule, and re-opening the session is the separate `entwurf_resume_call` verb — which DOES need `pi` on PATH, because it starts one.
|
|
71
87
|
- `entwurf_self` returns the same authoritative identity for pi sessions **and** trusted meta-sessions. A plain external host with no pi env and no trusted sender marker still fails because there is no reply address to report.
|
|
72
88
|
|
|
@@ -143,9 +159,131 @@ Unrelated servers, permissions, settings, and hooks are preserved; every adapter
|
|
|
143
159
|
|
|
144
160
|
The **global** MCP config live agy reads is `~/.gemini/config/mcp_config.json`. `~/.gemini/antigravity-cli/mcp_config.json` is not the global MCP root; the bridge installer one-way cleans only a stale entwurf-owned entry there. After the first model invocation, the imprint hook binds the native `conversationId` to a garden id, the statusline shows `🪛 <garden-id> agy`, and sends from that MCP child carry `agentId=meta-session/antigravity` with `replyable:true` only when the record exists and the live native-push probe succeeds.
|
|
145
161
|
|
|
162
|
+
#### OMP (`omp`, oh-my-pi)
|
|
163
|
+
|
|
164
|
+
Use the managed install surface rather than editing omp's files by hand:
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
entwurf install-omp-bridge # the BIRTH extension (a garden id per visible TUI session)
|
|
168
|
+
entwurf install-omp-mcp # the MCP hand (this section)
|
|
169
|
+
entwurf install-omp-receive # the RECEIVER extension (mailbox watch + announce-only doorbell)
|
|
170
|
+
|
|
171
|
+
entwurf doctor-omp-bridge
|
|
172
|
+
entwurf doctor-omp-mcp
|
|
173
|
+
entwurf doctor-omp-receive
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Three units, not two. The receiver is what makes the citizen answerable at all — without it omp
|
|
177
|
+
sends under its own garden id and every reply is refused as `mailbox-undeliverable` — and it is
|
|
178
|
+
also a prerequisite of visible fresh: the fresh preflight refuses this host before touching tmux
|
|
179
|
+
when the receive unit is missing, rather than opening a window that can never be reached.
|
|
180
|
+
|
|
181
|
+
`install-omp-mcp` writes ONE server into omp's own user MCP file,
|
|
182
|
+
`<omp agent dir>/mcp.json` (`~/.omp/agent/mcp.json`, profile-aware), in omp's own writer
|
|
183
|
+
shape — `{command, args?, env?}` with `type` omitted, since stdio is the default:
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"$schema": "https://raw.githubusercontent.com/can1357/oh-my-pi/main/packages/coding-agent/src/config/mcp-schema.json",
|
|
188
|
+
"mcpServers": {
|
|
189
|
+
"entwurf-bridge": {
|
|
190
|
+
"command": "bash",
|
|
191
|
+
"args": ["/absolute/path/to/entwurf/mcp/entwurf-bridge/start.sh"],
|
|
192
|
+
"env": { "ENTWURF_BRIDGE_EXTERNAL_AGENT_ID": "external-mcp/omp" }
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
**The server key is a pinned literal, and that is the whole point.** omp translates Claude
|
|
199
|
+
Code's `~/.claude.json` as an import provider, so a host that ever used Claude Code already
|
|
200
|
+
has an `entwurf-bridge` — carrying `external-mcp/claude-code`. An omp session riding that
|
|
201
|
+
import introduces itself to the bridge under Claude Code's name. Writing the native entry
|
|
202
|
+
under the byte-identical key shadows it: native provider priority 100 beats claude 80,
|
|
203
|
+
dedupe is first-wins on the server NAME, and on a key hit the equivalence check is never
|
|
204
|
+
consulted, so an entry whose env deliberately differs still suppresses the import outright
|
|
205
|
+
— not both-loaded, not merged, no warning. A different key would load BOTH.
|
|
206
|
+
`[측정]` 2026-08-27, omp/18.0.0: the vendor's own `/mcp list` pane flipped from
|
|
207
|
+
`Claude Code (~/.claude.json): entwurf-bridge ● connected` to
|
|
208
|
+
`User level (~/.omp/agent/mcp.json): entwurf-bridge ● connected [stdio]`, and the spawned
|
|
209
|
+
bridge child's environ flipped with it.
|
|
210
|
+
|
|
211
|
+
**`disabledServers` is never the way to hide the import.** Suppression is by name and a
|
|
212
|
+
suppressed item still claims the dedupe key, so denylisting `entwurf-bridge` kills the
|
|
213
|
+
native entry and the import together. `[측정]` with that denylist the pane shows
|
|
214
|
+
`entwurf-bridge ○ not connected` and no Claude Code section at all, and no MCP child is
|
|
215
|
+
spawned. The installer refuses to write into a config that denylists its own key, and
|
|
216
|
+
`doctor-omp-mcp` is red while one exists.
|
|
217
|
+
|
|
218
|
+
**The tool names are omp's dialect, not Claude's.** omp mints `mcp__<server>_<tool>` after
|
|
219
|
+
lowercasing and replacing every `[^a-z_]+` run with `_`, collapsing runs and trimming edges,
|
|
220
|
+
so `entwurf_v2` surfaces as `mcp__entwurf_bridge_entwurf_v` — the trailing digit is eaten by
|
|
221
|
+
the charset, not by the length cap. The live tool list is the acceptance oracle; a live
|
|
222
|
+
session mounts all seven.
|
|
223
|
+
|
|
224
|
+
**And the NAME is not the invocation. Under omp's default settings an MCP tool is not a
|
|
225
|
+
function the model calls — it is a virtual file it writes to.** `tools.xdev` (boolean,
|
|
226
|
+
**default on**) mounts "discoverable" tools as `xd://<tool>` devices and DROPS them from the
|
|
227
|
+
top-level toolset; the model then reads `xd://<tool>` for the schema and *writes* the JSON
|
|
228
|
+
argument object to `xd://<tool>` to execute it. `tools.xdevDocs` (**default `builtins`**)
|
|
229
|
+
keeps built-in docs inline while MCP and extension schemas stay off-prompt until read. That
|
|
230
|
+
default costs a real capability. `[측정]` 2026-08-28, omp/18.0.0: with the defaults, a plain
|
|
231
|
+
"send this message to garden id X" produced a `write` to `xd://…entwurf_peers` (a LISTING)
|
|
232
|
+
and then the sentence "보냈습니다" — no `entwurf_v2` call, nothing enqueued, `lastEnqueuedAt`
|
|
233
|
+
unchanged. Discovery and delivery share one verb (`write`) and neither schema was in the
|
|
234
|
+
prompt. The vendor has hit the same shape in its own toolset: its changelog records
|
|
235
|
+
`web_search` becoming unreachable under `tools.xdev: true` because the mount dropped it from
|
|
236
|
+
top-level (`Tool web_search not found`, upstream #5973), fixed by pinning it via
|
|
237
|
+
`XDEV_KEEP_TOP_LEVEL` — a pin no MCP tool has.
|
|
238
|
+
|
|
239
|
+
`read xd://` reports exactly what the default hides. `[측정]` on a host with only this
|
|
240
|
+
bridge registered, **11 devices**: omp's own `ast_edit`, `debug`, `lsp`, `browser`, plus all
|
|
241
|
+
seven `entwurf_*`. So the default does not merely wrap entwurf — it wraps omp's own LSP and
|
|
242
|
+
debugger too.
|
|
243
|
+
|
|
244
|
+
**Set this on any omp host that is meant to work as a citizen:**
|
|
245
|
+
|
|
246
|
+
```yaml
|
|
247
|
+
# ~/.omp/agent/config.yml
|
|
248
|
+
tools:
|
|
249
|
+
xdev: false # every enabled tool top-level — MCP is MCP again
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Nothing is disabled by that: the setting's own text is *"Disable to expose every enabled tool
|
|
253
|
+
top-level"*, and it moves tools rather than removing them. `[측정]` with `xdev: false` the
|
|
254
|
+
same plain-language request produced a first-try `mcp__entwurf_bridge_entwurf_v` function
|
|
255
|
+
call carrying a correct `intent`, the marker landed in the target mailbox, `read xd://`
|
|
256
|
+
answered `xd:// is not mounted in this session.`, and `lsp` / `debug` / `browser` /
|
|
257
|
+
`ast_edit` were all present top-level. The cost is prompt size: the system prompt's
|
|
258
|
+
non-message tokens went 18,707 → 21,834 (+3,127, +17%) on that host.
|
|
259
|
+
|
|
260
|
+
Two boundaries worth carrying:
|
|
261
|
+
|
|
262
|
+
- **`xd://` resolution devices survive the switch.** omp's plan mode and every staged-action
|
|
263
|
+
finalization write to `xd://propose` / `xd://resolve` / `xd://reject`, and its plan prompt
|
|
264
|
+
names them unconditionally — so "turn xdev off" looks like it should break planning. It
|
|
265
|
+
does not: the write dispatcher matches the resolution devices BEFORE the mount check.
|
|
266
|
+
`[측정]` with `xdev: false`, plan mode reached `write xd://propose` and the approval dialog
|
|
267
|
+
normally.
|
|
268
|
+
- **The narrow alternative keeps the wrapper.** `tools.xdevInlineDevices:
|
|
269
|
+
["mcp__entwurf_bridge_*"]` inlines only our schemas (+1,013 tokens instead of +3,127) and
|
|
270
|
+
also fixed the send in the same measurement — but the 11 devices stay off top-level, `lsp`
|
|
271
|
+
included, and the listing/delivery verb stays shared. Prefer it only on a host carrying so many MCP servers
|
|
272
|
+
that the full top-level toolset is the larger problem.
|
|
273
|
+
|
|
274
|
+
All of the above is measured against omp 18.0.0 and is a setting, not a contract: re-measure
|
|
275
|
+
at a vendor upgrade.
|
|
276
|
+
|
|
277
|
+
Registration is tools, not identity: sending needs the birth extension
|
|
278
|
+
(`install-omp-bridge`), whose sender marker is keyed to the omp host's OWN pid — omp runs
|
|
279
|
+
its extensions in-process, so the marker's owner, the host, and the MCP child's parent are
|
|
280
|
+
one pid rather than the two-process join Claude and Copilot have. An omp session is a
|
|
281
|
+
citizen only in the operator-visible TUI; task subagents borrow its tools under its garden
|
|
282
|
+
id and never receive a second address.
|
|
283
|
+
|
|
146
284
|
#### External-host skills and commands
|
|
147
285
|
|
|
148
|
-
MCP registration gives the external harness the tools; the host still needs workflow guidance. Put the Mitsein-over-MCP (cross-harness collaboration) rules in that host's instruction file or, when supported, as a host-native skill. Do not assume pi slash commands are portable across external hosts — if a workflow must work across Claude Code, Codex CLI, Antigravity, and future hosts, make it a skill or MCP tool rather than a command shortcut.
|
|
286
|
+
MCP registration gives the external harness the tools; the host still needs workflow guidance. Put the Mitsein-over-MCP (cross-harness collaboration) rules in that host's instruction file or, when supported, as a host-native skill. Do not assume pi slash commands are portable across external hosts — if a workflow must work across Claude Code, Codex CLI, Antigravity, OMP, and future hosts, make it a skill or MCP tool rather than a command shortcut.
|
|
149
287
|
|
|
150
288
|
For the maintained multi-harness setup and skill/command packaging details, see
|
|
151
289
|
[agent-config](https://github.com/junghan0611/agent-config). See also the
|
package/docs/setup-clean-host.md
CHANGED
|
@@ -9,10 +9,13 @@ only on Linux because its strict live-owner join uses `/proc`.
|
|
|
9
9
|
| Component | Requirement | Needed for |
|
|
10
10
|
|---|---|---|
|
|
11
11
|
| Node | **`>=24.0.0`** | package and bridge runtime |
|
|
12
|
-
| npm | bundled with Node | package installation |
|
|
13
|
-
|
|
|
14
|
-
|
|
|
12
|
+
| npm/pnpm | npm is bundled with Node; pnpm is required for source setup | package or source installation |
|
|
13
|
+
| Python 3 | required by `setup`/`install` (project-path normalization + settings writers); `--help`/`check-bridge` stay Python-free | pi/Claude/agy/Copilot wiring writers |
|
|
14
|
+
| entwurf | global/project-local `@junghanacs/entwurf`, or a source checkout | operator command and garden capability |
|
|
15
|
+
| pi | optional-by-presence, `>=0.84.3 <0.85` — absent is an explicit setup SKIP, below-floor is a named FAIL | ACP provider, control sockets |
|
|
15
16
|
| Claude Code | optional, **`>=2.1.217`** — the exec-form hook floor | Claude ACP auth/runtime and mailbox-backed native citizen |
|
|
17
|
+
| GitHub Copilot CLI | optional-by-presence, operator-installed and authenticated — absent is an explicit setup SKIP; detected composes all four units (birth/MCP/receiver/footer) | self-fetch citizen and visible fresh |
|
|
18
|
+
| OMP (`omp`) | optional, operator-installed; three units (birth/MCP/receiver) plus `tools: xdev: false` in the agent config | self-fetch citizen and visible fresh (accepted on one host — see §4b) |
|
|
16
19
|
| Antigravity `agy` | optional, operator-installed and authenticated | native-push citizen |
|
|
17
20
|
| Cortex Code | optional, operator-installed and authenticated | Cortex ACP backend |
|
|
18
21
|
|
|
@@ -51,6 +54,56 @@ npx entwurf check-bridge
|
|
|
51
54
|
`check-bridge` is auth-free. It proves the installed prebuilt MCP server boots and
|
|
52
55
|
lists the seven garden tools; it does not prove a backend model turn or native hook.
|
|
53
56
|
|
|
57
|
+
Neither npm form installs a harness runtime. `pi`, Claude Code, Copilot CLI, agy, Cortex and their
|
|
58
|
+
authentication remain operator-owned optional prerequisites for the integrations that use them;
|
|
59
|
+
all may be absent on an Entwurf-only host. A source checkout's pinned Pi development packages are
|
|
60
|
+
for building and testing this repo, not a transitive product installation promise.
|
|
61
|
+
|
|
62
|
+
Maintainers using a source checkout do not install a second global entwurf package. Full source
|
|
63
|
+
setup currently requires Node 24, pnpm, and Python 3 on PATH; every harness — including pi — is
|
|
64
|
+
optional-by-presence (absent → explicit SKIP, detected but below the supported floor → named FAIL
|
|
65
|
+
with a nonzero setup result):
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
git clone https://github.com/junghan0611/entwurf ~/repos/gh/entwurf
|
|
69
|
+
cd ~/repos/gh/entwurf
|
|
70
|
+
./run.sh setup /path/to/consumer-project
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
This owns `~/.local/bin/entwurf` as a symlink to that checkout's `run.sh` and fails if the
|
|
74
|
+
link is foreign, outside PATH, or shadowed by another command. It detects and wires
|
|
75
|
+
pi/Claude/agy/Copilot by presence and prints a computed per-component PASS/SKIP/FAIL summary — a
|
|
76
|
+
detected harness that cannot be completed makes setup exit nonzero. A detected `copilot`
|
|
77
|
+
composes all four native units (birth → MCP → receiver → visible footer) with independent
|
|
78
|
+
per-unit verdicts (#86 C3b); §4 keeps the explicit per-unit install/doctor/inverse surfaces for
|
|
79
|
+
repair.
|
|
80
|
+
|
|
81
|
+
### 1.1 User-scope ownership (one shared registration, one recorded owner)
|
|
82
|
+
|
|
83
|
+
The GLOBAL pi user-scope registration (`~/.pi/agent/settings.json` `packages[]` plus the
|
|
84
|
+
`entwurfProvider.mcpServers.entwurf-bridge` key) is ONE shared entry across every install root, and
|
|
85
|
+
it carries a recorded owner: `packageRoot` in `$XDG_DATA_HOME/entwurf/pi-package/install-state.json`
|
|
86
|
+
and `installerRoot` in the provider install-state. Normal `install`/`setup` from a different root —
|
|
87
|
+
whether the recorded owner is live or missing — refuses with zero settings bytes written; the only
|
|
88
|
+
writer that moves the shared entry is the operator-explicit `entwurf takeover-user-scope`
|
|
89
|
+
(old→new reported). Every user-scope operation is ATOMIC across the two halves: both ownership
|
|
90
|
+
preflights run read-only first, so a refusal on either side leaves the other byte-identical. A
|
|
91
|
+
takeover over an operator's own provider override is a SPLIT verdict — the package owner moves,
|
|
92
|
+
the override is preserved and stays unowned (its stale ownership state is cleared), never a false
|
|
93
|
+
"both owned". A LEGACY provider state (no `installerRoot`) accepts no inverse: run `setup`/`install`
|
|
94
|
+
from the owning root first (named adoption), then remove. Both install-states also bind the exact
|
|
95
|
+
settings file they manage (`managedSettingsPath`): pointing an operation at a different, symlinked
|
|
96
|
+
or unparseable file refuses with zero writes before either half proceeds, and the owned/orphan
|
|
97
|
+
inverse removes only the recorded owner's exact `packages[]` entry (0 or 2+ exact entries refuse).
|
|
98
|
+
`entwurf doctor-pi-package` names the package-side verdict including the
|
|
99
|
+
packageRoot↔installerRoot coupling mismatch and a package/provider managed-path mismatch.
|
|
100
|
+
|
|
101
|
+
| Root shape | Package root written | Stable commands from | Project write | User write | Takeover trigger | Inverse | Stale/moved verdict |
|
|
102
|
+
|---|---|---|---|---|---|---|---|
|
|
103
|
+
| source checkout | the checkout dir | `dev-bin` symlinks (`setup`) | `<project>/.pi/settings.json` | shared entry + owner state | `takeover-user-scope` from the new checkout | `remove` (project) / `remove-user-scope` (global, same-owner-only) | `doctor-pi-package` → `missing-owner`; normal install still refuses |
|
|
104
|
+
| global npm (`npm i -g`) | the global `node_modules/@junghanacs/entwurf` | npm bin linking | same | same shared entry | same explicit action | same; a LIVE foreign owner always refuses | same |
|
|
105
|
+
| project-local npm | that project's `node_modules/@junghanacs/entwurf` | `node_modules/.bin` | same | same shared entry | same explicit action | same | same; a deleted root becomes the aligned `remove-user-scope` orphan cleanup (entry + package state + provider installerRoot must all name that missing root) |
|
|
106
|
+
|
|
54
107
|
## 2. Optional pi adapter / ACP plugin
|
|
55
108
|
|
|
56
109
|
Install the exact release floor, then wire the project:
|
|
@@ -109,7 +162,135 @@ New macOS wiring is refused because the live join is not instrumented there. Dar
|
|
|
109
162
|
uninstall remains available for cleaning an older managed install; this is an evidence
|
|
110
163
|
boundary, not a permanent impossibility claim.
|
|
111
164
|
|
|
112
|
-
## 4. Optional
|
|
165
|
+
## 4. Optional GitHub Copilot CLI native citizen
|
|
166
|
+
|
|
167
|
+
Copilot has four independently owned surfaces. `setup` composes all four when `copilot` is on
|
|
168
|
+
PATH (#86 C3b); the commands below are the per-unit repair, doctor, and inverse surfaces. All
|
|
169
|
+
four must be green for supported visible fresh; a manual citizen may omit the footer, but fresh
|
|
170
|
+
refuses before opening a window when any required surface is absent.
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
entwurf install-copilot-bridge
|
|
174
|
+
entwurf install-copilot-mcp
|
|
175
|
+
entwurf install-copilot-receive
|
|
176
|
+
entwurf install-copilot-statusline
|
|
177
|
+
|
|
178
|
+
entwurf doctor-copilot-bridge
|
|
179
|
+
entwurf doctor-copilot-mcp
|
|
180
|
+
entwurf doctor-copilot-receive
|
|
181
|
+
entwurf doctor-copilot-statusline
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Launch the supported invocation with `entwurf copilot`, not bare `copilot`. It enables extension
|
|
185
|
+
scanning for that process, checks the receiver, removes inherited pi identity carriers, and owns
|
|
186
|
+
the model/permission defaults. Birth occurs on the first prompt. `entwurf_fresh_call` uses this
|
|
187
|
+
same managed invocation and requires the birth, MCP, receiver, and visible-identity preflight.
|
|
188
|
+
|
|
189
|
+
## 4b. Optional OMP (`omp`) native citizen — accepted on one host
|
|
190
|
+
|
|
191
|
+
Three independently owned surfaces, and a boundary that is part of the instructions rather
|
|
192
|
+
than a footnote. Birth, visible identity, who-sent, the MCP hand and RECEIVE are landed, and
|
|
193
|
+
`entwurf_fresh_call` opens an omp sibling on all three public surfaces. The clause 7 LIVE
|
|
194
|
+
receipt has been taken: `smoke-omp-fresh-live` went green on 2026-08-30 (omp 18.0.0, one
|
|
195
|
+
model, one accepted run), which is what `docs/adding-a-harness.md` step 9 asks for and why
|
|
196
|
+
that smoke is wired as a release-gate MUST — the label was never allowed to move ahead of the
|
|
197
|
+
evidence, and it moved only once the evidence existed. Read the receipt itself in DELIVERY.md's
|
|
198
|
+
OMP row; what it does NOT establish is multi-host, multi-model, or repeated fresh calls in one
|
|
199
|
+
process. Open omp yourself and it is a two-way citizen either way — it sends under its own
|
|
200
|
+
garden id and a reply lands on it.
|
|
201
|
+
|
|
202
|
+
The first turn of a fresh omp sibling is a TWO-STAGE BOOTSTRAP, not a positional prompt: the
|
|
203
|
+
launcher carries `{v,target,nonce,task}` on the fixed registered flag `--entwurf-bootstrap`,
|
|
204
|
+
and the installed birth extension waits until the callback tool is actually callable, sends a
|
|
205
|
+
callback-only prompt, and delivers the operator's task only after that exact call succeeds.
|
|
206
|
+
That is a measured correction — the interactive host defers MCP discovery, so a positional
|
|
207
|
+
first turn began before the tool it named existed.
|
|
208
|
+
|
|
209
|
+
**One operator setting is load-bearing for fresh, not just for receive.** `tools: xdev: false`
|
|
210
|
+
in the omp agent config is checked by the fresh preflight BEFORE any window opens, because the
|
|
211
|
+
vendor default mounts MCP tools as `xd://` devices whose schemas never reach the prompt: a
|
|
212
|
+
sibling launched onto a default-config host would start, look healthy, and be unable to call
|
|
213
|
+
the callback tool at all. A refusal there names `omp-callback-tool-uncallable` and opens
|
|
214
|
+
nothing.
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
entwurf install-omp-bridge # the birth extension, into <omp agent dir>/extensions/
|
|
218
|
+
entwurf install-omp-mcp # the omp-native entwurf-bridge server
|
|
219
|
+
entwurf install-omp-receive # the receiver extension: mailbox watch + doorbell
|
|
220
|
+
|
|
221
|
+
entwurf doctor-omp-bridge
|
|
222
|
+
entwurf doctor-omp-mcp
|
|
223
|
+
entwurf doctor-omp-receive
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
Order matters only in one direction: the receiver JOINS the citizen birth mints, and
|
|
227
|
+
announces a tool the MCP hand provides. Install it without them and it will log
|
|
228
|
+
`arm-deferred`, give up after ~20s, and `doctor-omp-receive` will name the missing sibling
|
|
229
|
+
as a note rather than a fault.
|
|
230
|
+
|
|
231
|
+
**The receiver arms per session, and only for the visible TUI host.** Opening omp arms it;
|
|
232
|
+
`/new` re-arms it for the replacement citizen and retires the previous one; closing omp
|
|
233
|
+
retires it. A task subagent arms nothing. While nothing is armed, dispatch to that garden
|
|
234
|
+
id is the honest `mailbox-undeliverable` refusal — an unarmed receiver is a legible state,
|
|
235
|
+
not a broken one.
|
|
236
|
+
|
|
237
|
+
The admission work has landed and `setup` still does not compose these: the three omp
|
|
238
|
+
units stay operator-selectable installs, so run them yourself on an omp host.
|
|
239
|
+
|
|
240
|
+
Both installers resolve the omp agent directory the way omp itself does, and REFUSE rather
|
|
241
|
+
than guess when an inherited `PI_CODING_AGENT_DIR`, `PI_CONFIG_DIR` or `PI_PROFILE` makes it
|
|
242
|
+
ambiguous: omp is a pi fork and reads pi's env vocabulary, so those names no longer say which
|
|
243
|
+
harness they address. Pass `ENTWURF_OMP_AGENT_DIR` if you genuinely mean a non-default one.
|
|
244
|
+
|
|
245
|
+
Two things the installers deliberately will NOT do. They never adopt an artifact already
|
|
246
|
+
sitting at their path without entwurf's own ownership state — a directory that merely looks
|
|
247
|
+
like our unit could be yours, and adopting it would overwrite it with no way back — so a
|
|
248
|
+
no-state path is a named refusal you resolve by hand. And the MCP writer's target is exactly
|
|
249
|
+
`<resolved omp agent dir>/mcp.json`; there is no path override, so it can never be aimed at
|
|
250
|
+
another tool's config.
|
|
251
|
+
|
|
252
|
+
**Where an omp citizen's garden artifacts live.** Under `$HOME/.pi/agent/meta-*`, the same
|
|
253
|
+
garden every other citizen uses — and that stays true under `omp --profile work`. omp is a pi
|
|
254
|
+
fork, so the vendor exports `PI_CODING_AGENT_DIR` for every named profile; for entwurf that
|
|
255
|
+
name means pi's persistence root, so honouring it here would put an omp session's record in a
|
|
256
|
+
different store (or in a pi sandbox). For backend omp it is read as the VENDOR's agent dir
|
|
257
|
+
only, and never as a garden root. Its presence on a live omp is normal and is not a fault.
|
|
258
|
+
The four `ENTWURF_META_*` variables remain the way to relocate the garden roots, and for
|
|
259
|
+
backend omp each one must be **absolute or `~`-rooted** (`~` or `~/…`). A relative value is
|
|
260
|
+
refused by name rather than resolved: it would resolve against each process's own working
|
|
261
|
+
directory, and the omp extension and `doctor-omp-bridge` do not share one — the doctor would
|
|
262
|
+
then report on a directory the extension never writes to. A refused value mints nothing and
|
|
263
|
+
turns the doctor's runtime axis red.
|
|
264
|
+
|
|
265
|
+
**One vendor setting is required, and the default is wrong for a citizen.** omp's
|
|
266
|
+
`tools.xdev` (default ON) mounts MCP tools as `xd://<tool>` devices and removes them from the
|
|
267
|
+
model's top-level toolset, so `entwurf_v2` is reached by WRITING JSON to a virtual file rather
|
|
268
|
+
than by calling a tool — and with `tools.xdevDocs` at its `builtins` default its schema is not
|
|
269
|
+
in the prompt at all. On that default a plain "send this to garden id X" was measured to list
|
|
270
|
+
peers and then CLAIM the send without ever dispatching. Put this in `~/.omp/agent/config.yml`
|
|
271
|
+
and restart the session:
|
|
272
|
+
|
|
273
|
+
```yaml
|
|
274
|
+
tools:
|
|
275
|
+
xdev: false
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
It disables nothing — it exposes every enabled tool top-level, omp's own `lsp`, `debug`,
|
|
279
|
+
`browser` and `ast_edit` included, which the default was hiding as well. Plan mode and staged
|
|
280
|
+
`xd://resolve` / `xd://propose` finalization keep working. The rationale, the numbers and the
|
|
281
|
+
narrower `tools.xdevInlineDevices` alternative are in
|
|
282
|
+
[`external-mcp-host.md`](./external-mcp-host.md).
|
|
283
|
+
|
|
284
|
+
Birth happens when the TUI OPENS (not on the first prompt, unlike Copilot), and the garden id
|
|
285
|
+
appears on omp's status line as `🪛 <garden-id> omp`. `/new`, fork and in-TUI resume mint the
|
|
286
|
+
replacement session's own record. Task subagents of that session are refused by design — they
|
|
287
|
+
borrow the host's tools under the host's garden id and never get a second address.
|
|
288
|
+
|
|
289
|
+
The MCP entry deliberately uses the same server key as any Claude Code import so that it
|
|
290
|
+
SHADOWS it; see [`external-mcp-host.md`](./external-mcp-host.md) for why that key is pinned and
|
|
291
|
+
why `disabledServers` is never the way to hide an import.
|
|
292
|
+
|
|
293
|
+
## 5. Optional Antigravity native citizen
|
|
113
294
|
|
|
114
295
|
Install the three independently owned surfaces:
|
|
115
296
|
|
|
@@ -134,7 +315,7 @@ Real native-push acceptance needs an already-running conversation:
|
|
|
134
315
|
LIVE=1 AGY_CONVERSATION_ID=<id> entwurf smoke-agy-native-push-live
|
|
135
316
|
```
|
|
136
317
|
|
|
137
|
-
##
|
|
318
|
+
## 6. Optional ACP backend turns
|
|
138
319
|
|
|
139
320
|
Claude uses the operator's existing local Claude authentication:
|
|
140
321
|
|
|
@@ -153,25 +334,34 @@ LIVE=1 ENTWURF_ACP_CORTEX_CONNECTION=<conn> \
|
|
|
153
334
|
The aggregate release gate is Claude-backed and does not run Cortex automatically.
|
|
154
335
|
Its silence is not a Cortex PASS.
|
|
155
336
|
|
|
156
|
-
##
|
|
337
|
+
## 7. Upgrade and repair
|
|
157
338
|
|
|
158
339
|
After upgrading the package, rerun the managed installers for every native harness
|
|
159
340
|
in use and restart their existing processes. Native plugin caches are not live-reload
|
|
160
341
|
safe across launch-contract changes.
|
|
161
342
|
|
|
162
343
|
If install or doctor reports an unreadable/old active citizen generation, do not edit
|
|
163
|
-
records by hand
|
|
344
|
+
records by hand. Close pi, Claude, Copilot, and agy sessions first, run
|
|
345
|
+
`entwurf meta-bridge-fresh-cut`, and read its exit status before any install. Then choose the
|
|
346
|
+
installation mode you actually own:
|
|
164
347
|
|
|
165
348
|
```bash
|
|
166
|
-
#
|
|
167
|
-
entwurf
|
|
168
|
-
entwurf
|
|
349
|
+
# npm package consumer
|
|
350
|
+
entwurf install ~/entwurf-smoke
|
|
351
|
+
entwurf install-meta-bridge
|
|
352
|
+
# `entwurf setup` re-composes the four Copilot units when `copilot` is on PATH
|
|
353
|
+
|
|
354
|
+
# source maintainer — from the checkout
|
|
355
|
+
./run.sh setup ~/entwurf-smoke
|
|
169
356
|
```
|
|
170
357
|
|
|
171
|
-
|
|
172
|
-
|
|
358
|
+
The package-installed `entwurf setup` is the same consumer command in installed mode: it names
|
|
359
|
+
that mode first, never runs npm/pnpm inside `node_modules` (the frozen pnpm bootstrap is
|
|
360
|
+
source-checkout-only), and composes the detected harnesses with the same per-component
|
|
361
|
+
PASS/SKIP/FAIL summary. The complete quiescence, archive, and exit-code contract is
|
|
362
|
+
[fresh-cut-policy.md](./fresh-cut-policy.md).
|
|
173
363
|
|
|
174
|
-
##
|
|
364
|
+
## 8. Release acceptance versus host acceptance
|
|
175
365
|
|
|
176
366
|
- `entwurf check-bridge`: installed MCP bytes boot; no backend auth.
|
|
177
367
|
- `pnpm check` / `pnpm run check:full`: tiered source deterministic floors (everyday
|
|
@@ -190,12 +380,27 @@ Run only the surfaces this host owns:
|
|
|
190
380
|
|
|
191
381
|
```bash
|
|
192
382
|
entwurf uninstall-meta-bridge
|
|
383
|
+
entwurf uninstall-copilot-statusline
|
|
384
|
+
entwurf uninstall-copilot-receive
|
|
385
|
+
entwurf uninstall-copilot-mcp
|
|
386
|
+
entwurf uninstall-copilot-bridge
|
|
193
387
|
entwurf uninstall-agy-hooks
|
|
194
388
|
entwurf uninstall-agy-statusline
|
|
195
389
|
entwurf uninstall-agy-bridge
|
|
196
|
-
entwurf
|
|
390
|
+
entwurf remove ~/entwurf-smoke
|
|
391
|
+
# only when no other project uses the shared user-scope pi registration:
|
|
392
|
+
entwurf remove-user-scope
|
|
197
393
|
npm uninstall -g @junghanacs/entwurf
|
|
198
394
|
```
|
|
199
395
|
|
|
200
|
-
|
|
201
|
-
|
|
396
|
+
The package `uninstall-*`/`remove` surfaces preserve unrelated native-harness configuration.
|
|
397
|
+
Copilot birth now has a package-owned inverse: `uninstall-copilot-bridge` removes exactly what
|
|
398
|
+
its install-state (`$XDG_DATA_HOME/entwurf/copilot-bridge/install-state.json`) records — the
|
|
399
|
+
qualified plugin, the local marketplace registration when it is owned and still at the recorded
|
|
400
|
+
path, and the recorded assembly — never with `--force`, never a bare plugin name that could
|
|
401
|
+
match somebody else's unit, and never the stale Claude unit. The complete ownership preflight
|
|
402
|
+
runs read-only before the first vendor write, so a marketplace under our name at another path,
|
|
403
|
+
a registration the state does not own, or a failing vendor list (UNKNOWN, never absence)
|
|
404
|
+
refuses the whole inverse with zero writes; the state is deleted last, so a partial failure
|
|
405
|
+
keeps a rerun-repair authority.
|
|
406
|
+
A legacy no-state installation is adopted by re-running `install-copilot-bridge` first.
|