v0.11.0
0.11.0. The entwurf v2 dispatch substrate (#35): a single additive verb,
entwurf_v2/runEntwurfV2, that unifies dispatch to existing garden citizens behind one decider which reads peer liveness as a fact and picks transport from a frozen table keyed on target state AND intent (not state alone): live pi + fire-and-forget → control-socket send, dormant pi + owned-outcome → spawn-bg resume, active self-fetch + fire-and-forget → meta-mailbox enqueue; every other state×intent pair (live+owned, dormant+fire-and-forget, self-fetch+owned) is an honest reject. It does not mint new siblings — fresh sibling creation stays the v1entwurfverb (0.12 cutover lane); thespawn-bg resumerow resumes an already-identified dormant citizen, it does not create one. Built bottom-up as pi-only TypeScript substrate (Stage 0): contract freeze → per-gid dispatch lock → pure decider → release-policy reducer → send/spawn hands → production deps assembly → pi-native + MCPentwurf_v2tool. On top of it the spawn-bg resident lifecycle — the headline guarantee of #35 — was proven LIVE for the first time (a realpi --entwurf-controlchild stands its socket up, resumes a dormant Entwurf session, and does a model turn), and that first LIVE run surfaced and closed a production contradiction in the resident-name guard. Finally a v2-only mode (PI_SHELL_ACP_V2_ONLY=1) hard-refuses every v1 entrypoint so v1 can be turned off ahead of its 0.12 removal. Scope is Stage 0 (pi-only substrate); Stage 1 (Claude↔Claude live) is explicitly out of scope. Release-gate restructured before the cut (2026-06-16): the pi floor was bumped to>=0.79.4(runtime parity) and the live gate was split into a two-tier MUST (release-blocking, owns the exit code) + BEHAVIOR (advisory, model-in-loop autonomous MCP tool-selection) summary. The prior flatLIVE=1 → PASS=18run (log…20260615T152058) predates BOTH changes and no longer describes the current tree. FreshLIVE=1 release-gateon the 0.79.4 + two-tier tree (2026-06-16, log…20260616T141023):MUST PASS=17 FAIL=0 SKIP=0(necessary condition met) +BEHAVIOR PASS=1 FAIL=1— the lone BEHAVIOR-FAIL issentinel(cell4/5S7Bash-bypass, advisory/non-blocking); resident-garden-guard positives flipped FAIL→PASS vs the earlier run with zero code change, confirming the advisory scoping. "green" applies to the MUST tier only.
Added (0.11.0 entwurf v2 — unified dispatch verb)
entwurf_v2/runEntwurfV2— one additive dispatch verb over three transports. The decider reads a peer's liveness as a fact (theentwurf_peersfact surface) and chooses transport from a frozen table keyed on state AND intent: alive pi + fire-and-forget → control-socket send, dormant pi + owned-outcome → spawn-bg resume, active/deliverable self-fetch + fire-and-forget → meta-mailbox enqueue; the complementary pairs (live + owned, dormant + fire-and-forget, self-fetch + owned, inactive self-fetch + fire-and-forget) are honest rejects, not silent fallbacks. Built as pure substrate first — the contract freeze, a per-gid lockfile primitive (F2), the pure decider, the release-policy reducer, the control-send + dead-control-send hands, the enqueue-only mailbox send body, the pure execute-router and the top-level decide→execute join — then surfaced as both a pi-native tool and an in-process MCP verb, plusdoctorsurface sanity and thePI_ENTWURF_PREFIX_ROOTSoperator-policy SSOT. Each slice landed behind its own deterministic gate.- v2 dispatch reachability + lock SSOT and a 3-cell LIVE matrix sentinel.
check-entwurf-v2-matrixis the reachability + lock-policy table;smoke-entwurf-v2-matrix-liveis a 3-cell LIVE sentinel (control / mailbox / guard) wired intorelease-gateafter the bridge check with an honestLIVE!=1skip.
Added (0.11.0 entwurf v2 — spawn-bg resident lifecycle, #35 headline)
smoke-entwurf-v2-spawn-resume-live— the full spawn-bg resident loop, proven LIVE (22 checks). A real saved Entwurf session is resumed by a detachedpi --entwurf-controlchild that stands its control socket up, does a model turn (nonce echoed in both the user and assistant turns of the session JSONL), releases its dispatch lock exactly once, and cleans up with zero litter. This is the first time the production spawn path (a detachedspawn()pi resident — not the v1 tmux smoke fixture) was exercised end to end, closing the acceptance debt step 5c-3c had deferred to "the matrix proves it."PI_SHELL_ACP_V2_RESUME_RESIDENT_SESSION_ID— sessionId-bound authorized Entwurf-child resident. The first LIVE run surfaced a production contradiction: a v2 spawn-bg resume launches its child with--entwurf-control, butmaybeSetResidentNamerefused anyentwurf-tagged resident (the tag is theentwurf_resumemarker), so the resume self-terminated before doing any work. Resolved by narrowing the invariant, not dropping it: operator residents still reject theentwurftag, but a v2 spawn-bg resume child is authorized by the sessionId-bound marker its launcher plants, keeps its tag, and stays re-resumable. The marker is a zero-import leaf so it is root-safe from both the.js-import (entwurf-control) and.ts-import (entwurf-v2-spawn-production) compilation worlds.
Added (0.11.0 entwurf v2 — v2-only mode)
PI_SHELL_ACP_V2_ONLY=1— hard-refuse every v1 entwurf entrypoint ahead of v1 removal. A zero-import leaf helper (entwurf-v2-only.ts:isV2OnlyModetrue only for exact"1",checkV1EntwurfAllowedpure return,assertV1EntwurfAllowedthrow wrapper) is the single source of truth; whenPI_SHELL_ACP_V2_ONLY=1, each of the 10 v1 entrypoints (9 surface groups —/entwurftool + command count as two) refuses before any side effect through its own existing hard-refusal channel (tool throw, command notify, isError result, RPCrespond(false), startup error report, MCPtextErr). The MCPentwurf_resumehandler and the control RPCspawn_async_resumeare both guarded so the socket path cannot bypass the MCP guard. v1 code is neither deleted nor unregistered — invocation refusal only; the 11-scenario v2 replacement and v1 removal are the 0.12 lane.check-entwurf-v2-only(28 checks) proves the helper contract, all 10 guard sites, the double guard, and that theentwurf_v2core stays flag-clean.
Added (0.11.0 entwurf v2 — fact surface)
listEntwurfFacts/entwurf_peers— the entwurf fact surface (4-value liveness). A purePeerFactcore (garden citizens from meta-records + record-less control sockets, each with alive / dead / indeterminate / unsupported liveness) assembled bottom-up with socket-axis hardening (symlink / dir-read / malformed diagnostics). It reports facts, never routing verbs — the dispatch decision is computed later by the v2 contract, not here.
Added (0.11.0 meta — delivery authority on v2 identity + trust)
- Meta delivery authority cut to v2 identity + state store (3D-2 … 3D-4). A v2 identity-normalization gate, a dual-read identity seam with delivery-agnostic consumers, the live mailbox receipt dual-write to the state store, and backend capability sourced from the registry rather than a const. The
entwurf_v2contract surface was frozen and gated before the verb was wired (step 4-pre). project_trusthandler + inherited-trust preflight (Trust 2층). The pi trust preflight carries inherited-trust evidence and a deny formatter (F5a/N3b); aproject_trusthandler adds an inherited-distrust escape.
Added (0.11.0 entwurf v2 — SE active-receiver deliverability)
- The SE-1/SE-2 deliverability seam — honest pi-native + meta-self replyability. A meta-receiver presence marker, MCP + pi-native
entwurf_sendmailbox-fallback gates, amailboxConversationalDeliverablepredicate, a guarded mailbox-enqueue wrapper, and the required v2 active-receiver deliverability seam, so a send to a deliverable self-fetch meta citizen (an active-receiver claude-code session) with no live socket can fall back to the mailbox transport, while direct-inject (pi) and inactive-receiver targets reject without leaving mailbox garbage instead of falsely succeeding.
Fixed (0.11.0 entwurf v2 — deliverability honesty, consumer-visible)
entwurf_send/entwurf_selfstop reporting false delivery to unreachable targets. Previously a send to a citizen with no live control socket, or areplyable: trueself-report, could be emitted even when the target could not actually receive — a socketless / record-less pi session, an inactive (human-terminated) meta receiver, or a direct-inject (pi) target — leaving a✓ deliveredsignal and stray.msgmailbox files behind. Now such targets are rejected honestly (no enqueue, no mailbox garbage), andentwurf_selfreportsreplyable: trueonly when a real inbound path exists. This is an observable change forentwurf_send/entwurf_selfconsumers, but it is a honesty bug-fix, not a behavior regression — a previously "successful" send to a dead/inactive target was always a false positive. Gates:check-entwurf-deliverability,check-entwurf-mailbox-guard,check-entwurf-self-address.entwurf_v2now reaches a record-less but live pi control socket (socket-only fire-and-forget target).entwurf_peerslists a livepi --entwurf-controlsession as alive whether or not it has a meta-record, but the v2 productionresolveTargetpreviously rejected any record-less gid asbad-target— so anentwurf_v2to an operator-greeted live pi peer failed while a legacyentwurf_sendto the same gid succeeded (a fact-surface ↔ dispatch contract gap; thebad-targetwas masked whenever a caller fell back to v1). v2 now accepts a record-LESS gid whose canonical control socket is a confirmed non-symlink socket as a socket-only pi endpoint: a PROBE-FREE presence hint (one lstat, no connect — the sharedsocket-discoveryclassifier, so listing and dispatch cannot drift) promotes it to afire-and-forgetcontrol-send target only. It is never an owned citizen — with no record there is no cwd/launch authority, soowned-outcomeis refused before any lock and spawn-bg can never open into it; a record-less dormant resume stays out of scope (0.11.1). Gates:check-entwurf-v2-decider(socket-only fire-and-forget execute / owned-outcome pre-lockbad-target/ dormant·indeterminate honest reject, never a spawn),check-entwurf-v2-production(record-absent + live socket → execute; symlink/absent →bad-target).- Mailbox payload guidance is now explicit at the tool schema boundary.
entwurf_sendandentwurf_v2message fields carry a broad hard cap (maxLength: 16000) plus guidance to send one compact atomic message; larger reviews/logs should be written as a file/artifact and sent as a path plus digest. This avoids encouraging multi-part chat sends on a self-fetch mailbox whose doorbell is edge-triggered and may coalesce. The pairedsmoke-meta-mailboxregression now proves the honest residual guarantee: if multiple.msgbodies do queue up, oneentwurf_inbox_readdrains the whole backlog in order, stamps one read receipt, archives every body, and re-read is empty. This is drain-scoped evidence, not a claim that every rapid send gets its own doorbell wake.
Changed (0.11.0 — entwurf surface affordance, consumer-visible)
entwurf_v2is now the canonical garden-id delivery surface;entwurf_sendis demoted to a lower-level direct-send compat tool (tool descriptions reworded). A live incident exposed a surface affordance bug, not a function bug: when an agent holds a garden id and bothentwurf_sendandentwurf_v2are visible, the name "send" pulls it toentwurf_send— but a bare garden id does not reveal whether the target is a live pi session or a Claude Code meta-session, so the agent picks the wrong transport and fails (it poked a live-socket path at a meta-session that needed the mailbox). The fix is at the affordance layer: theentwurf_v2tool description (MCP + pi-native) now leads with "canonical delivery surface for garden ids — when unsure which transport, useentwurf_v2", and theentwurf_senddescription (MCP + pi-native) now leads with "lower-level direct control-socket compat tool; for garden-id delivery preferentwurf_v2; use this only with a known live pi socket / forget_message·cleardebug". README's ACP-backed tool list now includesentwurf_v2+entwurf_inbox_readand states the rule plainly: send/reply →entwurf_v2, create → v1entwurf. No runtime dispatch behavior changed — this is description/affordance + docs only (no deterministic gate snapshots the description text; re-validated bypnpm check). The deeper convergence (foldingentwurf_senddelivery intoentwurf_v2, keeping only its debug actions, or unregistering v1 send under v2-only mode) is a 0.11.x /entwurf-repo lane.
Changed (0.11.0 — dependencies)
- pi floor bumped to 0.79.4 (runtime parity). Requires pi >= 0.79.4 (
@earendil-works/pi-ai/pi-coding-agent/pi-tuipeer floor>= 0.79.4; devDep pins, lockfile, thecheck-pi-runtime-versionFLOOR constant, and thecheck-pack-installpeer pins all moved to0.79.4so the repo-local deterministic gates and the operator pi runtime stop diverging). 0.79.4 was confirmed to carry no deterministic regression vs 0.79.3 (probe + forced spawn A/B); the floor bump is a transport/API-compatibility statement, not a claim that 0.79.4's model-in-loop behavior is fully deterministic — Claude Sonnet's MCP-vs-Bash autonomous tool-selection remains non-deterministic and is tracked in the release-gate BEHAVIOR lane (below). The substrate carries typecheck-fence and runtime guards that keep the.ts/.jsdual-import worlds honest undernode --experimental-strip-types. release-gatesplit into a two-tier MUST + BEHAVIOR summary. The single flat must-pass list was divided so that v1/v2 function (deterministic + programmatic gates:pnpm check,smoke-async-resume,smoke-entwurf-resume,check-native-async,check-bridge, the v2 matrix/spawn-resume LIVE gates, the resident-garden-guard negative/id-safety + /gnew zero-token half, …) stays release-blocking (MUST, owns the exit code), while the v1 behavior probes that depend on the model autonomously driving the MCP entwurf surface —sentinel(6-cell diagonal spawn) and resident-garden-guard positive (post-/gnewentwurf_selfidentity turn + positive garden model turn) — move to an advisory BEHAVIOR lane that is surfaced but never blocks the cut. This is a v1 behavior advisory, not "v1 unsupported/broken": the v1 tools themselves remain proven by the MUST programmatic gates. The S7 Bash-bypass detector (sentinel-runner.sh) stays a hard FAIL inside the BEHAVIOR lane — a Bash/Terminal/pi-CLI bypass is never relabelled a pass, only made non-blocking. A residual bypass after prompt strengthening is a 0.11.x usability item, not a 0.11.0 blocker. Rationale: the BEHAVIOR lane is new 0.11-era coverage (sentinel entered the release-gate6592c5f5/29; resident-garden-guard/T3440afba/7d453466/4) — it did not regress, it newly measured a v1 model-in-loop weakness the older gate never looked at.
Deprecated
plugins/openclawis deprecated and unmaintained (2026-06-10). The OpenClaw plugin layer no longer has a reason to exist: Claude and Gemini now support ACP natively (Claude on a credit basis from 2026-06-15), so routing them through an OpenClaw wrapper buys nothing. The pi-shell-acp bridge itself is unaffected and continues to support Claude / Codex / Gemini directly — only the OpenClaw adapter context changed. The npm package@junghan0611/openclaw-pi-shell-acp@0.0.1is marked deprecated on the registry (not unpublished); the source underplugins/openclawis frozen for reference. No further ClawHub / npm publishing. (The@junghanacsClawHub publisher handle was separately recovered via clawhub#2346 and is retained for other uses.)