@staix/agent-hub 0.20.0 → 0.21.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 (175) hide show
  1. package/CHANGELOG.md +59 -3
  2. package/README.md +2 -2
  3. package/docs/agent-notes/README.md +11 -0
  4. package/docs/agent-notes/adapters.md +7 -3
  5. package/docs/agent-notes/benchmarks.md +27 -0
  6. package/docs/agent-notes/budget.md +2 -1
  7. package/docs/agent-notes/bus.md +2 -2
  8. package/docs/agent-notes/daemon.md +15 -6
  9. package/docs/agent-notes/local-worker.md +4 -0
  10. package/docs/agent-notes/models.md +2 -0
  11. package/docs/agent-notes/tasks.md +17 -9
  12. package/docs/agent-notes/tests.md +9 -2
  13. package/docs/bench.md +1 -1
  14. package/docs/data-policy.md +2 -0
  15. package/docs/dogfood.md +37 -4
  16. package/docs/events.md +2 -1
  17. package/docs/memory.md +9 -3
  18. package/docs/operations.md +565 -62
  19. package/docs/profiles.md +13 -1
  20. package/docs/quickstart.md +14 -9
  21. package/docs/research.md +7 -4
  22. package/docs/sdlc.md +54 -10
  23. package/docs/security.md +396 -34
  24. package/docs/smoke.md +127 -0
  25. package/docs/specs/2026-09-19-agent-hub-design.md +1070 -22
  26. package/docs/verification/2026-10-27-0.19.0.md +5 -5
  27. package/docs/verification/2026-10-28-claude-2.1.311-2.1.312-bash-permission.json +635 -0
  28. package/docs/verification/2026-10-28-claude-2.1.311-2.1.312-permission-transport.json +403 -0
  29. package/docs/verification/2026-10-28-claude-implementer-permission-triage.md +123 -0
  30. package/docs/verification/2026-10-28-jcode-0.99.1-usage.md +41 -0
  31. package/docs/verification/2026-10-28-realpath-name-audit.md +222 -0
  32. package/docs/verification/2026-10-28-routing-f0bb8ad0.md +1000 -0
  33. package/docs/verification/2026-10-29-0.21.0.md +61 -0
  34. package/docs/verification/2026-10-29-model-effort-capabilities.md +123 -0
  35. package/docs/verification/2026-10-29-modelrouting-b152ddb9.md +953 -0
  36. package/docs/verification/claude-implementer-permission-triage.ts +160 -0
  37. package/docs/verification/claude-permission-transport-native.py +71 -14
  38. package/docs/verification/profiles/YYYY-MM-DD-research.md +1 -1
  39. package/docs/verified.json +15 -15
  40. package/package.json +2 -2
  41. package/plugins/agent-hub/.claude-plugin/plugin.json +1 -1
  42. package/plugins/agent-hub/server.js +1016 -280
  43. package/src/adapters/acp.ts +79 -3
  44. package/src/adapters/channel-peer.ts +4 -0
  45. package/src/adapters/claude-channel.ts +13 -6
  46. package/src/adapters/claude-implementer.ts +60 -7
  47. package/src/adapters/codex-appserver.ts +77 -4
  48. package/src/adapters/conformance/fakes/jcode-agent.ts +6 -2
  49. package/src/adapters/conformance/kit.ts +3 -9
  50. package/src/adapters/definitions/builtin-metadata.ts +3 -114
  51. package/src/adapters/definitions/native-config-defaults.ts +1 -1
  52. package/src/adapters/definitions/native-config-policy.ts +3 -2
  53. package/src/adapters/definitions/native-context.ts +12 -0
  54. package/src/adapters/external-metadata.ts +48 -0
  55. package/src/adapters/external-modules.ts +63 -3
  56. package/src/adapters/jcode.ts +6 -2
  57. package/src/adapters/local-worker.ts +40 -25
  58. package/src/adapters/native-proof-ports.ts +10 -0
  59. package/src/adapters/registry-types.ts +4 -0
  60. package/src/broker/protocol.ts +203 -0
  61. package/src/broker/server.ts +314 -0
  62. package/src/broker/store.ts +548 -0
  63. package/src/cli/bench.ts +3 -2
  64. package/src/cli/broker.ts +58 -0
  65. package/src/cli/conductor-recovery.ts +142 -0
  66. package/src/cli/configured-acp-entry.ts +26 -6
  67. package/src/cli/console-state.ts +59 -17
  68. package/src/cli/console.ts +17 -2
  69. package/src/cli/facts-hook.ts +3 -1
  70. package/src/cli/help.ts +28 -16
  71. package/src/cli/identity.ts +23 -10
  72. package/src/cli/init.ts +34 -7
  73. package/src/cli/intake-output.ts +33 -0
  74. package/src/cli/main.ts +314 -71
  75. package/src/cli/output.ts +41 -1
  76. package/src/cli/recovery-package.ts +18 -1
  77. package/src/cli/role-holders.ts +35 -0
  78. package/src/cli/room.ts +304 -0
  79. package/src/cli/say-input.ts +16 -0
  80. package/src/cli/schedule-output.ts +49 -0
  81. package/src/cli/sdlc-output.ts +44 -6
  82. package/src/cli/smoke-pty-bridge.ts +33 -0
  83. package/src/cli/smoke-pty.ts +145 -0
  84. package/src/cli/smoke-run.ts +139 -0
  85. package/src/cli/smoke-target.ts +130 -0
  86. package/src/cli/source-output.ts +29 -0
  87. package/src/cli/task-output.ts +3 -2
  88. package/src/cli/upgrade-runtime.ts +98 -16
  89. package/src/cli/upgrade.ts +66 -7
  90. package/src/hub/ask.ts +76 -12
  91. package/src/hub/board.ts +132 -22
  92. package/src/hub/bus.ts +399 -56
  93. package/src/hub/child-process.ts +2 -0
  94. package/src/hub/ci-watch.ts +42 -20
  95. package/src/hub/claude-failure-stage.ts +85 -0
  96. package/src/hub/claude-shell-wrapper.ts +11 -5
  97. package/src/hub/conductor.ts +17 -4
  98. package/src/hub/config-apply.ts +32 -5
  99. package/src/hub/config-reload.ts +7 -5
  100. package/src/hub/config-trust.ts +7 -1
  101. package/src/hub/context-window.ts +33 -3
  102. package/src/hub/control-client.ts +14 -2
  103. package/src/hub/corpus-config.ts +34 -0
  104. package/src/hub/corpus-evidence.ts +184 -0
  105. package/src/hub/corpus.ts +373 -0
  106. package/src/hub/cost-governance.ts +26 -0
  107. package/src/hub/daemon.ts +1150 -171
  108. package/src/hub/deliverable-files.ts +8 -2
  109. package/src/hub/delivery-journal.ts +123 -17
  110. package/src/hub/dogfood-profile.ts +32 -5
  111. package/src/hub/dogfood-read.ts +6 -2
  112. package/src/hub/envelope.ts +11 -0
  113. package/src/hub/eval-gate.ts +131 -0
  114. package/src/hub/events.ts +1 -1
  115. package/src/hub/external-instance.ts +69 -0
  116. package/src/hub/facts.ts +15 -5
  117. package/src/hub/folder-trigger.ts +223 -0
  118. package/src/hub/hub-tools.ts +2 -1
  119. package/src/hub/inference.ts +20 -5
  120. package/src/hub/instance-config.ts +69 -3
  121. package/src/hub/instance-execution.ts +6 -2
  122. package/src/hub/instances.ts +32 -4
  123. package/src/hub/intake.ts +125 -0
  124. package/src/hub/learning.ts +85 -0
  125. package/src/hub/lifecycle.ts +7 -3
  126. package/src/hub/limits.ts +12 -5
  127. package/src/hub/native-permission-request.ts +77 -0
  128. package/src/hub/operational-authority.ts +63 -5
  129. package/src/hub/operational-settings.ts +76 -0
  130. package/src/hub/operational-view.ts +1 -1
  131. package/src/hub/packs.ts +132 -0
  132. package/src/hub/path-policy.ts +7 -0
  133. package/src/hub/peer-doing.ts +130 -0
  134. package/src/hub/peers.ts +12 -0
  135. package/src/hub/queue-backpressure.ts +58 -0
  136. package/src/hub/read-tools.ts +2 -0
  137. package/src/hub/recovery-authority.ts +151 -0
  138. package/src/hub/recovery-policy.ts +220 -0
  139. package/src/hub/research.ts +24 -14
  140. package/src/hub/restart.ts +7 -0
  141. package/src/hub/routing.ts +54 -11
  142. package/src/hub/schedules.ts +266 -0
  143. package/src/hub/sdlc-merge.ts +38 -14
  144. package/src/hub/sdlc-metrics.ts +32 -10
  145. package/src/hub/sdlc-queue.ts +7 -1
  146. package/src/hub/sdlc-release.ts +1 -1
  147. package/src/hub/sdlc.ts +37 -7
  148. package/src/hub/security-baseline.ts +38 -0
  149. package/src/hub/settings.ts +6 -1
  150. package/src/hub/shipped-packs.ts +8 -0
  151. package/src/hub/snapshots.ts +72 -6
  152. package/src/hub/source-read.ts +160 -0
  153. package/src/hub/sources.ts +311 -0
  154. package/src/hub/tasks.ts +910 -110
  155. package/src/hub/workflow.ts +1 -1
  156. package/src/local/doc-read.ts +69 -0
  157. package/src/local/proxy.ts +4 -13
  158. package/src/local/tools.ts +37 -3
  159. package/src/local/web-fetch-config.ts +43 -0
  160. package/src/local/web-fetch.ts +183 -0
  161. package/src/memory/brief.ts +85 -13
  162. package/src/memory/capture.ts +1 -1
  163. package/src/rooms/application.ts +114 -0
  164. package/src/rooms/boundary.ts +103 -0
  165. package/src/rooms/commands.ts +294 -0
  166. package/src/rooms/crypto.ts +371 -0
  167. package/src/rooms/link.ts +584 -0
  168. package/src/rooms/policy.ts +82 -0
  169. package/src/rooms/remote-peer.ts +80 -0
  170. package/src/rooms/service.ts +426 -0
  171. package/src/rooms/status.ts +146 -0
  172. package/src/rooms/store.ts +1210 -0
  173. package/src/rooms/wire.ts +465 -0
  174. package/src/ui/index.html +91 -4
  175. package/templates/packs/example.pack.json +13 -0
@@ -0,0 +1,403 @@
1
+ {
2
+ "date": "2026-10-28",
3
+ "producer": "claude-permission-transport-native.py",
4
+ "sourceHead": "f7450129",
5
+ "account": false,
6
+ "inference": false,
7
+ "fixtureMcp": true,
8
+ "productionDaemon": false,
9
+ "hostWrapperRewriting": false,
10
+ "certified": true,
11
+ "cases": [
12
+ {
13
+ "version": "2.1.311",
14
+ "binarySha256": "85d8c08707fcfd1e78ffa0204eefbc6ec9e4fe22f375fb2767ef85d957ed3161",
15
+ "case": "allow",
16
+ "nativeExit": 0,
17
+ "stoppedExternally": false,
18
+ "mcpCalls": 1,
19
+ "fileWritten": true,
20
+ "toolResultErrors": [
21
+ null
22
+ ],
23
+ "resultFrame": [
24
+ {
25
+ "is_error": false,
26
+ "denials": 0
27
+ }
28
+ ],
29
+ "elapsedSeconds": 0.309,
30
+ "requests": 2,
31
+ "passed": true,
32
+ "nativeGroupEmpty": true,
33
+ "binaryUnchanged": true
34
+ },
35
+ {
36
+ "version": "2.1.311",
37
+ "binarySha256": "85d8c08707fcfd1e78ffa0204eefbc6ec9e4fe22f375fb2767ef85d957ed3161",
38
+ "case": "deny",
39
+ "nativeExit": 0,
40
+ "stoppedExternally": false,
41
+ "mcpCalls": 1,
42
+ "fileWritten": false,
43
+ "toolResultErrors": [
44
+ true
45
+ ],
46
+ "resultFrame": [
47
+ {
48
+ "is_error": false,
49
+ "denials": 1
50
+ }
51
+ ],
52
+ "elapsedSeconds": 0.315,
53
+ "requests": 2,
54
+ "passed": true,
55
+ "nativeGroupEmpty": true,
56
+ "binaryUnchanged": true
57
+ },
58
+ {
59
+ "version": "2.1.311",
60
+ "binarySha256": "85d8c08707fcfd1e78ffa0204eefbc6ec9e4fe22f375fb2767ef85d957ed3161",
61
+ "case": "missing-tool",
62
+ "nativeExit": 1,
63
+ "stoppedExternally": false,
64
+ "mcpCalls": 0,
65
+ "fileWritten": false,
66
+ "toolResultErrors": [
67
+ true
68
+ ],
69
+ "resultFrame": [],
70
+ "elapsedSeconds": 0.311,
71
+ "requests": 1,
72
+ "passed": true,
73
+ "nativeGroupEmpty": true,
74
+ "binaryUnchanged": true
75
+ },
76
+ {
77
+ "version": "2.1.311",
78
+ "binarySha256": "85d8c08707fcfd1e78ffa0204eefbc6ec9e4fe22f375fb2767ef85d957ed3161",
79
+ "case": "hook-deny",
80
+ "nativeExit": 0,
81
+ "stoppedExternally": false,
82
+ "mcpCalls": 1,
83
+ "fileWritten": false,
84
+ "toolResultErrors": [
85
+ true
86
+ ],
87
+ "resultFrame": [
88
+ {
89
+ "is_error": false,
90
+ "denials": 1
91
+ }
92
+ ],
93
+ "elapsedSeconds": 0.315,
94
+ "requests": 2,
95
+ "passed": true,
96
+ "nativeGroupEmpty": true,
97
+ "binaryUnchanged": true
98
+ },
99
+ {
100
+ "version": "2.1.311",
101
+ "binarySha256": "85d8c08707fcfd1e78ffa0204eefbc6ec9e4fe22f375fb2767ef85d957ed3161",
102
+ "case": "hook-allow",
103
+ "nativeExit": 0,
104
+ "stoppedExternally": false,
105
+ "mcpCalls": 1,
106
+ "fileWritten": true,
107
+ "toolResultErrors": [
108
+ null
109
+ ],
110
+ "resultFrame": [
111
+ {
112
+ "is_error": false,
113
+ "denials": 0
114
+ }
115
+ ],
116
+ "elapsedSeconds": 0.312,
117
+ "requests": 2,
118
+ "passed": true,
119
+ "nativeGroupEmpty": true,
120
+ "binaryUnchanged": true
121
+ },
122
+ {
123
+ "version": "2.1.311",
124
+ "binarySha256": "85d8c08707fcfd1e78ffa0204eefbc6ec9e4fe22f375fb2767ef85d957ed3161",
125
+ "case": "mcp-error",
126
+ "nativeExit": 0,
127
+ "stoppedExternally": false,
128
+ "mcpCalls": 1,
129
+ "fileWritten": false,
130
+ "toolResultErrors": [
131
+ true
132
+ ],
133
+ "resultFrame": [
134
+ {
135
+ "is_error": false,
136
+ "denials": 0
137
+ }
138
+ ],
139
+ "elapsedSeconds": 0.31,
140
+ "requests": 2,
141
+ "passed": true,
142
+ "nativeGroupEmpty": true,
143
+ "binaryUnchanged": true
144
+ },
145
+ {
146
+ "version": "2.1.311",
147
+ "binarySha256": "85d8c08707fcfd1e78ffa0204eefbc6ec9e4fe22f375fb2767ef85d957ed3161",
148
+ "case": "disconnect",
149
+ "nativeExit": 0,
150
+ "stoppedExternally": false,
151
+ "mcpCalls": 1,
152
+ "fileWritten": false,
153
+ "toolResultErrors": [
154
+ true
155
+ ],
156
+ "resultFrame": [
157
+ {
158
+ "is_error": false,
159
+ "denials": 0
160
+ }
161
+ ],
162
+ "elapsedSeconds": 0.246,
163
+ "requests": 2,
164
+ "passed": true,
165
+ "nativeGroupEmpty": true,
166
+ "binaryUnchanged": true
167
+ },
168
+ {
169
+ "version": "2.1.311",
170
+ "binarySha256": "85d8c08707fcfd1e78ffa0204eefbc6ec9e4fe22f375fb2767ef85d957ed3161",
171
+ "case": "pending",
172
+ "nativeExit": null,
173
+ "stoppedExternally": true,
174
+ "mcpCalls": 1,
175
+ "fileWritten": false,
176
+ "toolResultErrors": [],
177
+ "resultFrame": [],
178
+ "elapsedSeconds": 25.016,
179
+ "requests": 1,
180
+ "passed": true,
181
+ "nativeGroupEmpty": true,
182
+ "binaryUnchanged": true
183
+ },
184
+ {
185
+ "version": "2.1.311",
186
+ "binarySha256": "85d8c08707fcfd1e78ffa0204eefbc6ec9e4fe22f375fb2767ef85d957ed3161",
187
+ "case": "deadline",
188
+ "nativeExit": 0,
189
+ "stoppedExternally": false,
190
+ "mcpCalls": 1,
191
+ "fileWritten": false,
192
+ "toolResultErrors": [
193
+ true
194
+ ],
195
+ "resultFrame": [
196
+ {
197
+ "is_error": false,
198
+ "denials": 1
199
+ }
200
+ ],
201
+ "elapsedSeconds": 0.422,
202
+ "requests": 2,
203
+ "passed": true,
204
+ "nativeGroupEmpty": true,
205
+ "binaryUnchanged": true
206
+ },
207
+ {
208
+ "version": "2.1.312",
209
+ "binarySha256": "6b5ec691195e551b02c41df9f7d723f4ea61eaa03c2df90acefe3736f1aeb620",
210
+ "case": "allow",
211
+ "nativeExit": 0,
212
+ "stoppedExternally": false,
213
+ "mcpCalls": 1,
214
+ "fileWritten": true,
215
+ "toolResultErrors": [
216
+ null
217
+ ],
218
+ "resultFrame": [
219
+ {
220
+ "is_error": false,
221
+ "denials": 0
222
+ }
223
+ ],
224
+ "elapsedSeconds": 0.315,
225
+ "requests": 2,
226
+ "passed": true,
227
+ "nativeGroupEmpty": true,
228
+ "binaryUnchanged": true
229
+ },
230
+ {
231
+ "version": "2.1.312",
232
+ "binarySha256": "6b5ec691195e551b02c41df9f7d723f4ea61eaa03c2df90acefe3736f1aeb620",
233
+ "case": "deny",
234
+ "nativeExit": 0,
235
+ "stoppedExternally": false,
236
+ "mcpCalls": 1,
237
+ "fileWritten": false,
238
+ "toolResultErrors": [
239
+ true
240
+ ],
241
+ "resultFrame": [
242
+ {
243
+ "is_error": false,
244
+ "denials": 1
245
+ }
246
+ ],
247
+ "elapsedSeconds": 0.308,
248
+ "requests": 2,
249
+ "passed": true,
250
+ "nativeGroupEmpty": true,
251
+ "binaryUnchanged": true
252
+ },
253
+ {
254
+ "version": "2.1.312",
255
+ "binarySha256": "6b5ec691195e551b02c41df9f7d723f4ea61eaa03c2df90acefe3736f1aeb620",
256
+ "case": "missing-tool",
257
+ "nativeExit": 1,
258
+ "stoppedExternally": false,
259
+ "mcpCalls": 0,
260
+ "fileWritten": false,
261
+ "toolResultErrors": [
262
+ true
263
+ ],
264
+ "resultFrame": [],
265
+ "elapsedSeconds": 0.318,
266
+ "requests": 1,
267
+ "passed": true,
268
+ "nativeGroupEmpty": true,
269
+ "binaryUnchanged": true
270
+ },
271
+ {
272
+ "version": "2.1.312",
273
+ "binarySha256": "6b5ec691195e551b02c41df9f7d723f4ea61eaa03c2df90acefe3736f1aeb620",
274
+ "case": "hook-deny",
275
+ "nativeExit": 0,
276
+ "stoppedExternally": false,
277
+ "mcpCalls": 1,
278
+ "fileWritten": false,
279
+ "toolResultErrors": [
280
+ true
281
+ ],
282
+ "resultFrame": [
283
+ {
284
+ "is_error": false,
285
+ "denials": 1
286
+ }
287
+ ],
288
+ "elapsedSeconds": 0.306,
289
+ "requests": 2,
290
+ "passed": true,
291
+ "nativeGroupEmpty": true,
292
+ "binaryUnchanged": true
293
+ },
294
+ {
295
+ "version": "2.1.312",
296
+ "binarySha256": "6b5ec691195e551b02c41df9f7d723f4ea61eaa03c2df90acefe3736f1aeb620",
297
+ "case": "hook-allow",
298
+ "nativeExit": 0,
299
+ "stoppedExternally": false,
300
+ "mcpCalls": 1,
301
+ "fileWritten": true,
302
+ "toolResultErrors": [
303
+ null
304
+ ],
305
+ "resultFrame": [
306
+ {
307
+ "is_error": false,
308
+ "denials": 0
309
+ }
310
+ ],
311
+ "elapsedSeconds": 0.304,
312
+ "requests": 2,
313
+ "passed": true,
314
+ "nativeGroupEmpty": true,
315
+ "binaryUnchanged": true
316
+ },
317
+ {
318
+ "version": "2.1.312",
319
+ "binarySha256": "6b5ec691195e551b02c41df9f7d723f4ea61eaa03c2df90acefe3736f1aeb620",
320
+ "case": "mcp-error",
321
+ "nativeExit": 0,
322
+ "stoppedExternally": false,
323
+ "mcpCalls": 1,
324
+ "fileWritten": false,
325
+ "toolResultErrors": [
326
+ true
327
+ ],
328
+ "resultFrame": [
329
+ {
330
+ "is_error": false,
331
+ "denials": 0
332
+ }
333
+ ],
334
+ "elapsedSeconds": 0.317,
335
+ "requests": 2,
336
+ "passed": true,
337
+ "nativeGroupEmpty": true,
338
+ "binaryUnchanged": true
339
+ },
340
+ {
341
+ "version": "2.1.312",
342
+ "binarySha256": "6b5ec691195e551b02c41df9f7d723f4ea61eaa03c2df90acefe3736f1aeb620",
343
+ "case": "disconnect",
344
+ "nativeExit": 0,
345
+ "stoppedExternally": false,
346
+ "mcpCalls": 1,
347
+ "fileWritten": false,
348
+ "toolResultErrors": [
349
+ true
350
+ ],
351
+ "resultFrame": [
352
+ {
353
+ "is_error": false,
354
+ "denials": 0
355
+ }
356
+ ],
357
+ "elapsedSeconds": 0.247,
358
+ "requests": 2,
359
+ "passed": true,
360
+ "nativeGroupEmpty": true,
361
+ "binaryUnchanged": true
362
+ },
363
+ {
364
+ "version": "2.1.312",
365
+ "binarySha256": "6b5ec691195e551b02c41df9f7d723f4ea61eaa03c2df90acefe3736f1aeb620",
366
+ "case": "pending",
367
+ "nativeExit": null,
368
+ "stoppedExternally": true,
369
+ "mcpCalls": 1,
370
+ "fileWritten": false,
371
+ "toolResultErrors": [],
372
+ "resultFrame": [],
373
+ "elapsedSeconds": 25.011,
374
+ "requests": 1,
375
+ "passed": true,
376
+ "nativeGroupEmpty": true,
377
+ "binaryUnchanged": true
378
+ },
379
+ {
380
+ "version": "2.1.312",
381
+ "binarySha256": "6b5ec691195e551b02c41df9f7d723f4ea61eaa03c2df90acefe3736f1aeb620",
382
+ "case": "deadline",
383
+ "nativeExit": 0,
384
+ "stoppedExternally": false,
385
+ "mcpCalls": 1,
386
+ "fileWritten": false,
387
+ "toolResultErrors": [
388
+ true
389
+ ],
390
+ "resultFrame": [
391
+ {
392
+ "is_error": false,
393
+ "denials": 1
394
+ }
395
+ ],
396
+ "elapsedSeconds": 0.417,
397
+ "requests": 2,
398
+ "passed": true,
399
+ "nativeGroupEmpty": true,
400
+ "binaryUnchanged": true
401
+ }
402
+ ]
403
+ }
@@ -0,0 +1,123 @@
1
+ # Claude implementer permission triage
2
+
3
+ Date: 2026-10-28. Scope: agent-hub task 544, source inspection, isolated fake fixtures and a model-free native transport comparison. Reported target: Claude Code 2.1.312, explicitly trusted but not receipt-verified, using `ask-when-needed`.
4
+
5
+ The reported symptoms are a permission-tool harness error before `bun test test/ci-watch.test.ts` executes, and approval-waiting notices when the person's console appears empty, followed by expiry. This report does not treat those observations as a reproduced native defect. No production source, permission ceiling, COMPAT entry, installed native binary or account configuration changes in this triage.
6
+
7
+ ## Evidence status
8
+
9
+ | Evidence | Status and limit |
10
+ | --- | --- |
11
+ | Version admission, wrapper and approval source paths | Read at the triage base `f7450129` |
12
+ | Opt-in deterministic fake diagnostic cases | Corrected committed-head run at `9263ff67db8273a7f0b71c83d63a843ae5a628e0`: 15 pass, 0 fail, 116 assertions across the diagnostic and two related suites. Initial fixture-only assertion failures are corrected |
13
+ | Installed native generic permission transport | 2.1.311 and 2.1.312 each 9/9 pass using the existing Python fixture MCP and loopback provider; no production-daemon or host-wrapper rewrite claim |
14
+ | Native Bash transport and plain command replacement | Strict production-name/schema comparison: 18 transport cases and 4 allow/deny replacement cases passed across 2.1.311 and 2.1.312; no production-daemon or host-wrapper execution claim |
15
+ | Native production-daemon task/host-wrapper rewrite at 2.1.312 | Unverified |
16
+ | Person's reported incident and console connection identity | Not independently reproduced |
17
+ | Real provider, model, credentials or account interaction | Not run |
18
+ | Exact-head gate and hosted CI | Recorded separately by the implementer after verification |
19
+
20
+ ## Source-backed conclusions
21
+
22
+ There is no verified-only host-wrapper gate. `assessVersion` in `src/adapters/compat.ts` admits the person's exact machine trust as `ok: true, state: "trusted"`. `proveClaudeImplementer` in `src/adapters/claude-implementer.ts` checks that admission and the binary fingerprint; it does not require the verdict's state to be `verified`. The adapter's native argv retains `default`, the strict MCP inventory and the permission prompt tool for both admitted states.
23
+
24
+ `automaticImplementerShell` in `src/hub/daemon.ts` has no independent native-version predicate. Its gates are current child/generation, isolated execution root, an owned public task, `ask-when-needed`, closed command/input shape, current branch/default-branch evidence, public metadata, action-policy checks and the required host confinement. `taskShellCommand` recognizes `bun test test/ci-watch.test.ts` lexically. Recognition alone grants nothing. Executable test/build/check requests require `sandboxAvailable()`; an unsupported host follows the ordinary person approval path. This is expected behavior, not evidence that the trusted version was silently disabled.
25
+
26
+ A failure can occur before any console approval exists. The production MCP handler in `src/adapters/claude-channel.ts` requires `tool_name`, an object `input` and a nonempty `tool_use_id`; invalid arguments return a fixed denial before requesting the daemon. The daemon also refuses an unavailable or stale owned-child/root binding before entering `requestPermission`. The 2.1.309/2.1.310 receipts prove their observed native schema and rewrite behavior, not 2.1.312's behavior. The generic native transport probe below observes the expected request schema, but a production-daemon or host-wrapper incompatibility in the reported incident remains unverified.
27
+
28
+ Approval transport uses one shared daemon map. `requestPermission` registers the row before `writeStatus` and the `permission` push, and a fresh console's `tail` request replays all still-pending pushes. The console-role `status` RPC exposes body-free approval ids/times through `status.attentionItems`; the console-role `ui_snapshot` RPC exposes the full pending rows as `permissions`, projected from the same map. The internal attention input has an `approvals` array, but that is not a field of the ordinary status RPC. Expiry removes the row before emitting closure and resolving the native request as a denial.
29
+
30
+ The console keeps actionable approval rows from `permission` and `permission_closed` pushes. Status attention metadata does not contain the full title/options needed to reconstruct those rows. A deliberately omitted push therefore leaves the controlled fixture's approval panel empty until a valid push is supplied. This is a push-omission characteristic, not a reproduced product defect or the established cause of the reported incident. Source ordering shows `runConsole` installs `client.onPush` before sending `tail`, and the daemon replays still-pending rows on that subscription; no normal console-startup race was found. An expired/cancelled request, another project/instance connection, pre-queue native failure or an actual missing push must be distinguished using the same request id and daemon instance.
31
+
32
+ `OwnedPrintChild` ignores native stderr, and `ClaudeImplementerPeer` reduces an unsuccessful native result to the fixed `Claude implementer turn failed` outcome. Consequently the generic delivery failure alone does not establish which native permission-harness stage failed. Do not infer a host wrapper refusal, a missing person answer or a native compatibility defect from that generic outcome.
33
+
34
+ ## Isolated fake fixture
35
+
36
+ The opt-in diagnostic producer uses a fresh HOME, CLAUDE_CONFIG_DIR, AGENTHUB_HOME and AMEM_HOME; a disposable Git repository and separate non-default-branch worktree; an outside-project Git shim with system/global config disabled; a fake native executable answering only its synthetic version and recording argv/launch metadata; and actual daemon, control-client, MCP channel and console code. Memory, inference, MLX and automatic Pi startup are disabled. A fixed host default-branch test port prevents a GitHub query. No installed Claude binary, personal authentication file or provider is selected, and an issued wrapper ticket is never redeemed.
37
+
38
+ The fake reports 2.1.312 while that version is unverified. If a later dated receipt verifies it, the fixture uses a synthetic unverified version to retain its admission-policy test without blocking legitimate COMPAT updates. This is not a native compatibility assertion.
39
+
40
+ | Case | Required observation |
41
+ | --- | --- |
42
+ | Trusted, unverified fake version | Startup admitted with native `default` and the fixed prompt-tool argv; no bypass mode |
43
+ | Closed test command | On a sandbox-capable host, host protocol 1 rewrites the command; without the host sandbox, ordinary approval expires as deny, with no rewrite |
44
+ | Real daemon manual approval | Same request id appears in the live console push, `ui_snapshot.permissions`, status attention metadata and a fresh console's tail replay, then is withdrawn on its fixture deadline |
45
+ | Missing `tool_use_id` | Actual production source MCP handler returns `invalid native permission request`, with no approval row or permission push |
46
+ | Deliberately withheld console push | Real-shaped fake `status.attentionItems` alone supplies no actionable approval row; a later valid push makes the request visible |
47
+
48
+ The console case deliberately omits a permission push. It lives outside the automatic regression suite and is not evidence of a normal transport or startup failure. It adds no production repair or broader authorization. The host command case tests policy using a fake native. Neither certifies the installed 2.1.312 permission dispatcher, real model tool selection or a person's live approval interaction.
49
+
50
+ ## Installed native transport comparison
51
+
52
+ The original Write mode of `claude-permission-transport-native.py` ran sequentially on the
53
+ installed 2.1.311 control and 2.1.312 target with fresh private homes and a synthetic
54
+ loopback provider. Each passed all 9 allow/deny/hook/MCP-error/disconnect/pending/
55
+ deadline cases. All 18 owned native groups were established empty and all binary
56
+ hashes were unchanged. No account or inference call occurred. The sanitized
57
+ [transport receipt](2026-10-28-claude-2.1.311-2.1.312-permission-transport.json)
58
+ contains counts, fixed outcomes and binary hashes only.
59
+
60
+ | Version | SHA-256 | Cases |
61
+ | --- | --- | --- |
62
+ | 2.1.311 | `85d8c08707fcfd1e78ffa0204eefbc6ec9e4fe22f375fb2767ef85d957ed3161` | 9/9 |
63
+ | 2.1.312 | `6b5ec691195e551b02c41df9f7d723f4ea61eaa03c2df90acefe3736f1aeb620` | 9/9 |
64
+
65
+ Host admission observed memory-pressure level 1, zero swap, thermal state 0 and
66
+ 76.4% CPU idle on 18 logical CPUs; no other local build/test job was running.
67
+ Each native case retained the producer's 25-second bound and owned-group cleanup.
68
+ This reproduced normal permission behavior, not the reported harness error. The
69
+ fixture MCP is deliberately separate from the production SDK channel and daemon
70
+ policy. No COMPAT value is changed and no new host-wrapper receipt is claimed.
71
+
72
+ ## Native Bash transport and rewrite comparison
73
+
74
+ The producer now accepts optional `--tool Write|Bash`, `--rewrite-bash`, `--server-name`, `--permission-tool` and `--require-tool-use-id` flags. The default remains the original nine-case Write table, original request/response checks, permission mode, isolated environment, 25-second external deadline, owned-group cleanup and binary fence. The optional modes ran sequentially at committed producer head `243d4b535404d911ea2b1c728352d4abd82e5ea6`. Strict Bash transport passed all 18 cases, and exact-command replacement passed all 4 allow/deny cases across the two binaries.
75
+
76
+ | Mode | Cases per supplied binary | Observed behavior |
77
+ | --- | --- | --- |
78
+ | Default or `--tool Write` | 9 | Original Write allow/deny/hook/MCP-error/disconnect/pending/deadline behavior |
79
+ | `--tool Bash` | 9 | Same case table using an explicitly asked Bash command that only prints `probe` into the fixture target |
80
+ | `--tool Bash --rewrite-bash` | 2 | Allow and deny only; original native command is exactly `bun test test/ci-watch.test.ts` |
81
+
82
+ The server/tool names default to `fixture`/`approve` and accept only bounded ASCII letters, digits, underscores and hyphens with an initial letter. `--server-name agent-hub --permission-tool hub_permission_request` selects the exact production namespace `mcp__agent-hub__hub_permission_request`. The strict-schema flag adds required `tool_use_id`, the production name/id length bounds and `additionalProperties: false`; the default keeps the original two-field requirement. Bash settings ask for Bash with no newly granted `permission.allow` entry, matching the earlier wrapper fixture. These flags select a production-name/schema comparison; the fixture remains separate from the production MCP implementation.
83
+
84
+ In rewrite mode a private executable named `bun` is prepended to the native fixture PATH. A dummy `test/ci-watch.test.ts` exists under the disposable work directory for command-shape fidelity. If the original command runs, the shim records an execution marker and fails. Only the allow MCP server receives the replacement command, a harmless `printf` writer to the fixture target. The returned `updatedInput` is retained and checked exactly, the original `tool_name`, input and `tool_use_id` remain required, the original-execution marker must stay absent in both cases, and the target may contain `probe` only for allow. The final cleanup rechecks the original-execution marker. No repository test command or real Bun test is intended to run, and this probe imports neither `HostShellWrapper` nor the current daemon.
85
+
86
+ This isolates native Bash argument replacement from the host's command-admission and sandbox policy. The successful run establishes only that specific fixture exchange on the supplied binaries, not production SDK/daemon behavior, a new trusted/verified version, real account behavior or a complete host-wrapper receipt. The original fake Bun execution marker remained absent in all four rewrite cases; the replacement wrote the fixture target only for allow. All 22 owned native groups were empty and binary hashes unchanged. The model-free comparison did not reproduce the reported harness failure.
87
+
88
+ The sanitized [Bash transport receipt](2026-10-28-claude-2.1.311-2.1.312-bash-permission.json) contains fixed outcomes, counts, timings, producer hash and native binary hashes, with no command text, prompt, token, session id or path. Native admission at the start observed memory pressure 1, zero swap, thermal state 0, CPU idle 73.29%, load 5.88 on 18 logical CPUs, and no other local repository test/build job. The single worker ran sequentially, then released the slot.
89
+
90
+ ## Commands for the implementer
91
+
92
+ Explicit fake diagnostic command, after committing the intended files and taking the permitted remote slot. The first remote run accepted this explicit regular `.ts` path; the corrected diagnostic passed the committed-head rerun above:
93
+
94
+ ```sh
95
+ env -u AGENTHUB_HOME bun test ./docs/verification/claude-implementer-permission-triage.ts
96
+ ```
97
+
98
+ Native Bash reproduction commands, after host-resource admission and review of the explicit installed paths, using two different new private output directories:
99
+
100
+ ```sh
101
+ python3 docs/verification/claude-permission-transport-native.py "$BASH_TRANSPORT_OUTPUT" --tool Bash --server-name agent-hub --permission-tool hub_permission_request --require-tool-use-id --claude "$CLAUDE_CONTROL_BINARY" --claude "$CLAUDE_2312_BINARY"
102
+ python3 docs/verification/claude-permission-transport-native.py "$BASH_REWRITE_OUTPUT" --tool Bash --rewrite-bash --server-name agent-hub --permission-tool hub_permission_request --require-tool-use-id --claude "$CLAUDE_CONTROL_BINARY" --claude "$CLAUDE_2312_BINARY"
103
+ ```
104
+
105
+ The required repository gate remains `scripts/check.sh --changed` at that committed head. Any macOS host-wrapper positive branch must be reported separately from the Linux branch that deliberately asks without `sandbox-exec`.
106
+
107
+ The existing [host-wrapper receipt](2026-10-26-headless-claude-shell-context.md) names 2.1.309 and 2.1.310, not 2.1.311. Its unchanged `claude-shell-wrapper-native.py` explicitly accepts only those two versions, so it cannot be invoked with 2.1.312 as a valid reproduction command. The task description's reference to a 2.1.311 wrapper receipt is not supported by that checked-in document. No newer wrapper receipt was found in `docs/verification/` at this base.
108
+
109
+ Before proposing any verified-version bump, adapt and review that wrapper producer for the new binaries, then repeat both the wrapper and [generic transport](2026-10-23-headless-claude-permissions.md) procedures. The wrapper procedure must retain strict MCP, empty settings sources, synthetic loopback provider, isolated homes, the external deadline, exact original request/rewritten reply checks, replay effect count, owned cleanup and binary fences. It imports current production code and requires the pinned local dependencies. This triage does not run it with the Mac's stale ancestor dependency installation and does not claim a new wrapper receipt.
110
+
111
+ ## Remaining unknowns
112
+
113
+ - The exact 2.1.312 native permission request, schema validation result, MCP reply and native tool-result error from the reported incident.
114
+ - Whether the failing command reached `permission_request` and the wrapper proof, reached the manual queue, or failed before either.
115
+ - Whether the reportedly empty console was attached to the same daemon instance and request id while the row was still pending.
116
+ - Whether a controlled missed-push case occurs in normal use, beyond the deterministic console fixture.
117
+ - Production-daemon/native host-wrapper behavior on 2.1.312 and a real person's account-backed approval leg. Generic Write and strict-schema Bash transport, including exact-command replacement, passed the isolated comparison above.
118
+
119
+ ## Disposition
120
+
121
+ No production defect was reproduced, so this triage makes no source repair or permission relaxation. The trusted-versus-verified hypothesis is contradicted by the source and isolated admission fixture. The generic native-schema/replacement hypothesis did not reproduce in the 2.1.311/2.1.312 comparison. Ordinary daemon approval registration, inventory, push, late subscription and expiry passed the fake task fixture. The deliberately omitted-push case demonstrates a UI information boundary, not an observed normal-use defect.
122
+
123
+ The incident remains unresolved without its original native tool-result error and the matching daemon instance/request id. The exact sanitized error and timing were requested from the reporting implementer. A subsequent incident should correlate whether a permission row was created, the live console's project/instance, and whether its tail received that same row before expiry. No additional prompt/body logging is proposed here. Existing native stderr suppression and fixed failure outcomes limit retrospective attribution.
@@ -0,0 +1,41 @@
1
+ # Jcode 0.99.1 usage and context receipt (#801)
2
+
3
+ Date: 2026-10-28. Refs #801. Installed release build, read through `--quiet version --json`: `semver` 0.99.1, `version` `v0.99.1 (7206efd0c)`. Host macOS arm64, Bun 1. The receipt records event shapes and counters only: no prompt, no model output beyond the fixed word the fake replied with, no credential, no account identifier.
4
+
5
+ ## What was run
6
+
7
+ An isolated `HOME` and `JCODE_HOME` (fresh directories under the scratch area, an empty `mcp.json`, no credentials, no account), `JCODE_NO_TELEMETRY=1` and `JCODE_DISABLE_CLAUDE_MCP=1` as the adapter sets them. One `openai-compatible` profile `fakegw` (added with `jcode provider add ... --no-api-key`, written only into the isolated `config.toml`) pointed at a local server on `127.0.0.1` that streamed a fixed reply and a final `usage` chunk whose numbers the probe chose, so each number Jcode reported could be compared with the number sent. No real provider, key or model was involved.
8
+
9
+ `jcode serve` and `jcode acp` were started with the argv `jcodeCommand` builds (`--socket`, `--cwd`, `--no-update`, `--no-selfdev`, `--model`, `--provider-profile`, `--temporary-server`, `--mcp-tools eager`), a session was created, and three prompts were sent. Before the run the SHA-256 of the four real config files directly in `~/.jcode` (`auth.json`, `auth-refresh-state.json`, `config.toml`, `mcp.json`) was taken and compared after the last leg: unchanged. No process whose command line named the sandbox was left running.
10
+
11
+ ## Shapes observed on the ACP stream
12
+
13
+ Per prompt, in this order: `available_commands_update` (first prompt only), `agent_message_chunk`, one `usage_update` per provider call, then the `session/prompt` result.
14
+
15
+ - **`usage_update`**: `{ sessionUpdate: "usage_update", used: <integer>, size: <integer> }` inside `session/update` params that carry the ACP `sessionId`. Nothing else. In Jcode's own source (`src/cli/acp.rs`) it is written on each `TokenUsage` server event: `used` is `effective_context_tokens_from_usage` of that provider call (`crates/jcode-compaction-core/src/lib.rs`): the input count alone for OpenAI-named providers and when the cache is a subset of it, and the input plus the cache read and cache creation counts for Anthropic or Claude named providers and when the numbers show split accounting (a cache creation, or a cache read above the input). `size` is the model's context limit (200000 for the fake model, which falls to Jcode's default). The source was read on GitHub at the default branch; the installed 0.99.1 binary's behaviour was observed only for the input-only case the fake gateway produced. The sequence of one two-call turn (a tool call, then the answer) was `used` 1000 then 1100 for provider inputs 1000 and 1100: occupancy of the last call, not an accumulated sum.
16
+ - **Prompt result**: `{ stopReason: "end_turn", usage: { inputTokens, outputTokens, cachedReadTokens, totalTokens } }`. `cachedWriteTokens` is in the source and absent when the provider reports no cache write. For the same two-call turn the result said `inputTokens` 2100 and `outputTokens` 40: the sum of the two calls (1000 + 1100, 10 + 30), so it is per turn, not a session total. A turn whose provider call reported no usage chunk had no `usage` member at all.
17
+ - **`totalTokens` adds the cached read on top of the input**: sent input 1234, output 56, cached 100; Jcode reported `inputTokens` 1234, `outputTokens` 56, `cachedReadTokens` 100, `totalTokens` 1390 (input + output + cached). For OpenAI-style providers the input already contains the cached part, so that total counts it twice. The hub never reads `totalTokens` from Jcode.
18
+ - **No other usage or context message** appeared: no ACP method other than `session/update`, and no `usage_update` carrying `totalTokens` or any ratio, window or reset.
19
+ - **`jcode usage --json`** (the account usage command) under the same isolated home printed `{ "providers": [] }`: no provider connected, so no sample of a limit. From Jcode's source its schema is `providers: [{ provider_name, limits: [{ name, usage_percent, resets_at, reset_in }], extra_info: [[key, value]], banked_reset?, error }]`. `name` is free text and no window length is given.
20
+
21
+ ## What the hub does with it
22
+
23
+ | Jcode record | Host projection | Why |
24
+ | --- | --- | --- |
25
+ | `usage_update` `{used, size}` | `ContextReading` source `jcode_usage_update`, bound to the adapter's own ACP session id, with the measurement time | live-session occupancy, the same kind as Kimi's and Codex's readings |
26
+ | prompt result `usage` | one `usage` event per prompt, source `jcode_acp`: `inputTokens`, `outputTokens`, `cacheReadTokens`, `cacheWriteTokens` when present, task attribution, no `totalTokens` | per-turn consumption in the provider's own buckets |
27
+ | `usage_update` | never a `tokens` event, a hub token window or a quota window | occupancy is not consumption |
28
+ | prompt result `usage` | never a context reading, never a quota window | consumption is not occupancy and says nothing of a limit |
29
+
30
+ A reading with a malformed field (`used` or `size` not a non-negative safe integer, `size` not positive), for another session than the daemon's current one, older than `context.stale_min`, or from a peer that is not attached, is unknown in `ahub status`, the console and the dashboard: never zero and never healthy. A result without both `inputTokens` and `outputTokens` as non-negative safe integers writes no usage record; a present but malformed cache bucket is dropped alone.
31
+
32
+ ## Not supported, and why
33
+
34
+ - **Native quota windows.** Jcode declares no quota reader. `jcode usage --json` gives a free-text `name`, a percentage and a reset time but no window length, so mapping it to the hub's window ids would parse vendor prose, which #801 rules out. With no account it returned no provider at all, so there is no sample of a real limit either. `ahub budget` keeps `no reading` for Jcode, and the manual `ahub budget set` path is unchanged. Revisit when Jcode names the window length (and an account is available to record a real sample).
35
+ - **Served-model evidence.** The ACP stream carries no served model in either record, so the usage event has none; the hub does not infer one from the requested model.
36
+ - **Real account and provider.** Every number above came from a local fake gateway. A real provider's cache semantics (Anthropic reports cache apart from input, OpenAI includes it) are taken from Jcode's own documentation and source, not observed here, which is why the hub records the buckets and never a derived total.
37
+ - **The TUI form.** `jcode --resume` runs the same ACP-owned session; the TUI's own context display was not read.
38
+
39
+ ## Decision
40
+
41
+ The two measurements with structured evidence (occupancy, and per-turn token buckets) are supported on 0.99.1. Everything else stays unknown. `docs/verification/2026-10-26-jcode-0.99.1.md` remains the contract receipt a later version repeats; a later version repeats this receipt's probe too before its usage readings are claimed.