@junghanacs/entwurf 0.25.0 → 0.30.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.
Files changed (88) hide show
  1. package/AGENTS.md +1 -1
  2. package/BASELINE.md +1 -1
  3. package/CHANGELOG.md +182 -0
  4. package/CONTRIBUTING.md +1 -1
  5. package/DELIVERY.md +1 -1
  6. package/README.md +178 -674
  7. package/VERIFY.md +17 -16
  8. package/demo/README.md +1 -1
  9. package/docs/acp-backend-rail.md +6 -2
  10. package/docs/external-mcp-host.md +1 -1
  11. package/docs/setup-clean-host.md +346 -10
  12. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +27 -4
  13. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +12 -1
  14. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-peers-render.js +1 -1
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +2 -2
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-mailbox.js +2 -2
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +2 -2
  18. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +3 -5
  19. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-visible-resume.js +3 -3
  20. package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +13 -6
  21. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-mailbox-body.js +1 -1
  22. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +3 -3
  23. package/mcp/entwurf-bridge/src/index.ts +30 -3
  24. package/package.json +11 -11
  25. package/pi-extensions/entwurf-control.ts +50 -637
  26. package/pi-extensions/lib/acp/backend-adapter.ts +13 -1
  27. package/pi-extensions/lib/entwurf-fact-provider.ts +2 -2
  28. package/pi-extensions/lib/entwurf-mcp-server.ts +74 -0
  29. package/pi-extensions/lib/entwurf-peers-render.ts +1 -1
  30. package/pi-extensions/lib/entwurf-v2-decider.ts +2 -2
  31. package/pi-extensions/lib/entwurf-v2-mailbox.ts +2 -2
  32. package/pi-extensions/lib/entwurf-v2-production.ts +3 -3
  33. package/pi-extensions/lib/entwurf-v2-surface.ts +3 -5
  34. package/pi-extensions/lib/entwurf-v2-visible-resume.ts +3 -3
  35. package/pi-extensions/lib/fresh-call-composition.ts +13 -6
  36. package/pi-extensions/lib/meta-mailbox-body.ts +1 -1
  37. package/pi-extensions/lib/mux-fresh-call.ts +3 -3
  38. package/run.sh +168 -54
  39. package/scripts/check-entwurf-peers-surface.ts +8 -15
  40. package/scripts/check-entwurf-self-address.ts +7 -11
  41. package/scripts/check-entwurf-v2-surface.ts +20 -112
  42. package/scripts/check-fresh-call-dispatch.ts +12 -13
  43. package/scripts/check-gate-qualification.ts +2741 -157
  44. package/scripts/check-install-surface.ts +3 -2
  45. package/scripts/check-mux-resume-call.ts +24 -35
  46. package/scripts/check-pi-bridge-sender.ts +130 -0
  47. package/scripts/check-pi-mcp-bridge.ts +251 -0
  48. package/scripts/lib/codex-fresh-live-protocol.ts +17 -5
  49. package/scripts/lib/codex-fresh-source-receipts.ts +21 -2
  50. package/scripts/lib/mutation-qualify.ts +269 -44
  51. package/scripts/lib/pi-mcp-bridge-probe.mjs +170 -0
  52. package/scripts/lib/qualification-acceptance.ts +146 -0
  53. package/scripts/lib/qualification-artifact.ts +359 -0
  54. package/scripts/lib/qualification-collection.ts +384 -0
  55. package/scripts/lib/qualification-gh.ts +231 -0
  56. package/scripts/lib/qualification-ledger.ts +669 -0
  57. package/scripts/lib/qualification-oracle-core.ts +279 -0
  58. package/scripts/lib/qualification-receipt.ts +561 -0
  59. package/scripts/lib/qualification-release.ts +271 -0
  60. package/scripts/meta-bridge-doctor.sh +16 -5
  61. package/scripts/mutants/acp-foreground-only.json +17 -0
  62. package/scripts/mutants/codex-native.json +11 -11
  63. package/scripts/mutants/control-send-receipt.json +6 -4
  64. package/scripts/mutants/copilot-birth.json +2 -1
  65. package/scripts/mutants/fresh-call-dispatch.json +3 -14
  66. package/scripts/mutants/gate-qualification.json +59 -0
  67. package/scripts/mutants/mux-fresh-call.json +43 -45
  68. package/scripts/mutants/mux-resume-call.json +11 -35
  69. package/scripts/mutants/pack-install.json +15 -4
  70. package/scripts/mutants/pi-bridge-sender.json +54 -0
  71. package/scripts/mutants/pi-floor.json +6 -2
  72. package/scripts/mutants/pi-mcp-bridge.json +36 -0
  73. package/scripts/mutants/pi-mcp-register.json +51 -0
  74. package/scripts/mutants/qualification-ledger.json +489 -0
  75. package/scripts/mutants/v2-surface.json +6 -6
  76. package/scripts/qualification-oracle.ts +124 -0
  77. package/scripts/resident-rpc-drive.ts +5 -1
  78. package/scripts/smoke-acp-bundled-mcp-live.ts +3 -1
  79. package/scripts/smoke-acp-cortex-live.ts +3 -1
  80. package/scripts/smoke-acp-session-reuse-live.ts +29 -12
  81. package/scripts/smoke-acp-socket-citizen-live.ts +3 -1
  82. package/scripts/smoke-acp-v2-send-live.ts +3 -1
  83. package/scripts/smoke-codex-fresh-live.ts +20 -1
  84. package/scripts/smoke-entwurf-chain-live.ts +6 -2
  85. package/scripts/smoke-entwurf-v2-matrix-live.ts +3 -1
  86. package/scripts/smoke-herdr-raw-install-live.sh +8 -3
  87. package/scripts/smoke-mux-lifecycle-live.ts +1 -1
  88. package/scripts/smoke-resident-garden-guard.sh +3 -1
@@ -93,55 +93,31 @@
93
93
  "signatureSource": "scripts/check-mux-resume-call.ts"
94
94
  },
95
95
  {
96
- "claim": "MUXRESUME-PI-SURFACE-REGISTERED",
97
- "title": "the native pi registration is never called, so the verb exists in source and nowhere an operator can reach",
98
- "subject": "pi-extensions/entwurf-control.ts",
99
- "find": ["\t\tregisterResumeCallTool(pi);"],
100
- "replace": ["\t\tvoid registerResumeCallTool;"],
101
- "gate": ["bash", "run.sh", "check-mux-resume-call"],
102
- "timeoutSeconds": 60,
103
- "signature": "[QK:MUXRESUME-PI-SURFACE-REGISTERED]",
104
- "signatureSource": "scripts/check-mux-resume-call.ts"
105
- },
106
- {
107
- "claim": "MUXRESUME-PI-SURFACE-TARGET-ONLY",
108
- "title": "a task knob is added to the native schema, re-opening the prompt axis a resume deliberately does not have",
109
- "subject": "pi-extensions/entwurf-control.ts",
96
+ "claim": "MUXRESUME-DESC-CONTRACT-MCP",
97
+ "title": "the MCP description drops the dormant-only scope, inviting callers to aim the verb at live citizens it will refuse",
98
+ "subject": "mcp/entwurf-bridge/src/index.ts",
110
99
  "find": [
111
- "\t\t\t\tdescription: \"Garden id of the DORMANT pi citizen to reopen (discover with entwurf_peers).\",\n\t\t\t}),"
100
+ "\t\"Reopen ONE DORMANT pi citizen under its OWN garden id, in a visible window in the operator's own tmux \""
112
101
  ],
113
102
  "replace": [
114
- "\t\t\t\tdescription: \"Garden id of the DORMANT pi citizen to reopen (discover with entwurf_peers).\",\n\t\t\t}),\n\t\t\ttask: Type.String({ description: \"What the resumed citizen should do.\" }),"
103
+ "\t\"Reopen ONE pi citizen under its OWN garden id, in a visible window in the operator's own tmux \""
115
104
  ],
116
105
  "gate": ["bash", "run.sh", "check-mux-resume-call"],
117
106
  "timeoutSeconds": 60,
118
- "signature": "[QK:MUXRESUME-PI-SURFACE-TARGET-ONLY]",
119
- "signatureSource": "scripts/check-mux-resume-call.ts"
120
- },
121
- {
122
- "claim": "MUXRESUME-DESC-CONTRACT-PI",
123
- "title": "the native description stops saying a resume runs no turn, so a caller reasonably expects the citizen to act on being reopened",
124
- "subject": "pi-extensions/entwurf-control.ts",
125
- "find": ["This runs NO turn: the window comes\nback with the conversation and waits"],
126
- "replace": ["The window comes\nback with the conversation and waits"],
127
- "gate": ["bash", "run.sh", "check-mux-resume-call"],
128
- "timeoutSeconds": 60,
129
- "signature": "[QK:MUXRESUME-DESC-CONTRACT-PI]",
107
+ "signature": "[QK:MUXRESUME-DESC-CONTRACT-MCP]",
130
108
  "signatureSource": "scripts/check-mux-resume-call.ts"
131
109
  },
132
110
  {
133
- "claim": "MUXRESUME-DESC-CONTRACT-MCP",
134
- "title": "the MCP description drops the dormant-only scope, inviting callers to aim the verb at live citizens it will refuse",
111
+ "claim": "MUXRESUME-MCP-TARGET-PASSTHROUGH",
112
+ "title": "the bridge resume handler substitutes a constant id for the caller's target, so the record lookup reopens a citizen nobody named while the target-only schema stays green",
135
113
  "subject": "mcp/entwurf-bridge/src/index.ts",
136
- "find": [
137
- "\t\"Reopen ONE DORMANT pi citizen under its OWN garden id, in a visible window in the operator's own tmux \""
138
- ],
114
+ "find": ["\t\t\tconst result = await visibleResume(target, makeVisibleResumeDeps(visibleResumeLaunch));"],
139
115
  "replace": [
140
- "\t\"Reopen ONE pi citizen under its OWN garden id, in a visible window in the operator's own tmux \""
116
+ "\t\t\tconst result = await visibleResume(\"20260101T000000-feed00\", makeVisibleResumeDeps(visibleResumeLaunch));"
141
117
  ],
142
118
  "gate": ["bash", "run.sh", "check-mux-resume-call"],
143
119
  "timeoutSeconds": 60,
144
- "signature": "[QK:MUXRESUME-DESC-CONTRACT-MCP]",
120
+ "signature": "[QK:MUXRESUME-MCP-TARGET-PASSTHROUGH]",
145
121
  "signatureSource": "scripts/check-mux-resume-call.ts"
146
122
  }
147
123
  ]
@@ -6,8 +6,8 @@
6
6
  "claim": "PACK-INSTALL-PIN-MATCHER-BOUNDED",
7
7
  "title": "the pin-leak matcher loses its version boundary and blesses substring lookalikes — @0.85.10 reads as the pinned 0.85.1 and the gate announces a verified tree it never verified (independent review, 2026-08-25)",
8
8
  "subject": "run.sh",
9
- "find": [" grep '^@earendil-works+' | grep -Ev '@0\\.87\\.1(_|$)' || true"],
10
- "replace": [" grep '^@earendil-works+' | grep -v '@0\\.87\\.0' || true"],
9
+ "find": [" grep '^@earendil-works+' | grep -Ev '@1\\.0\\.0(_|$)' || true"],
10
+ "replace": [" grep '^@earendil-works+' | grep -v '@0\\.87\\.1' || true"],
11
11
  "gate": ["bash", "run.sh", "check-pack-pin-matcher"],
12
12
  "timeoutSeconds": 120,
13
13
  "signature": "[QK:PACK-INSTALL-PIN-MATCHER-BOUNDED]",
@@ -17,12 +17,23 @@
17
17
  "claim": "PACK-INSTALL-PIN-MATCHER-COVERS-CLOSURE",
18
18
  "title": "the pin-leak matcher narrows back to the pi-* families and goes blind to a non-pi member of the same runtime closure — @earendil-works/chord (new in pi 0.85.0, a runtime dependency of pi-coding-agent/pi-agent-core/pi-client/pi-protocol) floats unpinned while the gate prints a verified pin (measured 2026-09-06 on a real 0.85.1 install tree)",
19
19
  "subject": "run.sh",
20
- "find": [" grep '^@earendil-works+' | grep -Ev '@0\\.87\\.1(_|$)' || true"],
21
- "replace": [" grep '^@earendil-works+pi-' | grep -Ev '@0\\.87\\.1(_|$)' || true"],
20
+ "find": [" grep '^@earendil-works+' | grep -Ev '@1\\.0\\.0(_|$)' || true"],
21
+ "replace": [" grep '^@earendil-works+pi-' | grep -Ev '@1\\.0\\.0(_|$)' || true"],
22
22
  "gate": ["bash", "run.sh", "check-pack-pin-matcher"],
23
23
  "timeoutSeconds": 120,
24
24
  "signature": "[QK:PACK-INSTALL-PIN-MATCHER-COVERS-CLOSURE]",
25
25
  "signatureSource": "run.sh"
26
+ },
27
+ {
28
+ "claim": "PACK-INSTALL-CONSUMER-ROOTS-CONTAINED",
29
+ "title": "a consumer subcall stops naming its own PI_CODING_AGENT_DIR, so an inherited agent dir wins over the sandbox HOME and the consumer's user-scope registration lands outside it (measured 2026-10-01, #125)",
30
+ "subject": "run.sh",
31
+ "find": [" \"XDG_CACHE_HOME=$h/.cache\" \\\n \"PI_CODING_AGENT_DIR=$h/.pi/agent\""],
32
+ "replace": [" \"XDG_CACHE_HOME=$h/.cache\""],
33
+ "gate": ["bash", "run.sh", "check-pack-consumer-roots"],
34
+ "timeoutSeconds": 120,
35
+ "signature": "[QK:PACK-INSTALL-CONSUMER-ROOTS-CONTAINED]",
36
+ "signatureSource": "run.sh"
26
37
  }
27
38
  ]
28
39
  }
@@ -0,0 +1,54 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "lane": "pi-bridge-sender",
4
+ "mutants": [
5
+ {
6
+ "claim": "PI-BRIDGE-SENDER-RECORD-BACKED",
7
+ "title": "the backing check starts treating a missing control socket as inadmissible, so a dormant pi citizen loses its own identity instead of answering replyable:false",
8
+ "subject": "mcp/entwurf-bridge/src/index.ts",
9
+ "find": ["\tif (identity.backend !== \"pi\") {"],
10
+ "replace": [
11
+ "\tif (identity.backend !== \"pi\" || !existsSync(controlSocketPathIn(ENTWURF_DIR, envelope.sessionId))) {"
12
+ ],
13
+ "gate": ["bash", "run.sh", "check-pi-bridge-sender"],
14
+ "timeoutSeconds": 60,
15
+ "signature": "[QK:PI-BRIDGE-SENDER-RECORD-BACKED]",
16
+ "signatureSource": "scripts/check-pi-bridge-sender.ts"
17
+ },
18
+ {
19
+ "claim": "PI-BRIDGE-SENDER-MISSING-REFUSED",
20
+ "title": "the pi branch returns the raw carrier again, so any well-formed PI_SESSION_ID is served as a sender whether or not a record exists",
21
+ "subject": "mcp/entwurf-bridge/src/index.ts",
22
+ "find": ["\tif (pi && pi.sessionId === selected.id) return { envelope: requirePiSenderRecord(pi) };"],
23
+ "replace": ["\tif (pi && pi.sessionId === selected.id) return { envelope: pi };"],
24
+ "gate": ["bash", "run.sh", "check-pi-bridge-sender"],
25
+ "timeoutSeconds": 60,
26
+ "signature": "[QK:PI-BRIDGE-SENDER-MISSING-REFUSED]",
27
+ "signatureSource": "scripts/check-pi-bridge-sender.ts"
28
+ },
29
+ {
30
+ "claim": "PI-BRIDGE-SENDER-BACKEND-REFUSED",
31
+ "title": "the backend check is dropped, so a PI_SESSION_ID naming another harness's record is served as a pi sender",
32
+ "subject": "mcp/entwurf-bridge/src/index.ts",
33
+ "find": ["\tif (identity.backend !== \"pi\") {"],
34
+ "replace": ["\tif (identity.backend === undefined) {"],
35
+ "gate": ["bash", "run.sh", "check-pi-bridge-sender"],
36
+ "timeoutSeconds": 60,
37
+ "signature": "[QK:PI-BRIDGE-SENDER-BACKEND-REFUSED]",
38
+ "signatureSource": "scripts/check-pi-bridge-sender.ts"
39
+ },
40
+ {
41
+ "claim": "PI-BRIDGE-SENDER-UNREADABLE-CAUSE",
42
+ "title": "reader failures are flattened into the absent-record refusal, so a corrupt store reads as a citizen that simply does not exist",
43
+ "subject": "mcp/entwurf-bridge/src/index.ts",
44
+ "find": ["\tconst identity = readMetaIdentityByGardenId(envelope.sessionId);"],
45
+ "replace": [
46
+ "\tconst identity = (() => {\n\t\ttry {\n\t\t\treturn readMetaIdentityByGardenId(envelope.sessionId);\n\t\t} catch {\n\t\t\tthrow new Error(`no meta-record for garden id \"${envelope.sessionId}\"`);\n\t\t}\n\t})();"
47
+ ],
48
+ "gate": ["bash", "run.sh", "check-pi-bridge-sender"],
49
+ "timeoutSeconds": 60,
50
+ "signature": "[QK:PI-BRIDGE-SENDER-UNREADABLE-CAUSE]",
51
+ "signatureSource": "scripts/check-pi-bridge-sender.ts"
52
+ }
53
+ ]
54
+ }
@@ -6,8 +6,12 @@
6
6
  "claim": "PI-FLOOR-SINGLE-SOURCE",
7
7
  "title": "one row of the pnpm workspace closure is left on the previous floor while every other surface moved — the shape a version bump actually fails in. Nothing else reads that file, so the stranded row surfaces only at install time, in a different command, far from the change that stranded it",
8
8
  "subject": "pnpm-workspace.yaml",
9
- "find": [" - '@earendil-works/pi-telemetry@0.85.0 || 0.85.1 || 0.86.0 || 0.87.0 || 0.87.1'"],
10
- "replace": [" - '@earendil-works/pi-telemetry@0.85.0 || 0.85.1 || 0.86.0'"],
9
+ "find": [
10
+ " - '@earendil-works/pi-telemetry@0.85.0 || 0.85.1 || 0.86.0 || 0.87.0 || 0.87.1 || 0.99.1 || 0.99.2 || 1.0.0'"
11
+ ],
12
+ "replace": [
13
+ " - '@earendil-works/pi-telemetry@0.85.0 || 0.85.1 || 0.86.0 || 0.87.0 || 0.87.1 || 0.99.1 || 0.99.2'"
14
+ ],
11
15
  "gate": ["bash", "run.sh", "check-dep-versions"],
12
16
  "timeoutSeconds": 300,
13
17
  "signature": "[QK:PI-FLOOR-SINGLE-SOURCE]",
@@ -0,0 +1,36 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "lane": "pi-mcp-bridge",
4
+ "mutants": [
5
+ {
6
+ "claim": "PI-MCP-BRIDGE-DECLARED-SURFACE",
7
+ "title": "entwurf_self joins the hidden list, so a pi model is no longer declared the verb that tells it who it is",
8
+ "subject": "pi-extensions/lib/entwurf-mcp-server.ts",
9
+ "find": [
10
+ "export const ENTWURF_MCP_HIDDEN_TOOLS = [\"entwurf_inbox_read\", \"entwurf_register_native\"] as const;"
11
+ ],
12
+ "replace": [
13
+ "export const ENTWURF_MCP_HIDDEN_TOOLS = [\"entwurf_inbox_read\", \"entwurf_register_native\", \"entwurf_self\"] as const;"
14
+ ],
15
+ "gate": ["bash", "run.sh", "check-pi-mcp-bridge"],
16
+ "timeoutSeconds": 120,
17
+ "signature": "[QK:PI-MCP-BRIDGE-DECLARED-SURFACE]",
18
+ "signatureSource": "scripts/check-pi-mcp-bridge.ts",
19
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
20
+ },
21
+ {
22
+ "claim": "PI-MCP-BRIDGE-SAME-CHILD-IDENTITY",
23
+ "title": "the explicit carrier is built from the model label when one is known, so the spawned child claims an identity no record holds",
24
+ "subject": "pi-extensions/lib/entwurf-mcp-server.ts",
25
+ "find": ["\t\tenv: { PI_SESSION_ID: input.gardenId, ...(input.agentId ? { PI_AGENT_ID: input.agentId } : {}) },"],
26
+ "replace": [
27
+ "\t\tenv: { PI_SESSION_ID: input.agentId ?? input.gardenId, ...(input.agentId ? { PI_AGENT_ID: input.agentId } : {}) },"
28
+ ],
29
+ "gate": ["bash", "run.sh", "check-pi-mcp-bridge"],
30
+ "timeoutSeconds": 120,
31
+ "signature": "[QK:PI-MCP-BRIDGE-SAME-CHILD-IDENTITY]",
32
+ "signatureSource": "scripts/check-pi-mcp-bridge.ts",
33
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
34
+ }
35
+ ]
36
+ }
@@ -0,0 +1,51 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "lane": "pi-mcp-register",
4
+ "mutants": [
5
+ {
6
+ "claim": "PI-MCP-REGISTER-AFTER-BIRTH",
7
+ "title": "the extension factory registers the bridge at load, before any record exists — the server is on Pi's registry with no born identity to carry",
8
+ "subject": "pi-extensions/entwurf-control.ts",
9
+ "find": ["\tpi.registerMessageRenderer(SESSION_MESSAGE_TYPE, renderSessionMessage);"],
10
+ "replace": [
11
+ "\tpi.registerMessageRenderer(SESSION_MESSAGE_TYPE, renderSessionMessage);",
12
+ "\tpi.registerMcpServer(ENTWURF_MCP_SERVER_NAME, { command: process.execPath, args: [] });"
13
+ ],
14
+ "gate": ["bash", "run.sh", "check-pi-mcp-register"],
15
+ "timeoutSeconds": 60,
16
+ "signature": "[QK:PI-MCP-REGISTER-AFTER-BIRTH]",
17
+ "signatureSource": "pi-extensions/entwurf-control.test.ts",
18
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
19
+ },
20
+ {
21
+ "claim": "PI-MCP-IDENTITY-BEFORE-UI",
22
+ "title": "the status line is rendered before the registration, so a UI failure leaves a born citizen without its verbs",
23
+ "subject": "pi-extensions/entwurf-control.ts",
24
+ "find": [
25
+ "\t\tregisterEntwurfMcpServer(pi, ctx, birth.gardenId);",
26
+ "\t\tupdateStatus(ctx, true, birth.gardenId);"
27
+ ],
28
+ "replace": [
29
+ "\t\tupdateStatus(ctx, true, birth.gardenId);",
30
+ "\t\tregisterEntwurfMcpServer(pi, ctx, birth.gardenId);"
31
+ ],
32
+ "gate": ["bash", "run.sh", "check-pi-mcp-register"],
33
+ "timeoutSeconds": 60,
34
+ "signature": "[QK:PI-MCP-IDENTITY-BEFORE-UI]",
35
+ "signatureSource": "pi-extensions/entwurf-control.test.ts",
36
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
37
+ },
38
+ {
39
+ "claim": "PI-MCP-EXPOSURE",
40
+ "title": "the verbs are registered behind codemode instead of declared directly, so the model is handed a different surface than every other host",
41
+ "subject": "pi-extensions/lib/entwurf-mcp-server.ts",
42
+ "find": ["\t\texposure: \"direct\","],
43
+ "replace": ["\t\texposure: \"codemode\","],
44
+ "gate": ["bash", "run.sh", "check-pi-mcp-register"],
45
+ "timeoutSeconds": 60,
46
+ "signature": "[QK:PI-MCP-EXPOSURE]",
47
+ "signatureSource": "pi-extensions/entwurf-control.test.ts",
48
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
49
+ }
50
+ ]
51
+ }