@junghanacs/entwurf 0.30.1 → 0.31.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 +112 -0
- package/DELIVERY.md +1 -0
- package/README.md +47 -7
- package/VERIFY.md +17 -1
- package/demo/README.md +1 -1
- package/docs/acp-backend-rail.md +1 -1
- package/docs/setup-clean-host.md +104 -4
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +7 -7
- package/mcp/entwurf-bridge/dist/pi-extensions/entwurf-capabilities.json +1 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-deliverability.js +7 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +34 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +7 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +28 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +30 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-fresh-preflight.js +92 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-runtime.js +288 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-pi-durable.js +744 -0
- package/mcp/entwurf-bridge/src/index.ts +7 -7
- package/mcp/entwurf-bridge/tsconfig.build.json +8 -1
- package/package.json +13 -10
- package/pi/entwurf-capabilities.json +1 -0
- package/pi/pi-durable/bootstrap.mjs +281 -0
- package/pi/pi-durable/overlay/runtime-contacts.patch +91 -0
- package/pi/pi-durable/overlay/upstream-pin.json +16 -0
- package/pi-extensions/lib/entwurf-deliverability.ts +7 -1
- package/pi-extensions/lib/fresh-call-composition.ts +42 -7
- package/pi-extensions/lib/meta-sender-identity.ts +7 -1
- package/pi-extensions/lib/meta-session.ts +28 -2
- package/pi-extensions/lib/mux-fresh-call.ts +34 -2
- package/pi-extensions/lib/pi-durable-fresh-preflight.ts +113 -0
- package/pi-extensions/lib/pi-durable-runtime.ts +384 -0
- package/pi-extensions/meta-bridge-pi-durable.ts +1020 -0
- package/run.sh +200 -33
- package/scripts/check-fresh-call-dispatch.ts +18 -0
- package/scripts/check-gate-qualification.ts +2 -1
- package/scripts/check-pi-durable-contact.ts +834 -0
- package/scripts/check-pi-durable-receive.ts +1116 -0
- package/scripts/check-pi-durable-send.ts +1661 -0
- package/scripts/lib/pi-durable-fresh-live-receipts.ts +139 -0
- package/scripts/lib/pi-durable-r1.ts +100 -0
- package/scripts/lib/pi-durable-reap.ts +27 -0
- package/scripts/lib/pi-durable-receive.ts +137 -0
- package/scripts/mutants/control-send-receipt.json +1 -1
- package/scripts/mutants/copilot-birth.json +2 -2
- package/scripts/mutants/meta-hook-session-switch.json +4 -2
- package/scripts/mutants/mux-fresh-call.json +69 -3
- package/scripts/mutants/omp-birth.json +2 -2
- package/scripts/mutants/omp-fresh.json +6 -4
- package/scripts/mutants/pack-install.json +3 -3
- package/scripts/mutants/pi-durable.json +390 -0
- package/scripts/mutants/pi-floor.json +2 -2
- package/scripts/pi-durable-contact-host.mjs +105 -0
- package/scripts/pi-durable-receive-host.mjs +127 -0
- package/scripts/pi-durable-send-host.mjs +213 -0
- package/scripts/smoke-pi-durable-fresh-live.ts +624 -0
- package/scripts/smoke-setup-verdict.sh +21 -2
- package/scripts/tsconfig.json +1 -0
package/AGENTS.md
CHANGED
|
@@ -100,6 +100,7 @@ implement → affected focused gates → independent review → one amendment bu
|
|
|
100
100
|
## Type and Working Boundaries
|
|
101
101
|
|
|
102
102
|
- Each `.ts` file belongs to one declared typecheck fence; `exclude` may move a file between fences but never out of all of them, so an exclude states the receiving `include` in the same change. Root pi extensions use TypeBox through `@earendil-works/pi-ai`; MCP/scripts use explicit `.ts` imports required by Node strip-types. Installed surfaces route to compiled JS. Behavior-adjacent `.test.ts` takes the fence `test/` takes — `scripts/tsconfig.json`, never the emit-capable root program — and is kept out of the tarball by a files-array negation whose tripwire is `check-pack`.
|
|
103
|
+
- Develop only on branches in this repository checkout; never use worktrees or tmp development clones. Isolated test fixtures and temporary evidence are not development checkouts.
|
|
103
104
|
- Make surgical, one-contract changes. Removal repairs source and its proof together; a green gate never proves retired behavior.
|
|
104
105
|
- Before commit, sweep repository-wide for retired authority vocabulary and landed-plan future tense. Historical tombstones may remain; live docs, source, gates, and usage must agree.
|
|
105
106
|
- Prefer capability-domain language over identity rank. Use tabs unless the project formatter requires otherwise. GLG decides commit, push, and release gates.
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,118 @@ All notable changes to this project will be documented here. Format follows [Kee
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.31.0 - 2026-10-07
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **Native durable contact (`pi-durable`, #129).**
|
|
12
|
+
Treat the experimental durable coding app as a separate native harness. One
|
|
13
|
+
native host attaches to one V3 garden id; the contact adds visible garden
|
|
14
|
+
identity, self/peers, canonical outbound dispatch and announce-only root-directed
|
|
15
|
+
mailbox receive with explicit inbox read. Runtime, TUI, model/auth, SQLite
|
|
16
|
+
storage, transcript and recovery remain upstream-owned. Internal subagents do
|
|
17
|
+
not mint another citizen. Native recovery is not exactly-once Entwurf delivery.
|
|
18
|
+
|
|
19
|
+
### Installation
|
|
20
|
+
|
|
21
|
+
- **Entwurf's npm/source installation route stays unchanged.** Optional native
|
|
22
|
+
durable use additionally requires an operator-provided pinned upstream source
|
|
23
|
+
runtime and the narrow runtime-contact overlay (Pi 1.0.2/source `cd32f77` in this
|
|
24
|
+
lane). The `@earendil-works/pi-durable` **library** is npm-installable; the
|
|
25
|
+
experimental coding app/TUI is not supplied by the ordinary Pi npm package.
|
|
26
|
+
Entwurf does not install a harness or copy credentials. Existing non-durable
|
|
27
|
+
users do not need a source checkout. [Native durable setup boundary](docs/setup-clean-host.md#2b-optional-native-durable-pi-durable).
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- **Pi dependency/runtime floor is 1.0.2**, with pi peer range `>=1.0.2 <1.1`.
|
|
32
|
+
Native durable pins upstream source `cd32f77` and its narrow contact overlay;
|
|
33
|
+
no upgrade to a newer experimental app or replacement runtime is included.
|
|
34
|
+
- **Source workspace discovery is root-only.** Explicit `packages: ['.']` keeps
|
|
35
|
+
pnpm's workspace scan coherent with the root install, without disabling its
|
|
36
|
+
dependency verification. Prepack still runs the foreground build lifecycle,
|
|
37
|
+
with build output on stderr so pack JSON stays readable and failures propagate.
|
|
38
|
+
|
|
39
|
+
### Verification
|
|
40
|
+
|
|
41
|
+
- **Reviewed pre-version main:** product `165338e` and native-admission `535c2e1`
|
|
42
|
+
landed separately with normal hooks/shared safety scans. The final landing's
|
|
43
|
+
[exact-SHA CI](https://github.com/junghan0611/entwurf/actions/runs/37478003145)
|
|
44
|
+
at `535c2e1b63e6a66c45227e197de80bf261202aec` passed all four required jobs
|
|
45
|
+
and the qualification BODY **872/872 KILLED**, including the new foreign-sender
|
|
46
|
+
guard4.5s KILLED against subject `7bdea2c4c664…`. Implementation issue #129 is closed; #130 owns
|
|
47
|
+
npm-only runtime supply, Pi upgrades, ACP and UI follow-ups. This main receipt
|
|
48
|
+
is not the later prepared-commit or preserved-artifact acceptance.
|
|
49
|
+
- **Native first admission:** corrected real Pi → pi-durable → Pi LIVE36
|
|
50
|
+
passed in41s on `openai-codex/gpt-6.1-sol`, task-wide native5 + contact6 offering.
|
|
51
|
+
A consistent official SQLite backup establishes first callback, own-id inbox
|
|
52
|
+
read, joined successful native dispatch and the exact root doorbell reaching done.
|
|
53
|
+
Pi transcript row19 carries the exact expected payload and authoritative durable
|
|
54
|
+
sender. Native V evidence is distinct from checkout contact95/send19/receive21
|
|
55
|
+
scripted S + native H and installed-bootstrap import-only proof.
|
|
56
|
+
- **Receipt-oracle repair is portable and independently reviewed.** Exact payload,
|
|
57
|
+
terminal sender envelope, root scope, effective offering, call/result and doorbell
|
|
58
|
+
joins replace substring/union predicates. Eight inline tests and the existing mux
|
|
59
|
+
coordinate carry a foreign-sender guard mutant. The original35-GREEN predicate
|
|
60
|
+
selected fixture row15; real old-row19 delivery was independently present. Old raw,
|
|
61
|
+
wrong receipt and RED857/870 remain preserved, never relabelled new acceptance.
|
|
62
|
+
Native admission raw: `.tmp-verify/b9ffcb-pack-cause/live-pd-20261006T223708/`.
|
|
63
|
+
- **Versioned working-candidate P4:** FULL666s/exit0, HEAD/index/tracked work-surface
|
|
64
|
+
and binary diff frozen MATCH; pack dry-run580files. The pre-verdict release-metadata
|
|
65
|
+
patch/bytes are preserved in `.tmp-verify/031-release/prepare/p4/`, snapshot SHA
|
|
66
|
+
`2529949384af40c6ca15f65575638b97980817cb85d7a68bb81e9ff1b34c8fa7`, full-log SHA
|
|
67
|
+
`57da80e9e32159f8bc966381a2756d6a34cca647dd5ee5791ee681ed3509b0df`.
|
|
68
|
+
This floor used the exact private Herdr0.9.3 aarch64 supply pin; operator0.9.1 stayed
|
|
69
|
+
unchanged. No qualification BODY or native LIVE was executed in this P4 run.
|
|
70
|
+
- **Explicit agy criterion7 exception for this0.31.0 cut, confirmed by GLG
|
|
71
|
+
(2026-10-07):** “agy 예외. 0.30.1부터 그렇게 헀어 더 진행가자” permits continuing
|
|
72
|
+
prepare/make while agy1.2 remains **NOT CERTIFIED**. The historical1.1 pin and
|
|
73
|
+
DELIVERY certification row stay unchanged; #128 remains first-party own-context
|
|
74
|
+
prerequisite research. No nonce/credential extraction, old-CID replay, transport
|
|
75
|
+
implementation, permanent floor change or npm publication is authorized by this
|
|
76
|
+
exception. Other release axes remain mandatory.
|
|
77
|
+
- **Fresh native Claude host:** owned writer/registry refresh corrected the stale
|
|
78
|
+
deployed v3 bytes before P5. Source=assembled=installed writer `c8f05d394d0e`,
|
|
79
|
+
capability registry `2f95e94f1eb9`; strict doctor exits0 with four live owner joins.
|
|
80
|
+
A new Claude2.1.291 session after install, garden `20261007T024544-c71062`,
|
|
81
|
+
ownerPID2784041/startKey `linux:304383485`, bridge child2784080, joins sender,
|
|
82
|
+
receiver and V3 record with no model turn. `prepare/claude-native-cert/accepted.json`
|
|
83
|
+
retains the exact metadata. This is checkout-provenance certification, not an
|
|
84
|
+
installed emitted-JS/bin-shim, registry, model-turn or fresh delivery/reply receipt.
|
|
85
|
+
- **First P5 and scoped repair remain distinct.** The frozen candidate's first
|
|
86
|
+
`--cut` run ended RED: MUST23/2/0, BEHAVIOR1/0/0, qualification872/872 KILLED,
|
|
87
|
+
HEAD/index/tracked bytes MATCH. Log `/tmp/entwurf-release-gate-0.31.0.JdQ4q6/release-gate.log`.
|
|
88
|
+
The owned OMP receiver's stale writer was refreshed through its installer; strict
|
|
89
|
+
runtime/ownership doctor and fresh receive LIVE11 passed. Initial Pi's Codex relay
|
|
90
|
+
added one trailing newline; the exact source oracle rejected it. A fresh chain on
|
|
91
|
+
the unchanged candidate passed65 assertions, source audits Pi3/3 + Codex3/3, with
|
|
92
|
+
no oracle relaxation or old-CID replay. The owed on-demand seat×cwd fresh-call
|
|
93
|
+
matrix passed39. `prepare/p5-focused-1/accepted.json` retains those focused receipts;
|
|
94
|
+
they do not turn the original aggregate RED into GREEN. Immediate P9 was report-only,
|
|
95
|
+
five eligible roots312K after P5 and six328K after the focused bundle; protected
|
|
96
|
+
Emacs was the only reparented `/tmp` process, with no deletion or signal.
|
|
97
|
+
- **Final fresh P5 cut verdict:** `LIVE=1 ./run.sh release-gate
|
|
98
|
+
/tmp/entwurf-release-gate-0.31.0.Xzbk2b --cut` exited0 after110m15s:
|
|
99
|
+
**MUST PASS=25 FAIL=0 SKIP=0**, **BEHAVIOR PASS=1 FAIL=0 SKIP=0**, its own
|
|
100
|
+
FULL and qualification **872/872 KILLED**, frozen HEAD/index/tracked bytes MATCH.
|
|
101
|
+
Log SHA256 `609612baff850ec06fc74321002b33a6b71d3dabc76874dc1546b8722c317bf2`;
|
|
102
|
+
snapshot SHA256 `38c49ca5123ffc9883762d637084dba9ed77adbdd5f3e86287a1ace565f763de`.
|
|
103
|
+
`prepare/p5-final/accepted.json` retains the boundary; native durable raw is
|
|
104
|
+
`/tmp/smoke-pi-durable-fresh-live-2026-10-06T23-27-34-983Z`. Immediate P9 reported
|
|
105
|
+
unused198/eligible6/328K, protected Emacs only; no deletion/signal.
|
|
106
|
+
- **Fresh-eyes documentation alignment:** independent Grok review found one
|
|
107
|
+
underclaim bundle, not a false green: operator docs still called accepted native
|
|
108
|
+
admission pending and a direction note pointed to a retired branch handoff.
|
|
109
|
+
After the final P5 verdict, documentation-only commit `87de9f7` aligns those states
|
|
110
|
+
with DELIVERY/#129 and distinguishes seven citizen backends from six fresh-openable
|
|
111
|
+
ones. Bounded independent re-review closed the Defect (Blocker0/Defect0); normal
|
|
112
|
+
hooks/shared scanner passed, and main fast-forwarded locally before release-prep. Executable/gate/model/pin/manifest bytes are unchanged; no LIVE Claude ↔
|
|
113
|
+
durable or registry/runtime provision is inferred. Review artifacts live in
|
|
114
|
+
`.tmp-verify/031-release/grok-fresh-review/` and `docs-amendment/`.
|
|
115
|
+
- **Release acceptance is pending:** prep commit/prepared-SHA CI and preserved
|
|
116
|
+
artifact remain outstanding. No final candidate, tag, GitHub release or npm
|
|
117
|
+
publication is asserted here.
|
|
118
|
+
|
|
7
119
|
## 0.30.1 - 2026-10-04
|
|
8
120
|
|
|
9
121
|
### Fixed
|
package/DELIVERY.md
CHANGED
|
@@ -116,6 +116,7 @@ physical host. Do not read a D-level cell as a Darwin receipt.
|
|
|
116
116
|
| **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. |
|
|
117
117
|
| **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. |
|
|
118
118
|
| **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. |
|
|
119
|
+
| **pi-durable native host** | 0.31.0 candidate; visible fresh + addressed receive + both cross-harness legs accepted on one Linux host (2026-10-06, `smoke-pi-durable-fresh-live`, 36 assertions, exit 0) | D6 (D3/D4 shown); D7 partial; D8 unproven | The operator-provided pinned source runtime (`cd32f77` + overlay) launched by the managed `entwurf pi-durable --provider … --model … --width task-wide`; the contact registers six tools and spawns the compiled bridge as a direct child; receive is announce-only self-fetch (doorbell → root submission → `entwurf_inbox_read`). Receipt (V on both sides, `openai-codex/gpt-6.1-sol`): real Pi `20261006T223710-e51e21` opened pd `20261006T223720-ba0c08` through `entwurf_fresh_call`; pd's first action called back into Pi with the exact nonce; Pi's live turn → pd mailbox ENQUEUE `2026-10-06T13-37-35-446Z-b57c69.msg`, that message's doorbell submission `done` on pd's root conversation, drained by pd's live turn (`entwurf_inbox_read` of its own id, settled); pd's live turn → Pi `entwurf_v2` settled `control-socket → sent` (native tool-result, joined by call id) and landed as exactly one Pi row with the expected payload and pd as the anchored sender. Native offering (root `pi.system`, toolsAdded/toolsRemoved applied): the six contact tools + bash/read/edit/write/subagent; pd's first root tool call is the callback. Actual model from root `pi.assistant` rows; the generation checkpoint does not retain `request.model` after completion. |
|
|
119
120
|
| **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. |
|
|
120
121
|
| **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. |
|
|
121
122
|
|
package/README.md
CHANGED
|
@@ -27,6 +27,15 @@ Claude and Cortex Code are ACP backends. Codex and Antigravity stay native so th
|
|
|
27
27
|
retain their own tools and work context. Capabilities differ by rail: a shipped
|
|
28
28
|
citizen is not a promise of every lifecycle operation.
|
|
29
29
|
|
|
30
|
+
**Native durable contact (`pi-durable`) is accepted in the 0.31.0 candidate (#129).**
|
|
31
|
+
It is a separate native harness contact, not ordinary Pi's control-socket adapter.
|
|
32
|
+
The contact attaches one durable host to a garden id, adds visible identity and
|
|
33
|
+
two-way mailbox contact, while the upstream harness keeps its TUI, models/auth,
|
|
34
|
+
SQLite storage and recovery. First native admission passed on one Linux host;
|
|
35
|
+
release/artifact acceptance is separate. The
|
|
36
|
+
[installation requirements](#optional-native-durable--0310) differ from installing
|
|
37
|
+
the ordinary Pi CLI.
|
|
38
|
+
|
|
30
39
|
## Install
|
|
31
40
|
|
|
32
41
|
**Choose by where you work. Neither route installs a harness, subscription or login.**
|
|
@@ -35,7 +44,7 @@ citizen is not a promise of every lifecycle operation.
|
|
|
35
44
|
|
|
36
45
|
Prerequisites: **Node >=24.0.0**, Python 3 for `setup`, and any harnesses you choose
|
|
37
46
|
to use, already installed and authenticated. Pi is optional-by-presence, supported
|
|
38
|
-
range `>=1.0.
|
|
47
|
+
range `>=1.0.2 <1.1`; Claude Code supported floor `>=2.1.217` is required for its
|
|
39
48
|
managed exec-hook lifecycle. pnpm is needed only for source-checkout setup.
|
|
40
49
|
|
|
41
50
|
```bash
|
|
@@ -63,6 +72,34 @@ Detected harness wiring on Darwin can therefore be written while setup stays
|
|
|
63
72
|
non-green. Native Windows is **UNSUPPORTED**. The package has no npm `os`
|
|
64
73
|
restriction; that is not certification of every platform's harness rails.
|
|
65
74
|
|
|
75
|
+
### Optional native durable — 0.31.0
|
|
76
|
+
|
|
77
|
+
**Entwurf's npm installation does not change. Enabling durable additionally needs
|
|
78
|
+
an operator-provided native runtime; installing ordinary Pi from npm is not enough.**
|
|
79
|
+
|
|
80
|
+
| Component | How it is supplied | What it does not supply |
|
|
81
|
+
|---|---|---|
|
|
82
|
+
| Entwurf | Existing npm or source-checkout route above | A harness binary, source runtime, subscription or login |
|
|
83
|
+
| `@earendil-works/pi-durable` | npm **library** | The experimental app/TUI or Entwurf citizen attachment |
|
|
84
|
+
| Native experimental durable app | Pinned upstream **source checkout**, with Entwurf's narrow runtime-contact overlay | A replacement ordinary Pi CLI or an Entwurf-owned harness |
|
|
85
|
+
|
|
86
|
+
This lane retains Pi 1.0.2/source `cd32f77`; a newer global Pi installation does
|
|
87
|
+
not provision that experimental runtime. Existing non-durable users do not need
|
|
88
|
+
a Pi source checkout. Native auth and sessions stay upstream-owned: Entwurf does
|
|
89
|
+
not copy credentials or convert ordinary Pi sessions into durable SQLite sessions.
|
|
90
|
+
|
|
91
|
+
The package ships the compiled adapter and bootstrap: `entwurf setup` reports the
|
|
92
|
+
operator runtime as PASS/SKIP/FAIL without writing durable wiring, and
|
|
93
|
+
`entwurf pi-durable` is the managed launch. First native admission passed on
|
|
94
|
+
2026-10-06: visible fresh/callback, addressed receive and real Pi ↔ pi-durable
|
|
95
|
+
LIVE36 on one Linux host ([receipts](./DELIVERY.md)). Installed-bootstrap import
|
|
96
|
+
proof does not supply or certify the native runtime; npm installation alone is
|
|
97
|
+
not a durable readiness verdict. #129 closed at reviewed main; release acceptance
|
|
98
|
+
remains its own floor.
|
|
99
|
+
See [setup: native durable](./docs/setup-clean-host.md#2b-optional-native-durable-pi-durable)
|
|
100
|
+
and [#130](https://github.com/junghan0611/entwurf/issues/130) for runtime-supply,
|
|
101
|
+
Pi-upgrade, ACP and UI follow-ups.
|
|
102
|
+
|
|
66
103
|
### Herdr workbench
|
|
67
104
|
|
|
68
105
|
```bash
|
|
@@ -182,14 +219,17 @@ and [Herdr launch](https://github.com/junghan0611/entwurf/blob/main/docs/herdr-l
|
|
|
182
219
|
Instead of keeping native pi copies of the verbs, the adapter registers the same
|
|
183
220
|
compiled bridge after record birth, under the citizen's identity, and Pi supervises
|
|
184
221
|
that MCP child. **MCP is ingress; pi receive remains the record-addressed Unix
|
|
185
|
-
control socket.** Garden identity and dispatch stay Entwurf's.
|
|
186
|
-
|
|
187
|
-
|
|
222
|
+
control socket.** Garden identity and dispatch stay Entwurf's. That 0.30.0 cut
|
|
223
|
+
did not adopt or certify `pi-durable` or codemode. Native durable support is now
|
|
224
|
+
accepted as a separate 0.31.0 candidate contact, as described above; codemode remains a
|
|
225
|
+
harness-internal capability, not another garden citizen. The 0.30.0 follow-up
|
|
226
|
+
separately measured Herdr supply 0.9.3 and
|
|
188
227
|
re-pinned the plugin runtime to published npm 0.30.0 with manifest 0.30.0; its
|
|
189
228
|
public consumer and CI receipts live in the #126 thread. That dated alignment is
|
|
190
|
-
not a permanent version-equality rule.
|
|
191
|
-
`herdr-checkout` verification carrier
|
|
192
|
-
|
|
229
|
+
not a permanent version-equality rule. 0.30.1 is published (npm, 2026-10-04); at its tag the
|
|
230
|
+
plugin's runtime lock is still the closed `herdr-checkout` verification carrier. Publication did
|
|
231
|
+
not re-pin it: the measured npm re-pin and its source-specific proof are separate, still-open
|
|
232
|
+
work that the [plugin source contract](./plugins/herdr/README.md) owns.
|
|
193
233
|
|
|
194
234
|
Entwurf is the 0.12+ successor to
|
|
195
235
|
[`@junghanacs/pi-shell-acp`](https://www.npmjs.com/package/@junghanacs/pi-shell-acp):
|
package/VERIFY.md
CHANGED
|
@@ -200,6 +200,22 @@ that moved out of `scripts/` and into a file beside its subject would otherwise
|
|
|
200
200
|
|
|
201
201
|
Do not collapse source, package, fixture, and native-host evidence into one “green.”
|
|
202
202
|
|
|
203
|
+
**Native durable contact (#129).** `check-pi-durable-beside` is the deterministic
|
|
204
|
+
beside-test/mutant coordinate in `check:contracts`. The separate
|
|
205
|
+
`check-pi-durable-contact`, `check-pi-durable-send` and `check-pi-durable-receive`
|
|
206
|
+
are CHECKOUT-ONLY SDK/contact gates: they require the provisioned pinned overlay
|
|
207
|
+
runtime (`ENTWURF_PI_DURABLE_RUNTIME`) and a private compiled bridge emitted from
|
|
208
|
+
this candidate (`ENTWURF_PI_DURABLE_BRIDGE_ENTRY`). Missing inputs report SKIP 97,
|
|
209
|
+
never PASS; present invalid inputs fail. Installed packages refuse these developer
|
|
210
|
+
gates. Contact is adapter-direct/harness-bypassed; send/receive exercise scripted
|
|
211
|
+
loopback S plus actual native harness H, not vendor V. Their scoped raw records,
|
|
212
|
+
wire, native view and SQLite oracles do not certify every queue/crash window.
|
|
213
|
+
The installed-bootstrap import in `check-pack-install` proves package closure,
|
|
214
|
+
not runtime supply or native admission. First-release visible fresh/callback and
|
|
215
|
+
native caller/target/cross-harness LIVE are owed by `smoke-pi-durable-fresh-live`, a
|
|
216
|
+
release-gate MUST (LIVE=1; vendor V on a real Pi and a real pi-durable host, operator
|
|
217
|
+
runtime required); SDK or package green does not waive it.
|
|
218
|
+
|
|
203
219
|
| Axis | Required proof | Limit |
|
|
204
220
|
|---|---|---|
|
|
205
221
|
| Source | `pnpm run check:full` + `./run.sh check-gate-qualification` | Does not prove an installed consumer. |
|
|
@@ -290,7 +306,7 @@ The goal is not merely "invoke Claude Code." We want:
|
|
|
290
306
|
**One install command to remember: `./run.sh setup <project>`.** It is idempotent — re-run the exact same command whenever anything looks wrong. There is no second install surface to juggle: from a clone `setup` runs the whole floor in order.
|
|
291
307
|
|
|
292
308
|
1. `pnpm install` — installs the pinned development dependencies and builds the bridge (source-checkout bootstrap only; an installed package never runs npm/pnpm inside `node_modules`)
|
|
293
|
-
2. pi wiring → `<project>/.pi/settings.json` + user-scope registration — only when a `pi` inside the supported range (`>=1.0.
|
|
309
|
+
2. pi wiring → `<project>/.pi/settings.json` + user-scope registration — only when a `pi` inside the supported range (`>=1.0.2 <1.1`) is on PATH; absent pi is an explicit zero-state SKIP, a below-floor pi is a detected FAIL. The user-scope entry is owner-recorded (#86 C2): another root's live-or-missing ownership makes this step a zero-write refusal (setup: pi FAIL) that names `takeover-user-scope`; the install-states bind the exact managed settings path (a drifted/symlinked/corrupt target is a zero-write refusal) and the inverse removes only the recorded owner's exact entry; `doctor-pi-package` reports the verdict
|
|
294
310
|
3. Claude meta-bridge global plugin — only when `claude` is on PATH; otherwise skipped cleanly
|
|
295
311
|
4. source stable-bin exposure — including certified `entwurf` → this checkout's `run.sh`, the managed runtime Copilot fresh resolves; helper units are attempted independently and a foreign helper is a named FAIL
|
|
296
312
|
5. agy bridge + exact permission + statusline + `PreInvocation` hook — only when `agy` is on PATH; each adapter is idempotent and independently doctorable
|
package/demo/README.md
CHANGED
|
@@ -142,7 +142,7 @@ SCENE_DELAY=30 FINAL_PAUSE=10 bash demo.sh
|
|
|
142
142
|
|
|
143
143
|
## Prerequisites
|
|
144
144
|
|
|
145
|
-
- `pi` on PATH (current floor 1.0.
|
|
145
|
+
- `pi` on PATH (current floor 1.0.2)
|
|
146
146
|
- `entwurf` provider configured + auth ready for the selected sender/peer models
|
|
147
147
|
- `asciinema` installed
|
|
148
148
|
- `agg` installed (optional — only for GIF conversion)
|
package/docs/acp-backend-rail.md
CHANGED
|
@@ -134,7 +134,7 @@ ledger, 2026-10-03).
|
|
|
134
134
|
| Surface | Declaration | Class | What a green actually says |
|
|
135
135
|
|---|---|---|---|
|
|
136
136
|
| Entwurf package | `package.json` `version` | checkout declaration, not a release receipt | names the package label these rows sit beside; whether that label shipped, and with which rows, is CHANGELOG's record |
|
|
137
|
-
| pi runtime | devDep exact `1.0.
|
|
137
|
+
| pi runtime | devDep exact `1.0.2`, peer `>=1.0.2 <1.1` | **exact** oracle + **closed range** | the source pin this checkout builds and gates against; hosts inside the range are accepted, and the ceiling moves only on measurement. Unshipped candidate floor: the published 0.30.0 and 0.30.1 declare floor 1.0.0 with the same next-minor ceiling (`[측정 2026-10-05]` `npm view @junghanacs/entwurf@0.30.1 peerDependencies`; acceptance record CHANGELOG 0.30.0, #125 branch evidence). The 1.0.2 move and its receipts are ROADMAP's 2026-10-05 bump entry |
|
|
138
138
|
| ACP wire SDK | `@agentclientprotocol/sdk 1.6.0` | **exact** | the shared wire oracle both adapters speak |
|
|
139
139
|
| Claude ACP adapter | `@agentclientprotocol/claude-agent-acp 0.85.1` | **exact**, bundled | checkout candidate; resolved before any PATH fallback; declaration is not compatibility evidence |
|
|
140
140
|
| Claude Agent SDK | `0.3.286` (transitive) | **exact** oracle | the runtime risk surface behind the adapter |
|
package/docs/setup-clean-host.md
CHANGED
|
@@ -28,7 +28,8 @@ evidence split, and its three states must not collapse into "macOS is supported"
|
|
|
28
28
|
| npm/pnpm | npm is bundled with Node; pnpm is required for source setup | package or source installation |
|
|
29
29
|
| Python 3 | required by `setup`/`install` (project-path normalization + settings writers); `--help`/`check-bridge` stay Python-free | pi/Claude/agy/Copilot/Codex wiring writers |
|
|
30
30
|
| entwurf | global/project-local `@junghanacs/entwurf`, or a source checkout | operator command and garden capability |
|
|
31
|
-
| pi | optional-by-presence, `>=1.0.
|
|
31
|
+
| pi | optional-by-presence, `>=1.0.2 <1.1` — absent is an explicit setup SKIP, below-floor is a named FAIL | ACP provider, control sockets |
|
|
32
|
+
| Native durable (`pi-durable`) | optional-by-presence, operator-provided experimental source runtime at the fixed `…/entwurf/pi-durable/runtime`, pinned to `cd32f77` plus the narrow runtime-contact overlay; not supplied by ordinary Pi npm installation — absent is an explicit setup SKIP, present-but-not-the-pin a named FAIL | optional 0.31.0 candidate contact via `entwurf pi-durable`; first native Pi ↔ pi-durable admission/LIVE accepted on one Linux host, runtime provision and release acceptance separate (§2b) |
|
|
32
33
|
| Claude Code | optional, **`>=2.1.217`** — the exec-form hook floor | Claude ACP auth/runtime and mailbox-backed native citizen |
|
|
33
34
|
| 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 |
|
|
34
35
|
| 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) |
|
|
@@ -190,7 +191,7 @@ on Darwin; that is wiring, not a rail receipt. If `pi` is on PATH,
|
|
|
190
191
|
Install the exact release floor, then wire the project:
|
|
191
192
|
|
|
192
193
|
```bash
|
|
193
|
-
npm install -g @earendil-works/pi-coding-agent@1.0.
|
|
194
|
+
npm install -g @earendil-works/pi-coding-agent@1.0.2
|
|
194
195
|
pi --version
|
|
195
196
|
|
|
196
197
|
cd ~/entwurf-smoke
|
|
@@ -198,7 +199,7 @@ entwurf install .
|
|
|
198
199
|
pi -e "$(npm root -g)/@junghanacs/entwurf" --list-models entwurf
|
|
199
200
|
```
|
|
200
201
|
|
|
201
|
-
The supported range is `>=1.0.
|
|
202
|
+
The supported range is `>=1.0.2 <1.1`. It is a hard minimum: installing this
|
|
202
203
|
release onto a 0.83.x pi host upgrades the runtime rather than keeping the older
|
|
203
204
|
minor. A host using only the external MCP bridge can skip pi until it needs a
|
|
204
205
|
control socket; no delivery rail launches a pi process.
|
|
@@ -282,6 +283,105 @@ emacsclient -s "${PI_EMACS_AGENT_SOCKET:-server}" --eval '(...)'
|
|
|
282
283
|
|
|
283
284
|
</details>
|
|
284
285
|
|
|
286
|
+
## 2b. Optional native durable (`pi-durable`)
|
|
287
|
+
|
|
288
|
+
**0.31.0 installation contract; first native admission/LIVE accepted on one Linux host.**
|
|
289
|
+
The [DELIVERY matrix](../DELIVERY.md) records the 2026-10-06 LIVE36 candidate
|
|
290
|
+
acceptance; release/artifact and runtime-supply evidence remain separate.
|
|
291
|
+
Durable is a separate native harness contact, not an option automatically enabled
|
|
292
|
+
by `entwurf pi` or by registering ordinary Pi's adapter.
|
|
293
|
+
|
|
294
|
+
There are three different things to install or supply:
|
|
295
|
+
|
|
296
|
+
1. **Entwurf:** the existing global/project-local npm or source-checkout route in
|
|
297
|
+
§1 stays unchanged. It supplies Entwurf bytes, not the native harness.
|
|
298
|
+
2. **Durable library:** `@earendil-works/pi-durable` is npm-installable. A library
|
|
299
|
+
dependency does not install the experimental coding app/TUI or birth a citizen.
|
|
300
|
+
3. **Native app/runtime:** upstream's experimental durable app runs from a Pi
|
|
301
|
+
source checkout through its source resolver. The pinned 1.0.2 ordinary
|
|
302
|
+
`pi-coding-agent` package excludes experimental app output; upgrading the global
|
|
303
|
+
`pi` CLI does not supply it. Entwurf's maintained contact requires the exact
|
|
304
|
+
upstream commit `cd32f7725fdbddbaecdff5b1e68491563394e0ca` plus its narrow
|
|
305
|
+
runtime-contact overlay, operator-provided dependencies and pinned runtime data.
|
|
306
|
+
|
|
307
|
+
The upstream [library installation guide](https://github.com/earendil-works/pi/blob/cd32f7725fdbddbaecdff5b1e68491563394e0ca/packages/durable/README.md#installation)
|
|
308
|
+
and [experimental app guide](https://github.com/earendil-works/pi/blob/cd32f7725fdbddbaecdff5b1e68491563394e0ca/packages/coding-agent/src/experimental/durable/README.md)
|
|
309
|
+
describe different consumers. Running the bare upstream app does not attach
|
|
310
|
+
Entwurf's garden contact. Entwurf does not install a second harness distribution,
|
|
311
|
+
rebuild its controller/model/auth/storage system or proxy a subscription.
|
|
312
|
+
|
|
313
|
+
### What the operator supplies
|
|
314
|
+
|
|
315
|
+
The runtime lives at ONE fixed place, with no path override:
|
|
316
|
+
`$XDG_DATA_HOME/entwurf/pi-durable/runtime` (an absolute `XDG_DATA_HOME`; otherwise
|
|
317
|
+
`~/.local/share/entwurf/pi-durable/runtime`). It counts as the pin only when:
|
|
318
|
+
|
|
319
|
+
- HEAD is `cd32f7725fdbddbaecdff5b1e68491563394e0ca`, nothing is staged, `git diff`
|
|
320
|
+
equals the packaged overlay `pi/pi-durable/overlay/runtime-contacts.patch` byte for
|
|
321
|
+
byte, and no non-ignored file is untracked;
|
|
322
|
+
- the upstream source resolver
|
|
323
|
+
`packages/coding-agent/src/experimental/source-resolver.ts` is present;
|
|
324
|
+
- the git-ignored model data in `packages/ai/src/providers/data` matches the pinned
|
|
325
|
+
digest: the bytes `@earendil-works/pi-ai@1.0.2` ships in `dist/providers/data`,
|
|
326
|
+
**including its `.manifest.json` dotfile** (recorded in
|
|
327
|
+
`pi/pi-durable/overlay/upstream-pin.json`).
|
|
328
|
+
|
|
329
|
+
The operator supplies it by hand; Entwurf never downloads, installs, repairs,
|
|
330
|
+
moves or deletes the runtime. The sequence below was run on a Linux host
|
|
331
|
+
(2026-10-06); afterwards the runtime verifier `entwurf setup` consults returned
|
|
332
|
+
the pin (exit 0) and the checkout's native contact cells passed against it.
|
|
333
|
+
`ENTWURF_ROOT` is your Entwurf package root or checkout, which ships the patch:
|
|
334
|
+
|
|
335
|
+
```bash
|
|
336
|
+
case "${XDG_DATA_HOME:-}" in
|
|
337
|
+
/*) R="$XDG_DATA_HOME/entwurf/pi-durable/runtime" ;;
|
|
338
|
+
*) R="$HOME/.local/share/entwurf/pi-durable/runtime" ;;
|
|
339
|
+
esac
|
|
340
|
+
git clone --no-checkout https://github.com/earendil-works/pi.git "$R"
|
|
341
|
+
git -C "$R" checkout --detach cd32f7725fdbddbaecdff5b1e68491563394e0ca
|
|
342
|
+
git -C "$R" apply "$ENTWURF_ROOT/pi/pi-durable/overlay/runtime-contacts.patch" # worktree only; do not stage
|
|
343
|
+
(cd "$R" && npm ci --ignore-scripts) # upstream lockfile; dependency install scripts skipped
|
|
344
|
+
T=$(mktemp -d)
|
|
345
|
+
(cd "$T" && npm pack @earendil-works/pi-ai@1.0.2)
|
|
346
|
+
tar -xzf "$T/earendil-works-pi-ai-1.0.2.tgz" -C "$T" package/dist/providers/data
|
|
347
|
+
cp -a "$T/package/dist/providers/data/." "$R/packages/ai/src/providers/data/" # dotfiles too
|
|
348
|
+
entwurf setup # expect: pi-durable PASS
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
Why it is a source checkout and not `npm install`: `@earendil-works/pi-coding-agent`
|
|
352
|
+
(1.0.2 and 1.0.4 alike) excludes `dist/experimental` from its `files`, and its only
|
|
353
|
+
experimental export resolves to `src/`, which the tarball does not ship, so the
|
|
354
|
+
durable app's `experimental/durable/runtime.ts` and `tui.ts` exist only in a source
|
|
355
|
+
checkout. `@earendil-works/pi-durable` on npm is the library (no app, TUI or bin).
|
|
356
|
+
|
|
357
|
+
### What Entwurf does with it
|
|
358
|
+
|
|
359
|
+
- `entwurf setup` reports a `pi-durable` row from that check and writes no durable
|
|
360
|
+
wiring in any case: **PASS** when the runtime is the pin, **SKIP** when nothing is
|
|
361
|
+
at the fixed place, **FAIL** with the named refusal when something is there but is
|
|
362
|
+
not the pin.
|
|
363
|
+
- `entwurf pi-durable [args…]` is the managed launch. It verifies the same runtime
|
|
364
|
+
first (refusal exit 4 when absent, 3 otherwise), then runs the packaged bootstrap
|
|
365
|
+
`pi/pi-durable/bootstrap.mjs` under the runtime's source resolver, owning this
|
|
366
|
+
terminal. The bootstrap imports only the compiled closure shipped beside it
|
|
367
|
+
(`mcp/entwurf-bridge/dist/…`), so an installed package never imports checkout
|
|
368
|
+
TypeScript; a source checkout needs a built bridge (`pnpm run build-bridge`) first.
|
|
369
|
+
`plugins/pi-durable/bootstrap.mjs` is only the checkout path that re-exports it.
|
|
370
|
+
|
|
371
|
+
Existing users who do not enable durable keep the same installation steps. For
|
|
372
|
+
durable, native Pi owns credentials, model settings, SQLite sessions and recovery;
|
|
373
|
+
keep them in place rather than copying credentials or migrating ordinary Pi
|
|
374
|
+
transcripts. Native recovery does not prove exactly-once Entwurf dispatch or inbox
|
|
375
|
+
read recovery. The contact provides garden attachment, visible identity and
|
|
376
|
+
announce-only root-directed self-fetch. First native admission closed
|
|
377
|
+
[#129](https://github.com/junghan0611/entwurf/issues/129) at reviewed main:
|
|
378
|
+
visible fresh/callback, addressed receive and both real Pi ↔ pi-durable LIVE legs
|
|
379
|
+
passed on one Linux host. Installed-bootstrap import-only proof is not a native
|
|
380
|
+
runtime/TUI launch or a live Claude ↔ pi-durable receipt. This section states the
|
|
381
|
+
installation contract; exact release/artifact acceptance is a separate floor.
|
|
382
|
+
[#130](https://github.com/junghan0611/entwurf/issues/130) owns npm-only runtime
|
|
383
|
+
supply, later Pi versions, ACP and UI follow-ups.
|
|
384
|
+
|
|
285
385
|
## 3. Optional Claude Code native citizen
|
|
286
386
|
|
|
287
387
|
This rail is CERTIFIED on Linux; on macOS it is NOT CERTIFIED — pending physical
|
|
@@ -445,7 +545,7 @@ as a note rather than a fault.
|
|
|
445
545
|
|
|
446
546
|
**entwurf sets no OMP version floor in code, and will not grow one on schedule.** Detection is
|
|
447
547
|
presence-only (`command -v "${OMP_BIN:-omp}"`); there is no `entwurf.ompFloor`, no coherence
|
|
448
|
-
gate, and no exact pin — unlike Node (`engines.node`), pi (`>=1.0.
|
|
548
|
+
gate, and no exact pin — unlike Node (`engines.node`), pi (`>=1.0.2 <1.1`) and Claude Code
|
|
449
549
|
(`entwurf.claudeCodeFloor`), each of which has an enforcement point. That asymmetry is a
|
|
450
550
|
decision, not an omission. A floor is the answer to a vendor that fails SILENTLY — Claude Code
|
|
451
551
|
earned one because an older binary validates the exec manifest, drops `args` at runtime, and
|
|
@@ -630,8 +630,8 @@ server.tool("entwurf_register_native", "Register an ALREADY-RUNNING native conve
|
|
|
630
630
|
server.tool("entwurf_fresh_call", "Open ONE fresh visible sibling beside you and hand it a first task. WHERE it opens is decided by where THIS " +
|
|
631
631
|
"agent runs, never by a parameter: inside herdr (HERDR_ENV=1) it opens a NEW UNFOCUSED TAB in your own " +
|
|
632
632
|
"herdr workspace, pi and claude-code " +
|
|
633
|
-
"only; everywhere else it opens in the operator's tmux with all
|
|
634
|
-
"claude-code, copilot, omp, codex). No fallback: an incomplete herdr context is refused by name, " +
|
|
633
|
+
"only; everywhere else it opens in the operator's tmux with all six backends (pi, " +
|
|
634
|
+
"claude-code, copilot, omp, codex, pi-durable). No fallback: an incomplete herdr context is refused by name, " +
|
|
635
635
|
"never by a tmux window you cannot see from herdr. The sibling's FIRST action " +
|
|
636
636
|
"is a callback to you carrying a nonce, whose sender envelope is its garden id — that is how you learn the " +
|
|
637
637
|
"address of a thing that did not exist a moment ago. This returns a LAUNCH receipt (the owner's " +
|
|
@@ -639,8 +639,8 @@ server.tool("entwurf_fresh_call", "Open ONE fresh visible sibling beside you and
|
|
|
639
639
|
"the task was delivered. Those coordinates are a VIEW, never an address — a herdr tab/pane id can change under " +
|
|
640
640
|
"a running sibling. Nothing polls. " +
|
|
641
641
|
"For EXISTING citizens use entwurf_v2 — this tool only creates, and entwurf_peers only reports. Model is REQUIRED and passed to the chosen " +
|
|
642
|
-
"runtime CLI (`provider/model` for pi, an id/alias for Claude Code, a pattern for the rest). On tmux, copilot/omp/codex are refused BEFORE any window " +
|
|
643
|
-
"opens when their birth, MCP, receive or visible-identity units are absent, and codex also needs the " +
|
|
642
|
+
"runtime CLI (`provider/model` for pi, an id/alias for Claude Code, `provider/model id` exactly as the catalog names it for pi-durable, a pattern for the rest). On tmux, copilot/omp/codex/pi-durable are refused BEFORE any window " +
|
|
643
|
+
"opens when their birth, MCP, receive or visible-identity units are absent, pi-durable also when its operator-provided pinned runtime is absent or drifted, and codex also needs the " +
|
|
644
644
|
"operator-owned app-server socket entwurf never starts; in herdr they are refused by name first. " +
|
|
645
645
|
"Optional placement.tmuxSession is a TMUX-ONLY seat naming ONE EXISTING session and " +
|
|
646
646
|
"ALWAYS wins; omitted, the seat follows the CALLER, never the backend opened: a CODEX CALLER opens beside " +
|
|
@@ -648,8 +648,8 @@ server.tool("entwurf_fresh_call", "Open ONE fresh visible sibling beside you and
|
|
|
648
648
|
"NOTHING is created. In herdr the field is refused by name. Do not put secrets in the task — model and task argv are visible to same-user " +
|
|
649
649
|
"processes.", {
|
|
650
650
|
backend: z
|
|
651
|
-
.enum(["pi", "claude-code", "copilot", "omp", "codex"])
|
|
652
|
-
.describe("Which fixed runtime to open. Only these
|
|
651
|
+
.enum(["pi", "claude-code", "copilot", "omp", "codex", "pi-durable"])
|
|
652
|
+
.describe("Which fixed runtime to open. Only these six, and only pi/claude-code when this agent runs inside herdr; there is no arbitrary command."),
|
|
653
653
|
model: z
|
|
654
654
|
.string()
|
|
655
655
|
.min(1)
|
|
@@ -663,7 +663,7 @@ server.tool("entwurf_fresh_call", "Open ONE fresh visible sibling beside you and
|
|
|
663
663
|
// as an unused suppression while the escape goes back to being fixable.
|
|
664
664
|
// biome-ignore lint/complexity/noUselessEscapeInRegex: emitted to a Rust regex validator, see above
|
|
665
665
|
.regex(/^[A-Za-z0-9][A-Za-z0-9._/:\[\]-]*$/)
|
|
666
|
-
.describe("Required runtime model: canonical provider/model for pi, a Claude Code model id/alias, or a Copilot/OMP/Codex model name."),
|
|
666
|
+
.describe("Required runtime model: canonical provider/model for pi, provider/<exact catalog model id> for pi-durable, a Claude Code model id/alias, or a Copilot/OMP/Codex model name."),
|
|
667
667
|
task: z
|
|
668
668
|
.string()
|
|
669
669
|
.min(1)
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
"codex": { "wakeMode": "direct-inject", "deliveryLevel": "D6", "nativeIdLabel": "threadId" },
|
|
7
7
|
"copilot": { "wakeMode": "self-fetch", "deliveryLevel": "D6", "nativeIdLabel": "sessionId" },
|
|
8
8
|
"omp": { "wakeMode": "self-fetch", "deliveryLevel": "D6", "nativeIdLabel": "sessionId" },
|
|
9
|
+
"pi-durable": { "wakeMode": "self-fetch", "deliveryLevel": "D2", "nativeIdLabel": "sessionId" },
|
|
9
10
|
"pi": { "wakeMode": "direct-inject", "deliveryLevel": "D6", "nativeIdLabel": "sessionId" }
|
|
10
11
|
}
|
|
11
12
|
}
|
|
@@ -105,7 +105,13 @@ export function receiverMarkerMatchesIdentity(marker, identity) {
|
|
|
105
105
|
// previous garden in-process on its `/new` edge (the unarm the claude hook lacked),
|
|
106
106
|
// so the cell this join closes has a different owner there. Admitting it needs its
|
|
107
107
|
// own measurement, not this file's optimism.
|
|
108
|
-
|
|
108
|
+
//
|
|
109
|
+
// `pi-durable-host` is admitted because the join holds by construction: the durable contact
|
|
110
|
+
// writes its sender marker under the host's own pid and arms its watch in that same process
|
|
111
|
+
// (`meta-bridge-pi-durable.ts`), so the receiver marker's `ownerPid` IS the sender-marker key.
|
|
112
|
+
// Inside the scope a host whose sender marker is gone or names another garden is a retired
|
|
113
|
+
// watch, which is the refusal this admission exists to make reachable.
|
|
114
|
+
export const SENDER_JOINED_RECEIVER_OWNER_KINDS = ["claude-code-cli", "pi-durable-host"];
|
|
109
115
|
/** Does this watch owner share its pid with the backend's sender marker? */
|
|
110
116
|
export function receiverOwnerKindJoinsSender(ownerKind) {
|
|
111
117
|
return SENDER_JOINED_RECEIVER_OWNER_KINDS.includes(ownerKind);
|
|
@@ -23,11 +23,12 @@
|
|
|
23
23
|
*/
|
|
24
24
|
import { randomBytes } from "node:crypto";
|
|
25
25
|
/** The backends this rail can open. Fixed set, not a profile — a further one is a decision,
|
|
26
|
-
* not a config entry. `copilot` was added by #82 RAIL 9, `omp` by #87 Bundle C,
|
|
27
|
-
* by #95 after its system birth and app-server rails were measured
|
|
26
|
+
* not a config entry. `copilot` was added by #82 RAIL 9, `omp` by #87 Bundle C, `codex`
|
|
27
|
+
* by #95 after its system birth and app-server rails were measured, and `pi-durable` by #129
|
|
28
|
+
* (the operator-provided durable app through the managed `entwurf pi-durable`). The set is joined to the
|
|
28
29
|
* citizen backends by `check-harness-admission-parity`: a harness that mints records but is
|
|
29
30
|
* missing HERE is not an unwired convenience, it is a release blocker. */
|
|
30
|
-
export const FRESH_CALL_BACKENDS = ["pi", "claude-code", "copilot", "omp", "codex"];
|
|
31
|
+
export const FRESH_CALL_BACKENDS = ["pi", "claude-code", "copilot", "omp", "codex", "pi-durable"];
|
|
31
32
|
/**
|
|
32
33
|
* The callback tool NAME differs per backend and that is not cosmetic: every session reaches the
|
|
33
34
|
* capability under whatever name its harness composes for the `entwurf-bridge` MCP server, and
|
|
@@ -64,6 +65,11 @@ export const FRESH_CALL_CALLBACK_TOOL = {
|
|
|
64
65
|
// Codex's tool process is the operator app-server, not the pane: the no-arg
|
|
65
66
|
// verb refuses there by name. First action stays the delivery verb with args.
|
|
66
67
|
codex: "mcp__entwurf_bridge__entwurf_v2",
|
|
68
|
+
// The durable contact registers the bridge verbs as its OWN tools under their bare names, and the
|
|
69
|
+
// app offers a tool to the model by its registered name (`durable/harness/registry.ts:99`
|
|
70
|
+
// @cd32f77). Measured for `entwurf_v2` on the S+native-H wire (receipt 4012c066); the callback
|
|
71
|
+
// spelling follows the same rule and is owed its first LIVE observation.
|
|
72
|
+
"pi-durable": "entwurf_callback",
|
|
67
73
|
};
|
|
68
74
|
/** Where a sibling SENDS the task result. Always the delivery verb, never the birth callback. */
|
|
69
75
|
export const FRESH_CALL_DELIVERY_TOOL = {
|
|
@@ -72,6 +78,7 @@ export const FRESH_CALL_DELIVERY_TOOL = {
|
|
|
72
78
|
copilot: "entwurf-bridge-entwurf_v2",
|
|
73
79
|
omp: "mcp__entwurf_bridge_entwurf_v",
|
|
74
80
|
codex: "mcp__entwurf_bridge__entwurf_v2",
|
|
81
|
+
"pi-durable": "entwurf_v2",
|
|
75
82
|
};
|
|
76
83
|
/**
|
|
77
84
|
* The same dialects, for the tool the framing OFFERS rather than requires.
|
|
@@ -93,6 +100,7 @@ export const FRESH_CALL_PEERS_TOOL = {
|
|
|
93
100
|
copilot: "entwurf-bridge-entwurf_peers",
|
|
94
101
|
omp: "mcp__entwurf_bridge_entwurf_peers",
|
|
95
102
|
codex: "mcp__entwurf_bridge__entwurf_peers",
|
|
103
|
+
"pi-durable": "entwurf_peers",
|
|
96
104
|
};
|
|
97
105
|
/**
|
|
98
106
|
* ONE BACKEND NEEDS TO BE TOLD HOW TO REACH ITS OWN CALLBACK TOOL `[측정 2026-09-18, n=5 + n=3]`.
|
|
@@ -132,6 +140,7 @@ export const FRESH_CALL_TOOL_LOAD_HINT = {
|
|
|
132
140
|
copilot: [],
|
|
133
141
|
omp: [],
|
|
134
142
|
codex: [],
|
|
143
|
+
"pi-durable": [],
|
|
135
144
|
};
|
|
136
145
|
/**
|
|
137
146
|
* The omp bootstrap flag, spelled WITHOUT dashes — the vendor's flag map is keyed by bare
|
|
@@ -311,6 +320,28 @@ export function composeBackendArgs(backend, composition, model, resolveCodexSock
|
|
|
311
320
|
"--dangerously-bypass-approvals-and-sandbox",
|
|
312
321
|
composition.prompt,
|
|
313
322
|
];
|
|
323
|
+
case "pi-durable": {
|
|
324
|
+
// The managed verb (`entwurf pi-durable`) carries the explicit model as pi's own
|
|
325
|
+
// `--provider`/`--model` pair, split at the FIRST `/` (the preflight already refused a model
|
|
326
|
+
// with no provider), the explicit width, and the WHOLE framing as the closed `{v,task}`
|
|
327
|
+
// payload — the durable bootstrap submits it to the root once, after the birth. The
|
|
328
|
+
// caller's address rides the env pair, never this payload.
|
|
329
|
+
const at = model.indexOf("/");
|
|
330
|
+
if (at <= 0 || at === model.length - 1) {
|
|
331
|
+
throw new Error(`fresh-call composition: pi-durable model ${JSON.stringify(model)} is not <provider>/<model id>`);
|
|
332
|
+
}
|
|
333
|
+
return [
|
|
334
|
+
"pi-durable",
|
|
335
|
+
"--provider",
|
|
336
|
+
model.slice(0, at),
|
|
337
|
+
"--model",
|
|
338
|
+
model.slice(at + 1),
|
|
339
|
+
"--width",
|
|
340
|
+
"task-wide",
|
|
341
|
+
`--${OMP_BOOTSTRAP_FLAG}`,
|
|
342
|
+
JSON.stringify({ v: OMP_BOOTSTRAP_VERSION, task: composition.prompt }),
|
|
343
|
+
];
|
|
344
|
+
}
|
|
314
345
|
}
|
|
315
346
|
}
|
|
316
347
|
/**
|
|
@@ -57,7 +57,13 @@ import { resolveNativePushAdapter } from "./native-push/adapter.js";
|
|
|
57
57
|
* exactly the #46 defect on agy, and copilot joined the list only once its own hook wrote one
|
|
58
58
|
* (#82 RAIL 5b). Membership says a marker may EXIST, never that a reply can land: the reply
|
|
59
59
|
* rail is chosen from `nativePushSupported` at the bridge, not from this list. */
|
|
60
|
-
export const META_SENDER_BACKENDS = [
|
|
60
|
+
export const META_SENDER_BACKENDS = [
|
|
61
|
+
"claude-code",
|
|
62
|
+
"antigravity",
|
|
63
|
+
"copilot",
|
|
64
|
+
"omp",
|
|
65
|
+
"pi-durable",
|
|
66
|
+
];
|
|
61
67
|
/**
|
|
62
68
|
* Two live native sessions claim this MCP process as their own. We can SEE both identities but
|
|
63
69
|
* cannot say which one is calling, so we send under neither. Choosing by lookup order, backend
|