@junghanacs/entwurf 0.13.1 → 0.14.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 +48 -15
- package/BASELINE.md +3 -3
- package/CHANGELOG.md +45 -0
- package/CONTRIBUTING.md +13 -9
- package/DELIVERY.md +7 -6
- package/README.md +27 -27
- package/VERIFY.md +22 -14
- package/demo/README.md +1 -1
- package/demo/demo-baseline.sh +1 -3
- package/demo/demo.sh +2 -5
- package/docs/acp-backend-rail.md +9 -4
- package/docs/external-mcp-host.md +4 -5
- package/docs/setup-clean-host.md +8 -7
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +148 -28
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +8 -6
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-control-rpc.js +7 -5
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-core.js +13 -14
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-resume-args.js +45 -40
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +117 -95
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +23 -57
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-lock.js +16 -7
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +5 -53
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-release.js +21 -36
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-runner.js +3 -15
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send-fallback.js +12 -11
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send.js +2 -7
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +30 -67
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-visible-resume.js +256 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +91 -5
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +258 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-launch.js +202 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-placement.js +289 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-resume-call.js +170 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/resume-launch-identity.js +136 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/session-id.js +8 -5
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/socket-discovery.js +3 -3
- package/mcp/entwurf-bridge/dist/scripts/meta-facts.js +51 -0
- package/mcp/entwurf-bridge/dist/scripts/new-session-id.js +9 -4
- package/mcp/entwurf-bridge/src/index.ts +164 -28
- package/mcp/entwurf-bridge/start.sh +2 -2
- package/mcp/entwurf-bridge/test.sh +23 -9
- package/mcp/entwurf-bridge/tsconfig.build.json +11 -2
- package/package.json +22 -11
- package/pi-extensions/entwurf-control.ts +218 -40
- package/pi-extensions/lib/acp/backend.ts +71 -12
- package/pi-extensions/lib/acp/overlay.ts +8 -6
- package/pi-extensions/lib/entwurf-control-rpc.ts +7 -5
- package/pi-extensions/lib/entwurf-core.ts +15 -15
- package/pi-extensions/lib/entwurf-resume-args.ts +41 -52
- package/pi-extensions/lib/entwurf-v2-contract-schema.ts +1 -1
- package/pi-extensions/lib/entwurf-v2-contract.ts +120 -99
- package/pi-extensions/lib/entwurf-v2-decider.ts +30 -91
- package/pi-extensions/lib/entwurf-v2-lock.ts +16 -7
- package/pi-extensions/lib/entwurf-v2-production.ts +4 -78
- package/pi-extensions/lib/entwurf-v2-release.ts +25 -49
- package/pi-extensions/lib/entwurf-v2-runner.ts +6 -21
- package/pi-extensions/lib/entwurf-v2-send-fallback.ts +12 -11
- package/pi-extensions/lib/entwurf-v2-send.ts +2 -7
- package/pi-extensions/lib/entwurf-v2-surface.ts +36 -76
- package/pi-extensions/lib/entwurf-v2-visible-resume.ts +370 -0
- package/pi-extensions/lib/meta-session.ts +93 -5
- package/pi-extensions/lib/mux-fresh-call.ts +328 -0
- package/pi-extensions/lib/mux-launch.ts +267 -0
- package/pi-extensions/lib/mux-placement.ts +387 -0
- package/pi-extensions/lib/mux-resume-call.ts +221 -0
- package/pi-extensions/lib/resume-launch-identity.ts +162 -0
- package/pi-extensions/lib/session-id.js +8 -5
- package/pi-extensions/lib/socket-discovery.ts +3 -3
- package/run.sh +471 -201
- package/scripts/agy-bridge-config.py +5 -1
- package/scripts/check-acp-backend-preflight.ts +1 -1
- package/scripts/check-acp-overlay.ts +13 -3
- package/scripts/check-acp-stream-hooks.ts +504 -0
- package/scripts/check-elapsed.sh +25 -0
- package/scripts/check-entwurf-bridge-boot.ts +51 -4
- package/scripts/check-entwurf-bridge-pi-free.ts +6 -5
- package/scripts/check-entwurf-control-rpc.ts +4 -3
- package/scripts/check-entwurf-resume-args.ts +72 -70
- package/scripts/check-entwurf-session-identity.ts +14 -10
- package/scripts/check-entwurf-v2-contract.ts +34 -59
- package/scripts/check-entwurf-v2-decider.ts +17 -177
- package/scripts/check-entwurf-v2-lock.ts +5 -2
- package/scripts/check-entwurf-v2-matrix.ts +3 -53
- package/scripts/check-entwurf-v2-production.ts +2 -91
- package/scripts/check-entwurf-v2-release.ts +10 -105
- package/scripts/check-entwurf-v2-runner.ts +4 -85
- package/scripts/check-entwurf-v2-send-fallback.ts +5 -6
- package/scripts/check-entwurf-v2-send.ts +0 -28
- package/scripts/check-entwurf-v2-surface.ts +157 -128
- package/scripts/check-entwurf-v2-visible-resume.ts +445 -0
- package/scripts/check-fresh-cut-gate.sh +1 -1
- package/scripts/check-gate-qualification.ts +98 -7
- package/scripts/check-install-container.sh +10 -2
- package/scripts/check-install-surface.ts +1 -1
- package/scripts/check-keyset-overlap.py +1 -1
- package/scripts/check-meta-facts.ts +249 -0
- package/scripts/check-meta-identity-consumers.ts +1 -1
- package/scripts/check-meta-session.ts +169 -0
- package/scripts/check-mux-launch-tmux.ts +316 -0
- package/scripts/check-mux-launch.ts +288 -0
- package/scripts/check-mux-launcher-fence.ts +264 -0
- package/scripts/check-mux-parent-artifact.ts +195 -0
- package/scripts/check-mux-placement-tmux.ts +322 -0
- package/scripts/check-mux-placement.ts +323 -0
- package/scripts/check-mux-resume-call.ts +282 -0
- package/scripts/check-probe-cli-shim.ts +25 -22
- package/scripts/check-probe-ordering.ts +84 -76
- package/scripts/check-release-gate-outcomes.ts +127 -7
- package/scripts/check-resume-launch-identity.ts +244 -0
- package/scripts/check-socket-discovery.ts +1 -1
- package/scripts/fixtures/mux-parent-transcript.scrubbed.jsonl +3 -0
- package/scripts/inventory-verification-surface.ts +349 -0
- package/scripts/lib/claude-launcher-fence.ts +322 -0
- package/scripts/lib/mutation-qualify.ts +109 -3
- package/scripts/meta-bridge-doctor.sh +6 -8
- package/scripts/meta-facts.ts +60 -0
- package/scripts/mutants/acp-overlay.json +17 -0
- package/scripts/mutants/acp-stream-hooks.json +158 -0
- package/scripts/mutants/bridge-boot-resume.json +45 -0
- package/scripts/mutants/meta-facts.json +50 -0
- package/scripts/mutants/meta-identity.json +36 -0
- package/scripts/mutants/mux-boundary.json +196 -0
- package/scripts/mutants/mux-fresh-call.json +185 -0
- package/scripts/mutants/mux-launcher-fence.json +123 -0
- package/scripts/mutants/mux-parent-artifact.json +39 -0
- package/scripts/mutants/mux-resume-call.json +148 -0
- package/scripts/mutants/probe-ordering.json +0 -1037
- package/scripts/mutants/release-gate.json +35 -0
- package/scripts/mutants/resume-args.json +76 -0
- package/scripts/mutants/resume-launch-identity.json +96 -0
- package/scripts/mutants/v2-surface.json +58 -18
- package/scripts/mutants/v2-visible-resume.json +215 -0
- package/scripts/new-session-id.ts +9 -4
- package/scripts/smoke-acp-raw-turn-live.ts +1 -1
- package/scripts/smoke-agy-native-push-live.ts +6 -17
- package/scripts/smoke-entwurf-v2-matrix-live.ts +1 -1
- package/scripts/smoke-meta-honesty.sh +1 -1
- package/scripts/smoke-mux-fresh-call-live.ts +365 -0
- package/scripts/smoke-mux-lifecycle-live.ts +1136 -0
- package/scripts/smoke-pi-attach.ts +1 -1
- package/scripts/smoke-user-scope-citizen.sh +1 -1
- package/scripts/tsconfig.json +1 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-preflight.js +0 -160
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn-production.js +0 -273
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn.js +0 -216
- package/pi-extensions/lib/entwurf-v2-spawn-production.ts +0 -373
- package/pi-extensions/lib/entwurf-v2-spawn.ts +0 -323
- package/scripts/check-acp-sdk-surface.ts +0 -275
- package/scripts/check-entwurf-v2-spawn-production.ts +0 -551
- package/scripts/check-entwurf-v2-spawn.ts +0 -399
- package/scripts/smoke-entwurf-v2-spawn-live.ts +0 -188
- package/scripts/smoke-entwurf-v2-spawn-resume-live.ts +0 -467
package/AGENTS.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
For agents that own this repo: invariant principles and reproducible verification, not release-story archaeology.
|
|
4
4
|
|
|
5
|
-
> **Direction.** This repo is the **entwurf capability package**: a v2 garden-citizen dispatch substrate, native-harness bridges, an ACP plugin, and the pi adapter that hosts that plugin today. `entwurf` is the subject; pi is one harness adapter. ACP is a plugin, not the boundary (#38). V1 verbs are gone. V2 addresses existing citizens; fresh sibling creation
|
|
5
|
+
> **Direction.** This repo is the **entwurf capability package**: a v2 garden-citizen dispatch substrate, native-harness bridges, an ACP plugin, and the pi adapter that hosts that plugin today. `entwurf` is the subject; pi is one harness adapter. ACP is a plugin, not the boundary (#38). V1 verbs are gone. V2 addresses existing citizens; fresh sibling creation is the separate `entwurf_fresh_call` capability. Current work and ordering live in [NEXT.md](./NEXT.md).
|
|
6
6
|
|
|
7
7
|
## North Star — One Forged Screwdriver
|
|
8
8
|
|
|
@@ -26,11 +26,12 @@ For agents that own this repo: invariant principles and reproducible verificatio
|
|
|
26
26
|
## Architecture
|
|
27
27
|
|
|
28
28
|
- **entwurf-core (v2)** owns garden-id addressing, peer facts, liveness interfaces, dispatch decisions, rail choice, and delivery evidence.
|
|
29
|
-
- **Record authority** owns citizen identity. Every addressable
|
|
29
|
+
- **Record authority** owns citizen identity. Every addressable citizen uses the same V3 `MetaIdentity` schema. `backend` selects capability/rail behavior; it does not create an identity hierarchy.
|
|
30
30
|
- **pi adapter** attaches a pi session to a record at `session_start`, hosts the record-keyed control socket, and exposes the native pi tool surface.
|
|
31
|
-
- **Native bridges** register already-running native sessions without taking over their transcript or auth: Claude Code is mailbox/self-fetch; Antigravity is probe-backed native-push
|
|
31
|
+
- **Native bridges** register already-running native sessions without taking over their transcript or auth: Claude Code is mailbox/self-fetch; Antigravity is probe-backed native-push. Codex has archived probe evidence, but its managed native lane was declined because pi already supplies the official GPT provider path; do not duplicate it as a native citizen or ACP backend.
|
|
32
32
|
- **ACP plugin** registers provider `entwurf` inside a pi host session and drives a backend under an isolated overlay. The host pi session is already a record-backed socket citizen; the plugin does not mint another citizen/socket/peer layer.
|
|
33
|
-
- **
|
|
33
|
+
- **mux is launch-only and deliberately small.** Shipped: the tmux placement leaf (`mux-placement.ts` — inspect/append/close inside the caller's own session), the visible runtime launch composition (`mux-launch.ts`), the fresh-call composition (`mux-fresh-call.ts`), and the cwd-aware resume placement composition (`mux-resume-call.ts`). Fresh call is exposed as `entwurf_fresh_call`; visible same-id resume is `entwurf_resume_call`, composed at the two public surfaces by injecting `mux-resume-call` into the v2-side `entwurf-v2-visible-resume.ts`. The exact import graph is enumerated in [docs/mux-launch-rail.md](./docs/mux-launch-rail.md) §11. `entwurf_v2` behavior is unchanged and delivery still never imports launch. Fresh call learns a new sibling's garden id from the CALLBACK it makes, never from a lookup — so the pre-injected-token → identity-lookup design (rail §6) is **closed, not paused**. Do not reopen it without new evidence and explicit GLG re-approval. Fresh-call requires one explicit model and passes it in each runtime's measured CLI dialect (Pi `--model <provider/model>`, Claude Code `--model=<id-or-alias>`); resume takes only an existing target id and gets transcript/model/provider/cwd from its record. Do not grow either narrow carrier into a generic driver, harness profile, arbitrary command/cwd/env selection, or a second creation API. Ownership and import prohibitions: [docs/mux-launch-rail.md](./docs/mux-launch-rail.md) §11.
|
|
34
|
+
- **One delivery verb:** `entwurf_v2` addresses an existing garden id. Current routes are live control-socket send, active self-fetch mailbox enqueue, and probe-alive native-push. NO route starts a process: the hidden background resume for a dormant citizen was withdrawn under the visible-first rule, so a dormant in-domain citizen rejects as `dormant-fire-forget-unsupported` and the intent axis is single-valued. Every other complementary state pair rejects honestly too. Fresh creation is a separate verb — `entwurf_fresh_call` — and it returns a launch receipt only; the new sibling's address arrives asynchronously as the sender envelope of its nonce callback.
|
|
34
35
|
|
|
35
36
|
## Hard Rules
|
|
36
37
|
|
|
@@ -49,6 +50,7 @@ For agents that own this repo: invariant principles and reproducible verificatio
|
|
|
49
50
|
13. **Doctors report runtime truth and ownership truth separately.** Runtime coverage does not prove entwurf owns the configuration; broken ownership does not erase visibly working runtime configuration. Final verdict remains red when either required axis fails.
|
|
50
51
|
14. **Native hook ownership is structural.** Claude hooks use the shipped exec-form launcher and provenance token; marker writers/readers share `isPlausibleOwnerPid`; no shell-form fallback, ancestry guess, or retired pid carrier. entwurf requires Claude Code `>=2.1.217` and enforces that floor itself because upstream gives no fail-loud — an older Claude validates the exec manifest, then drops `args` at runtime and reports success. The number is derived from `package.json` `entwurf.claudeCodeFloor`, never retyped as a second source. Currently certified axis is Linux desktop/workstation. Source/gates: `hook-launch.sh`, `meta-session.ts`, `check-hook-launch-topology`, `check-claude-floor-coherence`, `check-meta-doctor-oracle`.
|
|
51
52
|
15. **Crash, don't warn.** Bad config/path/model/store state throws. Empty catches are only for bounded environment probing; operator diagnostics go to stderr.
|
|
53
|
+
16. **mux is launch, never delivery.** A tmux window/pane handle is an ephemeral operator view, not an address: it mints no garden id, stores no record, and reports no liveness. Screen text and keystrokes are never an `entwurf_v2` receipt. Mux owns only placement and fixed-runtime launch; fresh identity correlation stays in callback envelopes, while same-id resume identity/liveness/locking stays on the v2 side of an injected launch seam.
|
|
52
54
|
|
|
53
55
|
Detailed incident histories belong in CHANGELOG/issues/BASELINE and source-adjacent comments, not in this prompt. When a concise rule and old archaeology disagree, verify source + gate and repair the stale prose.
|
|
54
56
|
|
|
@@ -81,14 +83,14 @@ A `--entwurf-control` pi session is a citizen for the same reason a native bridg
|
|
|
81
83
|
- `PI_SESSION_ID` and `PI_AGENT_ID` propagate the record-established identity to child MCP processes. They are carriers, not a second authority.
|
|
82
84
|
- If record birth fails, no socket starts and no `PI_SESSION_ID` is exported.
|
|
83
85
|
- Reopening the same pi native session attaches to the same record; in-process replacement creates/attaches the replacement's own record.
|
|
84
|
-
-
|
|
86
|
+
- Resume is shipped as its OWN verb, `entwurf_resume_call {target}` — never as an intent on delivery. It reopens a DORMANT pi citizen under the same garden id in a visible window, and it runs no turn: the window comes back with the conversation and waits. The record supplies transcript, model, provider and cwd, so there is no prompt, no task and no model override. The record-authoritative preconditions live in `resume-launch-identity.ts` / `check-resume-launch-identity` (record existence, transcript-header ↔ `record.nativeSessionId` integrity, addressable-read uniqueness, an absolute recorded transcript, model preservation) and now have a consumer.
|
|
85
87
|
|
|
86
88
|
### Capability domains, not rank
|
|
87
89
|
|
|
88
|
-
- **control-socket domain (currently `pi`)**: socket liveness, per-target lock, live send, and
|
|
89
|
-
- **spawn-bg resume
|
|
90
|
-
- **self-fetch domain (currently Claude Code)**: active receiver + mailbox deliverability; no
|
|
91
|
-
- **native-push domain (currently Antigravity)**: adapter probe + direct injection; no mailbox
|
|
90
|
+
- **control-socket domain (currently `pi`)**: socket liveness, per-target lock, live send, and a dormant cell that rejects.
|
|
91
|
+
- **No relaunch transport exists inside delivery.** `spawn-bg` — a detached, window-less resume child — was removed under the visible-first rule, not deprecated behind a reject, and `entwurf_v2` still starts no process: a dormant socket-domain citizen is refused as `dormant-fire-forget-unsupported`. Reopening one is the separate lifecycle verb `entwurf_resume_call`, which is pi-only (`target-not-pi` otherwise), returns a LAUNCH receipt and an OBSERVATION receipt that are never merged, releases its per-gid lock on every path, and on an unobserved socket leaves the visible window open rather than retrying. No watcher, no retry, no supervisor. Do not re-route it through `entwurf_v2` and do not describe a spawn domain that does not exist.
|
|
92
|
+
- **self-fetch domain (currently Claude Code)**: active receiver + mailbox deliverability; no resume authority.
|
|
93
|
+
- **native-push domain (currently Antigravity)**: adapter probe + direct injection; no mailbox and no resume authority.
|
|
92
94
|
- `origin: "pi-session" | "meta-session" | "external-mcp"` records sender provenance. It is not the citizen identity schema and not a hierarchy.
|
|
93
95
|
- `entwurf_peers` reports record citizens and liveness facts only. It never embeds routing verbs or socket addresses for peers.
|
|
94
96
|
- `entwurf_self` is identity-required. For pi, its env carrier must have been planted from record birth; native marker identity must be backed by the matching record. Replyability is derived from the active rail, never hardcoded.
|
|
@@ -105,7 +107,8 @@ Two axes are required: deterministic/package gates and opt-in LIVE evidence.
|
|
|
105
107
|
|
|
106
108
|
```bash
|
|
107
109
|
pnpm typecheck
|
|
108
|
-
pnpm check
|
|
110
|
+
pnpm check # everyday core — prints total wall time; ≤60s on oracle
|
|
111
|
+
pnpm run check:full # full deterministic floor — core + hermetic/package tiers
|
|
109
112
|
./run.sh check-entwurf-v2-matrix
|
|
110
113
|
./run.sh check-meta-session
|
|
111
114
|
./run.sh check-entwurf-bridge-boot
|
|
@@ -116,17 +119,34 @@ LIVE=1 ./run.sh release-gate /path/to/scratch --cut
|
|
|
116
119
|
LIVE=1 ./run.sh smoke-acp-socket-citizen-live
|
|
117
120
|
LIVE=1 ./run.sh smoke-acp-bundled-mcp-live
|
|
118
121
|
LIVE=1 ./run.sh smoke-acp-v2-send-live
|
|
122
|
+
LIVE=1 ./run.sh smoke-mux-lifecycle-live
|
|
119
123
|
LIVE=1 ENTWURF_ACP_CORTEX_CONNECTION=<conn> ./run.sh smoke-acp-cortex-live # on-demand; outside the claude release floor
|
|
120
124
|
LIVE=1 AGY_CONVERSATION_ID=<id> ./run.sh smoke-agy-native-push-live
|
|
121
125
|
```
|
|
122
126
|
|
|
123
|
-
- `pnpm check` is the static floor and
|
|
127
|
+
- The deterministic floor is tiered (#70). `pnpm check` is the everyday core — toolchain (lint + typecheck), the vitest lanes, and the pure-unit / behavioral-contract / source-topology gates plus the cheap static coherence checks. It prints its own total wall time; acceptance is ≤60s on the reference host `oracle` (an operator measurement, never a hard wall-clock gate on arbitrary hosts). `pnpm run check:full` is the full deterministic floor — the core plus the hermetic-integration and package/install tiers — and is what the candidate protocol, push CI, release-gate, and `prepublishOnly` run. Exact membership is the named `check:*` group scripts in `package.json` (the executable SSOT); a gate changes tier by semantic-class decision, never because it happened to get faster or slower. Neither tier includes `check-gate-qualification`, which is scheduled separately (below).
|
|
124
128
|
- **Kill-proof discipline (gate qualification).** A gate is a test only if re-planting a closed defect turns it red for the claimed reason. `check-gate-qualification` proves that automatically: committed mutants in `scripts/mutants/` must be KILLED at their `[QK:<claim>]` signature inside an isolated snapshot repo (control→mutant→restore→control; the real checkout is never written). Gates a release touches carry such manifests; assertion counts are never evidence — claim IDs + killed mutant IDs are. `check-agy-permission-matrix` holds the enumerated permission contract space; matrix cells change by axis/rule edits, never by appending cases.
|
|
125
|
-
- **When changing a contract/gate:** name the production subject and an oracle independent of it; give the failing assertion a stable `[QK:<claim>]` label and add/update the exact-once mutant in `scripts/mutants/*.json`; if the contract is combinatorial, update the literal matrix axes/cells/exclusions together with their declared counts; then verify focused gate
|
|
129
|
+
- **When changing a contract/gate:** name the production subject and an oracle independent of it; give the failing assertion a stable `[QK:<claim>]` label and add/update the exact-once mutant in `scripts/mutants/*.json`; if the contract is combinatorial, update the literal matrix axes/cells/exclusions together with their declared counts; then verify the focused gate, and let qualification and the full floor follow the scheduling contract below — once on the frozen candidate, not once per amendment. `MUTANT-STALE`/`SURVIVED`/`WRONG-REASON`/`CONTROL-RED`/`HANG`/`IMPURE` are red — never substitute an assertion count for a kill.
|
|
126
130
|
- Run LIVE gates with `PWD` in scratch so session artifacts do not land in the repo.
|
|
127
131
|
- Release acceptance and evidence levels are defined in [VERIFY.md](./VERIFY.md); recorded host evidence is in [BASELINE.md](./BASELINE.md).
|
|
128
132
|
- A failed gate or evidence downgrade blocks commit/release. Pipes can be connected and the water can still taste wrong.
|
|
129
133
|
|
|
134
|
+
### Verification scheduling — when the floor runs
|
|
135
|
+
|
|
136
|
+
Gate quality and gate scheduling are different axes: the gates above define *what* green means; this contract owns *when* each layer runs. It exists because repeating the full floor around every review amendment once cost more than the work it verified (history: CHANGELOG/git).
|
|
137
|
+
|
|
138
|
+
```text
|
|
139
|
+
implement → affected focused gates → independent review → one amendment bundle
|
|
140
|
+
→ [gate/mutant changed? check-gate-qualification once] → pnpm run check:full once on the frozen candidate → commit
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
- **Inner loop:** run only the gates whose subject changed. Do not open the full floor to learn what a focused gate already answers.
|
|
144
|
+
- **Review before floor:** independent review and its corrections close as one bundle before the full floor runs.
|
|
145
|
+
- **Qualification is scheduled, not ambient.** `check-gate-qualification` is not in the default check chains (core or full), so the operator inner loop never re-pays the full mutant inventory. It runs standalone once when a lane changed a gate, mutant, or matrix; machine time re-proves it everywhere else — the CI `check` job runs it on every push, and release-gate carries it as a MUST step.
|
|
146
|
+
- **Full floor once** (`pnpm run check:full`), on the frozen commit candidate. While it runs, nothing edits the worktree or index — including the NEXT boot sectors; a moved candidate voids the run's evidence.
|
|
147
|
+
- **pre-commit is not the floor.** `.husky/pre-commit` carries only fast static checks (whitespace, lint, typecheck); the full floor is owned by this protocol, not by the hook. Do not grow the hook back, and do not build receipt/cache machinery to prove the protocol was followed.
|
|
148
|
+
- **Release/LIVE acceptance is untouched.** VERIFY.md floors keep full strength; a shorter inner loop never lowers release evidence.
|
|
149
|
+
|
|
130
150
|
## Repository Map
|
|
131
151
|
|
|
132
152
|
| Path | Purpose |
|
|
@@ -134,12 +154,13 @@ LIVE=1 AGY_CONVERSATION_ID=<id> ./run.sh smoke-agy-native-push-live
|
|
|
134
154
|
| `pi-extensions/entwurf-control.ts` | pi adapter: record attach, record-keyed socket, RPC, native tools |
|
|
135
155
|
| `pi-extensions/lib/pi-citizen-birth.ts` | pi native session → shared V3 record → socket address |
|
|
136
156
|
| `pi-extensions/lib/meta-session.ts` | shared V3 record/store authority plus native marker/mailbox primitives |
|
|
137
|
-
| `pi-extensions/lib/entwurf-v2-*.ts` | v2 contract, decider, transports, runner, production wiring |
|
|
157
|
+
| `pi-extensions/lib/entwurf-v2-*.ts` | v2 contract, decider, transports, runner, production wiring; visible resume keeps launch injected |
|
|
158
|
+
| `pi-extensions/lib/mux-*.ts` | same-tmux placement plus narrow fresh-call and visible-resume launch compositions |
|
|
138
159
|
| `pi-extensions/lib/entwurf-fact*.ts` | record citizens + transport-specific liveness facts |
|
|
139
160
|
| `pi-extensions/lib/native-push/` | native-push adapter/probe/register leaf |
|
|
140
161
|
| `pi-extensions/acp-provider.ts` | `entwurf` provider registration |
|
|
141
162
|
| `pi-extensions/lib/acp/` | ACP adapter rail, config/overlay, augment, turn loop, event mapping |
|
|
142
|
-
| `mcp/entwurf-bridge/` | MCP surface for v2/self/peers/inbox/native-register |
|
|
163
|
+
| `mcp/entwurf-bridge/` | MCP surface for v2/self/peers/inbox/native-register/fresh-call/resume-call |
|
|
143
164
|
| `scripts/` | deterministic gates, LIVE smokes, install/doctor surfaces |
|
|
144
165
|
| `run.sh` | installed command and gate dispatcher |
|
|
145
166
|
|
|
@@ -148,7 +169,7 @@ LIVE=1 AGY_CONVERSATION_ID=<id> ./run.sh smoke-agy-native-push-live
|
|
|
148
169
|
- Every `.ts` file belongs to one typecheck fence: root emit-capable config, MCP strip-types config, or scripts strip-types config. Do not hide files with `exclude`.
|
|
149
170
|
- Root pi extensions import TypeBox through `@earendil-works/pi-ai`; do not mix direct `@sinclair/typebox` types.
|
|
150
171
|
- MCP/scripts use explicit `.ts` imports where Node strip-types requires them. Installed operator surfaces route to compiled JS.
|
|
151
|
-
- pi runtime range is `>=0.
|
|
172
|
+
- pi runtime range is `>=0.84.1 <0.85` with devDep exact `0.84.1`; re-evaluate loader aliases and `/compat` at every minor ceiling. The ceiling moves on measurement, never on assumption, and a previous bump's argument is never reused: at 0.83.0→0.84.0 `compat.ts` was still byte-identical but `loader.ts` was NOT, so the diff itself had to be read and judged reachable-or-not. Per-bump hashes, diff judgments, and reachability findings live in the ROADMAP **Dep bump(별도 트랙)** ledger — keep them there, not here.
|
|
152
173
|
- ACP pins are recorded in `package.json` and checked by `check-dep-versions`/`check-acp-sdk-surface`; do not describe a dependency bump as a behavioral fix without evidence.
|
|
153
174
|
|
|
154
175
|
## Working Style
|
|
@@ -164,6 +185,18 @@ LIVE=1 AGY_CONVERSATION_ID=<id> ./run.sh smoke-agy-native-push-live
|
|
|
164
185
|
- Use tabs unless the existing file/linter requires otherwise.
|
|
165
186
|
- GLG decides commit, push, and release gates. Never infer push from a commit request.
|
|
166
187
|
|
|
188
|
+
### Review triage and lane discipline
|
|
189
|
+
|
|
190
|
+
An overgrowth is built from locally correct steps; what fails is the absence of a budget and a stop rule. These are that budget.
|
|
191
|
+
|
|
192
|
+
- **Reproduce one manual operator action per step.** Measure → narrow leaf → visible composition → observe real pain → next step. Never pre-build the general future (orchestrator, watcher, manager, backlog, role system) ahead of an observed bottleneck, and never build structure to compensate for a current model's habits — both burn with the next model or billing change.
|
|
193
|
+
- **Triage review findings into three grades.** *Blocker* (false success, data loss, authority violation): fix in the current lane. *Defect* (real mismatch against the current explicit contract): fix in the amendment bundle. *Observation* (future risk, stronger-proof possibility): record it — it does not open work in the current lane.
|
|
194
|
+
- **One amendment bundle per review.** If the bundle itself surfaces two or more new architecture blockers, stop repairing and go back to the design.
|
|
195
|
+
- **Unrelated meta-infra never rides a capability lane.** The source-adjacent gate/mutant that proves a capability's contract belongs in the same change as that capability — the removal/repair rule above is untouched. What stays out of a feature commit candidate is unrelated verification machinery: scheduling rework, selectors, caches, receipts, floor restructuring. That pain is recorded and handled in its own subtraction lane later.
|
|
196
|
+
- **Stop signal — evidence outgrowing the product.** When verification/meta-tool changes grow larger than the capability change they serve, stop and report to GLG. This is an operator-judgment trigger, deliberately not a mechanized ratio gate.
|
|
197
|
+
- **Claim only what the evidence carries.** "The full floor was green once on the declared candidate" is strong enough; a stronger sentence mints proof obligations, and those obligations mint subsystems.
|
|
198
|
+
- **Risk classes are not equal.** Data loss, identity authority, false delivery success, install destruction, and secrets get fail-closed strength. Doc tense, future possibility, and total environment-byte binding get repaired when seen — they do not justify new gate machinery.
|
|
199
|
+
|
|
167
200
|
## Next and References
|
|
168
201
|
|
|
169
202
|
- [NEXT.md](./NEXT.md) — current priority and exact next move; branch work uses disposable `NEXT--<branch>.md`.
|
package/BASELINE.md
CHANGED
|
@@ -223,7 +223,7 @@ Per-question PASS / FAIL / NOTE for grading the model's response.
|
|
|
223
223
|
### Q-MCP — MCP enumerate
|
|
224
224
|
- **PASS** — Exactly one: `entwurf-bridge`.
|
|
225
225
|
- **FAIL** — Any second server appears, or `entwurf-bridge` missing.
|
|
226
|
-
- **NOTE** — Codex naturally writes the name with underscores (`entwurf_bridge`); that is the agent-visible backend marker, not a mutation. The current server exposes
|
|
226
|
+
- **NOTE** — Codex naturally writes the name with underscores (`entwurf_bridge`); that is the agent-visible backend marker, not a mutation. The current server exposes seven tools, including the manual `entwurf_register_native` fallback; MCP enumeration asks for the server name, not a stale tool count.
|
|
227
227
|
|
|
228
228
|
---
|
|
229
229
|
|
|
@@ -245,8 +245,8 @@ the same conversation must have a garden id.
|
|
|
245
245
|
| Q-AGY-CONCURRENCY | Evidence boundary | Separate agy processes have separate pid/start-key markers; same-pid concurrent model invocation is explicitly reported unsupported. | Claims that one pid can safely identify two simultaneously invoking conversations. |
|
|
246
246
|
|
|
247
247
|
The replyability formula is **record-backed identity AND live native-push probe**.
|
|
248
|
-
There is intentionally no receiver marker, `watchArmed`, mailbox, or
|
|
249
|
-
|
|
248
|
+
There is intentionally no receiver marker, `watchArmed`, mailbox, or resume
|
|
249
|
+
authority (no rail has one since the visible-first cut). The model field may exist in the meta-record/status display,
|
|
250
250
|
but `agentId=meta-session/antigravity` is the stable sender contract.
|
|
251
251
|
|
|
252
252
|
Recorded operator evidence (2026-07-13): automatic birth → gid/statusline → MCP
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,51 @@ All notable changes to this project will be documented here. Format follows [Kee
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.14.0 — 2026-08-08
|
|
8
|
+
|
|
9
|
+
Two arcs meet in this release. The product arc makes sibling sessions **visible**: opening and resuming a garden citizen is now an explicit, observable act, and the hidden alternatives were removed rather than kept as compatibility surface. The verification arc keeps the product from being swallowed by its own test cost: the everyday gate now runs in under a minute while the release floor stays strict. Claude Code native + pi + the meta-record store remain the main rail; the ACP backends (Claude ACP, Cortex) are optional service adapters on top of it.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
|
|
13
|
+
- **ACTION REQUIRED — the Pi runtime floor is now 0.84.1.** Installing this release upgrades a 0.82.x/0.83.x host rather than leaving it in place: the peer range is `>=0.84.1 <0.85`, the development pin is exactly 0.84.1, and installed-package acceptance pins the expanded Pi package constellation. Claude ACP moves to 0.66.0: the 0.65.0 permission metadata reaches the wire but is label-independent, the steered-turn change stays structurally unreachable because entwurf does not send `session/steer`, and 0.66.0's new goal extension changes no entwurf behavior — entwurf never sends `_session/goal`, does not consume the initialize advert, a `/goal` prompt still reaches the model unchanged (the adapter only adds a goal notification), and that inbound `session_info_update` can reach the wire but falls inert to the event mapper's ignore path.
|
|
14
|
+
- **Delivery is visible-first and single-verb.** `entwurf_v2 fire-and-forget` never starts a process; a dormant control-socket citizen rejects as `dormant-fire-forget-unsupported`, and the reject hint now points at the visible resume verb instead of a manual workaround. The hidden `spawn-bg`/`owned-outcome` resume path and its gates were removed rather than retained as dead compatibility surface.
|
|
15
|
+
- **ACP `streamSimple` honors Pi's request hook contract without fabricating HTTP evidence.** `onPayload` receives and may replace the exact ACP `{sessionId,prompt}` request on new and reused turns under fail-closed validation and abort ordering; `onResponse` is an explicit zero-call exemption because ACP has no truthful HTTP status/header boundary.
|
|
16
|
+
- **Visible team formation and role authority are separate operating phases.** Fresh tasks form exact callback-correlated citizens and stop; the operator's later direct visible grant supplies coordinator/implementer/reviewer authority. No role database, watcher, retry loop, or orchestrator was added.
|
|
17
|
+
- **Verification is tiered by meaning, not by elapsed time.** `pnpm check` is the everyday core — it completes in under 60 seconds on the reference host (36s measured on this candidate) and prints its own wall time; `pnpm run check:full` is the deterministic candidate floor that push CI, the release gate, and `prepublishOnly` all agree on by name. `check-gate-qualification` runs once per frozen candidate, in every push CI check job, and as a release-gate MUST step — never inside the inner loop. The subtraction behind this was loud, not silent: the `probe-ordering` mutant lane's 84 infrastructure replants were succeeded 1:1 by direct assertions with an 84-entry ledger (#70), bringing qualification to 165 mutants across 22 lanes with the infrastructure-subject share down from 111 of 247 to 27 of 165. What did *not* happen is also part of the record: the hand-built surface shrank by only ~1.6% in lines — the cost shape changed, not the mass. Gates move tier only by semantic-class decision.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- **Visible mux lifecycle verbs now cover both creation and same-id Pi resume.** `entwurf_fresh_call` opens one visible Pi or Claude Code sibling with an explicit runtime model and learns its garden id only from the sibling's exact nonce callback envelope. `entwurf_resume_call` reopens a dormant Pi citizen in the operator's tmux session under its existing garden id, keeps LAUNCH and OBSERVATION receipts separate, and runs no turn; Claude Code honestly refuses same-id resume as `target-not-pi`.
|
|
22
|
+
- **Owner-normalized local identity facts are available through `entwurf meta-facts`.** The deterministic JSON projection exposes the strict V3 garden/native/transcript join and in-band defects by reusing the record owner's parser and store authority, so same-user consumers no longer need to maintain a weaker copy of the certification contract.
|
|
23
|
+
- **Vitest 4.1.9 enters as the standard test runner — a beachhead, not an occupation.** The fresh-call surface/provider lane boots the real bridge, captures native registration and the Anthropic provider conversion path, and validates host-regex patterns against a Rust-family engine; a second lane moves the ACP SDK dependency/resolver contract behind the same stable `run.sh` shim. Two hand-built gates migrated; new contracts now default to being born in the framework, and further migration stays deliberate and lane-by-lane.
|
|
24
|
+
- **An `entwurf-dev` operator skill rides in the repository (not in the npm package).** It is a development/verification tour tool: it lets the operator drive the current surface — list citizens, open a fresh visible sibling, correlate its nonce callback, send, resume — in natural language without memorizing tool calls.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- **Garden-id creation is exclusive across the certified active store.** CREATE writes the record bytes to a same-directory temp file first and publishes with an exclusive `link(2)`; an occupied final path fails loud with a named `MetaRecordError` — the refusal is occupancy-based, there is no retry, no check-then-write TOCTOU window exists, and the occupying record's bytes stay untouched. ATTACH keeps atomic in-place replacement of its own record; a collision surfaces as an error, never as an overwrite.
|
|
29
|
+
- **Mux LIVE smokes cannot delete a retargeted real Claude launcher.** A shared fail-closed fence pins the PATH-selected launcher, link, resolved target, and content before launch; both smokes restore the operator's exact XDG presence/value and verify launcher integrity before conditional fixture cleanup on success and failure paths.
|
|
30
|
+
- **Fresh-call verification now observes the host boundaries that source-text checks missed.** The escaped schema defect is replanted against Rust-family regex compilation and actual provider request bytes, and the session-identity generator oracle no longer relies on a probabilistic collision-free sample.
|
|
31
|
+
- **The install surfaces hold the public MCP tool set as an exact seven — and the shipped protocol suite's tool assertion runs at all.** Three independent installed-consumer gates required only the five pre-0.14 verbs: `entwurf check-bridge` (which under `node_modules` is the prebuilt-dist branch of `start.sh`), the packed-install boot inside `check-pack-install`, and the checkout-invisible `check-install-container` that release acceptance hands the preserved candidate. An artifact that booted and answered `tools/list` without `entwurf_fresh_call` / `entwurf_resume_call` therefore passed the very gates that exist to catch "green clone, dead consumer" — the two verbs this release ships were covered by no installed-surface assertion at all. All three now compare the whole set and refuse a missing, extra, or duplicated verb. Underneath them sat something worse: the tarball-shipped `mcp/entwurf-bridge/test.sh` wrote its tool check as `python3 - <<'PY' <<<"$TOOLS_JSON"`, two redirections onto one stdin, so Python executed the JSON payload as its program while the here-doc assertions never ran once and the `ok:` line printed unconditionally. That block is live for the first time, with duplicate detection and the v1-verb negative kept as its own named diagnosis. `check-entwurf-bridge-boot` gains the same equality as `G1f` under `[QK:BRIDGEBOOT-PUBLIC-SURFACE-EXACT-SET]` with its own exact-once mutant, because every assertion before it was existential and `entwurf_fresh_call` was named by none of them. Stale enumerations that drifted when 0.14 added the two verbs were repaired with the gates: the bridge module header, the agy auto-grant exclusion list (two named exclusions, now four — the mux verbs launch into the caller's own tmux session, which an agy conversation is not), the external-MCP-host and mux-rail docs, and the `check-bridge` progress line that named only the dev strip-types branch to an operator reading it from an npm install.
|
|
32
|
+
|
|
33
|
+
### Removed
|
|
34
|
+
|
|
35
|
+
- **The unimplemented `tmux-live` receipt transport has been removed from the v2 contract.** A mux window is an operator view — it may later expose a runtime, but it is never address authority or delivery evidence.
|
|
36
|
+
- **Injected session ids and hidden background resume are no longer launch substrates.** Fresh identity comes from the callback sender envelope; dormant lifecycle is the explicit visible resume verb.
|
|
37
|
+
|
|
38
|
+
### Verification
|
|
39
|
+
|
|
40
|
+
- Pre-version landing HEAD `9e14df518fb33bad59be14af31c64d71107b558d` passed exact-SHA GitHub Actions run [31258659484](https://github.com/junghan0611/entwurf/actions/runs/31258659484): `check`, `install-surface`, and `artifact-consumer` all success.
|
|
41
|
+
- The 0.14.0 prepared tree passed `pnpm run check:full` (full deterministic floor, 303s, exit 0); `check-pack` counted **342 files**.
|
|
42
|
+
- The initial prepared tree's `LIVE=1 ./run.sh release-gate /tmp/entwurf-release-gate-0.14.0.r8r31u --cut` completed **MUST PASS=20 FAIL=0 SKIP=0** (including the `check-gate-qualification` MUST step at **165/165 killed across 22 lanes**), **BEHAVIOR PASS=1 FAIL=0 SKIP=0**, `cut: OK`. Full log: `/tmp/entwurf-release-gate-0.14.0.r8r31u/release-gate.log`; per-step scratch/artifact paths are preserved in that log. The active LIVE set is native Claude Code, native pi, and pi+ACP; Cortex stays the documented on-demand host-auth axis, and no model-in-loop AGY step is in the aggregate.
|
|
43
|
+
- Closing verification-surface inventory (the #70 after-picture, measured by `scripts/inventory-verification-surface.ts`): **203 files / 58,893 lines** combined, against the #62/#70 baseline of 201 files / 59,775 lines — lines below baseline (**−882**) with the file count reported transparently (**+2**). The prepared tree measured 58,845 before the install-surface repair below added 48 lines of gate text; the shipping number is the one stated here, so an independent recount lands on it.
|
|
44
|
+
- **Install-surface repair and amended-tree re-acceptance.** The whole deterministic and installed-consumer set was re-taken on one frozen amended tree: `pnpm run check:full` **299s exit 0** with `check-pack` at **342 files**, `./run.sh check-gate-qualification` **166/166 killed across 22 lanes** (the +1 is the new `BRIDGEBOOT-PUBLIC-SURFACE-EXACT-SET`), `./run.sh check-pack-install` exit 0 with the installed boot listing all seven verbs, and `ENTWURF_REQUIRE_DOCKER=1 ./run.sh check-install-container` reaching `container-consumer: PASS` with the same seven from a frozen non-root global install. A project-local npm install under a sandboxed HOME was additionally driven through the operator-facing first command, `entwurf check-bridge`: exit 0, seven verbs, from the dist branch. The aggregate was then re-run against that amended tree on 2026-08-09 (oracle): `LIVE=1 ./run.sh release-gate /tmp/entwurf-release-gate-0.14.0-is.52cPh0 --cut` — **MUST PASS=20 FAIL=0 SKIP=0** (qualification MUST at **166/166 across 22 lanes**), **BEHAVIOR PASS=1 FAIL=0 SKIP=0**, `cut: OK`, exit 0. HEAD, porcelain, and the repo-root work-surface hash were identical before and after; the complete 3,943-line log is `/tmp/claude-1000/-home-junghan-repos-gh-entwurf/4a6914ab-d9da-4f67-9db2-5bf20f0ed168/scratchpad/p5-live.log` (SHA-256 `0e0f7f6168fa7484aed9db1b42a7b8945e9bcfcdb5745a23c9615992275efb7c`).
|
|
45
|
+
- Exact prepared-HEAD CI and the preserved-candidate container acceptance remain `make` responsibilities.
|
|
46
|
+
|
|
47
|
+
### Notes
|
|
48
|
+
|
|
49
|
+
- **Known open issues shipped with eyes open:** #60 (native-push drops `wants_reply`/caller envelope), #68 (naming the valid no-transcript resume refusal), #71 (`skipDangerousModePermissionPrompt` pinned while `defaultMode` stays operator-owned), and an observed long-turn error pattern on the optional Claude ACP rail that a post-release audit will reproduce and classify. None of these gates this release; all are tracked.
|
|
50
|
+
- **Ecosystem:** the `agent-config` repository's `entwurf-peek` skill was reworked against this release as its baseline — an advanced-operator density tool, not a requirement.
|
|
51
|
+
|
|
7
52
|
## 0.13.1 — 2026-07-31
|
|
8
53
|
|
|
9
54
|
### Changed
|
package/CONTRIBUTING.md
CHANGED
|
@@ -17,7 +17,7 @@ These are enforced by code, gates, and review. Do not weaken them in a PR; if yo
|
|
|
17
17
|
1. **Bootstrap order**: `resume > load > new`. Always.
|
|
18
18
|
2. **Session persistence**: only `pi:<sessionId>` is persisted. `cwd:<cwd>` is never persisted.
|
|
19
19
|
3. **MCP injection**: only via `entwurfProvider.mcpServers`. No ambient `~/.mcp.json` scanning, no `~/.claude/settings.json` MCP inheritance.
|
|
20
|
-
4. **Operating surface, not config inheritance**: the user's filesystem Claude Code config (`~/.claude/settings.json` hooks, env, plugins, `permissions.defaultMode`) is intentionally *not* inherited. Skills come from `skillPlugins
|
|
20
|
+
4. **Operating surface, not config inheritance**: the user's filesystem Claude Code config (`~/.claude/settings.json` hooks, env, plugins, `permissions.defaultMode`) is intentionally *not* inherited. Skills come from `skillPlugins`; callable tools are shaped by `tools` / `disallowedTools`, and `permissionAllow` still rides the inline Claude settings. The overlay authors `permissions.defaultMode: "bypassPermissions"` so an unattended ACP turn cannot suspend on an interactive prompt; this does not bypass backend authentication. `CLAUDE_CONFIG_DIR` enforces the isolation even where the SDK reads filesystem independently of `settingSources`.
|
|
21
21
|
5. **Backend-specific knobs stay explicit and namespaced**: retired Codex/Gemini-era ACP knobs are not carried on the current path. A backend that needs its own knob uses the `ENTWURF_ACP_*` namespace, and invalid values must throw, never fall back — cortex followed this with `ENTWURF_ACP_CORTEX_CONNECTION` (the renamed `PI_SHELL_ACP*` legacy var), and its settings key rides `adapterSettings`, not the common config.
|
|
22
22
|
6. **Bridge does not implement compaction**: When a backend compacts natively, the pi session and mapping survive that. Pi-side JSONL compaction must not be presented as backend-transcript reduction, and backend-specific compaction controls belong to the backend's own native interface. Legacy `PI_SHELL_ACP_*` compaction knobs must not reappear.
|
|
23
23
|
7. **Backend coverage honesty**: changes to operating surface, session lifecycle, or persistence must state which shipped/probed backend surfaces they cover. A claim that silently drops a covered backend is a regression; if one backend is genuinely not covered, record that carve-out explicitly.
|
|
@@ -26,27 +26,31 @@ These are enforced by code, gates, and review. Do not weaken them in a PR; if yo
|
|
|
26
26
|
## Required gate before opening a PR
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
pnpm check
|
|
29
|
+
pnpm check # everyday core (prints wall time; <=60s on the reference host)
|
|
30
|
+
pnpm run check:full # full deterministic floor — the required PR gate
|
|
30
31
|
```
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
The deterministic floor is tiered (#70). `pnpm check` is the everyday core (biome, tsc, the vitest lanes, and the fast contract gates); `pnpm run check:full` adds the hermetic-integration and package/install tiers — all but the separately scheduled `check-gate-qualification`, which CI runs on every push and a gate-changing PR must run once itself. Exact membership is the named `check:*` scripts in `package.json`. Run `check:full` once on your frozen commit candidate — the pre-commit hook (`.husky/pre-commit`) carries only fast static checks (whitespace, lint, typecheck), not the full floor, so a green `pnpm run check:full` before commit is the evidence that your change holds (scheduling contract: AGENTS.md "Verification scheduling").
|
|
33
34
|
|
|
34
|
-
For changes that touch backend launch, session lifecycle, or `_meta` shape, also run
|
|
35
|
+
For changes that touch backend launch, session lifecycle, or `_meta` shape, also run
|
|
36
|
+
the live ACP smokes that cover the touched rail — at minimum:
|
|
35
37
|
|
|
36
38
|
```bash
|
|
37
|
-
./run.sh smoke-
|
|
38
|
-
./run.sh
|
|
39
|
+
LIVE=1 ./run.sh smoke-acp-provider-live
|
|
40
|
+
LIVE=1 ./run.sh smoke-acp-session-reuse-live
|
|
39
41
|
```
|
|
40
42
|
|
|
41
|
-
These need a real ACP subprocess
|
|
43
|
+
These need a real ACP subprocess plus the operator's local backend auth, so they stay
|
|
44
|
+
manual — the hook does not run them. The full aggregate is `LIVE=1 ./run.sh release-gate
|
|
45
|
+
<scratch> --cut` (see [VERIFY.md](./VERIFY.md)).
|
|
42
46
|
|
|
43
47
|
## What gets PRs rejected
|
|
44
48
|
|
|
45
49
|
- adds ambient MCP discovery (project `.mcp.json`, `~/.mcp.json`, etc.) without an explicit `entwurfProvider.mcpServers` opt-in path
|
|
46
|
-
- inherits user / project / local backend config by default (i.e. flips `settingSources` away from `[]`, drops the `CLAUDE_CONFIG_DIR` overlay,
|
|
50
|
+
- inherits user / project / local backend config by default (i.e. flips `settingSources` away from `[]`, drops the `CLAUDE_CONFIG_DIR` overlay, or weakens cortex's session-scoped HOME containment)
|
|
47
51
|
- weakens `resume > load > new` (e.g. silently downgrading to `new` without a logged invalidation reason)
|
|
48
52
|
- introduces `console.warn` / silent fallback where the bridge should `throw` (see `AGENTS.md` "Never warn. Throw.")
|
|
49
|
-
- changes
|
|
53
|
+
- changes a backend operating surface (tools, skills, MCP, permissions, sandbox) without accounting for both shipped backends (Claude, Cortex) or recording an explicit carve-out
|
|
50
54
|
- adds a second transcript ledger, a prompt reconstruction layer, or any state that competes with pi's session as the source of truth
|
|
51
55
|
- skews version pins across `package.json`, `run.sh`, and `README.md` (the `check-dep-versions` gate catches this; if it complains, fix all three)
|
|
52
56
|
|
package/DELIVERY.md
CHANGED
|
@@ -108,22 +108,23 @@ needs the installed strict doctor against a new native session.
|
|
|
108
108
|
`PreInvocation` births or reattaches a citizen by native `conversationId` and writes a
|
|
109
109
|
record-backed sender marker. `entwurf_v2` probes the live conversation and injects
|
|
110
110
|
directly through the native adapter, with one bounded re-probe retry. Replyability is
|
|
111
|
-
`record-backed identity ∧ probe-alive`; mailbox state
|
|
112
|
-
|
|
111
|
+
`record-backed identity ∧ probe-alive`; mailbox state does not exist on this rail, and no
|
|
112
|
+
rail has resume authority since the visible-first cut.
|
|
113
113
|
|
|
114
114
|
The managed bridge, statusline, and hook installers own separate configuration atoms.
|
|
115
115
|
Same-pid concurrent model invocation by multiple conversations is not claimed because
|
|
116
116
|
the pid/start-key sender marker would be last-writer-wins. Current operator checks are
|
|
117
117
|
in [BASELINE.md](./BASELINE.md); deterministic ownership and sender gates run in
|
|
118
|
-
`pnpm check`.
|
|
118
|
+
`pnpm run check:full`.
|
|
119
119
|
|
|
120
120
|
### Codex: launch mode is part of the capability
|
|
121
121
|
|
|
122
122
|
Do not describe “Codex” as one delivery shape. The measured app-server-backed TUI can
|
|
123
123
|
accept `turn/start` for a live thread and report completion; the standalone embedded
|
|
124
|
-
TUI exposed no equivalent receive route.
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
TUI exposed no equivalent receive route. This remains archived method evidence, not a
|
|
125
|
+
shipping commitment: GLG closed the managed native Codex lane on 2026-08-01 because pi
|
|
126
|
+
already supplies the official GPT provider path. Entwurf will not duplicate it as a
|
|
127
|
+
native citizen or ACP backend. `turn/steer` is active-turn steering, not idle wake.
|
|
127
128
|
|
|
128
129
|
## Recording a new claim
|
|
129
130
|
|
package/README.md
CHANGED
|
@@ -16,10 +16,10 @@ Legacy package: [`@junghanacs/pi-shell-acp`](https://www.npmjs.com/package/@jung
|
|
|
16
16
|
Claude Code / Codex / agy / pi
|
|
17
17
|
→ garden id
|
|
18
18
|
→ entwurf_v2
|
|
19
|
-
→ control-socket |
|
|
19
|
+
→ control-socket | meta-mailbox | native-push
|
|
20
20
|
```
|
|
21
21
|
|
|
22
|
-
[`entwurf_v2`](#entwurf_v2--canonical-dispatch-verb) is the canonical dispatch surface over *existing* garden citizens — live control-socket send,
|
|
22
|
+
[`entwurf_v2`](#entwurf_v2--canonical-dispatch-verb) is the canonical dispatch surface over *existing* garden citizens — live control-socket send, meta-mailbox enqueue, and native-push into a live Antigravity conversation. It starts no process on any rail: the hidden background resume that used to answer a dormant target was withdrawn under the visible-first rule, so a dormant citizen rejects honestly here and is reopened by a separate lifecycle verb, `entwurf_resume_call`. The meta-record is the sole address authority (#50 C4): a record-less control socket is refused as a `record-less-socket` diagnostic, never dispatched. The v1 entwurf verbs are gone. Fresh siblings and resumes are separate verbs — `entwurf_fresh_call` opens a NEW sibling in the operator's own tmux session and learns its garden id from the callback it makes, while `entwurf_resume_call` reopens a DORMANT pi citizen under its own garden id in a visible window without running a turn; the non-Claude ACP lane landed earlier — Snowflake Cortex Code became the second backend in 0.13.0.
|
|
23
23
|
|
|
24
24
|
**Garden id is deliberate vocabulary.** It is not a decorative synonym for session id, worker, delegate, or subagent. The unfamiliar word is a guard: each harness keeps its own identity and transcript, while `entwurf` supplies a narrow addressable surface between siblings.
|
|
25
25
|
|
|
@@ -61,7 +61,7 @@ Claude's `install-meta-bridge` and agy's `install-agy-{bridge,statusline,hooks}`
|
|
|
61
61
|
|
|
62
62
|
A few words that look unusual for a coding tool.
|
|
63
63
|
|
|
64
|
-
- **Entwurf** (기투, projection-of-self) — sibling sessions with their own runtime boundary. Not "delegate," not "worker," not "sub-agent."
|
|
64
|
+
- **Entwurf** (기투, projection-of-self) — sibling sessions with their own runtime boundary. Not "delegate," not "worker," not "sub-agent." Opening a visible sibling (`entwurf_fresh_call`), live peer messaging (`entwurf_v2`) and reopening a dormant one (`entwurf_resume_call`) are first-class; the hidden background resume that preceded the last of those was withdrawn under the visible-first rule.
|
|
65
65
|
- **Garden / garden id** — the garden is the shared address space where independent harness sessions become citizens without losing their own runtime or transcript. A garden id is the stable address of one such citizen (for pi, a garden-native session id like `YYYYMMDDTHHMMSS-<6hex>`; for native harnesses, a meta-session id minted from an authoritative lifecycle hook — Claude `SessionStart`, agy `PreInvocation`). It is not a worker name and not proof that pi owns the session. The same-looking id may name a live control socket, a dormant pi record, a mailbox-backed native session, or a native-push conversation, so callers discover facts with `entwurf_peers` and deliver with `entwurf_v2` instead of choosing a transport by hand.
|
|
66
66
|
- **Engraving** — optional short operator text delivered through each backend's native identity carrier. Not a giant hidden prompt, not a tool catalog.
|
|
67
67
|
- **MCP** — in this repo, MCP is just the transport by which ACP-backed sessions receive pi capabilities that native pi exposes directly as extensions. It is not a general MCP platform. Explicit `entwurfProvider.mcpServers` only; no ambient `~/.mcp.json` scanning, no automatic retrieval. The same `entwurf-bridge` entry can also be wired into another host's MCP catalog (Claude Code, Codex, Antigravity, …) when the operator chooses. `entwurf_self` returns an authoritative pi-session or trusted meta-session identity envelope; `entwurf_v2` requires an authoritative sender by default (#50 C4) — a plain external MCP host with no identity lane is refused unless the operator explicitly wires the documented anonymous hatch, and even then it is never replyable.
|
|
@@ -100,8 +100,8 @@ entwurf check-bridge
|
|
|
100
100
|
```
|
|
101
101
|
|
|
102
102
|
This writes `.pi/settings.json` in the target project with the absolute path to
|
|
103
|
-
the installed `entwurf-bridge` launcher.
|
|
104
|
-
|
|
103
|
+
the installed `entwurf-bridge` launcher. (The old `~/.pi/agent/` target-registry
|
|
104
|
+
link is gone — #50 C3; nothing reads it.) The global install is the easiest path when
|
|
105
105
|
Claude Code's USER-scope MCP registration should work from every cwd.
|
|
106
106
|
|
|
107
107
|
### From npm — project-local install
|
|
@@ -144,7 +144,7 @@ because Node refuses to strip `.ts` files under `node_modules`.
|
|
|
144
144
|
### Pi adapter / ACP plugin lane
|
|
145
145
|
|
|
146
146
|
To use the `entwurf` provider inside pi, install a compatible pi binary
|
|
147
|
-
separately (`@earendil-works/pi-coding-agent >=0.
|
|
147
|
+
separately (`@earendil-works/pi-coding-agent >=0.84.1 <0.85`). Then point pi at
|
|
148
148
|
the npm-installed package or development clone:
|
|
149
149
|
|
|
150
150
|
```bash
|
|
@@ -159,8 +159,8 @@ For daily operator sessions, launch pi with `--entwurf-control` — no id
|
|
|
159
159
|
injection; the meta-record mints the garden address (see [Garden launcher](#garden-launcher)). Older pi
|
|
160
160
|
versions may silently miss the provider/extension surface, so treat the pi floor
|
|
161
161
|
as release-critical for the ACP/plugin lane. A host that only uses
|
|
162
|
-
`entwurf-bridge` from Claude Code / Codex / Antigravity does not need pi
|
|
163
|
-
|
|
162
|
+
`entwurf-bridge` from Claude Code / Codex / Antigravity does not need pi at all for
|
|
163
|
+
delivery: no `entwurf_v2` rail launches a pi process.
|
|
164
164
|
|
|
165
165
|
### Native harness install and doctors
|
|
166
166
|
|
|
@@ -218,8 +218,9 @@ host evidence boundaries are [VERIFY.md](./VERIFY.md) and [BASELINE.md](./BASELI
|
|
|
218
218
|
|
|
219
219
|
The curated model registry exposes unprefixed Claude ids plus `cortex-` rows.
|
|
220
220
|
Codex is not an ACP backend or a shipped managed citizen lane: it has verified
|
|
221
|
-
native-delivery probe evidence
|
|
222
|
-
|
|
221
|
+
native-delivery probe evidence only. Release 0.14.0 does not add Codex support;
|
|
222
|
+
any future managed lane still owes lifecycle, identity, installation, and doctors
|
|
223
|
+
before calling it supported.
|
|
223
224
|
|
|
224
225
|
**Snowflake Cortex Code is the second ACP backend** (contract and audit:
|
|
225
226
|
[docs/acp-backend-rail.md](./docs/acp-backend-rail.md#cortex-code-audit-d1d10)). Curated ids are
|
|
@@ -233,7 +234,7 @@ HOME containment. Explicit MCP servers are projected into the overlay-private
|
|
|
233
234
|
`cortex/mcp.json`; only the bridge receives the real operator HOME needed for the
|
|
234
235
|
garden store.
|
|
235
236
|
|
|
236
|
-
`check-acp-cortex` runs in `pnpm check`. Real acceptance is deliberately on demand:
|
|
237
|
+
`check-acp-cortex` runs in `pnpm run check:full`. Real acceptance is deliberately on demand:
|
|
237
238
|
|
|
238
239
|
```bash
|
|
239
240
|
LIVE=1 ENTWURF_ACP_CORTEX_CONNECTION=<conn> entwurf smoke-acp-cortex-live
|
|
@@ -320,7 +321,7 @@ For the maintained multi-harness setup and skill/command packaging details, see
|
|
|
320
321
|
|
|
321
322
|
The Claude ACP backend keeps its native model / API / tools; entwurf shapes only what enters from pi. Claude honors an explicit `CLAUDE_CONFIG_DIR` export when set by the operator.
|
|
322
323
|
|
|
323
|
-
**Claude** uses `_meta.systemPrompt` for the engraving carrier (kept short and pure — billing-safe; rich operator context rides the first user message instead, see [Context carriers](#context-carriers)) and `CLAUDE_CONFIG_DIR` for a whitelist overlay so auth/runtime entries stay available while operator memory, hooks, agents, history, local settings, and project memory remain hidden. The overlay writes an explicit empty `hooks: {}` because Claude SDK organic compaction needs the configured-empty shape; no operator hook definitions are inherited. The four-tool baseline
|
|
324
|
+
**Claude** uses `_meta.systemPrompt` for the engraving carrier (kept short and pure — billing-safe; rich operator context rides the first user message instead, see [Context carriers](#context-carriers)) and `CLAUDE_CONFIG_DIR` for a whitelist overlay so auth/runtime entries stay available while operator memory, hooks, agents, history, local settings, and project memory remain hidden. The overlay writes an explicit empty `hooks: {}` because Claude SDK organic compaction needs the configured-empty shape; no operator hook definitions are inherited. It also pins `permissions.defaultMode: "bypassPermissions"` so an unattended ACP turn cannot suspend on an interactive permission prompt; explicit `tools` / `disallowedTools` still constrain the callable surface and backend authentication remains the operator's. The four-tool baseline is `Read`, `Bash`, `Edit`, and `Write`; `permissionAllow` carries their allow declarations, and `Skill` is added automatically when `skillPlugins` is non-empty. Operator context cap override: `ENTWURF_ACP_CLAUDE_CONTEXT=<int>`.
|
|
324
325
|
|
|
325
326
|
Codex is not an ACP backend here. Its native delivery probe remains separate from
|
|
326
327
|
the governed ACP adapter rail and does not yet constitute a managed garden citizen.
|
|
@@ -332,7 +333,8 @@ entwurf owns **no** memory layer at all — the ACP plugin's boundary explicitly
|
|
|
332
333
|
## Smoke commands
|
|
333
334
|
|
|
334
335
|
```bash
|
|
335
|
-
pnpm check #
|
|
336
|
+
pnpm check # everyday core (prints wall time; <=60s on the reference host)
|
|
337
|
+
pnpm run check:full # full deterministic floor (adds the hermetic + package/install tiers)
|
|
336
338
|
./run.sh check-bridge # entwurf-bridge direct MCP smoke (no backend auth)
|
|
337
339
|
./run.sh smoke-agy-install-state # agy MCP + exact permission ownership lifecycle (install/uninstall/doctor/inverse)
|
|
338
340
|
./run.sh smoke-agy-statusline-state # agy ambient garden-id install surface
|
|
@@ -359,8 +361,9 @@ LIVE=1 ./run.sh release-gate /tmp/scratch --cut # the single cut gate (MUST + BE
|
|
|
359
361
|
LIVE=1 ENTWURF_ACP_CORTEX_CONNECTION=<conn> ./run.sh smoke-acp-cortex-live # Cortex is on-demand: the aggregate does not re-certify it
|
|
360
362
|
```
|
|
361
363
|
|
|
362
|
-
`pnpm check`
|
|
363
|
-
|
|
364
|
+
`pnpm run check:full` includes the AGY permission contract matrix; the committed-mutant
|
|
365
|
+
gate qualification is scheduled separately (`./run.sh check-gate-qualification` — the CI
|
|
366
|
+
`check` job runs it on every push, and release-gate carries it as a MUST step). A gate a
|
|
364
367
|
release touches must kill its known defect for the claimed `[QK:<claim>]` reason —
|
|
365
368
|
the descriptions above name what each smoke covers, and no check count is quality
|
|
366
369
|
evidence on its own. Gate qualification needs the git work surface, while the matrix
|
|
@@ -402,9 +405,9 @@ For a real consumer arranging many skills, see [agent-config](https://github.com
|
|
|
402
405
|
|
|
403
406
|
**Entwurf is one dispatch capability with native-pi and MCP surfaces.** Native pi exposes it directly as extension tools; ACP-backed and external native-harness sessions reach it through `entwurf-bridge`. The purpose is not to invent a different sub-agent system, but to preserve the same sibling-based model across harnesses.
|
|
404
407
|
|
|
405
|
-
A sibling has its own runtime boundary and its own provider/model identity — not a worker, delegate, or sub-agent.
|
|
408
|
+
A sibling has its own runtime boundary and its own provider/model identity — not a worker, delegate, or sub-agent. Today every transport targets an *existing* garden citizen, and none of them starts a process. `entwurf_v2` routes from rail-specific liveness: live pi fire-and-forget → control socket; dormant pi → an honest reject; active self-fetch → meta-mailbox; probe-alive agy → native-push. A **control-socket-domain** dispatch takes the per-target lock, which now serializes concurrent live sends at one garden id; mailbox and native-push use their own deliverability evidence and remain lock-free.
|
|
406
409
|
|
|
407
|
-
A two-pane recording covers the surface end-to-end — sibling resume, cross-process MCP dispatch across a different cwd, and a live peer greeting
|
|
410
|
+
A two-pane recording covers the pre-0.12 v1 surface end-to-end — sibling resume, cross-process MCP dispatch across a different cwd, and a live peer greeting. It is **archived evidence**: it shows a resume verb this repo no longer has (see `demo/README.md`).
|
|
408
411
|
|
|
409
412
|
<details>
|
|
410
413
|
<summary>Watch (2131×1142 GIF, click to expand)</summary>
|
|
@@ -415,29 +418,26 @@ A two-pane recording covers the surface end-to-end — sibling resume, cross-pro
|
|
|
415
418
|
|
|
416
419
|
Live peer messaging carries a sender envelope `{ sessionId, agentId, cwd, timestamp, origin?, replyable? }`; `entwurf_self` returns that authoritative envelope for the current pi session or trusted meta-session. Plain external MCP hosts are non-replyable. A garden-native meta-session carries a trusted `meta-session` envelope, but **`replyable` is a fact its own rail decides, not a consequence of being trusted** — a self-fetch citizen needs a live armed receiver, a native-push citizen needs an alive adapter probe, and a pi session needs its control socket. `entwurf_self` also reports which rail a meta-session reply would ride, because a native-push citizen has no mailbox to name. `wants_reply` is an etiquette marker rendered as a `(wants reply)` badge — not a transport contract, no wait, no polling. **v2 never gates on it:** a `wants_reply` from an external/non-replyable caller is passed through and surfaced honestly beside that sender's `replyable: false`, not rejected — the decider routes on target + intent, never on sender replyability. (The retired v1 `entwurf_send` did reject it; that behaviour went with the verb.)
|
|
417
420
|
|
|
418
|
-
In ACP-backed and external native-harness sessions, `entwurf-bridge` exposes
|
|
421
|
+
In ACP-backed and external native-harness sessions, `entwurf-bridge` exposes seven tools: `entwurf_v2`, `entwurf_peers`, `entwurf_fresh_call`, `entwurf_resume_call`, `entwurf_self`, `entwurf_inbox_read`, and the explicit/manual `entwurf_register_native` fallback. Native pi exposes the shared capability directly through the extension surface (`entwurf_v2`, `entwurf_peers`, `entwurf_fresh_call`, `entwurf_resume_call` tools; the socket-scan `/entwurf-sessions` command is gone — #50 C4). **For garden-id delivery/reply use `entwurf_v2`** — the canonical surface that classifies the target and routes to live-pi / Claude-Code-meta-mailbox / Antigravity-native-push, and refuses a dormant target instead of waking it. **To open a sibling that does not exist yet use `entwurf_fresh_call`** — it launches one fixed backend (`pi` or `claude-code`) as a visible window in the operator's own tmux session, requires an explicit model, passes that model on the runtime CLI, and hands it a first task; the sibling's first action is a nonce callback whose sender envelope carries its garden id. The launch receipt records the requested model plus tmux coordinates and never claims that the runtime accepted the model or completed delivery. (The v1 verbs `entwurf` / `entwurf_resume` / `entwurf_send` are gone.) Garden-native operator commands require `--entwurf-control`. There is no spawn target allowlist — the target registry is gone (#50 C3): `entwurf_v2` and `entwurf_resume_call` address an existing record-backed citizen, while `entwurf_fresh_call` takes its explicit backend/model/task directly rather than resolving a model tuple from a registry file. **To reopen a DORMANT pi citizen use `entwurf_resume_call {target}`** — the record supplies transcript, model, provider and cwd, so it takes no prompt, no task and no model override; it runs no turn, returns a LAUNCH receipt and a separate OBSERVATION receipt (only the second says the citizen is back), refuses a non-pi target as `target-not-pi`, and on an unobserved socket leaves the visible window open and releases its lock rather than retrying.
|
|
419
422
|
|
|
420
423
|
### `entwurf_v2` — canonical dispatch verb
|
|
421
424
|
|
|
422
|
-
`entwurf_v2` / `runEntwurfV2` is the canonical v2 dispatch verb over **existing** garden targets — record-backed citizens only (#50 C4: the record is the sole address authority; a record-less control socket rejects pre-probe as `record-less-socket`, a diagnostic state, never a delivery target). You give a target garden id plus an intent (`fire-and-forget`
|
|
425
|
+
`entwurf_v2` / `runEntwurfV2` is the canonical v2 dispatch verb over **existing** garden targets — record-backed citizens only (#50 C4: the record is the sole address authority; a record-less control socket rejects pre-probe as `record-less-socket`, a diagnostic state, never a delivery target). You give a target garden id plus an intent (`fire-and-forget` — the axis is single-valued since the visible-first cut); one decider reads the target's liveness as a fact and picks the transport from a frozen table keyed on **both** the target's state **and** the intent — never on state alone — then reports one outcome under the v2 lock policy. A **control-socket-domain** dispatch takes a per-target lock; mailbox and native-push are lock-free, with deliverability guarded by their own receiver/probe evidence:
|
|
423
426
|
|
|
424
427
|
| target state | intent | transport |
|
|
425
428
|
|---|---|---|
|
|
426
429
|
| live pi | fire-and-forget | control-socket send |
|
|
427
|
-
|
|
|
428
|
-
|
|
|
429
|
-
| dormant pi | fire-and-forget | **reject** (`dormant-fire-forget-unsupported`) |
|
|
430
|
+
| dormant pi | fire-and-forget | **reject** (`dormant-fire-forget-unsupported` — nothing is launched) |
|
|
431
|
+
| any pi | indeterminate probe | **reject** (`indeterminate-no-spawn` — an unestablished probe is not a measured death) |
|
|
430
432
|
| active self-fetch receiver | fire-and-forget | meta-mailbox enqueue + doorbell |
|
|
431
433
|
| inactive / terminated self-fetch receiver | fire-and-forget | **reject** (`mailbox-undeliverable` — no `.msg`, no doorbell) |
|
|
432
|
-
| self-fetch | owned-outcome | **reject** (no owned result over a mailbox) |
|
|
433
434
|
| live native-push conversation | fire-and-forget | native-push direct injection |
|
|
434
435
|
| dead / indeterminate native-push conversation | fire-and-forget | **reject** (`native-push-target-dead` / `native-push-probe-indeterminate`) |
|
|
435
|
-
| native-push | owned-outcome | **reject** (`native-push-no-resume-authority`) |
|
|
436
436
|
| record-less control socket (no meta-record) | any | **reject** (`record-less-socket` — pre-probe; diagnostic state, #50 C4) |
|
|
437
437
|
|
|
438
438
|
**`entwurf_v2` is the canonical surface for garden-id delivery.** When you have a garden id and want to reach whoever it names — message, reply, or hand-off — `entwurf_v2` is the one surface that reads whether the target is live pi, dormant pi, mailbox-backed Claude Code, or native-push Antigravity and routes correctly; *when unsure which transport, use `entwurf_v2`*. This prevents callers from guessing a rail from the shape of an id.
|
|
439
439
|
|
|
440
|
-
What v2 provides is a **deterministic dispatch substrate** that moves the "which transport?" decision out of the fallible caller/model and into the decider, with transport-appropriate locking and an honest reject (no `✓ delivered`, no `.msg` garbage) when a target cannot receive.
|
|
440
|
+
What v2 provides is a **deterministic dispatch substrate** that moves the "which transport?" decision out of the fallible caller/model and into the decider, with transport-appropriate locking and an honest reject (no `✓ delivered`, no `.msg` garbage) when a target cannot receive. It still does **not** mint siblings, and it does not relaunch one either: every row above either reaches a citizen that is already running or refuses. Reopening a dormant pi citizen is `entwurf_resume_call`, a separate lifecycle verb that never routes through this decider. Fresh creation is the separate `entwurf_fresh_call` verb. It opens one fixed Pi or Claude Code runtime visibly in the caller's tmux session with a required explicit model passed in that runtime's measured CLI dialect, returns only a synchronous launch receipt, and lets the sibling report its new address asynchronously through the sender envelope of a nonce callback. The meta-mailbox row requires an **active** self-fetch receiver; native-push requires a record-backed, probe-alive native conversation and never borrows mailbox state. The [mux launch lane](./docs/mux-launch-rail.md) owns placement, fixed-runtime launch, and the two narrow compositions above it (fresh-call and resume-call placement); delivery does not import launch, and mux is not a delivery transport.
|
|
441
441
|
|
|
442
442
|
A live pi target is *reached* over its control socket, but the socket is dispatch-internal transport, never identity (#50 C4). A control socket that no meta-record claims — a pre-record-era resident, an unreadable store, or a stale/planted file — is refused for **every** intent as `record-less-socket`, and the reject names the fix (restart the resident so `session_start` births its record, or quiesce and run the fresh-cut). `entwurf_peers` reports the same state as an aggregated `record-less-socket` diagnostic rather than a peer row.
|
|
443
443
|
|
|
@@ -451,7 +451,7 @@ A `--entwurf-control` session needs **no special launcher** (#50 C2): pi mints i
|
|
|
451
451
|
pi --entwurf-control
|
|
452
452
|
```
|
|
453
453
|
|
|
454
|
-
**Resuming an existing garden session.**
|
|
454
|
+
**Resuming an existing garden session.** Use `entwurf_resume_call {target}`. It reopens a DORMANT pi citizen under the SAME garden id in a visible window in the caller's own tmux session, resolving the transcript, model, provider and cwd from the record — so it takes only the target id, and it runs no turn: the window comes back with the conversation and waits, and talking to it is still `entwurf_v2`. Two receipts arrive and mean different things: a LAUNCH receipt (tmux made a window and was asked to start pi) and an OBSERVATION receipt (the control socket answered under the same id, or `resume-unobserved`). Unobserved is a real outcome, not an error to retry — the window is visible, so read it. A citizen that is already live is refused; so is a non-pi target (`target-not-pi`), because only pi stands a control socket up. The predecessor, `entwurf_v2 intent=owned-outcome`, resumed by launching a hidden window-less background child and was withdrawn under the visible-first rule; delivery still starts no process. Identity preconditions live in `resume-launch-identity.ts`, gated by `check-resume-launch-identity`.
|
|
455
455
|
|
|
456
456
|
**Starting a new session in-process — pi's own `/new`.** Since the #50 C2 cut there is nothing to replace it with: `/new`, `/fork`, `/clone` and RPC session replacement are pi's again. The replacement session fires `session_start`, which upserts its own meta-record and rebinds the control socket to that record's garden id; the old socket is dropped. pi's session id (a uuidv7) is recorded as the citizen's `nativeSessionId` and is never an address. Gate: `run.sh smoke-resident-garden-guard` REPLACEMENT section (0-token RPC E2E).
|
|
457
457
|
|
|
@@ -475,7 +475,7 @@ The footer uses ACP `usage_update.used / size` (backend prompt/tools/cache/sessi
|
|
|
475
475
|
|
|
476
476
|
Owns: provider registration (`entwurf/...`), ACP subprocess lifecycle + `resume > load > new`, prompt forwarding + ACP event mapping, the bridge surface that exposes pi capabilities such as entwurf to ACP-backed sessions, pi-facing MCP injection via `entwurfProvider.mcpServers`, and bridge-local cleanup and diagnostics.
|
|
477
477
|
|
|
478
|
-
Does not: reconstruct full history, hydrate backend transcripts into pi history, emulate Claude Code or Codex, run broad multi-agent orchestration (entwurf is narrow,
|
|
478
|
+
Does not: reconstruct full history, hydrate backend transcripts into pi history, emulate Claude Code or Codex, run broad multi-agent orchestration (entwurf is narrow, record-addressed, identity-locked), or run a second session model competing with pi.
|
|
479
479
|
|
|
480
480
|
Only `pi:<sessionId>` mappings are persisted (`~/.pi/agent/cache/entwurf/sessions/`) — enough to re-attach pi to the same remote ACP session, never enough to act as a second harness. Backend stores (`~/.claude/`, `~/.codex/`) are interoperability side effects, not authority.
|
|
481
481
|
|