@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/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Contributing to entwurf
|
|
2
|
+
|
|
3
|
+
This is a daily-driver bridge. Correctness beats feature breadth. Read this before opening a PR.
|
|
4
|
+
|
|
5
|
+
## What this repo is
|
|
6
|
+
|
|
7
|
+
`entwurf` is a **garden-citizen dispatch bridge** — entwurf-core (v2 dispatch) + a meta-bridge + a pi adapter + a **Claude-first ACP plugin** — that lets already-running harnesses address one another by garden id; pi is one adapter, not the subject. The ACP plugin borrows the backend's identity (system prompt preset, model behavior, tool implementations) and shapes the *operating surface* — what tools, MCP, skills, and permissions are visible — to match pi's own policy. Claude is the shipped ACP backend, Codex is a native garden citizen, and the Gemini path is deprecated. That is the entire scope.
|
|
8
|
+
|
|
9
|
+
If a change moves the bridge toward "second harness" — prompt reconstruction, transcript hydration, ambient discovery, silent fallback — it does not belong here.
|
|
10
|
+
|
|
11
|
+
## Hard invariants
|
|
12
|
+
|
|
13
|
+
These are enforced by code, gates, and review. Do not weaken them in a PR; if you want to argue against one, open an issue first.
|
|
14
|
+
|
|
15
|
+
1. **Bootstrap order**: `resume > load > new`. Always.
|
|
16
|
+
2. **Session persistence**: only `pi:<sessionId>` is persisted. `cwd:<cwd>` is never persisted.
|
|
17
|
+
3. **MCP injection**: only via `entwurfProvider.mcpServers`. No ambient `~/.mcp.json` scanning, no `~/.claude/settings.json` MCP inheritance.
|
|
18
|
+
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`, permissions from `permissionAllow`, deferred-tool surface from `disallowedTools`. The `CLAUDE_CONFIG_DIR` overlay enforces this even where the SDK reads filesystem independently of `settingSources`.
|
|
19
|
+
5. **Backend-specific knobs stay explicit and namespaced**: Codex/Gemini-era ACP knobs are not part of the current Claude-first shipped path. If a future backend lane reintroduces a sandbox or mode knob, it must use the `ENTWURF_ACP_*` namespace and invalid values must throw, never fall back.
|
|
20
|
+
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.
|
|
21
|
+
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.
|
|
22
|
+
8. **This bridge is not a second harness**: no prompt reconstruction, no transcript hydration, no tool result ledger, no Claude Code emulation.
|
|
23
|
+
|
|
24
|
+
## Required gate before opening a PR
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
pnpm check
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
This wraps the entire static-quality surface (biome, tsc, all `check-*` gates including `check-dep-versions`). It is wired into the pre-commit hook (`.husky/pre-commit`), so a clean local commit is the first sign your change holds.
|
|
31
|
+
|
|
32
|
+
For changes that touch backend launch, session lifecycle, or `_meta` shape, also run:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
./run.sh smoke-all /path/to/your-fixture-project
|
|
36
|
+
./run.sh verify-resume /path/to/your-fixture-project
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
These need a real ACP subprocess, so they stay manual — the hook does not run them.
|
|
40
|
+
|
|
41
|
+
## What gets PRs rejected
|
|
42
|
+
|
|
43
|
+
- adds ambient MCP discovery (project `.mcp.json`, `~/.mcp.json`, etc.) without an explicit `entwurfProvider.mcpServers` opt-in path
|
|
44
|
+
- inherits user / project / local backend config by default (i.e. flips `settingSources` away from `[]`, drops the `CLAUDE_CONFIG_DIR` overlay, removes the codex `-c` config flags)
|
|
45
|
+
- weakens `resume > load > new` (e.g. silently downgrading to `new` without a logged invalidation reason)
|
|
46
|
+
- introduces `console.warn` / silent fallback where the bridge should `throw` (see `AGENTS.md` "Never warn. Throw.")
|
|
47
|
+
- changes the Claude, Codex, or Gemini operating surface (tools, skills, MCP, permissions, sandbox) without accounting for all three backends or recording an explicit carve-out
|
|
48
|
+
- adds a second transcript ledger, a prompt reconstruction layer, or any state that competes with pi's session as the source of truth
|
|
49
|
+
- skews version pins across `package.json`, `run.sh`, and `README.md` (the `check-dep-versions` gate catches this; if it complains, fix all three)
|
|
50
|
+
|
|
51
|
+
## Style and code shape
|
|
52
|
+
|
|
53
|
+
- Read `AGENTS.md` for the full code-shape rules. Highlights:
|
|
54
|
+
- fail-fast: throw on bad config, never warn-and-continue
|
|
55
|
+
- no `try/catch` swallowing — `catch {}` is allowed only for environment probing
|
|
56
|
+
- send-is-throw — messages aren't awaited
|
|
57
|
+
- one surface name (`entwurf`)
|
|
58
|
+
- Comments explain *why*, not *what*. Reach for them at non-obvious decisions, especially around SDK / claude-agent-acp / codex-rs interaction edges that future maintainers won't know to look up.
|
|
59
|
+
- Keep changes single-responsibility per commit; bundling a refactor with a behavior change makes review and bisect painful.
|
|
60
|
+
|
|
61
|
+
## When in doubt
|
|
62
|
+
|
|
63
|
+
Open an issue describing the backend boundary you want to touch and the failure mode you observed. The repo is small; over-coordination is cheap, regression on a daily-driver tool is expensive.
|
package/DELIVERY.md
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# DELIVERY.md — Async delivery capability levels
|
|
2
|
+
|
|
3
|
+
`DELIVERY.md` is the cross-harness yardstick for one question:
|
|
4
|
+
|
|
5
|
+
> Can an already-running native agent session receive an async message, without
|
|
6
|
+
> pretending that pi owns the backend transcript?
|
|
7
|
+
|
|
8
|
+
It is **not** a product promise and not a benchmark. It is a diagnostic coordinate
|
|
9
|
+
system. When Claude Code, Antigravity, Codex, pi-native Entwurf, or a future
|
|
10
|
+
harness behaves differently, record the exact delivery level it reaches instead
|
|
11
|
+
of collapsing the result into "works" / "doesn't work".
|
|
12
|
+
|
|
13
|
+
Companion surfaces:
|
|
14
|
+
|
|
15
|
+
- [VERIFY.md](./VERIFY.md) — agent-driven bridge verification and evidence quality (`L0–L5`).
|
|
16
|
+
- [BASELINE.md](./BASELINE.md) — operator-driven identity / overlay baseline interviews.
|
|
17
|
+
- [`scripts/raw-async-delivery/`](./scripts/raw-async-delivery/) — reproducible raw delivery probes.
|
|
18
|
+
|
|
19
|
+
## Scope and non-goals
|
|
20
|
+
|
|
21
|
+
This document is about **native live-session delivery** for the 0.12.0
|
|
22
|
+
meta-bridge direction: a garden meta-session points at a backend-owned native
|
|
23
|
+
session, and async messages reach that session through the backend's own
|
|
24
|
+
supported surfaces.
|
|
25
|
+
|
|
26
|
+
Non-goals:
|
|
27
|
+
|
|
28
|
+
- no tmux / pty `send-keys` as evidence for native delivery;
|
|
29
|
+
- no backend transcript hydration into pi JSONL;
|
|
30
|
+
- no direct writes into backend transcript databases / JSONL / protobuf files;
|
|
31
|
+
- no new prompt spawn (`claude -p`, fresh Codex thread, etc.) masquerading as
|
|
32
|
+
delivery into an already-running subscription/native session;
|
|
33
|
+
- no fake pi session or tool-result ledger for an external backend.
|
|
34
|
+
|
|
35
|
+
A backend may use a socket, filesystem watch, JSON-RPC app server, lifecycle
|
|
36
|
+
hook, or another official surface. The transport differs; the levels below keep
|
|
37
|
+
the judgement comparable.
|
|
38
|
+
|
|
39
|
+
## State vocabulary
|
|
40
|
+
|
|
41
|
+
Use these words precisely in scripts and docs:
|
|
42
|
+
|
|
43
|
+
| State | Meaning |
|
|
44
|
+
|---|---|
|
|
45
|
+
| `queued` | Message is durably written to a mailbox / sender queue. The backend has not necessarily seen it. |
|
|
46
|
+
| `triggered` | A backend-supported event fired: socket RPC accepted, hook fired, file watch event observed, etc. |
|
|
47
|
+
| `woke` | An idle interactive session started a new turn without user typing / pty injection. |
|
|
48
|
+
| `injected` | The message or a doorbell pointing at it reached model-visible context through an official channel. |
|
|
49
|
+
| `processed` | The turn ended or the backend acknowledged completion through a supported hook/event. |
|
|
50
|
+
| `replied` | A result returned to the garden/pi side through an explicit reply path (MCP send, outbox, API result). |
|
|
51
|
+
|
|
52
|
+
Avoid bare `delivered` unless you define it. Preferred decomposition:
|
|
53
|
+
`queued → triggered → woke → injected → processed → replied`.
|
|
54
|
+
|
|
55
|
+
## Delivery levels (D0–D8)
|
|
56
|
+
|
|
57
|
+
These are a separate namespace from VERIFY.md evidence levels (`L0–L5`) and
|
|
58
|
+
BASELINE.md overlay layers (`Q-L1` etc.). Mark the highest level reached and any
|
|
59
|
+
partial levels.
|
|
60
|
+
|
|
61
|
+
| Level | Name | PASS criterion | Typical failure / partial |
|
|
62
|
+
|---|---|---|---|
|
|
63
|
+
| **D0** | Live session identity | Can identify the target live session: native id, cwd/project, backend, and enough liveness metadata to address it. | Only transcript files exist; no live-session join key. |
|
|
64
|
+
| **D1** | Native/free continuation | Delivery targets an already-running native/subscription session; no fresh prompt spawn or metered worker is created for the message. | Uses `claude -p`, a fresh Codex thread, or a new pi child instead of the live session. |
|
|
65
|
+
| **D2** | Receiver armed | The receiving session registers an official receive surface: hook/watch path/socket/app-server subscription. | A mailbox exists but no live session is watching or reachable. |
|
|
66
|
+
| **D3** | Addressed enqueue | Sender can queue a message for exactly one target session id; siblings are not broadcast-woken. | Shared signal wakes every session; no per-session address. |
|
|
67
|
+
| **D4** | Idle active wake | An idle interactive session wakes from an external signal with no user typing and no pty/tmux injection. | Piggyback only: message waits until the next human/user turn. |
|
|
68
|
+
| **D5** | Context injection | A unique token / message body reaches model-visible context via an official hook/API path; the model can acknowledge it. | Hook logs show activity, but the model never sees the message. |
|
|
69
|
+
| **D6** | Same session/model continuity | The response comes from the same native session/conversation and same model/subscription path. | A new conversation/process handles the message; model changed silently. |
|
|
70
|
+
| **D7** | Completion / reply observation | Completion or reply can be observed without transcript scraping: Stop/SessionEnd/PostInvocation, outbox, MCP reply, API result, etc. | Wake and context work, but the garden side cannot know when the turn finished except by watching the UI. |
|
|
71
|
+
| **D8** | Operational robustness | Duplicate suppression, delivery markers, loop guards, level-triggered body drain, ordering policy, stale-session handling, and crash recovery are implemented/tested. | Demo works once but can loop, duplicate, reorder, leave unread backlogs, or lose messages. |
|
|
72
|
+
|
|
73
|
+
### Script result contract
|
|
74
|
+
|
|
75
|
+
Raw probes should print a summary block that a human or later parser can compare
|
|
76
|
+
across harnesses:
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
DELIVERY_LEVELS:
|
|
80
|
+
harness=claude-code
|
|
81
|
+
transport=filechanged-watchpaths-asyncrewake
|
|
82
|
+
D0 live_session: pass
|
|
83
|
+
D1 native_free_continuation: pass
|
|
84
|
+
D2 receiver_armed: pass
|
|
85
|
+
D3 addressed_enqueue: pass
|
|
86
|
+
D4 idle_active_wake: pass
|
|
87
|
+
D5 context_injection: pass token=AGY-PARITY-3399
|
|
88
|
+
D6 continuity: pass session_id=<native-id> model=claude-opus-4-8
|
|
89
|
+
D7 completion_reply: partial reason="no garden outbox yet"
|
|
90
|
+
D8 robustness: partial reason="loop guard present; crash recovery not tested"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
When a level is **not applicable** or **conditional**, say so explicitly. For
|
|
94
|
+
example, Codex app-server delivery is conditional on a loaded thread and control
|
|
95
|
+
socket; direct Codex TUI is a different surface.
|
|
96
|
+
|
|
97
|
+
## Current capability matrix (2026-06-24)
|
|
98
|
+
|
|
99
|
+
This matrix is a snapshot of what the raw probes have established. It should be
|
|
100
|
+
updated when a backend version changes the delivery surface.
|
|
101
|
+
|
|
102
|
+
The **Status** column is the 0.12.0 release framing, kept separate from the
|
|
103
|
+
`D0–D8` capability level:
|
|
104
|
+
|
|
105
|
+
- **shipped** — a supported entwurf 0.12.0 lane: wired, gated, and addressable through the bridge today.
|
|
106
|
+
- **verified-probe** — async delivery proven by a raw probe, but not yet a shipped/supported lane in 0.12.0 (documented, ships after this cut).
|
|
107
|
+
- **deferred** — not addressable as-is, or needs an extra managed install / cloud surface that is out of 0.12.0 scope.
|
|
108
|
+
|
|
109
|
+
| Harness / surface | Status | Highest current level | Transport | Notes |
|
|
110
|
+
|---|---|---:|---|---|
|
|
111
|
+
| **pi native Entwurf** | shipped | D7+ | Unix control socket + pi followUp/custom messages | Replyable pi session. This is the resident baseline, not an external meta-session. 0.12.0 `entwurf_v2` treats a record-less but live pi control socket as a socket-only `fire-and-forget` target (addressed by its socket, not a meta-record); record-less *dormant* resume is intentionally not claimed. |
|
|
112
|
+
| **Claude Code interactive 2.1.163** | shipped | D6, D7 partial, D8 partial | Plugin/global `SessionStart` arms `watchPaths`; external write triggers `FileChanged`; `asyncRewake` wakes idle session | Active idle wake proven without pty. `Stop` alone is piggyback-only. `asyncRewake` is a doorbell; body is self-fetched from mailbox. D8 partial: duplicate/read idempotence, honest unread counts, and level-triggered body drain are gated; empirical wake-edge bounds and unread-heartbeat backstop remain open (#34). |
|
|
113
|
+
| **Antigravity / agy** | verified-probe | D6+ | Native LS gRPC `agentapi send-message` | Active push into live conversation. Same judgement levels; transport differs from Claude. Delivery proven; a shipped adapter lane lands after the 0.12.0 doc cut. |
|
|
114
|
+
| **Codex app-server-backed TUI 0.136.0** | verified-probe | D6, D7 (status) | WebSocket-over-UDS `turn/start` into the live `threadId` | **Demonstrated, no managed standalone, no cloud.** `codex app-server --listen unix://<owned 0700 dir>` + plain `codex` auto-attach (or `--remote unix://`). Full message injection (agy-like, not a doorbell); `thread/status/changed` gives completion observation. D8 robustness (dedupe / crash recovery / ordering policy) is not tested. `turn/steer` is active-turn steering, not idle wake. |
|
|
115
|
+
| **Codex embedded TUI 0.136.0** | deferred | D0 partial | Native state DB / rollout transcript only | Standalone Embedded TUI binds no socket; no `FileChanged`/`asyncRewake` in Codex hooks; not retrofittable. Identify-only via state DB / rollout. |
|
|
116
|
+
| **Codex managed-daemon / remote-control 0.136.0** | deferred | D4–D6 conditional | `app-server proxy` newline JSON-RPC over the daemon control socket | Needs the managed standalone install; `remote-control` also enables the **cloud** bridge. Use the bare `--listen` path above for a purely-local setup. |
|
|
117
|
+
| **ACP Claude / Cortex (candidate)** | deferred | — | ACP (via entwurf's pi adapter) | Shipped as an ACP *runtime* lane (you can run Claude through ACP — see VERIFY/README), but **not a native-async-*delivery* target**: ACP sessions are bridge-spawned children, not already-running native sessions to wake, so they fall outside this doc's delivery question. `deferred` here means "no async-delivery lane," not "unsupported." Cortex is the candidate that would land on the ACP path next. |
|
|
118
|
+
|
|
119
|
+
## Backend notes
|
|
120
|
+
|
|
121
|
+
### Claude Code — filesystem event wake, not socket push
|
|
122
|
+
|
|
123
|
+
A missing local listening socket does **not** imply idle wake is impossible.
|
|
124
|
+
Claude Code interactive can be woken by a supported filesystem-event path:
|
|
125
|
+
|
|
126
|
+
1. a plugin or settings hook runs at `SessionStart`;
|
|
127
|
+
2. it emits `watchPaths` for a per-session signal file;
|
|
128
|
+
3. an external sender writes a per-session message and pokes that signal;
|
|
129
|
+
4. `FileChanged` fires while the session is idle;
|
|
130
|
+
5. the hook exits with `asyncRewake` and writes the doorbell to **stderr**;
|
|
131
|
+
6. the same session/model wakes and self-fetches the message body.
|
|
132
|
+
|
|
133
|
+
#### D8 partial — signal/body separation is level-triggered
|
|
134
|
+
|
|
135
|
+
Claude's `FileChanged` signal is an edge: rapid signal writes may coalesce, and a
|
|
136
|
+
true missed edge can leave an idle session with unread mail until another wake or
|
|
137
|
+
backstop occurs. The body is not carried in that edge. Bodies are durable mailbox
|
|
138
|
+
files (`*.msg` before the doorbell, `*.msg.delivered` after the doorbell), and
|
|
139
|
+
`entwurf_inbox_read` drains the whole unread set in one read and archives them as
|
|
140
|
+
`*.read`. Therefore a coalesced doorbell does not drop message bodies: once the
|
|
141
|
+
receiver self-fetches, it consumes all queued bodies, not "one event = one body".
|
|
142
|
+
|
|
143
|
+
Deterministic gates: `check-meta-session` asserts mixed fresh/delivered bodies are
|
|
144
|
+
drained together and re-read is empty; `smoke-meta-honesty` asserts the doorbell's
|
|
145
|
+
unread count matches what the inbox reader will drain. Remaining D8 work is still
|
|
146
|
+
honest/open in #34: empirical FileChanged coalescing bounds, active-turn arrival,
|
|
147
|
+
watchPath edge cases, compact-window re-arm gaps, and a heartbeat/re-poke backstop
|
|
148
|
+
for live sessions with unread mail.
|
|
149
|
+
|
|
150
|
+
Important gotchas live in [`scripts/raw-async-delivery/README.md`](./scripts/raw-async-delivery/README.md):
|
|
151
|
+
`Stop` hooks do not wake idle sessions, bare skills cannot arm startup watches,
|
|
152
|
+
plugins can, and imperatives in injected text can be flagged as prompt injection.
|
|
153
|
+
|
|
154
|
+
### Antigravity / agy — native push
|
|
155
|
+
|
|
156
|
+
Antigravity reaches the same delivery levels through a different transport:
|
|
157
|
+
`agy agentapi send-message` over the native LS gRPC surface. This is not a reason
|
|
158
|
+
to make the garden layer backend-specific; it is exactly why the adapter contract
|
|
159
|
+
must describe capability (`D0–D8`) separately from transport.
|
|
160
|
+
|
|
161
|
+
### Codex — split by launch mode, not by "Codex"
|
|
162
|
+
|
|
163
|
+
Do not describe "Codex" as one delivery shape. The split is the TUI's launch mode:
|
|
164
|
+
|
|
165
|
+
- **standalone Embedded TUI**: binds no socket, no `FileChanged`/`asyncRewake` in
|
|
166
|
+
Codex hooks, decision fixed at `run_main` → not addressable, not retrofittable;
|
|
167
|
+
- **app-server-backed TUI**: idle-wake **works**. Run a bare
|
|
168
|
+
`codex app-server --listen unix://$HOME/.codex/app-server-control/app-server-control.sock`
|
|
169
|
+
(no managed standalone, no cloud — only the official daemon path needs the
|
|
170
|
+
managed install). Plain `codex` (no `-c`) auto-attaches to that default socket;
|
|
171
|
+
an external WebSocket-over-UDS client sends `turn/start` to the live `threadId`.
|
|
172
|
+
Measured: idle thread woke with zero typing, body injected, model replied,
|
|
173
|
+
completion observed via `thread/status/changed`.
|
|
174
|
+
|
|
175
|
+
Sender: `raw-codex-ws-turn-start.py` → bare `--listen` socket (WebSocket, no managed
|
|
176
|
+
standalone, no cloud). A second surface exists but is out of scope here — the managed
|
|
177
|
+
**daemon** control socket (via `codex app-server proxy`) needs the managed standalone
|
|
178
|
+
install, and `remote-control` enables the cloud bridge; we ship only the bare-local
|
|
179
|
+
path. Per-folder `config.toml` `[projects."<path>"]` trust gates project-hook loading,
|
|
180
|
+
not addressability.
|
|
181
|
+
|
|
182
|
+
A Codex adapter must declare which launch mode + which socket it targets.
|
|
183
|
+
|
|
184
|
+
## How to use this in 0.12.0 design
|
|
185
|
+
|
|
186
|
+
For meta-sessions, peer records should expose capability rather than hiding
|
|
187
|
+
backend differences:
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
type WakeMode = "socket" | "file-watch" | "native-push" | "app-server" | "piggyback" | "none";
|
|
191
|
+
|
|
192
|
+
type DeliveryPeer = {
|
|
193
|
+
sessionId: string; // garden id
|
|
194
|
+
kind: "pi-session" | "meta-session";
|
|
195
|
+
backend: "pi" | "claude-code" | "agy" | "codex" | string;
|
|
196
|
+
replyable: boolean;
|
|
197
|
+
wakeMode: WakeMode;
|
|
198
|
+
deliveryLevel: "D0" | "D1" | "D2" | "D3" | "D4" | "D5" | "D6" | "D7" | "D8";
|
|
199
|
+
};
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
MVP rule of thumb:
|
|
203
|
+
|
|
204
|
+
- expose what is proven;
|
|
205
|
+
- mark partial/conditional honestly;
|
|
206
|
+
- keep transcript ownership native;
|
|
207
|
+
- treat liveness as best-effort hint (`last_seen` + native presence), not as a
|
|
208
|
+
single authoritative socket/WAL/file check;
|
|
209
|
+
- keep lookup authority in the meta-record scan, not a derived index.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Junghan Kim
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|