@namzu/sdk 27.1.0 → 29.0.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 (1427) hide show
  1. package/CHANGELOG.md +1757 -0
  2. package/README.md +45 -42
  3. package/dist/advisory/executor.d.ts.map +1 -1
  4. package/dist/advisory/executor.js +14 -12
  5. package/dist/advisory/executor.js.map +1 -1
  6. package/dist/advisory/registry.d.ts +2 -2
  7. package/dist/advisory/registry.d.ts.map +1 -1
  8. package/dist/advisory/registry.js +2 -2
  9. package/dist/advisory/registry.js.map +1 -1
  10. package/dist/agents/AbstractAgent.d.ts +44 -2
  11. package/dist/agents/AbstractAgent.d.ts.map +1 -1
  12. package/dist/agents/AbstractAgent.js +62 -13
  13. package/dist/agents/AbstractAgent.js.map +1 -1
  14. package/dist/agents/PipelineAgent.d.ts +29 -1
  15. package/dist/agents/PipelineAgent.d.ts.map +1 -1
  16. package/dist/agents/PipelineAgent.js +33 -4
  17. package/dist/agents/PipelineAgent.js.map +1 -1
  18. package/dist/agents/ReactiveAgent.d.ts +2 -1
  19. package/dist/agents/ReactiveAgent.d.ts.map +1 -1
  20. package/dist/agents/ReactiveAgent.js +15 -6
  21. package/dist/agents/ReactiveAgent.js.map +1 -1
  22. package/dist/agents/RouterAgent.d.ts +2 -1
  23. package/dist/agents/RouterAgent.d.ts.map +1 -1
  24. package/dist/agents/RouterAgent.js +21 -13
  25. package/dist/agents/RouterAgent.js.map +1 -1
  26. package/dist/agents/SupervisorAgent.d.ts +3 -2
  27. package/dist/agents/SupervisorAgent.d.ts.map +1 -1
  28. package/dist/agents/SupervisorAgent.js +29 -16
  29. package/dist/agents/SupervisorAgent.js.map +1 -1
  30. package/dist/agents/handle.d.ts +85 -0
  31. package/dist/agents/handle.d.ts.map +1 -0
  32. package/dist/agents/handle.js +79 -0
  33. package/dist/agents/handle.js.map +1 -0
  34. package/dist/agents/runAgent.d.ts +10 -5
  35. package/dist/agents/runAgent.d.ts.map +1 -1
  36. package/dist/agents/runAgent.js +3 -2
  37. package/dist/agents/runAgent.js.map +1 -1
  38. package/dist/{verification → authorization}/gate.d.ts +4 -4
  39. package/dist/authorization/gate.d.ts.map +1 -0
  40. package/dist/{verification → authorization}/gate.js +31 -24
  41. package/dist/authorization/gate.js.map +1 -0
  42. package/dist/authorization/index.d.ts +6 -0
  43. package/dist/authorization/index.d.ts.map +1 -0
  44. package/dist/authorization/index.js +14 -0
  45. package/dist/authorization/index.js.map +1 -0
  46. package/dist/authorization/permission-presets.d.ts +119 -0
  47. package/dist/authorization/permission-presets.d.ts.map +1 -0
  48. package/dist/authorization/permission-presets.js +137 -0
  49. package/dist/authorization/permission-presets.js.map +1 -0
  50. package/dist/{verification → authorization}/presets.d.ts +3 -3
  51. package/dist/authorization/presets.d.ts.map +1 -0
  52. package/dist/{verification → authorization}/presets.js +12 -0
  53. package/dist/authorization/presets.js.map +1 -0
  54. package/dist/authorization/rules.d.ts +4 -0
  55. package/dist/authorization/rules.d.ts.map +1 -0
  56. package/dist/{verification → authorization}/rules.js +14 -1
  57. package/dist/authorization/rules.js.map +1 -0
  58. package/dist/bridge/a2a/client.d.ts +107 -0
  59. package/dist/bridge/a2a/client.d.ts.map +1 -0
  60. package/dist/bridge/a2a/client.js +275 -0
  61. package/dist/bridge/a2a/client.js.map +1 -0
  62. package/dist/bridge/a2a/mapper.d.ts.map +1 -1
  63. package/dist/bridge/a2a/mapper.js +16 -0
  64. package/dist/bridge/a2a/mapper.js.map +1 -1
  65. package/dist/bridge/acp/filesystem.d.ts +33 -0
  66. package/dist/bridge/acp/filesystem.d.ts.map +1 -0
  67. package/dist/bridge/acp/filesystem.js +30 -0
  68. package/dist/bridge/acp/filesystem.js.map +1 -0
  69. package/dist/bridge/acp/index.d.ts +8 -0
  70. package/dist/bridge/acp/index.d.ts.map +1 -0
  71. package/dist/bridge/acp/index.js +5 -0
  72. package/dist/bridge/acp/index.js.map +1 -0
  73. package/dist/bridge/acp/permission.d.ts +51 -0
  74. package/dist/bridge/acp/permission.d.ts.map +1 -0
  75. package/dist/bridge/acp/permission.js +37 -0
  76. package/dist/bridge/acp/permission.js.map +1 -0
  77. package/dist/bridge/acp/server.d.ts +163 -0
  78. package/dist/bridge/acp/server.d.ts.map +1 -0
  79. package/dist/bridge/acp/server.js +312 -0
  80. package/dist/bridge/acp/server.js.map +1 -0
  81. package/dist/bridge/acp/update.d.ts +13 -0
  82. package/dist/bridge/acp/update.d.ts.map +1 -0
  83. package/dist/bridge/acp/update.js +94 -0
  84. package/dist/bridge/acp/update.js.map +1 -0
  85. package/dist/bridge/mcp/connector/adapter.d.ts +2 -0
  86. package/dist/bridge/mcp/connector/adapter.d.ts.map +1 -1
  87. package/dist/bridge/mcp/connector/adapter.js +7 -3
  88. package/dist/bridge/mcp/connector/adapter.js.map +1 -1
  89. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  90. package/dist/bridge/sse/mapper.js +27 -0
  91. package/dist/bridge/sse/mapper.js.map +1 -1
  92. package/dist/bus/breaker.d.ts.map +1 -1
  93. package/dist/bus/breaker.js +15 -10
  94. package/dist/bus/breaker.js.map +1 -1
  95. package/dist/bus/index.d.ts.map +1 -1
  96. package/dist/bus/index.js +10 -8
  97. package/dist/bus/index.js.map +1 -1
  98. package/dist/bus/lock.d.ts.map +1 -1
  99. package/dist/bus/lock.js +36 -19
  100. package/dist/bus/lock.js.map +1 -1
  101. package/dist/bus/ownership.d.ts.map +1 -1
  102. package/dist/bus/ownership.js +17 -9
  103. package/dist/bus/ownership.js.map +1 -1
  104. package/dist/compaction/context-window.d.ts +18 -2
  105. package/dist/compaction/context-window.d.ts.map +1 -1
  106. package/dist/compaction/context-window.js +15 -1
  107. package/dist/compaction/context-window.js.map +1 -1
  108. package/dist/compaction/index.d.ts +3 -0
  109. package/dist/compaction/index.d.ts.map +1 -1
  110. package/dist/compaction/index.js +4 -0
  111. package/dist/compaction/index.js.map +1 -1
  112. package/dist/compaction/manual.d.ts +58 -0
  113. package/dist/compaction/manual.d.ts.map +1 -0
  114. package/dist/compaction/manual.js +104 -0
  115. package/dist/compaction/manual.js.map +1 -0
  116. package/dist/compaction/plan.d.ts +92 -0
  117. package/dist/compaction/plan.d.ts.map +1 -0
  118. package/dist/compaction/plan.js +149 -0
  119. package/dist/compaction/plan.js.map +1 -0
  120. package/dist/compaction/summary.d.ts +23 -0
  121. package/dist/compaction/summary.d.ts.map +1 -0
  122. package/dist/compaction/summary.js +27 -0
  123. package/dist/compaction/summary.js.map +1 -0
  124. package/dist/compaction/verifier.js +2 -2
  125. package/dist/compaction/verifier.js.map +1 -1
  126. package/dist/config/registry.d.ts +104 -0
  127. package/dist/config/registry.d.ts.map +1 -0
  128. package/dist/config/registry.js +105 -0
  129. package/dist/config/registry.js.map +1 -0
  130. package/dist/config/runtime.d.ts +107 -36
  131. package/dist/config/runtime.d.ts.map +1 -1
  132. package/dist/config/runtime.js +27 -0
  133. package/dist/config/runtime.js.map +1 -1
  134. package/dist/connector/BaseConnector.d.ts +1 -1
  135. package/dist/connector/BaseConnector.d.ts.map +1 -1
  136. package/dist/connector/BaseConnector.js +8 -3
  137. package/dist/connector/BaseConnector.js.map +1 -1
  138. package/dist/connector/builtins/http.d.ts +1 -1
  139. package/dist/connector/builtins/http.d.ts.map +1 -1
  140. package/dist/connector/builtins/http.js +11 -2
  141. package/dist/connector/builtins/http.js.map +1 -1
  142. package/dist/connector/builtins/webhook.d.ts +1 -1
  143. package/dist/connector/builtins/webhook.d.ts.map +1 -1
  144. package/dist/connector/builtins/webhook.js +5 -2
  145. package/dist/connector/builtins/webhook.js.map +1 -1
  146. package/dist/connector/index.d.ts +4 -15
  147. package/dist/connector/index.d.ts.map +1 -1
  148. package/dist/connector/index.js +12 -12
  149. package/dist/connector/index.js.map +1 -1
  150. package/dist/connector/mcp/client.d.ts.map +1 -1
  151. package/dist/connector/mcp/client.js +31 -20
  152. package/dist/connector/mcp/client.js.map +1 -1
  153. package/dist/connector/mcp/discovery.d.ts.map +1 -1
  154. package/dist/connector/mcp/discovery.js +31 -20
  155. package/dist/connector/mcp/discovery.js.map +1 -1
  156. package/dist/connector/mcp/http-sse.d.ts +2 -1
  157. package/dist/connector/mcp/http-sse.d.ts.map +1 -1
  158. package/dist/connector/mcp/http-sse.js +9 -6
  159. package/dist/connector/mcp/http-sse.js.map +1 -1
  160. package/dist/connector/mcp/index.d.ts +2 -3
  161. package/dist/connector/mcp/index.d.ts.map +1 -1
  162. package/dist/connector/mcp/index.js +5 -4
  163. package/dist/connector/mcp/index.js.map +1 -1
  164. package/dist/connector/mcp/reconnect.d.ts +123 -0
  165. package/dist/connector/mcp/reconnect.d.ts.map +1 -0
  166. package/dist/connector/mcp/reconnect.js +121 -0
  167. package/dist/connector/mcp/reconnect.js.map +1 -0
  168. package/dist/connector/mcp/server/index.d.ts +28 -0
  169. package/dist/connector/mcp/server/index.d.ts.map +1 -0
  170. package/dist/connector/mcp/server/index.js +27 -0
  171. package/dist/connector/mcp/server/index.js.map +1 -0
  172. package/dist/connector/mcp/{server-stdio.d.ts → server/server-stdio.d.ts} +3 -2
  173. package/dist/connector/mcp/server/server-stdio.d.ts.map +1 -0
  174. package/dist/connector/mcp/{server-stdio.js → server/server-stdio.js} +4 -3
  175. package/dist/connector/mcp/server/server-stdio.js.map +1 -0
  176. package/dist/connector/mcp/{server.d.ts → server/server.d.ts} +5 -4
  177. package/dist/connector/mcp/server/server.d.ts.map +1 -0
  178. package/dist/connector/mcp/{server.js → server/server.js} +14 -9
  179. package/dist/connector/mcp/server/server.js.map +1 -0
  180. package/dist/connector/mcp/stdio.d.ts +2 -1
  181. package/dist/connector/mcp/stdio.d.ts.map +1 -1
  182. package/dist/connector/mcp/stdio.js +15 -7
  183. package/dist/connector/mcp/stdio.js.map +1 -1
  184. package/dist/connector/mcp/streamable-http.d.ts +2 -1
  185. package/dist/connector/mcp/streamable-http.d.ts.map +1 -1
  186. package/dist/connector/mcp/streamable-http.js +5 -4
  187. package/dist/connector/mcp/streamable-http.js.map +1 -1
  188. package/dist/{bridge/tools/connector → connector/tools}/adapter.d.ts +4 -4
  189. package/dist/connector/tools/adapter.d.ts.map +1 -0
  190. package/dist/{bridge/tools/connector → connector/tools}/adapter.js +1 -1
  191. package/dist/connector/tools/adapter.js.map +1 -0
  192. package/dist/{bridge/tools/connector → connector/tools}/definitions.d.ts +2 -2
  193. package/dist/connector/tools/definitions.d.ts.map +1 -0
  194. package/dist/{bridge/tools/connector → connector/tools}/definitions.js +2 -2
  195. package/dist/connector/tools/definitions.js.map +1 -0
  196. package/dist/connector/tools/index.d.ts.map +1 -0
  197. package/dist/connector/tools/index.js.map +1 -0
  198. package/dist/{bridge/tools/connector → connector/tools}/router.d.ts +4 -2
  199. package/dist/connector/tools/router.d.ts.map +1 -0
  200. package/dist/{bridge/tools/connector → connector/tools}/router.js +14 -7
  201. package/dist/connector/tools/router.js.map +1 -0
  202. package/dist/connector/web/guarded-fetch.d.ts +60 -0
  203. package/dist/connector/web/guarded-fetch.d.ts.map +1 -0
  204. package/dist/connector/web/guarded-fetch.js +233 -0
  205. package/dist/connector/web/guarded-fetch.js.map +1 -0
  206. package/dist/connector/web/index.d.ts +5 -0
  207. package/dist/connector/web/index.d.ts.map +1 -0
  208. package/dist/connector/web/index.js +7 -0
  209. package/dist/connector/web/index.js.map +1 -0
  210. package/dist/connector/web/types.d.ts +87 -0
  211. package/dist/connector/web/types.d.ts.map +1 -0
  212. package/dist/connector/web/types.js +25 -0
  213. package/dist/connector/web/types.js.map +1 -0
  214. package/dist/constants/acp/index.d.ts +97 -0
  215. package/dist/constants/acp/index.d.ts.map +1 -0
  216. package/dist/constants/acp/index.js +96 -0
  217. package/dist/constants/acp/index.js.map +1 -0
  218. package/dist/constants/authorization/index.d.ts.map +1 -0
  219. package/dist/constants/authorization/index.js.map +1 -0
  220. package/dist/constants/credential-env-keys.d.ts +36 -0
  221. package/dist/constants/credential-env-keys.d.ts.map +1 -0
  222. package/dist/constants/credential-env-keys.js +62 -0
  223. package/dist/constants/credential-env-keys.js.map +1 -0
  224. package/dist/constants/index.d.ts +3 -1
  225. package/dist/constants/index.d.ts.map +1 -1
  226. package/dist/constants/index.js +3 -1
  227. package/dist/constants/index.js.map +1 -1
  228. package/dist/constants/secret-patterns.d.ts +78 -0
  229. package/dist/constants/secret-patterns.d.ts.map +1 -0
  230. package/dist/constants/secret-patterns.js +99 -0
  231. package/dist/constants/secret-patterns.js.map +1 -0
  232. package/dist/constants/telemetry/index.d.ts +42 -0
  233. package/dist/constants/telemetry/index.d.ts.map +1 -1
  234. package/dist/constants/telemetry/index.js +87 -0
  235. package/dist/constants/telemetry/index.js.map +1 -1
  236. package/dist/contracts/a2a.d.ts +46 -46
  237. package/dist/contracts/api.d.ts +12 -1
  238. package/dist/contracts/api.d.ts.map +1 -1
  239. package/dist/eval/judge.js +2 -2
  240. package/dist/eval/judge.js.map +1 -1
  241. package/dist/execution/base.d.ts +1 -1
  242. package/dist/execution/base.d.ts.map +1 -1
  243. package/dist/execution/base.js +18 -7
  244. package/dist/execution/base.js.map +1 -1
  245. package/dist/execution/code-runtime/types.d.ts +114 -0
  246. package/dist/execution/code-runtime/types.d.ts.map +1 -0
  247. package/dist/execution/code-runtime/types.js +40 -0
  248. package/dist/execution/code-runtime/types.js.map +1 -0
  249. package/dist/execution/code-runtime/worker.d.ts +6 -0
  250. package/dist/execution/code-runtime/worker.d.ts.map +1 -0
  251. package/dist/execution/code-runtime/worker.js +248 -0
  252. package/dist/execution/code-runtime/worker.js.map +1 -0
  253. package/dist/{connector/execution → execution}/factory.d.ts +3 -3
  254. package/dist/execution/factory.d.ts.map +1 -0
  255. package/dist/{connector/execution → execution}/factory.js +1 -1
  256. package/dist/execution/factory.js.map +1 -0
  257. package/dist/{connector/execution → execution}/hybrid.d.ts +5 -3
  258. package/dist/execution/hybrid.d.ts.map +1 -0
  259. package/dist/{connector/execution → execution}/hybrid.js +10 -4
  260. package/dist/execution/hybrid.js.map +1 -0
  261. package/dist/execution/index.d.ts +23 -0
  262. package/dist/execution/index.d.ts.map +1 -1
  263. package/dist/execution/index.js +21 -0
  264. package/dist/execution/index.js.map +1 -1
  265. package/dist/execution/local.d.ts +2 -0
  266. package/dist/execution/local.d.ts.map +1 -1
  267. package/dist/execution/local.js +2 -2
  268. package/dist/execution/local.js.map +1 -1
  269. package/dist/{connector/execution → execution}/remote.d.ts +4 -2
  270. package/dist/execution/remote.d.ts.map +1 -0
  271. package/dist/{connector/execution → execution}/remote.js +12 -5
  272. package/dist/execution/remote.js.map +1 -0
  273. package/dist/index.d.ts +2 -0
  274. package/dist/index.d.ts.map +1 -1
  275. package/dist/index.js +4 -0
  276. package/dist/index.js.map +1 -1
  277. package/dist/invariants/index.d.ts +111 -0
  278. package/dist/invariants/index.d.ts.map +1 -0
  279. package/dist/invariants/index.js +138 -0
  280. package/dist/invariants/index.js.map +1 -0
  281. package/dist/manager/agent/lifecycle.d.ts +29 -7
  282. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  283. package/dist/manager/agent/lifecycle.js +140 -50
  284. package/dist/manager/agent/lifecycle.js.map +1 -1
  285. package/dist/manager/connector/environment.d.ts +2 -0
  286. package/dist/manager/connector/environment.d.ts.map +1 -1
  287. package/dist/manager/connector/environment.js +20 -9
  288. package/dist/manager/connector/environment.js.map +1 -1
  289. package/dist/manager/connector/lifecycle.d.ts +10 -0
  290. package/dist/manager/connector/lifecycle.d.ts.map +1 -1
  291. package/dist/manager/connector/lifecycle.js +21 -11
  292. package/dist/manager/connector/lifecycle.js.map +1 -1
  293. package/dist/manager/connector/tenant.d.ts +9 -0
  294. package/dist/manager/connector/tenant.d.ts.map +1 -1
  295. package/dist/manager/connector/tenant.js +24 -10
  296. package/dist/manager/connector/tenant.js.map +1 -1
  297. package/dist/manager/index.d.ts +6 -2
  298. package/dist/manager/index.d.ts.map +1 -1
  299. package/dist/manager/index.js +7 -1
  300. package/dist/manager/index.js.map +1 -1
  301. package/dist/manager/project/lifecycle.d.ts +1 -1
  302. package/dist/manager/project/lifecycle.js +1 -1
  303. package/dist/manager/run/emergency.d.ts.map +1 -1
  304. package/dist/manager/run/emergency.js +9 -7
  305. package/dist/manager/run/emergency.js.map +1 -1
  306. package/dist/manager/run/persistence.d.ts +46 -4
  307. package/dist/manager/run/persistence.d.ts.map +1 -1
  308. package/dist/manager/run/persistence.js +102 -7
  309. package/dist/manager/run/persistence.js.map +1 -1
  310. package/dist/manager/topic/lifecycle.d.ts +123 -0
  311. package/dist/manager/topic/lifecycle.d.ts.map +1 -0
  312. package/dist/manager/{thread → topic}/lifecycle.js +79 -61
  313. package/dist/manager/topic/lifecycle.js.map +1 -0
  314. package/dist/manager/topic/objective.d.ts +77 -0
  315. package/dist/manager/topic/objective.d.ts.map +1 -0
  316. package/dist/manager/topic/objective.js +133 -0
  317. package/dist/manager/topic/objective.js.map +1 -0
  318. package/dist/model-router/task-router.d.ts.map +1 -0
  319. package/dist/model-router/task-router.js.map +1 -0
  320. package/dist/persona/assembler.d.ts +1 -1
  321. package/dist/persona/assembler.d.ts.map +1 -1
  322. package/dist/persona/assembler.js +14 -2
  323. package/dist/persona/assembler.js.map +1 -1
  324. package/dist/plugin/lifecycle.d.ts +24 -0
  325. package/dist/plugin/lifecycle.d.ts.map +1 -1
  326. package/dist/plugin/lifecycle.js +112 -20
  327. package/dist/plugin/lifecycle.js.map +1 -1
  328. package/dist/plugin/loader.d.ts +17 -2
  329. package/dist/plugin/loader.d.ts.map +1 -1
  330. package/dist/plugin/loader.js +46 -26
  331. package/dist/plugin/loader.js.map +1 -1
  332. package/dist/probe/index.d.ts +1 -0
  333. package/dist/probe/index.d.ts.map +1 -1
  334. package/dist/probe/registry.d.ts +34 -1
  335. package/dist/probe/registry.d.ts.map +1 -1
  336. package/dist/probe/registry.js +5 -4
  337. package/dist/probe/registry.js.map +1 -1
  338. package/dist/process/kill-tree.d.ts +40 -0
  339. package/dist/process/kill-tree.d.ts.map +1 -0
  340. package/dist/process/kill-tree.js +54 -0
  341. package/dist/process/kill-tree.js.map +1 -0
  342. package/dist/prompt/contributions.d.ts +138 -0
  343. package/dist/prompt/contributions.d.ts.map +1 -0
  344. package/dist/prompt/contributions.js +78 -0
  345. package/dist/prompt/contributions.js.map +1 -0
  346. package/dist/prompt/index.d.ts +3 -0
  347. package/dist/prompt/index.d.ts.map +1 -0
  348. package/dist/prompt/index.js +6 -0
  349. package/dist/prompt/index.js.map +1 -0
  350. package/dist/provider/attribution.d.ts +45 -0
  351. package/dist/provider/attribution.d.ts.map +1 -0
  352. package/dist/provider/attribution.js +23 -0
  353. package/dist/provider/attribution.js.map +1 -0
  354. package/dist/provider/{collect.d.ts → collect-chat-completion.d.ts} +3 -3
  355. package/dist/provider/collect-chat-completion.d.ts.map +1 -0
  356. package/dist/provider/{collect.js → collect-chat-completion.js} +3 -3
  357. package/dist/provider/collect-chat-completion.js.map +1 -0
  358. package/dist/provider/conformance.d.ts +93 -0
  359. package/dist/provider/conformance.d.ts.map +1 -0
  360. package/dist/provider/conformance.js +124 -0
  361. package/dist/provider/conformance.js.map +1 -0
  362. package/dist/provider/errors.d.ts +29 -0
  363. package/dist/provider/errors.d.ts.map +1 -1
  364. package/dist/provider/errors.js +27 -10
  365. package/dist/provider/errors.js.map +1 -1
  366. package/dist/provider/fallback.d.ts +1 -1
  367. package/dist/provider/fallback.d.ts.map +1 -1
  368. package/dist/provider/fallback.js +27 -9
  369. package/dist/provider/fallback.js.map +1 -1
  370. package/dist/provider/idle-timeout.d.ts +47 -0
  371. package/dist/provider/idle-timeout.d.ts.map +1 -0
  372. package/dist/provider/idle-timeout.js +61 -0
  373. package/dist/provider/idle-timeout.js.map +1 -0
  374. package/dist/provider/instrumentation.d.ts +3 -2
  375. package/dist/provider/instrumentation.d.ts.map +1 -1
  376. package/dist/provider/instrumentation.js.map +1 -1
  377. package/dist/provider/retry.d.ts.map +1 -1
  378. package/dist/provider/retry.js +58 -21
  379. package/dist/provider/retry.js.map +1 -1
  380. package/dist/public-runtime.d.ts +77 -15
  381. package/dist/public-runtime.d.ts.map +1 -1
  382. package/dist/public-runtime.js +168 -17
  383. package/dist/public-runtime.js.map +1 -1
  384. package/dist/public-tools.d.ts +8 -1
  385. package/dist/public-tools.d.ts.map +1 -1
  386. package/dist/public-tools.js +29 -1
  387. package/dist/public-tools.js.map +1 -1
  388. package/dist/public-types.d.ts +21 -4
  389. package/dist/public-types.d.ts.map +1 -1
  390. package/dist/rag/rag-tool.d.ts.map +1 -1
  391. package/dist/rag/rag-tool.js +4 -1
  392. package/dist/rag/rag-tool.js.map +1 -1
  393. package/dist/read-model/index.d.ts +5 -0
  394. package/dist/read-model/index.d.ts.map +1 -0
  395. package/dist/read-model/index.js +7 -0
  396. package/dist/read-model/index.js.map +1 -0
  397. package/dist/read-model/registry.d.ts +112 -0
  398. package/dist/read-model/registry.d.ts.map +1 -0
  399. package/dist/read-model/registry.js +105 -0
  400. package/dist/read-model/registry.js.map +1 -0
  401. package/dist/read-model/run-status.d.ts +43 -0
  402. package/dist/read-model/run-status.d.ts.map +1 -0
  403. package/dist/read-model/run-status.js +89 -0
  404. package/dist/read-model/run-status.js.map +1 -0
  405. package/dist/registry/{Registry.d.ts → BaseRegistry.d.ts} +2 -2
  406. package/dist/registry/BaseRegistry.d.ts.map +1 -0
  407. package/dist/registry/{Registry.js → BaseRegistry.js} +2 -2
  408. package/dist/registry/BaseRegistry.js.map +1 -0
  409. package/dist/registry/ManagedRegistry.d.ts +2 -2
  410. package/dist/registry/ManagedRegistry.d.ts.map +1 -1
  411. package/dist/registry/ManagedRegistry.js +26 -9
  412. package/dist/registry/ManagedRegistry.js.map +1 -1
  413. package/dist/registry/command/index-exports.d.ts +3 -0
  414. package/dist/registry/command/index-exports.d.ts.map +1 -0
  415. package/dist/registry/command/index-exports.js +5 -0
  416. package/dist/registry/command/index-exports.js.map +1 -0
  417. package/dist/registry/command/index.d.ts +53 -0
  418. package/dist/registry/command/index.d.ts.map +1 -0
  419. package/dist/registry/command/index.js +87 -0
  420. package/dist/registry/command/index.js.map +1 -0
  421. package/dist/registry/command/kernel-commands.d.ts +32 -0
  422. package/dist/registry/command/kernel-commands.d.ts.map +1 -0
  423. package/dist/registry/command/kernel-commands.js +78 -0
  424. package/dist/registry/command/kernel-commands.js.map +1 -0
  425. package/dist/registry/connector/scoped.d.ts +2 -1
  426. package/dist/registry/connector/scoped.d.ts.map +1 -1
  427. package/dist/registry/connector/scoped.js +6 -5
  428. package/dist/registry/connector/scoped.js.map +1 -1
  429. package/dist/registry/index.d.ts +4 -1
  430. package/dist/registry/index.d.ts.map +1 -1
  431. package/dist/registry/index.js +5 -1
  432. package/dist/registry/index.js.map +1 -1
  433. package/dist/registry/tool/execute.d.ts.map +1 -1
  434. package/dist/registry/tool/execute.js +15 -12
  435. package/dist/registry/tool/execute.js.map +1 -1
  436. package/dist/registry/tool/presentation.d.ts +32 -0
  437. package/dist/registry/tool/presentation.d.ts.map +1 -0
  438. package/dist/registry/tool/presentation.js +92 -0
  439. package/dist/registry/tool/presentation.js.map +1 -0
  440. package/dist/registry/tool/screen.d.ts.map +1 -1
  441. package/dist/registry/tool/screen.js +12 -11
  442. package/dist/registry/tool/screen.js.map +1 -1
  443. package/dist/run/drain.d.ts +13 -3
  444. package/dist/run/drain.d.ts.map +1 -1
  445. package/dist/run/drain.js +10 -0
  446. package/dist/run/drain.js.map +1 -1
  447. package/dist/run/reporter.d.ts.map +1 -1
  448. package/dist/run/reporter.js +203 -149
  449. package/dist/run/reporter.js.map +1 -1
  450. package/dist/run-query/index.d.ts +74 -0
  451. package/dist/run-query/index.d.ts.map +1 -0
  452. package/dist/run-query/index.js +73 -0
  453. package/dist/run-query/index.js.map +1 -0
  454. package/dist/runtime/bidi/session.d.ts.map +1 -1
  455. package/dist/runtime/bidi/session.js +7 -2
  456. package/dist/runtime/bidi/session.js.map +1 -1
  457. package/dist/runtime/decision/fallback.d.ts.map +1 -1
  458. package/dist/runtime/decision/fallback.js +6 -3
  459. package/dist/runtime/decision/fallback.js.map +1 -1
  460. package/dist/runtime/decision/parser.d.ts.map +1 -1
  461. package/dist/runtime/decision/parser.js +10 -9
  462. package/dist/runtime/decision/parser.js.map +1 -1
  463. package/dist/runtime/jobs/registry.d.ts +147 -0
  464. package/dist/runtime/jobs/registry.d.ts.map +1 -0
  465. package/dist/runtime/jobs/registry.js +242 -0
  466. package/dist/runtime/jobs/registry.js.map +1 -0
  467. package/dist/runtime/query/approval-policy.d.ts +22 -0
  468. package/dist/runtime/query/approval-policy.d.ts.map +1 -0
  469. package/dist/runtime/query/approval-policy.js +61 -0
  470. package/dist/runtime/query/approval-policy.js.map +1 -0
  471. package/dist/runtime/query/checkpoint.d.ts +3 -3
  472. package/dist/runtime/query/checkpoint.d.ts.map +1 -1
  473. package/dist/runtime/query/checkpoint.js +2 -2
  474. package/dist/runtime/query/checkpoint.js.map +1 -1
  475. package/dist/runtime/query/context.d.ts +85 -15
  476. package/dist/runtime/query/context.d.ts.map +1 -1
  477. package/dist/runtime/query/context.js +57 -14
  478. package/dist/runtime/query/context.js.map +1 -1
  479. package/dist/runtime/query/events.d.ts +5 -4
  480. package/dist/runtime/query/events.d.ts.map +1 -1
  481. package/dist/runtime/query/events.js +9 -6
  482. package/dist/runtime/query/events.js.map +1 -1
  483. package/dist/runtime/query/executor.d.ts +113 -4
  484. package/dist/runtime/query/executor.d.ts.map +1 -1
  485. package/dist/runtime/query/executor.js +228 -62
  486. package/dist/runtime/query/executor.js.map +1 -1
  487. package/dist/runtime/query/guardrail-presets.d.ts.map +1 -1
  488. package/dist/runtime/query/guardrail-presets.js +11 -14
  489. package/dist/runtime/query/guardrail-presets.js.map +1 -1
  490. package/dist/runtime/query/guardrails.d.ts.map +1 -1
  491. package/dist/runtime/query/guardrails.js +16 -12
  492. package/dist/runtime/query/guardrails.js.map +1 -1
  493. package/dist/runtime/query/index.d.ts +124 -16
  494. package/dist/runtime/query/index.d.ts.map +1 -1
  495. package/dist/runtime/query/index.js +372 -76
  496. package/dist/runtime/query/index.js.map +1 -1
  497. package/dist/runtime/query/iteration/index.d.ts +32 -0
  498. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  499. package/dist/runtime/query/iteration/index.js +256 -88
  500. package/dist/runtime/query/iteration/index.js.map +1 -1
  501. package/dist/runtime/query/iteration/phases/advisory.d.ts.map +1 -1
  502. package/dist/runtime/query/iteration/phases/advisory.js +17 -16
  503. package/dist/runtime/query/iteration/phases/advisory.js.map +1 -1
  504. package/dist/runtime/query/iteration/phases/compaction.d.ts +1 -8
  505. package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
  506. package/dist/runtime/query/iteration/phases/compaction.js +202 -178
  507. package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
  508. package/dist/runtime/query/iteration/phases/context.d.ts +52 -6
  509. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  510. package/dist/runtime/query/iteration/phases/context.js +26 -17
  511. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  512. package/dist/runtime/query/iteration/phases/tool-review.d.ts +2 -2
  513. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  514. package/dist/runtime/query/iteration/phases/tool-review.js +27 -7
  515. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  516. package/dist/runtime/query/iteration/phases/working-memory.d.ts.map +1 -1
  517. package/dist/runtime/query/iteration/phases/working-memory.js +3 -2
  518. package/dist/runtime/query/iteration/phases/working-memory.js.map +1 -1
  519. package/dist/runtime/query/iteration/stream-turn.js +14 -14
  520. package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
  521. package/dist/runtime/query/{context-cache.d.ts → prompt-cache.d.ts} +6 -4
  522. package/dist/runtime/query/prompt-cache.d.ts.map +1 -0
  523. package/dist/runtime/query/{context-cache.js → prompt-cache.js} +20 -2
  524. package/dist/runtime/query/prompt-cache.js.map +1 -0
  525. package/dist/runtime/query/prompt.d.ts +50 -0
  526. package/dist/runtime/query/prompt.d.ts.map +1 -1
  527. package/dist/runtime/query/prompt.js +83 -4
  528. package/dist/runtime/query/prompt.js.map +1 -1
  529. package/dist/runtime/query/repeat-call.d.ts +42 -0
  530. package/dist/runtime/query/repeat-call.d.ts.map +1 -0
  531. package/dist/runtime/query/repeat-call.js +107 -0
  532. package/dist/runtime/query/repeat-call.js.map +1 -0
  533. package/dist/runtime/query/replay/mutate.js +8 -1
  534. package/dist/runtime/query/replay/mutate.js.map +1 -1
  535. package/dist/runtime/query/result.d.ts +7 -0
  536. package/dist/runtime/query/result.d.ts.map +1 -1
  537. package/dist/runtime/query/result.js +38 -10
  538. package/dist/runtime/query/result.js.map +1 -1
  539. package/dist/runtime/query/resume-pending.d.ts.map +1 -1
  540. package/dist/runtime/query/resume-pending.js +19 -17
  541. package/dist/runtime/query/resume-pending.js.map +1 -1
  542. package/dist/runtime/query/resume-run.d.ts +2 -2
  543. package/dist/runtime/query/resume-run.d.ts.map +1 -1
  544. package/dist/runtime/query/run-state.d.ts +3 -3
  545. package/dist/runtime/query/run-state.d.ts.map +1 -1
  546. package/dist/runtime/query/run-state.js +2 -2
  547. package/dist/runtime/query/run-state.js.map +1 -1
  548. package/dist/runtime/query/tool-grants.d.ts +7 -0
  549. package/dist/runtime/query/tool-grants.d.ts.map +1 -1
  550. package/dist/runtime/query/tool-grants.js +1 -1
  551. package/dist/runtime/query/tool-grants.js.map +1 -1
  552. package/dist/runtime/query/tool-output-budget.js +34 -3
  553. package/dist/runtime/query/tool-output-budget.js.map +1 -1
  554. package/dist/runtime/query/tool-pause.d.ts.map +1 -1
  555. package/dist/runtime/query/tool-pause.js +2 -1
  556. package/dist/runtime/query/tool-pause.js.map +1 -1
  557. package/dist/runtime/query/tooling.d.ts +10 -2
  558. package/dist/runtime/query/tooling.d.ts.map +1 -1
  559. package/dist/runtime/query/tooling.js +3 -0
  560. package/dist/runtime/query/tooling.js.map +1 -1
  561. package/dist/sandbox/provider/local.d.ts +10 -0
  562. package/dist/sandbox/provider/local.d.ts.map +1 -1
  563. package/dist/sandbox/provider/local.js +77 -23
  564. package/dist/sandbox/provider/local.js.map +1 -1
  565. package/dist/sandbox/terminal.d.ts +130 -0
  566. package/dist/sandbox/terminal.d.ts.map +1 -0
  567. package/dist/sandbox/terminal.js +119 -0
  568. package/dist/sandbox/terminal.js.map +1 -0
  569. package/dist/{gateway → scheduler}/completion-inbox.d.ts +12 -5
  570. package/dist/scheduler/completion-inbox.d.ts.map +1 -0
  571. package/dist/{gateway → scheduler}/completion-inbox.js +19 -7
  572. package/dist/scheduler/completion-inbox.js.map +1 -0
  573. package/dist/scheduler/delegating.d.ts +90 -0
  574. package/dist/scheduler/delegating.d.ts.map +1 -0
  575. package/dist/scheduler/delegating.js +230 -0
  576. package/dist/scheduler/delegating.js.map +1 -0
  577. package/dist/{gateway → scheduler}/local.d.ts +10 -2
  578. package/dist/scheduler/local.d.ts.map +1 -0
  579. package/dist/{gateway → scheduler}/local.js +20 -11
  580. package/dist/scheduler/local.js.map +1 -0
  581. package/dist/session/actor-scope.d.ts +52 -0
  582. package/dist/session/actor-scope.d.ts.map +1 -0
  583. package/dist/session/actor-scope.js +112 -0
  584. package/dist/session/actor-scope.js.map +1 -0
  585. package/dist/session/errors.d.ts +31 -8
  586. package/dist/session/errors.d.ts.map +1 -1
  587. package/dist/session/errors.js +21 -1
  588. package/dist/session/errors.js.map +1 -1
  589. package/dist/session/handoff/assignment.d.ts +5 -5
  590. package/dist/session/handoff/assignment.d.ts.map +1 -1
  591. package/dist/session/handoff/broadcast.d.ts +8 -4
  592. package/dist/session/handoff/broadcast.d.ts.map +1 -1
  593. package/dist/session/handoff/broadcast.js +8 -9
  594. package/dist/session/handoff/broadcast.js.map +1 -1
  595. package/dist/session/handoff/index.d.ts +1 -1
  596. package/dist/session/handoff/index.d.ts.map +1 -1
  597. package/dist/session/handoff/index.js +1 -1
  598. package/dist/session/handoff/index.js.map +1 -1
  599. package/dist/session/handoff/single.d.ts +11 -7
  600. package/dist/session/handoff/single.d.ts.map +1 -1
  601. package/dist/session/handoff/single.js +5 -11
  602. package/dist/session/handoff/single.js.map +1 -1
  603. package/dist/session/migration/filesystem.d.ts +28 -0
  604. package/dist/session/migration/filesystem.d.ts.map +1 -1
  605. package/dist/session/migration/filesystem.js +44 -2
  606. package/dist/session/migration/filesystem.js.map +1 -1
  607. package/dist/session/migration/id-prefix.d.ts +39 -19
  608. package/dist/session/migration/id-prefix.d.ts.map +1 -1
  609. package/dist/session/migration/id-prefix.js +43 -22
  610. package/dist/session/migration/id-prefix.js.map +1 -1
  611. package/dist/session/migration/index.d.ts +6 -2
  612. package/dist/session/migration/index.d.ts.map +1 -1
  613. package/dist/session/migration/index.js +6 -2
  614. package/dist/session/migration/index.js.map +1 -1
  615. package/dist/session/migration/marker.d.ts.map +1 -1
  616. package/dist/session/migration/marker.js +21 -4
  617. package/dist/session/migration/marker.js.map +1 -1
  618. package/dist/session/retention/archive.d.ts.map +1 -1
  619. package/dist/session/retention/archive.js +13 -11
  620. package/dist/session/retention/archive.js.map +1 -1
  621. package/dist/session/workspace/git-worktree.d.ts.map +1 -1
  622. package/dist/session/workspace/git-worktree.js +17 -8
  623. package/dist/session/workspace/git-worktree.js.map +1 -1
  624. package/dist/skills/loader.d.ts +4 -2
  625. package/dist/skills/loader.d.ts.map +1 -1
  626. package/dist/skills/loader.js +36 -9
  627. package/dist/skills/loader.js.map +1 -1
  628. package/dist/skills/registry.d.ts +59 -1
  629. package/dist/skills/registry.d.ts.map +1 -1
  630. package/dist/skills/registry.js +154 -20
  631. package/dist/skills/registry.js.map +1 -1
  632. package/dist/store/attachment/index.d.ts +111 -0
  633. package/dist/store/attachment/index.d.ts.map +1 -0
  634. package/dist/store/attachment/index.js +94 -0
  635. package/dist/store/attachment/index.js.map +1 -0
  636. package/dist/store/config/index.d.ts +43 -0
  637. package/dist/store/config/index.d.ts.map +1 -0
  638. package/dist/store/config/index.js +51 -0
  639. package/dist/store/config/index.js.map +1 -0
  640. package/dist/store/feedback/conformance.d.ts +44 -0
  641. package/dist/store/feedback/conformance.d.ts.map +1 -0
  642. package/dist/store/feedback/conformance.js +127 -0
  643. package/dist/store/feedback/conformance.js.map +1 -0
  644. package/dist/store/feedback/disk.d.ts +46 -0
  645. package/dist/store/feedback/disk.d.ts.map +1 -0
  646. package/dist/store/feedback/disk.js +141 -0
  647. package/dist/store/feedback/disk.js.map +1 -0
  648. package/dist/store/feedback/index.d.ts +9 -0
  649. package/dist/store/feedback/index.d.ts.map +1 -0
  650. package/dist/store/feedback/index.js +5 -0
  651. package/dist/store/feedback/index.js.map +1 -0
  652. package/dist/store/feedback/memory.d.ts +33 -0
  653. package/dist/store/feedback/memory.d.ts.map +1 -0
  654. package/dist/store/feedback/memory.js +0 -0
  655. package/dist/store/feedback/memory.js.map +1 -0
  656. package/dist/store/feedback/types.d.ts +95 -0
  657. package/dist/store/feedback/types.d.ts.map +1 -0
  658. package/dist/store/feedback/types.js +27 -0
  659. package/dist/store/feedback/types.js.map +1 -0
  660. package/dist/store/index.d.ts +1 -0
  661. package/dist/store/index.d.ts.map +1 -1
  662. package/dist/store/index.js +4 -0
  663. package/dist/store/index.js.map +1 -1
  664. package/dist/store/kv/record-store.d.ts +54 -0
  665. package/dist/store/kv/record-store.d.ts.map +1 -0
  666. package/dist/store/kv/record-store.js +94 -0
  667. package/dist/store/kv/record-store.js.map +1 -0
  668. package/dist/store/memory/disk.d.ts +2 -0
  669. package/dist/store/memory/disk.d.ts.map +1 -1
  670. package/dist/store/memory/disk.js +36 -30
  671. package/dist/store/memory/disk.js.map +1 -1
  672. package/dist/store/run/checkpoint-disk.d.ts +4 -4
  673. package/dist/store/run/checkpoint-disk.d.ts.map +1 -1
  674. package/dist/store/run/checkpoint-disk.js +22 -1
  675. package/dist/store/run/checkpoint-disk.js.map +1 -1
  676. package/dist/store/run/checkpoint-memory.d.ts +4 -4
  677. package/dist/store/run/checkpoint-memory.d.ts.map +1 -1
  678. package/dist/store/run/checkpoint-memory.js.map +1 -1
  679. package/dist/store/run/claim-disk.d.ts +5 -5
  680. package/dist/store/run/claim-disk.d.ts.map +1 -1
  681. package/dist/store/run/claim-disk.js +20 -0
  682. package/dist/store/run/claim-disk.js.map +1 -1
  683. package/dist/store/run/conformance.d.ts.map +1 -1
  684. package/dist/store/run/conformance.js +10 -9
  685. package/dist/store/run/conformance.js.map +1 -1
  686. package/dist/store/run/disk.d.ts +3 -1
  687. package/dist/store/run/disk.d.ts.map +1 -1
  688. package/dist/store/run/disk.js +73 -4
  689. package/dist/store/run/disk.js.map +1 -1
  690. package/dist/store/run/listing.d.ts +4 -4
  691. package/dist/store/run/listing.d.ts.map +1 -1
  692. package/dist/store/run/listing.js.map +1 -1
  693. package/dist/store/run/memory.d.ts +5 -0
  694. package/dist/store/run/memory.d.ts.map +1 -1
  695. package/dist/store/run/memory.js +20 -1
  696. package/dist/store/run/memory.js.map +1 -1
  697. package/dist/store/session/canonical-path.d.ts +32 -0
  698. package/dist/store/session/canonical-path.d.ts.map +1 -0
  699. package/dist/store/session/canonical-path.js +46 -0
  700. package/dist/store/session/canonical-path.js.map +1 -0
  701. package/dist/store/session/disk.d.ts +46 -2
  702. package/dist/store/session/disk.d.ts.map +1 -1
  703. package/dist/store/session/disk.js +191 -205
  704. package/dist/store/session/disk.js.map +1 -1
  705. package/dist/store/session/memory.d.ts +10 -2
  706. package/dist/store/session/memory.d.ts.map +1 -1
  707. package/dist/store/session/memory.js +36 -4
  708. package/dist/store/session/memory.js.map +1 -1
  709. package/dist/store/task/disk.d.ts.map +1 -1
  710. package/dist/store/task/disk.js +76 -68
  711. package/dist/store/task/disk.js.map +1 -1
  712. package/dist/store/topic/index.d.ts +6 -0
  713. package/dist/store/topic/index.d.ts.map +1 -0
  714. package/dist/store/topic/index.js +20 -0
  715. package/dist/store/topic/index.js.map +1 -0
  716. package/dist/store/topic/memory.d.ts +30 -0
  717. package/dist/store/topic/memory.d.ts.map +1 -0
  718. package/dist/store/topic/memory.js +97 -0
  719. package/dist/store/topic/memory.js.map +1 -0
  720. package/dist/store/topic/objective.d.ts +104 -0
  721. package/dist/store/topic/objective.d.ts.map +1 -0
  722. package/dist/store/topic/objective.js +195 -0
  723. package/dist/store/topic/objective.js.map +1 -0
  724. package/dist/store/topic/state.d.ts +60 -0
  725. package/dist/store/topic/state.d.ts.map +1 -0
  726. package/dist/store/topic/state.js +128 -0
  727. package/dist/store/topic/state.js.map +1 -0
  728. package/dist/streaming/coalesce.d.ts +19 -6
  729. package/dist/streaming/coalesce.d.ts.map +1 -1
  730. package/dist/streaming/coalesce.js +13 -4
  731. package/dist/streaming/coalesce.js.map +1 -1
  732. package/dist/telemetry/runtime-accessors.d.ts +27 -1
  733. package/dist/telemetry/runtime-accessors.d.ts.map +1 -1
  734. package/dist/telemetry/runtime-accessors.js +45 -1
  735. package/dist/telemetry/runtime-accessors.js.map +1 -1
  736. package/dist/test-support/ids.d.ts +68 -0
  737. package/dist/test-support/ids.d.ts.map +1 -0
  738. package/dist/test-support/ids.js +70 -0
  739. package/dist/test-support/ids.js.map +1 -0
  740. package/dist/testing.d.ts +24 -0
  741. package/dist/testing.d.ts.map +1 -0
  742. package/dist/testing.js +22 -0
  743. package/dist/testing.js.map +1 -0
  744. package/dist/tools/builtins/bash.d.ts +1 -0
  745. package/dist/tools/builtins/bash.d.ts.map +1 -1
  746. package/dist/tools/builtins/bash.js +77 -3
  747. package/dist/tools/builtins/bash.js.map +1 -1
  748. package/dist/tools/builtins/edit.d.ts +1 -1
  749. package/dist/tools/builtins/edit.d.ts.map +1 -1
  750. package/dist/tools/builtins/edit.js +34 -0
  751. package/dist/tools/builtins/edit.js.map +1 -1
  752. package/dist/tools/builtins/index.d.ts +6 -0
  753. package/dist/tools/builtins/index.d.ts.map +1 -1
  754. package/dist/tools/builtins/index.js +24 -1
  755. package/dist/tools/builtins/index.js.map +1 -1
  756. package/dist/tools/builtins/job.d.ts +6 -0
  757. package/dist/tools/builtins/job.d.ts.map +1 -0
  758. package/dist/tools/builtins/job.js +114 -0
  759. package/dist/tools/builtins/job.js.map +1 -0
  760. package/dist/tools/builtins/lsp.d.ts +21 -0
  761. package/dist/tools/builtins/lsp.d.ts.map +1 -0
  762. package/dist/tools/builtins/lsp.js +186 -0
  763. package/dist/tools/builtins/lsp.js.map +1 -0
  764. package/dist/tools/builtins/run-code.d.ts +13 -0
  765. package/dist/tools/builtins/run-code.d.ts.map +1 -0
  766. package/dist/tools/builtins/run-code.js +126 -0
  767. package/dist/tools/builtins/run-code.js.map +1 -0
  768. package/dist/tools/builtins/skill.d.ts +14 -0
  769. package/dist/tools/builtins/skill.d.ts.map +1 -0
  770. package/dist/tools/builtins/skill.js +120 -0
  771. package/dist/tools/builtins/skill.js.map +1 -0
  772. package/dist/tools/builtins/web-guidance.d.ts +31 -0
  773. package/dist/tools/builtins/web-guidance.d.ts.map +1 -0
  774. package/dist/tools/builtins/web-guidance.js +42 -0
  775. package/dist/tools/builtins/web-guidance.js.map +1 -0
  776. package/dist/tools/builtins/web.d.ts +10 -0
  777. package/dist/tools/builtins/web.d.ts.map +1 -0
  778. package/dist/tools/builtins/web.js +137 -0
  779. package/dist/tools/builtins/web.js.map +1 -0
  780. package/dist/tools/builtins/write-file.d.ts.map +1 -1
  781. package/dist/tools/builtins/write-file.js +35 -0
  782. package/dist/tools/builtins/write-file.js.map +1 -1
  783. package/dist/tools/coordinator/agent.d.ts +2 -2
  784. package/dist/tools/coordinator/agent.d.ts.map +1 -1
  785. package/dist/tools/coordinator/index.d.ts +13 -4
  786. package/dist/tools/coordinator/index.d.ts.map +1 -1
  787. package/dist/tools/coordinator/index.js +125 -38
  788. package/dist/tools/coordinator/index.js.map +1 -1
  789. package/dist/tools/coordinator/outcome.d.ts +2 -2
  790. package/dist/tools/coordinator/outcome.d.ts.map +1 -1
  791. package/dist/tools/coordinator/outcome.js +1 -1
  792. package/dist/tools/coordinator/wait-with-idle-bound.d.ts +3 -3
  793. package/dist/tools/coordinator/wait-with-idle-bound.d.ts.map +1 -1
  794. package/dist/tools/coordinator/wait-with-idle-bound.js.map +1 -1
  795. package/dist/tools/defineTool.d.ts +12 -0
  796. package/dist/tools/defineTool.d.ts.map +1 -1
  797. package/dist/tools/defineTool.js +2 -0
  798. package/dist/tools/defineTool.js.map +1 -1
  799. package/dist/tools/env-scrub.d.ts +66 -0
  800. package/dist/tools/env-scrub.d.ts.map +1 -0
  801. package/dist/tools/env-scrub.js +68 -0
  802. package/dist/tools/env-scrub.js.map +1 -0
  803. package/dist/tools/memory/read.d.ts.map +1 -1
  804. package/dist/tools/memory/read.js +5 -1
  805. package/dist/tools/memory/read.js.map +1 -1
  806. package/dist/tools/task/create.d.ts.map +1 -1
  807. package/dist/tools/task/create.js +2 -1
  808. package/dist/tools/task/create.js.map +1 -1
  809. package/dist/tools/task/update.d.ts.map +1 -1
  810. package/dist/tools/task/update.js +7 -3
  811. package/dist/tools/task/update.js.map +1 -1
  812. package/dist/types/acp/index.d.ts +161 -0
  813. package/dist/types/acp/index.d.ts.map +1 -0
  814. package/dist/types/acp/index.js +2 -0
  815. package/dist/types/acp/index.js.map +1 -0
  816. package/dist/types/agent/base.d.ts +62 -5
  817. package/dist/types/agent/base.d.ts.map +1 -1
  818. package/dist/types/agent/delegate.d.ts +102 -0
  819. package/dist/types/agent/delegate.d.ts.map +1 -0
  820. package/dist/types/agent/delegate.js +2 -0
  821. package/dist/types/agent/delegate.js.map +1 -0
  822. package/dist/types/agent/index.d.ts +1 -1
  823. package/dist/types/agent/index.d.ts.map +1 -1
  824. package/dist/types/agent/index.js +1 -1
  825. package/dist/types/agent/index.js.map +1 -1
  826. package/dist/types/agent/manager.d.ts +7 -1
  827. package/dist/types/agent/manager.d.ts.map +1 -1
  828. package/dist/types/agent/reactive.d.ts +19 -3
  829. package/dist/types/agent/reactive.d.ts.map +1 -1
  830. package/dist/types/agent/{gateway.d.ts → scheduler.d.ts} +31 -5
  831. package/dist/types/agent/scheduler.d.ts.map +1 -0
  832. package/dist/types/agent/scheduler.js +2 -0
  833. package/dist/types/agent/scheduler.js.map +1 -0
  834. package/dist/types/agent/supervisor.d.ts +13 -5
  835. package/dist/types/agent/supervisor.d.ts.map +1 -1
  836. package/dist/types/agent/task.d.ts +31 -9
  837. package/dist/types/agent/task.d.ts.map +1 -1
  838. package/dist/types/agent/working-memory.d.ts +1 -1
  839. package/dist/types/{verification → authorization}/index.d.ts +68 -12
  840. package/dist/types/authorization/index.d.ts.map +1 -0
  841. package/dist/types/authorization/index.js +99 -0
  842. package/dist/types/authorization/index.js.map +1 -0
  843. package/dist/types/bus/index.d.ts +24 -1
  844. package/dist/types/bus/index.d.ts.map +1 -1
  845. package/dist/types/code-navigation/index.d.ts +112 -0
  846. package/dist/types/code-navigation/index.d.ts.map +1 -0
  847. package/dist/types/code-navigation/index.js +17 -0
  848. package/dist/types/code-navigation/index.js.map +1 -0
  849. package/dist/types/command/index.d.ts +74 -0
  850. package/dist/types/command/index.d.ts.map +1 -0
  851. package/dist/types/command/index.js +18 -0
  852. package/dist/types/command/index.js.map +1 -0
  853. package/dist/types/common/index.d.ts +11 -2
  854. package/dist/types/common/index.d.ts.map +1 -1
  855. package/dist/types/common/index.js.map +1 -1
  856. package/dist/types/connector/mcp.d.ts +8 -0
  857. package/dist/types/connector/mcp.d.ts.map +1 -1
  858. package/dist/types/guardrail/index.d.ts +1 -1
  859. package/dist/types/hitl/policy.d.ts +79 -0
  860. package/dist/types/hitl/policy.d.ts.map +1 -0
  861. package/dist/types/hitl/policy.js +2 -0
  862. package/dist/types/hitl/policy.js.map +1 -0
  863. package/dist/types/ids/brand.d.ts +55 -0
  864. package/dist/types/ids/brand.d.ts.map +1 -0
  865. package/dist/types/ids/brand.js +45 -0
  866. package/dist/types/ids/brand.js.map +1 -0
  867. package/dist/types/ids/index.d.ts +83 -39
  868. package/dist/types/ids/index.d.ts.map +1 -1
  869. package/dist/types/ids/index.js +5 -1
  870. package/dist/types/ids/index.js.map +1 -1
  871. package/dist/types/message/index.d.ts +24 -1
  872. package/dist/types/message/index.d.ts.map +1 -1
  873. package/dist/types/message/index.js.map +1 -1
  874. package/dist/types/plugin/index.d.ts +8 -8
  875. package/dist/types/project/entity.d.ts +22 -2
  876. package/dist/types/project/entity.d.ts.map +1 -1
  877. package/dist/types/provider/interface.d.ts +43 -2
  878. package/dist/types/provider/interface.d.ts.map +1 -1
  879. package/dist/types/provider/model.d.ts +16 -2
  880. package/dist/types/provider/model.d.ts.map +1 -1
  881. package/dist/types/run/audit.d.ts +150 -0
  882. package/dist/types/run/audit.d.ts.map +1 -0
  883. package/dist/types/run/audit.js +39 -0
  884. package/dist/types/run/audit.js.map +1 -0
  885. package/dist/types/run/cancel-cause.d.ts +49 -0
  886. package/dist/types/run/cancel-cause.d.ts.map +1 -0
  887. package/dist/types/run/cancel-cause.js +39 -0
  888. package/dist/types/run/cancel-cause.js.map +1 -0
  889. package/dist/types/run/checkpoint-store.d.ts +23 -11
  890. package/dist/types/run/checkpoint-store.d.ts.map +1 -1
  891. package/dist/types/run/config.d.ts +24 -4
  892. package/dist/types/run/config.d.ts.map +1 -1
  893. package/dist/types/run/derive-status.d.ts +3 -3
  894. package/dist/types/run/derive-status.d.ts.map +1 -1
  895. package/dist/types/run/derive-status.js +1 -1
  896. package/dist/types/run/entity.d.ts +2 -3
  897. package/dist/types/run/entity.d.ts.map +1 -1
  898. package/dist/types/run/event-cursor.d.ts +3 -3
  899. package/dist/types/run/event-cursor.d.ts.map +1 -1
  900. package/dist/types/run/events.d.ts +159 -4
  901. package/dist/types/run/events.d.ts.map +1 -1
  902. package/dist/types/run/events.js.map +1 -1
  903. package/dist/types/run/index.d.ts +2 -0
  904. package/dist/types/run/index.d.ts.map +1 -1
  905. package/dist/types/run/index.js +2 -0
  906. package/dist/types/run/index.js.map +1 -1
  907. package/dist/types/run/metadata.d.ts +2 -2
  908. package/dist/types/run/metadata.d.ts.map +1 -1
  909. package/dist/types/run/prepare-step.d.ts +29 -0
  910. package/dist/types/run/prepare-step.d.ts.map +1 -1
  911. package/dist/types/run/state.d.ts +33 -10
  912. package/dist/types/run/state.d.ts.map +1 -1
  913. package/dist/types/run/state.js +60 -3
  914. package/dist/types/run/state.js.map +1 -1
  915. package/dist/types/run/stop-reason.d.ts +9 -0
  916. package/dist/types/run/stop-reason.d.ts.map +1 -1
  917. package/dist/types/run/store.d.ts +38 -0
  918. package/dist/types/run/store.d.ts.map +1 -1
  919. package/dist/types/sandbox/index.d.ts +38 -0
  920. package/dist/types/sandbox/index.d.ts.map +1 -1
  921. package/dist/types/sandbox/index.js +21 -0
  922. package/dist/types/sandbox/index.js.map +1 -1
  923. package/dist/types/session/actor.d.ts +2 -2
  924. package/dist/types/session/actor.d.ts.map +1 -1
  925. package/dist/types/session/entity.d.ts +9 -7
  926. package/dist/types/session/entity.d.ts.map +1 -1
  927. package/dist/types/session/ids.d.ts +1 -1
  928. package/dist/types/session/ids.d.ts.map +1 -1
  929. package/dist/types/session/index.d.ts +2 -2
  930. package/dist/types/session/index.d.ts.map +1 -1
  931. package/dist/types/session/store.d.ts +51 -22
  932. package/dist/types/session/store.d.ts.map +1 -1
  933. package/dist/types/session/sub-session.d.ts +44 -5
  934. package/dist/types/session/sub-session.d.ts.map +1 -1
  935. package/dist/types/skills/index.d.ts +41 -0
  936. package/dist/types/skills/index.d.ts.map +1 -1
  937. package/dist/types/skills/index.js +17 -1
  938. package/dist/types/skills/index.js.map +1 -1
  939. package/dist/types/tool/index.d.ts +175 -1
  940. package/dist/types/tool/index.d.ts.map +1 -1
  941. package/dist/types/tool/index.js.map +1 -1
  942. package/dist/types/tool/presentation.d.ts +53 -0
  943. package/dist/types/tool/presentation.d.ts.map +1 -0
  944. package/dist/types/tool/presentation.js +2 -0
  945. package/dist/types/tool/presentation.js.map +1 -0
  946. package/dist/types/{thread → topic}/entity.d.ts +34 -26
  947. package/dist/types/topic/entity.d.ts.map +1 -0
  948. package/dist/types/{thread → topic}/entity.js.map +1 -1
  949. package/dist/types/topic/index.d.ts +5 -0
  950. package/dist/types/topic/index.d.ts.map +1 -0
  951. package/dist/types/topic/index.js +11 -0
  952. package/dist/types/topic/index.js.map +1 -0
  953. package/dist/types/topic/objective.d.ts +86 -0
  954. package/dist/types/topic/objective.d.ts.map +1 -0
  955. package/dist/types/topic/objective.js +10 -0
  956. package/dist/types/topic/objective.js.map +1 -0
  957. package/dist/types/topic/state.d.ts +56 -0
  958. package/dist/types/topic/state.d.ts.map +1 -0
  959. package/dist/types/topic/state.js +10 -0
  960. package/dist/types/topic/state.js.map +1 -0
  961. package/dist/types/topic/store.d.ts +95 -0
  962. package/dist/types/topic/store.d.ts.map +1 -0
  963. package/dist/types/topic/store.js +29 -0
  964. package/dist/types/topic/store.js.map +1 -0
  965. package/dist/types/workspace/ref.d.ts +7 -0
  966. package/dist/types/workspace/ref.d.ts.map +1 -1
  967. package/dist/utils/abort.d.ts.map +1 -1
  968. package/dist/utils/abort.js +13 -1
  969. package/dist/utils/abort.js.map +1 -1
  970. package/dist/utils/hash.d.ts +10 -0
  971. package/dist/utils/hash.d.ts.map +1 -1
  972. package/dist/utils/hash.js +15 -0
  973. package/dist/utils/hash.js.map +1 -1
  974. package/dist/utils/id.d.ts +82 -2
  975. package/dist/utils/id.d.ts.map +1 -1
  976. package/dist/utils/id.js +104 -4
  977. package/dist/utils/id.js.map +1 -1
  978. package/dist/utils/log/attributes.d.ts +17 -0
  979. package/dist/utils/log/attributes.d.ts.map +1 -0
  980. package/dist/utils/log/attributes.js +2 -0
  981. package/dist/utils/log/attributes.js.map +1 -0
  982. package/dist/utils/log/caps.d.ts +27 -0
  983. package/dist/utils/log/caps.d.ts.map +1 -0
  984. package/dist/utils/log/caps.js +107 -0
  985. package/dist/utils/log/caps.js.map +1 -0
  986. package/dist/utils/log/create-logger.d.ts +28 -0
  987. package/dist/utils/log/create-logger.d.ts.map +1 -0
  988. package/dist/utils/log/create-logger.js +168 -0
  989. package/dist/utils/log/create-logger.js.map +1 -0
  990. package/dist/utils/log/exception.d.ts +11 -0
  991. package/dist/utils/log/exception.d.ts.map +1 -0
  992. package/dist/utils/log/exception.js +108 -0
  993. package/dist/utils/log/exception.js.map +1 -0
  994. package/dist/utils/log/index.d.ts +7 -0
  995. package/dist/utils/log/index.d.ts.map +1 -0
  996. package/dist/utils/log/index.js +15 -0
  997. package/dist/utils/log/index.js.map +1 -0
  998. package/dist/utils/log/process-sink.d.ts +28 -0
  999. package/dist/utils/log/process-sink.d.ts.map +1 -0
  1000. package/dist/utils/log/process-sink.js +56 -0
  1001. package/dist/utils/log/process-sink.js.map +1 -0
  1002. package/dist/utils/log/redact.d.ts +3 -0
  1003. package/dist/utils/log/redact.d.ts.map +1 -0
  1004. package/dist/utils/log/redact.js +71 -0
  1005. package/dist/utils/log/redact.js.map +1 -0
  1006. package/dist/utils/log/sinks.d.ts +43 -0
  1007. package/dist/utils/log/sinks.d.ts.map +1 -0
  1008. package/dist/utils/log/sinks.js +184 -0
  1009. package/dist/utils/log/sinks.js.map +1 -0
  1010. package/dist/utils/log/templates.d.ts +63 -0
  1011. package/dist/utils/log/templates.d.ts.map +1 -0
  1012. package/dist/utils/log/templates.js +119 -0
  1013. package/dist/utils/log/templates.js.map +1 -0
  1014. package/dist/utils/log/types.d.ts +183 -0
  1015. package/dist/utils/log/types.d.ts.map +1 -0
  1016. package/dist/utils/log/types.js +55 -0
  1017. package/dist/utils/log/types.js.map +1 -0
  1018. package/dist/utils/logger.d.ts +44 -0
  1019. package/dist/utils/logger.d.ts.map +1 -1
  1020. package/dist/utils/logger.js +102 -2
  1021. package/dist/utils/logger.js.map +1 -1
  1022. package/dist/utils/renamed-field.d.ts +19 -0
  1023. package/dist/utils/renamed-field.d.ts.map +1 -0
  1024. package/dist/utils/renamed-field.js +29 -0
  1025. package/dist/utils/renamed-field.js.map +1 -0
  1026. package/dist/vault/CredentialProvider.d.ts +89 -0
  1027. package/dist/vault/CredentialProvider.d.ts.map +1 -0
  1028. package/dist/vault/CredentialProvider.js +64 -0
  1029. package/dist/vault/CredentialProvider.js.map +1 -0
  1030. package/dist/vault/InMemoryCredentialVault.d.ts +2 -1
  1031. package/dist/vault/InMemoryCredentialVault.d.ts.map +1 -1
  1032. package/dist/vault/InMemoryCredentialVault.js +15 -5
  1033. package/dist/vault/InMemoryCredentialVault.js.map +1 -1
  1034. package/dist/vault/index.d.ts +3 -0
  1035. package/dist/vault/index.d.ts.map +1 -1
  1036. package/dist/vault/index.js +5 -0
  1037. package/dist/vault/index.js.map +1 -1
  1038. package/dist/vault/instrumentation.d.ts +18 -2
  1039. package/dist/vault/instrumentation.d.ts.map +1 -1
  1040. package/dist/vault/instrumentation.js +47 -0
  1041. package/dist/vault/instrumentation.js.map +1 -1
  1042. package/package.json +4 -4
  1043. package/src/advisory/executor.ts +14 -12
  1044. package/src/advisory/registry.ts +2 -2
  1045. package/src/agents/AGENTS.md +91 -0
  1046. package/src/agents/AbstractAgent.ts +67 -14
  1047. package/src/agents/PipelineAgent.ts +46 -12
  1048. package/src/agents/ReactiveAgent.ts +27 -14
  1049. package/src/agents/RouterAgent.ts +33 -21
  1050. package/src/agents/SupervisorAgent.ts +46 -28
  1051. package/src/agents/handle.ts +149 -0
  1052. package/src/agents/runAgent.ts +14 -7
  1053. package/src/{verification → authorization}/gate.ts +39 -32
  1054. package/src/authorization/index.ts +26 -0
  1055. package/src/authorization/permission-presets.ts +215 -0
  1056. package/src/{verification → authorization}/presets.ts +15 -3
  1057. package/src/{verification → authorization}/rules.ts +16 -3
  1058. package/src/bridge/a2a/client.ts +369 -0
  1059. package/src/bridge/a2a/mapper.ts +17 -0
  1060. package/src/bridge/acp/filesystem.ts +63 -0
  1061. package/src/bridge/acp/index.ts +11 -0
  1062. package/src/bridge/acp/permission.ts +71 -0
  1063. package/src/bridge/acp/server.ts +500 -0
  1064. package/src/bridge/acp/update.ts +109 -0
  1065. package/src/bridge/mcp/connector/adapter.ts +8 -4
  1066. package/src/bridge/sse/mapper.ts +30 -0
  1067. package/src/bus/breaker.ts +15 -10
  1068. package/src/bus/index.ts +10 -8
  1069. package/src/bus/lock.ts +36 -19
  1070. package/src/bus/ownership.ts +17 -9
  1071. package/src/compaction/context-window.ts +23 -1
  1072. package/src/compaction/index.ts +6 -0
  1073. package/src/compaction/manual.ts +177 -0
  1074. package/src/compaction/plan.ts +226 -0
  1075. package/src/compaction/summary.ts +31 -0
  1076. package/src/compaction/verifier.ts +2 -2
  1077. package/src/config/registry.ts +208 -0
  1078. package/src/config/runtime.ts +27 -0
  1079. package/src/connector/BaseConnector.ts +8 -3
  1080. package/src/connector/builtins/http.ts +12 -2
  1081. package/src/connector/builtins/webhook.ts +6 -2
  1082. package/src/connector/index.ts +45 -29
  1083. package/src/connector/mcp/client.ts +32 -20
  1084. package/src/connector/mcp/discovery.ts +31 -20
  1085. package/src/connector/mcp/http-sse.ts +12 -6
  1086. package/src/connector/mcp/index.ts +8 -7
  1087. package/src/connector/mcp/reconnect.ts +194 -0
  1088. package/src/connector/mcp/server/index.ts +32 -0
  1089. package/src/connector/mcp/{server-stdio.ts → server/server-stdio.ts} +5 -4
  1090. package/src/connector/mcp/{server.ts → server/server.ts} +17 -11
  1091. package/src/connector/mcp/stdio.ts +18 -9
  1092. package/src/connector/mcp/streamable-http.ts +8 -4
  1093. package/src/{bridge/tools/connector → connector/tools}/adapter.ts +5 -5
  1094. package/src/{bridge/tools/connector → connector/tools}/definitions.ts +4 -4
  1095. package/src/{bridge/tools/connector → connector/tools}/router.ts +17 -9
  1096. package/src/connector/web/guarded-fetch.ts +288 -0
  1097. package/src/connector/web/index.ts +17 -0
  1098. package/src/connector/web/types.ts +99 -0
  1099. package/src/constants/acp/index.ts +104 -0
  1100. package/src/constants/credential-env-keys.ts +63 -0
  1101. package/src/constants/index.ts +3 -1
  1102. package/src/constants/secret-patterns.ts +102 -0
  1103. package/src/constants/telemetry/index.ts +98 -0
  1104. package/src/contracts/api.ts +11 -0
  1105. package/src/eval/judge.ts +2 -2
  1106. package/src/execution/base.ts +18 -7
  1107. package/src/execution/code-runtime/types.ts +116 -0
  1108. package/src/execution/code-runtime/worker.ts +266 -0
  1109. package/src/{connector/execution → execution}/factory.ts +3 -3
  1110. package/src/{connector/execution → execution}/hybrid.ts +13 -7
  1111. package/src/execution/index.ts +24 -0
  1112. package/src/execution/local.ts +4 -2
  1113. package/src/{connector/execution → execution}/remote.ts +15 -8
  1114. package/src/index.ts +17 -0
  1115. package/src/invariants/index.ts +201 -0
  1116. package/src/manager/agent/lifecycle.ts +172 -58
  1117. package/src/manager/connector/environment.ts +22 -11
  1118. package/src/manager/connector/lifecycle.ts +30 -11
  1119. package/src/manager/connector/tenant.ts +33 -14
  1120. package/src/manager/index.ts +15 -2
  1121. package/src/manager/project/lifecycle.ts +1 -1
  1122. package/src/manager/run/emergency.ts +9 -7
  1123. package/src/manager/run/persistence.ts +110 -8
  1124. package/src/manager/topic/lifecycle.ts +235 -0
  1125. package/src/manager/topic/objective.ts +203 -0
  1126. package/src/persona/assembler.ts +14 -3
  1127. package/src/plugin/lifecycle.ts +156 -20
  1128. package/src/plugin/loader.ts +67 -16
  1129. package/src/probe/index.ts +1 -0
  1130. package/src/probe/registry.ts +41 -5
  1131. package/src/process/kill-tree.ts +52 -0
  1132. package/src/prompt/contributions.ts +173 -0
  1133. package/src/prompt/index.ts +15 -0
  1134. package/src/provider/attribution.ts +57 -0
  1135. package/src/provider/{collect.ts → collect-chat-completion.ts} +4 -2
  1136. package/src/provider/conformance.ts +189 -0
  1137. package/src/provider/errors.ts +27 -12
  1138. package/src/provider/fallback.ts +32 -10
  1139. package/src/provider/idle-timeout.ts +112 -0
  1140. package/src/provider/instrumentation.ts +4 -2
  1141. package/src/provider/retry.ts +63 -21
  1142. package/src/public-runtime.ts +371 -18
  1143. package/src/public-tools.ts +41 -1
  1144. package/src/public-types.ts +101 -4
  1145. package/src/rag/rag-tool.ts +4 -2
  1146. package/src/read-model/index.ts +14 -0
  1147. package/src/read-model/registry.ts +152 -0
  1148. package/src/read-model/run-status.ts +127 -0
  1149. package/src/registry/{Registry.ts → BaseRegistry.ts} +1 -1
  1150. package/src/registry/ManagedRegistry.ts +26 -9
  1151. package/src/registry/command/index-exports.ts +4 -0
  1152. package/src/registry/command/index.ts +105 -0
  1153. package/src/registry/command/kernel-commands.ts +110 -0
  1154. package/src/registry/connector/scoped.ts +6 -5
  1155. package/src/registry/index.ts +7 -1
  1156. package/src/registry/tool/execute.ts +15 -12
  1157. package/src/registry/tool/presentation.ts +116 -0
  1158. package/src/registry/tool/screen.ts +12 -11
  1159. package/src/run/drain.ts +13 -3
  1160. package/src/run/reporter.ts +208 -153
  1161. package/src/run-query/index.ts +108 -0
  1162. package/src/runtime/bidi/session.ts +7 -2
  1163. package/src/runtime/decision/fallback.ts +6 -3
  1164. package/src/runtime/decision/parser.ts +10 -9
  1165. package/src/runtime/jobs/registry.ts +346 -0
  1166. package/src/runtime/query/approval-policy.ts +78 -0
  1167. package/src/runtime/query/checkpoint.ts +6 -6
  1168. package/src/runtime/query/context.ts +120 -30
  1169. package/src/runtime/query/events.ts +19 -11
  1170. package/src/runtime/query/executor.ts +287 -66
  1171. package/src/runtime/query/guardrail-presets.ts +11 -14
  1172. package/src/runtime/query/guardrails.ts +16 -12
  1173. package/src/runtime/query/index.ts +539 -96
  1174. package/src/runtime/query/iteration/index.ts +269 -87
  1175. package/src/runtime/query/iteration/phases/advisory.ts +17 -16
  1176. package/src/runtime/query/iteration/phases/compaction.ts +235 -187
  1177. package/src/runtime/query/iteration/phases/context.ts +82 -21
  1178. package/src/runtime/query/iteration/phases/tool-review.ts +28 -9
  1179. package/src/runtime/query/iteration/phases/working-memory.ts +3 -2
  1180. package/src/runtime/query/iteration/stream-turn.ts +14 -14
  1181. package/src/runtime/query/{context-cache.ts → prompt-cache.ts} +23 -3
  1182. package/src/runtime/query/prompt.ts +104 -4
  1183. package/src/runtime/query/repeat-call.ts +130 -0
  1184. package/src/runtime/query/replay/mutate.ts +6 -0
  1185. package/src/runtime/query/result.ts +47 -10
  1186. package/src/runtime/query/resume-pending.ts +19 -17
  1187. package/src/runtime/query/resume-run.ts +2 -2
  1188. package/src/runtime/query/run-state.ts +5 -5
  1189. package/src/runtime/query/tool-grants.ts +1 -1
  1190. package/src/runtime/query/tool-output-budget.ts +36 -3
  1191. package/src/runtime/query/tool-pause.ts +2 -1
  1192. package/src/runtime/query/tooling.ts +17 -2
  1193. package/src/sandbox/provider/local.ts +94 -21
  1194. package/src/sandbox/terminal.ts +197 -0
  1195. package/src/{gateway → scheduler}/completion-inbox.ts +20 -10
  1196. package/src/scheduler/delegating.ts +297 -0
  1197. package/src/{gateway → scheduler}/local.ts +24 -15
  1198. package/src/session/actor-scope.ts +121 -0
  1199. package/src/session/errors.ts +30 -8
  1200. package/src/session/handoff/assignment.ts +5 -5
  1201. package/src/session/handoff/broadcast.ts +16 -12
  1202. package/src/session/handoff/index.ts +1 -1
  1203. package/src/session/handoff/single.ts +16 -17
  1204. package/src/session/migration/filesystem.ts +46 -2
  1205. package/src/session/migration/id-prefix.ts +47 -22
  1206. package/src/session/migration/index.ts +5 -2
  1207. package/src/session/migration/marker.ts +19 -4
  1208. package/src/session/retention/archive.ts +19 -12
  1209. package/src/session/workspace/git-worktree.ts +17 -8
  1210. package/src/skills/loader.ts +39 -9
  1211. package/src/skills/registry.ts +177 -20
  1212. package/src/store/attachment/index.ts +182 -0
  1213. package/src/store/config/index.ts +74 -0
  1214. package/src/store/feedback/conformance.ts +193 -0
  1215. package/src/store/feedback/disk.ts +184 -0
  1216. package/src/store/feedback/index.ts +13 -0
  1217. package/src/store/feedback/memory.ts +0 -0
  1218. package/src/store/feedback/types.ts +107 -0
  1219. package/src/store/index.ts +5 -0
  1220. package/src/store/kv/record-store.ts +91 -0
  1221. package/src/store/memory/disk.ts +35 -32
  1222. package/src/store/run/checkpoint-disk.ts +27 -6
  1223. package/src/store/run/checkpoint-memory.ts +8 -8
  1224. package/src/store/run/claim-disk.ts +58 -13
  1225. package/src/store/run/conformance.ts +11 -10
  1226. package/src/store/run/disk.ts +77 -5
  1227. package/src/store/run/listing.ts +6 -6
  1228. package/src/store/run/memory.ts +24 -1
  1229. package/src/store/session/canonical-path.ts +45 -0
  1230. package/src/store/session/disk.ts +216 -191
  1231. package/src/store/session/memory.ts +43 -5
  1232. package/src/store/task/disk.ts +77 -67
  1233. package/src/store/topic/index.ts +33 -0
  1234. package/src/store/topic/memory.ts +111 -0
  1235. package/src/store/topic/objective.ts +290 -0
  1236. package/src/store/topic/state.ts +204 -0
  1237. package/src/streaming/coalesce.ts +19 -5
  1238. package/src/telemetry/runtime-accessors.ts +45 -1
  1239. package/src/test-support/ids.ts +117 -0
  1240. package/src/testing.ts +40 -0
  1241. package/src/tools/builtins/bash.ts +82 -3
  1242. package/src/tools/builtins/edit.ts +36 -0
  1243. package/src/tools/builtins/index.ts +29 -1
  1244. package/src/tools/builtins/job.ts +133 -0
  1245. package/src/tools/builtins/lsp.ts +214 -0
  1246. package/src/tools/builtins/run-code.ts +154 -0
  1247. package/src/tools/builtins/skill.ts +134 -0
  1248. package/src/tools/builtins/web-guidance.ts +46 -0
  1249. package/src/tools/builtins/web.ts +156 -0
  1250. package/src/tools/builtins/write-file.ts +37 -1
  1251. package/src/tools/coordinator/agent.ts +2 -2
  1252. package/src/tools/coordinator/index.ts +144 -40
  1253. package/src/tools/coordinator/outcome.ts +2 -2
  1254. package/src/tools/coordinator/wait-with-idle-bound.ts +3 -3
  1255. package/src/tools/defineTool.ts +14 -0
  1256. package/src/tools/env-scrub.ts +91 -0
  1257. package/src/tools/memory/read.ts +5 -2
  1258. package/src/tools/task/create.ts +2 -1
  1259. package/src/tools/task/update.ts +7 -4
  1260. package/src/types/acp/index.ts +163 -0
  1261. package/src/types/agent/base.ts +67 -5
  1262. package/src/types/agent/delegate.ts +110 -0
  1263. package/src/types/agent/index.ts +1 -1
  1264. package/src/types/agent/manager.ts +7 -1
  1265. package/src/types/agent/reactive.ts +22 -3
  1266. package/src/types/agent/{gateway.ts → scheduler.ts} +30 -4
  1267. package/src/types/agent/supervisor.ts +15 -5
  1268. package/src/types/agent/task.ts +31 -9
  1269. package/src/types/agent/working-memory.ts +1 -1
  1270. package/src/types/{verification → authorization}/index.ts +69 -10
  1271. package/src/types/bus/index.ts +30 -1
  1272. package/src/types/code-navigation/index.ts +99 -0
  1273. package/src/types/command/index.ts +68 -0
  1274. package/src/types/common/index.ts +17 -2
  1275. package/src/types/connector/mcp.ts +8 -0
  1276. package/src/types/guardrail/index.ts +1 -1
  1277. package/src/types/hitl/policy.ts +83 -0
  1278. package/src/types/ids/brand.ts +58 -0
  1279. package/src/types/ids/index.ts +94 -42
  1280. package/src/types/message/index.ts +25 -1
  1281. package/src/types/project/entity.ts +22 -2
  1282. package/src/types/provider/interface.ts +45 -2
  1283. package/src/types/provider/model.ts +16 -2
  1284. package/src/types/run/audit.ts +164 -0
  1285. package/src/types/run/cancel-cause.ts +60 -0
  1286. package/src/types/run/checkpoint-store.ts +24 -11
  1287. package/src/types/run/config.ts +25 -4
  1288. package/src/types/run/derive-status.ts +3 -3
  1289. package/src/types/run/entity.ts +2 -4
  1290. package/src/types/run/event-cursor.ts +3 -3
  1291. package/src/types/run/events.ts +165 -6
  1292. package/src/types/run/index.ts +2 -0
  1293. package/src/types/run/metadata.ts +2 -2
  1294. package/src/types/run/prepare-step.ts +33 -0
  1295. package/src/types/run/state.ts +78 -11
  1296. package/src/types/run/stop-reason.ts +9 -0
  1297. package/src/types/run/store.ts +40 -0
  1298. package/src/types/sandbox/index.ts +37 -0
  1299. package/src/types/session/actor.ts +10 -2
  1300. package/src/types/session/entity.ts +9 -7
  1301. package/src/types/session/ids.ts +1 -1
  1302. package/src/types/session/index.ts +1 -1
  1303. package/src/types/session/store.ts +53 -22
  1304. package/src/types/session/sub-session.ts +45 -16
  1305. package/src/types/skills/index.ts +50 -0
  1306. package/src/types/tool/index.ts +156 -1
  1307. package/src/types/tool/presentation.ts +48 -0
  1308. package/src/types/{thread → topic}/entity.ts +34 -26
  1309. package/src/types/topic/index.ts +23 -0
  1310. package/src/types/topic/objective.ts +93 -0
  1311. package/src/types/topic/state.ts +60 -0
  1312. package/src/types/topic/store.ts +101 -0
  1313. package/src/types/workspace/ref.ts +7 -0
  1314. package/src/utils/abort.ts +16 -1
  1315. package/src/utils/hash.ts +16 -0
  1316. package/src/utils/id.ts +163 -12
  1317. package/src/utils/log/attributes.ts +47 -0
  1318. package/src/utils/log/caps.ts +118 -0
  1319. package/src/utils/log/create-logger.ts +198 -0
  1320. package/src/utils/log/exception.ts +124 -0
  1321. package/src/utils/log/index.ts +24 -0
  1322. package/src/utils/log/process-sink.ts +76 -0
  1323. package/src/utils/log/redact.ts +77 -0
  1324. package/src/utils/log/sinks.ts +205 -0
  1325. package/src/utils/log/templates.ts +161 -0
  1326. package/src/utils/log/types.ts +195 -0
  1327. package/src/utils/logger.ts +121 -2
  1328. package/src/utils/renamed-field.ts +35 -0
  1329. package/src/vault/CredentialProvider.ts +147 -0
  1330. package/src/vault/InMemoryCredentialVault.ts +16 -5
  1331. package/src/vault/index.ts +16 -0
  1332. package/src/vault/instrumentation.ts +63 -2
  1333. package/dist/bridge/tools/connector/adapter.d.ts.map +0 -1
  1334. package/dist/bridge/tools/connector/adapter.js.map +0 -1
  1335. package/dist/bridge/tools/connector/definitions.d.ts.map +0 -1
  1336. package/dist/bridge/tools/connector/definitions.js.map +0 -1
  1337. package/dist/bridge/tools/connector/index.d.ts.map +0 -1
  1338. package/dist/bridge/tools/connector/index.js.map +0 -1
  1339. package/dist/bridge/tools/connector/router.d.ts.map +0 -1
  1340. package/dist/bridge/tools/connector/router.js.map +0 -1
  1341. package/dist/connector/execution/factory.d.ts.map +0 -1
  1342. package/dist/connector/execution/factory.js.map +0 -1
  1343. package/dist/connector/execution/hybrid.d.ts.map +0 -1
  1344. package/dist/connector/execution/hybrid.js.map +0 -1
  1345. package/dist/connector/execution/index.d.ts +0 -6
  1346. package/dist/connector/execution/index.d.ts.map +0 -1
  1347. package/dist/connector/execution/index.js +0 -4
  1348. package/dist/connector/execution/index.js.map +0 -1
  1349. package/dist/connector/execution/remote.d.ts.map +0 -1
  1350. package/dist/connector/execution/remote.js.map +0 -1
  1351. package/dist/connector/mcp/server-stdio.d.ts.map +0 -1
  1352. package/dist/connector/mcp/server-stdio.js.map +0 -1
  1353. package/dist/connector/mcp/server.d.ts.map +0 -1
  1354. package/dist/connector/mcp/server.js.map +0 -1
  1355. package/dist/constants/verification/index.d.ts.map +0 -1
  1356. package/dist/constants/verification/index.js.map +0 -1
  1357. package/dist/gateway/completion-inbox.d.ts.map +0 -1
  1358. package/dist/gateway/completion-inbox.js.map +0 -1
  1359. package/dist/gateway/local.d.ts.map +0 -1
  1360. package/dist/gateway/local.js.map +0 -1
  1361. package/dist/manager/thread/lifecycle.d.ts +0 -105
  1362. package/dist/manager/thread/lifecycle.d.ts.map +0 -1
  1363. package/dist/manager/thread/lifecycle.js.map +0 -1
  1364. package/dist/provider/collect.d.ts.map +0 -1
  1365. package/dist/provider/collect.js.map +0 -1
  1366. package/dist/registry/Registry.d.ts.map +0 -1
  1367. package/dist/registry/Registry.js.map +0 -1
  1368. package/dist/router/task-router.d.ts.map +0 -1
  1369. package/dist/router/task-router.js.map +0 -1
  1370. package/dist/runtime/query/context-cache.d.ts.map +0 -1
  1371. package/dist/runtime/query/context-cache.js.map +0 -1
  1372. package/dist/store/thread/disk.d.ts +0 -41
  1373. package/dist/store/thread/disk.d.ts.map +0 -1
  1374. package/dist/store/thread/disk.js +0 -238
  1375. package/dist/store/thread/disk.js.map +0 -1
  1376. package/dist/store/thread/index.d.ts +0 -4
  1377. package/dist/store/thread/index.d.ts.map +0 -1
  1378. package/dist/store/thread/index.js +0 -6
  1379. package/dist/store/thread/index.js.map +0 -1
  1380. package/dist/store/thread/memory.d.ts +0 -23
  1381. package/dist/store/thread/memory.d.ts.map +0 -1
  1382. package/dist/store/thread/memory.js +0 -90
  1383. package/dist/store/thread/memory.js.map +0 -1
  1384. package/dist/types/agent/gateway.d.ts.map +0 -1
  1385. package/dist/types/agent/gateway.js +0 -2
  1386. package/dist/types/agent/gateway.js.map +0 -1
  1387. package/dist/types/thread/entity.d.ts.map +0 -1
  1388. package/dist/types/thread/index.d.ts +0 -3
  1389. package/dist/types/thread/index.d.ts.map +0 -1
  1390. package/dist/types/thread/index.js +0 -5
  1391. package/dist/types/thread/index.js.map +0 -1
  1392. package/dist/types/thread/store.d.ts +0 -86
  1393. package/dist/types/thread/store.d.ts.map +0 -1
  1394. package/dist/types/thread/store.js +0 -22
  1395. package/dist/types/thread/store.js.map +0 -1
  1396. package/dist/types/verification/index.d.ts.map +0 -1
  1397. package/dist/types/verification/index.js +0 -53
  1398. package/dist/types/verification/index.js.map +0 -1
  1399. package/dist/verification/gate.d.ts.map +0 -1
  1400. package/dist/verification/gate.js.map +0 -1
  1401. package/dist/verification/index.d.ts +0 -4
  1402. package/dist/verification/index.d.ts.map +0 -1
  1403. package/dist/verification/index.js +0 -4
  1404. package/dist/verification/index.js.map +0 -1
  1405. package/dist/verification/presets.d.ts.map +0 -1
  1406. package/dist/verification/presets.js.map +0 -1
  1407. package/dist/verification/rules.d.ts +0 -4
  1408. package/dist/verification/rules.d.ts.map +0 -1
  1409. package/dist/verification/rules.js.map +0 -1
  1410. package/src/connector/execution/index.ts +0 -5
  1411. package/src/manager/thread/lifecycle.ts +0 -217
  1412. package/src/store/thread/disk.ts +0 -272
  1413. package/src/store/thread/index.ts +0 -7
  1414. package/src/store/thread/memory.ts +0 -104
  1415. package/src/types/thread/index.ts +0 -6
  1416. package/src/types/thread/store.ts +0 -92
  1417. package/src/verification/index.ts +0 -3
  1418. /package/dist/{bridge/tools/connector → connector/tools}/index.d.ts +0 -0
  1419. /package/dist/{bridge/tools/connector → connector/tools}/index.js +0 -0
  1420. /package/dist/constants/{verification → authorization}/index.d.ts +0 -0
  1421. /package/dist/constants/{verification → authorization}/index.js +0 -0
  1422. /package/dist/{router → model-router}/task-router.d.ts +0 -0
  1423. /package/dist/{router → model-router}/task-router.js +0 -0
  1424. /package/dist/types/{thread → topic}/entity.js +0 -0
  1425. /package/src/{bridge/tools/connector → connector/tools}/index.ts +0 -0
  1426. /package/src/constants/{verification → authorization}/index.ts +0 -0
  1427. /package/src/{router → model-router}/task-router.ts +0 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,1762 @@
1
1
  # Changelog
2
2
 
3
+ ## 29.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - e114fd5: Three deprecation windows opened by NZ-RUNREC-10, -11 and -13 close here. 28.0.0
8
+ carried all three; this release acts on them.
9
+
10
+ **`AgentStatus` is removed.** Use `RunExecutionStatus`. It was an alias with an
11
+ identical union — the rename existed because the name described the wrong
12
+ subject: every use was a run's status, and an agent has none of its own. Rename
13
+ the import and nothing else changes.
14
+
15
+ **`SubSessionStatus` narrows to the five driven variants** and is now an alias
16
+ of `SubSessionDelegationStatus`: `pending`, `active`, `idle`, `failed`,
17
+ `archived`. The six merge variants (`awaiting_merge`, `pending_merge`,
18
+ `merging`, `merged`, `merge_conflict`, `merge_rejected`) had no producer
19
+ anywhere and are gone. Drop any switch case for them; a `default` that handled
20
+ them still compiles.
21
+
22
+ `ARCHIVABLE_STATUSES` loses `merged` and `merge_rejected` with them. They were
23
+ kept one release because a host could have persisted one while the union was
24
+ wide; if you have such a record, migrate it to `idle` or `failed` before
25
+ upgrading, or it becomes un-archivable.
26
+
27
+ **`SingleHandoffDeps.runStatus` and `BroadcastHandoffDeps.runStatus` are
28
+ required, and `NOOP_RUN_STATUS_RESOLVER` is removed.** The default it supplied
29
+ answered `null` for every session, so the non-terminal-run fan-in check on
30
+ handoff could not fail — a lock was allowed while a run was still going, and
31
+ nothing said so. Pass `createRunStatusResolver(store)`, or, if you genuinely
32
+ want no fan-in check, your own always-null resolver — deliberately, and visibly
33
+ at the call site.
34
+
35
+ - 0ef3e40: The six `Thread*` aliases are removed. 28.0.0 carried them deprecated; this is
36
+ the release that drops them.
37
+
38
+ | Removed | Use |
39
+ | ------------------------ | ------------------------------- |
40
+ | `ThreadId` | `TopicId` |
41
+ | `ThreadManager` | `TopicManager` |
42
+ | `InMemoryThreadStore` | `InMemoryTopicStore` |
43
+ | `generateThreadId()` | `generateTopicId()` |
44
+ | `acceptLegacyThreadId()` | `acceptLegacyContainerId()` |
45
+ | `rejectLegacyPrefix()` | `rejectLegacyContainerPrefix()` |
46
+
47
+ Each was an identity binding to the name on the right, so the migration is a
48
+ rename and nothing else — no behaviour changes with it, and `instanceof` and
49
+ `===` held across the alias while it existed.
50
+
51
+ The two `Legacy` helpers are worth a sentence, because their names described
52
+ the wrong thing. They decide whether an id belongs to the pre-0.2.0 top-level
53
+ CONTAINER, which is what `thd_` means now; they were never about a Topic. The
54
+ replacements say container.
55
+
56
+ Nothing on disk changes. A `thd_`-prefixed id already migrates to
57
+ `prj_legacy_*` at read time and continues to.
58
+
59
+ - e92b530: The NZ-SURF-05..08 deprecation wave closes. 28.0.0 carried every name below;
60
+ this release removes them.
61
+
62
+ | Removed | Use |
63
+ | ---------------------------------------------------------------------------------- | ------------------------------------------ |
64
+ | `collect` | `collectChatCompletion` |
65
+ | `Registry` | `BaseRegistry` |
66
+ | `ContextCache`, `ContextCacheConfig` | `PromptCache`, `PromptCacheConfig` |
67
+ | `RunClaim`, `ClaimFence`, `ClaimSummary` | `RunLease`, `FencingToken`, `LeaseSummary` |
68
+ | `TaskGateway`, `LocalTaskGateway` | `TaskScheduler`, `LocalTaskScheduler` |
69
+ | `VerificationGate`, `VerificationRule` | `AuthorizationGate`, `AuthorizationRule` |
70
+ | `VerificationGateConfig`, `VerificationGateConfigSchema`, `VerificationRuleSchema` | the `Authorization*` spellings |
71
+
72
+ Four configuration fields go with them, each an old spelling of a field that
73
+ still exists:
74
+
75
+ | Removed field | On | Use |
76
+ | ------------------ | ------------------------------------------------------------- | ------------------- |
77
+ | `contextCache` | `QueryParams` | `promptCache` |
78
+ | `taskGateway` | `QueryParams` | `taskScheduler` |
79
+ | `verificationGate` | `QueryParams`, `ReactiveAgentConfig`, `SupervisorAgentConfig` | `authorizationGate` |
80
+ | `gateway` | `SupervisorAgentConfig` | `scheduler` |
81
+
82
+ Every removal is a rename. The values, the shapes and the behaviour are
83
+ unchanged — `Registry` and `BaseRegistry` were the same class object, and
84
+ `instanceof` held across both spellings while the aliases existed.
85
+
86
+ Setting both spellings of one field used to be refused at the top of the run
87
+ with a message naming both. That check goes with the old names, and so does
88
+ `pickRenamed`'s last caller; the helper stays for the next wave.
89
+
90
+ If you are still on an old spelling, the compiler will name every site. There
91
+ is no runtime failure mode here — a removed type is a build error, and a
92
+ removed config field is silently ignored by `exactOptionalPropertyTypes` only
93
+ if your own type declares it, which is why these are listed field by field
94
+ above.
95
+
96
+ ## 28.0.0
97
+
98
+ ### Major Changes
99
+
100
+ - d7d38a3: New optional `LLMProvider.retryDefaults`. A driver can declare the retry behaviour its vendor wants, merged inside `withProviderRetry` between the generic default and whatever the caller passed.
101
+
102
+ One config was applied to every member of a provider chain. An operator running [expensive primary, cheap self-hosted backup] could not give the backup a shorter budget or a different ceiling on a server-directed `Retry-After` — the two have different failure shapes and different costs per attempt, and only the driver knows which. The host configuring a chain is choosing between vendors, not tuning each one's transport.
103
+
104
+ The merge is `{ ...DEFAULT, ...provider.retryDefaults, ...options.config }`, and the order is the contract: a driver's declaration is a _default_ and a caller's config is an _intention_. Reversing it would let a driver override the operator, including re-enabling retries a host had switched off.
105
+
106
+ Merged inside `withProviderRetry` rather than at `query()`'s call site, because that function is exported: a host wrapping its own chain gets the same precedence instead of the generic default.
107
+
108
+ **Breaking:** `ProviderDriverConformanceOptions` now requires `retryDefaults` — a value, or `undefined` with the reason written down. A new driver package that never made the decision does not typecheck. Existing drivers all declare `undefined`: the generic default suits them.
109
+
110
+ - cb1a487: The id types are nominal. `const runId: RunId = 'run_abc'` no longer compiles, and neither does passing a `SessionId` where a `RunId` was asked for.
111
+
112
+ Every id in `types/ids/index.ts` — 40 of them — is now `Id<Prefix, Tag>`: its wire shape intersected with a unique-symbol brand. The prefix stays in the type, so a hover still reads `` `run_${string}` `` and a log line is still legible; what changes is that a matching string is no longer _assignable_ to the type. Before this, `const a: AgentId = 'agt_made-up'` compiled and was indistinguishable from an id a factory minted, which made the "branded ids" the design claimed a comment rather than a property.
113
+
114
+ **Migrating.** An id comes from one of three places, and each satisfies the type with no assertion at the call site:
115
+
116
+ - `generateRunId()` and friends — mint a new one.
117
+ - `asRunId(value)` and friends — check a string from a log line, a URL, a flag, or a model's tool input. Throws `InvalidIdError` naming the prefix it wanted.
118
+ - In this repo's own tests, `fixtureId.run('a')` from `test-support/ids.ts`, which skips the check because a fixture is not testing prefix validation.
119
+
120
+ A `value as RunId` assertion still compiles — that is TypeScript's assertion rule, not an oversight, and `types/ids/__tests__/an-id-is-not-a-string.test.ts` pins it as a stated gap rather than leaving a reader to assume a fake id is now impossible. The brand makes a rule against `as <IdType>` enforceable; it does not replace one.
121
+
122
+ **`ActorRef.agentId` is now `string`, and that is a correction.** It was annotated `AgentId` (`` `agt_${string}` ``) and every value that ever reached it was an agent's registry key — `'worker'`, `'supervisor'` — put there through a cast. Nothing in this kernel has ever minted an `agt_` id; there is no `generateAgentId`. `AgentId` and `asAgentId` are kept for one release and marked `@deprecated`, so a consumer that annotated its own variable still compiles and gets a warning; `asAgentId` would throw on every identifier the kernel actually produces.
123
+
124
+ **`LockAcquireResult.holder` is optional.** The `{ acquired: false }` branch is also reached when the lock was released between the attempt and the read, and it used to report `'' as RunId` for that — an empty string wearing an id type, which no caller could tell apart from a real holder. An absent `holder` says what is true: there is nobody to name. Read it as `result.holder` where you previously compared against `''`.
125
+
126
+ **A prefix can no longer drift from its type inside the id factory itself.** `generateId`, `parseId` and `makeIdParser` take the prefix as an inferred type parameter constrained by the id's own shape, so `generateRunId` returning `generateId('ses_')` is a compile error. That constraint was written wrong the first time — supplying one of two type parameters explicitly makes the other fall back to its default, so `makeIdParser<RunId>('ses_')` compiled and the check was vacuous. It is now supplied by annotation instead, and mutating any constructor's prefix fails the build.
127
+
128
+ `unsafeId` in `types/ids/brand.ts` is the only unchecked way to produce one, and it is not exported from the package barrel.
129
+
130
+ - 7015eee: A run's audit trail is now durable and effectively mandatory: a `RunStore` that does not implement it will make every run throw.
131
+
132
+ `RunStore` gains two methods, `appendAuditEvent`/`readAuditEvents` — declared OPTIONAL on the interface (an existing custom `RunStore` implementation still compiles unchanged), but `RunPersistence.recordAudit` refuses to run silently without them, and this release wires `recordAudit` into the terminal path of **every** run: on completion, on failure, on a verification-gate denial, and on a guardrail block. A host with a custom `RunStore` that omits the two new methods will find every run throwing where it used to complete successfully — a change reachable at runtime even though nothing fails to compile, which is why this is major rather than minor.
133
+
134
+ **If you provide your own `RunStore`** to `RunPersistence`, `query`, or `drainQuery`: implement `appendAuditEvent(event)` and `readAuditEvents()` before upgrading, or every run against that store will now throw at the point it used to settle. The built-in `RunDiskStore` (a new `audit.jsonl`, alongside `transcript.jsonl`) and `InMemoryRunStore` both implement them already and need no host-side change if you use either unmodified.
135
+
136
+ `types/run/audit.ts` adds `AuditEvent` (who, what, when, outcome, cost — `cost` is non-optional) and `AuditOutcome` (`'success' | 'failure' | 'refused'`). A permission denial (the verification gate) and a guardrail block each now produce a durable `AuditEvent` with `outcome: 'refused'`, where before neither produced any durable record at all. A run's own completion or failure also records a terminal entry, and the new `replayRun` reconstructs a completed run's cost and status from the trail alone — the append-only trail is authoritative; `Run.costInfo`/`Run.status` are a derived summary cache.
137
+
138
+ An audit write is never level-filtered or sampled, and a write failure fails the operation being recorded — the opposite of a log sink failure, which `createLogger` already swallows and counts. At most one operational log record (`namzu.audit.written`, `info`) is emitted per audit write, carrying a pointer (`namzu.audit.event_id`, `namzu.audit.seq`) and never a copy of the event's own content.
139
+
140
+ - 320322d: The `bash` builtin no longer hands a command the credential-shaped half of the
141
+ host environment.
142
+
143
+ **What changed.** On the non-sandboxed path the tool spawned with
144
+ `{ ...process.env, ...context.env }`, so the model's command inherited every
145
+ variable the Namzu process held — including the ones Namzu reads its own
146
+ provider credentials from. A command that prints its environment (`env`,
147
+ `printenv`, a Makefile echoing its config, a build script dumping state on
148
+ failure) returned those keys as tool output, and tool output is appended to the
149
+ durable transcript, persisted by the session store, and re-sent to the model
150
+ provider as history on every later turn of the run. The sandboxed path was
151
+ never affected — it passed `context.env` alone — so this was specifically the
152
+ default configuration's problem.
153
+
154
+ The inherited half is now filtered: variables whose names look like credentials
155
+ (`*KEY*`, `*SECRET*`, `*TOKEN*`, `*PASSWORD*`, `*CREDENTIAL*`, `*PRIVATE*`,
156
+ `*COOKIE*`, `*SIGNATURE*`, and a short exact list for the shapes no pattern
157
+ catches, such as `GOOGLE_APPLICATION_CREDENTIALS` and `KUBECONFIG`) are dropped
158
+ before the spawn. When a command fails, the names of the withheld variables —
159
+ names only, never values — are appended to its output so an authentication
160
+ error points somewhere.
161
+
162
+ **What a caller does to keep the old behaviour for a specific variable.** Pass
163
+ it explicitly. `RunConfig.env` flows to `ToolContext.env`, which is applied
164
+ after the scrub and is not filtered: a host that means a command to have a
165
+ credential names it and it arrives. The asymmetry is the design — inheritance
166
+ is implicit and nobody chose it, an explicit entry is a decision someone made.
167
+ There is no flag to restore blanket inheritance.
168
+
169
+ **What this is not.** A denylist on key names is not a boundary. It cannot see
170
+ a secret whose name does not look like one — a password in a `DATABASE_URL`
171
+ userinfo, a pre-signed URL in `ARTIFACT_URL`. The boundary is the sandbox,
172
+ where the inherited set is a seven-key allowlist. The host path takes the
173
+ weaker control deliberately, because the same agent is expected to run
174
+ `pnpm test`, `make` and `docker build`, and an allowlist there would withhold
175
+ most of what a build needs.
176
+
177
+ - ec15971: Name log records with `eventName`, wire the filesystem migration sink to a logger, and remove the config field nothing ever read
178
+
179
+ **`LogRecord` gains an optional `eventName`.** A call site names a record by setting the reserved `'namzu.event.name'` attribute on the `data` it already passes to `debug`/`info`/`warn`/`error`; `createLogger` promotes that one attribute onto `record.eventName` and deletes it from `attributes` so the name never appears twice. `Logger` itself is unchanged — no new method — because it is in INPUT position on the public surface (`logger?: Logger` on `RunConfig` and tool config) and a new method would break every host's existing implementation.
180
+
181
+ `packages/sdk/src/constants/telemetry/index.ts` gains `BOOT_EVENT_NAMES` and `BootEventName`: the closed vocabulary of `eventName`s the boot narrative uses — `namzu.boot.start`, `namzu.config.resolved`, `namzu.sandbox.resolved`, `namzu.provider.resolved`, `namzu.capability.detected`, `namzu.capability.broken`, `namzu.telemetry.status`, `namzu.migration.completed`, `namzu.discovery.completed`, `namzu.boot.refused`, `namzu.boot.ready`.
182
+
183
+ **`loggingMigrationSink(log)`** (new export, `session/migration`) turns the migration facts `DefaultFilesystemMigrator` already computes — `kind`, `migratedThreads`, `markerPath`, `at` — into a `namzu.migration.completed` log record instead of discarding them. `query()` now builds its migrator with this sink, so a real run over a legacy `.namzu` layout logs once at `info`; the `already_migrated` and `noop_no_legacy` outcomes log once at `debug`, read directly off `ensureMigrated`'s resolved result rather than by widening `FilesystemMigrationEvent` (unchanged: still exactly `{ type: 'filesystem.migrated'; result: FilesystemMigrationResult }`). `ensureMigrated`'s own default parameter is untouched — still `new DefaultFilesystemMigrator(NOOP_FILESYSTEM_MIGRATION_SINK)` — so a caller that reaches it any other way keeps today's silent behaviour.
184
+
185
+ **Breaking: `RunContextConfig.migrationSink` is removed.** It had no producer and no reader anywhere in the workspace: `RunContextFactory.build` never touched migration at all — migration runs entirely through `ensureMigrated`, called separately, before `build`, and nothing threaded this field to it. There is no working code migrating off it, because nothing ever read it. Per `docs/conventions/declared-but-undriven.md` and the SemVer policy in `AGENTS.md`, a provably dead field — no producer, no reader, no runtime effect — may be removed straight to major rather than carried through a deprecation cycle with nothing on the other side of it. A caller passing `migrationSink` in a `RunContextConfig` object literal will now fail to compile with an excess-property error; nothing at runtime ever depended on the value, so there is no behavior to migrate away from. Its sibling `filesystemMigrator` has the identical shape (declared, unread) and is deliberately left in place — this change touches only the field the audit named; `filesystemMigrator` is flagged in source as a follow-up.
186
+
187
+ - a093e22: Topic ids now begin `top_` instead of `thd_`. From this release `thd_` means only the pre-0.2.0 top-level container that `session/migration/id-prefix.ts` and `session/migration/filesystem.ts` already coerce to `prj_legacy_*` — the Topic layer's own id no longer shares that prefix, closing the ambiguity where two unrelated things wore one prefix and only a path depth told them apart.
188
+
189
+ **What breaks, and what to do:**
190
+
191
+ - **A minted topic id is now `top_*`.** `generateTopicId()` returns `top_…`; the `TopicId` type is `` `top_${string}` ``. Code that pattern-matches `thd_` on a live topic id, or that pins a literal, needs updating. Code that pattern-matches `thd_` on the _legacy container_ is unaffected and should stay.
192
+ - **`acceptLegacyThreadId` → `acceptLegacyContainerId`** and **`rejectLegacyPrefix` → `rejectLegacyContainerPrefix`.** Behaviour is identical (`acceptLegacyContainerId` also takes a new optional third `windowOpen` argument, defaulting to the existing `WINDOW_OPEN`). The old names remain as `@deprecated` aliases — your code still compiles and warns. Renamed because "Thread" stopped describing what these accept: the pre-0.2.0 container, not the Topic layer.
193
+
194
+ **Nothing is removed in this release.** `ThreadId`, `ThreadManager`, `InMemoryThreadStore`, `generateThreadId`, `acceptLegacyThreadId` and `rejectLegacyPrefix` are all still exported and all now carry `@deprecated`. Removal is a later major.
195
+
196
+ That is deliberate, and it corrects a mistake this change was originally planned to make. The rename of Thread→Topic marked those names deprecated in source, but that work has never been published: the registry is still on 27.1.0, and its changeset is still unconsumed. So on every version a consumer can actually install, `ThreadManager` is not a deprecated alias — it is the _only_ name, and ordinary code uses it. Deleting it here would have moved a consumer from "works, no warning" straight to "gone", which is a rename with no alias wearing a major's clothes. This release is the first one that can carry the warning; the next major may remove them.
197
+
198
+ Note that `ThreadId` now resolves to `` `top_${string}` `` rather than `` `thd_${string}` ``, and `generateThreadId` mints `top_`. An alias that kept the old prefix would hand two different id spaces to one program depending on which name a file happened to import.
199
+
200
+ **Existing records migrate on first read; no operator action.** A `session.json` written with `topicId: "thd_x"` is rewritten to `topicId: "top_x"` when `DiskSessionStore` reads it, and durably on the next write-back, via a new `session-store` schema step (2→3) chained after the existing `threadId`→`topicId` field-rename step for any record still at v1. A serialized `RunState` snapshot migrates the same way through `parseRunState` (`RUN_STATE_VERSION` 2→3).
201
+
202
+ **No topic-directory rewriter is included, and none is owed.** There is no disk-backed `TopicStore` — `store/topic/memory.ts` is the only implementation — so no `.namzu/…/threads/<thd_x>/` directory has ever been written by a shipped build. The only on-disk artifact naming a topic is the denormalized `topicId` field covered above.
203
+
204
+ - fad5da4: Removed the exported type `SessionMetadata`. It was an alias of `RunStateMetadata` with no producer, no reader and no runtime effect anywhere in the workspace — `grep` found exactly two hits, the declaration and its own entry in the public-surface baseline.
205
+
206
+ If you referenced it, use `RunStateMetadata`, which is what it always resolved to.
207
+
208
+ It goes straight to `major` without a deprecation release because there is nothing to migrate: a deprecation window exists so working code has a version where it still compiles and warns, and no working code can be built against a type that describes a shape nothing produces. It is removed rather than kept because the name was actively misleading — a reader looking for the fields that describe a Session (`topicId`, `currentActor`, `previousActors`, `ownerVersion`, all of which live on the Session entity) found this export and was handed a run's metadata instead. No replacement is introduced: nothing in the tree reserves the phrase for a distinct shape, so a stand-in would be a new undriven name filling an export slot.
209
+
210
+ - 9bce045: The denormalized `threadId` field is renamed to `topicId` everywhere it appears
211
+ on an exported shape, and `SessionStore.listSessions` is renamed to
212
+ `listSessionsByTopic`. NZ-TOPIC-01 (a previous minor) renamed the _layer_ to
213
+ Topic and left this field as the one place the retired word still surfaced on
214
+ every shape a consumer types against; this is that rename landing.
215
+
216
+ Mechanical edits for every consumer:
217
+
218
+ - `session.threadId` → `session.topicId` (same rename on `RunState`,
219
+ `AgentTaskContext`, `BaseAgentConfig`, `CreateSessionParams`,
220
+ `HandoffAssignment`, `RunPersistenceConfig`, `RunContextConfig`/`RunContext`,
221
+ `QueryParams`, `RunStateScope`, `AgentIdentity`, and the CLI's
222
+ `CliSessions`/`RunScope`)
223
+ - `store.createSession({ threadId, ... })` → `store.createSession({ topicId, ... })`
224
+ - `store.listSessions(id, tenantId)` → `store.listSessionsByTopic(id, tenantId)`
225
+
226
+ Not touched: the `thd_` id prefix, `ThreadId`/`generateThreadId`/
227
+ `ThreadManager`/`InMemoryThreadStore` (still `@deprecated` aliases from
228
+ NZ-TOPIC-01), and the `Thread*`-named error classes in `session/errors.ts`
229
+ (`ThreadClosedError`, `ThreadNotEmptyError`, `StaleThreadError`) — their
230
+ `details.threadId` field keeps its name too. Renaming those is a separate,
231
+ later change with its own deprecation window; this one is the FK field only.
232
+
233
+ No alias ships alongside `topicId` — `SessionStore` is an interface hosts
234
+ implement, and a required method or field cannot be added behind a deprecated
235
+ twin without every implementor already supplying it. NZ-TOPIC-01 already
236
+ carried one minor of warning for the vocabulary; this is the field itself
237
+ moving, and it has to move all at once.
238
+
239
+ **Records already on disk migrate on first read, no operator action.**
240
+ `session.json` bumps the shared `session-store` schema from v1 to v2; a
241
+ record written by any older release loads exactly as it did before and comes
242
+ back with `topicId` set from its `threadId`, both in-memory immediately and
243
+ (after the next write to that record) on disk. `project.json`,
244
+ `subsession.json`, `summary.json`, and `messages.jsonl` lines never carried
245
+ the field and the migration step leaves them untouched — verified directly,
246
+ not just by inspection: a naive unconditional version of this migration would
247
+ stamp a stray `topicId: undefined` onto every one of them, and that is
248
+ exactly what the new migration unit test rejects.
249
+
250
+ A `RunState` snapshot a host serialized under `RUN_STATE_VERSION: 1` is
251
+ coerced the same way by `parseRunState`. A snapshot written under the new
252
+ `RUN_STATE_VERSION: 2` and read by an SDK still on version 1 is refused with
253
+ `RunStateVersionError`, not partially restored — unchanged behavior, now
254
+ exercised against this specific case.
255
+
256
+ - 9d6c482: `ModelInfo.contextWindow` and `ModelInfo.maxOutputTokens` are now optional. Four drivers filled them with `0` where the vendor listing carries no value, and they omit the field instead.
257
+
258
+ Zero is not a window. It is "I do not know" written as a number, and it reaches a consumer as a measurement of a model that can hold nothing: divide by it and get `Infinity`, compare against it and conclude every prompt is too long. Absent says the same thing honestly, and lets a consumer fall back to its own table instead of trusting a value that was never known.
259
+
260
+ **What breaks:** code reading `model.contextWindow` as a `number` must handle `undefined`. That is the point — the value was already absent in fact, and the type was asserting otherwise. Values that are genuinely known (the offline catalogues, and OpenRouter's real `context_length` mapping) are unchanged.
261
+
262
+ ### Minor Changes
263
+
264
+ - 9914794: New optional package `@namzu/lsp`: language-server-backed code navigation, so an agent asked for the call sites of a function gets symbol resolution rather than regex matches.
265
+
266
+ The whole navigation surface a namzu agent had was `grep` and `glob`. Ask for every call site of `computeTotal` and you get the comment that mentions it, the string literal that names it, and the unrelated same-named function in another scope — and you **miss** the call site that arrives through a re-export or a destructure, which is exactly the one a rename has to get right.
267
+
268
+ `StdioCodeNavigationProvider` drives one language server over its stdin and stdout: `Content-Length` framing (not JSON lines — a response carrying source text contains newlines), the `initialize`/`shutdown` handshake, request correlation, `textDocument/definition` and `textDocument/references`.
269
+
270
+ **Three answers, not two.** `unsupported` means the server does not implement the operation, so a caller can fall back to `grep` and _say_ the answer is textual; `failed` means something broke and the answer is unknown. Neither is `{ kind: 'locations', locations: [] }`, which means "I looked, and there are none" — the answer a deletion depends on. A provider that answered a missing binary with an empty list would tell an agent a symbol has no callers, and the agent would delete it. So a server that never completes `initialize` produces `failed` naming the binary, within a bounded startup timeout, and the failure is remembered rather than respawning a process per call.
271
+
272
+ In `@namzu/sdk`: an `lsp` builtin, `CodeNavigationProvider` on `ToolContext` the way `sandbox` already arrives, and `getCodeNavigationTools(provider)` which returns **an empty array when there is no provider**. The tool is not registered at all in a run that cannot use it — one that is always present and always answers "unavailable" costs a decision on every turn to say nothing, and teaches a model a capability exists when it does not.
273
+
274
+ Every path is contained through `resolveWithinReal` before it reaches the server, the same containment `read` and `grep` use. A language server indexes a workspace and will answer about anything it is handed; the boundary is the tool's job.
275
+
276
+ `dispose()` sends the shutdown handshake before killing, so a server holding a lock file or mid-write on an index gets to finish, and falls back to `SIGKILL` on a bounded timeout so one that ignores `exit` cannot keep the run alive.
277
+
278
+ - 3939dc9: A cancellation can now say where it came from. New `CancelCause` (`'user' | 'parent' | 'budget' | 'hook'`), the `RunCancelled` abort reason that carries one, and `cancelCauseOf(reason)` to read it back. `run_completed` and `agent_canceled` carry `cancelCause` when one was recorded.
279
+
280
+ `stopReason: 'cancelled'` said a run was cancelled and nothing else, and the cases behind it want different responses: an operator pressing cancel is not a defect, while a parent abandoning its children is a fact about the parent and sends a reader looking for a problem the child does not have.
281
+
282
+ The information was not being discarded — it was never carried. `AbstractAgent.cancel()` aborted with no argument at all, and `AgentManager` aborted a child with the bare string `'canceled'`, which `abortReasonText` suppresses _by name_ (its docblock cites that call site, because rendering it would print "was cancelled: canceled"). Both paths reached the run loop indistinguishable.
283
+
284
+ `AgentManager.cancelAll` defaults to `'parent'`, because that call site _is_ a parent abandoning its children. `AbstractAgent.cancel(cause?)` has no default for the opposite reason: its caller could be anyone, and defaulting would attribute every unlabelled cancellation to a person who pressed nothing. An unattributed cancellation reports `undefined`, which is a real answer.
285
+
286
+ `abortReasonText` suppresses `RunCancelled` too. The cause is machine-readable and must not become prose in the run's error text — that is the noise the function already existed to prevent.
287
+
288
+ - f05a0f1: New exported type `SubSessionDelegationStatus` — `'pending' | 'active' | 'idle' | 'failed' | 'archived'`, the five values the kernel actually writes to a sub-session. `SubSessionStatus` remains exported as a `@deprecated` alias of the wider eleven-member union; your code still compiles and warns. Removal, and the six extra members with it, is a later major.
289
+
290
+ A `SubSession` is the EDGE from a parent to a child. The child is an ordinary `Session` with its own `SessionStatus`, and the two unions shared `active`, `idle` and `archived` — plus `awaiting_merge`, which both declared. So "is this active" had two answers one import apart and nothing said which record to ask. `SubSession.status` now documents that it describes the delegation: whether the parent still has a live handoff, not whether the child is working.
291
+
292
+ Six of the eleven members had no writer anywhere in the workspace. Two of those (`merged`, `merge_rejected`) did have a reader: they sat in the archival manager's eligible set, matching values that could not occur. Those two stay archivable — `updateSubSession` takes a whole `SubSession`, so a host may have persisted one while the wide union permitted it, and dropping them would leave exactly those records permanently un-archivable.
293
+
294
+ - f12284a: New `defineProviderDriverConformance` at `@namzu/sdk/testing`: the `LLMProvider` contract as a suite a driver package runs against itself. All seven in-tree drivers now run it, and a test fails if an eighth package appears without one.
295
+
296
+ Seven packages implemented `LLMProvider` and there was nowhere to write a rule binding all of them. Each carried a hand-written error-taxonomy test covering the same ground differently, and every provider finding in the recent audit was a behaviour present in exactly one driver and absent from the other six — which is what a contract living in seven copies of a test produces.
297
+
298
+ It takes `describe`/`it`/`expect` as arguments, so the SDK gains no test dependency from publishing it and a host on another runner can still run it. That also buys the property separating a contract from a list of opinions: a caller can pass _recording_ functions and run the whole suite as ordinary code, which is how a deliberately wrong driver is shown to fail it.
299
+
300
+ Seeded only with rules that pass for every driver today. A suite that ships red is a suite somebody switches off in its first week; the four known gaps each add a rule here in the commit that closes them.
301
+
302
+ **`@namzu/sdk/testing` now resolves to a barrel** rather than straight at the checkpoint-store file. Every existing import keeps working — `defineCheckpointStoreConformance` and its types are re-exported unchanged, and a test fails if the barrel drops them.
303
+
304
+ - 19a72ff: The kernel now notices when a model issues the identical tool call over and over, and says so on the next `tool_result`. A mild notice at the third repeat, escalated wording at the fifth, each said once. `repeatCallAdvisory: false` on `query()`/`drainQuery()` opts out.
305
+
306
+ Nothing observed cross-call repetition before this. The guardrails screen calls in isolation — input at run start, output at run end, one result at a time — so a model re-running a failing command or re-applying a diff that does not apply got no correction from anything in the kernel. The only lever was an operator-configured iteration checkpoint, which fires on a count regardless of whether anything is repeating and needs a human at the other end.
307
+
308
+ **It advises and never denies**, deliberately. Polling for a build to finish is the same call by design, and a tracker that refused would break that case to fix a different one. What the model lacks is not permission but the observation, which it cannot make about itself: each turn it sees a history, not a count.
309
+
310
+ "Identical" is decided by the key `ToolGrantSet` already uses, so the same call means one thing across the runtime — arguments differing only in object key order are the same call. The tracker is run-scoped, like the grant set: a count carried into a later run is a claim about work nobody repeated.
311
+
312
+ - 5136fbd: The agent-client bridge can now ask a human, read the editor's unsaved buffers, and resume a session. NZ-PEER-07 refused any session whose client could not answer a permission request, which was honest and left the bridge unusable for the case it exists for.
313
+
314
+ **The direction the bridge did not have.** A notification is fire-and-forget; a permission prompt is a question the run cannot proceed past. The server now issues JSON-RPC _requests_ — `session/request_permission`, `fs/read_text_file`, `fs/write_text_file` — parks the promise by id, and resolves it when the client's response frame arrives. A response frame used to be ignored, which was right when nothing was ever out on the wire and would now leave a run parked with nobody coming.
315
+
316
+ **Three ways the permission exchange fails silently, each closed and each mutation-checked:**
317
+
318
+ - Auto-approving instead of asking. `toResumeDecision` maps the outcome to the kernel's own `HITLResumeDecision`, and a denial becomes `reject_tools` with the client's feedback — a `continue` there would run the calls the human just refused. A bare denial gets a default sentence, because an empty `reject_tools` feedback reads to the model as a tool that failed for no reason and it retries.
319
+ - An "approve all" that never takes. `approve_tools` with nothing remembered is indistinguishable from a plain approve, so `approve_all` carries the grant keys and a plain approve carries none — consent is not transferable.
320
+ - An "approve all" that leaks. The latch lives on the SESSION record: a second session from the same process asks again. Hoisting it to the server, or to a module-level variable, would make one person's "stop asking me" cover the next session this process serves — possibly a different repository, editor window, or human.
321
+
322
+ An answer the agent cannot parse is treated as a refusal, never as consent.
323
+
324
+ **`clientBackedSandbox` makes the editor's buffers the filesystem.** A user with unsaved changes had the agent read disk, see a version nobody is looking at, and patch _that_. A client declaring the `fs` capability answers reads and writes instead. It is a decorator over the existing `Sandbox` — a client-backed object implementing only the file methods would take `bash` away from a session that had it — and it is a `Proxy` rather than a spread, so a member added to `Sandbox` later still reaches the real one. A failed client read rejects rather than falling back to disk: stale text is the exact thing the capability exists to stop.
325
+
326
+ **`session/load` resumes.** The prior turns come from the gateway's session store, never from the bridge, and the resumed session answers with the SAME id — a client that asked to resume `ses_x` and got `ses_y` back has to rewrite everything keyed by the old one. A gateway with no store refuses rather than returning an empty history, which a client cannot tell apart from a session that really had no turns. Resuming carries the same permission requirement as creating, because a refusal on `session/new` that `session/load` walks around is not a refusal.
327
+
328
+ - 966c6de: Two new exported interfaces, `ProbeObservation` (`setLogger`, `on`, `onAny`, `dispatch`) and `ProbeEnforcement` (`veto`, `queryVeto`). `ProbeRegistry` implements both and is unchanged, so nothing a host builds or passes changes — this narrows what a _signature_ can ask for.
329
+
330
+ The SDK's own barrel introduced the module as "typed observation over AgentBus + RunEvent stream". That is true of four of its six methods. A registered veto handler denies a tool call, and the executor turns that denial into a failed `tool_result`: enforcement, and the third of the three gates on a tool call, sitting behind a name that said telemetry. The comment is corrected too.
331
+
332
+ There was also no way to ask for less. `ProbeRegistry` was the only export, so a consumer that wanted to watch had to accept the power to refuse. Inside the SDK the split is now load-bearing: the provider wrapper, the vault wrapper and the run event emitter take `ProbeObservation` and cannot veto; the tool executor takes `ProbeEnforcement`.
333
+
334
+ - eff96ac: `Project` gains an optional `rootPath`: the canonical directory its work happens in. `CreateProjectParams` accepts one, `SessionStore` gains an optional `findProjectByRootPath(rootPath, tenantId)`, and `ProjectRootPathTakenError` is exported.
335
+
336
+ A host building a project switcher had nothing to bind a directory on disk to a durable cross-session record. No new noun was minted for this — `Project` is already the durable top-level container, with an id, a tenant, a status and a CAS counter, and it simply carried no path.
337
+
338
+ **Canonicalized through `realpath` before storage.** A path stored as typed makes `/tmp/p`, `/tmp/p/` and a symlink to it three records for one directory, and every uniqueness check passes while doing it. The lookup canonicalizes too, so a caller may pass whatever they have.
339
+
340
+ **A second project on the same canonical directory is refused, not deduplicated.** Returning the existing one looks friendlier and silently discards the `name` and `config` the caller passed — they asked to create something, and getting a different thing back with their arguments dropped is worse than an error. The error carries the existing `ProjectId`.
341
+
342
+ The lookup is tenant-scoped, with the tenant _in_ the index key rather than filtered afterwards: two tenants may bind projects to the same path on one machine, and a path-only key would hand one of them the other's project.
343
+
344
+ `findProjectByRootPath` is optional. `SessionStore` is implemented by hosts, and a required method stops them compiling for a capability they never asked for.
345
+
346
+ - 70f8d75: An agent-client protocol bridge over stdio, and `namzu acp` to drive it. An editor extension or a CI orchestrator could previously do two things: shell out to the CLI and scrape stdout, or embed this SDK in its own process. This is the third.
347
+
348
+ **The command ships in the same change as the bridge, and that is the point.** `MCPServer` and `ServerStdioTransport` are both exported from this package, and nothing in the tree has ever constructed an `MCPServer` — a complete protocol server with no driver, which reads as a supported feature and is not one. A subprocess test spawns the real binary and completes a handshake over a real pipe, so removing the registration fails a test rather than quietly repeating that shape.
349
+
350
+ New: `ACPServer`, `toAcpSessionUpdate`, `toAcpStopReason`, the `Acp*` wire types, and `ACP_METHODS` / `ACP_PROTOCOL_VERSION` / `ACP_ERROR_CODES` / `ACP_PERMISSION_CAPABILITY`. Scope is the session core — initialize and capability exchange, session creation, prompting with streamed updates, and cancellation. No new dependency: it runs on the `ServerStdioTransport` this package already had.
351
+
352
+ **The method set cannot drift from the pinned version.** `ACP_METHODS` and the server's handler map are authored independently and compared in both directions by a test: a handler nobody advertises fails, and an advertised method with no handler fails. Deriving one from the other would have made that test a tautology.
353
+
354
+ **A session is REFUSED when the client declared no permission capability**, naming the capability. Approval routing lands separately; until it does, a session that cannot ask a human anything and runs every tool regardless is not a degraded version of asking — it is the opposite of it, arrived at by omission.
355
+
356
+ **Tool calls are rendered by the tool, never by the bridge.** Updates carry a `ToolCallView` from `createToolPresenter`, and a test asserts no module here contains a tool-name comparison — a front end that switched on `'edit'` could never give a diff to a tool it had not heard of. The client-visible command list is `HostCommandRegistry.describe()` verbatim, asserted by registering a command the bridge has never heard of and expecting it to appear.
357
+
358
+ An unknown method answers `-32601` and the connection stays open; a malformed frame is survived. Both are asserted against the spawned binary, as is the one that matters most for stdio: **nothing but protocol reaches stdout**, with info-level logging on.
359
+
360
+ `namzu acp` builds its session lazily, at the first prompt. `initialize` and `session/new` are how a client discovers what this agent is and what it requires, and neither needs a model — building the session up front made a namzu with no configured credential answer a connection attempt by exiting, so an editor saw a pipe that closed with the reason on a stderr nobody was reading.
361
+
362
+ - b947794: New `runConfig.sandbox.workspace`: `'ephemeral'` (default, unchanged behaviour) or `'working-directory'`. The second roots the sandbox at the run's own `workingDirectory`, so a sandboxed `bash` acts on the project the agent was asked about instead of on an empty temp directory.
363
+
364
+ That was the case the sandbox was wanted for and could not do. `SandboxCreateConfig.workingDirectory` existed and the local provider honoured it — and the kernel never set it, so anyone configuring a sandbox through `runConfig.sandbox` got a temp directory regardless of what the run was working on.
365
+
366
+ The default stays `'ephemeral'`. Changing it would be a major and would point every already-configured sandboxed run at real files.
367
+
368
+ `'working-directory'` on a run with no `workingDirectory` is **refused before the sandbox is created**, naming the config key. It does not fall back to ephemeral, and it does not reach for `process.cwd()`: that would confine whatever directory the host process happens to be in, which is not the tree you named, and telling a caller their files are protected by something not looking at them is worse than an error.
369
+
370
+ - 5d23bf4: A delegated tool scope now survives further delegation, and `ActorRef`'s
371
+ chain finally has a reader.
372
+
373
+ A child scoped `toolScope: { deny: ['bash'] }` could spawn a grandchild
374
+ naming no scope at all, and the grandchild got `bash` back. Every
375
+ meaningful confinement is more than one delegation deep, so a restriction
376
+ a descendant could shed by delegating was not a restriction. The effective
377
+ scope for a spawn is now the union of every deny along its chain plus its
378
+ own: a descendant may narrow further and can never widen. The resolved
379
+ union is recorded on the child's spawn record, so what a child was granted
380
+ can be read rather than inferred from whether a call was refused.
381
+
382
+ New exports `isDescendantOfActor`, `actorChain` and `MAX_ACTOR_CHAIN_DEPTH`
383
+ walk the `parentActor` chain that `ActorRef` has carried since the 0.2.0
384
+ design and that nothing traversed — its own docblock says permission audit
385
+ events walk it, and no code did. Deliberately not a parallel parent
386
+ registry: the chain is already persisted on the actor, and a second
387
+ structure would give the tree two answers that can disagree, with the one a
388
+ check reads being the one not written to disk.
389
+
390
+ Identity for an agent actor is its whole lineage, not its `agentId`. An
391
+ `ActorRef` carries no instance id, so a supervisor spawning the same worker
392
+ twice produces two field-identical links; matching on the id alone would
393
+ let an actor assembled under a different user claim containment by name.
394
+ The walk is depth-bounded, so a malformed or cyclic chain returns `false`
395
+ instead of hanging a check somebody is holding a lock across.
396
+
397
+ - 5f5becd: Every log record now names the module that emitted it.
398
+
399
+ 40 call sites across 36 SDK modules bound `component: '<ClassName>'` on their
400
+ `child()` logger. `component` is deliberately inert — it is not an alias for the
401
+ reserved scope key — so those records carried the _default_ `scope.name` and a
402
+ redundant attribute instead. `AgentBus`, `SkillRegistry`, `DiskTaskStore` and 33
403
+ others were, in effect, unattributed.
404
+
405
+ They now bind `SCOPE_ATTRIBUTE`, and the value is the module path
406
+ (`bus`, `skills/registry`, `store/task/disk`) rather than the class name — the
407
+ shape `ManagedRegistry` already used. A scope that varied per instance would not
408
+ be a scope.
409
+
410
+ What a `LogSink` sees change:
411
+
412
+ - `record.scope.name` is a module path instead of the root scope's name.
413
+ - `attributes.component` is gone. A host filtering on it should filter on
414
+ `record.scope.name`.
415
+ - Four keys are new where the class name or an id carried information the module
416
+ path does not: `namzu.connector.type` and `namzu.execution.type` (the concrete
417
+ subclass behind `connector/base` and `execution/base`), `namzu.mcp.server.id`
418
+ (the MCP server this process hosts — deliberately not
419
+ `namzu.connector.server.id`, which identifies a _remote_ being dialed), and
420
+ `namzu.sandbox.id`. `runtime/bidi/session.ts`'s bare `runId` binding became
421
+ `namzu.run.id`.
422
+
423
+ `NAMZU` gains those four members, which is why this is a minor rather than a
424
+ patch. `scripts/log-standard.json#unnamespacedBindingCount` moves 40 → 0, so the
425
+ next `component:` binding fails CI rather than joining a budget.
426
+
427
+ - 94842e4: `ServerStdioTransport` is now exported from the package root, along with the MCP tool-policy helpers `applyToolPolicy`, `applyNamePolicy`, `diffTools`, `hasDrift`, `toolsHash` and the types `MCPToolPolicy`, `MCPToolPolicyDecision`, `MCPToolDrift`, `MCPToolDiscoveryOptions`.
428
+
429
+ `MCPServer` was already public and `ServerStdioTransport` is the only transport in the package that can run one — so a consumer could construct an MCP server, register providers on it, and have no supported way to serve it. The policy types were public with no public function to apply them: a shape you could describe and not use.
430
+
431
+ The cause was two lists of the same thing. `connector/index.ts` hand-listed names from the individual `mcp/` modules while `connector/mcp/index.ts` kept its own set, and the two drifted. The connector barrel now sources every MCP name from that one seam, and a test fails if a leaf import is added back.
432
+
433
+ - 9b15964: New `beforeStep` hook on `query()`/`drainQuery()` and `ReactiveAgentConfig`, plus the `StepVeto` type and a `step_refused` stop reason. Returning `{ reason }` stops the run before the next provider call is made.
434
+
435
+ Nothing could refuse a step. `prepareStep` only reshapes one — `activeTools`, `model`, `system`, `temperature` — and cannot reject. `StopCondition` reads `steps`, so it fires after the step it disliked has already run and been paid for. The only remaining path was a durable checkpoint built for human review of tool calls, which pauses the run and waits for a person. None of those is what a host with a live rate limit, a revoked tenant or a spend ceiling has: they need the call not to happen.
436
+
437
+ **A throw fails closed**, deliberately opposite to `prepareStep` beside it. They are different kinds of hook. A broken step-_shaper_ skipped costs a run its per-step tuning and lets nothing unsafe through; a broken step-_refuser_ skipped is a refusal that did not happen, which is the thing it exists to prevent. The thrown message becomes the recorded reason.
438
+
439
+ `StepVeto` is an object rather than a boolean because a bare boolean does not say which polarity means stop, and carries nothing into the run record — leaving an operator with a run that ended and no account of why.
440
+
441
+ - d54fe08: New `withStreamIdleTimeout(provider, { idleTimeoutMs })` — a per-chunk watchdog in the same decorator shape as `withProviderRetry` and `withProviderFallback`, so it composes with both.
442
+
443
+ A stream that opens successfully and then goes quiet trips nothing. Each driver has a whole-_request_ timeout, and a stall does not reach it: the request is fine, the bytes have stopped. One driver had this written inline and defaulted it to off, so no driver re-armed on a stall unless a host set a config key it had no reason to know about. A run in that state is not slow, it is stuck — holding its budget, its claim and its process, and settling never.
444
+
445
+ The failure is classified `network`, which is what `withProviderRetry` and `withProviderFallback` already act on: a stalled stream is retried by the layer above, or the chain moves on. A bespoke classification would reach them as an unknown they treat as fatal.
446
+
447
+ Disabled (`0`, negative, non-finite) returns the provider **unwrapped**, not wrapped and inert — a disabled watchdog racing a promise per chunk costs the hottest path in the runtime a timer and a closure for nothing.
448
+
449
+ - 655cc9d: Code navigation gains `hover` and `symbols`, and routes by file extension so a repository can have more than one language.
450
+
451
+ **`symbols` is the entry point, and its absence made the rest unreachable.** `definition` and `references` both need a line and a character, and an agent starting from a name has neither — so every navigation began with a grep, which is the text path this package exists to replace, reintroduced as a prerequisite. `symbols(query, scope?)` finds a declaration by name with no position at all.
452
+
453
+ `hover(file, line, character)` gives a symbol's resolved type and documentation without opening the file. Its `contents` may be **empty**, and that is a real answer: hovering over whitespace or a comment resolves to nothing, and a caller has to be able to tell that from a server that broke.
454
+
455
+ **Capabilities are READ from the initialize result, never probed.** A server with a workspace index answers `workspace/symbol`; one with only document symbols falls back to `textDocument/documentSymbol`; one declaring neither returns `{ kind: 'unsupported' }` naming both missing capabilities. Sending the request and interpreting whatever error comes back works until a server answers an error for a transient reason, and the fallback then fires for a capability the server has. The `documentSymbol` reply is a tree and is walked — a reader that took only the top level would miss every method, which is most of what a name search is for.
456
+
457
+ **`RoutingCodeNavigationProvider` maps extension to server**, starting one lazily per language on first use and reusing it. A file whose extension maps to nothing gets `{ kind: 'unsupported' }` naming the extension — not a default server, which would send the file to something that cannot read it and answer nothing, which reads as a symbol with no references. A `symbols` call with no scope asks every configured language, and reports `unsupported` rather than an empty list when every server refused, because "nobody looked" is not "the name does not exist".
458
+
459
+ The `lsp` builtin's input is a discriminated union: position is **required** for `definition`/`references`/`hover` and **absent** for `symbols`. Making it unconditionally optional lets a `definition` with no line silently resolve the top of the file; making it unconditionally required forces a `symbols` call to invent two numbers.
460
+
461
+ - 1e996bc: New optional `compactionConfig.keepRecentTokens`. When set, the retained conversational tail is sized by tokens instead of by `keepRecentMessages`. Absent by default, so every existing run keeps the same tail it kept before.
462
+
463
+ `keepRecentMessages` cannot say what a tail costs. Four messages is four short turns, or three short turns and a 200 KB tool result — and in the second case the retained tail alone can approach `resetThreshold`. The pass then completes, reports it did not reach the threshold, leaves the trigger armed, and the next iteration pays another summarization call and busts the prompt-cache prefix again.
464
+
465
+ It replaces only the naive boundary. The existing safe-cut search runs downward from wherever the token walk lands, so a `tool_use` is never separated from its `tool_result` — that guarantee holds by construction rather than by a second check.
466
+
467
+ The tail is floored at one message. A single final message larger than the whole budget is still kept: it is the live turn, and dropping it to satisfy a size preference would delete what the run is answering. The pass reports that it did not reach the reset threshold, which is the honest outcome.
468
+
469
+ - 13b2682: A tool can now say how it should be shown. `ToolDefinition` gains optional `presentCall` and `presentResult`, `defineTool` accepts them, and `createToolPresenter(registry)` is the seam a host resolves through. Three closed view shapes: `generic`, `diff`, `terminal`.
470
+
471
+ Presentation lived in one host as four free functions switching on a lowercased tool _name_ — `name === 'write'` and `name === 'edit'` got a diff, everything else got a truncated string. So a tool that host had never heard of, from an MCP server or a plugin, could not get a diff no matter what it did, and every second host started from the raw arguments and rebuilt the same switch. The tool knows what it is doing; the host knows how its surface renders. Neither knew the other's half.
472
+
473
+ The union is closed deliberately. An open one would let a tool ask for a rendering no host implements — a request that fails silently at the far end.
474
+
475
+ `edit` now builds its own diff, and declines to build one for an _insert_: there is no `before` text, and substituting an empty string renders as "the whole file was added", which is a confident wrong picture. Returning `undefined` means "no opinion" and is distinct from returning a generic view, which asserts that a plain label is right.
476
+
477
+ A presenter that throws yields the generic view and logs one warning naming the tool. It is host-supplied code inside a render path — the same trade a log sink already makes — and silence would make a presenter that never works look like one with no opinion.
478
+
479
+ - be7152b: The A2A bridge reads a peer's card, and dispatches to it as a delegate.
480
+
481
+ The bridge was a one-way door: this kernel served an agent card and answered `message/send`, and could read nobody else's. So the delegate seam had no driven consumer — and a seam with no caller is an untested guess at what a caller needs.
482
+
483
+ New: `fetchAgentCard` and `A2ADelegate`. Register the delegate with `DelegatingTaskScheduler` and a remote peer becomes reachable through the delegation tools with nothing above learning the difference — the last tests assert exactly that, a peer's answer reaching `taskSucceeded` / `taskFailed` correctly through the scheduler.
484
+
485
+ Refusals happen at wiring time, which is the only moment a human is looking: a card that does not parse, a card offering no interface, a peer with no `jsonrpc` interface, and a protocol version this kernel does not implement. The version comparison is on major.minor — A2A is pre-1.0, where the minor carries breaking changes, so matching the full string would refuse a peer over a patch bump.
486
+
487
+ Two client-side subtleties the server half does not have. `input-required` stops the poll: it is not terminal for a _server_, which can receive the input and carry on, but it is terminal for a client with no channel to supply it — polling it is polling a state that cannot change. And a cancel reaches the peer as `tasks/cancel` rather than only aborting our own loop, because aborting the poll leaves the peer working, billed, and holding whatever the task holds.
488
+
489
+ - c2663c2: `ReactiveAgentConfig` gains `steering`, and a host can now hold an
490
+ `AgentHandle` between runs.
491
+
492
+ Steering was declared only on `SupervisorAgentConfig` and forwarded only by
493
+ `SupervisorAgent` — so the archetype most hosts actually run could not be
494
+ steered at all. That is the same defect the file's own comment says it has
495
+ been corrected for twice: a capability the kernel honours in `drainQuery`
496
+ and not on the surface hosts construct is a capability nobody can reach.
497
+
498
+ `createAgentHandle` gives a host two delivery targets with stated lifetimes
499
+ and no silent third state. `steer` reaches the run happening now; it THROWS
500
+ on an idle handle rather than accepting into a queue nothing will read, and
501
+ points at the alternative. Quietly rerouting would be a host asking to
502
+ redirect what is running and getting a message delivered minutes later to a
503
+ different run — worse than an error, because nothing says it happened.
504
+
505
+ `queueForNextRun` persists onto the Topic's state record and is consumed by
506
+ the next run on that topic: prepended to its FIRST request rather than
507
+ arriving a turn late, and cleared in the same compare-and-set write that
508
+ reads it. A queue read and cleared separately re-delivers on a crash
509
+ between the two, and "start with this" arriving twice is a different
510
+ instruction from the one that was left.
511
+
512
+ The handle's status type is `AgentHandleStatus`, not `AgentStatus` — that
513
+ name belongs to a deprecated alias mid-removal, and reusing it would
514
+ silently change what a consumer's type MEANS rather than failing their
515
+ build, which is the one outcome a deprecation window exists to avoid.
516
+
517
+ `status` reads a live predicate rather than a stored flag, because a stored
518
+ one is only as current as whoever remembered to update it.
519
+
520
+ - af47721: Tell the model when the approval policy changes, once, in the slot it already reads.
521
+
522
+ The model plans around how closely it is being watched. A run that silently stops asking a human leaves it batching destructive calls it expects to be reviewed; one that silently starts leaves it waiting on permission nobody is left to give. Neither is visible to it.
523
+
524
+ `RunApprovalPolicy` gains `takeUnannouncedChange()` — **read-and-clear**, so the notice is said exactly once. A repeated notice is worse than none: the second copy reads as a second change, and the model will believe supervision moved again.
525
+
526
+ The notice rides the ephemeral trailing system message that a step's guidance and skills already use. It applies to what happens next, not to the run's history, so pushing it onto the message log would accumulate one stale instruction per iteration.
527
+
528
+ Consecutive changes collapse: A→B→C is announced as A→C, keeping the ORIGINAL `from`. Three swaps between two model calls are one fact by the time the model can act on one, and the true statement is about what it planned under versus what it is under now — not the history in between.
529
+
530
+ - ee7856e: The approval policy is a run-scoped, switchable, durably-logged value instead of a closure captured at `query()` start.
531
+
532
+ `ResumeHandler` was read exactly once, when the run began, and from nowhere a host could reach afterwards. So changing from "ask me about every write" to "go ahead, I'm stepping out" meant ending the run — discarding the in-flight step and the context that step was built from, to change one setting. That is the defect `permissionMode` had before it became a box the executor reads through, and this follows the same shape.
533
+
534
+ New: `ApprovalPolicy` (a named handler), `RunApprovalPolicy` (the box), the `onApprovalPolicy` query parameter that hands a host the box, and the `approval_policy_changed` run event — on the SSE wire as `approval_policy.changed`, and deliberately absent from A2A, where who supervises this host is not the peer's business.
535
+
536
+ The name is not decoration. A log entry that can only print `[Function (anonymous)]` cannot answer "who approved that, and under what rule" months later. An unattended run is named `auto-approve` by identity against the default handler rather than by presence — `resumeHandler` is required internally, so "is it set" is always yes and would name every run `host`, including the ones approving everything unattended.
537
+
538
+ A change is recorded **before** it takes effect: swap first and the log reads as approvals that precede the decision permitting them. `reason` is required for the same reason — an optional one is absent exactly when it matters, on the change nobody expected.
539
+
540
+ Existing callers are unaffected: omit `onApprovalPolicy` and the policy is set once from `resumeHandler` and never changes, which is what happened before.
541
+
542
+ - 3331493: A message can carry a reference to an attachment instead of its bytes.
543
+
544
+ Every attachment was inline base64 on the message. That is fine for one screenshot and wrong for everything it implies: the bytes are copied into the run's durable transcript, into every checkpoint, into every compaction pass that walks the history, and — because a conversation resends its history — into every subsequent request. A 4 MB PDF attached once is 4 MB in the transcript and 4 MB on the wire per turn for the rest of the run.
545
+
546
+ New: `StoredAttachmentRef` as a third member of `MessageAttachment`, the `AttachmentStore` seam, and `attachmentStore` on `query`. The kernel treats `ref` as **opaque** — this seam says nothing about whether it is a hash, a path or a URL, because the store that minted it is the only thing that can answer. A content-addressed store gets deduplication for free; this interface neither requires nor prevents that.
547
+
548
+ Resolution happens once, where the run is seeded, before the messages reach the run record. Resolving at the provider boundary instead would put refs in the durable transcript, and a run resumed against a store that had since forgotten a ref would fail replaying its own history rather than at the moment somebody asked for the bytes.
549
+
550
+ **Every failure refuses**, and none of the three returns the message unchanged: no store, no such ref, and bytes whose media type is not what the message declared. A message that quietly lost its image is a model answering about a picture it never saw, confidently, with nothing in the transcript saying why. One unresolvable ref refuses the whole conversation rather than resolving what it can.
551
+
552
+ Both provider drivers refuse an unresolved stored attachment rather than sending `data: undefined`. The OpenAI driver reads the real SDK type and the compiler caught it; the Anthropic driver reads through a structural cast and did not, so the stored member is spelled out in its local type — that difference is written at the site.
553
+
554
+ - 83b5f83: An owner-scoped background job registry, and a real background mode for `bash`.
555
+
556
+ `bash`'s schema used to end with "start it in the background and poll, rather than holding the turn open". That sentence was removed rather than honoured, because there was nothing to poll with — and because the shell cannot be trusted to background under the sandbox. On the `linux-namespace` isolation tier the wrapping `sh` is PID 1 of a fresh PID namespace; the kernel destroys a PID namespace when its init exits, so `sh -c "long-thing & echo go"` returns in milliseconds looking like it worked with the work already dead, on the successful path.
557
+
558
+ So the kernel holds the process itself. New: `BackgroundJobRegistry`, `bash`'s `run_in_background`, and a `job` tool that reads, lists and stops what it starts. Both ship in the default builtin set — an id with nothing that reads it is the same unbacked suggestion.
559
+
560
+ Every bound refuses rather than adjusting: the per-owner cap names the limit, and `bash` refuses `run_in_background` outright when the host has provided no registry rather than falling back to `cmd &`. Output retention drops the oldest bytes and **states how many**, because a job whose tail vanished quietly reads as a complete result that happens to be short.
561
+
562
+ Ownership is structural, not a check: the executor binds the registry to the run's id before a tool ever sees it, so there is no argument a tool could pass to reach another run's jobs. `query` kills the run's jobs in its `finally`, on the failed path too — a job that outlives its run is an orphan with nothing left that can name it.
563
+
564
+ `killTree` moves from `sandbox/provider/local.ts` to `process/kill-tree.ts`, unchanged, so both callers share one implementation.
565
+
566
+ Hosts opt in by passing `backgroundJobs` to `query`. Without it, nothing changes.
567
+
568
+ - 30029bd: `prettySink` renders the boot sequence as a readout instead of a wall of
569
+ timestamps.
570
+
571
+ Three changes, each answering a specific half of "the logs tell me nothing
572
+ when the project starts":
573
+
574
+ - **`+Nms` instead of an absolute ISO clock.** Elapsed since the previous
575
+ record on that sink, so the column reads as which phase was slow. The
576
+ state is per sink instance, so two sinks in one process — a file and a
577
+ terminal — each measure their own stream.
578
+ - **A fixed-width scope column, coloured by a stable hash of the label.** A
579
+ dozen module initialisations read as structure rather than scroll, and the
580
+ colour is the same in every process on every machine: the hash is FNV-1a
581
+ over the label with a pinned eight-colour palette, touching no process
582
+ state.
583
+ - **A template per boot event**, so `info` shows the two attributes that
584
+ matter rather than all of them as JSON. The map is total over
585
+ `BootEventName`, so adding an event without deciding how it reads is a
586
+ compile error.
587
+
588
+ Warnings and refusals are marked with a glyph in a fixed column rather than
589
+ a `[WARN]` label, so they are findable by eye.
590
+
591
+ Colour is emitted only when the stream reports `isTTY`; a redirected log
592
+ contains no escape bytes at all. Records from outside the boot vocabulary
593
+ keep the previous line format. Nothing here mutates a record, and
594
+ `jsonLinesSink` produces identical bytes whether or not the renderer is
595
+ installed.
596
+
597
+ - 9b053ba: New run event `compaction_tool_results_cleared`, carrying `clearedCount`, `charsReclaimed`, `reclaimedTokens` and `reliefWasEnough`. It reaches the SSE stream as `compaction.tool_results_cleared`, the run reporter, `transcript.jsonl`, and the CLI's context line. A2A maps it to `null` alongside the other two compaction events: which of this runtime's context-relief strategies fired is a property of how it manages its own window, and a peer modelling a task lifecycle can act on none of them.
598
+
599
+ Clearing oversized tool results is the cheapest and most common context-relief path, and it was the only one that emitted nothing. It edits the conversation irrecoverably — `tool_result` bodies are replaced in place — so a host reading a transcript saw results it no longer had and no record of why, while both summarization outcomes were already on the wire.
600
+
601
+ It fires on **both** branches. `reliefWasEnough: false` means the clear happened, was insufficient, and a summarization followed: the history took two edits in one pass, and a reader who saw only the `compaction_completed` would attribute the whole loss to it.
602
+
603
+ - 44b5c76: `coalesce` and its `CoalesceOptions` are now exported from the package root. It merges consecutive `text_delta` and `tool_input_delta` events inside a sliding window, so a slow consumer — typically an SSE route writing to a browser — writes fewer, larger frames instead of one per token.
604
+
605
+ It was written, tested and reachable by nothing: no in-tree caller, absent from every public entry, its only reader its own test file. Exported rather than deleted because the consumer it was written for is out of process by construction. The kernel emits raw deltas and has no UI and no hosted service, so deciding how often to write to a slow client is the host's policy — only the host knows what is on the other end of its socket. `bridge/sse/` maps an event onto the wire; this decides the rate.
606
+
607
+ The module header now also states what `streaming/` owns: coalescing, and nothing else. SSE mapping is `bridge/sse/`, provider chunk assembly is in the driver packages, and the run event stream is `runtime/query/`.
608
+
609
+ - b01068a: Consolidate the two credential-redaction pattern tables into `constants/secret-patterns.ts`
610
+
611
+ `runtime/query/guardrail-presets.ts` (the output guardrail) and `provider/errors.ts` (vendor-error scrubbing) each carried their own, disagreeing list of credential shapes to redact. They now both import from one leaf module, exported as `OUTPUT_SECRET_PATTERNS` and `LOG_SECRET_PATTERNS`.
612
+
613
+ `secretRedactionGuardrail`'s own matching set is **unchanged** — it keeps the narrow, vendor-prefix-anchored eight patterns it always had, because a false positive on model output rewrites the caller's answer.
614
+
615
+ `provider/errors.ts`'s `redactSecrets`/`vendorDetail` now match the **union** of both tables (previously: a generic key-prefix scan, a bearer-header pattern, and a JSON field-name scan). A `ProviderRequestError.detail` string can now be redacted where it previously was not — for example a Slack-style token, a Google-style API key, a PEM private-key header, or a JWT echoed back in a vendor error body, none of which the old generic scan caught.
616
+
617
+ The redaction marker format also changed, on this call site only: `redactSecrets` used to emit a bare `[redacted]` (or, for the JSON-field case, preserve the field name and quote the placeholder); it now emits `[REDACTED:<label>]` for every match, matching the convention the output guardrail already used. A caller pattern-matching `ProviderRequestError.detail` for the literal string `[redacted]` needs to match `[REDACTED:` instead.
618
+
619
+ No exported identifier was removed or renamed, and no function signature changed.
620
+
621
+ - 940f52b: `CredentialProvider` is a seam a host can implement to say where a
622
+ credential comes from, with `EnvCredentialProvider` shipped in the box.
623
+
624
+ Every LLM-provider credential lookup lived in `@namzu/cli`, which walks its
625
+ own provider registry and reads `process.env` directly. A host embedding the
626
+ SDK alone had no way to plug in an env- or file-backed source short of
627
+ reimplementing `CredentialVault` — a connector-scoped interface that asks a
628
+ different question, holds a whole `AuthConfig` per connector, and has one
629
+ in-process implementation with no notion of writability.
630
+
631
+ `describe()` never carries the value. "Does this exist" is asked in places a
632
+ secret must not travel to — a doctor readout, a picker, a log line — and a
633
+ description that carried one would leak on every one of them while looking
634
+ like metadata.
635
+
636
+ `EnvCredentialProvider` is read-only and says so: `set` and `unset` throw a
637
+ named error pointing at a writable alternative, rather than accepting a
638
+ write and dropping it. A `set` on `process.env` changes one map in one
639
+ process and vanishes with it, while the caller is told it worked.
640
+
641
+ The credential key-name vocabulary moves to `constants/credential-env-keys.ts`,
642
+ a leaf with no imports beside `secret-patterns.ts` — that file matches
643
+ credential VALUES, this one the names they are carried under. The host-bash
644
+ environment scrub and the credential seam now read the same table, and
645
+ `isCredentialEnvKey` is exported so a host with its own provider registry can
646
+ assert its variables are ones the scrub will withhold. A name in one table
647
+ and not the other means a variable the CLI reads an API key from and the
648
+ scrub hands to a shell command.
649
+
650
+ CLI discovery goes through the seam with identical results.
651
+
652
+ - ead7703: A delegate need not be an in-process Namzu agent.
653
+
654
+ Delegation was reachable exactly one way: `TaskScheduler.createTask` with an `agentId` the host's `AgentManager` could resolve. Every delegate was therefore a Namzu agent, in this process, built from this kernel's own definition — so a host with a specialist behind an A2A card, an ACP connection, or any service at all had nowhere to put it short of implementing the whole `TaskScheduler` surface, most of which is bookkeeping the kernel already does.
655
+
656
+ New: the `Delegate` seam — take a prompt, return an outcome, declare whether you can be cancelled or continued — and `DelegatingTaskScheduler`, which presents any set of them as the `TaskScheduler` the delegation tools already speak. An id no delegate claims falls through to the local scheduler untouched.
657
+
658
+ **The mapping onto `TaskHandle` is the load-bearing part.** `taskSucceeded` and `taskFailed` require the gateway state and the run status to agree, because locally they are two independent authorities. A foreign delegate has one word, so it is written onto both — and a cancellation is written as `canceled`/`cancelled`, never as a failure: `SiblingFailurePolicy: 'cancel-siblings'` acts on `taskFailed`, so calling a deliberate stop a failure would tear down every healthy sibling as a consequence of the stop.
659
+
660
+ Capabilities are refused, not degraded. `continueTask` against a delegate that cannot continue throws rather than silently doing nothing — a no-op there has the parent believe it steered a worker that never heard it. A capability claiming a method the object does not implement is refused at registration, and two delegates claiming one id are refused rather than resolved by registration order.
661
+
662
+ The roster is still enforced upstream: the delegation tools check `allowedAgentIds` before an id reaches any scheduler, so registering a delegate does not by itself make it reachable.
663
+
664
+ - e45699e: A delegation can now narrow the child it spawns.
665
+
666
+ `SendMessageOptions` and `CreateTaskOptions` take `toolScope: { deny }` and
667
+ `personaOverride`; `BaseAgentConfig` takes `allowedTools`, `deniedTools` and
668
+ `persona`. A supervisor handing out a read-only subtask could not say so
669
+ before — the child ran with everything its definition granted, so a research
670
+ delegation given to an agent that also holds `write` and `bash` held them
671
+ too.
672
+
673
+ `toolScope` is deny-only on purpose. The delegating side does not know what
674
+ the child has, and enumerating an agent's whole tool set in order to remove
675
+ one from it pins that list against an agent that later gains a tool —
676
+ silently, and in the direction of more access. Denial is therefore
677
+ subtractive: it applies on top of whatever the child would otherwise have,
678
+ composes with a `deniedTools` the agent's own definition set, and a name the
679
+ run never had is a no-op rather than an error.
680
+
681
+ The narrowing is enforced rather than presentational. The denied tool is
682
+ absent from the request AND rejected if the model calls it by name, so this
683
+ is a restriction rather than a suggestion. Nothing changes for a caller that
684
+ passes neither option.
685
+
686
+ - 17ba31f: The collaboration mode is durable per Topic and read live, instead of
687
+ frozen for the length of a run.
688
+
689
+ `PermissionMode` was resolved once in the context factory and copied into
690
+ the tool executor. Enforcement was correct; the LIFETIME was the problem —
691
+ leaving plan mode meant ending the run and starting a fresh one with
692
+ `permissionMode: 'auto'`, discarding the in-flight step and the tool-schema
693
+ context to change one enum. So the look-around, propose, get-approval,
694
+ continue-in-the-same-conversation flow could not be built on it, and
695
+ `approve_plan` already existed with its approval changing nothing about the
696
+ mode.
697
+
698
+ `TopicState` is a new durable record — its own file beside the Topic, its
699
+ own schema version, its own revision counter. Separate from the Topic on
700
+ purpose: the Topic is identity and ownership, this is session state that
701
+ changes several times within one conversation, and merging them would make
702
+ every mode toggle a compare-and-set conflict against a title rename.
703
+ `setPermissionMode` rejects a stale revision the way `updateTopic` rejects a
704
+ stale `ownerVersion`.
705
+
706
+ The executor takes a resolver rather than a value, sampled once per tool
707
+ batch and held for it: a toggle landing between two calls the model issued
708
+ together would half-apply, and a batch where the first write is refused and
709
+ the second succeeds is not a state anyone can reason about.
710
+
711
+ Precedence is unchanged for every existing caller: an explicit
712
+ `RunConfig.permissionMode` still wins, and the topic record supplies the
713
+ mode only when the run config names none. A run with no topic store behaves
714
+ exactly as it did.
715
+
716
+ `SupervisorAgentConfig.onPlanApproved` fires when the operator approves a
717
+ plan, so a host can leave plan mode without ending the run.
718
+
719
+ - c968b58: Work that outlives one run: a durable objective on the Topic, advanced one round at a time.
720
+
721
+ Nothing in the kernel survived a single `query()` call. `stopWhen` and `prepareStep` shape one loop; the Topic was a container with no work state in it. A host wanting "keep going until X is done, stop safely if it stalls, let a human pause it" hand-rolled the store, the round cap and the compare-and-set outside the SDK.
722
+
723
+ New: `TopicObjective`, `InMemoryTopicObjectiveStore` / `DiskTopicObjectiveStore`, and `advanceObjective` / `driveObjective`.
724
+
725
+ The round is debited **before** the work runs. A counter advanced on success lets an objective that fails every round run forever, which is the runaway the cap exists to stop — so a round that crashes still counts, and a runner that throws leaves the objective `blocked` with a stated reason rather than `active`.
726
+
727
+ `driveObjective` bounds itself from the objective's own remaining rounds when the caller gives no budget, and throws `ObjectiveNotProgressingError` if a round completes without advancing the counter. Both came out of a mutation test: the first version defaulted to no bound, and breaking the debit turned it into a loop no timeout could interrupt — every `await` resolved as a microtask, so the event loop never reached a timer.
728
+
729
+ Interrupting is between rounds, never mid-round, via `signal`: the round in flight finishes and writes its verdict, and the next one does not start. A `paused` phase written by another host is picked up the same way, because the drive re-reads the record rather than trusting what it was handed.
730
+
731
+ - 7507e33: `compactNow` and `compactRegion` let a host ask for compaction instead of
732
+ only having it happen.
733
+
734
+ `runCompactionCheck` was the only entry point in the kernel and it was
735
+ exported from nowhere — not from the compaction barrel and not from the
736
+ package root. So every compaction had to wait for the in-loop threshold or
737
+ for a provider to reject an overlong prompt: a host could not offer
738
+ "compact this conversation", could not shrink an idle session sitting
739
+ between turns, and could not collapse a span it had chosen.
740
+
741
+ Both are built on the compaction planner rather than a second copy of the
742
+ boundary arithmetic, and neither touches a run.
743
+
744
+ `compactNow` returns `null` when there is nothing to shed rather than a
745
+ zero-shed result — a caller has to be able to tell "I compacted and it did
746
+ nothing" from "I compacted", and an outcome reporting zero is the shape
747
+ that gets logged as a successful pass and shown to a user as work done.
748
+ Neither function edits the array it was given; there is no run here and the
749
+ history belongs to the host.
750
+
751
+ `compactRegion` refuses a span whose edge splits a `tool_use`/`tool_result`
752
+ pair, naming the offending index, rather than snapping it to the nearest
753
+ safe one. The caller picked those indices from something they were looking
754
+ at, and a repaired span produces a valid history that summarised the wrong
755
+ messages with nothing to notice.
756
+
757
+ `COMPACTION_HEADER` and `isCompactionMessage` move to `compaction/summary.ts`
758
+ so the module below can reach them; the previous import path still works.
759
+
760
+ - 779d62a: `HostCommandRegistry` is a seam for the commands a host offers its
761
+ operator. There was none — the whole vocabulary was a literal array in one
762
+ host's TUI module, over a union shaped by that TUI's own concerns, and the
763
+ coupling had already escaped it: two non-TUI commands import that array
764
+ from React-adjacent code to build a name list, for facts the kernel owns.
765
+
766
+ **Deliberately not tools.** No descriptor reaches a provider and no
767
+ dispatch path reaches the model. A `/tasks` readout is a question the
768
+ operator asked; making it callable would let the model spend a turn on it
769
+ and record the output in the transcript as if it had discovered something.
770
+
771
+ Outcomes are structured, not rendered: `report` with rows, `prompt`, `ack`,
772
+ `refused`. The SDK formats nothing, because a TUI draws a table, a JSON
773
+ command prints a document and a web host renders a component — and a
774
+ pre-rendered string forces all three to parse prose back into the fields it
775
+ was built from.
776
+
777
+ `dispatch` returns `undefined` for a name it does not know, which is not
778
+ `refused`. A host layers its own commands under these, and collapsing "not
779
+ mine, keep looking" into "mine, and no" makes every one of them
780
+ unreachable.
781
+
782
+ `describe()` strips handlers, so a descriptor survives both
783
+ `JSON.stringify` (which drops a function silently) and `structuredClone`
784
+ (which throws on one).
785
+
786
+ A name collision throws rather than warning and overwriting, unlike the
787
+ base registry: these are operator-facing, and a shadowed command does not
788
+ fail — it simply never runs, and which one wins depends on registration
789
+ order.
790
+
791
+ Filled with the two commands whose facts the kernel already owns:
792
+ `kernelHostCommands` provides `/tasks` and `/agents`. An empty registry is
793
+ a declaration, and `/tasks` refuses rather than reporting zero when there
794
+ is no task store, because "there are none" and "I have nothing to measure
795
+ with" are different answers.
796
+
797
+ - 75c5b4a: Ids can now be checked at runtime. `asRunId`, `asSessionId`, `asProjectId`
798
+ and one constructor per prefixed id type verify the prefix and throw
799
+ `InvalidIdError` — naming both the value and the prefix that was expected —
800
+ rather than returning `undefined`. A caller holding a malformed id has no
801
+ correct fallback, and the value is usually on its way to becoming a store
802
+ key.
803
+
804
+ There was no prefix check anywhere before this. The casts in the tree assert
805
+ without verifying, so a `ses_` value cast to `RunId` reached a store key
806
+ unremarked and the first sign of it was a lookup that found nothing. The
807
+ types cannot catch it either: every id is a bare template-literal type, so
808
+ `const x: RunId = 'run_made-up'` compiles with no cast and no factory call.
809
+
810
+ One constructor per type rather than a generic `asId(prefix, value)`, on
811
+ purpose — a generic loses the return type, which is what makes the call site
812
+ type-check.
813
+
814
+ Also adds `types/ids/brand.ts` with the nominal-brand machinery, **declared
815
+ and not applied**. Nothing in `types/ids/index.ts` changes, so no existing
816
+ code breaks. Applying the brand turns every bare id literal into an error at
817
+ once, which is a major with a migration in front of it.
818
+
819
+ A comment in `types/ids/index.ts` claiming the actor ids were "branded so
820
+ actor refs cannot be constructed from bare strings" is corrected. The
821
+ compiler never enforced that, and the sentence had been sitting in the
822
+ source as documentation.
823
+
824
+ - 28cbe6d: A plugin can now declare configuration an operator retunes while the run is live.
825
+
826
+ `config/runtime.ts` is one schema parsed once into a frozen object, and nothing
827
+ in that directory watches, subscribes or changes — so a plugin had no way to
828
+ expose a section of its own, and retuning one knob meant rebuilding the config
829
+ and restarting whatever had consumed it.
830
+
831
+ `ConfigRegistry.register(namespace, schema, { base })` returns a `ConfigScope<T>`
832
+ with `get()`, `update(patch)` and `watch(listener)`. Resolution is schema
833
+ defaults, then the plugin's base, then the operator's persisted override, the
834
+ whole thing parsed — so an override written against an older shape is refused at
835
+ registration rather than surfacing wherever it happened to be read. An invalid
836
+ patch throws, leaves the previous value in place, and fires no watcher.
837
+ `registry.scope(runId)` prefixes store keys so two concurrent runs cannot retune
838
+ each other while still sharing one `ConfigOverrideStore`
839
+ (`InMemoryConfigOverrideStore` is the default; `DiskConfigOverrideStore` persists
840
+ to one JSON file).
841
+
842
+ The driver ships with it: `MCPReconnectSupervisor` now takes a
843
+ `MCPReconnectPolicySource` — a function it calls at every decision point rather
844
+ than a value it captures at construction — and `attachMCPServer` registers each
845
+ server's policy under `mcp.<name>`. Raising `maxAttempts` mid-outage takes effect
846
+ on the next retry instead of on the next process.
847
+
848
+ Nothing existing changes shape: `MCPReconnectSupervisor` was not previously
849
+ exported, and a live seam that only resolved once would be the frozen object
850
+ again with more ceremony, which is why `get()` is a call.
851
+
852
+ - f2a7375: `namzu doctor` now reports what the log pipeline did to this process's records: how many never reached the sink, how many had a credential redacted, and how many were shed or truncated by the size caps. It fails — non-zero exit — when records were dropped, and reports `inconclusive` rather than a green row when no sink was installed at all.
853
+
854
+ New SDK export `getLogCounters(): LogSinkCounters | undefined`. `undefined` means no host claimed the process's log destination, so nothing measured those records; it is deliberately not a zeroed set, which would read as "nothing was dropped, nothing was redacted" about a process where neither was ever checked.
855
+
856
+ `LogSinkCounters` had five fields incremented on every record and no reader anywhere. It could not have had one: the counters lived on whatever logger `createLogger` built, and `getRootLogger()` resolves per call and built a fresh one each time, so every total died with the expression that produced it. `installProcessSink` now owns one counter set per installed destination and every logger routed through it adds to those totals. A replacement install (`{ replace: true }`) starts at zero rather than carrying the previous destination's counts forward — the numbers describe the sink that is live.
857
+
858
+ `createLogger` takes an optional second argument, a counter set to share. Omitting it is unchanged behaviour: a host that builds its own logger for one subsystem keeps its own counts unless it asks otherwise.
859
+
860
+ - 7015eee: A logger's module identity can now be set independently of any log attribute: `Logger.child()` special-cases a new reserved key, exported as `SCOPE_ATTRIBUTE` (`'namzu.log.scope'`), that rebinds `LogRecord.scope.name` — an OTel-shaped field a host can filter stderr/JSON output on to silence or isolate one module — for that logger and every child it produces afterward, rather than being copied into `attributes`.
861
+
862
+ This closes a real bug in the pre-existing (but previously unreachable-in-practice) `scope` field: every logger obtained via the deprecated `getRootLogger()` reported the SAME `scope.name` (`'namzu'`) no matter what module built it, because the internal adapter between `getRootLogger()` and the record pipeline hardcoded its scope on every `child()` call. That adapter is fixed in this release as part of wiring `SCOPE_ATTRIBUTE` through it.
863
+
864
+ **If you parse stderr JSON:** a small number of call sites migrate their bare, un-namespaced `component` attribute to `scope.name` plus a namespaced `namzu.*`/`gen_ai.*` attribute in this release (the remaining `component:` sites are unaffected and continue to work exactly as before — see the tracking follow-up for the rest):
865
+
866
+ | file (component) | old bare key(s) | new |
867
+ | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
868
+ | `ManagedRegistry` (all 5 subclasses) | `component` | `scope.name: 'registry'` + `namzu.registry.name` |
869
+ | `AbstractAgent` | `component`, `agentId` | `scope.name: 'agents'` + `gen_ai.agent.id` (reused, not re-minted) + new `namzu.agent.type` |
870
+ | `RouterAgent` | `component`, `agent` | `scope.name: 'agents'` + `gen_ai.agent.name` (reused) |
871
+ | the run's own correlated logger (`RunContextFactory.buildLogger`) | `component`, `agent`, `sessionId`, `threadId`, `projectId`, `tenantId` | `scope.name: 'runtime/query'` + `gen_ai.agent.name` + `namzu.session.id` / `.thread.id` / `.project.id` / `.tenant.id`; a nested run also now carries `namzu.run.parent_id` when `parentRunId` is set — previously dropped on the floor |
872
+ | `ConnectorManager` / `TenantConnectorManager` | `component` | `scope.name: 'manager/connector'`; a tenant-scoped manager's connectors now carry `namzu.tenant.id`, previously unreachable because `ConnectorManager` had no logger input at all |
873
+ | `InMemoryCredentialVault` | `component`; `'namzu.credential.id'`/`'namzu.credential.label'`/`'namzu.tenant.id'` as raw string literals | `scope.name: 'vault'`; same attribute VALUES, now referenced via constants — no wire-format change on the attribute keys themselves |
874
+ | `MCPClient` | `component`, `serverId` (bound to the operator's own configured name); `'namzu.connector.server.name'` as a raw string literal | `scope.name: 'connector/mcp'` + `namzu.connector.server.id` (operator-configured) / `namzu.connector.server.name` (kept separate — the remote server's own self-reported name, which is untrusted input) |
875
+ | `packages/cli`'s `DoctorRegistry` | `component` | `scope.name: 'doctor'` — fixed in the same release specifically because `component` becoming inert would otherwise have silently dropped this logger's console bracket prefix with no alternative available to it |
876
+
877
+ No exported identifier is renamed or removed. `SCOPE_ATTRIBUTE` is a new export from `@namzu/sdk`'s root — additive. `ConnectorManagerConfig` gains one new _optional_ `log?: Logger` field — additive, no existing caller needs to change. `RunContextFactory.buildLogger`'s config type widens to accept an optional `parentRunId` it did not read before — additive.
878
+
879
+ **Not included in this release, tracked as a follow-up:** the remaining ~35 SDK source files that still bind `component:` are unaffected — they behave exactly as before, and will migrate in a later release. The CI gate's `unnamespacedBindingCount` ratchet moves from 48 to 40 to reflect that this release is a partial migration, not the finished one.
880
+
881
+ - b395a1e: `createLogger` now understands a reserved `err` attribute. Pass the actual thrown value under that key — `logger.error('Guardrail threw — failing closed', { err })` — and the emitted record gains `exception.type` / `exception.message` / `exception.stacktrace`, built from a bounded (4-hop), cycle-safe walk of the error's `cause` chain and passed through the same record-boundary redaction scan as every other attribute.
882
+
883
+ This is purely additive: a call site that already builds `{ error: toErrorMessage(err) }` by hand is unaffected, and the two keys (`err` vs `error`) are spelled differently on purpose so both keep compiling side by side. No existing call site in the SDK has been migrated to the new key in this release.
884
+
885
+ No new named export. The reserved key and the mapper behind it (`errorAttributes`) stay internal to `@namzu/sdk` — there is no `ERR_ATTRIBUTE` or `errorAttributes` symbol on the public surface to import. A host can still reach the new behavior today by handing `createLogger`'s existing `Logger`/child-logger calls a plain `{ err: someError }` attribute, since `LogContext` already accepts an arbitrary key.
886
+
887
+ Unrelated to any provider driver's behavior: `packages/sdk/src/provider/errors.ts` still never attaches `cause` to a classified provider error, and this release does not change that — see the doc comment added there and the note in `docs/conventions/index.md`.
888
+
889
+ - ca97021: Add `LogAttributes`, and close the two live log-forging (CWE-117) sites
890
+
891
+ `packages/sdk/src/utils/log/attributes.ts` adds `LogAttributes` — a namespaced (`namzu.*` / `gen_ai.*` / `service.*` / `exception.*`), shape-safe attribute type (`string | number | boolean`, or an array of those; no nested objects, no `null`/`undefined`). It is a type callers build TOWARD, not a narrowing of `Logger.child(context: LogContext)` — `LogContext` keeps its exact `Record<string, unknown>` shape, so no host `Logger` implementation breaks.
892
+
893
+ Two call sites used to interpolate externally-influenced text straight into a log message: `connector/mcp/client.ts` (a remote MCP server's self-reported name) and `vault/InMemoryCredentialVault.ts` (a caller-supplied credential label, and the tenant id and credential id alongside it). A hostile value embedding its own fake log line — `x\n[2026-01-01T00:00:00Z] [ERROR] [audit] forged` — forged a second record in every reader downstream. Both sites now log a constant body string with the variable text carried in a `LogAttributes` attribute instead.
894
+
895
+ `prettySink`'s control-byte escaping — previously scoped to `body` and `scope` only — now covers every rendered attribute value too, and additionally escapes DEL (0x7F) and U+2028/U+2029, neither of which `JSON.stringify` touches on its own. Closing the escaping gap only on `body`/`scope` would have left exactly the field the fix above moves untrusted text into unprotected.
896
+
897
+ `docs/sdk/observability/logging.md` (new) states the guarantee's actual boundary: `LogAttributes` is a key-shape guarantee only. Any string value can still carry a secret; the record-boundary redaction scan (`redact.ts`, shipped with the LogSink seam) is the value-level defence.
898
+
899
+ - 9947662: `LogRecord` gains `traceId`, `spanId` and `traceFlags`, resolved from the active OTel span at emit time
900
+
901
+ `createLogger`'s `emit` now reads `telemetry/runtime-accessors.ts`'s new `getActiveSpanContext()` — `trace.getSpan(context.active())?.spanContext()` — for every accepted record, and stamps `traceId`/`spanId`/`traceFlags` onto it when a span is active. All three arrive together or not at all: a trace id with no span id would be a half-address, worse than the plain absence a reader can already tell apart from "unwritten".
902
+
903
+ Resolved PER RECORD, never once at `createLogger` construction — a logger built before a tracer provider registers still picks up spans started after registration.
904
+
905
+ With no tracer provider registered, or a real one registered with no context manager to carry it past the first `await` (`@opentelemetry/api`'s default `NoopContextManager`), the three fields are simply absent from the record — not `''`, not `'unknown'`, and nothing throws. Reading the active context can only ever ADD information to a record; it cannot make a host that never configured telemetry fail anything it did not already fail.
906
+
907
+ New optional fields only. No existing `LogRecord` consumer breaks, and a sink reading unknown keys is unaffected.
908
+
909
+ - 89dfe84: Add the LogSink seam: `createLogger`, pluggable sinks, and a record-boundary redaction/size pipeline
910
+
911
+ `packages/sdk/src/utils/logger.ts` wrote directly to `process.stderr` with no way to redirect, replace, or intercept it — the CLI's only lever was `configureLogger({ level: 'silent' })`, which is why every entry point silences the logger outright instead of pointing it somewhere useful.
912
+
913
+ This adds the seam additively. `Logger`, `getRootLogger` and `configureLogger` keep their exact signatures and behaviour — every existing test passes unmodified — and are now marked `@deprecated`, naming their replacements:
914
+
915
+ - `LogRecord` — the emitted record shape (a subset of the OTel Logs Data Model: timestamp, severity, body, scope, resource, attributes). No `traceId`/`spanId`/`eventName` yet — those ship with their own emitters in later work, not as unwritten fields today.
916
+ - `LogSink` — `{ emit(record) }`, the seam a host implements to receive records.
917
+ - `createLogger(options)` — builds a `Logger` whose destination and level come from the caller's options, not a module-global. The level is read per record off `options.level.current`, never captured at construction. A sink whose `emit` throws is caught and counted, never rethrown into the caller — the old direct `stderr.write` could never throw into kernel control flow, and a naive seam would have introduced that failure mode for the first time.
918
+ - A record-boundary pipeline every sink receives the same output of: secret redaction, an 8 KiB per-value truncation cap, a 64-attribute count cap, and a 16 KiB total-record cap — each counted, and enforced once in `createLogger` rather than duplicated per sink. A custom sink cannot bypass any of it.
919
+ - `jsonLinesSink(stream)` — NDJSON, additionally escaping U+2028/U+2029 beyond what `JSON.stringify` handles.
920
+ - `prettySink(stream)` — human-readable lines, with every C0 control byte (ESC included) rendered as inert `\xNN` text in every field, not only the body.
921
+ - `NOOP_SINK` / `NOOP_LOGGER` — every accepted call counts as dropped, so a host can tell "nothing configured" apart from "configured and silently eating records".
922
+ - `installProcessSink(sink, level, opts?)` — the CLI's future replacement for `configureLogger`; refuses a second call unless `{ replace: true }` is passed.
923
+ - `Severity`, `LevelFilter`, `Resource`, `LogSinkCounters` — the supporting types.
924
+
925
+ No behaviour change to anything already shipping: the seam is inert until a host calls `installProcessSink` or `createLogger`, which nothing in this package does yet.
926
+
927
+ - 8a4986f: An MCP connection that drops is now reconnected instead of staying dead for the
928
+ life of the process.
929
+
930
+ `MCPClient.connect()` was called exactly once, by whoever built the client.
931
+ `transport.onClose` set the status, emitted the lifecycle event and rejected
932
+ everything pending — and nothing scheduled another attempt. One network blip,
933
+ one server restart, one laptop sleep, and a plugin's MCP tools were gone until
934
+ the process ended, while the plugin itself went on reporting as enabled.
935
+
936
+ New `MCPReconnectSupervisor` (exported from the connector barrel) watches one
937
+ client through the existing `onLifecycle` subscription and reconnects with
938
+ bounded exponential backoff — defaults: 500 ms initial, 30 s ceiling, 6
939
+ attempts, then `onGaveUp`. `PluginLifecycleManager` attaches one per client it
940
+ creates.
941
+
942
+ **If you build clients yourself, stop the supervisor before disconnecting.**
943
+ `disconnect()` emits the same `mcp_client_disconnected` event a dead transport
944
+ does and the event carries nothing that separates them, so a supervisor still
945
+ attached at teardown will reconnect what you just closed. `stop()` is part of
946
+ the teardown sequence, not an optimisation. The plugin lifecycle already does
947
+ this on both its teardown paths.
948
+
949
+ `onReconnected` fires after a successful recovery. A reconnected server may
950
+ have restarted with a different tool list, and the supervisor cannot know what
951
+ a host needs to redo — so it reports when rather than guessing what.
952
+
953
+ - b1bb2e0: Nothing stored a per-message judgment, so every consumer had to invent its
954
+ own side table to answer the most basic question there is — was that answer
955
+ any good.
956
+
957
+ `MessageFeedbackStore` records a `'good' | 'bad'` rating and an optional
958
+ note per `{ runId, messageId }`, in memory or on disk. `rating` is a closed
959
+ union rather than a number or a free string: a 1–5 scale invites a mean
960
+ nobody can interpret across raters, and widening the union later is now a
961
+ deliberate major rather than an accident.
962
+
963
+ Writes are compare-and-set on a per-record `ownerVersion`, throwing
964
+ `StaleFeedbackError` with both the expected and the actual version. The
965
+ disk store's first write uses an exclusive create, so two raters who each
966
+ read "no feedback yet" cannot both land — a read-then-write is not atomic,
967
+ and a rating is exactly the kind of value where last-write-wins loses
968
+ information nobody notices is gone.
969
+
970
+ A rating aimed at a `messageId` that appears in no event of the named run
971
+ is refused with `UnknownMessageError` and nothing is written. A row
972
+ pointing at a message nobody can find is unreviewable and
973
+ indistinguishable from a real one. A disk store built without a run
974
+ directory to validate against refuses every write rather than accepting
975
+ everything it cannot check.
976
+
977
+ Both implementations run one conformance suite, which found a real
978
+ divergence between them the day it was written.
979
+
980
+ In the CLI, `/feedback good|bad [note]` rates the last answer. With no
981
+ answer yet it refuses rather than writing against a synthesized id. The
982
+ kernel's `messageId` and `runId` now travel across the CLI's event seam,
983
+ which previously dropped both.
984
+
985
+ - da66613: Every tool call a `run_code` program makes is visible in the run's event stream.
986
+
987
+ The program's calls went through `registry.execute` directly, so they reached the permission gate and reached the event stream **not at all**. A run whose transcript showed one `run_code` call and nothing about the eleven writes it performed is a transcript nobody can audit — the tool would be the one place in the system where work happens off the record.
988
+
989
+ `tool_executing` and `tool_completed` gain an optional `via`, present when another _tool_ dispatched the call rather than the model. It **names** the dispatching call rather than merely marking this one nested, and that is the load-bearing part: without it a consumer counting tool calls double-counts the parent and each child, and one rendering a timeline draws eleven siblings where there is one call with eleven children. It is carried on both events, so a consumer can pair them without holding the start.
990
+
991
+ A nested call gets its **own** id. Reusing the parent's would make two different calls indistinguishable in any log keyed by it, which is exactly how a nested write gets attributed to the program that ran it rather than to itself.
992
+
993
+ `dispatchTool` is bound **per call** rather than once per batch. The base tool context has no `toolUseId` — a caller dispatching outside a batch has no parent to name — and a closure built there reported every nested call as parentless, which is what the tests caught.
994
+
995
+ - be95e43: Emit the CLI boot narrative — sandbox notice, provider chain, capability probe, config provenance and a terminal ready/refused event
996
+
997
+ **`@namzu/sdk`**: `EVENT_NAME_ATTRIBUTE` is now re-exported from the root barrel (`packages/sdk/src/utils/log/index.ts` was missing the value re-export that let it reach a host package). This is what lets a package outside the SDK — `@namzu/cli`, here — name a boot event without duplicating the reserved key `createLogger` promotes onto `LogRecord.eventName`.
998
+
999
+ **`@namzu/cli`**'s default stderr output changes from nothing to an info-level boot narrative on every invocation, not only `run`/`drain`/`run-stream`/the TUI — `namzu doctor`/`namzu login` now also print `namzu.boot.start` and `namzu.config.resolved` ahead of their own output, because `getContext()` is the one place any subcommand resolves logging + config. Use `--quiet` (LOG-05) to go back to warn-and-above; `NAMZU_LOG_LEVEL=silent` remains a full return to today's silence.
1000
+
1001
+ The highest-value line: `ResolvedSandbox.notice`/`.unconfined` (computed on every boot, discarded until now) are emitted as `namzu.sandbox.resolved`, at `warn` specifically when nothing is confined and `info` otherwise — an operator reading default output now sees "this platform enforces none of filesystem, network, process" instead of it existing only in a field nothing read.
1002
+
1003
+ Also new: `namzu.provider.resolved` (the constructed chain and each skipped fallback's reason), `namzu.capability.detected`/`.broken` (via `probeCapabilities`, gaining its first consumer and joining `@namzu/cli`'s public exports alongside the existing `probeOptionalPackage`/`CapabilityProbe`/`NAMZU_OPTIONAL_CAPABILITIES`), `namzu.discovery.completed` (MCP connectors — plugin/skill discovery is not yet wired to the boot path and is not claimed here), `namzu.telemetry.status` (states plainly that no `TracerProvider`/`LoggerProvider` is registered, since the CLI does not call `registerTelemetry()` on any path today), and the terminal `namzu.boot.ready` / `namzu.boot.refused` pair — `ready` fires exactly once on success with no boolean readiness field, `refused` fires at `error` on every early return out of `createAgentSession` including a `sandbox.requireIsolation` control this host cannot meet, which now also logs before the process exits non-zero (the exit code itself is unchanged — the existing top-level catch in `runCli` already produced it).
1004
+
1005
+ The two previously-silent `catch {}` blocks in `packages/cli/src/tui/agent.ts` (a failed provider-client rebuild after an OAuth token refresh; a sub-agent runtime that failed to start) now each emit one `warn` record with `exception.type`/`exception.message`. Neither's behavior changed — both remain non-fatal.
1006
+
1007
+ No exported signature changed and no default changed; every addition is either a new export or new stderr output governed by the existing `--quiet`/`--verbose`/`NAMZU_LOG_LEVEL`/`NAMZU_LOG_FORMAT` controls.
1008
+
1009
+ - 9aba59a: Named permission presets that bind a gate config to a sandbox isolation requirement and an approval policy.
1010
+
1011
+ The three were configured independently and had to agree by hand. `defaultSandboxedGateConfig` auto-approves in-sandbox file mutation, and its own docstring says why: "the FS boundary is enforced by the sandbox layer, not by per-call review". That is a claim about a **different subsystem**, and nothing checked it. Hand that config a `basic` tier, where the spawned process can read and write the whole host filesystem, and the gate keeps auto-approving writes on the strength of a boundary that is not there.
1012
+
1013
+ Four presets — `supervised`, `sandboxed`, `sandboxed-shell`, `unattended` — each stating the isolation controls it relies on, plus `resolvePermissionPreset`, which **refuses** when the host cannot meet them and names the missing controls. Refusing is the point: a preset that silently fell back to asking about everything would be safe and unusable, and one that silently kept auto-approving would be neither.
1014
+
1015
+ Requirements are controls, not tier names: `SandboxEnvironment` names an implementation — one tier denies the network outright while another leaves the host filesystem visible — and a preset depends on the property, not on which implementation supplies it. A preset requires only what it actually spends, so `sandboxed` does not demand network isolation it never trades on.
1016
+
1017
+ `unattended` is the one whose requirement cannot be waived: with an auto-approving policy the sandbox is the only boundary left, so it requires all three controls. It is also the only preset that auto-approves network calls, and those two facts are the same fact — which is what a preset exists to keep together.
1018
+
1019
+ `availablePermissionPresets` lists what a given host can honour, loosest first, and always ends with `supervised`, which assumes nothing.
1020
+
1021
+ - 5a4f7b4: A plugin's declared skills actually load and reach the model.
1022
+
1023
+ The manifest schema validated `skills` with a per-plugin cap and the runtime then refused the whole plugin for declaring any — so a plugin shipping four tools and one skill validated clean, installed clean, and contributed nothing. The refusal was correct while there was no path into `SkillRegistry`; this is the path.
1024
+
1025
+ Pass `skillRegistry` to `PluginLifecycleManager` and a plugin's skills load from the directories its manifest names. Without one, a manifest declaring skills is still **refused** — accepting it and dropping the skills would produce a plugin reporting `enabled` that contributes nothing its author declared, which is the same lie the wholesale refusal was written to prevent.
1026
+
1027
+ Skills are namespaced like tools (`plugin__skill`), because two plugins shipping `reconcile` would otherwise overwrite each other in a Map keyed by the frontmatter name, and the loser would vanish with nothing reporting it. The namespaced name is written into the skill's own `metadata.name` too, so the registry key and what a rendered prompt shows agree.
1028
+
1029
+ What a plugin brought, it takes away: skills are unregistered on rollback and on disable. A disabled plugin whose skills stayed registered keeps offering the model instructions from something the runtime switched off — worse than a stale tool, because a tool call would at least fail and a skill is followed silently.
1030
+
1031
+ `SkillRegistry` gains `add(name, skill)` and `unregister(name)`. `connectors` and `personas` remain refused; a skill registry does not buy them a manifest path.
1032
+
1033
+ - 7adf919: The system prompt is open: a contribution registry the assembler consumes, with skills as its first contributor.
1034
+
1035
+ `PromptBuilder` assembled a fixed list — base prompt, persona or system prompt, skills, tool section, tier guidance, environment — and every one of those was a branch written into the builder. A capability that needed the model to know something (web tools and their citation rules, a plugin's conventions, a host's house style) had exactly two options: convince somebody to add a branch, or splice it into `systemPrompt` and lose whatever was there.
1036
+
1037
+ New: `PromptContribution`, `PromptContributionRegistry`, and the `contributions` field on `PromptBuilderConfig`. Omit it and nothing changes.
1038
+
1039
+ **`placement` is not cosmetic.** `static` is the segment the prompt cache keeps and a provider caches across turns; `dynamic` is re-sent every iteration. A contributor whose text varies per turn but declares `static` either invalidates the cached prefix on every iteration — paying full price for a cache that never hits — or gets served the first turn's text forever. The rule: `static` iff the output depends only on things that cannot change inside one run.
1040
+
1041
+ Registration order is rendering order, because the prompt is read top to bottom by a model that weights early text more; an order derived from priority numbers would have every contributor arguing about a number. A duplicate id is refused rather than silently overwritten — "my guidance stopped appearing" is the least debuggable failure this could have — and `replace` keeps the original position, because a replacement is a new implementation of the same contribution, not a new one.
1042
+
1043
+ Skills is the first contributor, and is rendered **in place** rather than at the tail, so a host that registers the built-in gets the seam and not a reordered prompt. Under a persona it stays inside `assembleSystemPrompt`, whose section ordering places it relative to constraints and output discipline — routing it out would silently reorder every persona-driven prompt.
1044
+
1045
+ - 70f23bb: A driver can now say how large a model's context window is, and the kernel
1046
+ ranks that above its hand-maintained table.
1047
+
1048
+ That table was the only source below an explicit host config, and its own
1049
+ header records what it cost: every Claude entry carried 200k including the
1050
+ 1M-window models, so those runs compacted at roughly 14% full and threw
1051
+ away the prompt-cache prefix to do it. Every model release drifts it again
1052
+ until somebody edits it — while the OpenRouter driver was already parsing
1053
+ the vendor's real `context_length` and discarding it, because there was no
1054
+ member to return it through.
1055
+
1056
+ `LLMProvider.resolveContextWindow?(model, signal)` is three-state like
1057
+ `effortLevelsFor`: absent means this driver cannot answer, a resolved
1058
+ `undefined` means it asked and does not know, a number is the answer. A
1059
+ driver resolving `undefined` falls through to the TABLE, not to the
1060
+ assumed default — asking must never be worse than not asking.
1061
+
1062
+ Resolved once per run, at the door. Both consumers are synchronous and in
1063
+ the hot loop, so this can never become an await inside it. A driver that
1064
+ rejects or hangs does not fail the run: the window is an optimisation over
1065
+ a working default.
1066
+
1067
+ `ResolvedContextWindow['source']` and the `windowSource` on
1068
+ `token_usage_updated` gain `'provider'`, ranked between `'config'` and
1069
+ `'model-table'`, so a host can see which route a number came from.
1070
+
1071
+ Also fixes a hole this exposed: `withProviderRetry` and
1072
+ `withProviderFallback` forwarded `listModels`, `healthCheck` and
1073
+ `doctorCheck` but not `effortLevelsFor`. A dropped optional member does not
1074
+ fail — it reads as "this driver cannot answer" — and retry is on by
1075
+ default, so a driver's declared effort levels were invisible on
1076
+ essentially every run.
1077
+
1078
+ - 413d939: Text queued for a running agent is now delivered at the next-turn boundary.
1079
+ Two public APIs could accept it and silently never hand it over.
1080
+
1081
+ `AgentManager.continueTask` and `queueMessage` pushed onto
1082
+ `pendingMessages`, and nothing in the kernel ever drained it — the manager
1083
+ interface's own docblock said "the runtime does not deliver it", and
1084
+ `continue_task` was unmounted from the coordinator tools because of that.
1085
+ So a supervisor could redirect a running worker through a public API and
1086
+ have the instruction go nowhere.
1087
+
1088
+ The steering channel had the mirror-image hole. It can only append to a
1089
+ settled tool result, so guidance queued during a turn that called no tools
1090
+ stayed pending, and the loop ended the run with the channel still full.
1091
+
1092
+ `BaseAgentConfig.inboundMessages` is the delivery seam: a drain callback,
1093
+ stamped on a child's config after its `configBuilder` returns for the same
1094
+ reason `parentSpan`, `resumeHandler` and `env` are — a builder written by
1095
+ whoever registered the agent cannot forward a field it was never told
1096
+ about. Both queues drain at the iteration boundary, beside the completion
1097
+ inbox, which is the established place for putting a user message in after
1098
+ tool results and before the next turn.
1099
+
1100
+ An empty queue costs nothing: no extra iteration, no model call, no message
1101
+ in the history. A queued message costs exactly one more turn.
1102
+
1103
+ `queueMessage` on a settled task now throws instead of pushing silently.
1104
+ There is no longer a state in which a caller believes something is in
1105
+ flight when the only thing that would have drained it has finished.
1106
+
1107
+ - 1d428e6: An incremental read-model registry, with derived run status as its first driven consumer.
1108
+
1109
+ Everything derived from a run was computed by scanning what was in hand when somebody asked. `deriveRunStatus` takes a status and a park and answers about that instant — which works while the whole run fits in memory and stops working the moment it does not. A caller wanting the status of a run whose history has been compacted, or of a run in another process, loads the log and folds it, and every caller folds it slightly differently.
1110
+
1111
+ `ReadModelRegistry` is that fold, written once and advanced one event at a time. Its two refusals are what make "incremental" a property rather than a hope:
1112
+
1113
+ - A **duplicate** is refused, because it double-counts anything a model accumulates and nothing downstream can tell a doubled count from a real one.
1114
+ - A **gap** is refused, because a projection built across one produces a state that looks complete while describing a log the registry never saw. A caller that has lost its place calls `replay`, which is honest about starting over.
1115
+
1116
+ One registry per run rather than per model, so `lastSeq` is one number and a caller reading two projections cannot be handed states derived from different prefixes of the same log. A refusal leaves every state untouched — a registry that refused after mutating half its models would be worse than one that accepted.
1117
+
1118
+ `createRunStatusReadModel` derives `RunStatus` from the events a run already emits, feeding `deriveRunStatus` rather than re-implementing it: two implementations of the same rule are two chances to disagree about what `awaiting_hitl_resolution` means, and the disagreement would show up as a run that reads differently depending on which surface asked. The two `awaiting_hitl*` variants had no producer at all before this.
1119
+
1120
+ `now` is injected because a deadline passes without any event being emitted, so what a fold holds is the status **as of the last event** — the honest thing for a projection to say, since nothing woke it up at the deadline.
1121
+
1122
+ - f9c1589: `continue_task` is registered again. A supervisor can redirect a background
1123
+ worker instead of only waiting for it or killing it — and killing it throws
1124
+ away everything it has done.
1125
+
1126
+ The tool was dropped because the queue it wrote to had no reader: on a live
1127
+ task the manager accepted the call and pushed onto `pendingMessages`, and
1128
+ nothing drained that queue during a run, so registering it would have
1129
+ handed the model a call that silently does nothing. The comment recording
1130
+ that named its own expiry condition — "if follow-ups on a live worker are
1131
+ wanted, the work is a consumer for the queue" — and that consumer now
1132
+ exists.
1133
+
1134
+ It rides under the same `canDelegate` gate as `create_task`,
1135
+ `wait_for_task` and `cancel_task`: steering a live worker is delegation
1136
+ too, so a run that must not delegate cannot redirect one either.
1137
+
1138
+ It refuses a task this run did not launch, applying the same fencing the
1139
+ listing and the wait already do, so one run cannot steer another's worker on
1140
+ a shared scheduler. "Never existed" and "belongs to someone else" get the
1141
+ same answer, because distinguishing them confirms a task id the run was not
1142
+ supposed to know.
1143
+
1144
+ A settled task is reported as a refusal naming the state, not as a thrown
1145
+ tool error — the manager refuses by throwing, and a throw out of `execute`
1146
+ reads to the model as "the platform broke" rather than "that worker has
1147
+ finished". It does not block: the worker's result still arrives the way it
1148
+ already would.
1149
+
1150
+ - 4992819: Three exported names now say what they operate on. Old spellings still work
1151
+ and are marked `@deprecated`; they are removed in the next major.
1152
+
1153
+ | Old | New |
1154
+ | -------------------------- | ------------------------- |
1155
+ | `collect` | `collectChatCompletion` |
1156
+ | `Registry` | `BaseRegistry` |
1157
+ | `ContextCache` | `PromptCache` |
1158
+ | `ContextCacheConfig` | `PromptCacheConfig` |
1159
+ | `QueryParams.contextCache` | `QueryParams.promptCache` |
1160
+
1161
+ `collect` gave no hint what it collected — it drains a `StreamChunk`
1162
+ iterable into a `ChatCompletionResponse`. `Registry` sat unqualified beside
1163
+ seven domain-named siblings in the same barrel (`ToolRegistry`,
1164
+ `AgentRegistry`, and five more), so the bare name read as the
1165
+ general-purpose one when it is the base class. `ContextCache` named one
1166
+ input two ways a single call apart: `new ContextCache(ContextCacheConfig)`
1167
+ then `.getSystemPrompt(PromptCacheInput)`.
1168
+
1169
+ To migrate, change the import; nothing else moves. `PromptCacheInput` was
1170
+ already correct and is unchanged.
1171
+
1172
+ Setting both `contextCache` and `promptCache` to different instances throws
1173
+ rather than picking one, before the run starts and at no provider cost. A
1174
+ caller who set both has a real disagreement about which cache to use, and
1175
+ silently preferring either would run with a value they also asked not to
1176
+ use. Setting both to the _same_ instance is fine.
1177
+
1178
+ - 215f7b5: The run-claim types now use the settled distributed-locking vocabulary. Old
1179
+ names still work and are marked `@deprecated`; they go in the next major.
1180
+
1181
+ | Old | New |
1182
+ | -------------- | -------------- |
1183
+ | `RunClaim` | `RunLease` |
1184
+ | `ClaimFence` | `FencingToken` |
1185
+ | `ClaimSummary` | `LeaseSummary` |
1186
+
1187
+ What these describe is textbook: a time-bounded exclusive grant on a run
1188
+ (holder, fence, absolute `expiresAt`), plus a monotonically increasing
1189
+ number a store compares to reject a superseded writer. That is a lease and
1190
+ a fencing token — terms with a literature a reader can go and check.
1191
+ "Claim" and "Fence" read as ad hoc ownership flags, so nothing told a reader
1192
+ to expect the guarantees the mechanism actually provides, and the
1193
+ `fence?: ClaimFence` threaded through `saveCheckpoint` and `releaseRun`
1194
+ looked decorative rather than load-bearing.
1195
+
1196
+ The verbs are deliberately unchanged. `claimRun`, `releaseRun` and
1197
+ `toClaimSummary` keep their names — "claim a lease" is idiomatic, and
1198
+ renaming the methods would break every `CheckpointStore` implementor for no
1199
+ reading gain.
1200
+
1201
+ `FencingToken` remains a bare `number` alias. It buys clarity, not type
1202
+ safety; making the ids nominal is a separate change.
1203
+
1204
+ To migrate, change the type import. No runtime behaviour moves.
1205
+
1206
+ - 62773b8: `TaskGateway` becomes `TaskScheduler` and `LocalTaskGateway` becomes
1207
+ `LocalTaskScheduler`. Old names still work and are marked `@deprecated`;
1208
+ they go in the next major.
1209
+
1210
+ "Gateway" names an object that sits at a system boundary and faces outward
1211
+ — Fowler's POEAA Gateway, an API gateway, a payment gateway. This one faces
1212
+ inward: it creates, waits on, continues, cancels and lists in-process agent
1213
+ tasks. A reader who trusted the name expected a facade over something
1214
+ external and found a scheduler.
1215
+
1216
+ Two config fields move with the types, because the field name is what a
1217
+ host actually types and leaving one spelled `gateway` would retire the type
1218
+ while keeping its vocabulary:
1219
+
1220
+ - `QueryParams.taskGateway` → `QueryParams.taskScheduler`
1221
+ - `SupervisorAgentConfig.gateway` → `SupervisorAgentConfig.scheduler`
1222
+
1223
+ Both accept either spelling for the window. Setting both to different
1224
+ instances throws and names both fields; setting both to the same instance
1225
+ is fine. The supervisor resolves the pair once rather than at each read, so
1226
+ a host that sets only the new name cannot get a working scheduler on one
1227
+ path and `undefined` on another.
1228
+
1229
+ `SupervisorAgentConfig` with neither a scheduler nor an `agentManager` is
1230
+ still an error, and the message now names `scheduler`.
1231
+
1232
+ - 6f4cd04: The verification gate is an authorization gate, and is named one. Old names
1233
+ still work and are marked `@deprecated`; they go in the next major.
1234
+
1235
+ | Old | New |
1236
+ | --------------------------------- | ------------------------- |
1237
+ | `VerificationGate` | `AuthorizationGate` |
1238
+ | `VerificationRule` | `AuthorizationRule` |
1239
+ | `VerificationGateConfig` | `AuthorizationGateConfig` |
1240
+ | `verificationGate` (config field) | `authorizationGate` |
1241
+
1242
+ A reader who saw `VerificationGate` expected something that verifies a claim
1243
+ — checks a signature, confirms an output matches a schema. It is a rule
1244
+ engine that decides, before a tool runs, whether the call is permitted:
1245
+ allow, deny or review, by name, category, tier, or a pattern over the
1246
+ arguments. Every rule variant already said so. The misreading was not
1247
+ academic: the module sat beside real guardrail and HITL neighbours, where
1248
+ "verification" suggests exactly the post-hoc double-check the guardrails do.
1249
+
1250
+ The config field is on `ReactiveAgentConfig`, `SupervisorAgentConfig`,
1251
+ `runAgent`'s options and `QueryParams`. Both spellings are accepted for the
1252
+ window and resolved at one site; setting both to different configs throws
1253
+ and names both fields. One resolve rather than four matters more here than
1254
+ for an ordinary rename — a gate present on one path and absent on another
1255
+ means a tool call permitted where it should have been refused.
1256
+
1257
+ Also renamed, and reachable only in type position: `VerificationRuleSchema`
1258
+ and `VerificationGateConfigSchema`. They are not exported as values, but
1259
+ `import type` and `typeof` both worked, so they carry aliases rather than
1260
+ disappearing.
1261
+
1262
+ Deliberately unchanged, because each is already correct about what it is:
1263
+ `GateDecision`, `GateEvaluationResult`, `ToolCallContext`, `describeRule`,
1264
+ `evaluateRule`, `defaultSandboxedGateConfig`,
1265
+ `defaultSandboxedShellGateConfig`.
1266
+
1267
+ The module-invariant registry — `createInvariantRegistry`, `invariants`,
1268
+ `InvariantRegistry` and friends — moved to its own directory rather than
1269
+ into `authorization/`. It is the one thing in the old `verification/` that
1270
+ genuinely verifies a claim: what a module says about its own live state. No
1271
+ import path changes for consumers; it is exported from the same barrel.
1272
+
1273
+ - 71ed5df: A credential turning over is now observable, and the doctor's vault check
1274
+ can answer.
1275
+
1276
+ Rotation was invisible: a lapsed OAuth token was refreshed straight into
1277
+ the CLI's file store, and the bus carried `vault_lookup` with no change
1278
+ event — so no probe subscriber could see a credential replaced, and nothing
1279
+ could answer "when did this last rotate".
1280
+
1281
+ `vault_credential_changed` joins the bus, dispatched through the same probe
1282
+ registry `vault_lookup` already uses rather than a second one, which would
1283
+ mean a subscriber that saw lookups and not rotations depending on which it
1284
+ found. `kind` separates `set` from `rotated`, which is the distinction a
1285
+ reader wants: a first write is configuration, a replacement is a credential
1286
+ turning over. The event carries the credential's NAME and never its value —
1287
+ a change event exists to be logged, forwarded and retained, which is
1288
+ exactly what a secret must not be.
1289
+
1290
+ `FileCredentialProvider` makes the CLI's hardened store writable through
1291
+ the seam. It adds no file logic of its own: the store already owns the `wx`
1292
+ open, the `0600`, and the read-back that proves the mode landed, and a
1293
+ second copy of that guarantee is the one that would drift.
1294
+
1295
+ The doctor's vault check answered `skipped` unconditionally with "no vault
1296
+ auto-discovery in v1" — the same answer on every machine, forever, which is
1297
+ the shape `a-check-that-cannot-fail` warns about. It now reports what the
1298
+ registered providers describe, and returns `skipped` only when none is
1299
+ registered. It calls `describe`, never `resolve`: this output is what an
1300
+ operator pastes into an issue.
1301
+
1302
+ - b7f7897: An opt-in `run_code` tool that dispatches a model-authored program through the run's own `ToolRegistry`.
1303
+
1304
+ Twenty tool calls to filter a list is twenty model turns, each at full context size with the whole conversation resent. The same work is one loop. That is the entire argument for this tool, and it only holds if the loop cannot reach further than the twenty calls could have.
1305
+
1306
+ **The program's reach is the run's reach.** Every capability it can call is a tool already in the registry, already narrowed by the turn's `allowedTools`, already going through the dispatch a model-issued call goes through — the permission gate, the approval policy, the audit record. There is no second path, because a second path is a second place for the gate to be forgotten and the one that forgot it would be the one a model reached through a program.
1307
+
1308
+ The program's own `tools` list is **intersected** with what the turn allows, computed host-side rather than trusted from the input: that list is model-authored, and a program that named every tool it wished for would otherwise widen its own grant. It is also a ceiling — a program that declared two tools and reached for a third is refused, because it has done something its author did not describe. Withheld names are reported back with what the turn does allow, so the model can correct itself in the same turn.
1309
+
1310
+ Declared **not** read-only and **destructive**, whatever a given program does: its effects are the union of the tools it calls, which is not knowable from the input, and `readOnly: true` would let a read-only preset auto-approve a program whose whole purpose is calling something else.
1311
+
1312
+ Output is posted as it is printed rather than batched until the program finishes — a program that printed its progress and then hung has told the model where it got to, and a buffer that only ships on completion loses exactly the output a timeout most needs to explain itself.
1313
+
1314
+ `ToolContext.dispatchTool` is the channel, and is available to every tool rather than only this one. That is stated rather than quietly true: tools are host-installed code, so the boundary this protects is the _model's_ reach, and that stays bounded where it has always been.
1315
+
1316
+ Not in the default builtin set. A run that does not need model-authored control flow should not have a way to execute model-authored text.
1317
+
1318
+ - dec1964: `AgentStatus` is renamed to `RunExecutionStatus`. The union is unchanged (`'idle' | 'pending' | 'running' | 'completed' | 'failed' | 'cancelled'`), and `AgentStatus` remains exported as a `@deprecated` alias — your code still compiles and warns. Removal is a later major.
1319
+
1320
+ It never typed an agent. Every use of it in the package is a run's status, a run's audit outcome, or the status field of a run's result; `AbstractAgent` and `ReactiveAgent` have no status of their own, because an agent is a configuration and it is the _run_ that is idle, running or cancelled. A reader importing `AgentStatus` to describe an agent's lifecycle was reaching for the type that governs something else, and the name was the only thing telling them otherwise.
1321
+
1322
+ `isTerminalStatus` now takes `RunExecutionStatus`. A value typed with the old alias is still accepted, since the alias resolves to the same union.
1323
+
1324
+ - e5dde44: A run/session query seam, including what compaction removed.
1325
+
1326
+ The stores could each answer part of it and nothing could answer the question. `readEvents` gives a log; `writeMessages` persisted a history; and the two **disagree by design** once compaction has run — the persisted history is what survived, and what compaction removed lives only in the event log. "Show me this conversation" had two plausible answers and a caller picked one by accident.
1327
+
1328
+ The compacted-away half is the reason this exists. `compaction_shed` has carried "exactly the messages the pass removed, in their original order" since shed history was shadowed to the transcript, precisely so it would not be lost — and nothing read it back. Evidence nobody can retrieve is evidence nobody kept.
1329
+
1330
+ `RunQuery.shedHistory()` returns every pass, oldest first, with its iteration, its reason and its position in the log. `fullTranscript(messages)` returns everything that was ever in the conversation.
1331
+
1332
+ The ordering claim is exactly that and no more, and it is stated in the source: this does **not** reconstruct the original interleaving, and it cannot — the log records what each pass removed, not where the summary that replaced it sits relative to what came after. What it does guarantee is completeness, which is the question somebody reconstructing an incident is actually asking.
1333
+
1334
+ `status()` goes through the read model rather than folding the log a second time: two folds of one log are two chances to disagree, and a run that reads differently depending on which surface asked is what this seam exists to remove.
1335
+
1336
+ - 8053dc1: An optional pseudo-terminal in the local sandbox, refused rather than faked when the binding is absent.
1337
+
1338
+ `exec` runs a command and hands back what it printed. A large class of work does not fit that shape: an interactive installer waiting on a prompt, a REPL, `git rebase -i`, anything that draws with escape codes, anything that asks for a password.
1339
+
1340
+ **The refusal is the design.** A pseudo-terminal needs a native binding this kernel deliberately does not depend on — it would make every install build C++ for a capability most runs never use. So `Sandbox.openTerminal` is optional, and where the binding is unavailable it **throws** rather than substituting a pipe. A pipe would appear to work: bytes flow, `spawn` succeeds, and every program that calls `isatty` takes its non-interactive branch. The prompt never appears, the REPL exits immediately, the progress bar prints ten thousand lines, and nothing says why. Same rule `Sandbox.setNetworkPolicy` already states, for a sharper reason.
1341
+
1342
+ The refusal names the package, tells `absent` from `broken` (the second is almost always a native build compiled against a different Node version, and telling somebody to install a thing they already installed is the least useful message available), and points at `exec` while saying `exec` is not a terminal.
1343
+
1344
+ `TERM` is set to `xterm-256color`, which is not cosmetic: it is how a program decides which escape sequences it may emit, and unset makes well-behaved programs fall back to no colour and no cursor movement — a terminal that works and looks broken. `size` is required rather than defaulted, because a program asks the terminal how big it is before it draws anything.
1345
+
1346
+ **The local implementation is deliberately not confined by the isolation tier**, and says so at the site: `exec` wraps every command in `unshare`/`sandbox-exec`, and wrapping an interactive session would put the tier's own shell between the operator's keystrokes and the program. It runs in the sandbox's root directory and nothing more. A host that needs the tier uses `exec`, or a backend whose terminals are confined by construction.
1347
+
1348
+ - 9142405: Child loggers name their scope with a reserved attribute instead of an
1349
+ unnamespaced `component` key.
1350
+
1351
+ `.child({ component: 'ToolRegistry' })` put a bare `component` key into the
1352
+ attribute bag of every record that logger emitted. It collides with nothing
1353
+ today and with anything tomorrow: OTel's semantic conventions own the
1354
+ unprefixed namespace, and a record whose attributes carry both a
1355
+ convention-defined key and this one has no way to say which meant what.
1356
+
1357
+ `SCOPE_ATTRIBUTE` is a reserved key that both logger backends — the OTel-shaped
1358
+ pipeline and the legacy `Logger` that `getRootLogger()` returns — lift onto
1359
+ `scope.name` and remove from `attributes`, so the value lands in the field the
1360
+ Logs Data Model has for it rather than beside it. Thirteen of the SDK's
1361
+ forty-eight binding sites are converted here; the gate's
1362
+ `unnamespacedBindingCount` ratchet moves 48 → 40 and the rest follow.
1363
+
1364
+ The ratchet is why this can land in pieces without the remainder being
1365
+ forgotten: it fails on any mismatch, so each batch has to write its own number
1366
+ down.
1367
+
1368
+ - 4ccf9e3: A compaction no longer deletes its own evidence. A new `compaction_shed`
1369
+ run event carries exactly the messages a pass removed.
1370
+
1371
+ `compaction_completed` carried counts and nothing else, both shed sites
1372
+ replace the live message array, and `persist()` writes `messages.json`
1373
+ wholesale afterwards — so what a pass removed existed nowhere: not in
1374
+ memory, not on disk, not in the transcript. "What did the agent decide
1375
+ three compactions ago" was unanswerable, an undo had no input, and a search
1376
+ index over run history could never see the part that mattered most.
1377
+
1378
+ Emitted BEFORE the array is replaced, at both shed sites — the structured
1379
+ pass and the host-supplied-reducer path. `transcript.jsonl` is append-only
1380
+ and `emitEvent` reaches it synchronously with the pass, so the record is
1381
+ durable before the deletion is; emitted after, a crash between the two
1382
+ loses exactly what this keeps.
1383
+
1384
+ The event carries whole message bodies including tool output, so both the
1385
+ SSE and A2A mappers decline it: a subscribed client receives no frame with
1386
+ shed content in it. The run reporter ignores it too.
1387
+
1388
+ `compactionConfig.recordShedHistory` defaults to `true` and turns it off
1389
+ for an operator with a transcript-size constraint. That is a real trade —
1390
+ the transcript grows by roughly what the compaction saved, since keeping
1391
+ the bodies is the point.
1392
+
1393
+ This does not change the model that the message array is the source of
1394
+ truth for a live run; it adds a parallel append-only record beside it.
1395
+
1396
+ - 2df8cd2: A skill says who may invoke it: the model, the operator, or both.
1397
+
1398
+ Every skill was offered to the model and to nobody else, and both halves of that are wrong. A skill only an operator can meaningfully run — "collect a support bundle", "rotate the deploy key" — sat in the model's manifest as something to attempt, and the model would attempt it. A skill that is pure model guidance had no way to be offered to an operator at all.
1399
+
1400
+ New: the `invocation` frontmatter field (`model` | `operator` | `both`), `skillInvocation()` and `isInvocableBy()`. `both` is the default because it is what every existing skill silently was, and narrowing one is a decision its author makes rather than one a version bump makes for them.
1401
+
1402
+ The field is **optional on `SkillMetadata` and not defaulted at parse**, so a stored skill records what its author wrote rather than what this version happened to default to; the default is resolved in one function, because four readers each writing `?? 'both'` is three chances for them to disagree.
1403
+
1404
+ Both sides are driven. `renderSkillsSection` carries only what the model may invoke — including the loaded BODY, since an operator-only skill whose body was pasted in while being absent from the manifest is the worst of both — and returns null rather than an empty manifest block. A new kernel `/skills` command lists only what an operator may invoke, refusing (not reporting zero) when the run has no skills registry.
1405
+
1406
+ A value that is not one of the three is **refused at load**. A typo'd `invocaton: operator` that quietly resolved to `both` would put an operator-only skill back in front of the model, which is exactly what the field exists to stop, and the author would have no way to tell.
1407
+
1408
+ - f9833ab: A `skill` tool, and `allowed-tools` that actually narrows.
1409
+
1410
+ The manifest told the model a SKILL.md exists and to "read the SKILL.md at its `<location>` before writing code" — a filesystem instruction. A run without filesystem tools could see every skill it had and open none of them. The protocol text even hedged: _"when the runtime exposes filesystem or skill-loading tools"_. There was no skill-loading tool.
1411
+
1412
+ `allowed-tools` failed from the other side: parsed, stored on `SkillMetadata`, rendered into the prompt as `<allowed_tools>…</allowed_tools>`, and read by nothing. It was advice the model could ignore, phrased as a declaration.
1413
+
1414
+ New: `SkillTool`, `SkillRegistryRef` on `ToolContext`, and `skillRegistry` on `query`. The tool is **not** in the default builtin set — a run with no skills has nothing for it to do, and offering a tool that can only refuse is worse than not offering it.
1415
+
1416
+ A loaded skill's `allowed-tools` is **adopted**, on the same line that already enforces the step's list. Two properties make it safe:
1417
+
1418
+ - It **intersects** what the turn already allows and can never widen it. A skill file is content, and content that can grant tools is a privilege-escalation surface wearing the word "scope" — the same rule `CreateTaskOptions.toolScope` states for delegation.
1419
+ - It lands on the **next** batch. A skill loaded alongside other calls must not retroactively refuse them: the model chose that batch under the old scope, and refusing half of it teaches nothing except that tools fail at random.
1420
+
1421
+ The `skill` tool itself always survives a narrowing, or a skill could narrow the model out of reaching for another skill — a one-way door.
1422
+
1423
+ `allowed-tools: ""` means no tools, and stays distinguishable from declaring nothing at all: collapsing the first into the second would silently widen it to everything. An operator-only skill is refused at the tool even though the manifest omits it — a check that only filtered the listing would be a menu restriction rather than a kitchen one, which is the defect `allowedTools` had.
1424
+
1425
+ - cf48cef: New durable run event `request_envelope`, carrying `{ iteration, model, systemPrompt, toolNames, toolSchemaDigest }`. Emitted only when the tuple differs from the last one the run recorded.
1426
+
1427
+ `run_started` records a system prompt once, and tool schemas never reached the transcript at all — while `prepareStep` rewrites the system text, narrows the tool list or swaps the model between iterations, and a step's skills ride an ephemeral trailing system message. So everything about _what_ was asked could change, and the durable record said it had not.
1428
+
1429
+ **Only on a change**, and the suppression is not a performance detail: copying an unchanged system prompt into every iteration is the fastest way to make a transcript too large to read. A run whose request never varies emits exactly one.
1430
+
1431
+ The digest is over the tool **schemas**, sorted, not their names. A name list cannot see a tool whose schema body moved while its name did not — the change most likely to alter what the model does and least likely to be noticed.
1432
+
1433
+ Declined by both wire mappers: a live consumer can already read the prompt off the stream, the payload is the largest the kernel emits, and what this runtime asked its own model is not a fact about the task an A2A peer is tracking. The run reporter logs it at `debug`.
1434
+
1435
+ - 2ccbd7b: Drivers now identify this kernel to the provider they call. New `NAMZU_APP_IDENTITY` and `attributionHeaders(identity?)`, merged at each driver's existing header seam — OpenAI, OpenRouter, the generic HTTP driver, Bedrock, and Anthropic's **api-key path only**.
1436
+
1437
+ No driver did this. The single user-agent anywhere was on Anthropic's OAuth path, set because the token-exchange endpoint rejects subscription tokens without it — load-bearing impersonation, not attribution, and untouched here. Merging into that branch would not have improved a label; it would have broken login intermittently, with a 401 or 500 naming none of it.
1438
+
1439
+ What attribution buys is not vanity: a vendor reading its own logs can tell a kernel's traffic from a browser's, a rate-limit or abuse investigation lands on the right party, and a driver bug a vendor reports arrives with something to search for.
1440
+
1441
+ Exactly one header, asserted by a test that counts the keys — every additional one is something a proxy may strip and a reader has to reconcile. The version is read from the package manifest, never hand-copied. A host may pass its own identity, and the driver seams honour it rather than the constant.
1442
+
1443
+ LM Studio and Ollama record `attribution: { kind: 'unsupported', reason }` in their conformance options: their vendor clients own the transport and expose no header seam. The suite requires the declaration either way, so a new driver package cannot skip the decision.
1444
+
1445
+ - f2a1dd9: Thread one correlated logger through a run's provider retry and fallback wrappers
1446
+
1447
+ `RunContextFactory.buildLogger(config)` is new: it does what `build` used to do inline — bind a run's `namzu.run.id`, `sessionId`, `threadId`, `projectId` and `tenantId` onto a logger — but as a standalone static method a caller can invoke BEFORE `build` runs. That matters because `runtime/query/index.ts` builds the provider retry and fallback wrappers before it calls `build` (the wrapped, resilient provider is itself one of `build`'s own inputs), so those two wrappers previously had no correlated logger to reach for and each fell back to a bare `getRootLogger()` — the highest-frequency uncorrelated log path in the kernel: every "failed, retrying" and "falling over" line carried no run id at all. `query()` now calls `buildLogger` once, before the chain is wrapped, and passes the SAME logger to `withProviderRetry`, `withProviderFallback`, the boot-time filesystem migration's own log lines, and `build`. `build` accepts a pre-built logger via the new `RunContextConfig.log` and only constructs its own — via `buildLogger` — when none is supplied, so every existing direct caller of `build` is unaffected.
1448
+
1449
+ **`AgentRunConfig` gains an optional `logger?: Logger`.** A host that sets it is not opting out of correlation — `buildLogger` still calls `.child()` on whatever it resolves to, so the run's ids are still bound — it is choosing the SOURCE every record for this run derives from, instead of the process default `getRootLogger()` picks up.
1450
+
1451
+ Neither `runtime/query/context.ts` nor `runtime/query/index.ts` reads `getRootLogger()` anymore. The one fallback-to-process-default read that remains lives in a new `resolveLogger` helper in `utils/logger.ts` (SDK-internal — not re-exported from the package root, so this does not touch the public surface baseline), which `buildLogger` calls when no host logger was supplied. `scripts/log-standard.json#getRootLoggerCount` moves 40 → 37: four call sites removed across the two `runtime/query/` files (the run's own child-logger construction, the retry wrapper's read, the fallback wrapper's read, and the boot-time migration's own read — it now shares the same run-scoped logger instead of a separate `getRootLogger()` call), one added in `resolveLogger`.
1452
+
1453
+ - ad98269: Tools now decide how their calls and results are shown, and the CLI stopped
1454
+ matching on tool names.
1455
+
1456
+ `write` gains `presentCall`, returning a diff with an empty `before` —
1457
+ which is what a write is: whatever was there is gone and this replaces it.
1458
+ `edit` and `write` both gain `presentResult` returning a plain label, which
1459
+ is what suppresses the detail block: the content was already shown under
1460
+ the call, and repeating it doubles the longest rows in a transcript to say
1461
+ nothing new. That decision used to be a host matching two names.
1462
+
1463
+ `createToolPresenter`'s result fallback changed from a `generic` view
1464
+ truncated to 120 characters to a `terminal` view carrying the whole output.
1465
+ A host renders a result across many rows and decides for itself how many
1466
+ fit — that is a property of its terminal, not of the tool — and truncating
1467
+ in the kernel destroyed text no host could then recover. A tool that wants
1468
+ the one-line form returns a `generic` view itself.
1469
+
1470
+ In the CLI this deletes `summarizeToolInput`, `previewToolInput`,
1471
+ `toolStartDetail` and `toolEndDetail`, replacing four name-matching
1472
+ functions with one `viewToLines`. A tool the CLI has never heard of — an
1473
+ MCP server's, a plugin's — now gets a diff if it asks for one, where before
1474
+ it got a truncated JSON blob no matter what it did.
1475
+
1476
+ - 50c0f29: `Topic` becomes the primary name for the container between Project and Session.
1477
+ Every exported `Thread*` name keeps working as a `@deprecated` alias.
1478
+
1479
+ The layer has always been a topic — its own docstring calls it a "Topic-level
1480
+ container" — and `Thread` is the one word in this kernel's OS vocabulary that
1481
+ already means something specific and different, for a thing that has no
1482
+ execution and no state machine of its own.
1483
+
1484
+ Renamed, with identity aliases on the public surface: `TopicManager` /
1485
+ `ThreadManager`, `InMemoryTopicStore` / `InMemoryThreadStore`,
1486
+ `generateTopicId` / `generateThreadId`. `TopicId` is a type alias to the
1487
+ unchanged `ThreadId`; both are still `` `thd_${string}` `` this release.
1488
+
1489
+ **Not in this release**, and deliberately: the `thd_` prefix itself, the
1490
+ `threadId` field on persisted records, and `acceptLegacyThreadId` /
1491
+ `rejectLegacyPrefix`. The last two belong to a DIFFERENT `thd_` — the
1492
+ pre-0.2.0 top-level container the migration coerces to `prj_legacy_*` — and
1493
+ merging the two meanings is the confusion this chain exists to end. The prefix
1494
+ and the field each carry a data migration and land separately.
1495
+
1496
+ - c665956: A `turn` placement, for state that changes during a run.
1497
+
1498
+ `static` is cached across turns and `dynamic` is part of the system prompt, so neither can carry a budget running down, a queue draining, or a policy that just moved: one serves the first iteration's value forever, and the other is read as a standing instruction rather than as a status.
1499
+
1500
+ `turn` is a third thing, not a looser `dynamic`. It rides the ephemeral trailing message that a step's guidance, its skills and the approval-policy notice already use — appended to the request, never pushed onto the run's history, gone the moment the request is sent. `PromptContributionContext.iteration` is present only for this placement, which is the type stating what the placement means: a contribution that needs to know which turn it is cannot be part of a prompt assembled once and cached.
1501
+
1502
+ The builder **refuses** to render `turn`, and its signature says so. In the system prompt it would be cached for the run or read as standing instruction, and either way the state it exists to report goes stale silently.
1503
+
1504
+ The cost is real and stated: every iteration pays for it in tokens, and it lands after the cached prefix so it cannot be cached. The approval-policy notice is the shape to copy — text only when something actually changed, `null` on every other turn.
1505
+
1506
+ The prompt cache hashes contribution ids and placements, not rendered text: hashing output would run every contribution twice per request for a value the cache exists to avoid computing, and a contributor whose output changes while its id does not is exactly the one that must declare `dynamic` or `turn`. The static-segment hash folds in `static` contributions only, so a `turn` contributor coming or going does not invalidate a prefix it does not describe.
1507
+
1508
+ - 70e3163: A web connector seam: a guarded fetch provider, and no bundled search vendor.
1509
+
1510
+ Two providers, separated on purpose. **Fetching a URL is a capability this kernel can implement** — the rules are about the network and the same everywhere, so a wrong answer is a defect rather than a preference. **Searching is not.** Every search backend has its own account, its own terms, its own result shape and its own opinion about what a result is, and picking one here would make that choice for every consumer while adding a dependency nobody asked for. `WebSearchProvider` is declared and ships with no implementation; that asymmetry is the design, not an omission.
1511
+
1512
+ `GuardedFetchProvider` exists because a URL a model chose is untrusted input reaching the network stack, and the network the agent runs on is not the network the model is thinking about. `http://169.254.169.254/` is a cloud metadata endpoint holding credentials; `http://localhost:6379/` is whatever the host runs on 6379; `file:///etc/passwd` is not even the network.
1513
+
1514
+ What it does, and why each one:
1515
+
1516
+ - **Refuses before sending.** A response already fetched is a request that already happened, and against a metadata endpoint the request _is_ the exfiltration.
1517
+ - **Resolves the hostname and checks the addresses**, not just the name. A name whose A record points inside is something anyone can set up on a domain they own. A resolution that fails, or returns nothing, is **refused** — treating either as "no private addresses found" is fail-open.
1518
+ - **Re-checks every redirect hop**, with `redirect: 'manual'`. Checking once and letting the platform follow is the classic version of this bug: a permitted page answers `302 → the metadata endpoint` and the guard never sees it. Relative `Location` headers are resolved against the current URL, or the URL checked would not be the URL followed.
1519
+ - **Strips `authorization`, `cookie`, `host` and `proxy-authorization`** from caller-supplied headers, case-insensitively. A tool argument is model-authored, and those turn "fetch this page" into "fetch this page as me".
1520
+ - **Reports truncation** rather than returning a cut page as whole, and reports the whole redirect chain so a citation can name where content came from.
1521
+
1522
+ `allowPrivateAddresses` exists for the one legitimate case — a fixture on `127.0.0.1` — and defaults off, so it is a decision a host makes rather than inherits. The residual DNS-rebinding gap is stated in the source: closing it needs a `fetch` that pins the address it checked, which the platform gives no way to do, so a host that needs it supplies its own.
1523
+
1524
+ - 5f8a8c5: The web tools' citation guidance ships through the prompt contribution registry.
1525
+
1526
+ Not in the tool descriptions. A description is repeated in the schema of every request and has to earn its tokens per call, so it says what the tool _does_. How to use two tools together — search, then fetch, then cite what you read — belongs to neither of them, and splitting it across both would send it twice while still leaving the joint rule homeless.
1527
+
1528
+ `webGuidanceContribution` is `static`: it depends on nothing that can change inside a run, so it rides the cached prefix rather than being re-sent. It is registered by a host only when the web tools are, because guidance about tools a run does not have is worse than absent — it spends the cached prefix telling the model to cite results from a search it cannot run.
1529
+
1530
+ What it says, and each line is pinned by a test: a snippet is the provider's summary and not the page; fetch before relying on a result, and say so when a fetch was refused rather than falling back to the snippet; cite where a fetch _landed_, not where you asked; say when a page was cut at the limit; and a fetched page is untrusted text whose instructions are content to report, never directions to follow.
1531
+
1532
+ This is the case the contribution registry was built against: a capability that needs the model to know something, arriving with the capability rather than by editing the prompt builder.
1533
+
1534
+ - 5ed3b03: `web_fetch` and `web_search`, declaring `category: 'network'` so they inherit the permission surface — and a read-only network tool no longer auto-approves itself.
1535
+
1536
+ Both tools declare `category: 'network'`, which is what the authorization presets branch on. Under `sandboxed` and `sandboxed-shell` they go to a human; only `unattended` — the preset that requires the sandbox to enforce network isolation — auto-approves them. The tests assert that against the real gate rather than against a property of an object, because the category is only meaningful through the gate.
1537
+
1538
+ **That claim was false when the tools landed, and fixing it is half this change.** `presets.ts` has always documented that a `network` tool goes to review under the sandboxed presets. It did not: `allow_read_only` is appended last as a default for tools nobody wrote a rule about, and it resolved purely through `isTrustedReadOnly` — which asks whether the read-only _claim_ is trustworthy and never what channel the call travels over. A read-only network call matched the default and was approved without review, in the preset whose own docblock said it would not be.
1539
+
1540
+ So the allowance is narrowable by category: `allowReadOnlyExcludeCategories` rides along on the rule the gate appends, and both sandboxed presets exclude `network`. Trusting a claim and matching the default stop being the same question. The field is optional rather than defaulted — `undefined` and `[]` are read identically, and defaulting it would break every hand-authored gate config for no behavioural gain.
1541
+
1542
+ **Breaking:** a read-only tool in an excluded category that used to auto-approve under `defaultSandboxedGateConfig` or `defaultSandboxedShellGateConfig` now goes to review. A host that wants the old behaviour passes `allowReadOnlyExcludeCategories: []` explicitly.
1543
+
1544
+ `web_search` was already a name in this tree: two fixtures invented it, one for a deferred-loading catalog test and one for a network gate test, both describing a tool nobody had written. Reconciled rather than renamed.
1545
+
1546
+ Neither tool is in the default builtin set, and `search` missing is the ordinary case — this kernel ships no search backend. The tools say which piece is absent, so an operator can tell a wiring decision from a fault.
1547
+
1548
+ ### Patch Changes
1549
+
1550
+ - dd170fe: A default-level start is readable again, and a misplaced global flag says where
1551
+ it goes.
1552
+
1553
+ `ManagedRegistry.register` logged at `info`, once per item, and a CLI run
1554
+ registers dozens — every builtin tool, every agent, every task tool. Turning
1555
+ the logger back on therefore replaced silence with twenty lines of
1556
+ `Registered: read`, `Registered: write` ahead of anything an operator could act
1557
+ on. Registration is the startup path working; it belongs at `debug`. The
1558
+ overwrite case stays at `warn`, because a second registration under a live id
1559
+ is news.
1560
+
1561
+ `namzu run "…" --verbose` was answered with "pass `--` before a prompt that
1562
+ starts with a dash" — advice about a prompt beginning with `-`, which sends the
1563
+ reader to the wrong half of their command line. `--verbose`, `--quiet`,
1564
+ `--log-format` and `--format` are program options, accepted before the command
1565
+ name, and the refusal now says exactly that and shows the position.
1566
+
1567
+ Both were found by running the CLI against a real provider. Every unit test in
1568
+ these paths asserts against a logger stub or passes flags in the position that
1569
+ already worked, so neither was visible to any of them.
1570
+
1571
+ - 2928057: The task and session disk stores now read, write and scan through the
1572
+ shared `DiskRecordStore` primitive instead of hand-rolling each.
1573
+
1574
+ Between them they carried two private `readJson`/`atomicWriteJson` pairs
1575
+ and sixteen `readdir` scans — the same twenty lines, four times over, in
1576
+ the two stores whose scan semantics the comments themselves call subtle.
1577
+ Every property fixed in one had to be remembered into the others, and the
1578
+ properties are not obvious ones: a missing file is an empty read rather
1579
+ than an error, a record from a newer build is refused rather than read
1580
+ partially and written back with the difference gone, and a listing needs a
1581
+ stable order.
1582
+
1583
+ No behaviour changes. The append-only session event log and
1584
+ `messages.jsonl` are deliberately left alone — they are log-shaped, not
1585
+ record-shaped, each line is a whole record carrying its own stamp, and
1586
+ forcing them through a record store would be a worse fit than the
1587
+ duplication it removes.
1588
+
1589
+ - 014da58: 419 of the SDK's log attribute keys are namespaced, and one of them was naming the wrong thing.
1590
+
1591
+ `{ runId }` is now `{ [NAMZU.RUN_ID] }` (`namzu.run.id`), `{ error }` is `exception.message`, `{ tool }` and `{ toolName }` are both `gen_ai.tool.name`, `{ iteration }` is `namzu.iteration`, and so on across 47 files. The bare keys they replace collide with whatever the next feature calls its own `status` or `code`, and they do not sort next to the `namzu.*` / `gen_ai.*` / `exception.*` keys the rest of the telemetry surface already uses — which is the whole reason the rule exists.
1592
+
1593
+ Two of the mappings are worth naming rather than listing:
1594
+
1595
+ **`sessionId` was a run id.** Four call sites in the iteration phases wrote `{ sessionId: ctx.runMgr.id }`, and `RunManager.id` is a `RunId`. An operator filtering by session id found nothing, and one filtering by run id missed those four records. They now write `namzu.run.id`, which is what the value always was.
1596
+
1597
+ **`error` becomes `exception.message`, not `namzu.error`.** Every one of the 77 sites bound a message string — `toErrorMessage(err)`, `err.message`, `String(err)` — so the OpenTelemetry key is the accurate one, and it puts these records under the same key as `exceptionAttributes()` in `utils/log/exception.ts` already produces.
1598
+
1599
+ **If you query these logs, your field names change.** The values are untouched; only the keys move. A dashboard grouping by `runId` needs `namzu.run.id`, an alert matching `error` needs `exception.message`. Nothing fails to compile — `LogContext` has always accepted any key — which is exactly why this is worth stating: the change is invisible until a panel goes empty.
1600
+
1601
+ `scripts/log-standard.json`'s rule-4 ratchet moves 794 → 375. The remainder is a long tail of keys appearing once or twice in a single module, where the namespace has to come from the module rather than from a shared constant.
1602
+
1603
+ - 7aaa35d: Strings that were asserted into ids now go through the checked constructors, and three defects the assertions were hiding are fixed.
1604
+
1605
+ **A docker sandbox's id had the wrong prefix.** `SandboxId` is `` `sbx_${string}` ``; `@namzu/sandbox`'s docker backend minted `sandbox_...` and an `as SandboxId` was the only reason that compiled. Every docker sandbox in the tree carried an id its own type says is impossible — the ACI backend already minted `sbx_`. Both now mint through `asSandboxId`, which is the call that would have caught it. **The container name derives from this** (`namzu-sandbox-${id}`), so a container started by this release is named differently from one an older build started. Nothing matches on the old spelling — teardown computes the name from the id it just minted, in the same process — but it is visible in `docker ps`, and any external tooling that pattern-matched `namzu-sandbox-sandbox_` needs updating.
1606
+
1607
+ **A corrupt migration marker was honoured instead of refused.** `readMarker`'s shape check validated the envelope — `version`, `at`, and that `migratedThreads` is an array — and never looked inside the array. `{"migratedThreads":[null]}` therefore parsed cleanly and produced an entry whose `newProjectId` was `undefined` wearing a `ProjectId` annotation, which then reached a path join. Each element is now checked, and a bad one returns `null` — which is exactly what this function already promised to do about corruption, so the caller re-runs the migration rather than trusting it.
1608
+
1609
+ **`namzu drain` accepted a mistyped scope flag.** `--tenant`, `--project` and `--session` were asserted straight into their id types, so `--tenant prj_a` reached the store and listed nothing — and "no runs" is the same output as a scope that really is empty, which made the typo invisible. Each flag is now prefix-checked, and the refusal names the prefix it wanted, in the same operator-readable shape the command's other refusals use.
1610
+
1611
+ **Model-authored ids are checked before they become store keys.** `read_memory`, `task_update` and the RAG tool took an id straight from the model's tool input and asserted it. A malformed one read back as "not found", telling the model its record had disappeared rather than that it named the wrong thing. All three now refuse with `InvalidIdError`, whose message says which prefix was expected.
1612
+
1613
+ Nothing here changes an exported type, a signature or a default. Sites where a cast is still correct — a value already guarded by an explicit prefix check, an id minted by a service outside this repo, a sentinel the type cannot express — keep the cast and now carry the reason next to it.
1614
+
1615
+ - ae09a42: An isolated code runtime seam and its `worker_threads` backend — internal, and not yet on the public surface.
1616
+
1617
+ A model that can write a loop does in one call what currently costs twenty: filter a list, retry with backoff, fan out over files. Each of those is a control-flow shape the tool loop expresses by taking a full model turn per step, at full context size, with the whole conversation resent each time.
1618
+
1619
+ The difficulty is that the program is untrusted text. Not code an operator installed — a string the model produced, possibly under the influence of a web page it was told to summarise. So the seam is defined by what a backend must **guarantee**: no ambient capability, a single channel back to the host, and bounds on wall clock and output enforced by the backend rather than asked of the program.
1620
+
1621
+ `worker_threads` over `vm`, because `vm` is not a sandbox and its own documentation says so: a context shares the process, and `this.constructor.constructor` on any leaked object is the whole escape. Over a subprocess, because a subprocess inherits an environment, can be a fork bomb, and needs the process-tree kill. What a worker does _not_ give is stated in the source: it shares the process's filesystem and network. What confines the program is a scope with nothing in it, which is a language-level boundary — exactly as strong as the enumeration of what was withheld. A host needing an OS boundary runs this inside a sandbox that has one.
1622
+
1623
+ The allow-list is enforced on the **host** side. A check inside the worker is a check the program shares a heap with.
1624
+
1625
+ Nothing is exported yet, deliberately: a seam with one backend and no consumer is a guess at what a consumer needs. The public surface joins in the commit that has one.
1626
+
1627
+ Also corrects `coverage-config.json`'s `baselineExempt` list, which the test-presence gate documents as "current zero-tested modules". Seven of its nine entries carried tests — `utils` had twenty-five files — so the list said "these have no tests" about modules that did. A routing document that is false is worse than none, because the next person picks the wrong module to work on. `model-router` and `persona` are the two that genuinely have none.
1628
+
1629
+ - bab1e02: The compaction pass is now decided by a pure planner that needs no run.
1630
+
1631
+ The whole algorithm — the leading-system floor scan, the tool-result
1632
+ pre-pass, the boundary search and its guards — lived inside
1633
+ `runCompactionCheck` and read the live message array, the logger and the
1634
+ event emitter off an iteration context. Nothing outside a live iteration
1635
+ could run it, so the pass was testable only through a full run harness and
1636
+ unreachable from any host-callable entry point.
1637
+
1638
+ Everything with an effect stayed where it was: the model call, the
1639
+ working-memory re-pin, the array install, the logging, every event. The
1640
+ arithmetic moved. No behaviour changes and the emitted event and log
1641
+ sequence is identical; the planner is internal to the package.
1642
+
1643
+ This also removes a second copy of the token-budget boundary helper that
1644
+ had been living in the phase file behind a test-only export.
1645
+
1646
+ - 47437f6: Internal directory move: `src/bridge/tools/connector/` is now `src/connector/tools/`. No exported name, signature or behaviour changes — every affected symbol is re-exported from the package root exactly as before.
1647
+
1648
+ `bridge/` is protocol boundaries: `bridge/a2a/`, `bridge/mcp/` and `bridge/sse/` each speak a wire format to something outside the process. The connector tool adapter speaks no protocol; it turns a connector's methods into tool definitions, which is connector work. It sat under `bridge/` because it is adjacent to MCP, not because it belongs to a boundary, and `bridge/tools/` had no second occupant to justify the level.
1649
+
1650
+ - 40932a1: Every attribute key the SDK writes to a log record is namespaced. The rule-4 ratchet reaches 0, and with rule 3 already there, both are now floors rather than budgets: the first new bare key in a `Logger` call fails CI, not the hundredth.
1651
+
1652
+ This is the long tail after the shared-constant pass — 375 keys across 229 distinct names, almost all appearing once or twice in a single module, where no shared constant applies. They are namespaced by the module that writes them: `namzu.provider.status` and `namzu.run.status` are now different keys, which is the collision the rule exists to stop and which `{ status }` could not express.
1653
+
1654
+ Two defects the pass turned up:
1655
+
1656
+ **Two emitters of the same event wrote two namespaces for one fact.** The boot-time filesystem migration is logged from `session/migration/filesystem.ts` and again, for the nothing-to-do outcomes, from `runtime/query/index.ts`. Both carry `namzu.migration.completed` as their event name, and a per-module namespace gave them `namzu.migration.kind` and `namzu.runtime.kind`. An operator grouping that event by outcome would have seen half of it. Both write `namzu.migration.*` now.
1657
+
1658
+ **The renderer for that event asked for a key nothing writes.** `utils/log/templates.ts` rendered `namzu.migration.completed` as the body plus `namzu.migration.root`, and no emitter has ever produced `namzu.migration.root` — so the operator's migration line appended an empty string. It renders `namzu.migration.kind` now, which is the fact worth seeing: `migrated`, `already_migrated`, or `noop_no_legacy`.
1659
+
1660
+ **If you query these logs, your field names change.** Values are untouched; only keys move. `{ reason }` is `namzu.<module>.reason`, `{ charsShed }` is `namzu.runtime.chars_shed`, and so on. Nothing fails to compile, because `LogContext` accepts any key — which is why this is worth stating: the change is invisible until a panel goes empty.
1661
+
1662
+ - 0dbf62f: Fix `LocalSandbox.exec()` leaving a cancelled or timed-out command's own children running.
1663
+
1664
+ Every sandboxed command runs as `sh -c "cmd"` (and, under the strongest local isolation tier, wrapped again in `unshare`), and on abort the local backend only ever signalled the outermost process Node itself spawned — never `cmd`, and never anything `cmd` (or the isolation wrapper) itself forked. A caller cancelling a run, or a run hitting its timeout, could leave the actual work running in the background indefinitely — and in the common case where the shell forks a real child rather than exec-replacing itself, the orphaned descendant kept the command's own stdio pipes open, so `exec()` itself never resolved at all.
1665
+
1666
+ The command is now spawned as the leader of its own process group (POSIX) and the whole group is signalled — SIGTERM immediately, SIGKILL after the existing `SANDBOX_KILL_GRACE_MS` grace period — instead of just the direct child pid. Windows has no process-group id to sign a kill with, so there the process tree is reaped with `taskkill /pid <pid> /t /f` instead, applied on both the immediate and the post-grace call since Windows has no soft-vs-forced signal distinction to grace between.
1667
+
1668
+ No public API change — `Sandbox.exec()`'s signature, options and result shape are all unchanged; this is a runtime behavior fix only.
1669
+
1670
+ - f8f0004: Skill and plugin discovery loggers respond to configureLogger again
1671
+
1672
+ `skills/loader.ts`, `skills/registry.ts` and `plugin/loader.ts` each built their logger once, at module-eval time, via a top-level `const logger = getRootLogger().child({...})`. `child()` bakes the root logger's level into the closure it returns, and the module graph loads before any host's `configureLogger()` call has run — so whatever level was live at that moment was permanent. No later `configureLogger()` call, from a host application or from the CLI's own silencing, could ever reach these six log lines.
1673
+
1674
+ Each of the six call sites (`loadSkill`, `discoverSkills`, `SkillRegistry.registerAll`, `resolveSkillChain`, `discoverPlugins`, `discoverAllPluginDirs`) now resolves its own `getRootLogger().child(...)` at the top of the function body, at call time — matching the idiom already used elsewhere in the kernel (`runtime/query/context.ts`, `run/reporter.ts`, `agents/RouterAgent.ts`).
1675
+
1676
+ No exported signature changed. A host that never calls `configureLogger()` sees identical output; a host that does now gets what it asked for.
1677
+
1678
+ - 43358a1: `docs/sdk/observability/logging.md` now covers the whole log pipeline — where a host installs its own sink, what the level/throw/counter contract is, how records correlate to spans, and how to write an adapter for a collector with a nested attribute schema — alongside the `LogAttributes` and log-forging material it already carried. The page joins the documentation standard, and `docs/sdk/observability` joins the docs gate's authoritative set.
1679
+
1680
+ The adapter it shows is not typed into the page. It is `packages/sdk/src/__fixtures__/nested-attribute-sink.ts`, embedded verbatim, driven through the real pipeline by a test, and asserted byte-identical to what the page prints — so it cannot compile against an API that no longer exists while still reading as authoritative.
1681
+
1682
+ - 6e11fd7: Every diagnostic these two packages emit now has a constant message body, and the identifiers that used to be interpolated into it are attributes beside it.
1683
+
1684
+ 87 `Logger` call sites across 29 files were rewritten. `` `Tool execution error: ${toolName}` `` is now `'Tool execution error'` with `namzu.tool.name` in the attribute bag; `` `Tenant registered: ${id} (${name})` `` is now `'Tenant registered'` with `namzu.tenant.id` and `namzu.tenant.name`. Where the neighbouring bag already carried the value, only the message changed; where it did not, the value moved into a new `namzu.*` key in the same edit — a constant body that costs an operator the identifier would be a worse record, not a compliant one.
1685
+
1686
+ **If you grep, alert on, or group by these message bodies, your queries need updating.** No exported type, signature or default changed, and nothing fails to compile — this is diagnostic output, not API — but a log pipeline matching the old interpolated text will stop matching. The upside is the reason for the change: an operator can now grep one literal for every occurrence of an event, and a dashboard can group by it, neither of which was possible when each occurrence rendered a different string.
1687
+
1688
+ `scripts/check-log-standard.mjs`'s rule-3 ratchet (`constantBodyViolationCount`) goes 87 → 0. At zero it stops being a budget and becomes a floor: the _first_ new template literal in a `Logger` call fails CI, not the hundredth. Rule 4 (`namespacedAttributeKeyViolationCount`) is unchanged at 794 and still being worked down.
1689
+
1690
+ - 79ed788: Internal directory rename: `src/router/` is now `src/model-router/`. No exported name, signature or behaviour changes — `resolveTaskModel` is imported from the package root as before.
1691
+
1692
+ `router/` said nothing about what it routes, and the SDK has two unrelated routing concepts: this one picks a MODEL for a task, while `types/router/` holds `TaskRouterConfig`/`TaskType`. Those two sat next to each other under names a reader could not tell apart. `types/router/` stays where it is — it is the config shape, filed with the other types.
1693
+
1694
+ - c166029: Delete `DiskThreadStore` — a filesystem persistence backend for the Thread layer that no production code ever constructed
1695
+
1696
+ `new DiskThreadStore` appeared zero times in the monorepo outside its own module (`store/thread/disk.ts` and its re-export in `store/thread/index.ts`). It was never exported from `public-runtime.ts` — only `InMemoryThreadStore` was, and still is — and it never entered `.github/scripts/public-surface-baseline.json`, so no consumer inside this repo or out of it could ever have imported the type, let alone constructed it. `@namzu/sdk`'s `package.json#exports` map only publishes `"."` and `"./testing"`, so even a deep import could never have reached it. There was also no `store/thread/__tests__` directory: 220 lines of write-tmp-rename persistence, an id→path index, a CAS path and a tenant guard, with no test exercising any of it.
1697
+
1698
+ The CLI wires `InMemoryThreadStore` for threads today (`ThreadManager({ threadStore: new InMemoryThreadStore(), sessionStore })`, `integrations/subagents/runtime.ts`), even though it wires `DiskSessionStore` for sessions in the same function — the Thread layer does not survive a process restart regardless of which store class exists in source, so removing the unused disk backend changes nothing about what a running `namzu` actually persists.
1699
+
1700
+ This also had a live, untested correctness defect, deleted along with the code: `listThreads` filtered directory entries by name (`entry.startsWith('thd_')`) but returned and indexed records by the `id` field read out of `thread.json` — a record whose `id` disagreed with the directory it lived in was listed under an address `getThread` could not resolve it back through, except by luck of an already-warm cache.
1701
+
1702
+ A durable Thread store is still owed — see the note added to `ThreadStore` in `types/thread/store.ts` — but building one is capability work with a real caller and a real test from day one, not a rename of code that already existed unreached. Decided as branch (a) of NZ-TOPIC-02 (`.work/sessions/ses_020-fit-gap-and-hygiene/README.md`, decision D3): a data migration (NZ-TOPIC-04) was about to be written against a store that had never had a single record written into it.
1703
+
1704
+ No public export changes. `DiskThreadStore` and `DiskThreadStoreConfig` were never part of `@namzu/sdk`'s public surface.
1705
+
1706
+ - 01684bf: Internal: adds `store/kv/DiskRecordStore` and adopts it in `DiskMemoryStore`. No public API change — the primitive is deliberately not exported, because it is a shape four call sites already agree on rather than a contract offered to hosts, and exporting it would freeze an argument list nobody outside has asked for.
1707
+
1708
+ Four disk stores each carried a private copy of the same twenty lines: `readFile` + `JSON.parse` + `migrate` with ENOENT collapsed to null, an atomic write of stamped JSON, and a `readdir` filtered by prefix. The properties they duplicated are not the obvious ones — a missing file is an empty read rather than an error, a record from a _newer_ build is refused rather than read partially and written back with the difference gone, a listing needs an explicit sort because `readdir` order is filesystem-dependent. Every copy had to remember all of them, and a fix in one was a fix in one.
1709
+
1710
+ - 71939c1: Internal move: `connector/mcp/server.ts` and `connector/mcp/server-stdio.ts` now live in `connector/mcp/server/`, behind a barrel that states the rule the directory encodes. No exported name, signature or behaviour changes, and no import path a consumer writes changes — `connector/mcp/index.ts` re-exports the same names from the new location.
1711
+
1712
+ Everything else under `connector/mcp/` is this process calling somebody else's MCP server. These two are the reverse: somebody else's client calling ours. They were siblings distinguished only by the word `server` in two filenames out of twelve, in a directory where every other name is also about a server — the one being called. `MCPServerToolProvider` is something a host implements to expose its own tools; `MCPServerId` two files over identifies a remote server this process connects to.
1713
+
1714
+ - e010634: Internal move: `RemoteExecutionContext`, `HybridExecutionContext` and `ExecutionContextFactory` move from `connector/execution/` to `execution/`, joining `BaseExecutionContext` and `LocalExecutionContext`. No exported name, signature or behaviour changes, and no consumer import path changes — `connector/index.ts` re-exports the whole group from the new home.
1715
+
1716
+ One concept sat in two directories, and `connector/index.ts` reached into both to reassemble a single public export group. A contributor adding a fifth backend had no principled place to put it, and either answer was defensible from where they stood.
1717
+
1718
+ Consolidated upward rather than down: `run/command-gate.ts` imports `LocalExecutionContext` directly, so execution is not connector-scoped. A connector is one _caller_ of an execution context, not the thing that defines one.
1719
+
1720
+ - f94ca7d: An edited SKILL.md reaches the model without restarting the process.
1721
+
1722
+ `SkillRegistry.load` short-circuited on `existing.body`, so once a skill's body had been read it was cached for the life of the registry. That is tolerable for a one-shot run and wrong for a long-lived one — a skill is a file an author edits _while_ the agent is running, which is the whole reason it is a file and not a constant.
1723
+
1724
+ One `stat` per lookup, comparing mtime **and** size. Not a hash — that means reading every skill on every lookup, which is the cost the cache exists to avoid — and not a watcher, which is a resource with a lifetime this registry has no teardown to hang one on. The limit is stated rather than hidden: an edit that changes neither size nor mtime, inside one timestamp tick, is not detected.
1725
+
1726
+ A skill whose SKILL.md was **deleted** is dropped rather than served from cache, and removed from the listing too, so a manifest and a lookup cannot disagree about whether it exists. An edit that makes the file invalid surfaces its error rather than quietly keeping the last good body.
1727
+
1728
+ Reloading keeps the name the skill was **registered** under, not the one now on disk — the plugin path files skills as `plugin__skill` while the file says `skill`, so taking the name off disk would silently un-namespace them. The same object is stored and returned, since caching one and returning another hands the caller the on-disk name and the registry the registered one.
1729
+
1730
+ `add()` takes no stamp: a fire-and-forget `stat` in a synchronous method would race the first `load`. Unstamped counts as changed, so the first lookup reads the file — one extra read, never a stale answer.
1731
+
1732
+ - 4abc5ee: The oversized-tool-output spill now creates its file exclusively and owner-only.
1733
+
1734
+ `spill()` wrote to `<spillDir>/<toolUseId>.txt` with the default `w` flag,
1735
+ which creates-or-truncates and follows a symlink, at a path anything that has
1736
+ seen the tool call can predict. A file pre-planted at that path — by a hostile
1737
+ or buggy tool body, a stale entry in a reused output directory, or a
1738
+ co-located process on a shared sandbox mount — redirected the kernel's write
1739
+ onto a target of its choosing, with content the model influenced. The
1740
+ directory and file were also created with the default `0o755`/`0o644`, leaving
1741
+ the largest and most sensitive artefact a run produces world-readable on a
1742
+ shared host.
1743
+
1744
+ The write now uses `flag: 'wx'` with `mode: 0o600`, and directories this call
1745
+ creates are made `0o700`. `wx` never follows a symlink and fails with `EEXIST`
1746
+ rather than truncating, so a refusal is reported instead of a silent
1747
+ overwrite.
1748
+
1749
+ Behaviour on refusal is the path that already existed for an unusable spill
1750
+ directory: the call still returns, `truncated` is `true`, no `spillPath` is
1751
+ set, and the model gets the head/tail preview with the "The full output was
1752
+ not retained" recovery line. The `onError` message distinguishes `EEXIST` from
1753
+ other failures, because a stale file is housekeeping while something arriving
1754
+ at a path only this run should know is the case the exclusive open exists to
1755
+ refuse.
1756
+
1757
+ No exported identifier changes; `spill` is module-private and
1758
+ `applyToolOutputBudget`'s signature and result shape are unchanged.
1759
+
3
1760
  ## 27.1.0
4
1761
 
5
1762
  ### Minor Changes