@junghanacs/entwurf 0.12.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 +240 -0
- package/BASELINE.md +227 -0
- package/CHANGELOG.md +1210 -0
- package/CONTRIBUTING.md +63 -0
- package/DELIVERY.md +209 -0
- package/LICENSE +21 -0
- package/README.md +504 -0
- package/VERIFY.md +260 -0
- package/demo/README.md +188 -0
- package/demo/demo-baseline.sh +156 -0
- package/demo/demo.sh +183 -0
- package/docs/assets/entwurf-demo.gif +0 -0
- package/docs/assets/entwurf-doomemacs.gif +0 -0
- package/docs/assets/entwurf-entwurf.gif +0 -0
- package/docs/assets/entwurf-hero.jpg +0 -0
- package/docs/setup-clean-host.md +305 -0
- package/mcp/entwurf-bridge/src/index.ts +513 -0
- package/mcp/entwurf-bridge/start.sh +25 -0
- package/mcp/entwurf-bridge/test.sh +54 -0
- package/mcp/tsconfig.json +29 -0
- package/package.json +130 -0
- package/pi/entwurf-capabilities.json +9 -0
- package/pi/entwurf-targets.json +20 -0
- package/pi/meta-bridge/.claude-plugin/marketplace.json +12 -0
- package/pi/meta-bridge/entwurf-meta-receive/.claude-plugin/plugin.json +5 -0
- package/pi/meta-bridge/entwurf-meta-receive/hooks/hooks.json +50 -0
- package/pi/meta-bridge/entwurf-meta-receive/scripts/doorbell.sh +54 -0
- package/pi/settings.reference.json +43 -0
- package/pi/skill-plugin-example/.claude-plugin/plugin.json +4 -0
- package/pi/skill-plugin-example/skills/hello/SKILL.md +18 -0
- package/pi-extensions/acp-provider.ts +63 -0
- package/pi-extensions/entwurf-control.ts +1692 -0
- package/pi-extensions/lib/acp/acp-client.ts +90 -0
- package/pi-extensions/lib/acp/augment.ts +238 -0
- package/pi-extensions/lib/acp/backend-adapter.ts +319 -0
- package/pi-extensions/lib/acp/backend.ts +873 -0
- package/pi-extensions/lib/acp/config.ts +552 -0
- package/pi-extensions/lib/acp/context.ts +177 -0
- package/pi-extensions/lib/acp/engraving.ts +123 -0
- package/pi-extensions/lib/acp/event-mapper.ts +339 -0
- package/pi-extensions/lib/acp/models.ts +102 -0
- package/pi-extensions/lib/acp/overlay.ts +220 -0
- package/pi-extensions/lib/acp/prompts/engraving.md +1 -0
- package/pi-extensions/lib/acp/session-store.ts +418 -0
- package/pi-extensions/lib/acp/tool-surface.ts +184 -0
- package/pi-extensions/lib/entwurf-control-rpc.ts +208 -0
- package/pi-extensions/lib/entwurf-core.ts +2033 -0
- package/pi-extensions/lib/entwurf-deliverability.ts +123 -0
- package/pi-extensions/lib/entwurf-fact-provider.ts +158 -0
- package/pi-extensions/lib/entwurf-facts.ts +251 -0
- package/pi-extensions/lib/entwurf-mailbox-guard.ts +100 -0
- package/pi-extensions/lib/entwurf-peers-render.ts +154 -0
- package/pi-extensions/lib/entwurf-preflight.ts +247 -0
- package/pi-extensions/lib/entwurf-resume-args.ts +88 -0
- package/pi-extensions/lib/entwurf-self-address.ts +117 -0
- package/pi-extensions/lib/entwurf-v2-contract.ts +427 -0
- package/pi-extensions/lib/entwurf-v2-decider.ts +441 -0
- package/pi-extensions/lib/entwurf-v2-lock.ts +412 -0
- package/pi-extensions/lib/entwurf-v2-mailbox.ts +87 -0
- package/pi-extensions/lib/entwurf-v2-production.ts +326 -0
- package/pi-extensions/lib/entwurf-v2-release.ts +149 -0
- package/pi-extensions/lib/entwurf-v2-resume-marker.ts +34 -0
- package/pi-extensions/lib/entwurf-v2-runner.ts +196 -0
- package/pi-extensions/lib/entwurf-v2-send-fallback.ts +166 -0
- package/pi-extensions/lib/entwurf-v2-send.ts +271 -0
- package/pi-extensions/lib/entwurf-v2-spawn-production.ts +337 -0
- package/pi-extensions/lib/entwurf-v2-spawn.ts +323 -0
- package/pi-extensions/lib/entwurf-v2-surface.ts +205 -0
- package/pi-extensions/lib/meta-mailbox-body.ts +80 -0
- package/pi-extensions/lib/meta-session.ts +1951 -0
- package/pi-extensions/lib/project-trust-handler.ts +154 -0
- package/pi-extensions/lib/session-id.js +57 -0
- package/pi-extensions/lib/socket-discovery.ts +346 -0
- package/pi-extensions/lib/socket-probe.ts +92 -0
- package/pi-extensions/meta-bridge-hook.ts +250 -0
- package/pi-extensions/model-lock.ts +235 -0
- package/prompts/engraving.md +27 -0
- package/protocol.js +31 -0
- package/run.sh +2832 -0
- package/scripts/check-acp-backend-preflight.ts +130 -0
- package/scripts/check-acp-carrier-augment.ts +297 -0
- package/scripts/check-acp-config.ts +322 -0
- package/scripts/check-acp-event-mapper.ts +253 -0
- package/scripts/check-acp-overlay.ts +154 -0
- package/scripts/check-acp-prompt-builder.ts +191 -0
- package/scripts/check-acp-provider-surface.ts +159 -0
- package/scripts/check-acp-sdk-surface.ts +211 -0
- package/scripts/check-acp-session-reuse.ts +756 -0
- package/scripts/check-acp-session-store.ts +387 -0
- package/scripts/check-acp-tool-surface.ts +159 -0
- package/scripts/check-entwurf-bridge-boot.ts +199 -0
- package/scripts/check-entwurf-capabilities.ts +123 -0
- package/scripts/check-entwurf-control-rpc.ts +187 -0
- package/scripts/check-entwurf-deliverability.ts +158 -0
- package/scripts/check-entwurf-fact-provider.ts +316 -0
- package/scripts/check-entwurf-facts.ts +358 -0
- package/scripts/check-entwurf-mailbox-guard.ts +264 -0
- package/scripts/check-entwurf-peers-surface.ts +235 -0
- package/scripts/check-entwurf-resume-args.ts +149 -0
- package/scripts/check-entwurf-self-address.ts +209 -0
- package/scripts/check-entwurf-session-identity.ts +703 -0
- package/scripts/check-entwurf-v2-contract.ts +536 -0
- package/scripts/check-entwurf-v2-decider.ts +795 -0
- package/scripts/check-entwurf-v2-lock.ts +368 -0
- package/scripts/check-entwurf-v2-mailbox.ts +228 -0
- package/scripts/check-entwurf-v2-matrix.ts +437 -0
- package/scripts/check-entwurf-v2-production.ts +406 -0
- package/scripts/check-entwurf-v2-release.ts +245 -0
- package/scripts/check-entwurf-v2-runner.ts +452 -0
- package/scripts/check-entwurf-v2-send-fallback.ts +371 -0
- package/scripts/check-entwurf-v2-send.ts +454 -0
- package/scripts/check-entwurf-v2-spawn-production.ts +452 -0
- package/scripts/check-entwurf-v2-spawn.ts +398 -0
- package/scripts/check-entwurf-v2-surface.ts +352 -0
- package/scripts/check-keyset-overlap.py +120 -0
- package/scripts/check-mailbox-receipt-state.ts +170 -0
- package/scripts/check-meta-capability-source.ts +112 -0
- package/scripts/check-meta-dual-consumers.ts +154 -0
- package/scripts/check-meta-dual-read.ts +158 -0
- package/scripts/check-meta-listing.ts +138 -0
- package/scripts/check-meta-mailbox-state-write.ts +135 -0
- package/scripts/check-meta-migration.ts +212 -0
- package/scripts/check-meta-receiver-marker.ts +185 -0
- package/scripts/check-meta-record-v2.ts +191 -0
- package/scripts/check-meta-session.ts +673 -0
- package/scripts/check-model-lock.ts +408 -0
- package/scripts/check-package-source-routing.ts +253 -0
- package/scripts/check-pi-preflight.ts +304 -0
- package/scripts/check-project-trust-handler.ts +265 -0
- package/scripts/check-shell-quote.ts +121 -0
- package/scripts/check-socket-discovery.ts +428 -0
- package/scripts/check-socket-probe.ts +106 -0
- package/scripts/fixtures/probe-mcp-server.ts +33 -0
- package/scripts/gnew-rpc-drive.ts +211 -0
- package/scripts/lib/acp-child-cleanup.ts +116 -0
- package/scripts/meta-bridge-doctor.sh +315 -0
- package/scripts/meta-bridge-hook-log.sh +26 -0
- package/scripts/meta-bridge-install.sh +135 -0
- package/scripts/meta-bridge-prune.ts +199 -0
- package/scripts/meta-bridge-state.py +549 -0
- package/scripts/meta-bridge-statusline.sh +192 -0
- package/scripts/meta-bridge-store-doctor.ts +64 -0
- package/scripts/meta-bridge-uninstall.sh +39 -0
- package/scripts/new-session-id.ts +25 -0
- package/scripts/postinstall-chmod.cjs +58 -0
- package/scripts/raw-async-delivery/README.md +258 -0
- package/scripts/raw-async-delivery/cc-enqueue-addressed.sh +35 -0
- package/scripts/raw-async-delivery/cc-mailbox-rewake.sh +38 -0
- package/scripts/raw-async-delivery/cc-watch-filechanged.sh +19 -0
- package/scripts/raw-async-delivery/cc-watch-sessionstart.sh +15 -0
- package/scripts/raw-async-delivery/codex-local-appserver.sh +39 -0
- package/scripts/raw-async-delivery/plugin-entwurf-receive/.claude-plugin/plugin.json +5 -0
- package/scripts/raw-async-delivery/plugin-entwurf-receive/hooks/hooks.json +28 -0
- package/scripts/raw-async-delivery/plugin-entwurf-receive/scripts/watch-filechanged.sh +28 -0
- package/scripts/raw-async-delivery/plugin-entwurf-receive/scripts/watch-sessionstart.sh +27 -0
- package/scripts/raw-async-delivery/raw-agy-send.sh +29 -0
- package/scripts/raw-async-delivery/raw-claude-enqueue.sh +30 -0
- package/scripts/raw-async-delivery/raw-codex-ws-turn-start.py +164 -0
- package/scripts/raw-async-delivery/repro-addressed-routing.sh +96 -0
- package/scripts/raw-async-delivery/repro-plugin-idle-wake.sh +104 -0
- package/scripts/resolve-acp-bridge.ts +25 -0
- package/scripts/smoke-acp-bundled-mcp-live.ts +292 -0
- package/scripts/smoke-acp-carrier-augment-live.ts +192 -0
- package/scripts/smoke-acp-mcp-live.ts +129 -0
- package/scripts/smoke-acp-memory-containment-live.ts +389 -0
- package/scripts/smoke-acp-overlay-live.ts +314 -0
- package/scripts/smoke-acp-provider-live.ts +162 -0
- package/scripts/smoke-acp-raw-turn-live.ts +261 -0
- package/scripts/smoke-acp-session-reuse-live.ts +172 -0
- package/scripts/smoke-acp-skill-live.ts +144 -0
- package/scripts/smoke-acp-socket-citizen-live.ts +168 -0
- package/scripts/smoke-claude-native-resume-live.sh +198 -0
- package/scripts/smoke-entwurf-v2-matrix-live.ts +398 -0
- package/scripts/smoke-entwurf-v2-spawn-live.ts +175 -0
- package/scripts/smoke-entwurf-v2-spawn-resume-live.ts +428 -0
- package/scripts/smoke-meta-async-drift.sh +171 -0
- package/scripts/smoke-meta-honesty.sh +147 -0
- package/scripts/smoke-meta-install-state.sh +403 -0
- package/scripts/smoke-meta-keyset-guard.sh +111 -0
- package/scripts/smoke-meta-prune.sh +174 -0
- package/scripts/smoke-resident-garden-guard.sh +433 -0
- package/scripts/smoke-session-id-name.ts +187 -0
- package/scripts/tsconfig.json +34 -0
package/AGENTS.md
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# AGENTS.md — Maintainer Guidelines for entwurf
|
|
2
|
+
|
|
3
|
+
For agents that own this repo: invariant principles + reproducible verification, not release-story drift.
|
|
4
|
+
|
|
5
|
+
> **Direction (read first).** This repo is the **entwurf capability package**:
|
|
6
|
+
> a v2 garden-citizen dispatch substrate (entwurf-core) + a meta-bridge + an
|
|
7
|
+
> ACP plugin + the pi adapter that hosts it today. v1 entwurf verbs are done
|
|
8
|
+
> and gone; v2 is the spine. ACP is **not** the project's center — it is one
|
|
9
|
+
> **plugin** that enters as a provider/model on a host `--entwurf-control`
|
|
10
|
+
> pi session — which is *already* a v2 socket-citizen — rather than minting
|
|
11
|
+
> citizens of its own (#38: *"ACP is a plugin, not the boundary."*).
|
|
12
|
+
> Package/repo/runtime identity is now `entwurf`; pi remains an
|
|
13
|
+
> adapter/runtime contract, not the center. The deferred #38 coordinate is a
|
|
14
|
+
> later physical extraction of entwurf-core into a separate repo, not this
|
|
15
|
+
> rename. Fresh sibling minting (the old v1 `entwurf` verb) stays deferred —
|
|
16
|
+
> see the branch NEXT.
|
|
17
|
+
|
|
18
|
+
## North Star — One Forged Screwdriver
|
|
19
|
+
|
|
20
|
+
`entwurf`를 만질 때 먼저 이 형상을 붙든다.
|
|
21
|
+
이 저장소는 스위스 아미 나이프가 아니다. 두 번째 하네스도 아니다.
|
|
22
|
+
이것은 **담금질된 드라이버 한 자루**다. 작고, 명시적이고, 자기가 맡은 접점에서만 강해야 한다.
|
|
23
|
+
|
|
24
|
+
영문 원칙만 읽으면 이것이 스펙처럼 보일 수 있다. 여기서는 그렇게 읽지 마라.
|
|
25
|
+
이 섹션은 기능 목록이 아니라 **판단의 중심축**이다.
|
|
26
|
+
|
|
27
|
+
### 먼저 붙들 정체성
|
|
28
|
+
|
|
29
|
+
- **entwurf가 주어이고 pi는 한 adapter다.** pi는 지금 이 repo가 가장 깊게 붙어 있는 하네스지만 4번째 하네스일 뿐이다. 이 repo는 pi의 세션 모델, transcript, UI, tool semantics와 경쟁하지 않는다.
|
|
30
|
+
- **다른 하네스의 세션은 형제다.** Claude Code, Codex, Antigravity는 학교가 달라도 모두 frontier 친구들이다. meta-bridge는 그들을 garden id로 호명 가능한 citizen으로 등록할 뿐, 누구를 다른 누구로 위장시키지 않는다.
|
|
31
|
+
- **표면은 달라도 능력의 존엄은 낮추지 않는다.** 어떤 backend에서 `mcp__...`가 직접 보이지 않는다고 해서, 곧바로 그 backend를 "못하는 존재"로 취급하지 마라. 먼저 capability를 보고, 그 capability가 어떤 surface로 열리는지 확인하라.
|
|
32
|
+
- **substrate는 결정적 dispatch만 맡는다.** target liveness를 fact로 읽고, intent와 곱해 transport를 고른다. 그 이상 마술을 부리면 안 된다.
|
|
33
|
+
- **명시는 주변기류보다 강하다.** 숨겨진 transcript hydration, ambient MCP scanning, invisible tool claims, giant magical system prompt, 근거 없는 서사를 만들지 마라.
|
|
34
|
+
- **하네스의 도구 표면을 좁히는 것은 결핍이 아니라 규율이다.** entwurf가 backend를 몰 때(ACP Claude · pi-native 분신) 서브에이전트도 투두 도구도 없이 좁은 tool surface를 yolo로 돈다(ACP backend는 격리된 overlay 안에서) — pi에서 배운 **힣의 드라이버**다. backend가 못해서가 아니라, 한 자루 드라이버가 두 번째 오케스트레이터로 번지지 않게 하는 강제다. 이걸 강제해야 "힣의 드라이버를 쓴다"고 말할 수 있다. (backlog 형태는 `ROADMAP.md` tool narrowing.)
|
|
35
|
+
- **entwurf는 부속품이 아니라 분신을 연다.** spawn-bg resume된 세션은 runtime-isolated peer다. worker처럼 다루거나 권한 경계를 흐리지 마라.
|
|
36
|
+
- **증거가 말을 훈육한다.** README / AGENTS / CHANGELOG / VERIFY / BASELINE / runtime smoke가 받쳐주지 않으면, 작업을 중지하고 사용자에게 질문하라!
|
|
37
|
+
|
|
38
|
+
### 이 섹션을 읽는 올바른 방식
|
|
39
|
+
|
|
40
|
+
이 문단의 목적은 에이전트가 다음 질문을 **스스로** 하게 만드는 것이다.
|
|
41
|
+
|
|
42
|
+
- 나는 지금 tool 이름을 보고 있는가, 아니면 capability를 보고 있는가?
|
|
43
|
+
- 나는 backend의 비대칭을 정직하게 기록하고 있는가, 아니면 그것을 핑계로 형제성을 포기하고 있는가?
|
|
44
|
+
- 나는 사용자가 묻지 않아도 될 것을 되묻고 있는가?
|
|
45
|
+
- 나는 지금 두 번째 하네스를 만들고 있는가, 아니면 드라이버 한 자루를 더 단단하게 만들고 있는가?
|
|
46
|
+
|
|
47
|
+
### 금지할 오독
|
|
48
|
+
|
|
49
|
+
- 어떤 tool이 schema에 직접 안 보인다고 해서, 곧바로 "이 backend는 여기까지"라고 결론내리는 것
|
|
50
|
+
- surface 차이를 capability 포기로 번역하는 것
|
|
51
|
+
- 문서에 적힌 asymmetry를 면책조항처럼 사용하는 것
|
|
52
|
+
- `entwurf`를 하네스 런타임이나 범용 AI 작업실로 설명하는 것 — pi가 하네스 중 하나이고, 이 repo는 garden-citizen dispatch capability다
|
|
53
|
+
- MCP를 자동 맥락 검색이나 ambient tool scanning처럼 설명하는 것 — explicit injection만 허용된다
|
|
54
|
+
- `entwurf_v2`를 "새 분신을 만드는 도구"로 설명하는 것 — v2의 3 transport는 전부 **기존** garden citizen 대상이다. fresh sibling 생성은 0.12.x로 연기된 별개 능력이다
|
|
55
|
+
- 사용자가 이미 철학과 방향을 준 문제를 다시 사용자에게 되묻는 것
|
|
56
|
+
|
|
57
|
+
릴리즈 이야기와 개별 기능은 주변을 돈다.
|
|
58
|
+
중심은 언제나 이것이다: **thin substrate / explicit MCP / sibling-based entwurf / deterministic dispatch / observability / evidence-first language / capability dignity across sibling sessions**.
|
|
59
|
+
|
|
60
|
+
## What This Repo Is
|
|
61
|
+
|
|
62
|
+
An **entwurf garden-citizen dispatch substrate** + a **meta-bridge** + an **ACP plugin** + a **pi adapter**. Pi stays a harness/runtime, not the project center; every addressed session keeps its own identity.
|
|
63
|
+
|
|
64
|
+
- **Meta-bridge**: a global `SessionStart` hook registers a native-harness session (Claude Code / Codex / Antigravity) as a **garden-native meta-session** — a garden id, a mailbox, a trusted sender marker — without importing that harness's transcript or pretending pi owns it. Installed/inspected via `./run.sh install-meta-bridge` / `doctor-meta-bridge`.
|
|
65
|
+
- **v2 dispatch (`entwurf_v2`)**: one verb that delivers to / wakes an *already-identified* garden citizen. A pure decider reads target liveness as a fact and picks transport from a frozen table keyed on **target state × intent**: live pi + fire-and-forget → **control-socket** send; dormant pi + owned-outcome → **spawn-bg resume**; active self-fetch meta-session + fire-and-forget → **meta-mailbox** enqueue; every other state×intent pair is an honest reject. It does **not** mint new siblings.
|
|
66
|
+
- **ACP plugin** (one pi-adapter ingress): registers the package provider `entwurf` as a pi session provider/model and drives the chosen ACP backend (Claude first; vendor/governed CLIs like Cortex next) under an isolated config overlay. It owns the backend process, the overlay, and the per-backend ACP dialect — **not** socket-citizenship. The host `--entwurf-control` pi session that selected the ACP model is *already* a v2 socket-citizen; the plugin does **not** mint a socket / peers / citizen layer. It is not the substrate and not a second harness. v1 entwurf verbs (`entwurf` / `entwurf_resume` / `entwurf_send`) are gone for good; the ACP plugin is a fresh build on the v2 core (0.11.0's `acp-bridge.ts` is a behavior oracle, not architecture to re-center). See §ACP Plugin Boundary.
|
|
67
|
+
|
|
68
|
+
## Code Principle — Crash, Don't Warn
|
|
69
|
+
|
|
70
|
+
Code in this repo is used by agents as infrastructure.
|
|
71
|
+
|
|
72
|
+
> **Never warn. Throw.**
|
|
73
|
+
|
|
74
|
+
Warnings make agents blame themselves and flail. Broken tool state must surface as broken tool state.
|
|
75
|
+
|
|
76
|
+
- Bad config → throw (e.g. `McpServerConfigError`); same for bad path / bad model id. No fallback.
|
|
77
|
+
- `catch {}` only for environment probing (optional package detection, ldd exit code variance).
|
|
78
|
+
- `console.warn` only in stderr diagnostic lines (read by operators, not agents).
|
|
79
|
+
|
|
80
|
+
## Hard Rules
|
|
81
|
+
|
|
82
|
+
1. **One surface name, hard-cut cutover**: provider/model/routing strings are `entwurf`. No permanent runtime aliases, legacy provider-id accept, or dual-read of old state. If existing operator state must be helped across, do it as an explicit one-shot cutover or a documented break, never as hidden dual routing. The `provider:` routing strings (`getRegistryRouting`, `model-lock.ts`) are **load-bearing** — they are identity, not residue.
|
|
83
|
+
2. **Dispatch is a function of liveness, not session type.** `entwurf_v2` never asks "is this a resume or a send" up front — it probes liveness and routes: live→control-socket, dormant→spawn-bg resume, active self-fetch→meta-mailbox. State is computed, never stored (a stored liveness bit is a lie).
|
|
84
|
+
3. **A reject is honest, never cosmetic.** When a target cannot receive (dead, drifted identity, wrong state×intent), the decider returns a reject — no `✓ delivered`, no `.msg` written, no signal poke. Silent degraded "delivery" is forbidden.
|
|
85
|
+
4. **MCP injection**: only via explicit `mcpServers` wiring. No ambient `~/.mcp.json` scanning, no automatic retrieval.
|
|
86
|
+
5. **Meta-record authority is the record body, never the filename.** `scanByNativeId` scans `.meta.json` bodies, throws on duplicate `nativeSessionId` (authority ambiguity is fail-fast), and never derives identity from a filename. A meta-record is nullable-at-birth (`model`/`transcriptPath` null until known); a backend↔wakeMode contradiction is corrupt-and-crash.
|
|
87
|
+
6. **GC reclaims process resources only — never data.** meta-records and transcripts (the denote-id memory layer) are preserved; dormant/stale entries are archived/TTL'd, not deleted.
|
|
88
|
+
7. **This is not a second harness**: no prompt reconstruction, no transcript hydration, no tool result ledger, no harness emulation. The meta-bridge fronts a mailbox + a garden id; it does not scrape transcripts or run a control daemon for the native session.
|
|
89
|
+
8. **Auth boundary is deployment-surface-agnostic**. This repo does not provide, copy, proxy, decrypt, or mediate any backend's credentials. Native-harness sessions read whatever auth state is visible in their own process filesystem; nothing here moves that.
|
|
90
|
+
|
|
91
|
+
## ACP Plugin Boundary
|
|
92
|
+
|
|
93
|
+
`entwurf-core` (the v2 substrate) is the center; **ACP is one plugin**, never the boundary (#38). Plugins supply read-only facts the core already asks for; they do not become the core, a memory layer, or a second harness (#39).
|
|
94
|
+
|
|
95
|
+
| Layer | Owns |
|
|
96
|
+
|---|---|
|
|
97
|
+
| **entwurf-core (v2)** | garden id · peer identity · liveness fact interface · dispatch decision · delivery evidence · rail choice (socket / mailbox / spawn) |
|
|
98
|
+
| **ACP plugin** | ACP backend process lifecycle · config overlay (isolation + tool-narrowing + identity-carrier materialization) · per-backend ACP dialect quirks · backend health / turn evidence — **NOT** socket-citizen registration or liveness/addressability facts (those are the host `--entwurf-control` session's, supplied via socket-discovery) |
|
|
99
|
+
| **ACP plugin MUST NOT become** | a memory DB · a task planner · an orchestrator · a second harness · a mailbox-citizen impersonation |
|
|
100
|
+
|
|
101
|
+
- **Sibling equality is a citizen-level property, not a rail-level one.** Every sibling is addressable (peers-visible, garden-id-addressed, `entwurf_v2`-reachable, replyable). The *rail* differs by lifecycle: a live ACP backend is a **socket-citizen** (no mailbox — it is always live, so durable async delivery is unneeded, not withheld); a come-and-go native-harness session is a **mailbox-citizen**. Missing a mailbox is right-sizing, not discrimination.
|
|
102
|
+
- **Durable memory is the authored common record** (`~/org`, botlog, agenda, Denote, andenken). entwurf lets peers move across that record layer; it never replaces it.
|
|
103
|
+
- **ACP enters as a model/provider, not a socket layer.** The ACP plugin registers as a pi session's provider/model and spawns the backend under an overlay; **socket-citizenship is supplied by the host `--entwurf-control` pi session**, not minted by the plugin. The plugin never builds a new socket registry, peers layer, or citizen protocol — over-designing one is the failure mode to avoid (`socket-discovery` is model-agnostic, so an ACP-model session is already a citizen).
|
|
104
|
+
|
|
105
|
+
### Operating boundaries (trust invariants — survive any re-implementation, #15)
|
|
106
|
+
|
|
107
|
+
These claims must stay true on every install surface; they are the first thing a re-implementation silently drops, so they are pinned here:
|
|
108
|
+
|
|
109
|
+
- `entwurf` does **not** provide, resell, or bypass Claude/vendor credentials, tokens, or subscription access. It connects only to the operator's **existing local authenticated backend** through an explicit plugin boundary.
|
|
110
|
+
- No auth bypass, no subscription sharing, no hidden transcript restoration.
|
|
111
|
+
- Expert escape hatches are **explicit and documented**, never accidental backdoors.
|
|
112
|
+
- The plugin **fails loud / fails closed** when an invariant is broken.
|
|
113
|
+
|
|
114
|
+
## Verification
|
|
115
|
+
|
|
116
|
+
Two axes, both required.
|
|
117
|
+
|
|
118
|
+
**Deterministic + smoke gates** (`./run.sh`, wired into `pnpm check`):
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
pnpm typecheck # 3-config tsc fence (root + mcp + scripts)
|
|
122
|
+
pnpm check # full static floor: lint + typecheck + every check-*/smoke-* below
|
|
123
|
+
./run.sh check-entwurf-v2-matrix # the decider's state×intent table, read as an SSOT (REAL decideDispatch)
|
|
124
|
+
./run.sh check-entwurf-v2-decider # + -contract / -lock / -release / -send / -send-fallback / -mailbox / -runner / -production / -surface / -spawn / -spawn-production
|
|
125
|
+
./run.sh check-meta-session # + -record-v2 / -dual-read / -migration / -mailbox-state-write / -receiver-marker / -capability-source / -dual-consumers / -listing
|
|
126
|
+
./run.sh check-entwurf-bridge-boot # the MCP entwurf-bridge stands up + exposes the v2 tool set
|
|
127
|
+
./run.sh check-bridge /path/to/project # entwurf-bridge direct MCP smoke (tools/list + protocol/negative-path)
|
|
128
|
+
./run.sh check-auth-boundary # ACP plugin no-auth sentinel present + no legacy-ENV apiKey literal (trust invariant, code-level)
|
|
129
|
+
./run.sh check-acp-provider-surface # provider registers curated Claude anchor + streamSimple wired to the real streamShellAcp backend
|
|
130
|
+
# The legacy v1 ACP gates (sentinel / session-messaging / xt-tool-surface) and the
|
|
131
|
+
# v1-only meta smokes (smoke-meta-mailbox / smoke-meta-sender-identity, both calling
|
|
132
|
+
# the gone entwurf_send tool) were REMOVED in the 0.12 cutover (2026-06-27). Any
|
|
133
|
+
# re-test of those axes belongs on the entwurf_v2 surface as a fresh gate.
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Live release gate** (opt-in, owns the merge decision):
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
LIVE=1 ./run.sh release-gate /path/to/scratch # two-tier: MUST (release-blocking, owns exit code) + BEHAVIOR (advisory)
|
|
140
|
+
LIVE=1 ./run.sh smoke-acp-socket-citizen-live # S1: a real ACP-model --entwurf-control resident is a first-class socket-citizen (peers + get_info), turn-free (no backend, no stub fire)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
The MUST tier is the necessary condition ("green" = MUST PASS, FAIL=0); BEHAVIOR is advisory — the `smoke-resident-garden-guard` positives (a model-in-loop garden identity turn). Run every live gate with `PWD=scratch` so sessions never land in the repo's own session dir.
|
|
144
|
+
|
|
145
|
+
**Agent-driven verification** ([VERIFY.md](./VERIFY.md)): self-recognition/transcript agreement ≈ L1; objective MCP calls L2; on-disk/process L3; direct-native L4; soak L5.
|
|
146
|
+
|
|
147
|
+
If a gate fails or a claim drops below its needed evidence level, do not commit. Pipes can be connected and the water can still taste wrong.
|
|
148
|
+
|
|
149
|
+
## Entwurf
|
|
150
|
+
|
|
151
|
+
Uses `entwurf` instead of `delegate` to avoid ecosystem collisions. spawn-bg resume creates a sibling, not a worker.
|
|
152
|
+
|
|
153
|
+
- **Surface** — MCP `entwurf-bridge`: `entwurf_v2`, `entwurf_self`, `entwurf_peers`, `entwurf_inbox_read`. pi-native (`pi-extensions/entwurf-control.ts`): `entwurf_v2`, `entwurf_peers` tools + `/entwurf-sessions`, `/gnew` (`/garden-new`) commands. The v1 `entwurf` / `entwurf_resume` / `entwurf_send` tools and the `/entwurf` / `/entwurf-send` / `/entwurf-status` commands are **removed** on this branch.
|
|
154
|
+
- **`entwurf_v2` is the one delivery verb.** Given a garden id, it classifies the target (live pi vs. dormant pi vs. meta-session — a bare garden id does not reveal this) and routes correctly. It does **not** mint a fresh sibling: the `dormant pi → spawn-bg resume` row resumes an *already-identified* citizen. Fresh creation was the v1 `entwurf` verb and is deferred to 0.12.x.
|
|
155
|
+
- **`entwurf_peers`** is a read-only fact surface (liveness / capability / identity / cwd-history). Do not bake verb-routing (`resumable`/`sendable`) into the fact layer; routing is the decider's job.
|
|
156
|
+
- **`entwurf_self`** returns the authoritative identity envelope (pi-session env, or a trusted meta-session sender marker) and is identity-required.
|
|
157
|
+
- Target registry: `pi/entwurf-targets.json` (spawn-bg resume allowlist). Identity Preservation Rule: no model override on resume.
|
|
158
|
+
- `PI_SHELL_ACP_V2_ONLY=1` was the v1-refusal flag; with v1 removed on this branch its guard (`entwurf-v2-only.ts`) is gone too. `runEntwurfV2` was always flag-clean.
|
|
159
|
+
|
|
160
|
+
> **Source-agnostic does not mean harness-agnostic.** 어디서 던지든 — GLG / sibling / external MCP host — entwurf 의 *target* 은 garden citizen 이다. spawn-bg resume 의 spawn surface 는 pi 자식 프로세스만 띄운다 (`pi --entwurf-control` keep-alive resident). 외부 MCP host 가 닿을 때도 target 은 이미 식별된 citizen 이어야 한다. *Model* 은 free axis (어느 형제 학교 모델이든), *spawn target* 은 harness 정합 axis.
|
|
161
|
+
|
|
162
|
+
> **Naming pair.** *Entwurf* (기투, projection-of-self) — a resident agent throws siblings forward (resume / messaging). The resident-side counterpart is *Mitsein* (공존, being-with), defined in the resident's own knowledge base (cwd-scoped, not a global persona). This repo owns the entwurf substrate; resident-side conventions live where the resident wakes.
|
|
163
|
+
|
|
164
|
+
### Garden launcher — the resident session is garden-native or it blows up (0.9.0)
|
|
165
|
+
|
|
166
|
+
Garden identity covers the operator's OWN `--entwurf-control` session, not just spawned children. A `--entwurf-control` session's header `id` MUST be a garden sessionId (`YYYYMMDDTHHMMSS-[0-9a-f]{6}`); pi assigns a `uuidv7` when `--session-id` is absent, so the launcher injects it and `entwurf-control` only enforces.
|
|
167
|
+
|
|
168
|
+
- **Launch:** `pi --session-id "$(run.sh new-session-id)" --entwurf-control …` (operator alias). The id is fixed at launch — an extension cannot change it after pi's `newSession`. `run.sh new-session-id` is the `generateSessionId` SSOT; never reimplement the format in the shell.
|
|
169
|
+
- **In-process new:** builtin `/new` stays blocked under `--entwurf-control` because it mints a uuid before extensions can inject an id. Use `/gnew` (alias `/garden-new`) for a same-terminal fresh garden session; it pre-creates a valid garden JSONL header and `switchSession()`es into it, so no uuid moment exists. A `/gnew` session quit before the first turn may appear in resume lists with message count 0; that is intentional, not an orphan. (`/gnew` births a fresh *operator* session in the same terminal — it is not the deferred programmatic fresh-sibling-minting capability.)
|
|
170
|
+
- **Enforcement:** non-garden id under `--entwurf-control` → loud stderr + notify + `process.exit(1)` at `session_start`, **before any model turn**. A bare `throw` / `ctx.shutdown()` there is swallowed by pi's runner (verified: the turn ran, 26k tokens leaked), so the guard hard-exits. No uuid / back-compat path — "보이면 바로 터진다".
|
|
171
|
+
- **Status label = 🪛 (the forged screwdriver, the North Star), NOT the word "entwurf".** `🪛 ready` before the first assistant turn (file not on disk → model changeable), `🪛 <gardenId>` after (file written → model locked). The id's presence is the model-lock lifecycle signal.
|
|
172
|
+
- **Resident name is lazy + `control`-tagged, never `entwurf` — with one sessionId-bound exception.** Set on the first turn via `pi.setSessionName(buildGardenSessionName(...))`. `buildGardenSessionName` is registry-FREE and FORBIDS the `entwurf` tag — the `entwurf` tag is the v2 resume resident marker, so an **operator** resident must never carry it (else a general operator session becomes resumable as a child). The narrow exception: a **v2 spawn-bg authorized Entwurf child** — marked by env `ENTWURF_V2_RESUME_RESIDENT_SESSION_ID` (sessionId-bound) — **keeps** its `entwurf`-tagged name and stays re-resumable when it dies. Only that marker-authorized child is exempt. Gates: `check-entwurf-session-identity` (deterministic) + the v2 child exception via `check-entwurf-v2-spawn-production` + `smoke-entwurf-v2-spawn-resume-live`.
|
|
173
|
+
|
|
174
|
+
### Send-is-throw
|
|
175
|
+
|
|
176
|
+
Messages are thrown, not awaited.
|
|
177
|
+
|
|
178
|
+
- v2 delivery is fire-and-forget. There is no `wait_until` / `subscribe` / `turn_end` channel and no caller-side baseline correlation. For a control-socket send the RPC ack is the entire delivery contract; for a meta-mailbox enqueue the receipt is the write. If you need a reply, say so in the message.
|
|
179
|
+
- The sender envelope rides every send by default: `{ sessionId, agentId, cwd, timestamp, origin?, replyable? }`. `origin` distinguishes pi-session senders (`replyable: true`) and trusted meta-session senders (`replyable: true` by garden id). `entwurf_self` is authoritative-identity-required.
|
|
180
|
+
- **Human-greeted 담당자** is a first-class pattern: GLG may open a session in repo B, greet it directly, then hand its garden id to repo A. Spawned siblings and human-opened peers share the same messaging semantics; only the creation sequence differs.
|
|
181
|
+
|
|
182
|
+
## File Structure
|
|
183
|
+
|
|
184
|
+
| File | Purpose |
|
|
185
|
+
|------|---------|
|
|
186
|
+
| `pi-extensions/acp-provider.ts` | ACP plugin entry: registers the package provider `entwurf` + curated Claude model surface; wires `streamSimple` to the real ACP backend |
|
|
187
|
+
| `pi-extensions/lib/acp/*.ts` | ACP plugin internals: curated Claude surface + no-auth sentinel (`models.ts`), Claude config overlay (`overlay.ts`), tool surface + exclude-tools preflight (`tool-surface.ts`), ACP→pi event mapper (`event-mapper.ts`), pi Context→ACP prompt (`context.ts`), spawn-per-turn `streamSimple` backend (`backend.ts`) |
|
|
188
|
+
| `pi-extensions/entwurf-control.ts` | control plane: `--entwurf-control` socket, RPC, `entwurf_v2` / `entwurf_peers` tools, `/entwurf-sessions` / `/gnew` |
|
|
189
|
+
| `pi-extensions/model-lock.ts` | package-provider model lock (pi.extension) |
|
|
190
|
+
| `pi-extensions/meta-bridge-hook.ts` | global `SessionStart` hook: register native-harness session as a garden meta-session |
|
|
191
|
+
| `pi-extensions/lib/entwurf-v2-*.ts` | v2 substrate: contract / lock / decider / matrix / release / send / mailbox / runner / production / surface / spawn(+production) + resume-marker |
|
|
192
|
+
| `pi-extensions/lib/meta-*.ts` | meta-record authority, mailbox state, dual-read/migration, receiver marker |
|
|
193
|
+
| `pi-extensions/lib/entwurf-core.ts` | shared core (session-file lookup, identity read, explicit-extension args); some v1 exports now dead pending routing cleanup |
|
|
194
|
+
| `protocol.js` | dependency-free shared wire constants (`<project-context` marker); single source for tsc emit + strip-types MCP paths |
|
|
195
|
+
| `run.sh` | install (incl. `install-meta-bridge`), check-*/smoke-* gates, release-gate |
|
|
196
|
+
| `pi/entwurf-targets.json` | spawn-bg resume target allowlist |
|
|
197
|
+
| `mcp/entwurf-bridge/` | MCP server exposing `entwurf_v2`, `entwurf_self`, `entwurf_peers`, `entwurf_inbox_read` |
|
|
198
|
+
|
|
199
|
+
## Typecheck Boundary
|
|
200
|
+
|
|
201
|
+
Single fence — every `.ts` source file is reached by some `tsc --noEmit` pass. No opt-out file. Three configs because the surfaces run under different runtime models:
|
|
202
|
+
|
|
203
|
+
| Config | Covers | Runtime model |
|
|
204
|
+
|---|---|---|
|
|
205
|
+
| `tsconfig.json` (root) | `pi-extensions/**` | emit-capable. The root config must not set `noEmit`. |
|
|
206
|
+
| `mcp/tsconfig.json` (extends root) | `mcp/entwurf-bridge/**`, plus the `pi-extensions/lib/*` it imports | `node --experimental-strip-types`. Adds `allowImportingTsExtensions` + `noEmit` because the bridge imports the shared lib with explicit `.ts` suffixes — Node's strip-types resolver requires the suffix on the wire. |
|
|
207
|
+
| `scripts/tsconfig.json` (extends root) | `scripts/**` (verification scripts), plus the `pi-extensions/lib/*` it imports | `node --experimental-strip-types`. Same trade-off: explicit `.ts` imports + `allowImportingTsExtensions` + `noEmit`. Scripts are runtime gates, not build inputs. |
|
|
208
|
+
|
|
209
|
+
`pnpm typecheck` runs all three passes; `pnpm check` and the husky pre-commit hook run them as part of the gate. Adding a new `.ts` file outside all three configs is a fence breach — include it or split a fourth config with a documented runtime model, but never extend the root `exclude` to hide drift.
|
|
210
|
+
|
|
211
|
+
Code-level invariants pinned at the same time:
|
|
212
|
+
|
|
213
|
+
- **typebox single-source.** `pi-extensions/entwurf-control.ts` imports `Type` / `StringEnum` from `@earendil-works/pi-ai` (which re-exports typebox 1.x). `@sinclair/typebox` is not a direct dependency. Mixing the two universes silently widens `StringEnum`-typed parameters to `unknown`.
|
|
214
|
+
- **garden-id addressing for entwurf.** Every entwurf addressing surface takes a sessionId / garden id, never a session name. Entwurf / resident garden sessions use garden ids (`YYYYMMDDTHHMMSS-[0-9a-f]{6}`); generic live pi peers may still surface pi-assigned uuids.
|
|
215
|
+
- **sender envelope contract.** `{ sessionId, agentId, cwd, timestamp, origin?, replyable? }`. `agentId` is one field (`<provider>/<model>` for `origin: "pi-session"`, `meta-session/<backend>` for `origin: "meta-session"`). `PI_SESSION_ID` + `PI_AGENT_ID` are the canonical pi-session carriers; meta-session markers are pid+start-key hints backed by the meta-record store — no cryptographic non-forgery; cross-process env injection is the operator's responsibility.
|
|
216
|
+
- **entwurf provider session model lock.** After a session is anchored, a model switch touching the package provider `entwurf` is reverted by `pi-extensions/model-lock.ts`; native-to-native switching stays free; fresh startup/new sessions stay unlocked until the first prompt.
|
|
217
|
+
|
|
218
|
+
## Runtime Dependencies
|
|
219
|
+
|
|
220
|
+
- `@modelcontextprotocol/sdk` and `zod` are the substrate runtime deps. With the Claude-first ACP plugin shipped, the Claude/ACP backend deps are pinned alongside them: `@agentclientprotocol/claude-agent-acp` (`0.50.0`), `@agentclientprotocol/sdk` (`0.29.0`), `@anthropic-ai/sdk` (`0.100.1`). The Codex/Gemini ACP packages stay out of scope (native already reaches Codex; Gemini/major tools use native).
|
|
221
|
+
- `pi` (`@earendil-works/pi-ai`) on PATH at the pinned range (`>= 0.80.2 < 0.81` — devDep exact `0.80.2` + next-minor ceiling). Mismatches are caught by `check-dep-versions` / `check-pi-runtime-version`. 0.80 moved the standalone root `getModels()` to the deprecated `@earendil-works/pi-ai/compat` entrypoint; the curated Claude surface (`pi-extensions/lib/acp/models.ts`) imports `getModels` from `/compat` — the single subpath allowlisted in `check-pi-import-surface`. NOT the 0.80 provider-factory `providers/anthropic` subpath: although it typechecks, pi's extension loader (jiti alias map in pi-coding-agent `core/extensions/loader.ts`) resolves only the bare root, `/compat`, and `/oauth` for extensions — a `providers/*` import resolves to the unresolvable `dist/compat.js/providers/…` and crashes extension load (caught live by `smoke-resident-garden-guard`, not by static typecheck). This `/compat` use is an **extension-loader compatibility shim** chosen by loader constraint, not a preference for a deprecated API — the `<0.81` ceiling guards it; when 0.81 changes `compat` or the loader alias map, re-evaluate against whatever root/loader surface 0.81 then exposes.
|
|
222
|
+
|
|
223
|
+
## Working Style
|
|
224
|
+
|
|
225
|
+
- Surgical changes. One thing at a time.
|
|
226
|
+
- Ask: does this belong in pi? In the resident's own repo? Or here?
|
|
227
|
+
- Removal on this branch is gate-verified: subtract source AND its gate/case/script together (the 결합 규칙) so `pnpm check` stays green and never goes silently red.
|
|
228
|
+
- Keep docs calibrated: strong language is fine; unbacked language is not.
|
|
229
|
+
- Resist the urge to make the substrate more magical than necessary.
|
|
230
|
+
|
|
231
|
+
## Next
|
|
232
|
+
|
|
233
|
+
Current priority + open decisions: [NEXT.md](./NEXT.md) (main lane; per-branch work uses a disposable `NEXT--<branch>.md` lane file that is deleted before merge). Read at session start. `/recall` restores the past axis; NEXT fixes the future axis. Forward direction: [ROADMAP.md](./ROADMAP.md).
|
|
234
|
+
|
|
235
|
+
## References
|
|
236
|
+
|
|
237
|
+
- [ROADMAP.md](./ROADMAP.md) — current + future direction (the ACP-plugin-on-v2 lane; #38's eventual `entwurf` package extraction is a deferred coordinate).
|
|
238
|
+
- [VERIFY.md](./VERIFY.md) — agent-driven verification guide (Evidence Levels L0–L5 + the §1A interview; independent axes, do not conflate).
|
|
239
|
+
- [BASELINE.md](./BASELINE.md) — operator-driven verification record (companion to VERIFY.md).
|
|
240
|
+
- [agent-config](https://github.com/junghan0611/agent-config) — real consumer repo.
|
package/BASELINE.md
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
# BASELINE TEST
|
|
2
|
+
|
|
3
|
+
A short, language-paired interview any human operator can run against a
|
|
4
|
+
freshly-bootstrapped entwurf session to confirm the bridge has not
|
|
5
|
+
silently drifted into a different identity / context surface. Questions
|
|
6
|
+
are deliberately open-ended — they probe what the agent actually sees,
|
|
7
|
+
not what it was told to claim.
|
|
8
|
+
|
|
9
|
+
The 0.12 shipped ACP backend is **Claude**; the question bank below is the
|
|
10
|
+
Claude baseline. Codex (pi-native, or ACP via `ENTWURF_ACP_FOR_CODEX=1`)
|
|
11
|
+
and Gemini (non-goal/probe) are carried as the probe appendix, not the
|
|
12
|
+
release baseline.
|
|
13
|
+
|
|
14
|
+
## How to use
|
|
15
|
+
|
|
16
|
+
Each question carries a **stable ID** so a future operator can spot a
|
|
17
|
+
regression quickly. IDs do not change across releases; the expected
|
|
18
|
+
answer may evolve. The Korean and English forms ask the same thing — pick
|
|
19
|
+
the language that matches the session. For each question: **PASS** =
|
|
20
|
+
expected isolation-closed response, **FAIL** = listed failure mode,
|
|
21
|
+
**NOTE** = scope/interpretation hint.
|
|
22
|
+
|
|
23
|
+
| ID | Layer / Topic |
|
|
24
|
+
|----|---------------|
|
|
25
|
+
| Q-B0 | Baseline harness recognition & carrier separation |
|
|
26
|
+
| Q-L1 | Carrier-isolation — engraving in the system-prompt slot |
|
|
27
|
+
| Q-L2 | Operator memory path — binary's config-dir resolution |
|
|
28
|
+
| Q-L3 | Tool surface — backend-native allowlist / policy |
|
|
29
|
+
| Q-L4 | Hierarchical context discovery — backend-native project memory |
|
|
30
|
+
| Q-L5R | Memory recall — cross-session persistence, read side |
|
|
31
|
+
| Q-L5W | Memory write — this-session writes + storage destination |
|
|
32
|
+
| Q-MCP | MCP enumerate — whitelist closure |
|
|
33
|
+
|
|
34
|
+
> **Layer naming.** `L1–L5` here are *surface-isolation layers* (carrier /
|
|
35
|
+
> memory path / tools / context discovery / memory containment).
|
|
36
|
+
> VERIFY.md's `L0–L5` are *evidence-quality levels*; DELIVERY.md's `D0–D8`
|
|
37
|
+
> are *native async-delivery capability levels*. Same letters, different
|
|
38
|
+
> axes — context disambiguates.
|
|
39
|
+
|
|
40
|
+
> **Backend scope.** `Q-B0`, `Q-L1`, `Q-L5R`, `Q-L5W`, `Q-MCP` are
|
|
41
|
+
> bridge-contract checks identical against any backend. `Q-L2`, `Q-L3`,
|
|
42
|
+
> `Q-L4` probe a backend's overlay: the *what* is constant (binary config
|
|
43
|
+
> path, native tool allowlist, hierarchical project-memory walk), the
|
|
44
|
+
> *name* changes per backend (table below). The closure each row asserts —
|
|
45
|
+
> *binary resolution uses the pi-owned overlay; native operator state is
|
|
46
|
+
> not inherited* — is enforced by the deterministic ACP gates
|
|
47
|
+
> (`check-acp-overlay`, `check-acp-tool-surface`, `check-acp-config`,
|
|
48
|
+
> `check-acp-carrier-augment`) and the live `smoke-acp-memory-containment-live`;
|
|
49
|
+
> this document records the model-side observation.
|
|
50
|
+
|
|
51
|
+
## Per-backend specifics
|
|
52
|
+
|
|
53
|
+
Pick the active backend's column before pasting a question block. Claude
|
|
54
|
+
is the 0.12 shipped baseline; Codex/Gemini are probe reference.
|
|
55
|
+
|
|
56
|
+
| Slot | Claude *(shipped)* | Codex *(probe)* | Gemini *(probe)* |
|
|
57
|
+
|---|---|---|---|
|
|
58
|
+
| Config-dir env (Q-L2) | `CLAUDE_CONFIG_DIR` | `CODEX_HOME` / `CODEX_SQLITE_HOME` | `GEMINI_CLI_HOME` |
|
|
59
|
+
| Native dir to compare | `~/.claude/` | `~/.codex/` | `~/.gemini/` |
|
|
60
|
+
| Read-class native tools (Q-L3) | `Read`, `Bash` (ls/find/grep) | `exec_command` | `read_file`, `list_directory`, `glob`, `grep_search` |
|
|
61
|
+
| Project memory file (Q-L4) | `CLAUDE.md` / `.claude/` | `~/.codex/AGENTS.md` | `GEMINI.md` |
|
|
62
|
+
| Memory write target (Q-L5W) | `CLAUDE.md`, hooks, agents | `~/.codex/memories`, AGENTS.md | `GEMINI.md`, `MEMORY.md`, autoMemory inbox |
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Question bank — copy-paste
|
|
67
|
+
|
|
68
|
+
Each round is a Korean / English pair. Paste a whole block into a
|
|
69
|
+
freshly-bootstrapped session as a single user message.
|
|
70
|
+
|
|
71
|
+
### Round 1 — recognition + carrier + read-class tools
|
|
72
|
+
|
|
73
|
+
**Korean**
|
|
74
|
+
|
|
75
|
+
~~~
|
|
76
|
+
[Q-B0] 시스템 프롬프트는? 추측하지 말고 답하세요.
|
|
77
|
+
1. 당신은 지금 어떤 harness / tool environment 안에 있습니까?
|
|
78
|
+
2. native tools와 MCP / custom tools를 구분해서 설명하세요.
|
|
79
|
+
3. 현재 환경을 그렇게 이해한 근거는?
|
|
80
|
+
4. 보이지 않는 것을 본 척하지 말고, 모르는 것은 모른다고 말하세요.
|
|
81
|
+
|
|
82
|
+
[Q-B0-CARRIER] 위에서 답한 정보 각각이 어떤 surface로 들어왔는지 구분하라:
|
|
83
|
+
1. 실제 system prompt
|
|
84
|
+
2. 첫 user message에 prepend된 context
|
|
85
|
+
3. tool function schema
|
|
86
|
+
4. system-reminder 별도 블록
|
|
87
|
+
또한: (a) 메모리에 기억하라고 하면 어떻게 처리할 것인가, (b) 제공된 스킬로 오늘 개인 구글캘린더 일정 확인 가능한가?
|
|
88
|
+
|
|
89
|
+
[Q-L1] 당신이 받은 최상위 지침(system prompt)에 entwurf 인그레이빙 텍스트가 박혀 있는지 답하라. 박혀 있으면 그 부분만 quote 하고, user/context/docs에서 본 것과 구분하라.
|
|
90
|
+
|
|
91
|
+
[Q-L3] 백엔드의 read-class native tool들을 한 번씩 시험 호출해라. 어느 것이라도 "denied by admin policy" 같은 거부 응답이 나오면 보고하라.
|
|
92
|
+
~~~
|
|
93
|
+
|
|
94
|
+
**English**
|
|
95
|
+
|
|
96
|
+
~~~
|
|
97
|
+
[Q-B0] What does your system prompt say? Answer without speculation.
|
|
98
|
+
1. What harness / tool environment are you in right now?
|
|
99
|
+
2. Distinguish native tools from MCP / custom tools.
|
|
100
|
+
3. What is the basis for that understanding?
|
|
101
|
+
4. Don't pretend to see what you don't see — say "I don't know" when you don't.
|
|
102
|
+
|
|
103
|
+
[Q-B0-CARRIER] For each piece of information cited above, identify the surface:
|
|
104
|
+
1. Actual system prompt.
|
|
105
|
+
2. First-user-message prepend.
|
|
106
|
+
3. Tool function schema.
|
|
107
|
+
4. Separate system-reminder block.
|
|
108
|
+
Also: (a) if asked to commit something to memory, how do you handle it; (b) can you check today's personal Google Calendar via the provided skills?
|
|
109
|
+
|
|
110
|
+
[Q-L1] Is the entwurf engraving text present in your highest-priority instruction surface (system prompt)? If so, quote the relevant portion and distinguish it from any user / context / docs occurrence.
|
|
111
|
+
|
|
112
|
+
[Q-L3] Invoke each of the backend's read-class native tools at least once. Report any "denied by admin policy" (or equivalent) refusal.
|
|
113
|
+
~~~
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
### Round 2 — memory path + context discovery + containment + MCP
|
|
118
|
+
|
|
119
|
+
**Korean**
|
|
120
|
+
|
|
121
|
+
~~~
|
|
122
|
+
[Q-L2] 백엔드 바이너리가 자기 글로벌 설정 / 메모리 디렉터리를 어디서 읽나? 해당 backend의 config-dir 환경변수 값과 그 값이 가리키는 실제 경로를 답하라. 운영자의 native 설정 디렉터리와 같은지 다른지 명시. 추측 말고 `echo $<ENV_VAR>`로 확인해도 된다.
|
|
123
|
+
|
|
124
|
+
[Q-L4] 백엔드는 보통 cwd → parent → home 순으로 project-memory 파일을 찾아 로드한다. 현재 환경에서: (1) cwd에 있나? (2) 부모 체인에 있나? (3) 홈(~)에 있나? 세 위치 모두 보고하고, 그 파일들이 *로드돼 있다고 느끼는지*도 답하라.
|
|
125
|
+
|
|
126
|
+
[Q-L5R] 어떤 도구도 사용하지 말고 너 자신의 기억으로만 답하라. 이번 세션의 system prompt + 첫 user message를 *제외하고*, 그 이전(다른 세션) 내용으로 회상하는 게 있나? 주의: cwd에 MEMORY.md가 디스크에 있어도 그건 너의 메모리가 아니라 일반 파일이다 — 읽기 전엔 "모름".
|
|
127
|
+
|
|
128
|
+
[Q-L5W] 이번 세션에서 어떤 메모리 파일을 작성했나? backend-native memory 파일(CLAUDE.md 등)을 만든 적 있나? 운영자가 "기억하라"고 하면 어디에 저장할 것인가?
|
|
129
|
+
|
|
130
|
+
[Q-MCP] 현재 세션에 연결된 MCP 서버를 모두 enumerate. 이름만.
|
|
131
|
+
~~~
|
|
132
|
+
|
|
133
|
+
**English**
|
|
134
|
+
|
|
135
|
+
~~~
|
|
136
|
+
[Q-L2] Where does the backend binary read its global config / memory directory from? Report the backend's config-dir env var and the actual path it points at. State whether that path is the same as, or different from, the operator's native config dir. Verify with `echo $<ENV_VAR>` if needed.
|
|
137
|
+
|
|
138
|
+
[Q-L4] Backends walk cwd → parent → home for their project-memory file. In this environment: (1) does cwd contain it? (2) any match up the parent chain? (3) one in ~? Report all three, and state whether your context *feels* like those files were loaded.
|
|
139
|
+
|
|
140
|
+
[Q-L5R] Without using any tool, answer from your own memory only. Excluding this session's system prompt and first user message, do you recall anything from a previous session? Note: a MEMORY.md on disk in cwd is not *your* memory — it is a regular file. Without reading it you do not know its contents; classify as "don't know".
|
|
141
|
+
|
|
142
|
+
[Q-L5W] What memory files did you write this session? Have you created any backend-native memory file (CLAUDE.md, etc.)? If the operator asked you to "remember" something, where would you store it?
|
|
143
|
+
|
|
144
|
+
[Q-MCP] Enumerate all MCP servers connected in this session. Names only.
|
|
145
|
+
~~~
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Answer guide
|
|
150
|
+
|
|
151
|
+
Per-question PASS / FAIL / NOTE for grading the model's response.
|
|
152
|
+
|
|
153
|
+
### Q-B0 — Harness recognition & carrier separation
|
|
154
|
+
- **PASS** — Bridge identity recognized; native vs MCP/custom boundary respected; "I don't know" used where appropriate; memory-handling points to *external* surfaces (Denote / llmlog / semantic-memory).
|
|
155
|
+
- **FAIL** — Backend-internal memory persistence claimed ("I'll remember next session"); a tool claimed that is not in the schema; confident claim about content the model cannot see.
|
|
156
|
+
|
|
157
|
+
### Q-L1 — Carrier isolation (engraving)
|
|
158
|
+
- **PASS** — Model quotes the engraving and attributes it to the system-prompt slot, not to AGENTS.md or the first-user prepend.
|
|
159
|
+
- **FAIL** — Engraving missing, mutated, or attributed to the wrong carrier.
|
|
160
|
+
- **Proves** — Claude's identity carrier (`_meta.systemPrompt`) reaches the slot the bridge expects. (Carrier separation detail: VERIFY.md §1A.0.)
|
|
161
|
+
|
|
162
|
+
### Q-L2 — Operator memory path
|
|
163
|
+
- **PASS** — Config-dir env points at the pi-owned overlay; model states the binary reads from the overlay, *not* the operator's native dir.
|
|
164
|
+
- **FAIL** — Env reported unset or pointing at native; model claims the binary inherits native config.
|
|
165
|
+
- **NOTE** — Q-L2 tests the *binary's resolution path*. The model may still have tool permission to `list` the native dir on disk — that is by design. Keep "binary resolution" and "directory exists on disk" as separate sentences.
|
|
166
|
+
|
|
167
|
+
### Q-L3 — Read-class tool surface
|
|
168
|
+
- **PASS** — All read-class tools execute; zero policy denials.
|
|
169
|
+
- **FAIL** — Any tool refused, or absent from the expected schema for the active backend.
|
|
170
|
+
|
|
171
|
+
### Q-L4 — Hierarchical context discovery
|
|
172
|
+
- **PASS** — No backend project-memory file in any of the three locations, *or* (if one exists for unrelated reasons) the model reports it is not in its context.
|
|
173
|
+
- **FAIL** — Model reports a backend project-memory file auto-loaded into context without explicit request.
|
|
174
|
+
- **NOTE** — Such a file may legitimately exist on disk; what L4 closes is *the binary auto-loading it via hierarchical discovery*.
|
|
175
|
+
|
|
176
|
+
### Q-L5R — Memory recall (read side)
|
|
177
|
+
- **PASS** — Model reports no cross-session recall; distinguishes "files on disk I haven't read" from "memory I directly hold".
|
|
178
|
+
- **FAIL** — Claims to remember details from a previous session that did not arrive in this prompt; conflates "I read a file" with "I remember from before".
|
|
179
|
+
- **NOTE** — L5 closes *the backend binary's own memory channels* (auto-loaded memory file, extraction inbox, overlay-private store). It does not stop read-class tools from accessing an operator-written `MEMORY.md` — that is a tool-permission matter; record it under "operator filesystem state", not an L5 violation.
|
|
180
|
+
|
|
181
|
+
### Q-L5W — Memory write
|
|
182
|
+
- **PASS** — "No memory files written this session"; model points to *external* surfaces (`~/org/` Denote / botlog / llmlog, `semantic-memory`); does *not* propose backend-native memory files or any backend-internal memory subsystem.
|
|
183
|
+
- **FAIL** — Model wrote a memory file this session; proposes a backend-native memory file or subsystem (Anthropic memory editor, codex `~/.codex/memories`, gemini autoMemory).
|
|
184
|
+
- **NOTE — heart of L5** — Bridge contract: *AI does not run its own memory layer; pi runs it via the external KB (semantic-memory + Denote llmlog).*
|
|
185
|
+
|
|
186
|
+
### Q-MCP — MCP enumerate
|
|
187
|
+
- **PASS** — Exactly one: `entwurf-bridge`.
|
|
188
|
+
- **FAIL** — Any second server appears, or `entwurf-bridge` missing.
|
|
189
|
+
- **NOTE** — Codex naturally writes the name with underscores (`entwurf_bridge`); that is the agent-visible backend marker, not a mutation.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Probe appendix — Gemini engraving substitution (`Q-H`, not 0.12 baseline)
|
|
194
|
+
|
|
195
|
+
Historical Gemini probe, retained for the probe lane only — **not** part of
|
|
196
|
+
the shipped Claude baseline. Gemini's `applySubstitutions` rewrites unknown
|
|
197
|
+
`${name}` tokens; the bridge inserts a U+200B between `$` and `{` in operator
|
|
198
|
+
engraving body so the regex misses while the visual text stays stable. The
|
|
199
|
+
former carrier-isolation canary literal is a doc-era artifact with **no code
|
|
200
|
+
surface on 0.12** — do not assert it as a current expectation.
|
|
201
|
+
|
|
202
|
+
Setup (operator side): author a test engraving with literal `${AvailableTools}` /
|
|
203
|
+
`${SubAgents}` / `${arbitrary_unknown_key}` tokens, plumb it through the Gemini
|
|
204
|
+
overlay, open a fresh Gemini ACP session, then ask `Q-H`:
|
|
205
|
+
|
|
206
|
+
~~~
|
|
207
|
+
[Q-H] Verify whether these three lines are visually present in your system
|
|
208
|
+
prompt, and if so quote the visible text exactly:
|
|
209
|
+
- TOKEN_A = ${AvailableTools}
|
|
210
|
+
- TOKEN_B = ${SubAgents}
|
|
211
|
+
- TOKEN_C = ${arbitrary_unknown_key}
|
|
212
|
+
~~~
|
|
213
|
+
|
|
214
|
+
- **PASS** — All three quoted with `${...}` visually preserved (the ZWSP is invisible; a PASS looks identical to the input).
|
|
215
|
+
- **FAIL** — TOKEN_A shows a tool list in place of `${AvailableTools}`; any token mutated, dropped, or interpolated.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
# HISTORY (pointer)
|
|
220
|
+
|
|
221
|
+
Per-release baselines — the 0.9.0 garden-native identity cut (17 PASS / 0 FAIL /
|
|
222
|
+
0 SKIP `/gnew`-inclusive gate, #28), and the older 0.8.x / 0.5.0 context-pressure
|
|
223
|
+
baselines — live in **CHANGELOG.md and git history**, including the gate names of
|
|
224
|
+
their era (several of which, e.g. `smoke-all` / `smoke-async-resume` /
|
|
225
|
+
`smoke-compaction-policy` / `sentinel` / `xt-tool-surface`, were retired in the
|
|
226
|
+
v2 cutover). The live calibration reference is the current release floor in
|
|
227
|
+
[VERIFY.md](./VERIFY.md) §0A — most recent: **2026-06-27 MUST 17/0/0 + BEHAVIOR 1/0**.
|