@junghanacs/entwurf 0.20.0 → 0.21.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 +85 -190
- package/BASELINE.md +6 -5
- package/CHANGELOG.md +220 -14
- package/CONTRIBUTING.md +1 -1
- package/DELIVERY.md +202 -60
- package/README.md +54 -26
- package/VERIFY.md +37 -7
- package/docs/acp-backend-rail.md +31 -15
- package/docs/external-mcp-host.md +58 -35
- package/docs/fresh-cut-policy.md +3 -2
- package/docs/setup-clean-host.md +110 -17
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +101 -109
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +2 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/tool-surface.js +6 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/codex-fresh-preflight.js +326 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-fact-provider.js +22 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-peers-render.js +3 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +6 -7
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-native-push.js +30 -17
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +7 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +7 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-mailbox-body.js +20 -11
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +227 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +50 -15
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/native-push/adapter.js +10 -7
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/native-push/codex-ws-client.js +403 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/native-push/register.js +4 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook-codex.js +325 -0
- package/mcp/entwurf-bridge/dist/scripts/meta-bridge-fresh-cut.js +6 -1
- package/mcp/entwurf-bridge/src/index.ts +115 -111
- package/mcp/entwurf-bridge/tsconfig.build.json +1 -0
- package/package.json +14 -5
- package/pi-extensions/entwurf-control.ts +71 -19
- package/pi-extensions/lib/acp/acp-client.ts +3 -3
- package/pi-extensions/lib/acp/backend-adapter.ts +3 -3
- package/pi-extensions/lib/acp/backend.ts +3 -3
- package/pi-extensions/lib/acp/event-mapper.ts +4 -4
- package/pi-extensions/lib/acp/tool-surface.ts +6 -0
- package/pi-extensions/lib/codex-fresh-preflight.ts +363 -0
- package/pi-extensions/lib/compaction-send-guard.ts +80 -0
- package/pi-extensions/lib/entwurf-fact-provider.ts +29 -3
- package/pi-extensions/lib/entwurf-peers-render.ts +4 -1
- package/pi-extensions/lib/entwurf-v2-contract.ts +6 -7
- package/pi-extensions/lib/entwurf-v2-native-push.ts +35 -18
- package/pi-extensions/lib/entwurf-v2-production.ts +10 -3
- package/pi-extensions/lib/entwurf-v2-surface.ts +7 -4
- package/pi-extensions/lib/meta-mailbox-body.ts +22 -13
- package/pi-extensions/lib/meta-sender-identity.ts +305 -0
- package/pi-extensions/lib/mux-fresh-call.ts +64 -19
- package/pi-extensions/lib/native-push/adapter.ts +21 -24
- package/pi-extensions/lib/native-push/codex-ws-client.ts +506 -0
- package/pi-extensions/lib/native-push/register.ts +7 -9
- package/pi-extensions/meta-bridge-hook-codex.ts +371 -0
- package/run.sh +251 -35
- package/scripts/check-acp-usage-accounting.ts +9 -9
- package/scripts/check-agy-sender-identity.ts +1 -1
- package/scripts/check-codex-birth-hook.ts +264 -0
- package/scripts/check-codex-bridge-identity.ts +179 -0
- package/scripts/check-codex-native-push.ts +386 -0
- package/scripts/check-codex-sender-identity.ts +495 -0
- package/scripts/check-compaction-send-guard.ts +130 -0
- package/scripts/check-copilot-receive-arm.ts +4 -1
- package/scripts/check-entwurf-fact-provider.ts +38 -0
- package/scripts/check-entwurf-peers-surface.ts +13 -1
- package/scripts/check-entwurf-self-address.ts +15 -16
- package/scripts/check-entwurf-v2-contract.ts +4 -3
- package/scripts/check-entwurf-v2-decider.ts +7 -5
- package/scripts/check-entwurf-v2-native-push.ts +35 -7
- package/scripts/check-entwurf-v2-production.ts +203 -11
- package/scripts/check-entwurf-v2-runner.ts +1 -1
- package/scripts/check-entwurf-v2-surface.ts +1 -1
- package/scripts/check-gate-qualification.ts +7 -4
- package/scripts/check-harness-admission-parity.ts +0 -1
- package/scripts/check-install-surface.ts +23 -7
- package/scripts/check-mux-launch-tmux.ts +47 -2
- package/scripts/check-native-push-adapter.ts +20 -16
- package/scripts/check-native-push-register.ts +5 -1
- package/scripts/check-release-gate-outcomes.ts +47 -1
- package/scripts/check-setup-qualification.sh +3 -1
- package/scripts/codex-birth-doctor.sh +276 -0
- package/scripts/codex-birth-install.sh +414 -0
- package/scripts/codex-birth-uninstall.sh +170 -0
- package/scripts/codex-mcp-config.py +435 -0
- package/scripts/codex-statusline-config.py +434 -0
- package/scripts/codex_toml_io.py +532 -0
- package/scripts/lib/codex-fresh-live-protocol.ts +113 -0
- package/scripts/lib/codex-fresh-source-receipts.ts +399 -0
- package/scripts/lib/launch-receipt-windows.ts +46 -0
- package/scripts/lib/tmux-coordinate-row.ts +58 -0
- package/scripts/meta-bridge-fresh-cut.ts +6 -1
- package/scripts/mutants/codex-native.json +838 -0
- package/scripts/mutants/compaction-send-guard.json +103 -0
- package/scripts/mutants/entwurf-peers.json +19 -0
- package/scripts/mutants/mux-fresh-call.json +19 -8
- package/scripts/mutants/omp-fresh.json +6 -4
- package/scripts/mutants/pi-package-ownership.json +26 -0
- package/scripts/mutants/release-gate.json +13 -0
- package/scripts/mutants/v2-surface.json +53 -1
- package/scripts/pi_settings_io.py +3 -1
- package/scripts/raw-async-delivery/README.md +2 -1
- package/scripts/raw-codex-measure/README.md +114 -46
- package/scripts/register-pi-package.py +38 -30
- package/scripts/register-pi-provider.py +3 -2
- package/scripts/smoke-acp-raw-turn-live.ts +1 -1
- package/scripts/smoke-agy-native-push-live.ts +3 -1
- package/scripts/smoke-codex-birth.sh +347 -0
- package/scripts/smoke-codex-config-state.sh +511 -0
- package/scripts/smoke-codex-fresh-live.ts +1186 -0
- package/scripts/smoke-codex-native-push-live.ts +75 -0
- package/scripts/smoke-setup-verdict.sh +123 -10
- package/scripts/smoke-user-scope-citizen.sh +199 -71
- package/scripts/tsconfig.json +1 -0
|
@@ -6,47 +6,45 @@ the one-line registration; everything an operator needs to actually wire a host
|
|
|
6
6
|
|
|
7
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
|
-
- **plain external MCP host**: no garden meta-record
|
|
10
|
-
- **garden-native native session**: a trusted lifecycle
|
|
9
|
+
- **plain external MCP host**: no garden meta-record or authoritative identity carrier. 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 event minted a garden id — `SessionStart` for Claude Code and Codex, `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. Claude/Copilot/agy/OMP then use record-backed process markers; Codex instead carries its matching native `threadId` on every MCP request. 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, 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
|
|
14
|
+
**Which verb an external agent should reach for:** to deliver to / reply to a garden id, use **`entwurf_v2`** — it is the canonical delivery surface and the only one that reads whether the target is live pi, dormant pi, a mailbox-backed self-fetch citizen (Claude Code, Copilot, OMP), or native-push Antigravity/Codex and routes correctly. Discover targets with `entwurf_peers`, confirm your own identity with `entwurf_self`, drain a mailbox with `entwurf_inbox_read`, and use `entwurf_register_native` only as the explicit/manual fallback for binding an already-running agy conversation. Open a NEW sibling with **`entwurf_fresh_call {backend, model, task, cwd?, placement?}`**, and reopen a DORMANT pi citizen under the same id with **`entwurf_resume_call {target}`**.
|
|
15
15
|
|
|
16
|
-
Observed: Claude Code, Codex CLI, Antigravity CLI, GitHub Copilot CLI and OMP all reach
|
|
16
|
+
Observed: Claude Code, Codex CLI, Antigravity CLI, GitHub Copilot CLI and OMP all reach this MCP bridge. Claude, Copilot and OMP become symmetric/replyable through mailbox-backed meta-sessions; agy and Codex use native-push. Codex's identity is request-scoped `_meta.threadId`, and its replyability requires that exact record plus a loaded app-server thread. Plain external hosts still need an identity lane to send.
|
|
17
17
|
|
|
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`, `spawn entwurf ENOENT`, or `spawn
|
|
23
|
-
|
|
24
|
-
> **Identity-carrier boundary.**
|
|
25
|
-
>
|
|
26
|
-
>
|
|
27
|
-
>
|
|
28
|
-
>
|
|
29
|
-
> managed
|
|
30
|
-
> harness establish its own identity
|
|
31
|
-
>
|
|
32
|
-
>
|
|
33
|
-
>
|
|
34
|
-
> contamination rather than silently preferring the marker.
|
|
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`, `spawn omp ENOENT`, or `spawn codex 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
|
+
|
|
24
|
+
> **Identity-carrier boundary.** The bridge reconciles every authoritative claim available to
|
|
25
|
+
> the request: the complete `PI_SESSION_ID` + `PI_AGENT_ID` pair, a native sender marker, and
|
|
26
|
+
> Codex request `_meta`. Zero claims is refused; multiple claims must name the same garden id or
|
|
27
|
+
> the call throws. Nothing silently wins. Those pi variables are correct only inside the pi
|
|
28
|
+
> process that planted them from record birth; they are foreign identity in another native
|
|
29
|
+
> harness. Every managed fresh launch therefore empties both variables at the tmux seam and lets
|
|
30
|
+
> the launched harness establish its own identity. Clearing only one is not a repair: an
|
|
31
|
+
> incomplete pair is itself invalid, while retaining either carrier invites future reader drift.
|
|
32
|
+
> An unmanaged launch that inherits them is unsupported. A native-harness admission must add a
|
|
33
|
+
> doctor or request-level contract that names contamination rather than trusting precedence.
|
|
35
34
|
>
|
|
36
|
-
> **
|
|
37
|
-
>
|
|
38
|
-
>
|
|
39
|
-
>
|
|
40
|
-
>
|
|
41
|
-
>
|
|
42
|
-
> as coverage for them.
|
|
35
|
+
> **The defenses are layered.** Copilot's managed launcher unsets both carriers before `exec`,
|
|
36
|
+
> and `doctor-copilot-receive` detects a contaminated live CLI. The shared fresh-call tmux seam
|
|
37
|
+
> empties them for every backend. OMP retains its process-environment doctor for manually opened
|
|
38
|
+
> sessions. Codex's request-level reconciler adds a different last line: a foreign pi claim and
|
|
39
|
+
> `_meta.threadId` claim cannot coexist under different garden ids. These are complementary;
|
|
40
|
+
> no backend's cell is evidence for another's unmanaged launch.
|
|
43
41
|
>
|
|
44
42
|
> **OMP has both halves, and the strip one is not an omp launcher** (#87 Bundle C). entwurf still
|
|
45
43
|
> owns no managed omp invocation — the bare vendor runtime IS this harness's clause 1 answer, and
|
|
46
44
|
> nothing here argues for a wrapper. The strip sits one level up instead, at the shared launch seam
|
|
47
45
|
> every `entwurf_fresh_call` backend passes through: `SCRUBBED_INHERITED_ENV` empties
|
|
48
46
|
> `PI_SESSION_ID` and `PI_AGENT_ID` on the `new-window` argv itself
|
|
49
|
-
> (`pi-extensions/lib/mux-fresh-call.ts
|
|
47
|
+
> (`pi-extensions/lib/mux-fresh-call.ts`), for all five backends rather than only the one whose
|
|
50
48
|
> measurement surfaced it, because the leak is a property of tmux and not of a vendor. `-e VAR=`
|
|
51
49
|
> sets the variable empty rather than unsetting it — tmux has no per-window unset — and every
|
|
52
50
|
> carrier reader trims and tests truthiness, so empty and absent are the same answer by
|
|
@@ -78,16 +76,16 @@ Then add it to the external MCP config:
|
|
|
78
76
|
}
|
|
79
77
|
```
|
|
80
78
|
|
|
81
|
-
**Anonymous sender hatch (explicit, documented — never a default).** The bridge refuses an `entwurf_v2` send when the process has neither pi-session env
|
|
79
|
+
**Anonymous sender hatch (explicit, documented — never a default).** The bridge refuses an `entwurf_v2` send when the process has neither pi-session env nor a trusted native identity claim. A deliberately-anonymous plain external host may opt out by adding `"ENTWURF_BRIDGE_ALLOW_ANONYMOUS_SENDER": "1"` to the MCP server `env`. The cost is honest and fixed: the send lands with `origin: "external-mcp"`, `replyable: false`, and `wants_reply: true` stays pointless. A managed Codex citizen does **not** use this hatch; request `_meta` supplies its authoritative identity.
|
|
82
80
|
|
|
83
81
|
Emergency/manual workaround when the MCP server environment is wrong but an existing entwurf session must be resumed: run `pi --session /path/to/entwurf.jsonl ...` from an interactive shell whose PATH is known-good. Treat this as a debug escape hatch, not a replacement for fixing the MCP launch environment.
|
|
84
82
|
|
|
85
83
|
External/meta-session semantics:
|
|
86
84
|
|
|
87
85
|
- `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.
|
|
88
|
-
- `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
|
|
86
|
+
- `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; Antigravity requires a live native probe; Codex requires a matching request-scoped record and loaded app-server thread. Identity survives either way; only `replyable` drops to `false`.
|
|
89
87
|
- `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.
|
|
90
|
-
- `entwurf_self` returns the same authoritative identity for pi sessions **and** trusted meta-sessions. A plain external host with no pi env
|
|
88
|
+
- `entwurf_self` returns the same authoritative identity for pi sessions **and** trusted meta-sessions. A plain external host with no pi env, native marker, or Codex request claim still fails because there is no reply address to report.
|
|
91
89
|
|
|
92
90
|
#### Claude Code
|
|
93
91
|
|
|
@@ -129,14 +127,37 @@ Claude Code reads `~/.mcp.json` in addition to `~/.claude.json`'s top-level `mcp
|
|
|
129
127
|
|
|
130
128
|
#### Codex CLI
|
|
131
129
|
|
|
132
|
-
|
|
130
|
+
Use the owned surfaces rather than editing `~/.codex/config.toml`:
|
|
133
131
|
|
|
134
|
-
```
|
|
135
|
-
|
|
136
|
-
|
|
132
|
+
```bash
|
|
133
|
+
entwurf install-codex-birth
|
|
134
|
+
entwurf install-codex-mcp
|
|
135
|
+
entwurf install-codex-statusline
|
|
136
|
+
|
|
137
|
+
entwurf doctor-codex-birth
|
|
138
|
+
entwurf doctor-codex-mcp
|
|
139
|
+
entwurf doctor-codex-statusline
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
The birth unit owns a `SessionStart` declaration in `$CODEX_HOME/hooks.json`, which the vendor
|
|
143
|
+
runs only after the operator trusts it once in a visible Codex; the other two units own
|
|
144
|
+
only `[mcp_servers.entwurf-bridge]` and the `thread-title` status-line member. The MCP
|
|
145
|
+
entry carries `ENTWURF_BRIDGE_NATIVE_HOST=codex`, which tells the bridge to require and
|
|
146
|
+
reconcile Codex request `_meta`. Do not add the anonymous hatch.
|
|
147
|
+
|
|
148
|
+
Native receive and visible fresh require the operator-owned default app-server. Entwurf
|
|
149
|
+
does not start or supervise it:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
|
|
153
|
+
codex app-server --listen "unix://$CODEX_HOME/app-server-control/app-server-control.sock"
|
|
137
154
|
```
|
|
138
155
|
|
|
139
|
-
|
|
156
|
+
Birth occurs on the first turn, not window open. It mints
|
|
157
|
+
`record.nativeSessionId = threadId` and sets the visible thread title to the garden id.
|
|
158
|
+
`entwurf_v2` probes the loaded-thread list and sends once through `codex queue`; it never
|
|
159
|
+
retries. `entwurf_fresh_call` accepts `backend: "codex"` after all three owned units and
|
|
160
|
+
the default socket pass preflight. Codex remains outside ACP and has no resume surface.
|
|
140
161
|
|
|
141
162
|
#### Antigravity CLI (`agy`)
|
|
142
163
|
|
|
@@ -169,6 +190,7 @@ Use the managed install surface rather than editing omp's files by hand:
|
|
|
169
190
|
```bash
|
|
170
191
|
entwurf install-omp-bridge # the BIRTH extension (a garden id per visible TUI session)
|
|
171
192
|
entwurf install-omp-mcp # the MCP hand (this section)
|
|
193
|
+
entwurf install-omp-config # the operator setting (tools.xdev: false)
|
|
172
194
|
entwurf install-omp-receive # the RECEIVER extension (mailbox watch + announce-only doorbell)
|
|
173
195
|
|
|
174
196
|
entwurf doctor-omp-bridge
|
|
@@ -176,7 +198,7 @@ entwurf doctor-omp-mcp
|
|
|
176
198
|
entwurf doctor-omp-receive
|
|
177
199
|
```
|
|
178
200
|
|
|
179
|
-
|
|
201
|
+
Four units, not two. The receiver is what makes the citizen answerable at all — without it omp
|
|
180
202
|
sends under its own garden id and every reply is refused as `mailbox-undeliverable` — and it is
|
|
181
203
|
also a prerequisite of visible fresh: the fresh preflight refuses this host before touching tmux
|
|
182
204
|
when the receive unit is missing, rather than opening a window that can never be reached.
|
|
@@ -244,7 +266,8 @@ bridge registered, **11 devices**: omp's own `ast_edit`, `debug`, `lsp`, `browse
|
|
|
244
266
|
seven `entwurf_*`. So the default does not merely wrap entwurf — it wraps omp's own LSP and
|
|
245
267
|
debugger too.
|
|
246
268
|
|
|
247
|
-
|
|
269
|
+
**`entwurf setup` writes this for a detected omp host, and `entwurf install-omp-config` is
|
|
270
|
+
the repair leaf. The value they own:**
|
|
248
271
|
|
|
249
272
|
```yaml
|
|
250
273
|
# ~/.omp/agent/config.yml
|
package/docs/fresh-cut-policy.md
CHANGED
|
@@ -22,7 +22,8 @@ the new generation.
|
|
|
22
22
|
## What certification checks
|
|
23
23
|
|
|
24
24
|
`certifyActiveStore` is shared by the doctor and all identity writers: pi birth,
|
|
25
|
-
Claude's `SessionStart`,
|
|
25
|
+
Claude's `SessionStart`, Copilot's first-prompt birth hook, OMP's birth extension,
|
|
26
|
+
agy's imprint, and `entwurf_register_native`. Every active
|
|
26
27
|
record must be:
|
|
27
28
|
|
|
28
29
|
- a regular, non-symlink `.meta.json` file;
|
|
@@ -43,7 +44,7 @@ are opened without following symlinks; implementation and race proofs live besid
|
|
|
43
44
|
|
|
44
45
|
## Running a cut
|
|
45
46
|
|
|
46
|
-
First close every pi, Claude Code, and agy session that could own a citizen or
|
|
47
|
+
First close every pi, Claude Code, Copilot, OMP, and agy session that could own a citizen or
|
|
47
48
|
transport artifact. Then run:
|
|
48
49
|
|
|
49
50
|
```bash
|
package/docs/setup-clean-host.md
CHANGED
|
@@ -8,8 +8,8 @@ evidence split, and its three states must not collapse into "macOS is supported"
|
|
|
8
8
|
(`macos-install-surface`). Weaker than a physical-host doctor green. §1 is
|
|
9
9
|
this surface.
|
|
10
10
|
- **NOT CERTIFIED — pending physical host** — **on macOS**, every garden-native
|
|
11
|
-
harness rail in §2–§6 (pi, Claude, Copilot, OMP, agy), marker join,
|
|
12
|
-
mux. Wiring may be written; that is not a rail receipt. The remaining
|
|
11
|
+
harness rail in §2–§6 (pi, Claude, Copilot, OMP, agy, Codex), marker/request join,
|
|
12
|
+
ACP turn, mux. Wiring may be written; that is not a rail receipt. The remaining
|
|
13
13
|
unmeasured Darwin doctor reason is per-process environment DISCOVERY
|
|
14
14
|
(start-key is portable).
|
|
15
15
|
- **UNSUPPORTED** — native Windows only. macOS is never this.
|
|
@@ -20,13 +20,14 @@ evidence split, and its three states must not collapse into "macOS is supported"
|
|
|
20
20
|
|---|---|---|
|
|
21
21
|
| Node | **`>=24.0.0`** | package and bridge runtime |
|
|
22
22
|
| npm/pnpm | npm is bundled with Node; pnpm is required for source setup | package or source installation |
|
|
23
|
-
| Python 3 | required by `setup`/`install` (project-path normalization + settings writers); `--help`/`check-bridge` stay Python-free | pi/Claude/agy/Copilot wiring writers |
|
|
23
|
+
| Python 3 | required by `setup`/`install` (project-path normalization + settings writers); `--help`/`check-bridge` stay Python-free | pi/Claude/agy/Copilot/Codex wiring writers |
|
|
24
24
|
| entwurf | global/project-local `@junghanacs/entwurf`, or a source checkout | operator command and garden capability |
|
|
25
25
|
| pi | optional-by-presence, `>=0.85.1 <0.86` — absent is an explicit setup SKIP, below-floor is a named FAIL | ACP provider, control sockets |
|
|
26
26
|
| Claude Code | optional, **`>=2.1.217`** — the exec-form hook floor | Claude ACP auth/runtime and mailbox-backed native citizen |
|
|
27
27
|
| 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 |
|
|
28
28
|
| OMP (`omp`) | optional-by-presence, operator-installed — absent is an explicit setup SKIP; detected composes all four units (birth/MCP/`tools.xdev` setting/receiver) | self-fetch citizen and visible fresh (accepted on one host — see §4b) |
|
|
29
29
|
| Antigravity `agy` | optional, operator-installed and authenticated | native-push citizen |
|
|
30
|
+
| OpenAI Codex CLI | optional-by-presence, operator-installed and authenticated; detected composes all three operator-owned units (birth/MCP/status-line) and stays non-green until the operator trusts the birth declaration once in a visible Codex; visible fresh also requires an operator-owned existing tmux session named `codex`, with its app-server and supported TUIs seated there | native-push and visible fresh, supported in 0.21.0 |
|
|
30
31
|
| Cortex Code | optional, operator-installed and authenticated | Cortex ACP backend |
|
|
31
32
|
|
|
32
33
|
Claude Code >=2.1.217 is required for the managed exec-hook lifecycle. The package
|
|
@@ -52,9 +53,9 @@ harness. The wiring is written; the row is FAIL:
|
|
|
52
53
|
> platform. Tracking: #78.
|
|
53
54
|
|
|
54
55
|
That FAIL is honest: setup runs no doctor, and no physical-host rail
|
|
55
|
-
receipt exists — it is not an install failure. An Entwurf-only host
|
|
56
|
-
harness on PATH
|
|
57
|
-
`result: green`), which is what CERTIFIED (CI)
|
|
56
|
+
receipt exists — it is not an install failure. An Entwurf-only host with no
|
|
57
|
+
harness on PATH stays green (six SKIP, `bins: PASS`, `core: PASS`,
|
|
58
|
+
`result: green`), which is what CERTIFIED (CI) observes.
|
|
58
59
|
|
|
59
60
|
A physical Mac can send host facts without installing entwurf or logging
|
|
60
61
|
into a harness: `scripts/raw-macos-measure/probe.sh` (`/bin/sh`, ~3.5s,
|
|
@@ -91,10 +92,10 @@ npx entwurf check-bridge
|
|
|
91
92
|
`check-bridge` is auth-free. It proves the installed prebuilt MCP server boots and
|
|
92
93
|
lists the seven garden tools; it does not prove a backend model turn or native hook.
|
|
93
94
|
|
|
94
|
-
Neither npm form installs a harness runtime. `pi`, Claude Code, Copilot CLI, agy,
|
|
95
|
-
authentication remain operator-owned optional prerequisites for the
|
|
96
|
-
all may be absent on an Entwurf-only host. A source checkout's
|
|
97
|
-
for building and testing this repo, not a transitive product installation promise.
|
|
95
|
+
Neither npm form installs a harness runtime. `pi`, Claude Code, Copilot CLI, Codex CLI, agy,
|
|
96
|
+
Cortex, and their authentication remain operator-owned optional prerequisites for the
|
|
97
|
+
integrations that use them; all may be absent on an Entwurf-only host. A source checkout's
|
|
98
|
+
pinned Pi development packages are for building and testing this repo, not a transitive product installation promise.
|
|
98
99
|
|
|
99
100
|
Maintainers using a source checkout do not install a second global entwurf package. Full source
|
|
100
101
|
setup currently requires Node 24, pnpm, and Python 3 on PATH; every harness — including pi — is
|
|
@@ -109,12 +110,14 @@ cd ~/repos/gh/entwurf
|
|
|
109
110
|
|
|
110
111
|
This owns `~/.local/bin/entwurf` as a symlink to that checkout's `run.sh` and fails if the
|
|
111
112
|
link is foreign, outside PATH, or shadowed by another command. It detects and wires
|
|
112
|
-
pi/Claude/agy/Copilot/OMP by presence and prints a computed per-component
|
|
113
|
-
detected harness that cannot be completed makes setup exit nonzero.
|
|
114
|
-
composes all four native units
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
113
|
+
pi/Claude/agy/Copilot/OMP/Codex by presence and prints a computed per-component
|
|
114
|
+
PASS/SKIP/FAIL summary — a detected harness that cannot be completed makes setup exit nonzero.
|
|
115
|
+
A detected `copilot` composes all four native units, and a detected `omp` composes its own four.
|
|
116
|
+
A detected Codex install is a supported 0.21.0 path: setup composes its user-scope birth,
|
|
117
|
+
MCP, and status-line atoms but never escalates or starts the app-server. It reports independent
|
|
118
|
+
component outcomes, preserves exact env forwarding and idempotence, and returns a named
|
|
119
|
+
`codex-birth FAIL` until the vendor trust receipt exists.
|
|
120
|
+
§4, §4b, and §4c keep the explicit per-unit install/doctor/inverse surfaces.
|
|
118
121
|
|
|
119
122
|
### 1.1 User-scope ownership (one shared registration, one recorded owner)
|
|
120
123
|
|
|
@@ -396,6 +399,92 @@ The MCP entry deliberately uses the same server key as any Claude Code import so
|
|
|
396
399
|
SHADOWS it; see [`external-mcp-host.md`](./external-mcp-host.md) for why that key is pinned and
|
|
397
400
|
why `disabledServers` is never the way to hide an import.
|
|
398
401
|
|
|
402
|
+
## 4c. Optional OpenAI Codex CLI native citizen
|
|
403
|
+
|
|
404
|
+
Supported in 0.21.0 with Linux-focused evidence; on macOS it is NOT CERTIFIED —
|
|
405
|
+
pending physical host. It is native, not ACP: the purpose is to preserve the operator's
|
|
406
|
+
Codex tools, delegation, and work context rather than provide another GPT access path.
|
|
407
|
+
Entwurf owns three atoms, not the harness and not a daemon:
|
|
408
|
+
|
|
409
|
+
```bash
|
|
410
|
+
# All three are operator-scope; `entwurf setup` runs them when it detects Codex. No root.
|
|
411
|
+
entwurf install-codex-birth
|
|
412
|
+
entwurf install-codex-mcp
|
|
413
|
+
entwurf install-codex-statusline
|
|
414
|
+
|
|
415
|
+
entwurf doctor-codex-birth
|
|
416
|
+
entwurf doctor-codex-mcp
|
|
417
|
+
entwurf doctor-codex-statusline
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
The birth atom publishes a `SessionStart` declaration into `$CODEX_HOME/hooks.json` with its
|
|
421
|
+
launcher closure under `$XDG_DATA_HOME/entwurf/codex-birth`; it mints a V3 record on the
|
|
422
|
+
thread's first turn and sets the thread title to the garden id.
|
|
423
|
+
|
|
424
|
+
**One step is the operator's, and no command can do it for them.** The vendor will not run a
|
|
425
|
+
user-layer hook until it has been trusted once: open a visible plain Codex, answer
|
|
426
|
+
`Trust all and continue`, then send one first turn. `doctor-codex-birth` reads the receipt the
|
|
427
|
+
vendor writes for that declaration and is RED without it — entwurf never writes, pre-seeds or
|
|
428
|
+
recomputes that value, because it is the operator's security decision, not ours. After the one
|
|
429
|
+
answer, later sessions raise no prompt and are born automatically. The MCP writer owns
|
|
430
|
+
`[mcp_servers.entwurf-bridge]` in `$CODEX_HOME/config.toml`. Its exact `env_vars` allowlist is
|
|
431
|
+
`CODEX_HOME`, `ENTWURF_DIR`, `PI_CODING_AGENT_DIR`, `ENTWURF_META_SESSIONS_DIR`,
|
|
432
|
+
`ENTWURF_META_MAILBOX_DIR`, `ENTWURF_META_SENDERS_DIR`, `ENTWURF_META_RECEIVERS_DIR`,
|
|
433
|
+
`TMUX`, and `TMUX_PANE`.
|
|
434
|
+
The status-line writer owns only `thread-title`. Foreign or symlinked config is refused.
|
|
435
|
+
|
|
436
|
+
Native delivery requires the operator-owned default app-server and one existing tmux session
|
|
437
|
+
named exactly `codex`. Start the app-server from a pane there and seat supported Codex TUIs there:
|
|
438
|
+
|
|
439
|
+
```bash
|
|
440
|
+
# Run these commands inside the operator-owned tmux session named exactly `codex`.
|
|
441
|
+
CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
|
|
442
|
+
mkdir -p "$CODEX_HOME/app-server-control"
|
|
443
|
+
codex app-server --listen "unix://$CODEX_HOME/app-server-control/app-server-control.sock"
|
|
444
|
+
codex --remote "unix://$CODEX_HOME/app-server-control/app-server-control.sock"
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
Omitted Codex fresh placement resolves exact `codex` on the caller's tmux server. The app-server's
|
|
448
|
+
`TMUX`/`TMUX_PANE` is forwarded to its MCP child, so a Codex citizen's omitted outbound Pi placement
|
|
449
|
+
stays in that home. It is **not** an arbitrary attached-TUI pane join. Exact Codex 0.153.4 source
|
|
450
|
+
exposes no request→attached-TUI-seat carrier, so clients attached from other sessions have no
|
|
451
|
+
adjacency claim; that wider topology is unsupported and unclaimed. Entwurf does not guess panes,
|
|
452
|
+
create the tmux home, expose a generic app-server manager/API, or start/restart the server. Custom
|
|
453
|
+
`CODEX_HOME` and Entwurf roots cross the same explicit `env_vars` boundary. Strict request `_meta`
|
|
454
|
+
identifies the thread caller, not its seat. Delivery uses one `codex queue` invocation with no retry.
|
|
455
|
+
|
|
456
|
+
The 2026-09-11 loaded-thread run remains pre-amendment native-push/identity evidence. The final
|
|
457
|
+
first-admission acceptance passed on 2026-09-12: real initial Pi outside `codex`, then omitted-placement
|
|
458
|
+
Codex and outbound Pi inside it, with exact callbacks and addressed delivery both ways. `DELIVERY.md`
|
|
459
|
+
owns the 57-assertion receipt, four coordinates, and digest.
|
|
460
|
+
|
|
461
|
+
`entwurf_fresh_call` accepts backend `codex` — supported in 0.21.0 — and requires an explicit model. Its
|
|
462
|
+
preflight must prove the safe birth closure, exact MCP/env atom, `thread-title`, and app-server
|
|
463
|
+
socket before tmux mutation. The sibling's garden id comes from the callback sender envelope,
|
|
464
|
+
never the launch receipt. There is no Codex resume surface, watcher, supervisor, or app-server
|
|
465
|
+
lifecycle ownership. The accepted LIVE used a real record-backed visible Pi for the first leg;
|
|
466
|
+
release-gate stripped ambient `PI_SESSION_ID`/`PI_AGENT_ID`, and the fixture/self-fetch citizen only
|
|
467
|
+
collected receipts. The smoke reported initial Pi, app-server, fresh Codex, and outbound Pi
|
|
468
|
+
coordinates separately: the initial Pi differed and the latter three matched the exact `codex` home.
|
|
469
|
+
Qualification and the frozen full floor are complete for this lane: `check-gate-qualification`
|
|
470
|
+
killed 475/475 across 43 lanes with origin purity green, `check:full` exited 0, and the LIVE release
|
|
471
|
+
gate reported MUST 24/0/0 with `cut: OK`. The bounds above are unchanged — no request→arbitrary
|
|
472
|
+
attached-TUI seat join, no resume surface, and macOS remains NOT CERTIFIED pending a physical host.
|
|
473
|
+
|
|
474
|
+
Oracle runs the first-admission LIVE with explicit ownership/model selectors:
|
|
475
|
+
|
|
476
|
+
```bash
|
|
477
|
+
LIVE=1 \
|
|
478
|
+
ENTWURF_CODEX_APP_SERVER_PID=<existing-app-server-pid> \
|
|
479
|
+
ENTWURF_CODEX_FRESH_MODEL=<codex-model> \
|
|
480
|
+
ENTWURF_CODEX_FRESH_PI_MODEL=<pi-model> \
|
|
481
|
+
entwurf smoke-codex-fresh-live
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
Run this from a tmux session other than `codex`. The entrypoint name does not waive the contract
|
|
485
|
+
above. A fixture/self-fetch citizen may collect receipts but cannot replace the real visible Pi leg;
|
|
486
|
+
a Pi that starts inside the Codex home proves only the weaker shared-seat mechanism.
|
|
487
|
+
|
|
399
488
|
## 5. Optional Antigravity native citizen
|
|
400
489
|
|
|
401
490
|
This rail is CERTIFIED on Linux; on macOS it is NOT CERTIFIED — pending
|
|
@@ -464,7 +553,7 @@ rail receipt. Doctors refuse on Darwin until a physical-host receipt
|
|
|
464
553
|
exists.
|
|
465
554
|
|
|
466
555
|
If install or doctor reports an unreadable/old active citizen generation, do not edit
|
|
467
|
-
records by hand. Close pi, Claude, Copilot,
|
|
556
|
+
records by hand. Close pi, Claude, Copilot, OMP, agy, and Codex sessions first, run
|
|
468
557
|
`entwurf meta-bridge-fresh-cut`, and read its exit status before any install. Then choose the
|
|
469
558
|
installation mode you actually own:
|
|
470
559
|
|
|
@@ -496,6 +585,7 @@ PASS/SKIP/FAIL summary. The complete quiescence, archive, and exit-code contract
|
|
|
496
585
|
- `scripts/raw-macos-measure/probe.sh`: physical-Darwin host facts (~3.5s,
|
|
497
586
|
no install, no login). Measurement, not a certification path.
|
|
498
587
|
- `doctor-meta-bridge`: one installed real Claude host, only with a new live session.
|
|
588
|
+
- `doctor-codex-{birth,mcp,statusline}` plus `LIVE=1 CODEX_LIVE_THREAD_ID=<id> entwurf smoke-codex-native-push-live`: one installed Codex host; the aggregate does not own a loaded thread.
|
|
499
589
|
- `LIVE=1 entwurf release-gate /path/to/scratch --cut`: aggregate runtime acceptance (`--cut` makes any MUST SKIP red; without it the run is a diagnostic pass).
|
|
500
590
|
|
|
501
591
|
Keep these verdicts separate. Current protocol is [VERIFY.md](../VERIFY.md); recorded
|
|
@@ -519,6 +609,9 @@ entwurf uninstall-copilot-bridge
|
|
|
519
609
|
entwurf uninstall-agy-hooks
|
|
520
610
|
entwurf uninstall-agy-statusline
|
|
521
611
|
entwurf uninstall-agy-bridge
|
|
612
|
+
entwurf uninstall-codex-statusline
|
|
613
|
+
entwurf uninstall-codex-mcp
|
|
614
|
+
entwurf uninstall-codex-birth
|
|
522
615
|
entwurf remove ~/entwurf-smoke
|
|
523
616
|
# only when no other project uses the shared user-scope pi registration:
|
|
524
617
|
entwurf remove-user-scope
|