@plurnk/plurnk-service 1.7.0 → 1.9.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 (381) hide show
  1. package/.env.defaults +49 -42
  2. package/INSTALL.md +48 -11
  3. package/README.md +12 -2
  4. package/SPEC.md +1166 -475
  5. package/digest-sql/channel-dispositions/dispositions.sql +15 -0
  6. package/digest-sql/channel-state/state.sql +6 -0
  7. package/digest-sql/curation/curation.sql +5 -0
  8. package/digest-sql/derivations/derivations.sql +4 -0
  9. package/digest-sql/embeddings/embeddings.sql +4 -0
  10. package/digest-sql/entry-dispositions/dispositions.sql +15 -0
  11. package/digest-sql/entry-state/state.sql +6 -0
  12. package/digest-sql/token-counts/token-counts.sql +2 -0
  13. package/dist/Paths.d.ts +0 -4
  14. package/dist/Paths.d.ts.map +1 -1
  15. package/dist/Paths.js +1 -21
  16. package/dist/Paths.js.map +1 -1
  17. package/dist/build-info.json +1 -1
  18. package/dist/content/read-projector.d.ts.map +1 -1
  19. package/dist/content/read-projector.js +4 -3
  20. package/dist/content/read-projector.js.map +1 -1
  21. package/dist/core/BudgetReadout.d.ts.map +1 -1
  22. package/dist/core/BudgetReadout.js +12 -22
  23. package/dist/core/BudgetReadout.js.map +1 -1
  24. package/dist/core/ChannelWrite.d.ts +8 -3
  25. package/dist/core/ChannelWrite.d.ts.map +1 -1
  26. package/dist/core/ChannelWrite.js +40 -8
  27. package/dist/core/ChannelWrite.js.map +1 -1
  28. package/dist/core/ChannelWrite.sql +19 -5
  29. package/dist/core/CoreSchemeServices.d.ts +7 -3
  30. package/dist/core/CoreSchemeServices.d.ts.map +1 -1
  31. package/dist/core/CoreSchemeServices.js +8 -1
  32. package/dist/core/CoreSchemeServices.js.map +1 -1
  33. package/dist/core/Dispatcher.d.ts +15 -6
  34. package/dist/core/Dispatcher.d.ts.map +1 -1
  35. package/dist/core/Dispatcher.js +352 -306
  36. package/dist/core/Dispatcher.js.map +1 -1
  37. package/dist/core/Engine.d.ts +22 -10
  38. package/dist/core/Engine.d.ts.map +1 -1
  39. package/dist/core/Engine.js +86 -46
  40. package/dist/core/Engine.js.map +1 -1
  41. package/dist/core/Engine.sql +202 -177
  42. package/dist/core/EntryAddressBinding.d.ts +32 -0
  43. package/dist/core/EntryAddressBinding.d.ts.map +1 -0
  44. package/dist/core/EntryAddressBinding.js +93 -0
  45. package/dist/core/EntryAddressBinding.js.map +1 -0
  46. package/dist/core/ExecutorRegistry.d.ts +12 -6
  47. package/dist/core/ExecutorRegistry.d.ts.map +1 -1
  48. package/dist/core/ExecutorRegistry.js +34 -31
  49. package/dist/core/ExecutorRegistry.js.map +1 -1
  50. package/dist/core/HostPaths.d.ts +29 -0
  51. package/dist/core/HostPaths.d.ts.map +1 -0
  52. package/dist/core/HostPaths.js +74 -0
  53. package/dist/core/HostPaths.js.map +1 -0
  54. package/dist/core/LegacyHome.d.ts +10 -0
  55. package/dist/core/LegacyHome.d.ts.map +1 -0
  56. package/dist/core/LegacyHome.js +170 -0
  57. package/dist/core/LegacyHome.js.map +1 -0
  58. package/dist/core/LogBody.d.ts +1 -1
  59. package/dist/core/LogBody.d.ts.map +1 -1
  60. package/dist/core/LogBody.js +21 -3
  61. package/dist/core/LogBody.js.map +1 -1
  62. package/dist/core/LogEntryProjection.js +1 -1
  63. package/dist/core/LogEntryProjection.js.map +1 -1
  64. package/dist/core/LogVisibility.d.ts +28 -0
  65. package/dist/core/LogVisibility.d.ts.map +1 -0
  66. package/dist/core/LogVisibility.js +215 -0
  67. package/dist/core/LogVisibility.js.map +1 -0
  68. package/dist/core/LoopLifecycle.d.ts +1 -0
  69. package/dist/core/LoopLifecycle.d.ts.map +1 -1
  70. package/dist/core/LoopLifecycle.js +8 -0
  71. package/dist/core/LoopLifecycle.js.map +1 -1
  72. package/dist/core/LoopLifecycle.sql +10 -0
  73. package/dist/core/OperatorConfig.d.ts +6 -0
  74. package/dist/core/OperatorConfig.d.ts.map +1 -0
  75. package/dist/core/OperatorConfig.js +95 -0
  76. package/dist/core/OperatorConfig.js.map +1 -0
  77. package/dist/core/OverflowTurn.d.ts +11 -0
  78. package/dist/core/OverflowTurn.d.ts.map +1 -0
  79. package/dist/core/OverflowTurn.js +81 -0
  80. package/dist/core/OverflowTurn.js.map +1 -0
  81. package/dist/core/Owner.js +3 -3
  82. package/dist/core/Owner.js.map +1 -1
  83. package/dist/core/PacketBuilder.d.ts +7 -15
  84. package/dist/core/PacketBuilder.d.ts.map +1 -1
  85. package/dist/core/PacketBuilder.js +64 -127
  86. package/dist/core/PacketBuilder.js.map +1 -1
  87. package/dist/core/ProblemLog.js +1 -1
  88. package/dist/core/ProblemLog.js.map +1 -1
  89. package/dist/core/ProposalLifecycle.d.ts +4 -1
  90. package/dist/core/ProposalLifecycle.d.ts.map +1 -1
  91. package/dist/core/ProposalLifecycle.js +86 -47
  92. package/dist/core/ProposalLifecycle.js.map +1 -1
  93. package/dist/core/ProviderInstantiate.d.ts +9 -5
  94. package/dist/core/ProviderInstantiate.d.ts.map +1 -1
  95. package/dist/core/ProviderInstantiate.js +99 -104
  96. package/dist/core/ProviderInstantiate.js.map +1 -1
  97. package/dist/core/ReasoningEvent.d.ts +13 -0
  98. package/dist/core/ReasoningEvent.d.ts.map +1 -0
  99. package/dist/core/ReasoningEvent.js +6 -0
  100. package/dist/core/ReasoningEvent.js.map +1 -0
  101. package/dist/core/ResourceMutations.d.ts +15 -19
  102. package/dist/core/ResourceMutations.d.ts.map +1 -1
  103. package/dist/core/ResourceMutations.js +118 -41
  104. package/dist/core/ResourceMutations.js.map +1 -1
  105. package/dist/core/SchemeRegistry.d.ts +12 -12
  106. package/dist/core/SchemeRegistry.d.ts.map +1 -1
  107. package/dist/core/SchemeRegistry.js +58 -57
  108. package/dist/core/SchemeRegistry.js.map +1 -1
  109. package/dist/core/ToolResources.d.ts +19 -0
  110. package/dist/core/ToolResources.d.ts.map +1 -0
  111. package/dist/core/ToolResources.js +123 -0
  112. package/dist/core/ToolResources.js.map +1 -0
  113. package/dist/core/Turn.d.ts +27 -0
  114. package/dist/core/Turn.d.ts.map +1 -0
  115. package/dist/core/Turn.js +43 -0
  116. package/dist/core/Turn.js.map +1 -0
  117. package/dist/core/Turn.sql +72 -0
  118. package/dist/core/TurnOps.d.ts +7 -0
  119. package/dist/core/TurnOps.d.ts.map +1 -0
  120. package/dist/core/TurnOps.js +73 -0
  121. package/dist/core/TurnOps.js.map +1 -0
  122. package/dist/core/TurnRunner.d.ts +56 -5
  123. package/dist/core/TurnRunner.d.ts.map +1 -1
  124. package/dist/core/TurnRunner.js +1163 -929
  125. package/dist/core/TurnRunner.js.map +1 -1
  126. package/dist/core/WorkerName.d.ts +2 -1
  127. package/dist/core/WorkerName.d.ts.map +1 -1
  128. package/dist/core/WorkerName.js +2 -1
  129. package/dist/core/WorkerName.js.map +1 -1
  130. package/dist/core/WorkerName.sql +17 -2
  131. package/dist/core/WorkspaceGate.js +1 -1
  132. package/dist/core/WorkspaceGate.js.map +1 -1
  133. package/dist/core/caps/CapsResolve.d.ts +2 -2
  134. package/dist/core/caps/CapsResolve.d.ts.map +1 -1
  135. package/dist/core/caps/CapsResolve.js +5 -7
  136. package/dist/core/caps/CapsResolve.js.map +1 -1
  137. package/dist/core/caps/DbChannelCaps.d.ts +1 -1
  138. package/dist/core/caps/DbChannelCaps.d.ts.map +1 -1
  139. package/dist/core/caps/DbChannelCaps.js +13 -11
  140. package/dist/core/caps/DbChannelCaps.js.map +1 -1
  141. package/dist/core/caps/DbEntryCaps.d.ts +5 -5
  142. package/dist/core/caps/DbEntryCaps.d.ts.map +1 -1
  143. package/dist/core/caps/DbEntryCaps.js +27 -30
  144. package/dist/core/caps/DbEntryCaps.js.map +1 -1
  145. package/dist/core/caps/DbNotifyCaps.d.ts +1 -1
  146. package/dist/core/caps/DbNotifyCaps.d.ts.map +1 -1
  147. package/dist/core/caps/DbNotifyCaps.js +5 -3
  148. package/dist/core/caps/DbNotifyCaps.js.map +1 -1
  149. package/dist/core/caps/DbSubscriptionCaps.d.ts +3 -3
  150. package/dist/core/caps/DbSubscriptionCaps.d.ts.map +1 -1
  151. package/dist/core/caps/DbSubscriptionCaps.js +16 -26
  152. package/dist/core/caps/DbSubscriptionCaps.js.map +1 -1
  153. package/dist/core/caps/SchemeCtxImpl.d.ts +6 -4
  154. package/dist/core/caps/SchemeCtxImpl.d.ts.map +1 -1
  155. package/dist/core/caps/SchemeCtxImpl.js +37 -5
  156. package/dist/core/caps/SchemeCtxImpl.js.map +1 -1
  157. package/dist/core/env-defaults.d.ts.map +1 -1
  158. package/dist/core/env-defaults.js +7 -5
  159. package/dist/core/env-defaults.js.map +1 -1
  160. package/dist/core/file-creation-policy.d.ts +9 -0
  161. package/dist/core/file-creation-policy.d.ts.map +1 -0
  162. package/dist/core/file-creation-policy.js +25 -0
  163. package/dist/core/file-creation-policy.js.map +1 -0
  164. package/dist/core/fork.d.ts +4 -1
  165. package/dist/core/fork.d.ts.map +1 -1
  166. package/dist/core/fork.js +39 -16
  167. package/dist/core/fork.js.map +1 -1
  168. package/dist/core/fork.sql +83 -40
  169. package/dist/core/git-env.d.ts +0 -1
  170. package/dist/core/git-env.d.ts.map +1 -1
  171. package/dist/core/git-env.js +0 -3
  172. package/dist/core/git-env.js.map +1 -1
  173. package/dist/core/git-membership.d.ts +19 -1
  174. package/dist/core/git-membership.d.ts.map +1 -1
  175. package/dist/core/git-membership.js +233 -74
  176. package/dist/core/git-membership.js.map +1 -1
  177. package/dist/core/git-state.d.ts.map +1 -1
  178. package/dist/core/git-state.js +13 -14
  179. package/dist/core/git-state.js.map +1 -1
  180. package/dist/core/operation-target-groups.d.ts +3 -0
  181. package/dist/core/operation-target-groups.d.ts.map +1 -0
  182. package/dist/core/operation-target-groups.js +53 -0
  183. package/dist/core/operation-target-groups.js.map +1 -0
  184. package/dist/core/packet-inject.d.ts +0 -1
  185. package/dist/core/packet-inject.d.ts.map +1 -1
  186. package/dist/core/packet-inject.js +6 -13
  187. package/dist/core/packet-inject.js.map +1 -1
  188. package/dist/core/packet-wire.d.ts +4 -0
  189. package/dist/core/packet-wire.d.ts.map +1 -1
  190. package/dist/core/packet-wire.js +226 -53
  191. package/dist/core/packet-wire.js.map +1 -1
  192. package/dist/core/plurnk-uri.d.ts +14 -3
  193. package/dist/core/plurnk-uri.d.ts.map +1 -1
  194. package/dist/core/plurnk-uri.js +62 -24
  195. package/dist/core/plurnk-uri.js.map +1 -1
  196. package/dist/core/scheme-types.d.ts +1 -0
  197. package/dist/core/scheme-types.d.ts.map +1 -1
  198. package/dist/core/teaching.d.ts.map +1 -1
  199. package/dist/core/teaching.js +4 -5
  200. package/dist/core/teaching.js.map +1 -1
  201. package/dist/core/worker-ops.sql +10 -6
  202. package/dist/core/worker-settings.d.ts +10 -0
  203. package/dist/core/worker-settings.d.ts.map +1 -0
  204. package/dist/core/worker-settings.js +32 -0
  205. package/dist/core/worker-settings.js.map +1 -0
  206. package/dist/core/workspace-settings.d.ts +2 -11
  207. package/dist/core/workspace-settings.d.ts.map +1 -1
  208. package/dist/core/workspace-settings.js +7 -47
  209. package/dist/core/workspace-settings.js.map +1 -1
  210. package/dist/digest/Digest.d.ts.map +1 -1
  211. package/dist/digest/Digest.js +164 -92
  212. package/dist/digest/Digest.js.map +1 -1
  213. package/dist/digest/digest.sql +9 -3
  214. package/dist/observe/genai.d.ts +9 -0
  215. package/dist/observe/genai.d.ts.map +1 -0
  216. package/dist/observe/genai.js +31 -0
  217. package/dist/observe/genai.js.map +1 -0
  218. package/dist/observe/spans.d.ts +3 -3
  219. package/dist/observe/spans.d.ts.map +1 -1
  220. package/dist/observe/spans.js +20 -5
  221. package/dist/observe/spans.js.map +1 -1
  222. package/dist/schemes/EffectPolicy.d.ts +3 -0
  223. package/dist/schemes/EffectPolicy.d.ts.map +1 -1
  224. package/dist/schemes/EffectPolicy.js +38 -6
  225. package/dist/schemes/EffectPolicy.js.map +1 -1
  226. package/dist/schemes/Exec.d.ts +3 -2
  227. package/dist/schemes/Exec.d.ts.map +1 -1
  228. package/dist/schemes/Exec.js +109 -34
  229. package/dist/schemes/Exec.js.map +1 -1
  230. package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
  231. package/dist/schemes/ExecOutputScheme.js +5 -4
  232. package/dist/schemes/ExecOutputScheme.js.map +1 -1
  233. package/dist/schemes/File.d.ts.map +1 -1
  234. package/dist/schemes/File.js +170 -80
  235. package/dist/schemes/File.js.map +1 -1
  236. package/dist/schemes/Log.d.ts +6 -2
  237. package/dist/schemes/Log.d.ts.map +1 -1
  238. package/dist/schemes/Log.js +73 -22
  239. package/dist/schemes/Log.js.map +1 -1
  240. package/dist/schemes/Log.sql +25 -7
  241. package/dist/schemes/Prompt.d.ts +2 -3
  242. package/dist/schemes/Prompt.d.ts.map +1 -1
  243. package/dist/schemes/Prompt.js +5 -9
  244. package/dist/schemes/Prompt.js.map +1 -1
  245. package/dist/schemes/QuestionTool.d.ts +10 -0
  246. package/dist/schemes/QuestionTool.d.ts.map +1 -0
  247. package/dist/schemes/QuestionTool.js +81 -0
  248. package/dist/schemes/QuestionTool.js.map +1 -0
  249. package/dist/schemes/Skill.d.ts.map +1 -1
  250. package/dist/schemes/Skill.js +6 -1
  251. package/dist/schemes/Skill.js.map +1 -1
  252. package/dist/schemes/Worker.d.ts.map +1 -1
  253. package/dist/schemes/Worker.js +97 -34
  254. package/dist/schemes/Worker.js.map +1 -1
  255. package/dist/schemes/_entry-crud.d.ts +5 -5
  256. package/dist/schemes/_entry-crud.d.ts.map +1 -1
  257. package/dist/schemes/_entry-crud.js +22 -17
  258. package/dist/schemes/_entry-crud.js.map +1 -1
  259. package/dist/schemes/_entry-crud.sql +77 -24
  260. package/dist/schemes/_entry-find.d.ts +8 -5
  261. package/dist/schemes/_entry-find.d.ts.map +1 -1
  262. package/dist/schemes/_entry-find.js +121 -40
  263. package/dist/schemes/_entry-find.js.map +1 -1
  264. package/dist/schemes/_entry-find.sql +16 -11
  265. package/dist/schemes/_entry-graph.sql +2 -6
  266. package/dist/schemes/_entry-manifest.d.ts +2 -2
  267. package/dist/schemes/_entry-manifest.d.ts.map +1 -1
  268. package/dist/schemes/_entry-manifest.js +18 -6
  269. package/dist/schemes/_entry-manifest.js.map +1 -1
  270. package/dist/schemes/_entry-ops.d.ts +6 -5
  271. package/dist/schemes/_entry-ops.d.ts.map +1 -1
  272. package/dist/schemes/_entry-ops.js +39 -46
  273. package/dist/schemes/_entry-ops.js.map +1 -1
  274. package/dist/schemes/_entry-ops.sql +9 -6
  275. package/dist/schemes/_entry-send.d.ts +2 -2
  276. package/dist/schemes/_entry-send.d.ts.map +1 -1
  277. package/dist/schemes/_entry-send.js +16 -14
  278. package/dist/schemes/_entry-send.js.map +1 -1
  279. package/dist/schemes/_search-index.d.ts.map +1 -1
  280. package/dist/schemes/_search-index.js +39 -25
  281. package/dist/schemes/_search-index.js.map +1 -1
  282. package/dist/server/Daemon.d.ts +98 -15
  283. package/dist/server/Daemon.d.ts.map +1 -1
  284. package/dist/server/Daemon.js +864 -348
  285. package/dist/server/Daemon.js.map +1 -1
  286. package/dist/server/DaemonModule.d.ts +84 -19
  287. package/dist/server/DaemonModule.d.ts.map +1 -1
  288. package/dist/server/DrainSupervisor.d.ts +15 -10
  289. package/dist/server/DrainSupervisor.d.ts.map +1 -1
  290. package/dist/server/DrainSupervisor.js +70 -19
  291. package/dist/server/DrainSupervisor.js.map +1 -1
  292. package/dist/server/Functionality.d.ts +44 -0
  293. package/dist/server/Functionality.d.ts.map +1 -0
  294. package/dist/server/Functionality.js +422 -0
  295. package/dist/server/Functionality.js.map +1 -0
  296. package/dist/server/FunctionalityManager.d.ts +22 -0
  297. package/dist/server/FunctionalityManager.d.ts.map +1 -0
  298. package/dist/server/FunctionalityManager.js +121 -0
  299. package/dist/server/FunctionalityManager.js.map +1 -0
  300. package/dist/server/SkillsFunctionality.d.ts +61 -0
  301. package/dist/server/SkillsFunctionality.d.ts.map +1 -0
  302. package/dist/server/SkillsFunctionality.js +449 -0
  303. package/dist/server/SkillsFunctionality.js.map +1 -0
  304. package/dist/server/WorkerCapabilities.d.ts +21 -0
  305. package/dist/server/WorkerCapabilities.d.ts.map +1 -0
  306. package/dist/server/WorkerCapabilities.js +214 -0
  307. package/dist/server/WorkerCapabilities.js.map +1 -0
  308. package/dist/server/WorkerResidency.d.ts +40 -0
  309. package/dist/server/WorkerResidency.d.ts.map +1 -0
  310. package/dist/server/WorkerResidency.js +283 -0
  311. package/dist/server/WorkerResidency.js.map +1 -0
  312. package/dist/server/client-input.d.ts +6 -2
  313. package/dist/server/client-input.d.ts.map +1 -1
  314. package/dist/server/client-input.js +72 -32
  315. package/dist/server/client-input.js.map +1 -1
  316. package/dist/server/dispatch-as-plurnk.d.ts +2 -2
  317. package/dist/server/dispatch-as-plurnk.d.ts.map +1 -1
  318. package/dist/server/dispatch-as-plurnk.js +109 -23
  319. package/dist/server/dispatch-as-plurnk.js.map +1 -1
  320. package/dist/server/drain.sql +33 -13
  321. package/dist/server/envelope.d.ts +7 -2
  322. package/dist/server/envelope.d.ts.map +1 -1
  323. package/dist/server/envelope.js +12 -6
  324. package/dist/server/envelope.js.map +1 -1
  325. package/dist/server/envelope.sql +36 -4
  326. package/dist/server/lifecycle-recovery.sql +24 -17
  327. package/dist/server/logEntry.d.ts +2 -1
  328. package/dist/server/logEntry.d.ts.map +1 -1
  329. package/dist/server/logEntry.js +3 -2
  330. package/dist/server/logEntry.js.map +1 -1
  331. package/dist/server/logEntry.sql +7 -0
  332. package/dist/server/loop-model.d.ts +2 -2
  333. package/dist/server/loop-model.d.ts.map +1 -1
  334. package/dist/server/loop-model.js +23 -33
  335. package/dist/server/loop-model.js.map +1 -1
  336. package/dist/server/loopDocs.d.ts +2 -1
  337. package/dist/server/loopDocs.d.ts.map +1 -1
  338. package/dist/server/loopDocs.js +88 -21
  339. package/dist/server/loopDocs.js.map +1 -1
  340. package/dist/server/loopDocs.sql +14 -8
  341. package/dist/server/model-catalog.d.ts +3 -0
  342. package/dist/server/model-catalog.d.ts.map +1 -0
  343. package/dist/server/model-catalog.js +83 -0
  344. package/dist/server/model-catalog.js.map +1 -0
  345. package/dist/server/model-route.d.ts +7 -0
  346. package/dist/server/model-route.d.ts.map +1 -0
  347. package/dist/server/model-route.js +47 -0
  348. package/dist/server/model-route.js.map +1 -0
  349. package/dist/server/module-discovery.d.ts +13 -0
  350. package/dist/server/module-discovery.d.ts.map +1 -0
  351. package/dist/server/module-discovery.js +103 -0
  352. package/dist/server/module-discovery.js.map +1 -0
  353. package/dist/server/seam-entry-read.sql +9 -7
  354. package/dist/server/seam-log-read.sql +1 -1
  355. package/dist/server/seam-loop.sql +10 -1
  356. package/dist/server/seam-proposal-list.sql +4 -2
  357. package/dist/server/worker-capabilities.sql +19 -0
  358. package/dist/service.d.ts.map +1 -1
  359. package/dist/service.js +193 -124
  360. package/dist/service.js.map +1 -1
  361. package/migrations/001_schema.sql +905 -196
  362. package/package.json +40 -38
  363. package/dist/core/ExecutableTools.d.ts +0 -11
  364. package/dist/core/ExecutableTools.d.ts.map +0 -1
  365. package/dist/core/ExecutableTools.js +0 -49
  366. package/dist/core/ExecutableTools.js.map +0 -1
  367. package/dist/core/JournalTurn.d.ts +0 -9
  368. package/dist/core/JournalTurn.d.ts.map +0 -1
  369. package/dist/core/JournalTurn.js +0 -14
  370. package/dist/core/JournalTurn.js.map +0 -1
  371. package/dist/core/JournalTurn.sql +0 -10
  372. package/dist/core/git-iso.d.ts +0 -13
  373. package/dist/core/git-iso.d.ts.map +0 -1
  374. package/dist/core/git-iso.js +0 -267
  375. package/dist/core/git-iso.js.map +0 -1
  376. package/dist/core/search-gate.d.ts +0 -17
  377. package/dist/core/search-gate.d.ts.map +0 -1
  378. package/dist/core/search-gate.js +0 -77
  379. package/dist/core/search-gate.js.map +0 -1
  380. package/dist/digest/Digest.sql +0 -1
  381. package/dist/server/workspace-capabilities.sql +0 -19
package/SPEC.md CHANGED
@@ -26,23 +26,56 @@ flowchart LR
26
26
  | **agent** | PLURNK | The plurnk runtime. Acts in-workspace as the reserved `plurnk` worker ({§actor-boundary} self-hosting), never a privileged singleton owning its own entries ({§entry-owner}, {§machine-processes}). |
27
27
  | **workspace** | Core | Durable user-named shared world. Persists across workers and process restarts. Identity: `workspaces.id` + unique `workspaces.name`. |
28
28
  | **worker** | Core | Durable actor and private history over one workspace. Owns its loops and log rows, may carry a `parent_worker_id`, and has one process-local cancellation scope while active. |
29
- | **loop** | Core | Queued-to-terminal unit of model or client work within a worker. Status ∈ {100 pending · 102 running · 200 done · 202 waiting (blocked on a live obligation, {§send}) · 413 provider input-capacity failure · 429 turn-ceiling · 499 cancelled · 500 failed · 504 wall-clock timeout ({§operator-config-loop-timeout}) · 508 runaway}. Many loops may belong to one worker. |
30
- | **turn** | Core | One engine scheduling unit (or one client-op scheduling unit). A model turn sends one assembled prompt through one or more emission attempts and admits at most one response. Many turns may belong to one loop. Identity: `(loop_id, sequence)`. |
29
+ | **loop** | Core | Queued-to-terminal unit of model or client work within a worker. Status ∈ {100 pending · 102 running · 200 done · 202 waiting (blocked on a live obligation, {§send}) · 413 input-capacity failure · 429 model-turn ceiling · 499 cancelled · 500 failed · 504 wall-clock timeout ({§operator-config-loop-timeout}) · 508 runaway}. Many loops may belong to one worker. |
30
+ | **turn** | Core | One durable, producer-neutral batch of ordered operations. A turn may be authored by a model, client, plugin, or `_plurnk`; only a model turn assembles a packet and owns an emission call. Many turns may belong to one loop. Identity: `(loop_id, sequence)`. |
31
31
  | **model call** | Core/provider | One logical `provider.generate` invocation. Emission attempts and BARE inferences share this durable accounting owner; provider retries remain cardinal physical requests beneath it. Identity: `(turn_id, sequence)`. |
32
- | **op** | Model/core | One DSL operation the model emits, parsed into a `PlurnkStatement`. One admitted turn produces zero or more ops. |
32
+ | **op** | Producer/core | One DSL operation a producer submits, parsed into a `PlurnkStatement`. One admitted source-backed turn produces an ordered PLAN…SEND program. |
33
33
  | **statement** | Model/core | A parsed op: the `PlurnkStatement` AST from `@plurnk/plurnk-contracts`. |
34
- | **action** | Core | One executed op. Execution normally produces a `log_entries` row at `log:///<L>/<T>/<S>/<op>`; an engine rail may instead record an actionless `op='error'` row ({§operation-results}). Actionless artifacts carry no fabricated operation. |
34
+ | **action** | Core | One executed op. Execution normally produces a `log_entries` row at `log:///<L>/<T>/<S>/<op>`; an engine rail may instead record an `op='error'` row ({§operation-results}). A source artifact carries no fabricated operation. |
35
35
  | **dispatch** | Core | Routing a statement to its scheme's op handler. |
36
36
  | **AG-UI Run** | AG-UI protocol | A client request/stream envelope identified by the client's `runId`. A message or resume AG-UI Run binds to one core loop; a management-action AG-UI Run may complete without creating a core loop. |
37
37
  | **AG-UI thread** | AG-UI protocol | Conversation identity. Within an explicitly selected workspace, `threadId` resolves to one conversation worker. |
38
38
  | **`--run`** | Client compatibility | A compatibility-sensitive client spelling, not an internal entity. |
39
39
  | **session** | Retired/unqualified | Not a PLURNK lifecycle noun. Use the actual core noun; a third-party standard may use only its explicitly qualified protocol term. <!-- lexicon-allow: this row defines the retired noun --> |
40
40
 
41
+ ### §turn-record Producer-neutral turn record
42
+
43
+ A turn is the durable container for one producer's ordered operations. Packet
44
+ and provider fields are optional evidence belonging only to model inference;
45
+ their absence never makes a client, plugin, or `_plurnk` turn exceptional.
46
+
47
+ | Field | Contract |
48
+ |---|---|
49
+ | `producer` | Required actor class: `model`, `client`, `plugin`, or `_plurnk`. |
50
+ | `kind` | Required purpose: `inference`, `initialization`, `overflow`, `operation`, or `maintenance`. Model iff inference; initialization, overflow, and maintenance require `_plurnk`. A maintenance turn's successful rows are packet-suppressed — a receipt answers an asker, and maintenance has none ({§actor-boundary-doc-injection}). |
51
+ | `status`, `completed_at` | A new turn is open at status 102 with `completed_at=NULL`. Completion records the exact terminal SEND/operation disposition and timestamp; a completed 102 is therefore distinct from an open 102. |
52
+ | Operations | Ordered by `(turn_id, sequence)` on one exact worker/loop/turn chain. Each row's `origin` is the turn producer or `_plurnk` making a system observation; the observation does not impersonate the producer. |
53
+ | `turnOps` | Every admitted source-backed turn preserves its exact PLAN…SEND program as one undecorated actionless log item under {§turn-ops-entry}. The item supplements rather than replaces the executed operation rows. |
54
+ | Inference evidence | Model calls, `packet`, model, finish reason, and provider metadata belong only to model/inference turns. Turn fields are nullable until recorded and remain NULL for every other kind. |
55
+
56
+ One lifecycle owner opens, optionally records inference evidence, and completes
57
+ every turn. Initialization, overflow recovery, client dispatch, and model
58
+ inference use that same path. `plugin` is the producer identity for
59
+ plugin-authored operation turns; exposing that path must not introduce a
60
+ parallel record or lifecycle. The sole identity transition is an open,
61
+ evidence-free model/inference candidate becoming `_plurnk`/overflow before
62
+ provider admission. Process-restart recovery completes any turn whose producer
63
+ vanished.
64
+
65
+ §turn-ops-admission-path **Source acquisition varies; admitted-turn execution does not.**
66
+ A provider response, deterministic `_plurnk` program, or future client/plugin
67
+ program crosses one admission boundary into the same executor. That executor
68
+ parses once, dispatches the admitted statements in order, records their ordinary
69
+ outcomes and the exact `turnOps`, and completes the turn from its SEND ruling.
70
+ Provider attempts, grammar recovery, reasoning, and accounting end before this
71
+ shared seam. A programmatic operation batch that supplied no Plurnk source does
72
+ not fabricate verbatim source.
73
+
41
74
  ### §storage-terms Storage terms
42
75
 
43
76
  | Term | Meaning |
44
77
  |---|---|
45
- | **entry** | The unit of canonical state. Identity: `(workspace, owner, scheme, pathname)` ({§entry-identity-no-null}). Holds one or more `channels` of content plus private `attributes`. |
78
+ | **entry** | The unit of canonical state. Identity: `(owner, scheme, authority, pathname)`; the owner Worker determines the workspace ({§entry-identity-no-null}). Holds one or more `channels` of content plus private `attributes`. |
46
79
  | **channel** | A named content buffer on an entry. Examples: `body`, `stdout`, `stderr`, `headers`, `symbols`. Each channel has `content`, `mimetype`, curation `weight`, and lifecycle `state`. |
47
80
  | **scope** | A scheme-manifest declaration ignored by core; registrations are discovered at boot and are not persisted. Entry sharing and privacy are owner-based; #80 owns retiring this residual axis. |
48
81
  | **scheme** | An addressed capability family + handler. Built-ins include `worker`, `prompt`, `log`, and bare/file paths; discovered schemes and executor-runtime tags extend that set. Internal `exec` routes the EXEC op but is not an addressable model namespace. Consumption surface {§scheme-surface}; author contract: [plurnk-schemes](../plurnk-schemes/SPEC.md). |
@@ -64,9 +97,9 @@ Independent axes on entries and channels. Confusion across them is a recurring s
64
97
 
65
98
  | Term | Meaning |
66
99
  |---|---|
67
- | **writer** | The identity authoring a write. One of `model \| client \| plurnk \| plugin`. Carried on `ctx.writer` for schemes; engine enforces `manifest.writableBy`. |
100
+ | **writer** | The identity authoring a write. One of `model \| client \| _plurnk \| plugin`. Carried on `ctx.writer` for schemes; engine enforces `manifest.writableBy`. |
68
101
  | **origin** | Synonym for writer in log_entries (`log_entries.origin`). Historical naming; treat as equivalent. |
69
- | **writable_by** | The set of writers a scheme accepts. Subset of `{model, client, plurnk, plugin}`. Engine rejects writes outside the set with 403; the rejection is logged as the action-entry ({§subscriptions} action-entry-as-outcome). |
102
+ | **writable_by** | The set of writers a scheme accepts. Subset of `{model, client, _plurnk, plugin}`. Engine rejects writes outside the set with 403; the rejection is logged as the action-entry ({§subscriptions} action-entry-as-outcome). |
70
103
 
71
104
  ### §engine-rails Engine rails
72
105
 
@@ -181,8 +214,33 @@ clients render and submit actions but contain no engine logic.
181
214
 
182
215
  OpenTelemetry may observe PLURNK; it never becomes product state, failure transport, scheduler input, model teaching, or client protocol. Domain and client activity remain on AG-UI. Reusable packages depend on the OTel API only; the daemon constructs only the explicitly configured trace and metric providers. An unconfigured or standards-valid disabled process loads no SDK or exporter implementation and keeps the API's no-op behavior with bounded overhead. OTel Logs have no provider or initialization path.
183
216
 
217
+ ### §standards-discernment Standards discernment
218
+
219
+ Seven principles govern which exterior standards Plurnk conforms to (#299):
220
+
221
+ 1. **UVP first.** Never conform away what users chose Plurnk for; the OP grammar, curated log, packet, and worker graph are the product, not a compatibility gap.
222
+ 2. **Right-fit.** Hobbyist-first: an enterprise-grade feature is acceptable only when its cost lands on the party that wants it, never on general adoption.
223
+ 3. **Traction.** Count running counterparties today; integration horizon must be shorter than the standard's expected half-life. Sockets stay configurable with no default until a candidate earns it.
224
+ 4. **POSIX app identity.** Decades-stable host-ecosystem conventions (XDG, NO_COLOR, man, completions, service units) outrank months-stable AI-pipeline fashions.
225
+ 5. **Faces, never organs.** A standard adopts as one adapter or projection behind an existing seam; if it cannot, that is the alarm, and it goes to a design gate.
226
+ 6. **Deletion is the price of admission.** A standard earns adoption by deleting bespoke surface (the ACP Plan object deleted the Markdown plan microformat); parallel representations, second discovery paths, and compatibility grammars are refused.
227
+ 7. **Two arbiters.** Model-facing surfaces change only on measured model evidence; human-facing surfaces follow host-ecosystem convention without ceremony. Standards bodies get a vote on neither.
228
+
184
229
  Configuration uses the standard `OTEL_*` environment: `OTEL_TRACES_EXPORTER` / `OTEL_METRICS_EXPORTER` select `otlp` or `console` per signal (a missing or `none` value keeps that signal off; no SDK default selects an exporter), `OTEL_SERVICE_NAME` names the service (default `plurnk-service`), case-insensitive `true` in `OTEL_SDK_DISABLED` turns the boundary off, and OTLP exporters honor `OTEL_EXPORTER_OTLP_*`. An unknown exporter name fails daemon boot; a typo never silently disables observation. OTel Logs and direct draft semantic-convention use are excluded. HTTP spans carry only an AG-UI-owned bounded route class, never an input pathname or query. Spans otherwise carry high-cardinality identifiers; metric labels stay low-cardinality. Prompts, reasoning, file bodies, arbitrary URLs, secrets, and plugin payloads are never recorded as attributes or metric values by default. Exporter failure cannot change product results or client lifecycle. Daemon, telemetry, and database teardown are independent reverse-ownership phases; every phase runs and aggregate failure preserves every cause.
185
230
 
231
+ §observability-genai-conventions **GenAI convention projection.** Provider
232
+ request spans use the OpenTelemetry GenAI semantic conventions: a
233
+ CLIENT-kind `gen_ai.client.request` span carrying `gen_ai.operation.name`
234
+ (`chat`), `gen_ai.system` (the provider alias), and `gen_ai.request.model`;
235
+ on settlement it gains `gen_ai.usage.input_tokens` and
236
+ `gen_ai.usage.output_tokens` from validated accounting plus
237
+ `gen_ai.response.finish_reasons`; failures carry `error.type` as the class
238
+ name only. Plurnk custom attributes (attempt, kind, status, loop/turn ids)
239
+ ride alongside and never replace the convention attributes. The redaction
240
+ boundary is unchanged — no prompts, reasoning, bodies, or URLs. This is the
241
+ sanctioned exception to the blanket draft-convention exclusion; no other
242
+ draft convention is projected.
243
+
186
244
  ### §in-process In-process architecture
187
245
 
188
246
  Composed daemon internals + admin CLI. Four plug points:
@@ -190,7 +248,7 @@ Composed daemon internals + admin CLI. Four plug points:
190
248
  - **Providers** ({§provider}) — LLM transports. Engine sends a turn's messages, receives raw content + usage; engine parses the content into `PlurnkStatement[]`.
191
249
  - **Schemes** ({§scheme}) — addressed capabilities. A scheme handler interprets targets under its prefix and owns its storage substrate.
192
250
  - **Mimetypes** ({§mimetype}) — content interpretation. Render-time handlers consume channel content; framework owns the dispatch.
193
- - **Executors** ({§exec} / {§bundled-set}) — EXEC runtime dispatch for subprocess, search, data, and pure-computation runtimes.
251
+ - **Executors** ({§exec} / {§bundled-set}) — EXEC runtime dispatch for subprocess, data, and pure-computation runtimes; web discovery rides the ordinary MCP surface.
194
252
 
195
253
  Core's internal owners compose without becoming new package or public seams:
196
254
 
@@ -199,7 +257,7 @@ Core's internal owners compose without becoming new package or public seams:
199
257
  | `Daemon` | Process/module lifecycle, dependency composition, provider policy, notifications, and the external client façade. |
200
258
  | `DrainSupervisor` | One worker's queue consumer, drain identity, wake obligations, cancellation scope, poll/park timers, and terminal cleanup. |
201
259
  | `Engine` | Loop lifecycle and the public turn, dispatch, derivation, and proposal façades. |
202
- | `TurnRunner` | One durable model turn from materialization through provider admission, operation scheduling, and settlement. |
260
+ | `TurnRunner` | Model inference plus `_plurnk` initialization/overflow turns from materialization through operation settlement. |
203
261
  | `Dispatcher` | Operation admission/routing, scheme execution, proposal waiting, curation, and durable log writes. |
204
262
  | `ResourceMutations` | EDIT/COPY/MOVE selection, anchor preconditions, cross-scheme effects, and mutation settlement. |
205
263
 
@@ -241,9 +299,10 @@ preserving the originating failure.
241
299
 
242
300
  ```mermaid
243
301
  flowchart LR
244
- actor["Worker A"] -->|"shared file or shared entry op"| state["Shared project files<br/>and shared workspace entries"]
245
- state -->|"folded attributed delta<br/>environment door"| log["Worker B log"]
246
- actor -->|"SEND to worker B<br/>voice door"| log
302
+ child["Child worker"] -->|"durable activity<br/>environment door"| parent["Direct parent log"]
303
+ actor["Any worker"] -->|"mutate worker:/// commons"| commons["Workspace commons"]
304
+ commons -->|"one folded broadcast occurrence"| logs["Every existing worker log"]
305
+ actor -->|"SEND to named worker<br/>voice door"| log["Addressed worker log"]
247
306
  client["User / client"] -->|"loop.inject<br/>voice door"| log
248
307
  ```
249
308
 
@@ -258,34 +317,68 @@ render-time filter.
258
317
  **attribution** — the delta's provenance ({§env-delta}) — and is never read to
259
318
  filter a row.
260
319
 
320
+ §actor-boundary-attached-functionality **A client operates in the Worker it is
321
+ attached to.** A client connection is attached to one conversation Worker; its
322
+ management commands mutate that Worker's Functionality ({§module-worker-capabilities}),
323
+ and its operations execute in that Worker's environment — executable families,
324
+ runtime schemes, per-Worker tool admission, flag-scoped scheme availability,
325
+ and effect policy resolve through the attached Worker — while the operation
326
+ journals in the client's own worker ({§connection-lifecycle}) and any entry it
327
+ writes binds its principal through that client worker. Every dispatch therefore
328
+ carries two coordinates: `workerId`, the journaling and entry principal, and
329
+ `functionalityWorkerId`, the Worker whose Functionality applies. They are equal
330
+ for model and `_plurnk` dispatches; a client dispatch names its attached
331
+ Worker, which must belong to the same workspace, and Functionality residency is
332
+ acquired for that Worker. Attachment is a connection fact, not topology: it is
333
+ many-to-one, non-owning, and never expressed as parentage.
334
+
261
335
  §actor-boundary-two-doors **Cross-worker arrival is limited to two doors.**
262
336
  An explicit READ is not an arrival: the reading worker deliberately addresses a
263
337
  file or ancestry-authorized entry through ordinary dispatch ({§worker-read-scope}).
264
338
 
265
- | Door | Carries | Wake behavior |
266
- | ----------- | --------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
267
- | Environment | A change to a shared project file or shared worker entry, as a folded attributed delta. | Ambient state never wakes an idle worker ({§env-delta}). |
268
- | Voice | A directed `loop.inject` or `## SEND0 (worker://name)` message. | An active worker folds it into its next turn; an idle one wakes. |
269
-
270
- §actor-boundary-no-mutex **Wild west by default; explicit branch batches are the exception.** Ordinary workers share workspace state without locks. Coordination is cooperative and softly fenced (the {§membership} `read-only` overlay, a workspace policy, bounds every worker's writable surface uniformly — {§machine-processes}); a conflict *surfaces* as a delta rather than being prevented. A branch-tagged WORK/FORK opts the whole workspace into the bounded, exclusive Git transaction in {§worker-branch-batch}. It is not a general entry mutex or a hidden per-worker filesystem.
339
+ | Door | Carries | Wake behavior |
340
+ | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
341
+ | Environment | A direct child's durable activity to its parent, plus a successful mutation of the deliberately global `worker:///` commons to every worker. | Intermediate activity and commons never wake; a child's terminal disposition wakes its parent. |
342
+ | Voice | A directed `loop.inject` or `## SEND0 (worker://name)` message. | An active worker folds it into its next turn; an idle one wakes. |
343
+
344
+ §actor-boundary-lineage-attention **Addressability is workspace-wide; attention
345
+ is lineage-scoped.** Project files, registered resources, and permitted worker
346
+ entries remain addressable throughout the workspace, but ordinary changes do
347
+ not enter unrelated workers' logs. A child's activity reaches only its direct
348
+ parent. That observer row carries the source occurrence identity and never
349
+ republishes, so grandparents observe what their own direct children do without
350
+ receiving an automatic recursive mirror of every descendant.
351
+
352
+ §actor-boundary-commons-broadcast **`worker:///` is the explicit global
353
+ attention surface.** A successful mutation whose landed effects touch the
354
+ commons emits one occurrence to every worker that existed when it landed.
355
+ Lineage and commons audiences are a union over that one identity: when a child
356
+ mutates the commons, its parent receives one observer row, never a parent copy
357
+ plus a broadcast duplicate. Ordinary project files, private worker entries,
358
+ and remote resources do not acquire ambient attention merely because they are
359
+ workspace-addressable.
360
+
361
+ §actor-boundary-no-mutex **Wild west by default; explicit branch batches are the exception.** Ordinary workers share workspace state without locks. Coordination is cooperative and softly fenced (the {§membership} `read-only` overlay, a workspace policy, bounds every worker's writable surface uniformly — {§machine-processes}); stale writes reject at their anchor or compare-and-swap boundary rather than being prevented by a lock ({§line-anchors}, {§membership-edit-write-cas}). A branch-tagged WORK/FORK opts the whole workspace into the bounded, exclusive Git transaction in {§worker-branch-batch}. It is not a general entry mutex or a hidden per-worker filesystem.
271
362
 
272
363
  §actor-boundary-passive-wake **Passive wake follows ownership.** A directed
273
364
  voice wakes an idle worker. A parked continuation resumes when an obligation it
274
- owns — a child or stream — reaches an observable transition ({§worker-loop-lifecycle}).
275
- An ambient environment delta never wakes; it queues until one of those directed
276
- events produces a turn ({§env-delta}). The obligation edge is continuation
277
- control, not a third door through which arbitrary sibling state can enter.
365
+ owns — a child or stream — reaches an observable terminal transition
366
+ ({§worker-loop-lifecycle}). Intermediate child activity and commons broadcasts
367
+ never wake; they queue until another cause produces a turn ({§env-delta}). The
368
+ obligation edge is continuation control, not a third door through which
369
+ arbitrary workspace state can enter.
278
370
 
279
371
  §actor-boundary-self-hosting **Use the actor path when the work has an
280
372
  operation; retain irreducible rails in the kernel.** The workspace has one
281
373
  reserved `plurnk` worker. It is durable; `DispatchAsPlurnk` opens a fresh
282
374
  administrative loop and turn for each ordinary operation batch. Other workers
283
- never receive its private log. They deliberately READ its published entries;
284
- ambient shared-state changes still cross only through the environment door.
375
+ cannot read its private log or entries. Generated references are instead
376
+ materialized directly in the addressed worker's private space; only direct
377
+ lineage activity and explicit commons mutations cross the environment door.
285
378
 
286
379
  | Work | Owning path | Why |
287
380
  | --------------------------------------- | ------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
288
- | Operator/client reference documents | Reserved `plurnk` worker; ordinary EDIT through engine dispatch. | Creating or replacing an entry is already an operation. |
381
+ | Worker reference documents | Addressed worker; `_plurnk` EDIT through engine dispatch. | Creating or replacing a private entry is already an operation. |
289
382
  | Git membership and disk materialization | Kernel `GitMembership` / entry CRUD. | Ingesting existing disk state is not a model-authored EDIT. |
290
383
  | Disk-divergence narration | Kernel writes an EDIT-shaped `source=file` row to the `plurnk` log. | It reports an environment event honestly; no operation is fabricated as having run. |
291
384
  | Search derivation and catalog render | Kernel. | They are indexes and read-only projections, not entry operations. |
@@ -294,17 +387,50 @@ ambient shared-state changes still cross only through the environment door.
294
387
  Git membership includes tracked and untracked-but-not-ignored project files
295
388
  ({§membership-auto-add}); it does not stage them or run `git add`.
296
389
 
297
- §actor-boundary-doc-injection **Operator reference documents use the actor
298
- path.** `PLURNK_SERVICE_MD_<ALIAS>=<path>` ({§operator-config}) materializes
299
- `<path>` as `worker://plurnk/<ALIAS>.md` through a `DispatchAsPlurnk` EDIT, then
300
- foists a READ into each model worker's turn 0. The materializing EDIT remains in
301
- the `plurnk` worker's log; the model sees the shared entry through its own READ.
302
- Client-provided workspace documents union with the operator set at the same
303
- entry surface.
304
-
305
- §actor-boundary-catalog-preview **Catalog preview.** `PLURNK_SERVICE_FILES_ITEMS` foists turn-0 FINDs into the worker's first turn, so a worker opens with a navigable map instead of blank. An enabled preview executes exactly four orienting surveys in order: project files (`## FIND0 [+init] (*)`), workspace commons (`## FIND0 [+init] (worker:///*)`), the worker's own space (`## FIND0 [+init] (worker://~/*)`), and kernel docs (`## FIND0 [+init,+docs] (worker://plurnk/docs/**) <1,-1>`). Their log classifications make the opening survey one `init` set while retaining `docs` on its documentation row ({§log-item-tags}). A shallow result renders direct entries normally and every deeper first-segment directory as an actionable `dir/**` summary with its recursive `items` and `tokens`. Ordinary surveys use FIND's markerless first-16 page, whose range metadata reports the requested and returned page against the complete result total; only the small curated kernel-doc surface explicitly selects all. The opening exemplar therefore demonstrates both `*` and `**` without normalizing an all-results override. Every survey executes even when empty because zero results are useful orientation. A positive `N` explicitly caps only the file map's rendered rows, using the map's actual direct-entry-plus-directory count; `-1` enables the ordinary markerless page; unset / `0` disables previews. `log://` is absent because the current worker's log already renders in present mode.
306
-
307
- §worker-initialization-entry **Worker initialization is not model output.** A worker's first loop begins with one born-OPEN actionless row at `log:///1/1/1`: `origin="plurnk"`, `op` null, and `attrs.kind="initialization"`. Its `text/vnd.plurnk` body dynamically mirrors the turn-zero PLAN, the orienting operations actually dispatched, and terminal `SEND0 [102]`. The PLAN states `* Initialization complete.` and `* Next: address the prompt.`; SEND hands off with `Next, address the prompt.`
390
+ §turn0-agents-stunt **The project AGENTS.md is a turn-0 stunt.** When
391
+ `<projectRoot>/AGENTS.md` exists, LoopDocs materializes it as the current worker's private
392
+ `worker://~/_plurnk/agents.md` entry and the engine foists one READ of it into
393
+ that model worker's first turn visible, logged, line-addressable. Absent
394
+ file: no entry, no stunt, nothing 404s. The global XDG configuration `AGENTS.md`
395
+ remains system-prompt policy ({§policy-sections}); the stunt carries only
396
+ local repo guidance.
397
+
398
+ §actor-boundary-doc-injection **Generated documents use the actor path.** The
399
+ project's `AGENTS.md`, skills, and Functionality references are materialized in
400
+ the addressed worker's `_plurnk/` subtree ({§worker-generated-subtree}) through
401
+ ordinary `_plurnk` operation turns. Their exact
402
+ EDIT and SEND programs remain durable in that worker's log; generated state is
403
+ neither a hidden database write nor a kernel-owned mirror.
404
+
405
+ §actor-boundary-catalog-preview **Catalog preview.** `PLURNK_SERVICE_FILES_ITEMS`
406
+ foists turn-0 discovery into the worker's first turn, so a worker opens with a
407
+ navigable map instead of blank. An enabled preview executes exactly seven baseline
408
+ bodyless FIND surveys in order: enabled Agent Skills (`## FIND0 [+init,+skills]
409
+ (worker://~/_plurnk/skills/*.md) <1,-1>`), Plurnk-generated reference families
410
+ (`## FIND0 [+init,+skills] (worker://~/_plurnk/skills/plurnk/*.md) <1,-1>`), enabled
411
+ tool families (`## FIND0 [+init,+tools] (worker://~/_plurnk/tools/*.md) <1,-1>`),
412
+ enabled outbound agents (`## FIND0 [+init,+agents] (worker://~/_plurnk/agents/*.md)
413
+ <1,-1>`, {§a2a-agents-catalog}), project files (`## FIND0 [+init] (*)`), workspace commons (`## FIND0 [+init]
414
+ (worker:///*)`), and the worker's own space (`## FIND0 [+init] (worker://~/*)`).
415
+ The catalogs select every direct document independently of its authored body;
416
+ ordinary READ supplies its examples and complete instructions on demand. Their
417
+ log classifications make the opening discovery one `init` set while retaining
418
+ `skills`, `tools`, or `agents` on the corresponding rows ({§log-item-tags}). A shallow
419
+ result renders direct entries normally and every deeper first-segment directory
420
+ as an actionable `dir/**` summary with its recursive `items` and `tokens`;
421
+ tool-family rows also carry the concise `{§scheme-catalog-summary}` that drives
422
+ on-demand capability discovery. Ordinary surveys use FIND's markerless first-16
423
+ page, whose range metadata reports the requested and returned page against the
424
+ complete result total; only the small curated skills and tools surfaces
425
+ explicitly select all. The opening survey demonstrates both `*` and `**` without
426
+ normalizing an all-results override. Every survey executes even when empty
427
+ because zero results are useful orientation. A positive `N` explicitly caps
428
+ only the file map's rendered rows, using the map's actual
429
+ direct-entry-plus-directory count; `-1` enables the ordinary markerless page;
430
+ unset / `0` disables previews. `log://` is absent because the current worker's
431
+ log already renders in present mode.
432
+
433
+ §worker-initialization-entry **Model-worker initialization is a real `_plurnk` turn.** A model worker's first loop begins with one packetless `{ producer="_plurnk", kind="initialization" }` turn submitted through {§turn-ops-admission-path}. It preserves one OPEN exact `turnOps` item and dispatches the same source into ordinary PLAN, orienting READ/FIND, and terminal `SEND0 [102]` rows. Every row is structurally classified `_plurnk` and `init`. The PLAN is the canonical {§plan-value} with one `medium`, `in_progress` entry whose content is `Discover the tooling available and survey the workspace file root.`; SEND hands off with `Next: Address the prompt.` The first model request occupies the following turn and therefore begins at database/log turn sequence 2; “turn zero” is the initialization phase's model-facing label, not a zero-based database coordinate. Client and `_plurnk` administrative workers execute operation turns and do not receive model initialization.
308
434
 
309
435
  ### §machine-processes The machine and its processes: workspace, worker, fork
310
436
 
@@ -340,23 +466,32 @@ terminal history.**
340
466
  | Project files ({§machine-processes-one-filesystem}) | Workspace | Shared live; a fork does not create another checkout. |
341
467
  | Shared worker entries (`worker:///...`) | Workspace commons | Shared live. |
342
468
  | Membership overlay ({§machine-processes-one-overlay}) | Workspace | Shared unchanged; divergent membership requires another workspace. |
343
- | Log items ({§machine-processes-fork-copies-the-log}) | Worker | Rows, event identities, curation effects, tags, fold state, and the matching observation cursor are copied as terminal history. |
469
+ | Log items ({§machine-processes-fork-copies-the-log}) | Worker | Rows, event identities, curation effects, tags, folded body intervals, and the matching observation cursor are copied as terminal history. Parent-audience occurrences still pending at the fork boundary belong to the snapshot; later sibling activity does not. |
344
470
  | §machine-processes-fork-cost **Provider evidence and accounting** | Worker | Turns and their model-facing log history are copied, but `model_calls`, emission-admission rows, and physical provider requests are not: one issued call or request has one owning worker. Parent and fork accounting therefore includes only work issued in that branch, while workspace accounting never double-counts copied history. |
345
- | Private worker entries (`worker://~/...`) | Worker | Deep-copied with ownership remapped; parent and child then diverge. |
471
+ | §machine-processes-entry-inheritance **Worker-owned entries** | Worker | The scheme's mandatory `{§manifest-entry-inheritance}` decides: `snapshot` copies only entries whose channels are all quiescent and remaps ownership; `rederive` copies no bytes and lets the child materializer rebuild them from inherited Functionality; `none` carries nothing. Within a `snapshot` scheme the Worker scheme's generated subtree is always rederived ({§worker-generated-subtree}). Parent and child then diverge. |
346
472
  | Active loops, turns, and cancellation | Worker | Never copied as live work; inherited structure is terminal history, then a new loop starts. |
347
473
 
348
474
  §machine-processes-worker-is-its-log **A worker's conversational memory of
349
475
  the shared world is its log, with no hidden per-worker snapshot beside it.**
350
- OPEN/FOLD changes `log_entries.expanded` on that worker's rows ({§open-fold});
351
- environment changes arrive as attributed log entries ({§env-delta}). Private
352
- worker entries are deliberate scratch that the worker reads and writes through
353
- `worker://~/...`, not an invisible mirror of shared state. The environment door
354
- therefore carries only shared project-file and shared-entry changes
355
- ({§env-delta-worker-entry-visibility}).
476
+ OPEN/FOLD changes canonical folded body intervals on that worker's rows ({§open-fold});
477
+ lineage activity and explicit commons broadcasts arrive as attributed log
478
+ entries ({§env-delta}). Worker-owned entries include deliberate scratch and
479
+ other private resources; their manifest declares whether a FORK snapshots,
480
+ rederives, or omits each class. They are not an invisible mirror of shared state. Workspace
481
+ addressability does not imply packet membership or ambient notification
482
+ ({§actor-boundary-lineage-attention}).
483
+
484
+ §machine-processes-fork-pending-activity **A fork is a closed snapshot of the
485
+ parent's view.** It copies rows already materialized in the parent and inherits
486
+ parent-audience occurrences newer than the copied observation cursor through
487
+ the occurrence high-water captured by worker creation. Activity addressed to
488
+ the parent after that boundary is sibling activity, not fork history. Global
489
+ commons broadcasts remain live after the fork because the branch is then an
490
+ existing workspace worker in its own right.
356
491
 
357
492
  §machine-processes-model-worker-readable **A worker's log is private to packets, not to the workspace.** Isolation ({§actor-boundary}) governs what an *actor* sees — its own worker, never a sibling's. It does not wall off the client interface: `readLog({ workspaceId, workerId })` may read any ownership-verified worker in that workspace, and `listWorkers` enumerates them. A client-interface module chooses the default worker from its own conversation binding. The read is observation, never packet membership — no actor sees it.
358
493
 
359
- §machine-processes-worker-origin **A worker carries its actor.** Each worker records its `origin` — `model` (a conversation), `client` (a client-interface actor), or `plurnk` (the runtime's self-hosting worker) — set once at creation and inherited by a fork. `listWorkers` returns it, so a client interface identifies actor class without parsing the name, which is set at instantiation and immutable (a worker is permanent history, {§machine-processes-worker-is-its-log}).
494
+ §machine-processes-worker-origin **A worker carries its actor.** Each worker records its `origin` — `model` (a conversation), `client` (a client-interface actor), or `_plurnk` (the runtime's self-hosting worker) — set once at creation and inherited by a fork. `listWorkers` returns it, so a client interface identifies actor class without parsing the name, which is set at instantiation and immutable (a worker is permanent history, {§machine-processes-worker-is-its-log}).
360
495
 
361
496
  §worker-provider-identity **A worker owns a durable provider identity distinct
362
497
  from its database id.** Creation mints a globally unique, opaque 128-bit value;
@@ -378,9 +513,9 @@ shared entries, and membership remain live and uncopied.
378
513
  histories over one workspace are worker forks. A divergent project filesystem
379
514
  or membership overlay requires a new workspace.
380
515
 
381
- ### §worker-scheme The worker:// scheme — the knowledgebase (commons, own space, named spaces, the kernel surface) and worker control (spawn, irc, fork, terminate, cap, collect)
516
+ ### §worker-scheme The worker:// scheme — the knowledgebase (commons, own space, named spaces) and worker control (spawn, irc, fork, terminate, cap, collect)
382
517
 
383
- §worker-authority-carving **The authority names the OWNER:** `worker:///notes.md` is in the COMMONS — a shared blackboard; `worker://~/draft.md` is the calling worker's own private space; `worker://<name>/result.md` is a named worker's space; `worker://plurnk/docs/x.md` is the kernel's published surface, world-readable. Storage keys the owner on the entries.owner_id column ({§entry-owner}) — the pathname is always the bare entry path, and a FIND's result paths re-apply the queried authority so the model sees the address it typed. `~` is the sole current-worker sigil and cannot be minted; `commons` and `plurnk` are internal worker names unavailable for minting. Every other mintable authority, including `self`, is a literal worker name ({§worker-name}).
518
+ §worker-authority-carving **The authority names the OWNER:** `worker:///notes.md` is in the COMMONS — a shared blackboard; `worker://~/draft.md` is the calling worker's own private space; `worker://<name>/result.md` is a named worker's space. Storage keys the owner on the entries.owner_id column ({§entry-owner}) — the pathname is always the bare entry path, and a FIND's result paths re-apply the queried authority so the model sees the address it typed. `~` is the sole current-worker sigil and cannot be minted; `commons` and `plurnk` are internal worker names unavailable for minting. Every other mintable authority, including `self`, is a literal worker name ({§worker-name}).
384
519
 
385
520
  §worker-name-minting **URI ingestion is permissive; worker minting is not.**
386
521
  Every model/client worker-creation door applies the contracts-owned
@@ -394,9 +529,11 @@ continues to decompose other authorities without treating them as mintable.
394
529
  | Any other spelling | Refused as `name-invalid` before lookup, insertion, or child startup. |
395
530
  | Automatic name | Generated, then admitted through the same predicate. |
396
531
 
397
- §worker-read-scope **Named spaces are ancestry-gated reads**: the reader is the owner or an ANCESTOR (the recursive parent_worker_id walk) — oversight flows down the tree, a parent reads `worker://child/result` across generations, a child cannot snoop upward, and an unknown name or unpermitted reader resolves 404 with no existence leak. The kernel surface is the one world-readable named space.
532
+ §worker-read-scope **Named spaces are ancestry-gated reads**: the reader is the owner or an ANCESTOR (the recursive parent_worker_id walk) — oversight flows down the tree, a parent reads `worker://child/result` across generations, a child cannot snoop upward, and an unknown name or unpermitted reader resolves 404 with no existence leak. Reserved runtime workers obey the same rule; there is no world-readable named space.
533
+
534
+ §worker-write-scoping **Writes are own-space-and-commons only**: a model writes `worker://~/` and `worker:///` — every ancestry-readable named authority is read-only to it (403), while an unreadable name remains 404 under {§worker-read-scope}. `owner_id` is engine-stamped from the dispatch context, never model-set. Nothing worker-authored can land under another principal. The entry-copy seam (COPY/MOVE) is pathname-keyed and addresses the commons; a space's content moves via READ + EDIT. The one exception inside a writable space is the generated subtree below.
398
535
 
399
- §worker-write-scoping **Writes are own-space-and-commons only**: a model writes `worker://~/` and `worker:///`every named authority is read-only to it (403), and owner_id is engine-stamped from the dispatch context, never model-set. Nothing worker-authored can land under another principal `worker://plurnk/` included, which is what makes the kernel surface the trust boundary with no guard to forget (only the kernel, dispatching as itself, authors it). The entry-copy seam (COPY/MOVE) is pathname-keyed and addresses the commons; a space's content moves via READ + EDIT.
536
+ §worker-generated-subtree **`_plurnk/` is Plurnk's generated subtree in every worker space.** Every Plurnk-generated per-Worker document lives under `worker://~/_plurnk/`: the project instructions (`_plurnk/agents.md`, with nested AGENTS.md files under `_plurnk/instructions/**` preserving their subtree paths the standard's closest-file scope, materialized without any foisted READ or teaching), standard Agent Skills and Plurnk-generated references (`_plurnk/skills/**`), executable families (`_plurnk/tools/**`), and future family catalogs. The subtree is readable exactly like the rest of the space ({§worker-read-scope}) and writable only by the `_plurnk` writer tier: a model, client, or plugin EDIT, KILL, SEND 410, or COPY/MOVE destination whose pathname begins `/_plurnk/` is refused 403 `worker-generated-read-only`, in the commons as well as in own and named spaces. Its documents are materialized through ordinary `_plurnk` **maintenance** turns ({§actor-boundary-doc-injection}), so provenance is legible at the address and durable in the log but a receipt answers an asker, and maintenance turns have none: their successful rows never render in the packet (failures remain visible), while READ over `log:///` recovers them exactly and the turn's self-FOLD keeps client waterfalls tidy. On FORK the subtree is never byte-copied; the child rederives it from its inherited Functionality ({§machine-processes-entry-inheritance}). A runtime's `resourcesPath` is relative to this root ({§tools-resource-materialization}). No world-readable kernel authority exists; there is no `worker://plurnk/`.
400
537
 
401
538
  §worker-control-addressing **Only an exact authority-only address selects worker
402
539
  control.** Control is same-workspace only ({§actor-boundary}). Generic URI
@@ -425,7 +562,7 @@ literal `workers.name` value.
425
562
  | `KILL` | existing literal name, `~` | Terminate the named worker or caller. |
426
563
 
427
564
  - §worker-scheme-spawn **Spawn** — `## WORK0 (worker://<name>)` with a task body creates a new worker sister (empty log) and starts it with that task on its first loop. WORK/FORK are the worker-creation verbs: EDIT is file/entry only, so EDIT on the bare worker entity is a **400** steering to WORK/FORK — the entity is not an entry. A name is **frozen per worker** but **reclaimable across time** ({§machine-processes-worker-origin}): a name held only by a *terminated* sister is free to reuse — a fresh spawn takes a new row and `worker_resolve_by_name` resolves the newest, the corpse keeping its name in permanent history. A name a *live* sister still holds is a conflict — **409 `worker '<name>' is already running`**, legible at the spawn gate, never a raw store-level uniqueness error.
428
- - §worker-scheme-irc **irc** — `## SEND0 (worker://<name>)` with a message body delivers it to an existing sister, the **voice door** ({§actor-boundary-two-doors}): an active sister folds it into its next turn, an idle one wakes ({§actor-boundary-passive-wake}). `## SEND0 (worker://~)` targets the caller; a literal name with no worker in the workspace is 404.
565
+ - §worker-scheme-irc **irc** — `## SEND0 (worker://<name>)` with a message body delivers it to an existing sister, the **voice door** ({§actor-boundary-two-doors}): an active sister folds it into its next turn, an idle one wakes ({§actor-boundary-passive-wake}). A fresh receiving loop retains that worker's durable model, spawn override, and reasoning policy; the sender and daemon default do not re-select it. `## SEND0 (worker://~)` targets the caller; a literal name with no worker in the workspace is 404.
429
566
  - §worker-scheme-fork **Fork** — `## FORK0 (worker://<name>)` with a task body branches the
430
567
  current worker into a **named** sister: its log is deep-copied
431
568
  ({§machine-processes-fork-copies-the-log}), which continues with `task`; the
@@ -505,13 +642,14 @@ The remaining worker surfaces are:
505
642
  - §worker-scheme-terminate **Terminate** — `## KILL0 (worker://<name>)` aborts a named worker and `## KILL0 (worker://~)` aborts the caller: every unresolved loop in that worker's subtree closes 499 and every subscription in the subtree tears down; a literal name with no worker is 404. Cancellation is structured: descendants cannot detach implicitly. The override to the fire-and-forget default is not a parent-power — whoever holds the address may end it; a worker left alone simply ends at its own SEND signal `200`.
506
643
  - §worker-scheme-cap **Cap** — `PLURNK_SERVICE_WORKSPACE_WORKERS_MAX_ACTIVE` ceilings the *concurrent* active workers per workspace (a worker with a non-terminal loop); a spawn or fork past it fails hard (508 — no queue, no retry), irc exempt; `-1` disables it. The fork-bomb brake, sized for workspaces that live for months.
507
644
  - §worker-scheme-collect **Collect** — a worker's loop reaching a terminal status
508
- surfaces to its sisters as an ambient delta ({§env-delta}): a `SEND` from
645
+ surfaces to its direct parent as an ambient delta ({§env-delta}): a `SEND` from
509
646
  `worker://<name>` carrying the loop's exact terminal operation result. A
510
647
  **2xx deliverable is born OPEN** (its body
511
648
  materialized into the parent's packet, not hidden behind a fold): a child's
512
649
  success must reach the parent open and awakening, never a bodyless row. An
513
650
  non-2xx result surfaces folded; a failure retains its exact status and Problem. Every death-path is stamped uniformly,
514
- so no termination is silent; collection is the shared world moving, never a
651
+ so no child termination is silent to its owner; collection is lineage
652
+ supervision, never a
515
653
  verb. The **pull** side mirrors the push: a path-absent
516
654
  `## READ0 (worker://<name>)` collects that same result on demand for a
517
655
  concluded worker; a worker **still running** has not delivered, so the READ
@@ -524,11 +662,11 @@ The remaining worker surfaces are:
524
662
  turn the packet's status clump surfaces the live things this worker currently
525
663
  holds — open streams (`## Child Streams`) and unconcluded child workers
526
664
  (`## Active Child Workers`) — as terse `* <status> <path>` pointers (the same
527
- shape as the errors section), just above it. A worker is otherwise marked
528
- only at spawn and at conclusion; in between it goes silent, so a model loses
529
- track of what it holds and premature-terminates. This is orienting state,
530
- never advice: the model sees its live subtree (`* 102 worker://worker-x`,
531
- `* active sh:///1/2/3`) and reasons for itself — READ/OPEN/KILL via the path.
665
+ shape as the errors section), just above it. Folded child activity is durable
666
+ history; this clump is the current inventory that keeps an active obligation
667
+ visible even when no new activity arrived. It is orienting state, never
668
+ advice: the model sees its live subtree (`* 102 worker://worker-x`, `* active
669
+ sh:///1/2/3`) and reasons for itself — READ/OPEN/KILL via the path.
532
670
  Empty sections are omitted, like errors.
533
671
 
534
672
  ### §worker-loop-lifecycle Worker and loop lifecycle: drain, reap, and passive wake
@@ -551,6 +689,12 @@ stateDiagram-v2
551
689
 
552
690
  §worker-lifecycle-state-machine The lifecycle store admits only the guarded transitions shown above: `100 → 102`, `102 → 202`, `202 → 100`, and any unresolved state (`100`, `102`, `202`) to a terminal status. Terminal state is immutable. `DrainSupervisor` owns claim, wake, and cancellation; the dispatcher owns model-requested park/conclusion; the daemon owns boot-recovery orchestration; and the engine owns policy terminals. A racing transition that loses observes the durable winner; it does not overwrite it or report the requested state as fact.
553
691
 
692
+ §worker-lifecycle-live **Worker liveness is existential, not latest-state.** A
693
+ Worker is live while ANY of its loops is unresolved (`100`, `102`, or `202`). A
694
+ newer terminal loop cannot mask older queued, running, or parked work. Name
695
+ collision, workspace worker caps, child obligations, orientation, and recovery
696
+ all use that one definition.
697
+
554
698
  §stream-catalog-lifecycle Streams are independently durable subscriptions owned by a worker. Payload and
555
699
  lifecycle are orthogonal: zero bytes is a valid payload for both success and
556
700
  failure, while the closed subscription and its status are the terminal fact.
@@ -663,7 +807,7 @@ boundary.
663
807
  - §worker-lifecycle-total-reap **Cancellation is recursive and reaps every held stream.** `loop.cancel`, worker `KILL`, shutdown, and a worker's SEND signal `499` terminalize every unresolved loop in the cancelled worker subtree and iterate each worker's durable open-subscription rows, invoking each exact callable owner from the process-local live registry. The durable rows answer *what is held*; the live registry answers *how this process tears it down*; the abort signal is a fast-path optimization. There is no implicit detachment. Before shutdown awaits drains, it cancels every process-local proposal waiter through {§proposal-cancel-aborts} with outcome `daemon_stopping`, so a stopped-world dispatch cannot hold teardown open. A stream that is running, mid-spawn (its row written before it is killable), or spawned after the cancel is reaped alike. The teardown abort is bounded: the executor sends a polite signal then SIGKILL after a consumer-set grace (`PLURNK_SERVICE_EXEC_KILL_GRACE_MS`). A model `## KILL0 [code]` on one live stream instead delivers exactly that signal once (bare KILL uses the executor's SIGHUP default; `## KILL0 [9]` uses SIGKILL).
664
808
  - §worker-lifecycle-exec-epoch-bound **A stream's kill binds to the scope it captured at spawn.** A stream captures the worker's cancellation scope as it registers and wires its kill to it, re-checking `aborted` AFTER wiring — no check-then-listen gap can drop an abort that lands mid-registration. Because the scope is replaced only once aborted, a captured-then-replaced scope is necessarily already aborted, so replacement never strands a live stream.
665
809
  - §worker-lifecycle-no-resurrection **A cancelled worker is not resurrected by its own torn-down work.** A stream conclusion delivered to a cancelled, idle worker starts no fresh drain: an aborted (499) conclusion is skipped, and a straggler that concluded cleanly surfaces its deliverable as an environment delta ({§env-delta}), never a revived loop. The cancel was deliberate; only an explicit `runLoop` request resumes the worker.
666
- - §worker-lifecycle-wake-liveness **A stream conclusion always reaches its worker.** When a backgrounded stream concludes, `DrainSupervisor` routes it through the same inject seam as any loop source ({§actor-boundary-passive-wake}): an active worker folds the conclusion into its next turn; a worker **blocked on a 202 wait** for that stream ({§wait-obligation-matrix}) **awakens that loop in place** — the blocked loop *is* the continuation, so there is no fresh loop and no summary-as-prompt fiction. The result is never lost: a blocked loop sleeps rather than ending, and the stream's status-transition is the arrival ({§actor-boundary-passive-wake}) that wakes it; on resume it reads the concluded stream's own state, not a synthetic prompt.
810
+ - §worker-lifecycle-wake-liveness **A stream conclusion always reaches its worker.** The stream first persists its terminal state. A worker **blocked on a 202 wait** for that stream ({§wait-obligation-matrix}) then **awakens that loop in place** — the blocked loop *is* the continuation, so there is no fresh loop and no summary-as-prompt fiction. An already-active worker needs no injected prompt or second wake because its next packet reads the durable terminal state. A concluded worker receives no synthetic loop from ambient stream closure. The result remains available in the stream's own state under every case.
667
811
  - §worker-lifecycle-child-wake **A child worker concluding wakes a parent blocked on it — the topology join.** `worker://` spawn/fork records `parent_worker_id` ({§lifecycle-terms}). When a worker's drain exits having **concluded** — no `202`-blocked loop, no open stream — `DrainSupervisor.#onDrainExit` resumes its parent **in place** through the shared `#wakeParkedWorker`, the same 202→100 resume a stream conclusion uses. So a parent that spawns work and blocks with SEND signal `202` is woken the moment its child finishes; on resume it reads the child's deliverable from the {§worker-scheme-collect} delta in its own log — a control edge, **never an injected prompt**. The wake recurses upward via the parent's own drain-exit. A child still running — or itself blocked at 202 — is not *concluded*, so it does not wake the parent (it's still a live thing the subtree holds). This is the structured-concurrency join: streams and child workers are the same kind of "live thing a worker holds," driving premature-terminate ({§send-premature-terminate}), the wake edge, and the collect delta identically. A worker conclusion is a **bounded, un-loseable** wake: if the conclusion fires while the parent is mid-turn (before its block commits), `#wakeParkedWorker` finds it not-yet-slept and records an **owed wake**, which the drain honors when the parent blocks — so a wait awaiting workers **always returns**, never dead-blocks on a conclude-before-block race. (Only a live exec stream, unbounded absent a timeout, may legitimately hold a wait open.)
668
812
  - §worker-optimistic-settlement **Asynchronous settlement receives one bounded worker-local opportunity before model dispatch.** An initiating turn lets only the streams it started settle before its terminal SEND; separately, a stream or direct-child conclusion persists and publishes immediately but holds the parked worker's single `202→100` requeue while another stream or direct child remains live. Both use `PLURNK_SERVICE_OPTIMISTIC_WAIT_MS`, shipped at five seconds; zero disables the opportunity. The wake hold ends as soon as no sibling obligation remains, never extends its original deadline, and coalesces every conclusion that lands within it into one requeue. With no sibling obligation the wake is immediate; at the deadline, surviving work follows the ordinary monitored lifecycle. A conclusion that lands after provider dispatch begins retains its next wake, while poll, park-deadline, prompt, and operator wakes never open this hold. Only packet/provider dispatch waits: terminal state, client events, cancellation, and child execution do not. One redaction-safe span records elapsed time, quiescence versus deadline, and conclusion count without entering the packet.
669
813
  - §worker-lifecycle-idle-is-concluded **An idle worker concludes; it does not park.** A loop is idle only when it has neither live obligations nor completed results awaiting their first packet. A live child or stream blocks a SEND signal `202` join; a completed stream, child result, or same-turn retrieval continues directly to the next packet where it is observed. Only after those sets are drained does signal `202` resolve like signal `200`. There is no held-open idle loop and no `loop/quiesced` soft signal. A concluded worker is durable working history and an addressed arrival reawakens it as a new loop.
@@ -685,7 +829,7 @@ Three current entry points:
685
829
  - §provider-surface-capacity `provider.assessRequestCapacity(messages, maxOutputTokens?, signal?)` — provider-owned intersection of request-shaped token evidence and every known physical input limit. It admits, rejects only a proven exact overflow, or defers ambiguity to upstream ({§tokenomics-context-envelope-admission}). `generate` performs this assessment for its exact request and preserves the evidence on success and capacity failure.
686
830
  - §provider-surface-prompt-measurement `provider.countPromptTokens(messages, signal)` — the cancellable complete-request measurement primitive used by provider capacity assessment, with `exact`, `upper_bound`, `estimate`, or `unavailable` provenance. Core never substitutes this physical fact for its curation ruler.
687
831
 
688
- §provider-surface-identity Provider capacity and identity are immutable for one instance. `contextWindow`, `maxInputTokens`, and `maxOutputTokens` carry known model limits; `outputBudget` is the total generation envelope, optional `reasoningBudget` is its strict subset, and `inputCapacity` is the stable intersection of known input constraints ({§tokenomics}). Unknown facts remain `null`. `model` identifies persisted turn/provider evidence. Local GBNF boot verification also consumes `constrainsOutput` ({§grammar-enforcement-verified-at-boot}).
832
+ §provider-surface-identity Provider capacity and identity are immutable for one instance. `contextWindow`, `maxInputTokens`, and `maxOutputTokens` carry known model limits; `outputBudget` is the total generation envelope, optional `reasoningBudget` is its strict subset, and `inputCapacity` is the stable intersection of known input constraints ({§tokenomics}). Unknown facts remain `null`. `model` identifies persisted turn/provider evidence. Local GBNF admission also consumes `constrainsOutput` ({§grammar-configuration-admission}).
689
833
 
690
834
  §meta-passthrough **Metadata passthrough (provider → client).** `generate` may return an open `meta: Record<string, unknown>` bag. The service stores it unenforced per turn (`turns.meta`, `json_valid` only — no schema) and forwards the latest turn's blob in `loop/terminated.usage` ({§notifications}). The service never reads a field within it. Providers own their metadata shapes; monetary values carry an explicit amount and currency rather than an implied unit. Absent → `{}`. The mirror direction (client → provider, the self-identified `client` id) rides `generate({client})` ({§attribution}).
691
835
 
@@ -703,9 +847,11 @@ Three current entry points:
703
847
 
704
848
  A completed provider exchange is an **emission attempt**, not necessarily an engine turn. The provider transports and observes the model's bytes; ANTLR is the admission authority only after provider completion. Admission asks whether the exchange has a trustworthy frame: its first parsed operation is PLAN, its last parsed operation is a terminal SEND, every hard parse error is bounded between those anchors, and no `unparsedTail` exists. Missing anchors, an error outside the frame, or a boundary-destroying tail rejects the entire exchange regardless of `finishReason`; no recovered prefix dispatches. Parser warnings remain admissible. `finish=length` is forensic evidence of likely truncation, not an independent rejection rule. A provider-declared resource interruption never reaches admission, even when its partial bytes form a complete-looking frame ({§provider-interrupted-attempt}).
705
849
 
706
- Core retries a rejected emission against the exact same packet beneath the same engine turn, up to `PLURNK_SERVICE_EMISSION_ATTEMPTS`. Rejected bytes never dispatch or reach the engine strike rail. Before each `generate`, Core opens one durable logical `model_calls` row and its emission-specific `turn_attempts` admission row. A call that ends without response evidence leaves that admission row unclassified (`accepted IS NULL`) and does not consume the emission-attempt ceiling. Beneath the model call, every provider observer invocation opens one cardinal `provider_requests` occurrence immediately before physical I/O and settles it as response or error. Adapter retries and capacity failover append requests in issue order; a response-less failure therefore remains an accounted occurrence rather than disappearing. Normalized response evidence is durable before parser classification and does not duplicate the separately owned accounting. The accepted exchange alone completes `turns.packet`; every physical request remains in turn and loop accounting, while the context gauge reads the latest settled emission request on the latest turn. Digest exposes rejected response evidence as `packetNNN.attemptNNN.rejected.*` and every physical request in its machine-readable ledger.
850
+ §safe-uri-target-groups After source and authored-command admission, Core tolerates one target group on READ, FOLD, or OPEN only when splitting its raw target at top-level comma or whitespace separators produces at least two members and every member independently parses as an explicit `scheme://` URI. Request-metadata blocks are opaque to this split. Each member becomes one ordinary statement with an independent dispatch outcome and log row, in authored member order; scheduling may still move the complete operation class under {§op-mode-phases}. Otherwise the target remains exactly singular, including local filenames containing spaces or commas. The stored `turnOps` and authored command count remain unexpanded, and no other operation admits target groups.
707
851
 
708
- The first exhaustion in a consecutive sequence closes that unadmitted turn as a continue and opens exactly one ordinary recovery turn. Its packet projects the latest rejected response OPEN from a durably FOLDED model item under {§model-entry-log-curation} and carries one transient `invalid_emission` Notice whose complete message is: `Your previous response contained an unrecoverable syntax error. No operations were performed. Try again.` No parser diagnostic, attempt count, or rail state becomes model-facing. The recovery turn has its own honestly stored packet and its configured private same-packet attempts. The packet-local projection never changes the row's curation state, so no later packet repeats the malformed body unless the model explicitly OPENs it. Admission clears the recovery state; exhausting the informed turn terminates instead of opening another.
852
+ Core retries a rejected emission against the exact same packet beneath the same engine turn, up to `PLURNK_SERVICE_EMISSION_ATTEMPTS`. Rejected bytes never dispatch or reach the engine strike rail. Before each `generate`, Core opens one durable logical `model_calls` row and its emission-specific `turn_attempts` admission row. A call that ends without response evidence leaves that admission row unclassified (`accepted IS NULL`) and does not consume the emission-attempt ceiling. Beneath the model call, every provider observer invocation opens one cardinal `provider_requests` occurrence immediately before physical I/O and settles it as response or error. Adapter retries and capacity failover append requests in issue order; a response-less failure therefore remains an accounted occurrence rather than disappearing. Normalized response evidence is durable before parser classification and does not duplicate the separately owned accounting. The accepted exchange alone extends `turns.packet` with response evidence; every physical request remains in turn and loop accounting, while the context gauge reads the latest settled emission request on the latest turn. Digest exposes rejected response evidence as `packetNNN.attemptNNN.rejected.*` and every physical request in its machine-readable ledger.
853
+
854
+ The first exhaustion in a consecutive sequence closes that unadmitted turn as a continue and opens exactly one ordinary recovery turn. Its packet projects the latest rejected response OPEN from a durably FOLDED emission-attempt item under {§rejected-emission-entry} and carries one transient `invalid_emission` Notice whose complete message is: `Your previous response contained an unrecoverable syntax error. No operations were performed. Try again.` No parser diagnostic, attempt count, or rail state becomes model-facing. The recovery turn has its own honestly stored packet and its configured private same-packet attempts. The packet-local projection never changes the row's curation state, so no later packet repeats the malformed body unless the model explicitly OPENs it. Admission clears the recovery state; exhausting the informed turn terminates instead of opening another.
709
855
 
710
856
  An admitted frame may contain bounded malformed statements. Parsed operations still dispatch; each malformed statement becomes one durable model-origin `error` row with the parser's exact diagnostic under {§parse-diagnostics} and status 400. These failures are committed before the terminal disposition, participate in the ordinary strike rail, and prevent SEND signal `200` or an already-drained signal `202` from concluding before the model sees them in the next packet. This is operation recovery, not provider resampling.
711
857
  The Problem recovery states that only the failed operation needs correction
@@ -759,27 +905,42 @@ it or reinterpret a malformed tag list.
759
905
  service-side caching, per-loop selection, context-cap handling, and local GBNF
760
906
  verification. Cataloged providers use Models.dev metadata and official AI SDK
761
907
  bindings; an operator declaration covers an uncataloged compatible endpoint;
762
- plugin discovery is the last protocol-extension seam.
908
+ plugin discovery is the last protocol-extension seam. Cache identity includes
909
+ the alias, wire route, and complete provider-knob projection; a registered
910
+ preconstructed handle occupies that same identity and cannot shadow changed
911
+ tuning.
763
912
 
764
- §grammar-enforcement-verified-at-boot **Optional local GBNF is verified at boot.**
913
+ §grammar-configuration-admission **Optional local GBNF is admitted without model generation.**
765
914
  The ANTLR grammar always defines and validates the PLURNK language. Separately,
766
- an operator may configure `PLURNK_PROVIDERS_GBNF_<alias>` for a local
767
- llama-server. The provider must advertise GBNF transport and satisfy a forcing
768
- probe whose sampled sentence and pre-projection response match the selected
769
- rail's template boundary followed by the `PLURNK-RAILS-LIVE` sentinel, or boot
770
- fails. The setting is resolved
771
- per alias and is unset by default. Configuring it on a cloud or endpoint-managed
772
- provider is an error, not a request for best-effort filtering.
773
- Alias-scoped `PLURNK_PROVIDERS_GBNF_DEBUG` deliberately withholds transport, so
774
- boot skips the enforcement probe while real requests retain the configured rail
775
- for local syntax validation and the engine's withheld-rail verdict.
776
- Runtime injection uses the provider's registered alias, falling back only to
777
- the process's active alias. Suffixed rail settings with neither identity fail
778
- instead of guessing. A configured package variant or explicit path that cannot
779
- be loaded also fails; it never silently becomes unconstrained.
915
+ an operator may configure global `PLURNK_PROVIDERS_GBNF` or
916
+ `PLURNK_PROVIDERS_GBNF_<alias>` for a local
917
+ llama-server. Startup requires the provider to advertise GBNF transport and a
918
+ reasoning-compatible configuration, but daemon lifecycle grants no inference
919
+ or spending authority and therefore generates no verification tokens. The
920
+ setting is resolved globally for an exact route and per alias for a declared
921
+ alias; it is unset by default. Configuring it on a cloud
922
+ or endpoint-managed provider is an error, not a request for best-effort
923
+ filtering. Every user-authorized constrained generation proves transport through
924
+ its exact pre-projection evidence ({§rail-truth-engine-verdict}). Alias-scoped
925
+ `PLURNK_PROVIDERS_GBNF_DEBUG` is the explicit exception: it deliberately
926
+ withholds transport while retaining local grammar validation and the engine's
927
+ withheld-rail verdict. Runtime injection uses the provider's registered alias,
928
+ falling back only to a real process-active alias; an alias-free route uses the
929
+ global setting and ignores unrelated suffixes. A configured package variant or
930
+ explicit path that cannot be loaded also fails; it never silently becomes
931
+ unconstrained.
932
+
933
+ §grammar-rail-registration **Rail variants are built-in names or import
934
+ specifiers.** A bare variant (no `/`, no `:`) resolves as a built-in rail
935
+ subpath under `@plurnk/plurnk-contracts`. Any other variant form is an import
936
+ specifier — an absolute or relative operator file path, or a package export
937
+ subpath (e.g. `@acme/plurnk-rails/custom.gbnf`) — resolved through the Node
938
+ resolution chain, so a third-party rail package plugs in with no built-in
939
+ registry. An unresolvable or unreadable rail fails the constrained generation
940
+ loudly; it never silently becomes unconstrained.
780
941
 
781
942
  §gbnf-requires-reasoning Both shipped PLURNK rails require reasoning. The same alias-scoped configuration
782
- must resolve reasoning to `adaptive` or `on`; `off` with GBNF is rejected before
943
+ must resolve reasoning to `adaptive` or a supported fixed effort; `off` with GBNF is rejected before
783
944
  the probe or any model generation. Reasoning-off remains valid when no GBNF rail
784
945
  is configured.
785
946
 
@@ -787,9 +948,9 @@ is configured.
787
948
  For a configured local GBNF, the provider returns the pre-projection sentence as
788
949
  `grammarEvidence` under `plurnk-providers` {§gbnf-response-observation}. The engine
789
950
  requires that evidence, independently validates `grammarEvidence.input` with the
790
- artifact's declared response root, and
791
- stamps `railsAttached: "client"` when transported or `"withheld"` in debug mode
792
- plus `railsVerdict`; it never validates projected
951
+ artifact's declared response root, and requires `transported: true` unless the
952
+ operator explicitly enabled debug mode. It stamps `railsAttached: "client"`
953
+ when transported or `"withheld"` in debug mode plus `railsVerdict`; it never validates projected
793
954
  `assistant.content` as though the required reasoning enclosure were still
794
955
  present. A non-accept verdict emits one `grammar_unenforced` notice. A raw
795
956
  position at or after `contentStart` is translated to a content offset; a failure
@@ -819,21 +980,25 @@ Author-facing contract: [`@plurnk/plurnk-schemes`](../plurnk-schemes/SPEC.md). B
819
980
 
820
981
  When an op carries a target, RFC 3986 supplies the component model and WHATWG
821
982
  URL supplies canonical decomposition; an entry key is
822
- `(workspace, owner, scheme, pathname)` ({§entry-identity-no-null}). Handler
823
- routing and resource identity are separate:
824
-
825
- - §scheme-address-namespace-fold A **registered non-network, non-worker scheme** mechanically folds its authority into the canonical storage pathname (`Dispatcher.#extractTarget` → `foldAuthorityIntoPath`). For an entry namespace, the authority is therefore a leading path segment rather than a separate identity component.
826
- - The **`worker` scheme is the registered exception**: its authority selects an owner ({§worker-authority-carving}) and remains distinct through dispatch; the handler strips it only after resolving the entry owner.
983
+ `(owner, scheme, authority, pathname)`; the owner Worker determines the
984
+ workspace ({§entry-identity-no-null}).
985
+ The registered manifest's {§manifest-authority} disposition determines the one
986
+ meaning of an authored URI authority before any entry capability is exposed:
987
+
988
+ - §scheme-address-namespace-fold A **namespace scheme** mechanically folds its authored authority into the canonical storage pathname and persists the empty entry authority. For an entry tree, the authored authority is therefore a leading path segment rather than a separate resource coordinate.
989
+ - An **owner scheme** consumes its authored authority while resolving `entries.owner_id` and persists the empty entry authority. `worker` uses this disposition ({§worker-authority-carving}).
990
+ - A **resource scheme** preserves its canonical authority as the durable entry-authority coordinate. Every capability and exact query is bound to that authority; it cannot collide with or observe the same pathname at another authority.
827
991
  - §scheme-address-network A **network resource** uses the shared schemes-layer
828
992
  normalization contract {§network-address}:
829
993
  `https://example.com:8443/page?b=2&a=1` →
830
- `(https, /example.com:8443/page?b=2&a=1)`. The exact protocol, canonical
994
+ `(https, example.com:8443, /page?b=2&a=1)`. The exact protocol, canonical
831
995
  host, non-default port, path, and serialized query are identity; query order,
832
996
  duplicates, and an explicit empty `?` survive. A fragment is a Plurnk channel
833
997
  selector, not network identity or transport. URL userinfo is rejected and
834
- request metadata never enters identity. `https` may route through `http`,
998
+ request metadata never enters identity. Plain `http` routes through `https`,
835
999
  just as `ws` routes through `wss`; those implementation aliases never alias
836
- resources. `SchemeCtx.entries` binds every cap to the addressed protocol.
1000
+ resources, and the secure face is the one taught — `http` stays supported
1001
+ for the endpoint that requires it, never advertised as a peer. `SchemeCtx.entries` binds every cap to the addressed protocol.
837
1002
  Absolute network URLs are single resources even when their path ends `/` —
838
1003
  folder/glob expansion belongs to entry namespaces, never an HTTP origin.
839
1004
  - The **`file` class is the workspace filesystem** — a mount namespace with its own resolution and naming law, specified below.
@@ -841,37 +1006,83 @@ routing and resource identity are separate:
841
1006
  §client-entry-address A client entry read carries the observing `workerId` and
842
1007
  passes its selector through the registered data scheme's
843
1008
  {§entry-address-resolution} before querying storage. The scheme returns its
844
- canonical pathname and semantic owner; core alone resolves that owner to
845
- `entries.owner_id` and queries the complete `(workspace, owner, scheme,
846
- pathname)` identity. Worker and capability-stream authorities reuse their
1009
+ canonical authority, pathname, and semantic owner; core alone resolves that
1010
+ owner to `entries.owner_id` and queries the complete `(owner, scheme,
1011
+ authority, pathname)` identity. Worker and capability-stream authorities reuse their
847
1012
  ancestry checks, so unknown or unauthorized owners return the same 404 and
848
1013
  cannot select an arbitrary colliding row. The result is the contracts-owned
849
1014
  {§entry-read-result}; persistence columns never cross the seam.
850
1015
 
1016
+ §scheme-entry-matrix URI authority, entry principal, access, and fork
1017
+ inheritance are independent decisions. The built-in surfaces declare them
1018
+ explicitly:
1019
+
1020
+ | Surface | URI authority | Entry principal | Cross-Worker read | FORK entry disposition |
1021
+ |---|---|---|---|---|
1022
+ | Project file | Filesystem name | `commons` | Workspace-shared | Shared live; no copy |
1023
+ | `worker:///...` | Empty selects commons | `resolved` commons | Workspace-shared | Shared live; no copy |
1024
+ | `worker://~/...` | `~` selects caller | `resolved` Worker | Self; parent may use the child's literal name | Quiescent snapshot; `_plurnk/**` rederived |
1025
+ | `worker://<name>/...` | Literal Worker selector | `resolved` Worker | Owner or ancestor | Scheme disposition only when the selected owner is the fork source; otherwise no copy |
1026
+ | `prompt:///...` | Loop-relative coordinate | Calling Worker | Self-only | Quiescent snapshot |
1027
+ | Provisional `skill:///...` | Entry namespace | Calling Worker | Self-only | Quiescent snapshot |
1028
+ | `http(s)://...` | Remote resource identity | Calling Worker | Self-only | Quiescent snapshot; an active stream is omitted |
1029
+ | `wss://...` | Remote resource identity | Calling Worker | Self-only | None |
1030
+ | Executor/MCP output | Optional named actor selector | `resolved` Worker | Owner or ancestor | None |
1031
+ | `a2a://...` outbound resource | Remote-agent identity | Calling Worker | Self-only | None |
1032
+
1033
+ A resolved-owner scheme authorizes the actor selector before returning its
1034
+ principal; a numeric Worker id is never extension input. `worker` ownership has
1035
+ no cross-actor form. Thus identical HTTP, WSS, A2A, prompt, Skill, or unqualified
1036
+ executor addresses in independent root Workers are distinct resources without
1037
+ render-time filtering.
1038
+
851
1039
  §fs-namespace **The workspace is a mount namespace; `project_root` is the model's `/`.** Chroot semantics: host paths do not exist inside the jail, and no engine surface folds a host-absolute spelling onto a member. The root is **fixed immutably at workspace creation** (headless is forever); the namespace's mount table changes only through the declared membership overlay ({§membership}), never by re-rooting. At `project_root = /` the jail is the whole filesystem and every rule below degenerates to identity — the design's proof case, and the common benchmark topology.
852
1040
 
853
1041
  §fs-namei **Resolution is namei over the mount table.** The model's CWD is permanently `/`, so `src/x.md` and `/src/x.md` are the same name — the slash rule is a corollary, never a legislated equivalence. Resolution is lexical: `.` and `..` resolve before anything touches storage (`..` is legal *during* traversal); the final name lands in the root subtree (a bare key), on a declared outside-root mount (a `../`-prefixed key — the git-style overlay), or names nothing (404 carrying the resolved form). Containment is the resolution semantics — there is no separate traversal check to forget.
854
1042
 
855
1043
  §fs-canonical-name **One canonical name, storage ≡ wire: the git pathspec.** Member keys follow gitformat-index(5) verbatim (reference edition: git 2.47.3): relative to the workspace `project_root`, without leading slash, `/`-separated, no trailing slash or NUL. Directories are never entries and the root needs no name. When `project_root` is below the containing repository's top level, Git members above it naturally use the same `../`-prefixed CWD-relative names that `git ls-files` emits without `--full-name`; these are not outside-repository mounts. The database stores that root-relative key directly because workspace identity is rooted at the access point. Every model spelling canonicalizes before storage or comparison.
856
1044
 
857
- §fs-visibility-grantors **Visibility has three grantors; plurnk is never one of them.** A file is visible to the model only when admitted by (1) the client's explicit `pick` grant, (2) the containing repository's inclusion semantics (ls-files untracked-not-ignored − ignored), or (3) the AGENTS.md knob ({§policy-sections} auto-pulled as POLICY, deliberately not a member; a git-tracked AGENTS.md may separately be an ordinary member via grantor 2). Model creation is a WRITE permission, never a visibility source — the created file's visibility rides git's rules, so a gitignored creation would be invisible even to its creator (which is why the write gate refuses it — the blind-write closure in fs-write-surface}). **Counterintuitive on purpose**: a file physically inside the root that no grantor admits DOES NOT EXIST for the model. Every visible byte traces to the client's constraint table or the operator's Git rules, never to a Plurnk guess.
858
-
859
- §fs-write-surface **The write surface — mount semantics, grantor-keyed.** The project root is the model's one read-write mount; writability elsewhere tracks the grantor: *write permission = inside the root, or client-granted outside it Git grants read-write only within the project.*
860
-
861
- | Location | Path state | Admission | Result |
862
- |------------------------|---------------------|---------------------------|--------|
863
- | Project root | Absent | Git or client after write | Exclusive CREATE (`open(O_CREAT\|O_EXCL)` semantics), only when the result will remain visible. |
864
- | Project root | Existing member | Any grantor | Proposal-gated EDIT. |
865
- | Project root | Existing non-member | None | Refuse; reveal occupancy only, never content. |
866
- | Declared outside mount | Existing member | Client | Read-write, proposal-gated; the explicit pick acts as a per-file rw bind mount. |
867
- | Declared outside mount | Existing member | Git | Read-only. |
868
- | Declared outside mount | Absent | Any | Refuse; only the project root mints files. |
869
-
870
- The **blind-write closure** refuses a root create that Git would ignore and no
871
- client pick covers, because Plurnk never writes bytes its own sandbox cannot
872
- subsequently see. A non-Git root grants nothing by itself. Refusing an occupied
873
- non-member follows the POSIX exclusive-create precedent: namespace occupancy is
874
- not secret, but content remains dark.
1045
+ §fs-visibility-grantors **File visibility has two represented grantors; Plurnk never invents a private third one.** A file member is admitted by the active Git substrate or by an ordinary `pick` constraint. A `pick` is either explicit client policy or the exact, inspectable record of an accepted creation ({§fs-create-generated-pick}); both resolve to `constraint` membership. AGENTS.md remains auto-pulled as POLICY ({§policy-sections}), deliberately not a file member. A physically existing path that neither Git nor `pick` admits does not exist for the model and cannot be overwritten.
1046
+
1047
+ §fs-write-surface **The write surface — one admission and incorporation path.** Existing writes remain membership-gated. An absent path additionally crosses the effective creation scope and the complete constraint/Git policy before a proposal is issued. EDIT, COPY destinations, and MOVE destinations use this same path regardless of whether the producer is a model, client, plugin, or `_plurnk`.
1048
+
1049
+ | Case | Required admission | Accepted result |
1050
+ |------|--------------------|-----------------|
1051
+ | §fs-create-disabled Absent path, effective scope `none` | None | Refuse without touching disk. |
1052
+ | §fs-create-root Absent path inside `project_root` | Effective scope `root` or `namespace`; no matching `hide` or `view` | Exclusive CREATE (`open(O_CREAT\|O_EXCL)` semantics), then incorporation below. |
1053
+ | §fs-create-namespace Absent canonical `../` path | Effective scope `namespace`; no matching `hide` or `view` | Exclusive CREATE, then an exact `pick` so the outside member is read-write. |
1054
+ | §fs-create-ignored Absent path ignored by active Git | Matching **explicit** `pick` | Exclusive CREATE through that pick; an automatic/generated pick never overrides Git ignore. |
1055
+ | §fs-create-git Absent in-root path admitted by active Git | Not ignored | Exclusive CREATE followed by successful `git add -- <path>`; a staging failure falls back to an exact generated pick. |
1056
+ | §fs-create-pick Absent admitted path without Git incorporation | Existing explicit pick or automatic incorporation permitted | Exclusive CREATE followed by an exact generated pick when no explicit pick already covers it. |
1057
+ | §fs-write-member Existing in-root member | Git or pick membership; no matching `view` | Proposal-gated EDIT. |
1058
+ | §fs-write-outside Existing canonical `../` member | Pick membership; no matching `view` | Proposal-gated EDIT. Git-only outside members are read-only. |
1059
+ | §fs-write-nonmember Existing non-member | None | Refuse; reveal occupancy only, never content. |
1060
+
1061
+ §fs-create-incorporation **Creation incorporation is durable workspace state, not a transient entry exception.** `workspace_constraints.source` distinguishes an operator/client-authored `explicit` constraint from a runtime-authored `create` constraint. An explicit row interprets `glob` as a pattern; a generated row interprets the same field as one literal canonical path, so legal filename metacharacters never become wildcard syntax. Generated constraints appear through the ordinary `workspace.constraints` client surface. An explicit pick covering the same path always wins and is never demoted.
1062
+
1063
+ | Event | Generated-pick lifecycle |
1064
+ |-------|--------------------------|
1065
+ | §fs-create-generated-pick Successful creation not incorporated by Git or an existing explicit pick | Insert exact `{ effect: "pick", glob: canonicalPath, source: "create" }`. |
1066
+ | §fs-create-copy COPY to a new path | Incorporate the destination independently; the source is unchanged. |
1067
+ | §fs-create-move MOVE to a new path | Incorporate the destination, then remove the source's generated exact pick after deleting the source. |
1068
+ | §fs-create-kill KILL or accepted whole-resource deletion | Remove the deleted path's generated exact pick. |
1069
+ | §fs-create-explicit-promotion Explicit `pick` added at the same exact path | Promote/retain the row as `source: "explicit"`; later automatic cleanup cannot remove it. |
1070
+ | §fs-create-masked A later `hide` or active Git-ignore rule excludes a generated-pick member | Preserve the generated pick as dormant policy; removing the exclusion restores membership when the file still exists. A later `view` leaves it visible but read-only. |
1071
+ | §fs-create-ambient-delete Reconciliation confirms a generated-pick path disappeared outside Plurnk | Remove the generated exact pick; explicit picks remain operator policy. |
1072
+
1073
+ The file-creation invariants are deliberately redundant with the matrices only
1074
+ where the invariant closes an architectural failure mode:
1075
+
1076
+ - §file-create-no-orphans A successful create always ends in Git membership or a real pick; no accepted file is orphaned from the workspace that created it.
1077
+ - §file-create-no-clobber Creation is exclusive and an existing non-member remains unreadable and non-overwritable.
1078
+ - §file-create-exclusions-win `hide` and `view` outrank all automatic creation; active Git ignore is overridden only by an explicit pick.
1079
+ - §file-create-scope The effective creation scope is the minimum of the service ceiling and workspace setting; no call site or producer may widen it.
1080
+ - §file-create-producer-neutral The file contract depends on the operation and target, never the producer identity.
1081
+ - §file-create-single-owner File membership owns prospective admission, incorporation choice, and generated-pick lifecycle; file operations consume that decision rather than re-deriving Git and constraint policy.
1082
+ - §file-create-transaction Success requires both exclusive disk creation and durable incorporation. Approval re-resolves physical containment and policy, so a proposal-time parent cannot be swapped for an outside-pointing symlink. Incorporation failure removes the created entry and file; incomplete rollback is an explicit partial-failure Problem.
1083
+
1084
+ Refusing an occupied non-member follows the POSIX exclusive-create precedent:
1085
+ namespace occupancy is not secret, but content remains dark.
875
1086
 
876
1087
  §fs-answer-in-canon **The engine answers in canon.** Every engine-authored address — log-row pathname columns, rx spans and error facts, FIND results, the catalog, the foists — renders the one canonical form: exactly what `git ls-files --full-name` prints, byte-for-byte on the git-membership subset. A miss names the RESOLVED form, never an echo of the model's spelling. The single verbatim survivor is the model's own emission text — history is never rewritten. There is no shadow universe of model-preferred addressing.
877
1088
 
@@ -888,7 +1099,7 @@ Every fact names the canonical key, never the host root or an echo of the
888
1099
  model's spelling. These classes let a caller distinguish a wrong address, an
889
1100
  invalid range, read-only authority, and occupied hidden state without guessing.
890
1101
 
891
- §fs-world-state **The world-state harness — coverage that closes the class.** Op-outcome tests check what an op returned; the harness checks the resulting world. `WorldState.check(db)` asserts, pure-db and read-only: identity uniqueness in practice (no tuple holds two rows), the canonical fixpoint on every file-class key, channel orphan-freedom, the closed admission set (a file row's grantor is git or a client act or the create-accepted transient NULL the next reconcile stamps), and sig-coherence. It runs as a lifecycle-test epilogue and at every soak turn boundary, where the delta half applies: an idle turn grows the entries table by ZERO. A violation names its law and its row.
1102
+ §fs-world-state **The world-state harness — coverage that closes the class.** Op-outcome tests check what an op returned; the harness checks the resulting world. `WorldState.check(db)` asserts, pure-db and read-only: identity uniqueness in practice (no tuple holds two rows), the canonical fixpoint on every file-class key, channel orphan-freedom, the closed admission set (every file row's origin is Git or constraint), and sig-coherence. Generated-pick incorporation and lifecycle require filesystem/Git evidence and are covered by the composed creation matrix rather than a false pure-database proxy. The harness runs as a lifecycle-test epilogue and at every soak turn boundary, where the delta half applies: an idle turn grows the entries table by ZERO. A violation names its law and its row.
892
1103
 
893
1104
  ### §scheme-manifest Manifest
894
1105
 
@@ -962,7 +1173,9 @@ Directed SEND (non-null path) routes to scheme's `send`. Status = intent:
962
1173
 
963
1174
  - §log-uniform-query **Log speaks the universal query contract** — `## FIND0 (log://…)` works like every scheme's FIND. Candidates are worker rows scoped by the coordinate hierarchy ({§log-coordinate-hierarchy}) and projected exactly as READ shows them. Content dialects use `Matcher.matchCandidates`; `~semantic` and `@graph` use the same persistent derivation artifacts and candidate rankers as entries. Broad results are one-channel catalog groups whose `[0].path` is `log:///loop/turn/seq/OP`; exact matcher results are flat locations ({§find-result-projection}). A FIND signal classifies the FIND result row and never changes this candidate set ({§log-item-tags}). Log remains the core event ledger rather than duplicating rows into `entries`; its core-private storage adapter supplies one complete channel representation to the same READ projector. That adapter is not a plugin seam and grants no protocol scheme an alternate READ path.
964
1175
  - §find-source-agnostic **The content matcher is source-agnostic** — `Matcher.matchCandidates(body, candidates, mimetypes)` applies a content matcher (regex/jsonpath/xpath/glob) to candidates from ANY source, keyed by the caller's own identity (a pathname for entries, a `loop/turn/seq` coordinate for log). The matcher never cares what table the content came from, so FIND works uniformly across schemes by construction: `EntryFind` and `Log.find` run the one shared primitive rather than re-implementing it per scheme. Log stays its own event stream, but its rows are candidates the shared matcher covers like any entry's content.
965
- - §matcher-selection-signal **Matching carries navigation evidence** - a matcher is a boolean resource predicate. Internally, each selected resource carries `matches: MatchEvidence[]`, where `MatchEvidence` is `{locator?,region?}`. `locator` preserves a structural address without overloading the resource row's `path`; `region` is a complete four-coordinate `TextRegion` only when the finding maps honestly into the exact text the model can READ. Exact duplicate evidence deduplicates. Relation findings map their indexed source spans through the same readable text coordinate index. FIND alone decides whether that grouped selection projects as resource rows or flat locations (find-result-projection}); the engine never fabricates a region or guesses which surgical READ the model wants.
1176
+ - §channel-selection-visibility **Channel selection is decision-time information, not a guess** every multi-channel resource presents its channels with extents wherever FIND presents the resource: broad results list each channel's path, mimetype, tokens, and lines (default channel first), and matcher locations name the channel their line coordinates address. The packet never presents channels as equal and indistinguishable; extents derive from the stored channels by construction. Budget enforcement stays withoverflow-turn} this is information, not a second guard.
1177
+
1178
+ - §matcher-selection-signal **Matching carries navigation evidence** - a matcher is a boolean resource predicate. Internally, each selected resource carries `matches: MatchEvidence[]`, where `MatchEvidence` is `{channel?,locator?,region?}`; `channel` names the entry channel the finding was located in and is absent for channel-less resources such as log rows, so line coordinates cannot be mis-attributed across channels of the same resource ({§channel-selection-visibility}). `locator` preserves a structural address without overloading the resource row's `path`; `region` is a complete four-coordinate `TextRegion` only when the finding maps honestly into the exact text the model can READ. Exact duplicate evidence deduplicates. Relation findings map their indexed source spans through the same readable text coordinate index. FIND alone decides whether that grouped selection projects as resource rows or flat locations ({§find-result-projection}); the engine never fabricates a region or guesses which surgical READ the model wants.
966
1179
 
967
1180
  `## SEND0 [410] (path[#fragment])` also deletes the target entry/channel — an implemented side-effect, NOT taught to the model and with no live/demo surface. The model-facing delete idiom is KILL ({§move}).
968
1181
 
@@ -981,7 +1194,7 @@ interface PlurnkSchemeContext {
981
1194
  readonly workerId: number;
982
1195
  readonly loopId: number;
983
1196
  readonly turnId: number;
984
- readonly writer: "model" | "client" | "plurnk" | "plugin"; // WriterTier
1197
+ readonly writer: "model" | "client" | "_plurnk" | "plugin"; // WriterTier
985
1198
  readonly signal: AbortSignal | undefined;
986
1199
  readonly streamEventNotify?: StreamEventNotify;
987
1200
  readonly wakeWorkerNotify?: WakeWorkerNotify;
@@ -1001,14 +1214,14 @@ Engine → scheme guarantees:
1001
1214
  - `ctx` is fresh per call. No mutation across calls.
1002
1215
  - §universal-read-composition **Exact READ has one composition.** Core resolves
1003
1216
  canonical identity and owner once, gives a data scheme its optional
1004
- `prepareRepresentation({ target, pathname })` opportunity, reads the complete
1217
+ `prepareRepresentation({ target, authority, pathname })` opportunity, reads the complete
1005
1218
  canonical channels, selects the authored channel, applies binary and
1006
1219
  text-coordinate rules, and finally composes that channel's durable producer
1007
1220
  result. Preparation receives neither fragment nor `lineMarker`; finite work
1008
1221
  returns `200`, while only a retained live representation may return `102`
1009
1222
  ({§read-preparation}). No public handler can replace READ.
1010
1223
  - Exact FIND uses the same resolved identity and representation preparation
1011
- before standard entry selection, then composes the exact default channel's
1224
+ before standard entry selection, then composes the exact selected channel's
1012
1225
  durable producer result with the core-owned query projection. Broad FIND may invoke a custom `find()` for
1013
1226
  genuinely protocol-owned candidate enumeration, or `prepareFind()` followed
1014
1227
  by the standard catalog query. Acquisition never owns matcher, pagination,
@@ -1121,7 +1334,7 @@ model-independent ruler for stored/catalog weights and the model-facing curation
1121
1334
  confined to provider-owned physical capacity assessment
1122
1335
  ({§tokenomics-context-envelope-admission}).
1123
1336
 
1124
- §persistent-search-index **Persistent search index.** `SearchIndex.maintain` is the pre-model engine pass. Each searchable resource supplies an address and the exact readable body its READ exposes. Entries supply their default body; `LogBody` resolves each log row's canonical full body from its durable tx/rx envelope. Acquisition schemes project remote source material before storing that body; search never introduces a second hidden text projection. The readable body, mimetype, resolved text/binary classification, mimetype projection identity, embedder configuration, and applicable search exclusion form a content hash. Complete artifacts own FTS, vectors, symbol definitions, and references; resource rows hold only the attachment hash. Binary, empty, and excluded derivations do not invoke handler projections and therefore use one fixed no-projection identity.
1337
+ §persistent-search-index **Persistent search index.** `SearchIndex.maintain` is the pre-model engine pass. Every addressable entry channel supplies the exact readable representation its READ exposes; `LogBody` resolves each log row's canonical full body from its durable tx/rx envelope. Acquisition schemes project remote source material before storing addressable channels; search never introduces a second hidden text projection. The channel content, mimetype, resolved text/binary classification, mimetype projection identity, embedder configuration, and applicable search exclusion form a content hash. Complete artifacts own FTS, vectors, symbol definitions, and references; each `entry_channels` row or log row holds only its own attachment hash. Binary, empty, and excluded derivations do not invoke handler projections and therefore use one fixed no-projection identity.
1125
1338
 
1126
1339
  §search-exclusion **File-search eligibility is Core policy.**
1127
1340
  `PLURNK_SERVICE_SEARCH_EXCLUDE` is a comma-separated table of anchored
@@ -1129,21 +1342,21 @@ body-glob patterns. Patterns containing `/` match the full pathname; every
1129
1342
  other pattern matches the basename. Whitespace around entries is ignored, an
1130
1343
  empty setting excludes nothing, and the first match is the observable reason.
1131
1344
 
1132
- | Search subject | Exclusion evaluation |
1133
- |--------------------|---------------------------------------------------------|
1134
- | `file` entry | Apply the configured repository-path patterns once. |
1135
- | Other-scheme entry | Always eligible; its pathname is a resource identity. |
1136
- | Log projection | Always eligible; it has no repository-path membership. |
1345
+ | Search subject | Exclusion evaluation |
1346
+ |----------------------|---------------------------------------------------------|
1347
+ | `file` entry | Apply the configured repository-path patterns once. |
1348
+ | Other-scheme channel | Always eligible; its pathname is a resource identity. |
1349
+ | Log projection | Always eligible; it has no repository-path membership. |
1137
1350
 
1138
1351
  A match produces the `excluded` derivation disposition and suppresses graph,
1139
- FTS, and vectors while leaving the stored body and direct READ unchanged. The
1352
+ FTS, and vectors while leaving the stored channel and direct READ unchanged. The
1140
1353
  same reason participates in the derivation hash and is surfaced by diagnostics
1141
1354
  and digests. Mimetype detection and projection do not read or report this
1142
1355
  scheme policy.
1143
1356
 
1144
1357
  ```mermaid
1145
1358
  flowchart LR
1146
- E["entry default body"] --> P["exact READ body"]
1359
+ E["entry channel"] --> P["exact addressed READ"]
1147
1360
  L["log result envelope"] --> P
1148
1361
  P --> H["content-addressed derivation"]
1149
1362
  H --> F["FTS"]
@@ -1156,7 +1369,7 @@ flowchart LR
1156
1369
  G --> Q
1157
1370
  ```
1158
1371
 
1159
- §derivation-exhaustive Identical projections attach the same immutable artifact regardless of their source table. Search primitives therefore consume only `{key, deepHash}` candidates and cannot depend on entry or log storage. Semantic and graph FIND require every selected candidate—and graph's relationship universe—to be attached. An incomplete set returns 503 with `problem.search = {state:"incomplete", indexed, total}`; it never silently searches a partial corpus. Normal execution joins the eager workspace warm before model dispatch, so that response is an interface invariant and diagnostic, not a lazy-search mode.
1372
+ §derivation-exhaustive Identical projections attach the same immutable artifact regardless of their source table. Search primitives therefore consume only `{key, deepHash}` candidates and cannot depend on entry or log storage. Semantic and graph FIND require every selected channel candidate—and every channel in graph's relationship universe—to be attached. An incomplete set returns 503 with `problem.search = {state:"incomplete", indexed, total}`; it never silently searches a partial corpus. Explicit membership changes may warm eagerly; every model turn joins exhaustive derivation before dispatch. Passive workspace creation and attachment do not launch it. The incomplete response is therefore an interface invariant and diagnostic, not a lazy-search mode.
1160
1373
 
1161
1374
  The graph projection stores only addressable symbol names. A structured-data handler may legitimately emit an empty key into its symbols channel, but the `@graph` matcher cannot name an empty symbol; that one definition is omitted from graph storage without suppressing FTS, vectors, or the remaining definitions. Invalid references and other persistence violations still fail the resource derivation explicitly.
1162
1375
 
@@ -1247,8 +1460,9 @@ Per-op semantics. AST shapes come from `@plurnk/plurnk-contracts`'s `PlurnkState
1247
1460
 
1248
1461
  ### §line-anchors Text line anchors
1249
1462
 
1250
- A scheme declaring `textEditScopes: true` with model write authority publishes
1251
- the contracts-owned {§text-line-anchor-syntax}. For canonical model-facing
1463
+ A scheme declaring `lineAnchors: true`, or `textEditScopes: true` with model
1464
+ write authority, publishes the contracts-owned {§text-line-anchor-syntax}.
1465
+ Model-writable `textEditScopes` implies anchors; `lineAnchors` alone makes no EDIT claim. For canonical model-facing
1252
1466
  resource identity `R`, one-based line ordinal `L`, configured non-negative
1253
1467
  neighbor count `C`, and ordered content array `W` containing that line and up to
1254
1468
  `C` complete lines on either side (all excluding separators), core hashes the
@@ -1345,13 +1559,15 @@ copied with log history on fork.
1345
1559
 
1346
1560
  ### §open-fold OPEN / FOLD
1347
1561
 
1348
- AST: `{ op: "OPEN"|"FOLD", target, body: MatcherBody | null, signal: tags | null, lineMarker: null }`.
1562
+ AST: `{ op: "OPEN"|"FOLD", target, body: MatcherBody | null, signal: tags | null, lineMarker: TextLineMarker | null }`.
1349
1563
 
1350
- OPEN/FOLD operate on the **log** (`log:///`) - the model's context-curation surface ({§packet}). FOLD collapses a log row to its path; OPEN restores its ordinary packet projection, including any preview bound ({§body-projection}). Both select by target, matcher, and the symmetric ALL-tags filter, then apply the tag changes defined by {§log-item-tags}. The canonical full body remains available through READ of the log URI with `<1,-1>`. Non-destructive: rows and bodies persist. On any valid row, applying its current state again or targeting a bodyless row is a successful visibility no-op; classification changes still land. Malformed targets and nonexistent exact coordinates fail at their addressing boundary. Entries carry no visibility ({§no-visibility}), so OPEN/FOLD against an entry scheme returns 501.
1564
+ OPEN/FOLD operate on the **log** (`log:///`) - the model's context-curation surface ({§packet}). Without a scope, FOLD hides and OPEN reveals the whole canonical log body. With a one-line or inclusive two-line scope, each operation changes only that body's intersecting body-relative physical lines. An anchor may be one already published on that immutable body or one returned by READing its `log:///` identity; numeric lines outside a selected body and absent or ambiguous anchors are successful per-body no-ops. Both select rows by target, matcher, and the symmetric ALL-tags filter before independently applying the scope and tag changes to each selected row. Folded intervals are durable, sorted, disjoint, and compositional; `[]` is wholly open and `[[1,-1]]` wholly folded. The canonical body remains complete through log READ/FIND regardless of visibility. Rows and bodies persist, and classification changes still land when visibility is a no-op. Malformed targets, unsupported coordinate arity, and nonexistent exact coordinates fail at their owning boundary. Entries carry no visibility ({§no-visibility}), so OPEN/FOLD against an entry scheme returns 501.
1351
1565
 
1352
1566
  ### §jsonplurnk The Log's wire format
1353
1567
 
1354
- The `## Log` section renders as a fixed three-backtick `jsonplurnk` fence - a JSON array of entry objects, otherwise-valid JSON with **exactly one** deviation: an open, nonempty `body` is a raw multiline string. Its opening JSON quote is followed by a physical newline, every content line begins with a numeric `N:` or anchored `@hash N:` coordinate prefix whose separator is one or more ASCII spaces, and its closing quote appears at column zero before either the object close or a following member. Source quotes, braces, fences, and headings cannot collide with either boundary because source text never occupies column zero after projection; source backticks therefore cannot form a CommonMark closing fence. The fixed opener keeps the packet prefix stable across content changes. The carve-out is localized to `body`, so the strip-parser recognizes `"body":"` followed by a newline, consumes one or more coordinate-prefixed lines, and replaces the raw multiline value with an escaped JSON string while preserving following members to recover strict JSON. The body shape is a strict three-state invariant: `"display":"none","body":""` for no body, `"display":"folded"` with the ordinary projection withheld, and `"display":"open","body":"\n<coordinate>...\n"` with it shown. `path` is the complete model-facing log identity: when a projected operation exists it ends in `/OP`, and no separate `op` field duplicates it. Nonempty `tags` is the row's complete deduplicated, sorted folksonomy; an untagged row omits it. When an OPEN bounded projection differs from the canonical body, it appends `"chunk":"showing <selected> of <complete>"` after `body`; otherwise it omits `chunk`. Complete-line extents use inclusive two-coordinate line regions. A cut inside a line uses four-coordinate, start-inclusive and end-exclusive regions with 1-based Unicode code-point columns. The row's `path` remains the canonical READ target. The block is data only - no prose leads the fence. `tokens` is the model-facing projection of the row's curation weight: the room OPEN adds and FOLD saves. A FIND's nonzero `itemsTokenTotal` weighs the complete matched set; a nonzero `returnedItemsTokenTotal` appears only when the returned page has a different weight. These are curation weights, not dollars. The invariants bind regardless of shape ({§packet}): addressability (`path`/`target`/`#channel`/coordinate-prefixed bodies), weighability (per-item `tokens`), honesty (every 4xx/5xx row and the exact body/display state). {§jsonplurnk} {§packet-jsonplurnk-exception}
1568
+ The `## Log` section renders as a fixed three-backtick `jsonplurnk` fence - a JSON array of entry objects, otherwise-valid JSON with **exactly one** deviation: an open, nonempty `body` is a raw multiline string. Its opening JSON quote is followed by a physical newline, every visible content line retains its canonical numeric `N:` or anchored `@hash N:` coordinate, and its closing quote appears at column zero before either the object close or a following member. Source quotes, braces, fences, and headings cannot collide with either boundary because source text never occupies column zero after projection; source backticks therefore cannot form a CommonMark closing fence. The fixed opener keeps the packet prefix stable across content changes. The carve-out is localized to `body`, so the strip-parser recognizes `"body":"` followed by a newline, consumes one or more coordinate-prefixed lines, and replaces the raw multiline value with an escaped JSON string while preserving following members to recover strict JSON. The three body states are self-describing through field presence alone: a `body` field means open, `tokensBody` without `body` means folded (the value prices the OPEN), and neither means no canonical body; no `display` label exists. Two defaults are likewise field absence: `origin` is omitted for the worker's own model authorship (exactly as `source` absence means the owning worker), and `status` is omitted for a routine 200 on a non-SEND row — SEND always carries its submit code and every non-200 stays explicit. A partially hidden open row also carries `"folded":["<scope>",...]`; coordinate gaps in its body make the omission explicit without renumbering later lines. `path` is the complete model-facing log identity: when a projected operation exists it ends in `/OP`, and no separate `op` field duplicates it. It leads each entry object; the remaining members follow in stable alphabetical order. A present authored operation annotation appears as `annotation`; its absence omits the field. Nonempty `tags` is the row's complete deduplicated, sorted folksonomy; an untagged row omits it. When an automatic bounded projection differs from the visibility-selected body, it appends `"chunk":"showing <selected> of <complete>"` after `body`; otherwise it omits `chunk`. Complete-line extents use inclusive two-coordinate line regions. A cut inside a line uses four-coordinate, start-inclusive and end-exclusive regions with 1-based Unicode code-point columns. The row's `path` remains the canonical READ target. The block is data only - no prose leads the fence. Every row's accounting: {§packet-token-accounting}.
1569
+
1570
+ - §packet-token-accounting Every row reports its real weight so the packet self-reconciles against the budget: `tokensBody` is the projected body's nonzero weight whenever a canonical body would render (never `0` — a priceless OPEN is field absence), and `tokensActive` is the complete row's weight in the packet right now. The metadata share is derivable (`tokensActive − tokensBody` when open; `tokensActive` otherwise) and is never serialized — it feeds no curation decision. Thus FOLD removes the rendered body's weight while KILL removes `tokensActive`; on a folded row `tokensBody` previews the body share an OPEN would activate. The completed row, including its accounting field and framing, is measured to a fixed point. A FIND's nonzero `itemsTokenTotal` weighs the complete matched set; a nonzero `returnedItemsTokenTotal` appears only when the returned page has a different weight. These are curation weights, not dollars. The invariants bind regardless of shape ({§packet}): addressability (`path`/`target`/`#channel`/coordinate-prefixed bodies), weighability (per-item `tokens`), honesty (every 4xx/5xx row and the exact body state). {§jsonplurnk} {§packet-jsonplurnk-exception}
1355
1571
 
1356
1572
  ### §retrieval-packet-metadata READ/FIND packet metadata
1357
1573
 
@@ -1363,7 +1579,7 @@ The packet projects one actionable owner for each retrieval fact:
1363
1579
  | exact-coordinate READ | none | top-level `region` | none |
1364
1580
  | READ-shaped materialization notice | none | none | generic body `lines` |
1365
1581
  | catalog/path FIND | compact `resource` range | none | none |
1366
- | broad matcher FIND | compact `resource` range | per-resource match-location counts | nonzero complete `matchLocationCount` |
1582
+ | broad matcher FIND | compact `resource` range | per-resource match-location counts; a resource with exactly one match also carries that match's `locator`/`region` | nonzero complete `matchLocationCount` |
1367
1583
  | exact matcher FIND | compact `matchLocation` range | each row's locator/region | none |
1368
1584
 
1369
1585
  The compact range is `{ unit, total, requested: [first,last], returned?:
@@ -1379,17 +1595,19 @@ generic body `lines` remains available on READ-shaped materialization notices
1379
1595
  that have no retrieval extent. FIND content weights follow {§jsonplurnk};
1380
1596
  ordinary bounded bodies expose their displayed and complete chunk extents there.
1381
1597
 
1382
- ### §model-entry The model's own emission, mirrored back
1598
+ ### §turn-ops-entry The admitted turn program
1599
+
1600
+ §turn-ops-log-curation A source-backed turn preserves its **exact admitted Plurnk program** as an actionless log item in addition to the ordinary result row for every dispatched statement. `op` is null, `attrs.kind="turnOps"` identifies the item, `origin` is the turn producer, no target exists, `tx` is empty, and the source lives in `rx.content`, typed `text/vnd.plurnk`. Its exact address is the undecorated three-part coordinate `log:///<L>/<T>/<S>` because it is the turn program, not another operation. It is line-numbered and OPEN/FOLD/KILL-able like any log body. The worker-initialization `turnOps` is born OPEN because it is the worked orientation example; every other `turnOps`, including model inference and overflow recovery, is born FOLDED and remains available on demand. Log-KILL clears the `writableBy` gate for a model-authored item (Log's handler surface — kill only — keeps every other mutating op at 501). The shared executor writes exactly one after every admitted source-backed turn.
1383
1601
 
1384
- §model-entry-log-curation A model-emission log row is the model's **verbatim emission**, mirrored back so it can inspect and curate its own behavior. It is an actionless artifact: `op` is null, `attrs.kind="model_emission"` identifies the row, no target exists, `tx` is empty, and the emission lives in `rx.content`, typed `text/vnd.plurnk`. Its exact address is the undecorated three-part coordinate `log:///<L>/<T>/<S>` because no operation exists to append. An admitted emission is **always born FOLDED** (budget-neutral), line-numbered like all content, and OPEN/FOLD/KILL-able like any log row. Log-KILL clears the `writableBy` gate for the model (the DB-storage curation lever plurnk.md teaches; Log's handler surface — kill only — keeps every other mutating op at 501). The engine writes one after each admitted model turn. The invalid-emission recovery item under {§emission-admission} mirrors only the latest rejected response, is born FOLDED with `attrs.admission="rejected"`, and is projected OPEN only in the informed recovery packet; every other rejected attempt remains forensic-only.
1602
+ §rejected-emission-entry A rejected provider response is not `turnOps`: it never became an admitted turn program. The one bounded invalid-emission recovery item under {§emission-admission} has `attrs.kind="emissionAttempt"`, `origin="model"`, and the exact latest rejected response. It is born durably FOLDED and projected OPEN only in the informed recovery packet; every other rejected attempt remains forensic-only.
1385
1603
 
1386
1604
  - §log-coordinate-hierarchy **Log coordinates are a hierarchical prefix; the trailing slash is optional** — a coordinate is `loop/turn/sequence`, and a PARTIAL coordinate selects its descendants: `log:///1` = loop 1's rows, `log:///1/2` = turn 1/2's rows, `log:///1/2/3` = the one row. A full coordinate is always three parts, so a one- or two-part path is unambiguously a prefix — the trailing slash is an optional alias (`log:///1/2` ≡ `log:///1/2/`), uniform with `## READ0 (worker:///docs/)`. A rendered operation row appends its canonical model-facing `/OP`, not a fourth resource level. Exact consumers tolerate the unsuffixed three-part shorthand; when supplied, the case-insensitive suffix is authoritative and a disagreement resolves 404. Typed entry materialization therefore resolves as `/READ` while retaining its durable `EDIT` event ({§exec-entry-sink}). `log:///1/2/*` still selects the turn's item rows, while `log:///**/READ` deliberately filters the canonical suffix.
1387
1605
  - §log-curation-folder-idiom **Log curation speaks the folder idiom; a zero-match sweep is a no-op success** — OPEN/FOLD/KILL take a concrete coordinate or a path-glob, and a **trailing slash or a partial coordinate means "the contents"** ({§log-coordinate-hierarchy}), like a folder-scoped FIND: `## FOLD0 (log:///1/2)` folds turn 1/2's rows. OPEN and FOLD may instead take only a tag filter ({§log-item-tags}). A **well-formed selection that matches nothing is 204 with `matched: 0`**; a successful sweep's rx carries `matched: N`. A targetless operation without tags or a matcher is 400.
1388
- - §log-curation-set-selection **Set selection, never positional curation** — target/glob, optional body matcher, and optional ALL-tags filter compose by intersection into the affected row set. OPEN and FOLD have no `<L>` marker and never paginate that set; FIND owns result pagination.
1606
+ - §log-curation-set-selection **Row selection and body scope are independent** — target/glob, optional body matcher, and optional ALL-tags filter compose by intersection into the affected row set. An optional `<L>` or `<SL,EL>` then intersects each selected canonical body; it never paginates or changes the selected set. Thus `## FOLD0 (log:///**/READ) <17,-1>` may change long READs and no-op on short ones while reporting every selected row in `matched`.
1389
1607
 
1390
- §fold-open-meta-operations **OPEN and FOLD are meta-operations — log-curation directives, not world actions.** They change log visibility and classifications, never the underlying resources. A **successful** OPEN/FOLD **is recorded in the log** but **suppressed from the packet render**: the row exists for forensics — a curation act with NO trace is how a weak model folding its own task frame stayed invisible until a database dig — while the render still costs it nothing, so FOLD stays genuinely free (the original rowless design's concern, met by hide-not-drop). Its exact selected target set, each target's pre-event visibility, and the classifications actually added and removed persist with that event; `matched: N` and the authored selector are not the database's sole effect evidence. The operation row, visibility changes, tag changes, and landed effects commit in one database statement. The emission also survives verbatim in its model-emission mirror. A **failed** OPEN/FOLD (bad target, matcher, or tag signal) renders normally with its status — errors are signals. The idle-turn gate reads the *emitted statements*, so a pure-curation turn is work, never idleness.
1608
+ §fold-open-meta-operations **OPEN and FOLD are meta-operations — log-curation directives, not world actions.** They change log visibility and classifications, never the underlying resources. A **successful** OPEN/FOLD **is recorded in the log** but **suppressed from the packet render**: the row exists for forensics — a curation act with NO trace is how a weak model folding its own task frame stayed invisible until a database dig — while the render still costs it nothing, so FOLD stays genuinely free (the original rowless design's concern, met by hide-not-drop). Its exact selected target set, each target's folded intervals before and after, and the classifications actually added and removed persist with that event; `matched: N` and the authored selector are not the database's sole effect evidence. The operation row, visibility changes, tag changes, and landed effects commit in one database statement with each before state as a collision guard. The authored program also survives verbatim in its `turnOps` item. A **failed** OPEN/FOLD (bad target, matcher, or tag signal) renders normally with its status — errors are signals. The idle-turn gate reads the *emitted statements*, so a pure-curation turn is work, never idleness.
1391
1609
 
1392
- §kill-log-receipt-suppressed **A successful KILL of a log item is suppressed from the render too — same principle, different mechanism.** KILL is a real deletion (not a meta-op), but once it has executed against a `log://` target its tombstone is *spent*: the killed row is gone, and a receipt saying "I deleted it" is no forward-actionable context. So a **successful** `KILL` whose target is a **log item** is recorded in the DB (forensics) and suppressed from the packet, while its emission survives in its model-emission mirror. Without suppression, every deleted row would create a replacement receipt, so per-row curation could not shrink the log. The suppression is **scoped to log targets**: a `KILL` of a `worker://` note, an `sh://` stream, or any stored artifact is a **world mutation**, not log housekeeping, and stays visible. A **failed** KILL (bad target, no match ≠ error but a malformed coordinate is) renders like any error.
1610
+ §kill-log-receipt-suppressed **A successful KILL of a log item is suppressed from the render too — same principle, different mechanism.** KILL is a real deletion (not a meta-op), but once it has executed against a `log://` target its tombstone is *spent*: the killed row is gone, and a receipt saying "I deleted it" is no forward-actionable context. So a **successful** `KILL` whose target is a **log item** is recorded in the DB (forensics) and suppressed from the packet, while its authored program survives in its `turnOps` item. Without suppression, every deleted row would create a replacement receipt, so per-row curation could not shrink the log. The suppression is **scoped to log targets**: a `KILL` of a `worker://` note, an `sh://` stream, or any stored artifact is a **world mutation**, not log housekeeping, and stays visible. A **failed** KILL (bad target, no match ≠ error but a malformed coordinate is) renders like any error.
1393
1611
 
1394
1612
  ### §log-sensitive-request-evidence Durable request evidence
1395
1613
 
@@ -1404,7 +1622,7 @@ secret detection.
1404
1622
  | Query and authored body | Preserved exactly; they are authored content and URI identity, not structurally identifiable credential slots. |
1405
1623
  | Parser failure | Preserves the structural diagnosis and source position without quoting request-metadata contents ({§path-request-metadata}). |
1406
1624
  | Client, fork, packet, and digest | Consume the stored projection; none owns a second redaction policy. |
1407
- | Model-call evidence and model-emission mirror | `model_calls.response` under {§emission-admission} and the folded row under {§model-entry-log-curation} remain exact forensic evidence and are the explicit exception. |
1625
+ | Model-call evidence and source artifacts | `model_calls.response` under {§emission-admission}, `turnOps` under {§turn-ops-log-curation}, and `emissionAttempt` under {§rejected-emission-entry} remain exact forensic evidence and are the explicit exception. |
1408
1626
 
1409
1627
  ### §copy COPY (engine-orchestrated)
1410
1628
 
@@ -1467,11 +1685,12 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
1467
1685
  AST: `{ op: "FIND", target (scope), body: MatcherBody | null (predicate), signal: tags | null, lineMarker? }`.
1468
1686
 
1469
1687
  - §find-scope-prefix-filter Filters entries within scope. A **bare** path is the exact entry; an explicit **shell glob**, classified once by {§path-glob}, expands to a scope. Path globs use segment semantics: `*` and `?` never cross `/`; `**` does. Terminal `*` and `**` are structural catalog selectors and include dot-prefixed entries, so a complete map does not hide `.env.defaults` or `.github`; richer patterns retain native shell behavior. SQLite prefix queries may reduce the candidate set but never decide the match. A trailing slash is a recursive FIND scope only for a scheme whose manifest declares `folderScopes: true`; otherwise it is ordinary resource syntax. This is an explicit plugin contract, never inferred from URL punctuation.
1470
- - An exact target resolves to the same canonical `(scheme, pathname)` identity
1688
+ - An exact target resolves to the same canonical `(scheme, authority, pathname)` identity
1471
1689
  as READ, entry CRUD, and any preceding `prepareFind()`. URI authorities are
1472
1690
  identity-bearing: `https://example.com/page` queries
1473
- `(https, /example.com/page)`, never `(https, /page)`.
1474
- - §find-glob-filter-on-content `body` matcher operates on entry content (glob/regex/jsonpath/xpath), per `plurnk.md` "Pattern Filtering"; the path-glob lives in the (target), not the body.
1691
+ `(https, example.com, /page)`, never an empty-authority row at `/page`.
1692
+ - §find-channel-selection The target selects a channel under {§channel-selection}. That channel controls candidate eligibility, every matcher dialect's content or derivation, match-evidence coordinates, and exact producer-result composition. A selected channel absent from an exact entry is 404; a broad scope simply excludes entries lacking it. Successful resource-mode results remain complete default-first channel groups, so sibling channels are navigable catalog metadata rather than additional matches.
1693
+ - §find-glob-filter-on-content `body` matcher operates on the addressed entry channel (glob/regex/jsonpath/xpath), per `plurnk.md` "Pattern Filtering"; the path-glob lives in the (target), not the body.
1475
1694
  - §find-semantic-selection Every matcher operates only over the candidate set selected by `(target)`; relation matchers do not bypass that selection. Semantic ranking is exhaustive within that candidate set, then applies the ordinary FIND result scope. Markerless semantic FIND therefore uses the same `<1,16>` default as every other matcher. Integers retain FIND's positional contract: `<N>` selects result N and `<N,M>` selects the inclusive range. A leading decimal first applies a minimum cosine-similarity threshold; following integers select positions within that ranked threshold set. Thus `<0.7,10,20>` means threshold 0.7 followed by results 10 through 20, while `<0.7>` applies the threshold and the ordinary first-16 page.
1476
1695
  - §find-scoped-isolation Workspace + scheme scoped — no cross-workspace/cross-scheme leakage.
1477
1696
  - §find-result-projection **The authored target shape determines the result unit; result cardinality never changes it** ({§find-result-unit}). Returns `FindResult { status, content, mimetype, results, range, matchingPathCount, matchLocationCount, itemsWeightTotal, returnedItemsWeightTotal }`:
@@ -1481,14 +1700,15 @@ AST: `{ op: "FIND", target (scope), body: MatcherBody | null (predicate), signal
1481
1700
  | exact | absent | `resource` | the one catalog channel group |
1482
1701
  | glob or folder | absent | `resource` | catalog channel groups |
1483
1702
  | glob or folder | present | `resource` | matching channel groups with `matchLocationCount` on `[0]` |
1484
- | exact | present | `matchLocation` | flat `{ locator?, region? }` locations |
1703
+ | exact | present | `matchLocation` | flat `{ channel?, locator?, region? }` locations |
1485
1704
 
1486
1705
  A glob or folder remains resource mode when it resolves to one path. An exact
1487
1706
  target remains location mode when it has many locations. A valid exact match
1488
1707
  with no addressable location is status 200 with `matchingPathCount: 1`,
1489
1708
  `matchLocationCount: 0`, and no fabricated row; a matcher selecting no
1490
1709
  resource is 204. A body-less broad empty catalog survey is status 200; an
1491
- absent exact resource is 404.
1710
+ absent exact resource is 404. Every entry-channel location names its `channel`
1711
+ ({§channel-selection-visibility}); log rows carry none.
1492
1712
 
1493
1713
  Inside `FindResult`, `matchingPathCount` and `matchLocationCount` describe the
1494
1714
  complete selection before pagination; the packet curates those facts under
@@ -1498,9 +1718,15 @@ AST: `{ op: "FIND", target (scope), body: MatcherBody | null (predicate), signal
1498
1718
  contains one nonempty, flat channel array per resource. Element `[0]` is always
1499
1719
  the default channel and carries the bare resource path; later elements carry
1500
1720
  their complete `path#channel` addresses. Each channel is
1501
- `{ path, mimetype, weight, lines, parseIssues? }`; `parseIssues` is the
1721
+ `{ path, mimetype, weight, lines, summary?, parseIssues? }`; `parseIssues` is the
1502
1722
  positive-only advisory projection of `{§mimetype-parse-issues}` for the exact
1503
- body derivation under `{§scheme-catalog-parse-issues}`. Resource-level `stream` and broad-match
1723
+ channel derivation under `{§scheme-catalog-parse-issues}`.
1724
+
1725
+ §scheme-catalog-summary **Catalog summary.** `summary` is the exact channel
1726
+ derivation's `{§mimetype-summary}` clipped to at most 256 Unicode code points
1727
+ including a visible terminal ellipsis; absent metadata is omitted.
1728
+
1729
+ Resource-level `stream` and broad-match
1504
1730
  `matchLocationCount` live only on `[0]`. A single-channel resource is therefore
1505
1731
  a one-element array, with no path-owning wrapper or duplicated channel map.
1506
1732
  A terminal single-star path scope is a one-level map: direct entries retain
@@ -1520,7 +1746,9 @@ AST: `{ op: "FIND", target (scope), body: MatcherBody | null (predicate), signal
1520
1746
  final model-facing representation from `weight` to `tokens`
1521
1747
  ({§json-result-rendering}), so universal packet numbering makes result
1522
1748
  ordinal N addressable as line N, matching `<N>` pagination without a second
1523
- coordinate system. Pagination is the only FIND materialization bound; no
1749
+ coordinate system. A returned page begins at `range.returned[0]`, and every
1750
+ page left-pads its ordinals to the decimal width of `range.total`; content
1751
+ therefore keeps one stable column across the complete result set. Pagination is the only FIND materialization bound; no
1524
1752
  hidden complete row or location collection is retained behind the public
1525
1753
  projection.
1526
1754
 
@@ -1562,7 +1790,7 @@ the loop continue; repeated offenses terminate through the engine's 500.
1562
1790
 
1563
1791
  - §send-idle-turn **Idle turn** — a continuing turn (102) whose ops are only PLAN/SEND — no work op. The model continued with nothing to do. The steer, verbatim: *"If your work is done, conclude with `## SEND0 [200]`. If you're waiting on a child or stream you spawned, use `## SEND0 [202]` to block on it — a 202 with nothing to wait on simply concludes."* A successful same-turn FOLD is the exception: its `202` continues without a strike so the curated packet can support the next reasoning turn.
1564
1792
  - §send-premature-terminate **Premature terminate — the pending set.**
1565
- Completion is gated by one rule: *nothing pending may be silently
1793
+ A model's completion claim is gated by one rule: *nothing pending may be silently
1566
1794
  discarded*. Pending work has two states: **live obligations** (open
1567
1795
  streams/spawns and live child workers) and **completed-but-unobserved
1568
1796
  results** (same-turn READ/FIND/OPEN results, failed operations, terminal
@@ -1572,12 +1800,16 @@ the loop continue; repeated offenses terminate through the engine's 500.
1572
1800
  and the loop continues; every refusal strikes uniformly, including a
1573
1801
  retrieval-only refusal. The pending kind changes the corrective message, not
1574
1802
  rail accounting. `[499]` deliberately abandons regardless.
1803
+ - §send-administrative-terminal **An administrative terminal closes its own
1804
+ transaction.** A client, plugin, or `_plurnk` operation program runs in its
1805
+ own administrative loop. Its SEND signal `200` concludes exactly that loop;
1806
+ it neither claims nor consumes the Worker's model-visible pending set. Model
1807
+ completion rails therefore apply only to a model-authored disposition.
1575
1808
  - §send-undelivered-child-term **Completion is not delivery.** A result becomes
1576
1809
  observed only after crossing a packet boundary. SEND signal `202` parks only on
1577
1810
  live obligations. If work has completed but is unobserved, it continues
1578
1811
  directly to the next packet because the wake edge has already fired; only a
1579
1812
  genuinely empty set with no successful same-turn FOLD resolves immediately like `[200]`.
1580
- - §send-300-choices **SEND signal `300` is an operator question - a PROPOSAL using the same stop-the-world system as file edits.** Enablement cascades: `PLURNK_QUESTIONS=0` is a servicewide ceiling; otherwise the client affirmatively requests per workspace (`settings.questions: true` at workspace creation), which ALSO injects the required `questions.md` teaching - capability and teaching gate as one ({§teaching-corpus}). An enabled workspace fails doc materialization with the read cause if that source is broken; a disabled workspace does not consume it. Enabled: the `;`-delimited body parses leniently (first segment the question, the rest choices; zero choices = an open question - never malformed), and the ask raises a proposal: dispatch stops the world, `loop/proposal` carries `{question, choices}` in attrs, and the client's accepted proposal body delivers the ANSWER - written into the ask's own model-facing rx (`{"status":200,"body":...}`), read next packet. Reject/timeout resolve through the standard {§proposal} semantics; the turn records a continue either way (never a 300 terminal), and the loop simply proceeds. Loop auto never auto-answers a question - it exists precisely to stop the world for a human, and the workspace opted in. Disabled: refused 409 with a self-decide steer, never a park into the void.
1581
1813
 
1582
1814
  ### §exec EXEC
1583
1815
 
@@ -1628,10 +1860,12 @@ target at its run boundary.
1628
1860
  core-owned temporary file after acceptance. Core reparses the complete authored
1629
1861
  address and resolves one exact `<1,-1>` READ through
1630
1862
  {§universal-read-composition}; internal source consumption never borrows the
1631
- model-facing 16-line preview. The file lives through the executor run and core
1632
- removes it after the subscription's terminal result has settled. A removal
1633
- failure is reported to daemon diagnostics with its complete cause; it cannot
1634
- rewrite the execution result, stream state, or completion wake.
1863
+ model-facing 16-line preview. Each spawn creates its file with an exclusive,
1864
+ process- and database-coordinate-independent identity. The file lives through
1865
+ the executor run and core removes it after the subscription's terminal result
1866
+ has settled. A removal failure is reported to daemon diagnostics with its
1867
+ complete cause; it cannot rewrite the execution result, stream state, or
1868
+ completion wake.
1635
1869
 
1636
1870
  Loop-flag authority follows the selected runtime's declaration:
1637
1871
 
@@ -1653,18 +1887,18 @@ effect-qualified hold policy. The post-acceptance materialization path never
1653
1887
  triggers reclassification.
1654
1888
 
1655
1889
  §exec-registry-resolves The runtime slot (`signal`) selects an executor from
1656
- the current workspace snapshot. Installed siblings form the immutable base:
1890
+ the current worker snapshot. Installed siblings form the immutable base:
1657
1891
  they are discovered and probed at startup, and availability is cached.
1658
- Workspace capability providers may atomically overlay additional names under
1659
- {§module-workspace-capabilities}; a name has one owner within a workspace, while
1660
- independent workspaces may use the same name. An absent or empty tag selects
1892
+ Worker Functionality providers may atomically overlay additional names under
1893
+ {§module-worker-capabilities}; a name has one owner within a worker, while
1894
+ independent workers may use the same name. An absent or empty tag selects
1661
1895
  `sh`; a non-empty tag selects exactly that registered executable tool. Unknown
1662
1896
  tags are refused 501 with direction to use only the advertised catalogue or
1663
1897
  put a complete command in bare `EXEC`; they are never reinterpreted as shell
1664
1898
  command words. An unavailable runtime is also 501 and carries the probe
1665
1899
  `detail`.
1666
1900
 
1667
- For a family runtime, `ExecutorRegistry.toolRegistry(tag, workspaceId)`
1901
+ For a family runtime, `ExecutorRegistry.toolRegistry(tag, workerId)`
1668
1902
  validates the one executor-owned snapshot used by packet presentation,
1669
1903
  dispatch admission, and pull-document materialization. Core performs no
1670
1904
  protocol discovery while building a packet and has no alternate tool
@@ -1707,7 +1941,17 @@ edge. Stream closure remains a wake edge under every poll policy.
1707
1941
 
1708
1942
  §exec-host-proposes **Effect-gating.** Each executor declares an `effect` (`pure` | `read` | `host`); the service maps it to policy (`EffectPolicy`). A `host` runtime (subprocess; file-backed sqlite) mutates the host → **propose** (lifecycle {§proposal}): the worker waits for a human gate, then spawns and writes stdout/stderr to channels of a `<runtime>:///<loop>/<turn>/<seq>` entry (the runtime tag is the URI scheme, {§exec}; the coordinate matches the op's log-row coordinate, e.g. `sh:///1/1/2`), returning `102 Processing` immediately. Channel state transitions (`active` → `closed`/`errored`) drive what the model sees at subsequent turn boundaries ({§channel-state}).
1709
1943
 
1710
- §entry-owner **Every entry is owned by a worker.** `entries.owner_id` is a real worker row, part of the identity key — the workspace's reserved `commons` worker for shared content, the spawning worker for capability streams. Never NULL (NULLs are distinct under UNIQUE — a nullable owner would let the shared-content identity fragment into duplicate rows), never rendered into a URI or packet: the model addresses owners by NAME in the authority slot. `plurnk` (the kernel) and `commons` are the two reserved rows; no spawn or client may take their names (nor `~`, the current-worker sigil).
1944
+ §entry-owner **Every entry has one structurally bound principal.**
1945
+ `entries.owner_id` is a real Worker row and part of the identity key: the
1946
+ workspace's reserved `commons` Worker for deliberately shared content, the
1947
+ effective Worker for private resources, or the exact authorized Worker selected
1948
+ by a resolved-owner scheme. It is never nullable or supplied by a plugin call.
1949
+ Core binds it once through {§entry-address-resolution} before exposing any
1950
+ entry, channel, notification, subscription, mutation, proposal, client-read, or
1951
+ cancellation capability. URI authority remains a separate coordinate; a scheme
1952
+ may use a semantic Worker name there, but the private numeric id never appears
1953
+ in a URI or packet. `plurnk` and `commons` are reserved Workers, and `~` is the
1954
+ current-Worker sigil; none can be minted by a spawn or client.
1711
1955
 
1712
1956
  §stream-owner-scoped **Capability streams are owner-scoped.** Concurrent workers' stream coordinates are loop-relative and IDENTICAL (every worker's first loop is sequence 1), so the entry identity keys on the owner and identical coordinates across workers are distinct rows. The address's authority names the owner: **empty = the calling worker** — your own streams need no qualifier, so a fan-out sibling's output can never surface under your READ — and a **named authority** reaches that worker's streams gated by ancestry (the reader is the owner or an ancestor; oversight flows down the tree, unknown-or-unpermitted resolves 404 with no existence leak). KILL stays self-only — a parent controls a child through the worker lifecycle, never by reaching into its streams. The storage pathname stays the bare loop coordinate; the owner rides the column, so nothing model-facing carries a worker id.
1713
1957
 
@@ -1715,11 +1959,19 @@ edge. Stream closure remains a wake edge under every poll policy.
1715
1959
 
1716
1960
  §exec-readpure-ungated A `read` runtime (observes external state, e.g. search) or `pure` runtime (no observable effect, e.g. `:memory:` sqlite) is side-effect-free → **auto-run**: no proposal, no human gate, no notification. Core persists the prepared operation before applying it; that write-ahead staging has no resolution waiter and therefore cannot enter proposal discovery ({§proposal-list}). It skips the gate a host command faces, but it does NOT resolve in-band — like every exec it backgrounds and streams, its output reaching the model through the environment-observation injector (a foisted READ of newly publishable stream content each turn, {§exec-stream}), never a same-turn receipt.
1717
1961
 
1962
+ §effect-policy-tunable **Effect admission is deployment-tunable.** The default
1963
+ map (`host` proposes; `read`/`pure` auto-run) is the contract; the operator may
1964
+ override it deployment-wide with `PLURNK_SERVICE_EFFECT_POLICY`, a
1965
+ comma-separated `<effect>:<policy>` list (e.g. `read:propose` proposes even
1966
+ read effects). Unlisted effects keep the default. An invalid entry — unknown
1967
+ effect, unknown policy, or a non-`<effect>:<policy>` shape — fails daemon boot
1968
+ loudly rather than degrading admission.
1969
+
1718
1970
  After all non-SEND operations dispatch, the initiating turn applies {§worker-optimistic-settlement} to only the EXEC streams it started, then dispatches its terminal SEND against the refreshed lifecycle state. An older stream receives no renewed opportunity merely because another turn began. This is a settlement barrier before disposition, not sibling-operation serialization: dependent EXECs remain separate observed turns.
1719
1971
 
1720
1972
  §exec-stream **Stream surfacing.** An exec's output is *observed, not fetched*.
1721
1973
  Each turn the environment-observation injector publishes newly publishable content
1722
- from each owned channel as an `origin=plurnk` READ at
1974
+ from each owned channel as an `origin=_plurnk` READ at
1723
1975
  `<runtime>:///<coord>#<channel>`, preserving the channel's current mimetype:
1724
1976
 
1725
1977
  | channel mimetype | while active | at terminal state |
@@ -1728,14 +1980,18 @@ from each owned channel as an `origin=plurnk` READ at
1728
1980
  | `application/jsonl` or `application/x-ndjson` | complete newline-terminated records | every remaining record |
1729
1981
  | every other mimetype | nothing | the complete atomic document |
1730
1982
 
1731
- The per-channel cursor advances only through content actually published, so an
1732
- active atomic document or trailing partial JSONL record never reaches the model
1733
- as malformed structured data. Ongoing observations are folded and a terminal
1734
- observation is born OPEN; a terminal state with no newly publishable body still
1735
- produces one conclusion row. Every READ then obeys {§body-projection} and
1736
- therefore renders its selected result complete. A stream that closes before a
1737
- same-turn wait remains pending until this terminal READ crosses the next packet
1738
- boundary. The EXEC row separately records the authored invocation.
1983
+ The durable per-subscription, per-channel cursor advances only through content
1984
+ actually published, so an active atomic document or trailing partial JSONL
1985
+ record never reaches the model as malformed structured data. Its transition and
1986
+ the generated READ commit atomically. Ongoing observations are folded and a
1987
+ terminal observation is born OPEN; a terminal state with no newly publishable
1988
+ body still produces one bodyless conclusion row. OPEN, FOLD, or KILL may curate
1989
+ that log row without rewinding the cursor or publishing the terminal result
1990
+ again; the exact terminal result and channel content remain READable at the
1991
+ stream address. Every READ then obeys {§body-projection} and therefore renders
1992
+ its selected result complete. A stream that closes before a same-turn wait
1993
+ remains pending until every selected channel's terminal READ crosses the next
1994
+ packet boundary. The EXEC row separately records the authored invocation.
1739
1995
 
1740
1996
  `## KILL0 (<runtime>:///<loop>/<turn>/<seq>)` cancels an active subprocess via
1741
1997
  the subscription registry's stored controller. A terminal stream is immutable:
@@ -1747,17 +2003,17 @@ stream cannot fall through an internal `exec`-only query. {§stream-control}
1747
2003
  §exec-env-scoped **Scoped environment.** An EXEC subprocess inherits the *project's* environment — its `.env`, the standard shell vars — so the model's commands run as the project expects; but never plurnk's own secrets: the provider API keys and `PLURNK_*` config are stripped before the spawn, so a model-executed command can't `printenv` the engine's keys. The service owns the scoping policy (the denylist); the executor spawns with the env it is handed.
1748
2004
 
1749
2005
  - §exec-hold-until-concluded **The turn-hold exception** — for runtimes in `PLURNK_SERVICE_EXEC_HOLD` (a decision-table env, shipped listing the search family), an in-flight stream **pauses the cycle**: the next packet does not assemble until the stream concludes, so the model never burns a turn asking "are we there yet" about a result the engine controls end-to-end. This exception is limited to seconds-bounded runtimes whose final result the engine controls end-to-end. Bounded by `PLURNK_SERVICE_EXEC_HOLD_MS` and **fail-open**: at the cap the standard cycle resumes untouched (waits, wakes, polls). Zero grammar or teaching surface — the model emits EXEC followed by SEND signal `102` as ever; the wake-shaped world simply arrives one packet sooner. It extends selected runtimes beyond the ordinary {§worker-optimistic-settlement} cap before the next packet assembles. A bare entry holds ALL of a runtime's spawns; a `<runtime>:<effect>` suffix (`github:read`) holds only that effect-class — an MCP server is one runtime whose tools split (a `read` `get_issue` is instant; a `host` `run_migration` is a slow mutation), so an operator opts the known-fast read-class in without parking on the mutation. Conservative stays default: an arbitrary third-party server's latency never parks the engine unless a suffix opts a class in.
1750
- - §exec-entry-sink **The entry() sink** — an executor may *request* entry materialization (execs SPEC §2.6: every sink is a consumer-implemented callback; the executor owns zero substrate). The service implements it in exec dispatch: `entry(path, content: string | null, {tags, mimetype?})` upserts the entry, then journals ONE typed `EDIT` row in the reserved `plurnk` worker's log — the fs-fiction pattern, `source` = the calling worker, `weight` = the canonical resulting span's curation weight, and `attrs.kind="entry_materialized"`. The requested tags classify that journal row under {§log-item-tags}; they never become resource metadata or duplicate into attrs. Durable replay and clients retain that exact creation event. The model packet projects the typed event as a folded system `READ` of the resulting ordinary resource: its relevant truth is readable state now available in the environment, not an agent-authored mutation. **The executor owns no fetcher:** a `content: null` is a *declaration* — the service acquires the page through schemes-http's checked WebFetcher and accepts its model-facing body and available source/evidence channels {§html-materialization}. Generic public HTML follows the same origin-Markdown, configured Tavily, and local-projection routes as exact HTTP acquisition. A failed acquisition, body-production failure, materialization exception, or absent final projection rejects the sink and produces no HTTP entry, but does not invalidate a search runtime's upstream discovery row; materialization exceptions retain their cause in daemon diagnostics. A non-null `content` is the materialize-given-body path (the caller already holds the bytes and states their mimetype) and grants no provider authority. **No page body ever rides a packet**; the announcement is the folded row's path, weight, and log classifications, and the model READs/~queries what it chooses. Parallel `entry()` calls serialize on a per-spawn chain; a rejected call leaves the chain healthy. The spawn tail settles that complete chain before unregistering, so executor idleness and shutdown are barriers over its materialization writes. The narration context (one plurnk-worker turn) is lazy per spawn, not per entry.
2006
+ - §exec-entry-sink **The entry() sink** — an executor may *request* entry materialization (execs SPEC §2.6: every sink is a consumer-implemented callback; the executor owns zero substrate). The service implements it in exec dispatch: `entry(path, content: string | null, {tags, mimetype?})` upserts the entry, then records ONE typed `EDIT` row in the reserved `plurnk` worker's log — the fs-fiction pattern, `source` = the calling worker, `weight` = the canonical resulting span's curation weight, and `attrs.kind="entry_materialized"`. The requested tags classify that log row under {§log-item-tags}; they never become resource metadata or duplicate into attrs. Durable replay and clients retain that exact creation event. The model packet projects the typed event as a folded system `READ` of the resulting ordinary resource: its relevant truth is readable state now available in the environment, not an agent-authored mutation. **The executor owns no fetcher:** a `content: null` is a *declaration* — the service acquires the page through schemes-http's checked WebFetcher and accepts its model-facing body and available source/evidence channels {§html-materialization}. Generic public HTML follows the same origin-Markdown, configured materializer, and local-projection routes as exact HTTP acquisition ({§http-materializer-plugins}). A failed acquisition, body-production failure, materialization exception, or absent final projection rejects the sink and produces no HTTP entry, but does not invalidate a search runtime's upstream discovery row; materialization exceptions retain their cause in daemon diagnostics. A non-null `content` is the materialize-given-body path (the caller already holds the bytes and states their mimetype) and grants no provider authority. **No page body ever rides a packet**; the announcement is the folded row's path, weight, and log classifications, and the model READs/~queries what it chooses. Parallel `entry()` calls serialize on a per-spawn chain; a rejected call leaves the chain healthy. The spawn tail settles that complete chain before unregistering, so executor idleness and shutdown are barriers over its materialization writes. The narration context (one plurnk-worker turn) is lazy per spawn, not per entry.
1751
2007
 
1752
2008
  ### §proposal The proposal lifecycle
1753
2009
 
1754
- §proposal-202-pauses A side-effecting op does not execute on dispatch — it **proposes**. The scheme returns **202** (an EXEC `host` runtime {§exec}, an EDIT to a member file {§membership}); the engine writes the log row `state='proposed'`, registers a waiter keyed by `logEntryId`, and **pauses `dispatch`** awaiting a resolution. The pause is internal to dispatch the turn has already closed, sogrinder} strike accounting sees the *resolved* status, never the 202. On accept the status becomes 200 and the scheme's effect runs.
2010
+ §proposal-202-pauses A side-effecting op does not execute on dispatch — it **proposes**. The scheme returns **202** (an EXEC `host` runtime {§exec}, an EDIT to a member file {§membership}); the engine writes the log row `state='proposed'`, registers a waiter keyed by `logEntryId`, and **pauses `dispatch`** awaiting a resolution. The provider exchange and emitted operation are already durable, while the turn remains open until dispatch settles; engine-rails} therefore sees the *resolved* status, never the provisional 202. On accept the status becomes 200 and the scheme's effect runs.
1755
2011
 
1756
2012
  **Resolution arrives through one lifecycle:**
1757
2013
 
1758
2014
  - **Client disposition** ({§methods-proposal-resolve}) — a client interface delivers accept, reject, or cancel; AG-UI uses standard resume entries ({§agui-proposal-resolve}).
1759
2015
  - **Loop disposition** ({§proposal-disposition}) — core applies the exact automatic accept/reject before observational subscribers run; automatic policy is not an event listener or client fallback.
1760
- - §proposal-timeout-cancels **Timeout is OPT-IN; the shipped default is a world that WAITS** - `PLURNK_SERVICE_PROPOSAL_TIMEOUT_MS` empty (shipped) means a pending proposal - a file edit awaiting review or a [300] question - waits indefinitely for its human: absence is not an answer, so the service does not synthesize a cancellation. A finite positive millisecond value establishes the bound; then elapsing synthesizes `cancel` (outcome `timeout`), server-side, needing no client. Every other explicit value fails at the proposal lifecycle owner and terminalizes an already-written proposal rather than silently choosing an indefinite wait.
2016
+ - §proposal-timeout-cancels **Timeout is OPT-IN; the shipped default is a world that WAITS** - `PLURNK_SERVICE_PROPOSAL_TIMEOUT_MS` empty (shipped) means a pending proposal - a file edit awaiting review - waits indefinitely for its human: absence is not an answer, so the service does not synthesize a cancellation. A finite positive millisecond value establishes the bound; then elapsing synthesizes `cancel` (outcome `timeout`), server-side, needing no client. Every other explicit value fails at the proposal lifecycle owner and terminalizes an already-written proposal rather than silently choosing an indefinite wait.
1761
2017
 
1762
2018
  **The decision drives a one-way state transition** on `log_entries.state` (resolution is idempotent — `WHERE state='proposed'`, so a second resolution 404s):
1763
2019
 
@@ -1778,11 +2034,10 @@ Core derives the contracts-owned `ProposalProjection` from the durable proposed
1778
2034
  | Projection field | Durable authority |
1779
2035
  | --------------------- | ------------------------------------------------------------------------------------------------------------------ |
1780
2036
  | identity | proposed log row `id`, `worker_id`, `loop_id`, `turn_id`, and validated `op` |
1781
- | `target` | canonical `attrs.proposalTarget` for staged COPY/MOVE, otherwise the log row target |
2037
+ | `target` | canonical `{ scheme, authority, pathname }` from `attrs.proposalTarget` for staged COPY/MOVE, otherwise the log row target |
1782
2038
  | `body` | proposed operation result `rx.body`; absent means the empty review body |
1783
2039
  | `attrs` | proposed log row `attrs` object |
1784
2040
  | `flags` | validated persisted loop flags expanded over contracts-owned defaults |
1785
- | `staleClobberRisk` | target-matched ambient file divergence in the proposal's worker and turn |
1786
2041
  | `disposition` | {§proposal-disposition}; the same value drives automatic settlement and client presentation |
1787
2042
 
1788
2043
  Workspace scope remains the event envelope / seam argument ({§notifications-envelope-carries-workspaceid}); it is not forged into `ProposalProjection`. Malformed durable JSON, target metadata, result envelopes, loop policy, or final projection fails at core with its cause; after insertion, core terminalizes that row as a 500 `policy_failed` before propagating the internal failure, so no waiter or durable stopped world is orphaned.
@@ -1808,17 +2063,13 @@ removes ownerless rows without fabricating cancellation, payload, or replay.
1808
2063
 
1809
2064
  `ProposalDisposition` is either `{ owner: "client" }` or `{ owner: "loop", decision: "accept" | "reject", outcome? }`. The decision table is complete and ordered:
1810
2065
 
1811
- The `[300]` branch is identified by the durable SEND operation signal; `attrs.question` is its required presentation payload, not an independent policy switch ({§send-300-choices}).
1812
-
1813
- | `auto` | `[300]` question | stale target | `noProposals` | Disposition |
1814
- | ------ | ---------------- | ------------ | ------------- | ------------------------------------------------------------------ |
1815
- | true | yes | any | any | client |
1816
- | true | no | true | any | loop reject, outcome `stale_read_clobber` |
1817
- | true | no | false | any | loop accept |
1818
- | false | any | any | true | loop reject, outcome `no_review_channel` |
1819
- | false | any | any | false | client |
2066
+ | `auto` | `noProposals` | Disposition |
2067
+ | ------ | ------------- | ---------------------------------------- |
2068
+ | true | any | loop accept |
2069
+ | false | true | loop reject, outcome `no_review_channel` |
2070
+ | false | false | client |
1820
2071
 
1821
- Thus `auto` wins the otherwise nonsensical `auto + noProposals` combination, but its operator-question exception still leaves that question client-owned ({§send-300-choices}). Loop-owned settlement occurs before observational notification; observer failures are diagnosed with their cause and cannot change disposition or leave an eligible automatic proposal pending.
2072
+ Thus `auto` wins the otherwise nonsensical `auto + noProposals` combination. Loop-owned settlement occurs before observational notification; observer failures are diagnosed with their cause and cannot change disposition or leave an eligible automatic proposal pending.
1822
2073
 
1823
2074
  ---
1824
2075
 
@@ -1830,14 +2081,14 @@ Thus `auto` wins the otherwise nonsensical `auto + noProposals` combination, but
1830
2081
 
1831
2082
  §subscriptions-subscription-registry-routes-cancellation READ on a streaming scheme is a subscription, not a one-shot. The scheme establishes its protocol-specific acquisition boundary, returns `102 Processing`, and stays alive through the `StreamSubscription` returned by `subscriptions.open()`. The service commits that initial operation result normally; later chunk and terminal work cannot rewrite it. Durable terminal truth lives on the subscription and its channels. The service records durable subscription identity and metadata in SQLite and retains the callable `SubscriptionHandle` only in its process-local live registry. SEND signal `499`, worker cancellation, turn-scoped reap, and shutdown all route through that one live registry; no handler-specific cancellation hook or database access is part of the plugin contract.
1832
2083
 
1833
- The durable row is lifecycle evidence and the lookup key, not a serialized callback. `subscriptions.open()` establishes both halves before yielding a composed `StreamSubscription`: an `AbortSignal` whose fused `notifyChunk` and terminal `close` methods are safe to retain without the operation's general `SchemeCtx`. `close(result, summary?)` validates and persists the exact universal operation result, settles channel state, closes the durable row, wakes the worker when appropriate, and unregisters the live handle. `close_status` is a constrained relational projection of `close_result.status`, never an independent result. A durable open row without a live handle is an explicit lifecycle failure, never a fabricated cancellation success. Channel state ({§channel-state}) + log entries ({§no-chunk-rows}) carry lifecycle.
2084
+ The durable row is lifecycle evidence and the lookup key, not a serialized callback. `subscriptions.open()` establishes both halves before yielding a composed `StreamSubscription`: an `AbortSignal` whose fused `notifyChunk` and terminal `close` methods are safe to retain without the operation's general `SchemeCtx`. `close(result, summary?, channelResults?)` validates one universal terminal producer result plus exact named channel overrides. One SQLite transition closes the subscription and installs each channel's terminal `producerResult`; its lifecycle state derives from that result. The transition then wakes the worker when appropriate and unregisters the live handle. `close_status` is a constrained relational projection of `close_result.status`, never an independent result, while `channel_results` preserves historical overrides after a later subscription replaces the channel's current evidence. A durable open row without a live handle is an explicit lifecycle failure, never a fabricated cancellation success. Channel state ({§channel-state}) + log entries ({§no-chunk-rows}) carry lifecycle.
1834
2085
 
1835
2086
  At process restart every still-open row is necessarily missing its callable owner. Boot
1836
2087
  settles it as interruption (`500`) and errors active channels before evaluating parked
1837
2088
  loops ({§worker-lifecycle-restart-recovery}); it never reports cancellation (`499`) or
1838
2089
  pretends to reconstruct an opaque plugin connection.
1839
2090
 
1840
- §subscriptions-fold-keeps-subscription FOLD/OPEN toggles `log_entries.expanded` ({§open-fold}) — a per-worker render bit, never the subscription registry. FOLDing a streaming entry's log row collapses its body out of the packet but leaves the live stream running: curation is render-only, never cancellation.
2091
+ §subscriptions-fold-keeps-subscription FOLD/OPEN changes a log row's folded body intervals ({§open-fold}), never the subscription registry. Curation of a streaming entry's log body leaves the live stream running: visibility is render-only, never cancellation.
1841
2092
 
1842
2093
  ### §chunk-accumulation Chunk accumulation
1843
2094
 
@@ -1891,7 +2142,7 @@ No generator. SQLite-optimal: STRICT (3.37+), `INTEGER PRIMARY KEY` aliasing, ex
1891
2142
 
1892
2143
  - **Schema-alignment test**: loads `@plurnk/plurnk-contracts/schema/*.json`, parses DDL via `node:sqlite` introspection, asserts every required schema field has a corresponding `NOT NULL` column. Contract drift fails CI.
1893
2144
  - DDL = storage truth; JSON Schemas = wire truth. Tested-aligned, allowed to differ where ergonomics demand.
1894
- - §entry-identity-no-null **Identity components are never NULL.** The entries identity tuple — (workspace, owner, scheme, pathname) — admits no NULL component because SQLite treats NULLs as distinct under a UNIQUE index, allowing duplicate logical identities. File members persist under the reserved **`file`** scheme (`storedScheme: "file"`; they still render as bare paths); `entries.scheme` is `NOT NULL`; a manifest declaring `storedScheme: null` is refused at registration.
2145
+ - §entry-identity-no-null **Identity components are never NULL.** The entries identity tuple — `(owner, scheme, authority, pathname)` — admits no NULL component because SQLite treats NULLs as distinct under a UNIQUE index, allowing duplicate logical identities. `owner_id` references one Worker, which is the sole workspace coordinate; `entries` stores no redundant `workspace_id` that could contradict it. `authority` defaults to the canonical empty string for namespace and owner schemes; resource schemes persist their canonical authority there. File members persist under the reserved **`file`** scheme (`storedScheme: "file"`; they still render as bare paths); `entries.scheme` and `entries.authority` are `NOT NULL`; a manifest declaring `storedScheme: null` is refused at registration.
1895
2146
 
1896
2147
  ### §sql-ts-boundary SQL/TS responsibility boundary
1897
2148
 
@@ -1974,10 +2225,17 @@ freshness remains the owning family's concern.
1974
2225
  | Family | Lean framework | Service-owned default leaves |
1975
2226
  |-----------|------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|
1976
2227
  | Schemes | `@plurnk/plurnk-schemes` | `@plurnk/plurnk-schemes-http` |
1977
- | Mimetypes | `@plurnk/plurnk-mimetypes` | `application-ipynb`, `application-json`, `application-jsonl`, `application-pdf`, and `application-xml` format leaves. |
2228
+ | Mimetypes | `@plurnk/plurnk-mimetypes` | `application-ipynb`, `application-json`, `application-jsonl`, and `application-xml` format leaves. |
1978
2229
  | | | `text-csv`, `text-diff`, `text-dotenv`, `text-html`, `text-ini`, `text-markdown`, and `text-plain` format leaves. |
1979
- | | | Fixed `embeddings` and `tokenizers` artifacts. All names use the `@plurnk/plurnk-mimetypes-*` prefix. |
1980
- | Executors | `@plurnk/plurnk-execs` | `common`, `git`, `jq`, `search`, `sqlite`, and `wasm` leaves under the `@plurnk/plurnk-execs-*` prefix. |
2230
+ | | | Fixed `embeddings` artifact. All names use the `@plurnk/plurnk-mimetypes-*` prefix. |
2231
+ | Executors | `@plurnk/plurnk-execs` | `common`, `git`, `jq`, `sqlite`, and `wasm` leaves under the `@plurnk/plurnk-execs-*` prefix. |
2232
+
2233
+ The independently published `application-pdf` handler and `tokenizers`
2234
+ artifact are opt-in leaves. Installing either beside the service admits it
2235
+ through ordinary package discovery without changing the service manifest. The
2236
+ default local embedding artifact owns the exact counter for its own model;
2237
+ remote embedding deployments install `tokenizers` when their provider does not
2238
+ supply an exact counter.
1981
2239
 
1982
2240
  **Providers:** `@plurnk/plurnk-providers` resolves the Models.dev catalog,
1983
2241
  operator declarations, local adapters, and finally installed AI SDK provider
@@ -2022,12 +2280,32 @@ service manifest edit.
2022
2280
 
2023
2281
  ## §operator-config Operator Configuration
2024
2282
 
2283
+ ### §host-path-layout Host filesystem layout
2284
+
2285
+ On XDG-compatible hosts, artifact semantics select the default location. An
2286
+ unset or empty base variable uses the XDG default; a relative value is invalid
2287
+ and is ignored rather than resolved against the working directory.
2288
+
2289
+ | Class | Base | Plurnk member |
2290
+ |---|---|---|
2291
+ | Configuration | `$XDG_CONFIG_HOME` (default `~/.config`) | `plurnk/.env`, `plurnk/AGENTS.md` |
2292
+ | Durable user data | `$XDG_DATA_HOME` (default `~/.local/share`) | `plurnk/plurnk.db` and SQLite sidecars |
2293
+ | Persistent operational state | `$XDG_STATE_HOME` (default `~/.local/state`) | Reserved; no directory is created without an owned artifact. |
2294
+ | Reproducible cache | `$XDG_CACHE_HOME` (default `~/.cache`) | Reserved; no directory is created without an owned artifact. |
2295
+ | Shared global Agent Skills | User home | `.agents/skills/<name>/SKILL.md` |
2296
+
2297
+ The service creates only a directory required by the current command. A newly
2298
+ created configuration or data directory uses mode `0700`; a newly seeded
2299
+ secret-bearing `.env` uses `0600`. Existing user-owned permissions are not
2300
+ rewritten. Explicit Plurnk path overrides retain `~/` expansion and their
2301
+ ordinary precedence; XDG variables themselves require absolute paths.
2302
+
2025
2303
  §operator-config-precedence Configuration is one environment cascade. Higher-priority sources preserve or replace values supplied by every lower source:
2026
2304
 
2027
2305
  | Priority | Source | Ordering |
2028
2306
  |---------:|------------------------------------|-----------------------------------------------------------|
2029
2307
  | 1 | Assembled package `.env.defaults` | Set-if-unset floor; one owner per key. |
2030
- | 2 | `~/.plurnk/.env` | User-level ambient configuration. |
2308
+ | 2 | `$XDG_CONFIG_HOME/plurnk/.env` | User-level ambient configuration. |
2031
2309
  | 3 | `./.env` | Working-directory ambient configuration. |
2032
2310
  | 4 | `--config=<path>` | Singular service-owned explicit file. |
2033
2311
  | 5 | `--env-file*` | Repeatable explicit files; later selected files win. |
@@ -2036,17 +2314,28 @@ service manifest edit.
2036
2314
 
2037
2315
  Node's pre-script env-file form and the executable's post-script form share the same later-file-wins ordering. `--env-file-if-exists` skips an absent file without changing the order of selected files.
2038
2316
 
2039
- §operator-config-env-defaults **Every package owns its knobs — `.env.defaults` is the standard.** Each package in the daemon's ecosystem — internal or third-party — ships a `.env.defaults` at its package root declaring its own knobs; the file is the package's configuration reference, traveling in the tarball and changing with the code that reads it. At boot the daemon assembles every installed member's file into one floor (membership = the `@plurnk/*` scope or a `plurnk` package.json field, gated by `PLURNK_PLUGINS_TRUSTED_ONLY` with discover()'s exact semantics), applies it set-if-unset under every operator source, and renders the assembled catalog to `~/.plurnk/.env.defaults`. The catalog is machine-owned, regenerated each boot, and never read back as configuration. A key claimed by two packages fails boot naming both. With the reader-declares discipline, each key has one implementation and one defaults owner.
2317
+ §operator-config-env-defaults **Every package owns its knobs — `.env.defaults` is the standard.** Each package in the daemon's ecosystem — internal or third-party — ships a `.env.defaults` at its package root declaring its own knobs; the file is the package's configuration reference, traveling in the tarball and changing with the code that reads it. At boot the daemon assembles every installed member's file into one floor (membership = the `@plurnk/*` scope or a `plurnk` package.json field, gated by `PLURNK_PLUGINS_TRUSTED_ONLY` with discover()'s exact semantics) and applies it set-if-unset under every operator source. `plurnk-service config defaults` renders the same complete, owner-labelled aggregate to stdout on demand, preserving comments and optional declarations without persisting a second copy or exposing effective secret values. A key claimed by two packages fails boot naming both. With the reader-declares discipline, each key has one implementation and one defaults owner.
2318
+
2319
+ §operator-config-discovery The conventional `plurnk-service config` command
2320
+ family is a view over the environment cascade, never another configuration
2321
+ representation. `config` reports the canonical `.env`, actual source order,
2322
+ and model-selection state; `config edit` opens that file through `$VISUAL` or
2323
+ `$EDITOR`; `config defaults` emits the aggregate above; and `config check`
2324
+ validates the provider-free configuration contracts without starting a model
2325
+ or provider request. The seeded `.env`, first-run diagnostic, service help, and
2326
+ missing-model recovery all signpost `plurnk-service config defaults` as the
2327
+ complete installed option catalog.
2040
2328
 
2041
- Model selection: separate alias cascade in `ProviderRegistry` ({§provider-instantiation}). `PLURNK_MODEL_<alias>=<provider>/<model-id>` declares; `PLURNK_MODEL=<alias>` selects. Optional `PLURNK_MODEL_CHILD=<alias>` selects the default child provider; unset means inherit the spawning loop's provider. Aliases and selections live in `.env`, not `.env.defaults` (operator-specific).
2329
+ Model selection uses one selector vocabulary in `ProviderRegistry` ({§provider-instantiation}). `PLURNK_MODEL_<alias>=<provider>/<model-id>` optionally declares a friendly route and tuning scope; `PLURNK_MODEL=<selector>` selects either that alias or an exact provider/model route. `PLURNK_MODEL_CHILD=<selector>` uses the same vocabulary for the default child provider; unset means inherit the spawning loop's provider. Operator selections and alias declarations live in `.env`, not `.env.defaults`.
2042
2330
 
2043
2331
  | Var | Default | Purpose |
2044
2332
  |-------------------------------------------------------------|---------|---------|
2045
- | `PLURNK_SERVICE_DB_PATH` | `~/.plurnk/plurnk.db` | SQLite file path. |
2333
+ | `PLURNK_SERVICE_DB_PATH` | `$XDG_DATA_HOME/plurnk/plurnk.db` | SQLite file path; an explicit non-empty value overrides the derived default. |
2046
2334
  | `PLURNK_HOST` | `127.0.0.1` | Bind address for the listener. Local-only by default. |
2047
2335
  | `PLURNK_PORT` | `3044` | TCP port for THE client surface — the AG-UI+ listener (the plurnk-agui plugin module binds it at boot). Production is single-listener. |
2048
2336
  | §operator-config-git-ceiling `PLURNK_SERVICE_GIT_ALLOWED` | `1` | Hard service ceiling: only `1` admits Git membership, status, branch batching, and `git`/`isogit` executors; every other value denies them before executor registration or packet teaching. |
2049
- | `PLURNK_SERVICE_MAX_TURNS` | `-1` | Operator turn **ceiling** — `-1` = no cap; a positive value clamps `runLoop({maxTurns})`. The effective value is persisted on the durable loop and counts cumulatively across every `202` park/resume. |
2337
+ | §operator-config-file-create-scope `PLURNK_SERVICE_FILE_CREATE_SCOPE` | `root` | Hard file-creation ceiling: `none < root < namespace`. `none` denies new filesystem files, `root` admits only paths inside `project_root`, and `namespace` also admits canonical outside-root paths. Existing-member writes are unaffected. |
2338
+ | `PLURNK_SERVICE_MAX_TURNS` | `-1` | Operator inference-turn **ceiling** — `-1` = no cap; a positive value clamps `runLoop({maxTurns})`. The effective value is persisted on the durable loop and counts completed model/inference turns cumulatively across every `202` park/resume; `_plurnk`, client, and plugin turns remain chronology but consume none of this allowance. |
2050
2339
  | `PLURNK_SERVICE_MAX_COMMANDS` | `-1` | Per-emission action ceiling; `-1` = no cap (default) — every generated op dispatches. A positive value caps dispatched actions: overflow ops drop with one durable `max-commands-exceeded` error row on the next packet. PLAN and the final disposition always dispatch. Tightened per workspace via `settings.maxCommands` (min wins). |
2051
2340
  | §operator-config-loop-timeout `PLURNK_SERVICE_LOOP_TIMEOUT` | `86400000` | ms wall-clock budget for a single core loop: expiry aborts the loop signal mid-flight (a stuck `generate` included) and the loop terminates `504 loop_timeout` — a legible engine terminal, kin to the exec `<T>` reap's 504 ({§exec-timeout}). |
2052
2341
  | `PLURNK_SERVICE_MAX_STRIKES` | `6` | Consecutive admitted-turn strike threshold ({§engine-rails}). |
@@ -2060,23 +2349,23 @@ Model selection: separate alias cascade in `ProviderRegistry` ({§provider-insta
2060
2349
  | `PLURNK_SERVICE_MAX_CYCLE_PERIOD` | `4` | Max period length cycle detection examines ({§engine-rails}). |
2061
2350
  | `PLURNK_SERVICE_REQUIEM_MAX_TOKENS` | `16384` | Initial forensic witness output allowance ({§digest-requiem}). |
2062
2351
  | `PLURNK_SERVICE_REQUIEM_RETRY_MAX_TOKENS` | `32768` | Retry allowance; must be at least the initial requiem allowance ({§digest-requiem}). |
2063
- | `PLURNK_SERVICE_MD_<ALIAS>` | (unset) | Operator reference doc: materializes `<path>` as `worker://plurnk/<ALIAS>.md`, auto-READ into every model worker's turn 0 ({§actor-boundary-doc-injection}). `~` expands to home. |
2064
2352
  | `PLURNK_SERVICE_FILES_ITEMS` | `-1` | Turn-0 catalog preview. Folder-capable schemes render a one-level `*` map with `dir/**` rollups; kernel docs remain recursive and explicitly complete. `-1` = markerless first pages; positive `N` explicitly caps only file-map rows; `0` / unset = off ({§actor-boundary-catalog-preview}). |
2065
2353
  | `PLURNK_SERVICE_PROPOSAL_TIMEOUT_MS` | (empty — waits indefinitely) | Finite positive milliseconds before cancellation with outcome `timeout`; empty waits, and every other explicit value fails ({§proposal-timeout-cancels}). |
2354
+ | §operator-config-worker-warm `PLURNK_SERVICE_WORKER_WARM_MS` | `900000` | Milliseconds a lease-free worker Functionality snapshot remains warm; `0` cools without grace and `-1` disables time-based cooling ({§module-worker-residency}). |
2355
+ | `PLURNK_SERVICE_WORKER_WARM_MAX` | `2` | Maximum lease-free worker Functionality snapshots retained process-wide; `0` retains none and `-1` disables the idle-LRU bound ({§module-worker-residency}). |
2066
2356
 
2067
2357
  Every core knob listed is enforced at its owning read site; `.env.defaults` is the authoritative default ({§operator-config-env-defaults}). Provider, scheme, executor, mimetype, and client-interface knobs are documented by their owning packages and appear in the assembled catalog.
2068
2358
 
2069
2359
  **Two override semantics — ceiling vs default.** Which kind a var is determines what "override" means across the cascade:
2070
2360
 
2071
- - **Ceiling** (most-restrictive-wins) — an operator-set hard bound nothing downstream may exceed: not a lower-precedence file, not a per-workspace constraint, not a per-call seam argument. `PLURNK_SERVICE_GIT_ALLOWED` ({§operator-config-git-ceiling}), `PLURNK_SERVICE_MAX_COMMANDS`, `PLURNK_SERVICE_MAX_STRIKES`, and `PLURNK_SERVICE_MAX_TURNS` (`-1` ships it off; a positive value caps the per-call request). The sandbox/cost guarantee: the operator caps it; no client widens it.
2072
- - **Default** (explicit-wins) — a fallback the most-specific setter replaces freely: `PLURNK_MODEL` (a `runLoop({alias})` request overrides it) and the config-time vars (`HOST` / `PORT` / `DB_PATH`).
2361
+ - **Ceiling** (most-restrictive-wins) — an operator-set hard bound nothing downstream may exceed: not a lower-precedence file, not a per-workspace constraint, not a per-call seam argument. `PLURNK_SERVICE_GIT_ALLOWED` ({§operator-config-git-ceiling}), `PLURNK_SERVICE_FILE_CREATE_SCOPE` ({§operator-config-file-create-scope}), `PLURNK_SERVICE_MAX_COMMANDS`, `PLURNK_SERVICE_MAX_STRIKES`, and `PLURNK_SERVICE_MAX_TURNS` (`-1` ships it off; a positive value caps the per-call request). The sandbox/cost guarantee: the operator caps it; no client widens it.
2362
+ - **Default** (explicit-wins) — a fallback the most-specific setter replaces freely: `PLURNK_MODEL` (a `runLoop({selector})` request overrides it) and the config-time vars (`HOST` / `PORT` / `DB_PATH`).
2073
2363
 
2074
2364
  §operator-config-shipped-defaults **The shipped `.env.defaults` is itself under
2075
- test.** It has no active `PLURNK_SERVICE_MD_*` doc alias because policy is a
2076
- section and a doc default double-injects it; no active `PLURNK_MODEL`; no active
2077
- local GBNF constraint; and the policy renders in exactly one packet section.
2078
- Every other tier runs the test cascade, so shipped-default regressions are
2079
- otherwise invisible by construction.
2365
+ test.** It has no active `PLURNK_MODEL`; no active local GBNF constraint; and
2366
+ the policy renders in exactly one packet section. Every other tier runs the
2367
+ test cascade, so shipped-default regressions are otherwise invisible by
2368
+ construction.
2080
2369
 
2081
2370
  §operator-config-flag-parity The companion **flag-parity** check binds code and
2082
2371
  template both ways: every `PLURNK_SERVICE_*` the service reads has a
@@ -2124,12 +2413,11 @@ boundary. Operator-arcane knobs stay environment-only.
2124
2413
  | Field | Admitted value | Composition / owner |
2125
2414
  | ---------------------- | ---------------------------------------------- | ------------------------------------------------------------- |
2126
2415
  | `settings.filesItems` | Integer `>= -1` | Explicit replacement {§operator-config-workspace-files-items} |
2127
- | `settings.mdDocs` | Array of `{ alias: [\w.-]+, content: string }` | Alias-keyed union {§operator-config-workspace-md-docs} |
2128
2416
  | `settings.maxCommands` | Non-negative integer | Tightening ceiling {§operator-config-workspace-max-commands} |
2129
2417
  | `settings.git` | Boolean | Tightening denial {§operator-config-workspace-git} |
2418
+ | `settings.fileCreateScope` | `none`, `root`, or `namespace` | Tightening ceiling {§operator-config-workspace-file-create-scope} |
2130
2419
  | `settings.client` | Nonempty string | Stable self-identification {§client-metadata} |
2131
2420
  | `settings.execs` | Record of policy-key to string | Subtractive executor layer {§operator-config-workspace-execs} |
2132
- | `settings.questions` | Boolean | Affirmative question request {§send-300-choices} |
2133
2421
 
2134
2422
  The composition families remain distinct so one setting's semantics never
2135
2423
  leak into another.
@@ -2137,8 +2425,6 @@ leak into another.
2137
2425
  *Defaults — explicit-wins (the client replaces/merges freely):*
2138
2426
 
2139
2427
  - §operator-config-workspace-files-items `settings.filesItems` (number) **replaces** `PLURNK_SERVICE_FILES_ITEMS` for the workspace: a one-shot opens clean (`0`, no preview), with ordinary markerless pages (`-1`), or with the file list explicitly capped (`N`, other surveys remain markerless). A single scalar — the client value wins outright.
2140
- - §operator-config-workspace-md-docs `settings.mdDocs` (`[{alias, content}]`) **unions** with the server's `PLURNK_SERVICE_MD_*` docs, keyed by alias — a client adds its own repo docs atop the operator's systemwide policy doc. On alias collision the client wins before I/O (a deliberate shadow), so the unselected operator path is not read; every selected non-empty operator path is required, and absence or another read failure rejects materialization with its cause. The client sends content (it owns the file), not a path.
2141
-
2142
2428
  *Ceilings — most-restrictive-wins (the client may only narrow, never widen):*
2143
2429
 
2144
2430
  - §operator-config-workspace-max-commands `settings.maxCommands` (number)
@@ -2146,10 +2432,11 @@ leak into another.
2146
2432
  workspace: a client tightens the runaway-op guard and never raises it past
2147
2433
  the operator's.
2148
2434
  - §operator-config-workspace-max-commands-floor The cap bounds *actions* only.
2149
- PLAN (intended goals) and the final disposition `SEND` (`102`, `200`, `202`,
2435
+ PLAN (complete current Plan) and the final disposition `SEND` (`102`, `200`, `202`,
2150
2436
  `300`, or `499`) are never counted and always dispatch, so `0` is a valid
2151
2437
  floor — the tightest — admitting a plan and disposition with zero actions.
2152
2438
  - §operator-config-workspace-git `settings.git` (`false`) **denies** git for the workspace (`PLURNK_SERVICE_GIT_ALLOWED` AND workspace) — the client opts its workspace out of git membership and working-tree status; it can never re-enable git past the operator's service-wide lockout.
2439
+ - §operator-config-workspace-file-create-scope `settings.fileCreateScope` narrows `PLURNK_SERVICE_FILE_CREATE_SCOPE` by the ordered lattice `none < root < namespace`; a workspace may disable creation or confine a namespace-enabled service to its root, but never widen the operator's ceiling. Unknown service values fail configuration validation and unknown workspace values fail `workspace.create`.
2153
2440
  - §operator-config-workspace-execs `settings.execs` is a workspace-stable
2154
2441
  snapshot of one `Record<string, string>` policy layer using
2155
2442
  {§executor-policy}. Keys are matched case-insensitively and must be
@@ -2158,9 +2445,8 @@ leak into another.
2158
2445
  effective workspace registry is authoritative and the settings layer only
2159
2446
  intersects it: settings cannot register or re-enable a runtime. A canonical
2160
2447
  key for a currently absent tag is accepted as inert policy and applies if a
2161
- workspace capability provider later publishes that tag. Dispatch, the
2162
- model-facing capability sheet, and executor
2163
- document materialization use the same registered-set intersection and policy
2448
+ worker Functionality provider later publishes that tag. Dispatch and
2449
+ model-facing tool-resource materialization use the same registered-set intersection and policy
2164
2450
  predicate, so a workspace-disabled tag is neither executable nor taught.
2165
2451
 
2166
2452
  Feature-flag bools use `process.env.X === "1"` exactly — never `=== "true"`.
@@ -2173,7 +2459,8 @@ External plugins declare their own env vars in their own `.env.defaults`, assemb
2173
2459
 
2174
2460
  ## §rpc Module seam
2175
2461
 
2176
- Core owns a typed in-process module seam. It owns no external listener, public
2462
+ Core implements the contracts-owned {§application-port} and owns the typed
2463
+ module setup seam. It owns no external listener, public
2177
2464
  action-name catalog, or generic string-dispatched method registry. A
2178
2465
  client-interface module such as `plurnk-agui` owns its public protocol, action
2179
2466
  names, request validation, discovery result, and event projection.
@@ -2183,33 +2470,74 @@ names, request validation, discovery result, and event projection.
2183
2470
  ```mermaid
2184
2471
  flowchart LR
2185
2472
  register["Daemon.registerModule"] --> setup["module.setup(ModuleSetupSeam)"]
2186
- setup --> capabilities["Register static capabilities,<br/>workspace providers, and actions"]
2187
- capabilities --> ready["Schemes ready; docs published;<br/>durable lifecycle recovered"]
2188
- ready --> start["module.start(CoreSeam)"]
2473
+ setup --> capabilities["Register static capabilities,<br/>workspace activators, and actions"]
2474
+ capabilities --> ready["Process-wide schemes ready"]
2475
+ ready --> recovery["Reconcile durable lifecycle"]
2476
+ recovery --> start["module.start(ApplicationPort)"]
2189
2477
  start --> interface["Module-owned listener<br/>and client protocol"]
2190
- interface --> calls["Typed CoreSeam calls"]
2478
+ recovery -->|durable workspace work| demand["First workspace demand"]
2479
+ interface -->|client workspace work| demand
2480
+ demand --> lease["Acquire capability residency"]
2481
+ lease --> activate["Activate if cold;<br/>publish workspace docs"]
2482
+ activate --> calls["Typed ApplicationPort calls"]
2483
+ calls --> release["Release demand lease"]
2484
+ release --> warm["Bounded warm grace / idle LRU"]
2485
+ warm -->|new demand| lease
2486
+ warm -->|idle bound| cool["Deactivate providers;<br/>withdraw runtime projections"]
2487
+ interface -->|worldless call| calls
2191
2488
  calls --> core["Core state and orchestration"]
2192
2489
  core --> events["subscribeToEvents<br/>(workspaceId, event, payload)"]
2193
2490
  events --> interface
2194
2491
  ```
2195
2492
 
2196
2493
  Every registered module's `setup` runs in registration order before any
2197
- module's `start`. Core then readies schemes, publishes installed capabilities,
2198
- recovers durable lifecycle, and starts modules in registration order. Shutdown
2199
- closes started and self-closing modules in reverse order and surfaces aggregated
2200
- close failures.
2201
-
2202
- §module-shutdown-order `Daemon.stop()` returns only after active worker drains,
2203
- streaming producers, derivations, mimetypes, schemes, and every accepted
2204
- conclusion-wake task have settled in dependency order. The supervisor owns each
2205
- asynchronous wake task from acceptance through settlement; a task failure
2206
- participates in the shutdown aggregate. The database may be released only after
2207
- the final wake barrier resolves.
2494
+ module's `start`. Core then readies process-wide schemes, reconciles durable
2495
+ lifecycle, and starts modules in registration order. Persisted workspaces with
2496
+ no durable work stay passive until first demand; activation publishes their
2497
+ complete capabilities and documentation before the demanding operation
2498
+ proceeds. `setup` is the readiness boundary for every capability registered
2499
+ with Core: recovery may demand a workspace provider before `start`. `start`
2500
+ opens module-owned exterior ingress only after recovery, so no registered
2501
+ capability may depend on it. Shutdown begins started and self-closing module
2502
+ closure in reverse order and surfaces aggregated close failures.
2503
+
2504
+ §module-discovery **Third-party daemon-module composition is manifest
2505
+ discovery.** A package declares `plurnk: { kind: "module", module:
2506
+ "<export-subpath>" }`; the export is one DaemonModule (an object, or a no-arg
2507
+ factory returning one). At boot, core scans installed packages under the
2508
+ executor family's discovery and trust rules ({§plugin-discovery}) and
2509
+ registers every trusted declaring module before any module setup runs, in
2510
+ package-name order. The service's explicit composition — the AG-UI,
2511
+ hooks, and MCP modules — carries init options and is wired in service.ts;
2512
+ discovery never duplicates those packages. An untrusted declaring package is
2513
+ skipped with a boot warning, never executed. A module export that is neither
2514
+ an object nor a no-arg factory, a factory returning a non-object, or an object
2515
+ with a non-function lifecycle member fails boot loudly.
2516
+
2517
+ §module-shutdown-order `Daemon.stop()` first rejects new capability demand and
2518
+ aborts proposals, branches, derivations, and worker scopes. It simultaneously
2519
+ begins every module closer in reverse registration order, allowing exterior
2520
+ listeners to stop accepting work while active requests observe those
2521
+ cancellations. It then settles branches, drains, module closers, streaming
2522
+ producers, derivations, mimetypes, and schemes before its final conclusion-wake
2523
+ barrier. The supervisor owns each asynchronous wake task from acceptance
2524
+ through settlement; a task failure participates in the shutdown aggregate. The
2525
+ database may be released only after the final wake barrier resolves.
2526
+
2527
+ §crash-only-stop The settle sequence is deadline-bounded
2528
+ (`PLURNK_SERVICE_STOP_TIMEOUT_MS`, default 30000): past the deadline each wait
2529
+ is abandoned with a named error instead of hanging the daemon on a child that
2530
+ never closes. A wedged child costs a forced shutdown; it must never cost an
2531
+ unbounded one.
2208
2532
 
2209
2533
  ```mermaid
2210
2534
  flowchart LR
2211
- stop[Stop accepting work] --> drains[Settle worker drains]
2212
- drains --> producers[Settle streaming producers]
2535
+ stop[Begin stop] --> abort[Abort core producers]
2536
+ stop --> moduleClose[Begin reverse module closure]
2537
+ abort --> drains[Settle worker drains]
2538
+ drains --> joined[Settle module closures]
2539
+ moduleClose --> joined
2540
+ joined --> producers[Settle streaming producers]
2213
2541
  producers --> resources[Dispose derivations,<br/>mimetypes, and schemes]
2214
2542
  resources --> wakes[Settle conclusion wakes]
2215
2543
  wakes --> database[Release database]
@@ -2219,30 +2547,166 @@ flowchart LR
2219
2547
  |---|---|
2220
2548
  | `registerRuntimes([{ decl, executor, availability, scheme? }, ...])` | Validates the complete canonical tag set under {§executor-runtime-declaration}, then publishes every process-wide executor and optional claimed scheme facet atomically. |
2221
2549
  | `registerScheme(name, handler)` | Adds one process-wide addressable scheme handler; scheme readiness and model-facing capability publication remain core-owned. |
2222
- | §module-action-registration `registerModuleAction({ name, scope, handler })` | Adds one non-empty, extension-unique action. `scope` is exactly `worldless` or `workspace`; the handler receives validated params and a separate matching context. A workspace context contains the trusted bound `workspaceId`, never a client parameter. A client-interface module decides whether and how the name becomes public and owns collisions with its built-ins. |
2223
- | §module-workspace-provider `registerWorkspaceCapabilityProvider(namespaceOwner, provider)` | Registers one extension-unique provider whose `hydrate(workspaceId)` reconstructs its effective snapshot. Core invokes every provider for existing workspaces before capability publication and for a new workspace before that workspace is returned or advertised. |
2224
- | §module-workspace-state `readWorkspaceModuleState(workspaceId, namespaceOwner)` | Reads the provider's one nullable JSON state value. Core owns workspace isolation and storage; the provider owns and validates its schema. Secret values are forbidden when a durable symbolic reference can identify their authoritative source. |
2225
- | §module-workspace-capabilities `replaceWorkspaceCapabilities({ workspaceId, namespaceOwner, state, runtimes })` | Replaces one provider's complete durable state and runtime/scheme snapshot at a quiescent workspace boundary. Core validates base/peer namespace claims before mutation, blocks new turns, commits the snapshot, and reconciles pull docs as one operation. Failure restores the prior state and presentation. The empty runtime set removes that provider's workspace namespace. |
2226
-
2227
- §module-workspace-quiescence **A capability snapshot changes only between
2228
- workspace operations.** A replacement attempt while a turn or another
2550
+ | §module-action-registration `registerModuleAction({ name, scope, inputSchema, outputSchema, handler })` | Adds one non-empty, extension-unique action with resolvable JSON Schemas. `scope` is exactly `worldless`, `workspace`, or `worker`; the handler receives schema-validated params and a separate matching context. Scoped contexts contain trusted bound identifiers, never client parameters. A client-interface module decides whether and how the name becomes public, validates successful output, and owns collisions with its built-ins. |
2551
+ | §module-worker-provider `registerWorkerCapabilityProvider(namespaceOwner, provider)` | Registers one extension-unique Functionality provider. `activate({ workspaceId, workerId, retain })` reconstructs that worker's effective snapshot; idempotent `deactivate({ workspaceId, workerId })` releases its process-local resources. Core coalesces activation and cooling, publishes complete private documentation before use, and supplies `retain()` so provider work that outlives its caller holds an idempotently releasable residency lease. Dormant workers perform no provider work at boot. |
2552
+ | §module-worker-state `readWorkerModuleState(workerId, namespaceOwner)` | Reads the provider's one nullable JSON state value for one worker. Core owns worker isolation and storage; the provider owns and validates its schema. Secret values are forbidden when a durable symbolic reference can identify their authoritative source. |
2553
+ | §module-functionality-adapter `registerFunctionalityAdapter(adapter)` | Registers one family of managed Functionality beneath the shared coordinator ({§functionality-coordinator}). The adapter owns protocol truth; the coordinator owns lifecycle, durable state, publication, and both projections. |
2554
+ | §module-worker-capabilities `replaceWorkerCapabilities({ workspaceId, workerId, namespaceOwner, state, runtimes })` | Replaces one provider's complete durable state and runtime/scheme snapshot for one worker at a quiescent workspace-operation boundary. Core validates worker membership and base/peer namespace claims before mutation, commits the snapshot, and reconciles that worker's private pull docs as one operation. Failure restores the prior state and presentation. The empty runtime set removes that provider from the worker's Functionality. |
2555
+
2556
+ §module-worker-quiescence **A worker's Functionality snapshot changes only
2557
+ between workspace operations.** A replacement attempt while a turn or another
2229
2558
  capability mutation owns the workspace fails 409 instead of waiting behind an
2230
2559
  unbounded proposal. Candidate discovery may occur before the gate, but the
2231
2560
  provider must re-check its old connection for active user work after acquiring
2232
2561
  the gate. Infrastructure-owned watches may be cancelled during replacement;
2233
2562
  an active request, input exchange, or Task keeps the old snapshot authoritative
2234
- and makes replacement fail 409.
2235
-
2236
- The version-1 baseline table `workspace_module_state` stores one JSON value per
2237
- `(workspace_id, namespace_owner)`. It is not an alternate registry: executable
2238
- and resource presentation always comes from the in-memory snapshot reconstructed
2239
- by the registered provider. Deleting a workspace cascades its module state.
2240
-
2241
- ### §methods CoreSeam function set
2242
-
2243
- `CoreSeam` is a curated `Pick<Daemon, ...>` and therefore changes with the
2244
- implementation at compile time rather than through a parallel method catalog.
2245
- Its function names are transport-neutral library calls, not public wire names.
2563
+ and makes replacement fail 409. The workspace-wide gate is an atomicity
2564
+ boundary, not ownership: only the addressed worker's snapshot changes. A Worker's
2565
+ own accepted Functionality mutation is the one replacement that waits instead of
2566
+ failing: it queues fairly behind the turn that raised it and publishes at that
2567
+ turn's boundary ({§functionality-model-mutation}). Two publications take no
2568
+ gate of their own because their demand already holds whatever applies: a
2569
+ Worker's activation (demanded from a client action, an operation, or a child's
2570
+ turn inside its parent's held lineage) and a family's turn-admission refresh
2571
+ ({§skills-hotload}), which republishes inside the turn it is admitting. The
2572
+ three modes are explicit at the host boundary `try` (409 while held),
2573
+ `wait` (queue behind the holder), `none` (publish within the demand) — and
2574
+ nothing else may choose `none`.
2575
+
2576
+ §module-worker-inheritance **Functionality inherits by value.** Creating a
2577
+ child copies every parent `worker_module_state` row into the child in the same
2578
+ database transaction. Parent and child thereafter mutate independently;
2579
+ activation reconstructs each worker's own snapshot and generated references.
2580
+ Workers that merely share a workspace never share enabled Functionality.
2581
+
2582
+ §module-worker-residency **Persistence is not residency.** Model execution,
2583
+ capability-aware client reads and operations, worker module actions, and
2584
+ provider work retained through the setup context hold that worker's Functionality
2585
+ resident. Daemon boot, workspace or worker creation, attachment, listing,
2586
+ renaming, an idle client, and durable queued or parked state do not. After the
2587
+ final lease releases, core keeps the complete snapshot warm for
2588
+ `PLURNK_SERVICE_WORKER_WARM_MS` (default `900000`) while an idle LRU keeps at
2589
+ most `PLURNK_SERVICE_WORKER_WARM_MAX` (default `2`) lease-free workers.
2590
+ `0` disables the respective grace or idle allowance; `-1` disables that bound.
2591
+ Only lease-free workers cool. New demand cancels pending cooling or waits for
2592
+ in-progress cooling before one coalesced reactivation.
2593
+
2594
+ Cooling runs at a quiescent workspace-operation boundary. It deactivates every
2595
+ provider for that worker, withdraws its ephemeral executor and scheme snapshots,
2596
+ and evicts its passive process caches; durable workspace, worker, history,
2597
+ module-state, and reference-entry rows remain unchanged. Client connection
2598
+ presence and naming never participate in this lifecycle. Shutdown cancels warm
2599
+ timers and closes all still-resident provider resources through their module
2600
+ owner.
2601
+
2602
+ The version-1 baseline table `worker_module_state` stores one JSON value per
2603
+ `(worker_id, namespace_owner)`. It is not an alternate registry: executable and
2604
+ resource presentation always comes from the in-memory snapshot reconstructed by
2605
+ the registered provider. Deleting a worker cascades its state; child creation
2606
+ applies {§module-worker-inheritance}.
2607
+
2608
+ ### §functionality Worker Functionality: one lifecycle above every family
2609
+
2610
+ §functionality-coordinator **Core owns one coordinator above every family
2611
+ adapter.** Agent Skills, MCP servers, and outbound A2A agents are families of
2612
+ managed Functionality. Each family registers one adapter
2613
+ ({§functionality-adapter}); the coordinator owns the common lifecycle —
2614
+ `list | discover | add | enable | disable | remove` — its durable per-Worker
2615
+ state ({§functionality-state}), serialization per Worker and family, atomic
2616
+ publication ({§functionality-publication}), and both projections: worker-scoped
2617
+ client actions `worker.<family>.<verb>` and one generated executor family per
2618
+ Worker ({§functionality-model-projection}). An explicit client action and an
2619
+ accepted model proposal converge on the same coordinator method; no family
2620
+ invents a third management grammar, configuration path, proposal policy, or
2621
+ hotload mechanism.
2622
+
2623
+ | Verb | Common contract |
2624
+ |---|---|
2625
+ | `list` | Project every definition with its origin, desired enabledness, and current state — `disabled`, `active`, `unavailable` with its exact Problem, or `authorization-required` — without exposing credentials. |
2626
+ | `discover` | Inspect a query or source and return inert candidates with provenance. Discovery never installs, persists, enables, executes, or widens authority. |
2627
+ | `add` | Admit one exact definition through the adapter, persist it as a worker-origin definition, prepare it, and enable it atomically. A worker definition may shadow a same-alias service definition; a second worker definition for one alias is a 409 collision. |
2628
+ | `enable` | Prepare and publish one available definition; re-enabling an unavailable one retries its preparation. |
2629
+ | `disable` | Withdraw the effective capability while keeping the definition available and client-visible. |
2630
+ | `remove` | Disable and forget the Worker's own definition; a same-alias service definition becomes visible again, disabled. Service definitions are disable-only. |
2631
+
2632
+ §functionality-adapter **An adapter owns protocol truth and nothing else.** It
2633
+ declares its family (the action segment and EXEC tag), its one namespace owner,
2634
+ the exact definition schema one `add` accepts, its service-contributed
2635
+ definitions with their default enabledness, inert discovery, admission of an
2636
+ authored definition, two-phase preparation of the enabled set, and teardown.
2637
+ Preparation returns the family's runtimes, its generated documents, one outcome
2638
+ per enabled alias, and a snapshot with `commit`/`abort`; the coordinator
2639
+ never tears down a previous snapshot behind the adapter — it commits after a
2640
+ successful publication, aborts after a failed one, and tears down only on
2641
+ deactivation. Protocol continuations (an OAuth completion, an input-required
2642
+ answer) remain adapter-registered actions beneath the common grammar. An
2643
+ adapter may declare `forget`: before the coordinator forgets a Worker-origin
2644
+ definition on `remove` it lets the adapter release what that definition
2645
+ installed or provisioned ({§skills-remove}); a failed release rejects the
2646
+ removal and changes nothing.
2647
+
2648
+ §functionality-state **One durable value per Worker and family.** The
2649
+ coordinator stores `{ version: 1, definitions: { [alias]: { origin, enabled,
2650
+ definition? } } }` in `worker_module_state` under the adapter's namespace
2651
+ owner. A `service` alias persists only its enabledness; a `worker` alias
2652
+ persists its exact definition. Enabledness is durable desired state; active,
2653
+ unavailable, and authorization-required are the current preparation outcome.
2654
+ Inheritance by value is the table's own birth snapshot
2655
+ ({§module-worker-inheritance}); service, user, project, and client configuration
2656
+ contribute available definitions and defaults but are never the live effective
2657
+ authority.
2658
+
2659
+ §functionality-publication **One replacement publishes a family.** The
2660
+ coordinator prepares the enabled set, then replaces the family's state and
2661
+ runtimes — the family's manager runtime first, the adapter's capabilities after
2662
+ it — in one {§module-worker-capabilities} call, so admission, generated
2663
+ documentation, resources, effects, Turn 0, client status, and teardown derive
2664
+ from one committed snapshot. A failed replacement aborts the preparation and
2665
+ keeps the previous snapshot authoritative. Mutations serialize per Worker and
2666
+ family; shutdown — and any caller that must observe a boundary publication
2667
+ before acting, through `settleFunctionality` — settles every queued
2668
+ publication before closing the database.
2669
+
2670
+ §functionality-documents **A family's generated documents travel with its
2671
+ snapshot.** Preparation may return documents addressed relative to the
2672
+ Worker's generated subtree ({§worker-generated-subtree}); the coordinator
2673
+ contributes them to the Worker's reference entries so they reconcile with the
2674
+ same `_plurnk` materialization as every other generated document. The model
2675
+ surface is silent until active (operator ruling, #333): a disabled or
2676
+ enabled-but-unavailable definition publishes no document and no Turn 0 row —
2677
+ the hot path carries only working capability, never "a thing you cannot do."
2678
+ An unavailable definition's exact Problem stays reachable on demand: the
2679
+ family's `list` verb returns it and invoking the alias is rejected with it.
2680
+
2681
+ §functionality-model-projection **The model face is a generated executor
2682
+ family per Worker.** Every activated Worker publishes, for each registered
2683
+ family, one executor tagged with the family name whose registered targets are
2684
+ exactly the six verbs; its documents render through
2685
+ {§tools-resource-materialization} like every family, so the model learns the
2686
+ manager from `_plurnk/skills/plurnk/<family>.md` and never from hand-written
2687
+ teaching. `list` and `discover` are `read` effects and run ungated; `add`,
2688
+ `enable`, `disable`, and `remove` are `host` effects and propose through
2689
+ the ordinary Exec proposal lifecycle. A verb's JSON outcome streams into the
2690
+ family's output entry. `ExecArgs` carries no Worker identity, which is why
2691
+ the manager is published per Worker rather than once.
2692
+
2693
+ §functionality-model-mutation **An accepted mutation publishes at its turn
2694
+ boundary.** The verb runs inside the turn that raised it, which holds the
2695
+ workspace; the coordinator persists desired state and prepares immediately —
2696
+ so the result reports `active`, `unavailable`, or `authorization-required`
2697
+ — and a failed preparation publishes an enabled-but-unavailable outcome rather
2698
+ than rejecting. Publication queues behind that turn in the family's serialized
2699
+ lane and settles before the Worker's next operation or packet. An explicit
2700
+ client action instead publishes now, rejects a failed preparation, and fails
2701
+ 409 while the workspace is held ({§module-worker-quiescence}). Rejecting a
2702
+ proposal prepares, persists, and publishes nothing.
2703
+
2704
+ ### §methods ApplicationPort function set
2705
+
2706
+ `ApplicationPort` is the contracts-owned interface implemented by `Daemon` and
2707
+ consumed by every exterior adapter ({§application-port}). Its function names are
2708
+ transport-neutral library calls, not public wire names; this table specifies
2709
+ Core's behavior behind them.
2246
2710
 
2247
2711
  | Area | Function | Core contract |
2248
2712
  |---------------------------------------------------|----------|---------------|
@@ -2251,15 +2715,16 @@ Its function names are transport-neutral library calls, not public wire names.
2251
2715
  | §methods-proposal-resolve Proposals | `resolveProposal(logEntryId, resolution)` | Validates and delivers one accept, reject, or cancel decision to the engine. An unknown or already-resolved id fails; the client protocol owns how the decision arrived. |
2252
2716
  | §client-interaction-list Client interactions | `pendingClientInteractions(workspaceId)` | Intersects durable interaction rows with their live operation waiters and returns the contracts-owned projection; a row alone is not a resumable interaction. |
2253
2717
  | §methods-client-interaction-resolve Client interactions | `resolveClientInteraction(interactionId, resolution)` | Validates and delivers one resolved payload or cancellation. Unknown, ownerless, and already-resolved identities fail before affecting an operation. |
2254
- | §methods-loop-run Loops | `runLoop({ workspaceId, workerId, prompt, maxTurns?, flags?, openPaths?, alias?, model?, childAlias?, childModel? })` | Validates a model worker and provider policy, persists it with the effective turn ceiling, then returns an immediate status-100 acknowledgement with `loopId` and `action`. The exact terminal result arrives only through `loop/terminated`; parking and resuming do not replace the loop. |
2255
- | §methods-loop-cancel Loops | `cancelDrain(workerId, reason?)` | Begins durable structured cancellation of the worker tree and reaps its process-local scopes. The boolean reports whether process-local work existed when called; queued or parked durable work is still terminalized when it is `false`. |
2256
- | §methods-op-mirror Client dispatch | `dispatchClientAction({ workspaceId, workerId, statements })` | Dispatches already-parsed grammar statements as one client action and one journal segment. Every statement is an ordered turn, and every committed `log/entry` is emitted before the action promise resolves; a proposal may keep that promise and segment open until resolution. Core exposes no per-op method family. |
2257
- | Client observation | `look({ workspaceId, workerId, statement })` | Runs an already-parsed READ through the full resolver without a log row. A non-READ statement is rejected ({§op-look}). |
2718
+ | §methods-loop-run Loops | `runLoop({ workspaceId, workerId, prompt, source?, maxTurns?, flags?, openPaths?, selector?, childSelector? })` | Validates a model worker and provider policy, persists it with the effective turn ceiling, then returns an immediate status-100 acknowledgement with `loopId` and `action`. A trusted adapter may identify the prompt's causal actor with one canonical `source`; ordinary clients cannot author it through their protocol surface. The exact terminal result arrives only through `loop/terminated`; parking and resuming do not replace the loop. |
2719
+ | §methods-loop-cancel Loops | `cancelDrain(workerId, reason?)`; `cancelWorker({ workspaceId, workerId, reason? })` | `cancelDrain` begins durable structured cancellation and reports whether process-local work existed when called; queued or parked durable work is still terminalized when it is `false`. The ownership-bounded `cancelWorker` awaits that same tree cancellation and stream reap, so an exterior protocol can project the settled durable result without polling or fabricating state. |
2720
+ | §methods-op-mirror Client dispatch | `dispatchClientAction({ workspaceId, workerId, functionalityWorkerId, statements })` | Dispatches already-parsed grammar statements as one client action in one administrative loop in the client worker, executing in the attached Worker's Functionality ({§actor-boundary-attached-functionality}). Every statement is an ordered client/operation turn, and every committed `log/entry` is emitted before the action promise resolves; a proposal may keep its turn, loop, and action promise open until resolution. Core exposes no per-op method family. |
2721
+ | Client observation | `look({ workspaceId, workerId, functionalityWorkerId, statement })` | Runs an already-parsed READ through the full resolver in the attached Worker's Functionality without a log row. A non-READ statement is rejected ({§op-look}). |
2258
2722
  | §methods-log-read Reads | `readLog({ workspaceId, workerId, ...coordinate })` | Ownership-checks the worker, then reads by ids, recency, or the complete `loopSeq`/`turnSeq`/`sequence` display coordinate. `limit` defaults to 100 and is capped at 1000. |
2259
2723
  | §methods-entry-read Reads | `readEntry({ workspaceId, workerId, target, channel?, offset? })` | Resolves the selector from that worker's perspective and returns {§entry-read-result}, either complete or as one channel suffix, without creating action evidence. |
2260
2724
  | Providers | `listProviders()` | Lists configured aliases with provider/model identity, active state, and the effective provider-derived `inputCapacity` when known. |
2725
+ | Model catalog | `listModels(query)` | Returns one validated bounded {§model-catalog-wire} page under {§model-catalog}; performs no provider request or selection. |
2261
2726
  | Client capabilities | `listClientDisplayCapabilities()` | Composes sorted scheme declarations ({§manifest-client-display}) followed by sorted MIME declarations ({§mimetype-client-display}) into the validated shared wire ({§client-display-capabilities}). The internal `exec` operation handler is excluded; its addressable runtime-tag scheme faces remain included. |
2262
- | §methods-workspace-create Workspace lifecycle | `createWorkspace({ name?, projectRoot?, settings?, constraints? })` | Validates `settings` through {§operator-config-workspace-settings}, creates the world and its client envelope, materializes current docs and constraints, starts derivation warming, and emits global `workspace/created`. `projectRoot` is established here or the workspace remains headless. |
2727
+ | §methods-workspace-create Workspace lifecycle | `createWorkspace({ name?, projectRoot?, settings?, constraints? })` | Validates `settings` through {§operator-config-workspace-settings}, creates the world and its client envelope, applies constraints, and emits global `workspace/created`. Creation and attachment are passive: neither starts derivation nor activates worker Functionality. `projectRoot` is established here or the workspace remains headless. |
2263
2728
  | §methods-workspace-attach Workspace lifecycle | `attachWorkspace({ workspaceId, workerId?, workerName? })` | Validates ownership and returns a client envelope for an existing world. It does not retain caller or transport binding state in core. |
2264
2729
  | §methods-model-worker Workspace lifecycle | `ensureModelWorker(workspaceId)` | Returns the workspace's stable default model worker, creating it on first use. A durable default-conversation role identifies it independently of worker name and root creation order. Repeated and concurrent calls return the same root; fresh conversations and forks do not replace it. |
2265
2730
  | §methods-conversation-worker Workspace lifecycle | `createConversationWorker({ workspaceId, name? })` | Creates a distinct model-origin root worker with empty private history: a fresh conversation over the same world, not a fork or the stable default. |
@@ -2267,8 +2732,11 @@ Its function names are transport-neutral library calls, not public wire names.
2267
2732
  | §methods-workspace-rename Workspace metadata | `renameWorkspace(workspaceId, name)` | Changes only the world's unique mutable name; workers, log, and membership remain intact. |
2268
2733
  | Workspace metadata | `constrain(...)`, `unconstrain(...)`, `listConstraints(...)`, `listMembers(...)` | Owns the membership overlay and returns its resolved effects; clients do not reimplement constraint semantics. |
2269
2734
  | §methods-workspace-prompts Workspace metadata | `listPrompts(workspaceId, limit?)` | Returns nonempty loop-seed prompts from the workspace's model-origin root conversations, newest-first. The positive limit defaults to 100; spawned and forked child prompts are excluded. |
2270
- | Workspace metadata | `listWorkspaces()`, `listWorkers(...)`, `workspaceDerivationStatus(...)` | Reads current workspace topology and derivation progress. |
2271
- | Extension actions | `listModuleActions()`, `invokeModuleAction(name, params, context)` | Lists setup-registered `{ name, scope }` descriptors in sorted order. Invocation requires a context matching the registered scope; missing names, forged scope, and missing workspace identity fail before the owner runs. Handler values remain opaque to core. |
2735
+ | Workspace metadata | `listWorkspaces()`, `workspaceDerivationStatus(...)` | Reads current workspace identity and derivation progress. |
2736
+ | §methods-worker-read Worker topology | `readWorker({ workspaceId, identity })` | Ownership-bounds an exact id-or-name lookup and returns one durable Worker projection or `null` under {§application-worker-observation}. Supplying both identities or neither is invalid. |
2737
+ | §methods-worker-list Worker topology | `listWorkers(workspaceId, query?)` | Returns the workspace's durable Worker projections under {§application-worker-observation}. The origin filter is exact; an explicitly present `parentWorkerId` filters roots (`null`) or one immediate parent (id), while omission returns every lineage position. |
2738
+ | §methods-worker-loops Loop lifecycle | `listWorkerLoops({ workspaceId, workerId })` | Ownership-checks the Worker and returns its Loops in sequence order under {§application-loop-observation}, including the validated exact terminal result when one exists. It performs no scheduling or event replay. |
2739
+ | Extension actions | `listModuleActions()`, `invokeModuleAction(name, params, context)` | Lists setup-registered `{ name, scope, inputSchema, outputSchema }` descriptors in sorted order. Invocation requires a context matching the registered scope; missing names, forged scope, and missing workspace identity fail before the owner runs. Handler values remain opaque to core. |
2272
2740
 
2273
2741
  §methods-loop-run-fold-consistency **A folded prompt cannot silently reconfigure
2274
2742
  its loop.** When `runLoop` targets an active or 202-parked loop, core appends the
@@ -2306,8 +2774,8 @@ workspace lifecycle calls return exactly the workspace and selected client actor
2306
2774
  carry no conversation-worker or action-loop binding. Core retains no connection,
2307
2775
  thread, or current-workspace mapping. A module may replace its own binding with a
2308
2776
  later create or attach result without requiring a new transport; it resolves the
2309
- conversation worker separately, while each client action allocates its own journal
2310
- segment under {§connection-lifecycle}.
2777
+ conversation worker separately, while each client action allocates its own
2778
+ administrative loop under {§connection-lifecycle}.
2311
2779
 
2312
2780
  §methods-worker-name-reserved **Client worker-name admission.** Attach,
2313
2781
  fresh-conversation, and fork apply {§worker-name-minting} before lookup or
@@ -2315,24 +2783,118 @@ creation. A client therefore cannot forge or resume an internal worker, insert
2315
2783
  a non-mintable spelling, or make the client registry diverge from model worker
2316
2784
  control.
2317
2785
 
2318
- §methods-loop-run-model **Per-loop model selection.** Optional `model`
2319
- (client-resolved `<provider>/<model>`, wins) or `alias` (a declared
2320
- `PLURNK_MODEL_<alias>`) overrides the boot default for a newly created loop.
2321
- The fully resolved provider identity is persisted on that loop and remains
2322
- immutable through turns, parks, wakes, and restart. Injecting into an existing
2323
- loop with a conflicting selection fails before work is accepted. Provider
2324
- instances are cached; no resume path substitutes a boot default for missing or
2325
- malformed durable selection.
2786
+ §worker-settings **The worker carries its own behavioral rules.** The
2787
+ workspace is the world how things are; each worker is an actor inside it,
2788
+ carrying the rules its loops obey. Those rules live in one JSON bag
2789
+ (`workers.settings`), declared by the client at worker creation and mutable
2790
+ between loops through `readWorkerSettings`/`setWorkerSettings`; the bag is
2791
+ validated at the client-input boundary against a closed known-key set, and
2792
+ unknown keys never persist. A fork begins with the default empty bag — no
2793
+ inherited rules, no live link. Readers are permissive: malformed persisted
2794
+ JSON yields the default rules, never a read failure. There is no servicewide
2795
+ or workspace ceiling on a worker's own rules; each client decides for its own
2796
+ workers.
2797
+
2798
+ §question-tool **The native request-user-input tool.** Core registers one
2799
+ in-process `question` runtime at boot. Its body is the MCP2 2026-07-28
2800
+ form-elicitation shape verbatim — `{ message, requestedSchema }` — and its
2801
+ `results` channel carries the standard `ElicitResult`
2802
+ (`{ action: "accept", content }` or `{ action: "cancel" }`); nothing bespoke
2803
+ crosses the wire. The executor maps the body onto the contracts-owned
2804
+ `ClientInteractionRequest` (toolName `question`) and awaits the shared
2805
+ client-interaction lifecycle — durable pause, reconnect discovery,
2806
+ cancellation, and the answer-as-resolution all come from
2807
+ {§client-interactions}; there is no loopback MCP and no proposal masquerade.
2808
+ Effect `read`: the tool observes the human's answer and is never
2809
+ proposal-gated. Admission is per-worker under {§worker-settings}: the tool
2810
+ exists for a worker only when that worker's `requestUserInput` rule is set.
2811
+
2812
+ §worker-tool-admission **Per-worker tool admission.** A runtime may be
2813
+ admitted per worker through the reserved tool tree's visibility rule: the
2814
+ find/read faces of the worker scheme drop a tool doc for an asking worker
2815
+ whose own rules don't admit it, before matching and rendering, so counts,
2816
+ weights, and the catalog text all agree — the tool does not exist for that
2817
+ worker's FIND. Dispatch enforces the same boundary with an explicit
2818
+ not-available outcome. Admission reads the worker's behavioral rules
2819
+ ({§worker-settings}) at the operation boundary, never at registration.
2820
+
2821
+ §model-catalog **Model discovery is a bounded local projection, not provider
2822
+ activity.** Core composes the release-pinned Models.dev snapshot with
2823
+ provider-owned `{§model-catalog-readiness}`. The default query includes only
2824
+ providers configured enough to attempt; `availability: "all"` includes every
2825
+ catalog model with structured missing-configuration causes. Provider and text
2826
+ filters apply before deterministic selector ordering and offset/limit paging;
2827
+ the default page is 50 and the schema caps it at 100. Discovery never probes,
2828
+ authenticates, invokes, or selects a model, and catalog data never enters model
2829
+ packets or state snapshots.
2830
+
2831
+ §worker-model-selection **Worker-owned model selection.** Every model worker
2832
+ owns one durable model, persisted as a nullable `model_routes` foreign key.
2833
+ The root conversation worker is seeded once — from an explicit selection, else
2834
+ the daemon default — and never re-seeded from a later default change. A
2835
+ deliberately modelless daemon leaves the worker unset and rejects model work
2836
+ until an explicit selection. Starting a loop snapshots the worker's resolved
2837
+ model onto the loop; inject, park, wake, retry, reconnect, and restart
2838
+ continue from the loop snapshot and never re-resolve through the alias
2839
+ cascade. A WORK/FORK child copies the spawning loop's effective spawn model
2840
+ (spawn override ?? model) onto the new worker by value at creation; it retains
2841
+ no live link and begins with no override, so a later parent change affects
2842
+ only that worker's future loops and descendants. Client operation actors and
2843
+ Plurnk-owned bookkeeping workers run no model loops and own no model
2844
+ selection. An explicit selection or spawn-override change while the worker
2845
+ holds a live or parked loop is a precise `409 worker-loop-active`, never a
2846
+ silent retroactive switch of the immutable loop snapshot; select after
2847
+ concluding or cancelling the loop.
2848
+
2849
+ A client-created branch copies the source worker's durable model, spawn
2850
+ override, and reasoning policy by value alongside its history. It retains no
2851
+ live policy link to the source worker.
2852
+
2853
+ §worker-reasoning-policy **Reasoning is a durable worker policy.** Each selected
2854
+ worker model has exactly one member of the shared `{§reasoning-policy-wire}`;
2855
+ a modelless worker has none. A declared alias's scoped environment value—or the
2856
+ global provider value for an exact route—seeds the policy only when the worker
2857
+ first receives its model. Model identity and reasoning
2858
+ policy are persisted atomically, while visibility of returned reasoning and
2859
+ token ceilings remain separate concerns. An explicit policy change validates
2860
+ the exact policy against both the worker model and its optional spawn model and
2861
+ is refused while the worker owns a live or parked loop. Client inspection
2862
+ returns the supported-policy intersection of those two routes. Inspection or
2863
+ mutation materializes the daemon-default model and policy onto an uninitialized
2864
+ model worker before answering; a deliberately modelless daemon remains unset.
2865
+
2866
+ Starting a loop snapshots the worker's policy beside its model. Restart, retry,
2867
+ park, wake, and injection retain that immutable snapshot. WORK, FORK, and BARE
2868
+ inherit the spawning loop's policy by value; no descendant consults a later
2869
+ environment or parent-worker change. Unsupported policies fail with a precise
2870
+ provider-boundary problem rather than being silently weakened or translated.
2871
+
2872
+ §methods-loop-run-model **Per-loop model selection.** `runLoop` accepts one
2873
+ optional `selector`: either a declared alias or an exact `<provider>/<model>`
2874
+ route. An exact route stores no fabricated alias and receives no alias-scoped
2875
+ configuration. An explicit selection persists onto the
2876
+ addressed worker before the loop snapshots it; an omitted selector is not a
2877
+ selection and continues the worker's durable model
2878
+ ({§worker-model-selection}). The fully resolved provider identity and reasoning
2879
+ policy are persisted on the loop and remain immutable through turns, parks,
2880
+ wakes, and restart ({§worker-reasoning-policy}).
2881
+ Injecting into an existing loop with a conflicting explicit selection fails
2882
+ before work is accepted. Provider instances are cached; no resume path
2883
+ substitutes a boot default for missing or malformed durable selection.
2326
2884
 
2327
2885
  §methods-loop-run-child-provider **Child-provider selection is one durable
2328
- subcall policy.** Optional `childModel` (client-resolved `<provider>/<model>`, wins) or
2329
- `childAlias` selects the provider for every WORK/FORK descendant and BARE inference; omitted uses
2330
- `PLURNK_MODEL_CHILD`, while explicit `childAlias: null` means inherit. Core
2331
- persists the resolved policy on each loop. A child runs on that provider and
2332
- carries the same policy deeper; inherit uses the spawning loop's provider and
2333
- remains inherit. BARE consumes the selection without spawning a child. Packet admission is unchanged: a smaller WORK is valid when
2334
- its packet fits, and an oversized inherited FORK terminates through the ordinary
2335
- child-loop result without preflight assembly or provider fallback.
2886
+ subcall policy.** Optional `childSelector` uses the same alias-or-exact-route
2887
+ vocabulary for every WORK/FORK descendant and BARE inference; omitted uses
2888
+ `PLURNK_MODEL_CHILD`, while explicit `childSelector: null` means inherit. An
2889
+ explicit override persists onto the addressed worker before the loop
2890
+ snapshots it; an omitted selector continues the worker's durable override
2891
+ ({§worker-model-selection}). Core persists the resolved policy on each loop. A
2892
+ child runs on the spawning loop's effective spawn model and carries the same
2893
+ policy deeper; inherit uses the spawning loop's provider and remains inherit.
2894
+ BARE consumes the selection without spawning a child. Packet admission is
2895
+ unchanged: a smaller WORK is valid when its packet fits, and an oversized
2896
+ inherited FORK terminates through the ordinary child-loop result without
2897
+ preflight assembly or provider fallback.
2336
2898
 
2337
2899
  §methods-log-coordinate **Log coordinate.** Every `LogEntry` returned by
2338
2900
  `readLog` or emitted through `log/entry` carries `loop_seq` and `turn_seq`
@@ -2344,6 +2906,13 @@ preserve causal `source` and parse the row's JSON `attrs` into structured data;
2344
2906
  they also project the row's complete sorted `tags` classification. Client
2345
2907
  interfaces do not reconstruct these fields from operation or origin.
2346
2908
 
2909
+ §methods-readable-reasoning **Readable provider reasoning remains derived
2910
+ provider evidence.** On the model SEND row only, `readLog` and `log/entry`
2911
+ project a nonempty admitted `packet.assistant.reasoning` as the optional
2912
+ `reasoning` field. The durable packet remains the sole stored representation;
2913
+ core does not copy readable reasoning into log attributes or bodies. A turn
2914
+ without readable reasoning omits the field.
2915
+
2347
2916
  §op-look **LOOK ownership.** A client-interface module owns the public LOOK
2348
2917
  spelling and grammar parsing. It rewrites a valid LOOK statement to READ and
2349
2918
  hands the AST to core's `look`; core owns the full resolver and the no-log
@@ -2365,6 +2934,7 @@ active lifecycle behind. LOOK text anchors resolve through the same
2365
2934
  | §notifications-stream-event-on-channel-change `stream/event` | `{ entryId, workerId, target, channel, state, contentLength, mimetype?, loop_seq?, turn_seq?, sequence? }` | Channel content grows or channel state transitions. `workerId` is the entry owner and read perspective; `target` is its canonical URI. The optional coordinate is copied from schemes whose addresses carry one. Core-managed channel writes include the current stored `mimetype`, which may change per call ({§channel-mimetype}); the generic plugin notification capability does not require it. It carries metadata, not content; consumers read bytes from the stated worker perspective. |
2366
2935
  | §notifications-stream-concluded `stream/concluded` | `{ entryId, workerId, target, subscriptionId, scheme, result, summary, wakeAction, wakeLoopId?, loop_seq?, turn_seq?, sequence? }` | A subscription closes. `workerId` identifies the entry owner; `target` is its canonical URI. The optional coordinate is copied from schemes whose addresses carry one, so clients never parse it back out of `target`. Exact result truth is preserved; `wakeAction` records whether core resumed a parked loop, folded into an active loop, skipped an aborted/cancelled worker, or found no loop. |
2367
2936
  | §notifications-notice-event `notice/event` | `{ loopId, notice: Notice }` | A transient observation or progress notice occurs. It cannot alter durable history, scheduling, recovery, or model-visible failure truth. |
2937
+ | §notifications-reasoning-event `reasoning/event` | `{ workerId, loopId, turnId, modelCallId, phase, delta? }` | A main emission call exposes readable reasoning. A nonempty stream is balanced start/content/end; only content carries a nonempty exact delta. It is transient presentation evidence, never a log row, Notice, packet field, or BARE/child channel. The settled provider response remains the durable authority. |
2368
2938
 
2369
2939
  §notifications-stream-event-failure-isolation The plugin-facing
2370
2940
  `NotifyCaps.streamEvent()` remains a synchronous advisory call while core
@@ -2386,11 +2956,13 @@ outward envelope that requires it and owns workspace fan-out.
2386
2956
  ### §connection-lifecycle Client action evidence
2387
2957
 
2388
2958
  A module client is an actor ({§machine-processes}). Its dispatched side effects
2389
- write to its own client worker with `origin="client"`; one client action owns
2390
- one journal segment, and its statements become ordered turns inside that
2391
- segment. A proposal may hold the segment across an external interrupt/resume,
2392
- but the segment records durable evidence rather than defining the public client
2393
- lifecycle. Multiple client actors have distinct workers.
2959
+ write to its own client worker with `origin="client"` and execute in the
2960
+ Functionality of the Worker the client is attached to
2961
+ ({§actor-boundary-attached-functionality}); one client action owns
2962
+ one administrative loop, and its statements become ordered operation turns
2963
+ inside that loop. A proposal may hold its turn and loop across an external
2964
+ interrupt/resume, but those records preserve durable evidence rather than
2965
+ defining the public client lifecycle. Multiple client actors have distinct workers.
2394
2966
 
2395
2967
  `runLoop` targets a separate model worker holding the conversation with
2396
2968
  `origin="model"`. Both workers share workspace state, while a packet renders
@@ -2415,14 +2987,14 @@ implementation status, and superseded alternatives belong in forge issues.
2415
2987
 
2416
2988
  `PacketBuilder.buildRequestPacket` owns the engine's default ordered section
2417
2989
  list. Trusted scheme plugins may transform that first-class list before it is
2418
- rendered or measured; the grinder remains an engine-owned post-build rail.
2990
+ rendered or measured; {§overflow-turn} remains an engine-owned post-build rail.
2419
2991
 
2420
2992
  ```mermaid
2421
2993
  flowchart LR
2422
2994
  defaults[Engine section drafts] --> transforms[Trusted scheme transforms<br/>and boundary validation]
2423
2995
  transforms --> render[Render system and user slots]
2424
2996
  render --> measure[Budget substitution and<br/>core-owned measurement]
2425
- measure --> rail[Engine grinder and dispatch]
2997
+ measure --> rail[Engine budget admission and dispatch]
2426
2998
  ```
2427
2999
 
2428
3000
  #### §packet-cache-monotone Default order and cache locality
@@ -2434,21 +3006,19 @@ Conditional absence never reorders the surviving default sections.
2434
3006
  | 1 | system | `definition` | Framework definition; leads the most stable prefix. |
2435
3007
  | 2 | system | `system-policy` | Operator policy; empty content is omitted on the wire. |
2436
3008
  | 3 | system | `project-policy` | Project policy; empty content is omitted on the wire. |
2437
- | 4 | system | `tools` | Executable capability sheet for this loop. |
2438
- | 5 | system | `optional-operations` | Present only when optional operations are enabled. |
2439
- | 6 | system | `schemes` | Active resource catalogue. |
2440
- | 7 | system | `inject` | Present only when operator notes are configured. |
2441
- | 8 | user | `log` | Append-mostly model-visible history. |
2442
- | 9 | user | `child-streams` | Per-turn status; empty content is omitted. |
2443
- | 10 | user | `child-workers` | Per-turn status; empty content is omitted. |
2444
- | 11 | user | `errors` | Per-turn failure pointers; empty content is omitted. |
2445
- | 12 | user | `notices` | Per-turn observations; empty content is omitted. |
2446
- | 13 | user | `git` | Per-turn workspace status; empty content is omitted. |
2447
- | 14 | user | `budget` | Model-facing packet pressure; omitted when capacity is unknown. |
2448
- | 15 | user | `prompt` | Current prompt-entry pointers. |
3009
+ | 4 | system | `schemes` | Active resource catalogue. |
3010
+ | 5 | system | `inject` | Present only when operator notes are configured. |
3011
+ | 6 | user | `log` | Append-mostly model-visible history. |
3012
+ | 7 | user | `child-streams` | Per-turn status; empty content is omitted. |
3013
+ | 8 | user | `child-workers` | Per-turn status; empty content is omitted. |
3014
+ | 9 | user | `errors` | Per-turn failure pointers; empty content is omitted. |
3015
+ | 10 | user | `notices` | Per-turn observations; empty content is omitted. |
3016
+ | 11 | user | `git` | Per-turn workspace status; empty content is omitted. |
3017
+ | 12 | user | `budget` | `Context Token Budget`; omitted when capacity is unknown. |
3018
+ | 13 | user | `prompt` | Current prompt-entry pointers. |
2449
3019
 
2450
3020
  The order favors prefix-cache locality where semantics permit: the definition
2451
- and privileged policy lead loop-dependent capabilities, while the append-mostly
3021
+ and privileged policy lead the resource directory, while the append-mostly
2452
3022
  log leads the volatile user-status clump. It does **not** claim that every system byte is
2453
3023
  immutable or that the complete packet is globally monotone in volatility:
2454
3024
  capabilities, operator notes, and policies can change. Trust is a separate
@@ -2469,7 +3039,7 @@ sections. It receives no separate engine, database, actor, or request context.
2469
3039
  This is strictly a trusted in-process seam, admitted through the common plugin
2470
3040
  trust gate; an external client action cannot invoke it. Whole-list transformation is
2471
3041
  the fork-avoidance valve for alternate packet shapes ({§ecosystem}), while
2472
- grinding and folding remain closed engine concerns.
3042
+ overflow recovery and folding remain closed engine concerns.
2473
3043
 
2474
3044
  ### §tokenomics Tokenomics: four facts, one curation ruler
2475
3045
 
@@ -2484,8 +3054,8 @@ time of measurement.
2484
3054
  | Provider usage and cost | Provider-reported input/output/cache/reasoning tokens and monetary evidence | After every physical request | Durable physical-request forensics under {§provider-usage}; never curation state or a preflight estimate. |
2485
3055
 
2486
3056
  - §tokenomics-weight-stored-at-write **Curation weight, stored at write.** `entry_channels.weight` weighs the complete channel content. `log_entries.weight` weighs the complete canonical `LogBody` content before coordinate and packet presentation; persistence `tx`/`rx` envelopes contribute nothing merely by existing, and proposal settlement recomputes the value when the canonical result changes. Bodyless rows therefore weigh zero. The stored number is a stable content-depth measurement, not a provider-token prediction.
2487
- - §tokenomics-render-weight-budget **Packet curation budget.** The Curation headline measures the *assembled packet* after section transforms and readout substitution. Core measures minimum-width probes, monotonically expands fields that do not fit, then right-aligns final values into those widths; final substitution is length-invariant and displayed weight equals the stored request weight. A `SUM` of stored content weights measures a different artifact and cannot substitute for packet render weight.
2488
- - §tokenomics-context-percent **Curation percent.** The headline carries packet weight as a percentage of its curation budget beside the absolutes. It reads the capacity already resolved by the provider; no extra provider call.
3057
+ - §tokenomics-render-weight-budget **Packet curation budget.** `tokensActiveTotal` measures the *complete assembled packet* after section transforms and readout substitution; it is not a sum of log-row `tokensActive` fields. Core measures minimum-width probes, monotonically expands fields that do not fit, then right-aligns final values into those widths; final substitution is length-invariant and the displayed total equals the stored request weight. `tokensActiveMax` is the provider-derived curation calibration. A `SUM` of stored content weights measures a different artifact and cannot substitute for packet render weight.
3058
+ - §tokenomics-context-percent **Curation percent.** `tokensActiveTotal` carries packet weight as a percentage of `tokensActiveMax`. It reads the capacity already resolved by the provider; no extra provider call.
2489
3059
  - §tokenomics-window-partition **One capacity derivation; no service-side token budget.** The provider owns model limits and the configured total output envelope. Its resolved `inputCapacity` is the numeric curation-budget calibration as well as the physical denominator exposed to clients. That reuse is policy, not a unit conversion: Core compares stable curation weight with it only to shape context, while provider request-shaped evidence alone admits or rejects I/O. `PLURNK_SERVICE_PROMPT_BUDGET`, `PLURNK_SERVICE_SAFETY`, and the additive reasoning/completion reserve knobs are retired; local and custom deployments tune context window, total output budget, optional reasoning subset, and prompt-projection percentage at their owning layers.
2490
3060
  - §tokenomics-prompt-projection-share **Prompt projection is stable packet policy.**
2491
3061
  `PLURNK_SERVICE_PROMPT_PROJECTION` is a required alias-scoped percentage in
@@ -2496,15 +3066,15 @@ time of measurement.
2496
3066
  one prompt's projection byte-stable as the worker log evolves.
2497
3067
  - §tokenomics-window-unpollable-deliberate **Unknown provider capacity stays unknown.** When the provider cannot derive `inputCapacity`, Core omits denominator-dependent curation telemetry and uses the ordinary bounded prompt projection. The provider still sends requests whose measurement or limits are estimates or unavailable: ambiguity defers to the upstream capacity oracle rather than becoming a local rejection.
2498
3068
 
2499
- §tokenomics-client-gauge **Clients receive curation and physical occupancy as separate pairs.** `loop/terminated.usage` carries latest-turn `curationWeight`/`curationBudget` and latest-emission-call `contextTokens`/`contextCapacity`; each unknown fact is `null`. Both physical facts bind to that same call: a preflight rejection may report capacity while its absent physical request leaves `contextTokens=null`, never borrowed from an earlier call. Clients never divide provider-reported physical tokens by Core curation weight. `providers.list` exposes each instantiated alias's `inputCapacity`. A model switch replaces the latest-turn facts together; aggregate provider accounting remains cardinal monetary evidence, not a gauge input.
3069
+ §tokenomics-client-gauge **Clients receive curation and physical occupancy as separate pairs.** `loop/terminated.usage` carries latest packet-bearing model-turn `curationWeight`/`curationBudget` and latest-emission-call `contextTokens`/`contextCapacity`; each unknown fact is `null`. Packetless chronology cannot erase an assembled-request gauge. Both physical facts bind to that same call: a preflight rejection may report capacity while its absent physical request leaves `contextTokens=null`, never borrowed from an earlier call. Clients never divide provider-reported physical tokens by Core curation weight. `providers.list` exposes each instantiated alias's `inputCapacity`. A model switch replaces the latest-turn facts together; aggregate provider accounting remains cardinal monetary evidence, not a gauge input.
2500
3070
 
2501
- - **Derivation is eager and exhaustive.** Workspace creation and searchable-resource changes start one coalesced warm. The first model turn joins that warm; later turns derive intervening changes before dispatch. No model operation observes partial graph or vector coverage. A semantic query ranks every eligible candidate in scope, so lexical overlap never gates vector recall. With no embedder, readable-content FTS is the explicit keyword fallback. Progress notices make the wait visible; latency is never hidden by partial semantics. {§derivation-exhaustive}
3071
+ - **Derivation is exhaustive and demand-led.** Explicit searchable-resource changes may start one coalesced warm. Passive creation and attachment do not. The first model turn starts or joins that warm; later turns derive intervening changes before dispatch. No model operation observes partial graph or vector coverage. A semantic query ranks every eligible candidate in scope, so lexical overlap never gates vector recall. With no embedder, readable-content FTS is the explicit keyword fallback. Progress notices make the wait visible; latency is never hidden by partial semantics. {§derivation-exhaustive}
2502
3072
  - §membership-binary-sniff **Binary truth beats the label; no entry dominates the corpus.** A tracked member whose HEAD bytes contain NUL enters {§membership-source-projection} as `application/octet-stream` **regardless of what extension-based detection claims**; byte-level evidence outranks a default label. Every eligible text is tiled losslessly to the embedder window and every tile is embedded before its derivation attaches; semantic ranking max-pools the best chunk per candidate.
2503
3073
  - §tokenomics-agnostic-ruler **One model-agnostic curation ruler.** The daemon runs workers on different models in one workspace concurrently, while catalog and log accounting are workspace-wide. `contentWeight = ceil(chars/2)` therefore gives one content one stable number without per-model workspace state or recount passes. It controls curation only; every provider call independently measures the complete request as well as it can.
2504
- - §tokenomics-neutral-telemetry **Curation telemetry is state, with one pressure alarm.** The model-facing Curation section ordinarily has one line: budget, current packet weight and percentage, and free weight. When free weight is negative, exactly one second line directs the model to FOLD or KILL less-relevant log items. Per-entry weights remain on log rows where they describe OPEN cost and FOLD savings. Packet-level composition, rankings, and physical token speculation are absent.
3074
+ - §tokenomics-neutral-telemetry **Curation telemetry is state, not response allowance.** The model-facing `Context Token Budget` section contains exactly two fields on separate lines: `tokensActiveTotal: N (P%)` and `tokensActiveMax: M`. It never presents their difference as free response tokens. The protocol definition directly requires FOLD, KILL, or trimming of irrelevant log items to keep the next packet within the maximum. Per-entry weights remain on log rows where they describe OPEN cost and FOLD savings. Packet-level composition, rankings, and physical token speculation are absent.
2505
3075
  - §tokenomics-content-hash-identity **Content identity, not per-tokenizer counts.** Static channel writes stamp `content_hash` (SHA-256) as stable content identity. `weight` is stored beside that content and is never keyed or recomputed by model.
2506
- - §tokenomics-provider-usage **Provider accounting is physical-request evidence, not curation state.** Every issued physical request has one durable pre-I/O `provider_requests` identity and settles once as response or error. Each record preserves conventional {§provider-usage} quantities and required {§provider-cost} evidence; an unreported quantity remains absent, including on response-less failures, and is never replaced by zero. `model_calls` own logical response/failure evidence, `turn_attempts` specialize emission admission, and `provider_requests` are the sole durable accounting representation. Emissions, BARE calls, rejected responses, retries, failovers, and errors therefore remain cardinal and ordered. Turn, loop, worker, workspace, digest, and protocol accounting are derived from those records through the shared {§provider-accounting} projection; only emission calls contribute the latest-packet context gauge. The baseline stores no floating-point money, denormalized totals, or rollup triggers. A documented direct charge becomes `charged`; otherwise the provider may compute an exact-decimal USD `estimated` amount from complete usage and the exact model's Models.dev rates; insufficient evidence becomes `unknown`. Derived `costUsd` is an exact decimal string only when every request is expressible in USD and is `null` otherwise. This is operational request accounting, not invoice reconciliation. Output and reasoning are quantities the model cannot FOLD, so they never alter the model-facing Budget ledger.
2507
- - §tokenomics-negative-pressure **Negative curation pressure is honest and nonterminal.** The readout describes the packet the model actually receives: weight and percent may exceed the curation budget, and free weight equals `budget - weight` without flooring. Crossing the budget records {§grinder-overflow-problem}, then the grinder (grinder}) folds only the newest boundary. Remaining curation debt never decides physical admission, creates a strike, or establishes a one-turn quota.
3076
+ - §tokenomics-provider-usage **Provider accounting is physical-request evidence, not curation state.** Every issued physical request has one durable pre-I/O `provider_requests` identity and settles once as response or error. Each record preserves conventional {§provider-usage} quantities and required {§provider-cost} evidence; an unreported quantity remains absent, including on response-less failures, and is never replaced by zero. `model_calls` own logical response/failure evidence, `turn_attempts` specialize emission admission, and `provider_requests` are the sole durable accounting representation. Emissions, BARE calls, rejected responses, retries, failovers, and errors therefore remain cardinal and ordered. Turn, loop, worker, workspace, digest, and protocol accounting are derived from those records through the shared {§provider-accounting} projection; only emission calls contribute the latest-packet context gauge. The baseline stores no floating-point money, denormalized totals, or rollup triggers. A documented direct charge becomes `charged`; otherwise the provider may compute an exact-decimal USD `estimated` amount from complete usage and the exact model's Models.dev rates; insufficient evidence becomes `unknown`. Derived `costUsd` sums every USD-expressible request and is `null` only when no request is expressible; a response-less failure or an uncataloged model is skipped, never allowed to erase the expressible evidence. The derived aggregate usage sums every reported quantity the same way. This is operational request accounting, not invoice reconciliation. Output and reasoning are quantities the model cannot FOLD, so they never alter the model-facing Budget ledger.
3077
+ - §tokenomics-negative-pressure **Negative curation pressure is honest but never submitted.** The provisional readout may report `tokensActiveTotal` and its percentage above `tokensActiveMax`. Crossing the maximum diverts that would-be model turn intooverflow-turn}; no over-ceiling packet reaches `provider.generate`. Automatic recovery does not create a strike or consume a model-turn allowance.
2508
3078
 
2509
3079
  ### §membership Workspace identity, membership, disk co-location
2510
3080
 
@@ -2537,7 +3107,7 @@ flowchart LR
2537
3107
  | Internal entries | Workspace or worker entries are canonical store state. Writing one never implies a project-file write. |
2538
3108
  | Authority | Service flags set the membership ceiling; workspace constraints narrow it; client or loop auto resolves proposals. `origin` is attribution. |
2539
3109
 
2540
- §web-search-retrieval **Web search and retrieval are one first-class composition.** A search runtime enumerates a configured maximum of candidate URLs and hands each to the engine as a `content: null` `entry()` request ({§exec-entry-sink}): the guarded `WebFetcher` sink fetches candidates in parallel, off the write-serialization chain, and materializes successful bodies as ordinary HTTP entries. SearXNG owns membership and rank; Plurnk does not rerank or classify sources. Every candidate whose `entry()` call rejects, regardless of failure reason, is mechanically omitted from the model-facing result directory; survivors retain upstream order. The compact directory carries `title/url/snippet/publishedDate/materialized`; it locates readable resources and is not a substitute for their contents. Without an entry sink the executor cannot test materialization and omits the verdict.
3110
+ §web-search-retrieval **Web discovery is an ordinary MCP concern; retrieval is a first-class composition.** PLURNK owns no search runtime: a search-capable MCP server (e.g. Brave Search) participates through the ordinary MCP contract — admission, read-effect classification, tool documentation, and packet projection are identical to every other MCP tool ({§mcp-tool-presentation}). An executor that wants to materialize discovered pages uses the generic `content: null` `entry()` request ({§exec-entry-sink}): the guarded `WebFetcher` sink fetches candidates in parallel, off the write-serialization chain, and materializes successful bodies as ordinary HTTP entries. Every candidate whose `entry()` call rejects, regardless of failure reason, is mechanically omitted from the model-facing result directory; survivors retain upstream order. Without an entry sink the executor cannot test materialization and omits the verdict.
2541
3111
 
2542
3112
  Search prefetch and direct HTTP READ materialize the same resource contract:
2543
3113
  protocol + canonical authority (including a non-default port) + path + serialized
@@ -2547,13 +3117,10 @@ media type, and projection identity remain explicit auxiliary evidence. A
2547
3117
  normal
2548
3118
  `## READ0 (https://host/path?query)` therefore publishes only the sanitized body
2549
3119
  under that exact URL—never raw HTML, response headers, or a channel-selection
2550
- lesson. FIND and embeddings consume the same stored readable
2551
- projection and never re-fetch each match. Because the search family is in
2552
- `PLURNK_SERVICE_EXEC_HOLD`, the cycle holds until acquisition concludes
2553
- ({§exec-hold-until-concluded}), so the next packet contains final
2554
- materialization verdicts and folded ambient rows for every acquired page.
3120
+ lesson. FIND and embeddings consume the addressed stored channel representation
3121
+ and never re-fetch a match.
2555
3122
 
2556
- §search-gate Coverage protects the composition at distinct seams: HTTP unit tests pin fragmentless-body publication and explicit auxiliary selection; integration tests pin search→materialize→FIND and persistence/publication separation. Model web demos run the live composition end to end — real SearXNG, real pages; stubbed acquisition is confined to unit and integration seams and never appears in a demo. A live positive-control demo requires a materialized HTTPS body and a substantive answer from a real sanitized page. Live discovery demos remain diagnostic and may expose model judgment failures without weakening these assertions. **The search gates** are rail-family accounting — in-memory per-loop state cleaned at the same seam as strikes, restart-drop accepted (a post-restart duplicate re-fetches; the TTL makes it cheap): an IDENTICAL duplicate (same runtime + query in one loop) **strikes and serves** — status 409 (the strike rail counts the turn failure) carrying the prior ranked digest re-read live from the original exec entry, no re-fetch, no provenance prose; the per-turn CAP (`PLURNK_SERVICE_SEARCH_MAX_PER_TURN`) is flood control — 429 with a legible steer, nothing served.
3123
+ §web-retrieval-live Coverage protects the composition at distinct seams: HTTP unit tests pin fragmentless-body publication and explicit auxiliary selection; integration tests pin materialize→FIND and persistence/publication separation. A live positive-control demo requires a materialized HTTPS body and a substantive answer from a real sanitized page; live discovery demos remain diagnostic and may expose model judgment failures without weakening these assertions.
2557
3124
 
2558
3125
  **Git is the substrate and the repository is the boundary:**
2559
3126
 
@@ -2564,27 +3131,22 @@ materialization verdicts and folded ambient rows for every acquired page.
2564
3131
  or nested independent repository is not discovered or managed by this
2565
3132
  workspace. When Git is absent there is no filesystem walk; `pick` is then the
2566
3133
  sole source.
2567
- - §git-native-default **Core Git reads use native Git by default.** Membership
2568
- and status execute the installed Git binary.
3134
+ - §git-native-default **Core Git reads use native Git.** Membership and status
3135
+ execute the installed Git binary. An absent or failed binary yields no
3136
+ automatic Git membership or status; core has no alternate implementation or
3137
+ fallback. An independently installed `isogit` executor remains an explicit,
3138
+ model-invoked subset for shellless deployments, not an ambient Git backend.
2569
3139
  - §membership-git-hermetic Native Git runs with ambient `GIT_*` and
2570
3140
  global/system config scrubbed, so repository identity follows `project_root`,
2571
3141
  never the daemon's launch environment.
2572
- - §git-isomorphic-opt-in `PLURNK_SERVICE_GIT_ISO=1` explicitly selects the
2573
- in-process isomorphic-git backend for a deployment that cannot spawn Git. The
2574
- alternative is never an automatic fallback: an absent native binary yields
2575
- no automatic Git membership or status, never an isomorphic retry; an
2576
- incompatible isomorphic repository surfaces its preserved upstream cause
2577
- and directs the operator back to the default. The isomorphic untracked scan
2578
- remains differential-gated against native
2579
- `ls-files --others --exclude-standard`.
2580
- - §membership-edit-membership-gate **Membership-gated edits.** EDIT is bounded by membership exactly as READ is. An existing **member**'s baseline is its entry snapshot — the body channel the model READ, not a fresh disk read — so the diff is naive against the view the model saw, never empty (the write-side CAS, {§membership-edit-write-cas}, prevents the silent overwrite of out-of-band drift). An existing **non-member** is refused (403) *before* any read or write: the model never reads a file it can't see (no leak into the proposal) and never overwrites one (no wiping a gitignored `.env` it never added). A **new path** stays open — proposal→accept adds it to the manifest. Reaching past membership is `## EXEC0 [sh]`'s job, not the file scheme's.
3142
+ - §membership-edit-membership-gate **Membership-gated edits.** EDIT is bounded by membership exactly as READ is. An existing **member**'s baseline is its entry snapshot — the body channel the model READ, not a fresh disk read — so the diff is naive against the view the model saw, never empty (the write-side CAS, {§membership-edit-write-cas}, prevents the silent overwrite of out-of-band drift). An existing **non-member** is refused (403) *before* any read or write: the model never reads a file it can't see (no leak into the proposal) and never overwrites one (no wiping a gitignored `.env` it never added). A **new path** crosses the creation matrix in {§fs-write-surface}; proposal acceptance cannot bypass its scope, exclusion, or incorporation rules. Reaching past membership is `## EXEC0 [sh]`'s job, not the file scheme's.
2581
3143
  - §membership-create-parents **Parent-complete creation.** An accepted File creation—whether authored as EDIT or as a COPY/MOVE destination—recursively creates missing parent directories before writing and registering the new member.
2582
3144
 
2583
3145
  **The overlay — `pick | view | hide`, removed by `drop`.** A `workspace_constraints` table is the client's supersede over Git. Resolved membership is `(project repository files ∪ pick) − hide`, with `view` enforced at the edit gate.
2584
3146
 
2585
- - §membership-auto-add **Auto-add** — the project repository's membership is its tracked `ls-files` plus untracked-but-not-ignored files (`git ls-files --others --exclude-standard`), with `git` origin. A model-created file is a member the moment it exists—no `git add`—while `.gitignore` still filters it.
2586
- - §membership-overlay-pick **`pick`** — admit an untracked file git misses: a targeted client-dictated `node:fs` glob scan over untracked matches (files only), 'constraint' origin, reconciled like git members. Enumerated, so the manifest stays exhaustive. git-absent, `pick` is the *sole* membership source.
2587
- - §membership-overlay-hide **`hide`** — exclude a tracked file: resolution drops matches (`node:path.matchesGlob`) and reconciles so the entry set *equals* the member set. The lever to exclude a committed-but-sensitive tracked file; `entries.membership_origin` keeps reconciliation off model-created members.
3147
+ - §membership-auto-add **Auto-add** — the project repository's ambient membership is its tracked `ls-files` plus untracked-but-not-ignored files (`git ls-files --others --exclude-standard`), with `git` origin. An accepted creation selected for Git incorporation is explicitly staged; failure falls back to an exact generated pick, never an orphan ({§file-create-no-orphans}).
3148
+ - §membership-overlay-pick **`pick`** — admit a file Git misses through a targeted constraint scan (files only), with `constraint` origin. `source: "explicit"` records operator/client policy; `source: "create"` is the exact durable record of an accepted creation. Only explicit picks override active Git ignore. In a Git-absent root, picks are the sole file-membership source.
3149
+ - §membership-overlay-hide **`hide`** — exclude a tracked or picked file: resolution drops matches (`node:path.matchesGlob`) and reconciles so the entry set *equals* the member set. The lever to exclude a committed-but-sensitive tracked file; exclusions mask generated creation picks without deleting their provenance ({§fs-create-masked}).
2588
3150
  - §membership-overlay-view **`view`** — keep a member readable but refuse `File.edit`, 403'd at the membership check before any diff. (Admitting an untracked file as `view` rides on `pick`'s scan.)
2589
3151
  - §membership-resolved-effects **Resolved effect is a read, not a re-derivation.** `workspace.members` surfaces each candidate's resolved effect — `(ls-files ∪ pick) − hide` tagged `member` / `view`, plus the `hide`-excluded `hidden` set — so a client signs file visibility (member / read-only / ignored) without reimplementing the overlay glob-matching. The daemon owns git + the globs; the per-file effect is its to resolve, the client's to render.
2590
3152
 
@@ -2601,13 +3163,14 @@ identity, and terminal disposition without exposing raw bytes or a base64 lane.
2601
3163
  | Binary with readable projection | Derived Unicode as `text/markdown` | READ uses the projection; source-aware EDIT remains 415. |
2602
3164
  | Binary without projection/over cap | Empty marker under the source binary mimetype | READ and EDIT return 415; private metadata distinguishes unavailable from limit. |
2603
3165
 
2604
- §derivation-dedup-parallel **The index dedups then parallelizes.** The derivation identity hashes the exact READ body, mimetype, reader behavior, embedding configuration, and applicable search exclusion. A resource attaches the immutable artifact only after it is complete; identical entry and log bodies therefore share one FTS row, one symbol graph, and one vector set without copying. Distinct artifacts run with bounded producer concurrency (`PLURNK_SERVICE_DERIVE_CONCURRENCY`). Pending artifacts sort by readable content length before entering that pool, so small resources start first while every outlier still derives fully. Unset uses a host-relative square-root fan-out; a positive integer is an exact operator budget and `-1` claims every core. Token-count and embedding batches retain only a pool-sized promise window; graph persistence writes at most `PLURNK_SERVICE_DERIVE_STORE_BATCH` definitions or references per SQLite statement. Every resource completed by a successful pass attaches a terminal classified artifact, identically at concurrency 1 and N. Multi-item warming reports aggregate milestones and heartbeat notices according to `PLURNK_SERVICE_DERIVE_PROGRESS_STEPS` and `PLURNK_SERVICE_DERIVE_PROGRESS_HEARTBEAT_MS`.
3166
+ §derivation-dedup-parallel **The index dedups then parallelizes.** The derivation identity hashes the exact READ channel representation, mimetype, reader behavior, embedding configuration, and applicable search exclusion. A channel or log projection attaches the immutable artifact only after it is complete; identical projections therefore share one FTS row, one symbol graph, and one vector set without copying. Distinct artifacts run with bounded producer concurrency (`PLURNK_SERVICE_DERIVE_CONCURRENCY`). Pending artifacts sort by readable content length before entering that pool, so small resources start first while every outlier still derives fully. Unset uses a host-relative square-root fan-out; a positive integer is an exact operator budget and `-1` claims every core. Token-count and embedding batches retain only a pool-sized promise window; graph persistence writes at most `PLURNK_SERVICE_DERIVE_STORE_BATCH` definitions or references per SQLite statement. Every representation completed by a successful pass attaches a terminal classified artifact, identically at concurrency 1 and N. Multi-item warming reports aggregate milestones and heartbeat notices according to `PLURNK_SERVICE_DERIVE_PROGRESS_STEPS` and `PLURNK_SERVICE_DERIVE_PROGRESS_HEARTBEAT_MS`.
2605
3167
 
2606
- The artifact also retains a positive `{§mimetype-parse-issues}` count when the
2607
- exact parsed body reported one. It remains advisory alongside a normally
2608
- completed semantic disposition; zero and unavailable evidence persist as
2609
- absence. Catalog projection attaches it only to that parsed body channel, never
2610
- to sibling channels whose content the artifact does not describe.
3168
+ The artifact also retains a positive `{§mimetype-parse-issues}` count and the
3169
+ full normalized `{§mimetype-summary}` when the exact parsed channel reported
3170
+ either. Both remain advisory alongside a normally completed semantic
3171
+ disposition; zero, empty, and unavailable evidence persist as absence. Catalog
3172
+ projection attaches either only to that channel, never to a sibling whose
3173
+ content the artifact does not describe.
2611
3174
 
2612
3175
  Every completed artifact records one terminal disposition: `vector`, `lexical`
2613
3176
  (only no embedder or an operator size ceiling), `excluded` (the configured
@@ -2621,21 +3184,21 @@ every non-vector attachment with its disposition and reason. Successful
2621
3184
  optional projection degradations continue indexing and surface their framework
2622
3185
  Notice once per identical observation in a maintenance pass.
2623
3186
 
2624
- §semantic-embed-dedup **Identical content embeds once.** The metaproject's repeated `tokenizer.json` bodies - and any log result exposing the same exact READ body - attach one content-addressed derivation artifact. Graph, FTS, and chunk vectors exist once; addresses join through the artifact hash. One pass-wide semantic plan binds the selected chunk counter to this identity: the embedder's own counter is covered by model-space identity, while a separately resolved fallback counter contributes its `tokenizerId` and exactness. Model, vocabulary, vector-wire encoding ({§mimetype-embedding-wire}), or configuration changes therefore produce a different identity, so incompatible vector spaces, encodings, or chunk boundaries never share.
3187
+ §semantic-embed-dedup **Identical content embeds once.** The metaproject's repeated `tokenizer.json` channels - and any log result exposing the same exact readable text - attach one content-addressed derivation artifact. Graph, FTS, and chunk vectors exist once; addresses join through the artifact hash. One pass-wide semantic plan binds the selected chunk counter to this identity: the embedder's own counter is covered by model-space identity, while a separately resolved fallback counter contributes its `tokenizerId` and exactness. Model, vocabulary, vector-wire encoding ({§mimetype-embedding-wire}), or configuration changes therefore produce a different identity, so incompatible vector spaces, encodings, or chunk boundaries never share.
2625
3188
 
2626
3189
  Lossless chunk admission requires either the embedder's own counter or an exact fallback tokenizer. An empirical estimate never proves that content fits the declared token window. When pending readable content would require vectors and only an estimate is available, maintenance surfaces its degradation Notice and fails before embedding or attaching a derivation; no/disabled embedding and the established empty, binary, excluded, and maximum-size dispositions remain non-vector outcomes.
2627
3190
 
2628
- §semantic-max-embed-size **Embedding has an optional size posture.** `PLURNK_SERVICE_MAX_EMBED_SIZE` is an operator-set maximum UTF-8 byte size eligible for vectors; `0` is unlimited and is the shipped default. The measured value is the exact default body READ exposes and the embedder receives. Exhaustive embedding therefore remains the normal posture. When a nonzero ceiling rejects an oversized body, the entry remains directly readable with full graph and lexical indexing; only vectors are absent. The setting is folded into the deep derivation signature, so changing it honestly re-derives affected entries. Client notices report compact aggregate progress; the digest records every non-vector pathname, terminal disposition, and reason for forensic inspection.
3191
+ §semantic-max-embed-size **Embedding has an optional size posture.** `PLURNK_SERVICE_MAX_EMBED_SIZE` is an operator-set maximum UTF-8 byte size eligible for vectors; `0` is unlimited and is the shipped default. The measured value is the exact addressed channel representation READ exposes and the embedder receives. Exhaustive embedding therefore remains the normal posture. When a nonzero ceiling rejects an oversized representation, its channel remains directly readable with full graph and lexical indexing; only vectors are absent. The setting is folded into the deep derivation signature, so changing it honestly re-derives affected channels. Client notices report compact aggregate progress; the digest records every non-vector address, terminal disposition, and reason for forensic inspection.
2629
3192
 
2630
3193
  §membership-change-gated-sync **Sync is idempotent and change-gated.** Per turn, membership materializes every member's model-readable snapshot into its entry. Text with an unchanged disk signature is a stat-only no-op. The version token is either the observed `mtime:size` or the explicit `absent` state; an observed deletion removes the stale readable channels, and a later reappearance is therefore a new divergence rather than a first-sight materialization. Binary sources additionally compare the cached per-mimetype projection identity; unchanged bytes are never reacquired, while changed reader behavior rematerializes without fabricating a filesystem-divergence event. Coverage is exhaustive across the project repository while work is proportional to source or projection change. After a pass every member carries the current representation defined by {§membership-source-projection}.
2631
3194
 
2632
- §membership-emi-divergence-signal **EMI divergence signal.** The detector that gates the work *is* the one that fires this — one mechanism, not a second full read. When the change-detect finds a member moved out-of-band, the delta detector ({§env-delta}) surfaces it as a system `EDIT` log row naming the file, `source="file"` the model sees what changed without diffing the manifest against memory. The model's own edits are write-through (the entry equals disk after a File write), so the scan never mis-attributes them as external divergence.
3195
+ §membership-emi-divergence-signal **EMI divergence evidence.** The detector that gates the work *is* the one that records this — one mechanism, not a second full read. When change detection finds a member moved out-of-band, the runtime actor records an `EDIT`-shaped row naming the file with `source="file"`; it does not broadcast that workspace change into unrelated workers' logs ({§env-delta-filesystem-narration}). The model's own edits are write-through (the entry equals disk after a File write), so the scan never mis-attributes them as external divergence. The current file remains ordinarily addressable. A stale anchored edit rejects under {§line-anchors}; a disk race after proposal rejects under {§membership-edit-write-cas}.
2633
3196
 
2634
- §membership-edit-write-cas **The write-back is a compare-and-swap — never a clobber, never a clever merge.** EDIT is *naive against the editable text snapshot*: it diffs the model's change onto the entry's body channel — the exact Unicode the model READ — and the proposal carries the `synced_sig` that snapshot was taken at. Binary sources are refused before this path ({§membership-source-projection}). At accept, `applyResolution` re-stats disk and lands the proposed content only if that signature still matches. If disk moved out-of-band in the propose→accept window — a sibling worker, the user's editor, a build step — the write is **refused** with the same neutral `edit-collision` as {§edit-collision}, and **nothing is written**. The engine neither blind-writes over the ambient change (a *clobber*) nor silently re-diffs the model's edit against a state it never saw (getting *clever*) — both would bury a stale-view contract violation under a fallback. The collision surfaces instead: a ≥400 apply downgrades to a reject ({§proposal}), so the model sees that EDIT **did not occur** (400; the `edit_collision` outcome is forensics-only), the next reconcile narrates the real disk content as a `source=file` divergence ({§membership-emi-divergence-signal}), and the model re-reads and re-proposes against the fresh snapshot.
3197
+ §membership-edit-write-cas **The write-back is a compare-and-swap — never a clobber, never a clever merge.** EDIT is *naive against the editable text snapshot*: it diffs the model's change onto the entry's body channel — the exact Unicode the model READ — and the proposal carries the `synced_sig` that snapshot was taken at. Binary sources are refused before this path ({§membership-source-projection}). At accept, `applyResolution` re-stats disk and lands the proposed content only if that signature still matches. If disk moved out-of-band in the propose→accept window — a sibling worker, the user's editor, a build step — the write is **refused** with the same neutral `edit-collision` as {§edit-collision}, and **nothing is written**. The engine neither blind-writes over the ambient change (a *clobber*) nor silently re-diffs the model's edit against a state it never saw (getting *clever*) — both would bury a stale-view contract violation under a fallback. The collision surfaces instead: a ≥400 apply downgrades to a reject ({§proposal}), so the model sees that EDIT **did not occur** (400; the `edit_collision` outcome is forensics-only). Reconciliation aligns the current file projection and records the `source=file` evidence in the runtime log ({§membership-emi-divergence-signal}); the model re-reads and re-proposes against the fresh snapshot.
2635
3198
 
2636
3199
  The version travels *with the proposal*, never re-read from the entry at accept: a sibling worker in the same workspace may reconcile while this proposal sits paused, advancing the entry's `synced_sig` to the drifted disk — comparing against the *current* entry sig would wave that clobber through, so the comparison is always against the sig the proposal was computed at. A proposal that assumed an **absent** path (a create) conflicts only if a file has since appeared; a member with **no recorded snapshot** (an un-materialized entry, null `synced_sig`) has no baseline to guard and writes through — the two are told apart by the proposal's `existed` flag, not by a null sig alone. On a clean landing the entry refreshes to the written content and `synced_sig` is **restamped** to it, so the next reconcile recognizes the model's own write (not an external divergence) and a second same-turn edit bases on the landed bytes, not a stale sig. This is the write-side twin of the read-side change-gate ({§membership-change-gated-sync}): one `synced_sig`, gating both the re-read and the write.
2637
3200
 
2638
- The CAS is the **hard backstop**, at the moment of writing, on every accept path. It composes with — and is distinct from — the loop-auto `staleClobberRisk` guard (proposal-ownership-auto-stale-clobber}): that guard refuses to resolve an edit whose target already diverged earlier this turn (the read→propose window, auto path only); the CAS refuses to write against a snapshot disk has left (the propose→write window, every path). Together they bracket the full read→write span.
3201
+ The CAS is the **hard backstop**, at the moment of writing, on every accept path. It composes with the model-facingline-anchors}: an anchor rejects a target whose relevant neighborhood changed before dispatch, while the CAS refuses to write against a snapshot disk left after proposal. An unanchored edit deliberately claims no pre-dispatch stale-view guarantee.
2639
3202
 
2640
3203
  §membership-git-flags **Permission flags.** Service-wide Git admission comes from {§operator-config-git-ceiling}. `PLURNK_SERVICE_GIT_AUTO=1` (default) includes the repository containing `project_root`; `=0` disables automatic Git membership, leaving `pick` as the only membership source. `ALLOWED` gates `AUTO`.
2641
3204
 
@@ -2647,130 +3210,131 @@ beneath each call. Its constraints distinguish pending calls, response
2647
3210
  evidence, and response-less errors while monetary classification remains
2648
3211
  explicit.
2649
3212
 
2650
- ### §grinder Budget enforcement: the grinder
3213
+ ### §overflow-turn Budget enforcement: automated recovery turns
2651
3214
 
2652
- The grinder is the one pre-provider curation path for the model-facing gauge.
2653
- It never decides physical admission. Every request then crosses the provider's
2654
- request-shaped capacity boundary, where proven exact overflow may reject
2655
- pre-I/O and ambiguous evidence defers to upstream:
3215
+ Budget recovery is an ordinary state-machine transition, not a private packet
3216
+ mutation. Every candidate model request first crosses the model-facing curation
3217
+ ceiling and then, only if admitted, the provider's request-shaped physical
3218
+ capacity boundary:
2656
3219
 
2657
3220
  ```mermaid
2658
3221
  flowchart TD
2659
- assemble["Assemble and measure<br/>request packet"] --> policy{"Packet weight ≤<br/>curation budget?"}
2660
- policy -->|yes| generate["Provider generate"]
2661
- policy -->|no| problem["Record nonterminal 413<br/>Token Budget Overflow"]
2662
- problem --> fold["FOLD newest boundary<br/>and its OPEN effects<br/>tag overflow"]
2663
- fold --> rebuild["Rebuild and remeasure"]
2664
- rebuild --> generate
2665
- generate --> capacity{"Provider capacity<br/>failure?"}
3222
+ assemble["Assemble and measure<br/>candidate request"] --> budget{"Weight curation ceiling?"}
3223
+ budget -->|yes| generate["Provider generate"]
3224
+ budget -->|no| recover["Keep turn packetless<br/>reclassify as `_plurnk` overflow"]
3225
+ recover --> fold["Dispatch PLAN, whole-body FOLD ops,<br/>and SEND through ordinary dispatch"]
3226
+ fold --> verify{"Rebuilt request fits?"}
3227
+ verify -->|yes| next["Next model turn"]
3228
+ verify -->|no| stop["Terminal 413"]
3229
+ next --> assemble
3230
+ generate --> capacity{"Provider capacity failure?"}
2666
3231
  capacity -->|no| response["Classify completed response"]
2667
3232
  capacity -->|yes| prompt{"Withholding automatic<br/>prompt bodies changes request?"}
2668
- prompt -->|yes| retryPrompt["Persist failure;<br/>rebuild and retry"]
2669
- retryPrompt --> generate
2670
- prompt -->|no| boundary{"Newest boundary not yet<br/>rolled back, and rollback<br/>changes request?"}
2671
- boundary -->|yes| retryBoundary["Persist failure;<br/>roll back, rebuild, retry"]
2672
- retryBoundary --> generate
2673
- boundary -->|no| stop["Persist terminal 413"]
3233
+ prompt -->|yes| retry["Persist failure;<br/>rebuild and retry"]
3234
+ retry --> generate
3235
+ prompt -->|no| stop
2674
3236
  ```
2675
3237
 
2676
- §grinder-overflow-only **The grinder fires only on actual overflow.** In
2677
- `Engine.runTurn`, after `PacketBuilder.buildRequestPacket` assembles the request
2678
- and before `provider.generate`, it compares the packet's render-weight
2679
- ({§tokenomics}) with the provider-derived curation budget. At or under the budget, the packet
2680
- ships untouched. The grinder never trims
2681
- speculatively or "helpfully."
2682
-
2683
- - §grinder-overflow-problem **Token Budget Overflow is a nonterminal 413 Problem.** Every over-ceiling assembly records exactly one `engine/context/token-budget-overflow` Problem before automatic recovery, with pre-recovery `usage`, `ceiling`, and `deficit` evidence. Its exact `detail` is `Token Budget Overflow: Token Usage exceeded Token Ceiling. Newest log items were automatically FOLDed to fit within token budget. Curate the log and/or perform more conservatively scoped or chunked retrieval operations to recover.` The Problem remains durable and model-visible even when folding restores room and the turn later concludes successfully; it does not strike or replace the turn's terminal disposition.
2684
- - §grinder-layer1-rollback **One rule, every turn: roll back context introduced by the newest boundary.** On overflow the grinder folds, in one set operation, still-open rows born in the immediately prior turn or current pre-model turn plus exact older rows that a successful OPEN in the immediately prior turn transitioned from folded to open. It reads those landed effects from {§fold-open-meta-operations}; it never re-runs the selector, treats an already-open target as newly introduced, or chooses other older history by relevance. Turn 1 has no prior turn, so only its pre-model rows qualify. The same set operation additively applies the `overflow` tag to every row it folds; rows and bodies remain re-OPENable.
2685
- - §grinder-errors-exempt **Errors, the prompt, AND the plan are exempt.** The grinder never folds an `op='error'` row: errors are the model's durable, curatable record of what went wrong. Nor does it fold the actionless **user prompt** row (`prompt:///<loop>/<N>`): the task frame is not ordinary model-authored memory. Nor a **PLAN row**: the checklist is the model's orientation surface when the grinder fires. All three stay OPEN until the model itself FOLDs or KILLs them.
2686
- - §grinder-hard-413 **Only a provider capacity failure can terminalize at 413.** Every `provider.generate` assesses its exact request under {§provider-surface-capacity}. A proven exact preflight overflow issues no physical request; estimate, unavailable evidence, and a non-fitting upper bound defer to upstream, whose context rejection normalizes to the same `capacity_exceeded` failure. Core retries only after changing the request: first by withholding automatic prompt-body projection when that changes the packet, then by rolling back the newest boundary once when the grinder has not already done so and that changes the packet. Each failed logical call, any issued physical request, capacity evidence, and model-visible provider Problem remain durable; these recovery calls do not consume the completed-emission attempt budget. Core never resends identical bytes as capacity recovery and never chooses arbitrary older history. If neither recovery changes the request, or the changed request is still rejected, the request-only turn and exact provider Problem terminalize the loop at **413 Content Too Large**.
2687
-
2688
- - §tokenomics-fetch-fits-free **A retrieval larger than the available packet room arrives folded with a 413 explanation.** The result lands in the next build; if that build exceeds the curation budget, Core records {§grinder-overflow-problem} and folds the newest boundary, which contains the result. Its row and exact body remain durable and re-OPENable, and its `overflow` tag identifies every row selected by the automatic fold. Remaining curation debt follows {§tokenomics-negative-pressure}.
2689
-
2690
- - §loop-terminals **Engine-imposed terminals are HTTP-precise** — the loop-status vocabulary, one meaning each: `200` concluded (the model's SEND signal `200`) · `499` model-abandoned (signal `499`, or a cancel) · `429` maxTurns exhausted · `413` provider input-capacity failure after changed-request recovery · `500` strike threshold or invalid-emission exhaustion (distinct Problem types; `508` when the crossing strike was a detected cycle) · `504` loop timeout / exec-timeout restamp · `202` the bounded wait — a loop blocked on a live obligation (the model's `## SEND0 [202] <T,P>`, {§wait-obligation-matrix}); a wait on nothing resolves to `200` unless a successful same-turn FOLD requires the curated next packet · `100`/`102` queued/running. Never a catch-all, never a new value without changing the owning schema.
2691
-
2692
- §grinder-pressure-surface **What the model sees.** A fold-to-fit packet carries the open {§grinder-overflow-problem} row, its terse `## Errors` pointer, and ordinary folded rows whose complete sorted `tags` include `overflow`. If curation pressure remains negative but the provider accepts the request, the Budget section also reports the negative free-weight value and its one panic line ({§tokenomics-neutral-telemetry}). The curation 413 diagnoses the overflow without striking, terminalizing the turn, or changing the ordinary operation contract.
2693
-
2694
- The model controls its context; the provider owns physical admission, and Core
2695
- performs only bounded changed-request recovery without choosing what older
2696
- history matters. The same boundary applies on turn 1 and turn 101. The grinder
2697
- folds reversibly, never deletes, and never performs speculative or non-overflow
2698
- trimming.
3238
+ §overflow-turn-only **Recovery occurs only after measured overflow and before
3239
+ provider I/O.** After packet assembly, Core compares render weight
3240
+ ({§tokenomics}) with the provider-derived curation ceiling. An admitted packet
3241
+ ships untouched. An over-ceiling candidate is never stored as a model request
3242
+ and never reaches `provider.generate`; its already-created database turn instead
3243
+ becomes a packetless `_plurnk` turn. Packetless initialization and recovery turns
3244
+ remain ordinary turn chronology but do not consume `maxTurns`, model-call,
3245
+ emission-attempt, usage, or cost accounting.
3246
+
3247
+ - §overflow-turn-script **Recovery is one ordinary admitted `_plurnk` program.** Its canonical {§plan-value} has one `medium`, `in_progress` entry whose content is `Automatically FOLD log bodies newly active at token-budget overflow.`, followed by every causal whole-body FOLD and terminal `SEND0 [102]` with body `Next: YOU MUST ONLY FOLD, KILL, or trim ALL superseded, stale, or irrelevant log content in bulk in the next turn.` The final sentence requires the successor's substantive operations to be one dedicated, comprehensive bulk-curation program; mandatory PLAN and SEND framing still applies. Its exact `turnOps` is born FOLDED; successful FOLD rows follow {§fold-open-meta-operations} and therefore remain durable but packet-suppressed. Every recovery row carries `_plurnk` and `overflow`; no model call, synthetic receipt, or parallel explanation exists.
3248
+ - §overflow-turn-curation **The preceding turn owns the pressure it introduced.** Core deterministically selects every body already created in the packetless candidate turn, every body created by the immediately preceding completed turn in that worker's chronology, and every older body whose visibility that preceding turn's successful OPEN increased. Every selected body is FOLDed whole (`<1,-1>`) through ordinary dispatch. Already-wholly-folded and bodyless rows require no operation. Core performs no relevance judgment, exempts no operation or resource kind, reconstructs no interval delta, re-runs no authored selector, and chooses no unrelated older history.
3249
+ - §overflow-turn-hard-413 **Recovery fails hard when the causal fold cannot fit.** After the ordinary FOLDs land, Core rebuilds and remeasures once. If the plan changes no visibility or the rebuilt request still exceeds the ceiling, the loop terminalizes with an exact `engine/context/token-budget-overflow` 413 Problem; Core neither submits excess bytes nor chooses unrelated older history. Separately, every `provider.generate` assesses physical capacity under {§provider-surface-capacity}. Core may retry a provider capacity rejection only after withholding automatic prompt-body projection when that changes the request. If it cannot produce changed bytes or the changed request is still rejected, the request-only model turn and provider-owned Problem terminalize at **413 Content Too Large**.
3250
+
3251
+ - §tokenomics-fetch-fits-free **A retrieval larger than the available packet room remains addressable.** Its complete row lands in the model turn that requested it. If the following candidate packet exceeds the curation ceiling, {§overflow-turn-curation} FOLDs the new body and classifies it `_plurnk` and `overflow`; the exact body remains durable and selectively re-OPENable.
3252
+
3253
+ - §loop-terminals **Engine-imposed terminals are HTTP-precise** — the loop-status vocabulary, one meaning each: `200` concluded (the model's SEND signal `200`) · `499` model-abandoned (signal `499`, or a cancel) · `429` maxTurns exhausted · `413` token-ceiling recovery failure or provider input-capacity failure after changed-request recovery · `500` strike threshold or invalid-emission exhaustion (distinct Problem types; `508` when the crossing strike was a detected cycle) · `504` loop timeout / exec-timeout restamp · `202` the bounded wait — a loop blocked on a live obligation (the model's `## SEND0 [202] <T,P>`, {§wait-obligation-matrix}); a wait on nothing resolves to `200` unless a successful same-turn FOLD requires the curated next packet · `100`/`102` queued/running. Never a catch-all, never a new value without changing the owning schema.
3254
+
3255
+ §overflow-turn-surface **The packet is the resulting state, not an account of it.**
3256
+ The first request after recovery is assembled by the ordinary packet path from
3257
+ the actual durable log after the recovery turn. It therefore carries the prior
3258
+ causal rows genuinely FOLDED, the recovery PLAN and SEND genuinely OPEN, and
3259
+ the recovery `turnOps` genuinely FOLDED. Successful recovery FOLD receipts are
3260
+ absent under the universal curation rule. No notice, reconstruction, auto-open,
3261
+ or overflow-specific projection simulates what `_plurnk` did; OPENing the exact
3262
+ `turnOps` reveals the program that did it. The model retains complete authority
3263
+ to reverse or refine that curation through ordinary log operations.
2699
3264
 
2700
3265
  ### §env-delta The environment delta: what changed since the model last looked
2701
3266
 
2702
3267
  Catalog FIND results ({§packet-catalog}) state what existed when observed. The
2703
- environment delta supplies the events that made a worker's prior view stale
2704
- without copying the shared world into worker-private state.
3268
+ environment delta supplies structurally addressed activity without copying the
3269
+ workspace into every worker's private state.
2705
3270
 
2706
3271
  ```mermaid
2707
3272
  flowchart LR
2708
- sibling["Sibling resolves EDIT<br/>on shared entry"] --> events["Durable shared-event record"]
2709
- disk["Project file diverges<br/>from materialized snapshot"] --> kernel["Reserved plurnk worker<br/>records source=file EDIT"]
2710
- sink["Executor entry() sink<br/>materializes readable entry"] --> typed["Reserved plurnk worker<br/>records typed EDIT event"]
2711
- kernel --> events
2712
- typed --> events
2713
- events --> pull["Pre-turn lossless pull<br/>(cursor, captured high-water]"]
2714
- pull --> log["Observer's self-contained log<br/>origin=plurnk; born FOLDed"]
3273
+ child["Child commits activity"] --> event["One durable occurrence"]
3274
+ commons["Any worker mutates worker:///"] --> event
3275
+ event --> parent["Direct-parent audience"]
3276
+ event -->|"commons only"| global["Workspace audience"]
3277
+ parent --> pull["Pre-turn lossless pull<br/>(cursor, captured high-water]"]
3278
+ global --> pull
3279
+ pull --> log["Observer's self-contained log<br/>origin=_plurnk"]
2715
3280
  log --> packet["Packet lists coordinate;<br/>OPEN recalls exact body"]
2716
3281
  ```
2717
3282
 
2718
3283
  §env-delta-log-pull **Pull the event record, never a world snapshot.** At
2719
- pre-turn, a worker materializes every other actor's event on shared state after
2720
- its last completed observation boundary into its own log. The set is
2721
- exhaustive, unranked, and exactly once; the engine makes no relevance decision.
2722
- Each copied event retains its effect, cause, typed attributes, and initial
2723
- log classifications ({§log-item-tags}). Every
2724
- producer appends to one workspace-scoped occurrence journal with a monotonic
2725
- identity. A pull captures one closed `(worker cursor, high-water]` interval,
2726
- materializes each identity idempotently, then advances the cursor only after the
2727
- whole interval is durable. An event racing the capture is therefore in this
2728
- interval or a later one, never neither or both. Source-log curation cannot erase
2729
- the occurrence record.
2730
-
2731
- The cursor is observation progress, not a private copy of entry contents. A
2732
- fresh worker baselines the current high-water immediately after opening its
2733
- first turn: older state arrives through the ordinary current-world projections,
2734
- while events racing that first packet remain deliverable. A fork copies the
2735
- parent's captured cursor with its log; copied event identities cannot republish,
2736
- and occurrences the parent had not observed remain pending independently for
2737
- both workers.
2738
-
2739
- §env-delta-worker-entry-visibility **Worker-entry visibility follows the
2740
- authority contract.** Commons mutations (`worker:///...`) and mutations to the
2741
- published kernel surface (`worker://plurnk/...`) are shared-state events and
2742
- retain that authority in the observer row. Current-worker scratch
2743
- (`worker://~/...`) and every ordinary named worker space are private: they never
2744
- cross this door, while an ancestry-authorized explicit READ remains available.
2745
-
2746
- | Producer | Durable event | Observer projection |
2747
- | -------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
2748
- | §env-delta-sibling-edit Sibling commons mutation | The sibling's successful resolved `EDIT` row and its receipt. | One folded `EDIT` retaining the exact effect and typed attributes. |
2749
- | §env-delta-kernel-entry-edit Kernel-published mutation | The reserved `plurnk` worker's successful resolved `EDIT` row on `worker://plurnk/...`. | One folded `EDIT` retaining the published authority, exact effect, and typed attributes. |
2750
- | §env-delta-filesystem-narration Project-file divergence | The reserved `plurnk` worker records one `source=file` EDIT-shaped event during pre-turn membership reconciliation. | One folded `EDIT` naming the file and carrying the net changed span plus the exact two-coordinate Git porcelain status in `git` metadata when Git reports that path. No model operation is fabricated as having run. |
2751
- | §env-delta-entry-materialization Executor `entry()` sink | The reserved `plurnk` worker records a typed `EDIT` event with `kind="entry_materialized"` and the calling worker as cause. | One folded system `READ` projection advertising newly readable state; the durable event remains an EDIT for replay and forensics ({§exec-entry-sink}). |
3284
+ pre-turn, a worker materializes only occurrences whose structural audience
3285
+ includes that worker. The set is exhaustive, unranked, and exactly once; the
3286
+ engine makes no relevance decision. Each copied event retains the operation,
3287
+ result, typed attributes, and initial log classifications ({§log-item-tags}).
3288
+ Every producer appends to one workspace-scoped occurrence journal with a
3289
+ monotonic identity. A pull captures one closed `(worker cursor, high-water]`
3290
+ interval, materializes each addressed identity idempotently, then advances the
3291
+ cursor only after the whole interval is durable. An event racing the capture is
3292
+ therefore in this interval or a later one, never neither or both. Source-log
3293
+ curation cannot erase the occurrence record.
3294
+
3295
+ The cursor is observation progress, not a private copy of resource contents. A
3296
+ fresh worker captures the current high-water when its worker row is created, so
3297
+ pre-existing broadcast history stays out while later occurrences remain
3298
+ deliverable even before its first packet. A fork instead copies the parent's
3299
+ cursor and captures its own fork high-water atomically with worker creation
3300
+ ({§machine-processes-fork-pending-activity}). Observer rows retain the source
3301
+ identity and never publish another occurrence.
3302
+
3303
+ §env-delta-worker-entry-visibility **The commons is global; every other
3304
+ resource follows lineage.** A successful state-changing `EDIT`, `COPY`, `MOVE`,
3305
+ entry-path `KILL`, or entry-path `SEND` signal `410` whose landed effects touch `worker:///...` acquires the workspace
3306
+ audience and retains the commons address in its observer row. Mutations to
3307
+ `worker://~/...`, named worker spaces, project files, and remote resources do
3308
+ not broadcast. When authored by a child, their
3309
+ ordinary operation evidence still reaches that child's direct parent.
3310
+
3311
+ | Producer / event | Durable occurrence | Observer projection |
3312
+ | ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
3313
+ | §env-delta-child-activity Direct-child activity | Every final op-bearing child log row except runtime-private `_plurnk/operation` maintenance: prompt, PLAN, operation result, or actionless error. | Direct parent only; one exact attributed row born folded. Provider reasoning, calls, rejected emissions, turnOps, and harness maintenance do not cross. |
3314
+ | §env-delta-child-termination Direct-child termination | The child's exact terminal loop result when the loop contains at least one non-maintenance turn. | Direct parent only; a 2xx deliverable is born open and every failure is folded ({§worker-scheme-collect}). |
3315
+ | §env-delta-commons-mutation Commons mutation | One successful resolved operation whose landed effects touch `worker:///...`. | Every existing worker; one folded row per observer, deduplicated with any lineage audience. |
3316
+ | §env-delta-filesystem-narration Project-file divergence | Runtime-owned reconciliation evidence remains in the runtime actor's own log. | No ambient observer row. Current content remains addressable and stale hash edits reject at their owned boundary. |
3317
+ | §env-delta-entry-materialization Executor `entry()` sink | The runtime records typed materialization evidence under its owning actor. | No ambient observer row unless the resulting operation itself is direct-child activity or a commons mutation ({§exec-entry-sink}). |
2752
3318
 
2753
3319
  §env-delta-attribution **Ownership, authorship, and cause are independent.**
2754
3320
 
2755
3321
  | Field | Meaning |
2756
3322
  | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
2757
3323
  | `worker_id` | The worker whose self-contained log owns the materialized row. |
2758
- | `origin` | The actor tier that wrote the row; a materialized delta is `plurnk`. |
2759
- | `source` | The causal identity. Worker causes use the canonical `worker://<name>` control identity; non-worker causes use a stable subsystem token (currently `file`); self-authored rows omit it. |
3324
+ | `origin` | The actor tier that wrote the row; a materialized delta is `_plurnk`. |
3325
+ | `source` | The immediate causal identity in this log. A lineage or commons observation uses the canonical `worker://<producer>` control identity; self-authored rows omit it. |
2760
3326
 
2761
- §env-delta-no-coalescing **Only filesystem observation nets.** One filesystem
2762
- event is `editedSpan(entry-as-of-last-align, disk-now)`, inherently netting any
2763
- number of out-of-band writes before reconciliation. Sibling edits are discrete
2764
- events already in the log and remain discrete. Coalescing them would destroy
2765
- the record and conflate state comparison with event replay.
3327
+ §env-delta-no-coalescing **Activity is never coalesced.** Each admitted child
3328
+ operation and each commons mutation has one occurrence identity. Combining
3329
+ them would destroy causal order and conflate event replay with a state
3330
+ comparison.
2766
3331
 
2767
3332
  §env-delta-passive **Observation never forces a turn.** Deltas materialize only
2768
- while a packet is already assembling, so an ambient change cannot wake an idle
2769
- worker. Urgent directed communication uses the voice door
2770
- ({§actor-boundary-two-doors}). Sibling loop conclusions and owned stream
2771
- progress reuse durable ambient log delivery under {§worker-scheme-collect} and
2772
- exec-stream}; their lifecycle-specific open/fold and wake rules remain owned
2773
- there.
3333
+ while a packet is already assembling. Intermediate child activity and commons
3334
+ broadcasts therefore cannot wake an idle worker. Urgent directed communication
3335
+ uses the voice door ({§actor-boundary-two-doors}); direct-child terminal
3336
+ disposition alone carries the structured-concurrency wake owned by
3337
+ worker-scheme-collect}. Stream progress remains owned by {§exec-stream}.
2774
3338
 
2775
3339
  ### §edit-result-render Mutation log rows render truthful effects
2776
3340
 
@@ -2889,8 +3453,6 @@ only after authority crosses the client boundary.
2889
3453
 
2890
3454
  §proposal-ownership-notification **The notification carries disposition, not policy inputs.** `loop/proposal` carries the core-owned `ProposalDisposition` ({§notifications}, {§proposal-disposition}). A connected client presents only `owner="client"`; it never reimplements precedence from flags, operation, or attrs.
2891
3455
 
2892
- §proposal-ownership-auto-stale-clobber **Auto is not blind — it refuses a stale clobber.** When an EDIT's target diverged on disk this turn, accepting it would overwrite an ambient change. The projection carries `staleClobberRisk=true`, and core's loop disposition rejects it; the model can re-READ and retry. This brackets the read→propose window for loop auto, while the compare-and-swap ({§membership-edit-write-cas}) brackets propose→write for every accept path.
2893
-
2894
3456
  ---
2895
3457
 
2896
3458
  ## §packet Packet shape
@@ -2904,7 +3466,7 @@ leaves the request-only record, while rejected exchanges remain in
2904
3466
 
2905
3467
  | Turn state | `turns.packet` |
2906
3468
  | ----------------------------- | ----------------------------------------------- |
2907
- | No model request assembled | SQL `NULL` |
3469
+ | No model request assembled (including initialization and overflow turns) | SQL `NULL` |
2908
3470
  | Request assembled | `{ weight, sections }` |
2909
3471
  | Response admitted | `{ weight, sections, assistant, assistantRaw }` |
2910
3472
 
@@ -2921,9 +3483,27 @@ leaves the request-only record, while rejected exchanges remain in
2921
3483
  `StoredPacket` is the one core type and validation path for this algebra. The
2922
3484
  flat schema enforces its root states; typed reads additionally validate every
2923
3485
  section and parsed operation. A hard budget stop remains request-only. Client,
2924
- setup, filesystem-narration, and executor-materialization turns are
2925
- journal-only and therefore store `NULL`. Digest writes an explicit journal-only
2926
- or request-only note instead of fabricating response files.
3486
+ setup, filesystem-narration, and executor-materialization turns are ordinary
3487
+ operation turns and therefore store `NULL`. Digest projects exact operation
3488
+ source independently from this optional model-exchange record; a request-only
3489
+ turn receives a note instead of a fabricated response.
3490
+
3491
+ §digest-turn-artifact-identity **Digest packet artifacts project durable turns.**
3492
+ After selectors are applied, digest retains every turn with exact `turnOps` or
3493
+ a stored provider request, orders those turns by durable chronology, and names
3494
+ them contiguously from `packet000`. The producer does not affect projection.
3495
+
3496
+ | Artifact | Present when | Authority |
3497
+ |----------|--------------|-----------|
3498
+ | `packetNNN.assistant.md` | The turn has `turnOps` | Exact persisted `turnOps` source |
3499
+ | `packetNNN.system.md`, `packetNNN.user.md` | The turn stored a provider request | Stored packet sections projected through `PacketWire` |
3500
+ | `packetNNN.assistantRaw.json` | The request has an admitted provider response | Stored opaque provider response |
3501
+ | `packetNNN.response.md`, attempt artifacts | The request received no admitted response | Stored request and attempt state |
3502
+
3503
+ A source-backed turn without provider participation therefore produces only
3504
+ `assistant.md`; a request-only turn produces no fabricated assistant. A
3505
+ source-less programmatic turn with no provider request has no forensic payload
3506
+ to project and reserves no ordinal.
2927
3507
 
2928
3508
  The external tokenless draft and transformation boundary is owned by
2929
3509
  {§scheme-packet-transform}. Core alone extends each validated draft with its
@@ -2952,13 +3532,13 @@ Retired terms stay retired: the lexicon guard rejects `thinking`, the unqualifie
2952
3532
 
2953
3533
  §encrypted-reasoning-carrier **Encrypted reasoning is opaque client evidence.**
2954
3534
  When a provider returns encrypted reasoning items, core attaches that list to
2955
- the admitted model-emission row's `attrs.reasoning`. `log/entry` and `readLog`
3535
+ the admitted model `turnOps` row's `attrs.reasoning`. `log/entry` and `readLog`
2956
3536
  carry it to AG-UI, which may project correlated standard reasoning entities.
2957
3537
  Core never decodes the blobs or renders them into a model packet; readable
2958
3538
  reasoning text remains separate in `assistant.reasoning`. The provider-detail
2959
3539
  identity and derived classification retain their exact provider-normalized
2960
3540
  meaning from {§provider-encrypted-reasoning}; core never reinterprets either as
2961
- a client entity. The mirror row and logical model call remain the lossless
3541
+ a client entity. The source row and logical model call remain the lossless
2962
3542
  evidence when a downstream standard cannot represent the complete list.
2963
3543
 
2964
3544
  §body-projection **One full body, one packet projection.** Every durable log row has one canonical full body resolved from its stored tx/rx envelope by `LogBody`. READ and FIND over `log:///`, persistent search derivation, and packet rendering all consume that same meaning. Only packet rendering may project it:
@@ -2966,16 +3546,18 @@ evidence when a downstream standard cannot represent the complete list.
2966
3546
  | row producer | ordinary OPEN projection |
2967
3547
  |---|---|
2968
3548
  | any `READ` or `FIND` | complete selected operation result |
2969
- | any `PLAN` | complete authored working memory |
3549
+ | any `PLAN` | complete canonical Plurnk Plan JSON {§plan-value} |
2970
3550
  | actionless lowercase `prompt` | budgeted head under {§prompt-projection} |
2971
3551
  | structured `EDIT` receipt or textual `COPY`/`MOVE` effects | complete receipt-owned join context |
2972
3552
  | every other nonempty body | head bounded independently by `PLURNK_SERVICE_PREVIEW_LINES` and `PLURNK_SERVICE_PREVIEW_CHARS` |
2973
3553
  | bodyless row | `"display":"none","body":""` |
2974
3554
 
2975
- READ and FIND own their range or pagination before packet rendering; the packet never applies a second hidden substring bound to their selected result. PLAN is likewise complete while OPEN: it is the model's explicit persistent reasoning inventory, not ordinary content that the model should have to retrieve from itself. Prompt rows follow their separate adaptive projection contract. Structured mutation contexts already carry the receipt-owned bound in {§edit-result-receipt-truth}, so packet rendering does not preview them again. Model-emission mirrors, SEND/WORK/FORK bodies, EXEC commands, environment-delta EDIT spans, and extension-produced bodies use the ordinary fixed bound. When an OPEN projection differs from its canonical body, `chunk` follows the displayed `body` with the exact selected and complete extents defined by {§jsonplurnk}; complete and FOLDED bodies omit it. `## READ0 (log:///<coordinate>/<OP>)` applies its default or explicit text range to the canonical body; the unsuffixed exact shorthand and authoritative suffix behavior are defined by {§log-coordinate-hierarchy}. `## FIND0 (log:///...)` and search match that same full body. FOLD hides the ordinary projection, and OPEN restores the producer's projection without changing its bound. System/policy sections are not log bodies. Notices are transient non-log observations; they share the ordinary line/character bounds but have no durable body or recovery URI.
3555
+ READ and FIND own their range or pagination before packet rendering; the packet never applies a second hidden substring bound to their selected result. PLAN is likewise complete while OPEN: it is the model's explicit persistent reasoning inventory, serialized once as compact JSON rather than clipped or reparsed from source text. Prompt rows follow their separate adaptive projection contract. Structured mutation contexts already carry the receipt-owned bound in {§edit-result-receipt-truth}, so packet rendering does not preview them again. Actionless source artifacts, SEND/WORK/FORK bodies, EXEC commands, environment-delta EDIT spans, and extension-produced bodies use the ordinary fixed bound. When an OPEN projection differs from its canonical body, `chunk` follows the displayed `body` with the exact selected and complete extents defined by {§jsonplurnk}; complete and FOLDED bodies omit it. `## READ0 (log:///<coordinate>/<OP>)` applies its default or explicit text range to the canonical body; the unsuffixed exact shorthand and authoritative suffix behavior are defined by {§log-coordinate-hierarchy}. `## FIND0 (log:///...)` and search match that same full body. FOLD hides the ordinary projection, and OPEN restores the producer's projection without changing its bound. System/policy sections are not log bodies. Notices are transient non-log observations; they share the ordinary line/character bounds but have no durable body or recovery URI.
2976
3556
 
2977
3557
  §prompt-entry **Prompt as a first-class entry and log row.** Each prompt is stored once at `prompt:///<loop>/<N>` as an owner-keyed text/markdown entry, then published to its turn as one actionless lowercase `prompt` log row. No synthetic EDIT or READ operation is invented. The row is born OPEN and obeys {§body-projection}. The **Active User Prompts** section closes the user-slot status clump as a paths-only list (`* prompt:///<loop>/<N>`), so every frame remains directly READable even after its log row is folded or killed.
2978
3558
 
3559
+ §prompt-causal-source **Prompt authorship and delivery are distinct facts.** The harness publishes every prompt row with `origin="_plurnk"`; the row's existing `source` carries the canonical address of a different causal actor. Native WORK, FORK, and directed worker SEND derive `worker://<sender>` from the authenticated sender worker ID. A trusted exterior adapter may supply its own canonical actor address through {§methods-loop-run}. An absent source means the owning worker itself. Attribution persists with the prompt frame through active delivery, parking, orphan recovery, restart, and later log projection; model syntax cannot author it.
3560
+
2979
3561
  §prompt-projection **Prompt storage is unbounded by model context; automatic materialization is not.** Core persists every accepted prompt completely before packet assembly. The selected provider's derived `inputCapacity` and the alias-resolved percentage from `PLURNK_SERVICE_PROMPT_PROJECTION` derive one aggregate curation-weight allowance for OPEN prompt bodies. Complete prompt bodies render when their aggregate weight fits. Otherwise all OPEN prompt rows share the allowance: full bodies consume only their required share, unused shares are redistributed, and partial bodies render the largest leading complete-line region that fits their share or an exact character-bound prefix when the first physical line alone is larger. The sum of their rendered body weights never exceeds the allowance. Every partial body carries its exact `chunk` after `body`; the canonical `prompt:///` entry and `log:///` body remain complete and READ/FIND-addressable. When provider input capacity is unknown the percentage is underivable, so prompt rows retain the ordinary bounded projection rather than inventing capacity. This policy never rejects, summarizes, or discards a prompt because it exceeds a context window.
2980
3562
 
2981
3563
  §prompt-self-only The frame is self-only and owner-keyed:
@@ -2990,8 +3572,8 @@ that loop has no `op='prompt'` row, oldest first. Every still-undelivered frame
2990
3572
  at conclusion is re-ordinalized into one source-keyed recovery loop; that loop's
2991
3573
  first turn publishes the complete ordered set exactly once. Recovery retries
2992
3574
  complete the same queued loop and never mint duplicate work. The automatic
2993
- grinder preserves prompt rows; explicit OPEN/FOLD/KILL follows the ordinary log
2994
- contract.
3575
+ overflow turn preserves prompt rows; explicit OPEN/FOLD/KILL follows the ordinary
3576
+ log contract.
2995
3577
 
2996
3578
  §packet-catalog **Catalogs are query results, not packet state.** The packet
2997
3579
  stores no materialized manifest. Complete and one-level entry directories,
@@ -3002,7 +3584,7 @@ their row shape, and their ordering are ordinary FIND projections owned by
3002
3584
 
3003
3585
  The model's runtime alert surface has two distinct kinds of information:
3004
3586
 
3005
- - **Turn failures are log items.** A failed action and an engine-rail failure are durable `log_entries` rows whose `rx` is an RFC 9457 operation result. They fold, kill, and budget like every other row. The `errors` section is a derived pointer index over recent `status_rx ≥ 400` rows; it owns no bodies or failure state. Rejected emissions never become accepted turn content; their private response and admission evidence remains in `model_calls` and `turn_attempts`, apart from the bounded recovery mirror under {§invalid-emission-attempts}.
3587
+ - **Turn failures are log items.** A failed action and an engine-rail failure are durable `log_entries` rows whose `rx` is an RFC 9457 operation result. They fold, kill, and budget like every other row. The `errors` section is a derived pointer index over recent `status_rx ≥ 400` rows; it owns no bodies or failure state. Rejected emissions never become accepted turn content; their private response and admission evidence remains in `model_calls` and `turn_attempts`, apart from the bounded recovery `emissionAttempt` under {§invalid-emission-attempts}.
3006
3588
  - **Notices are transient observations.** Progress and non-fatal diagnostics such as `turn_awaiting_model`, `embed_progress`, and `grammar_unenforced` may appear once in the packet and broadcast live. They neither substitute for a failure result nor influence scheduling or recovery.
3007
3589
 
3008
3590
  The `log` is durable product truth. The `errors` section points at its failures
@@ -3039,16 +3621,15 @@ retain distinct contracts and lifetimes.
3039
3621
  | failure | row | status |
3040
3622
  |---|---|---|
3041
3623
  | action failure | the failed op's own row; the owning scheme supplies Problem Details | 4xx/5xx |
3042
- | provider input capacity | `op='error'`, origin `plurnk`, source `provider`; exact provider-owned `capacity-exceeded` Problem Details | 413 |
3043
- | max commands exceeded | `op='error'`, origin `plurnk`, source `rail`; `engine/rail/max-commands-exceeded` Problem Details | 429 |
3044
- | idle turn | `op='error'`, origin `plurnk`, source `rail`; `engine/rail/idle-turn` Problem Details | 409 |
3624
+ | provider input capacity | `op='error'`, origin `_plurnk`, source `provider`; exact provider-owned `capacity-exceeded` Problem Details | 413 |
3625
+ | max commands exceeded | `op='error'`, origin `_plurnk`, source `rail`; `engine/rail/max-commands-exceeded` Problem Details | 429 |
3626
+ | idle turn | `op='error'`, origin `_plurnk`, source `rail`; `engine/rail/idle-turn` Problem Details | 409 |
3045
3627
 
3046
3628
  | notice `kind` | Source | Position |
3047
3629
  |---|---|---|
3048
3630
  | `grammar_unenforced` | engine rail verdict, or a forwarded provider transport anomaly such as a discarded-channel escape | content-offset when the observed position maps into content; none for a reasoning-prefix divergence |
3049
3631
  | `parse_advisory` | grammar parser — recoverable near-miss which did not invalidate the parsed statements | content-offset into the model's emission |
3050
3632
  | `embed_progress` | repository materialization/indexing lifecycle ({§mimetype-surface}); structured phase, count, and percent; `level: info` except terminal failure | none |
3051
- | `search_progress` | aggregate search-page acquisition lifecycle; structured phase, counts, and percent; never candidate URLs or per-result notices | none |
3052
3633
 
3053
3634
  §notice-level **Severity on the wire (`level`, required).** Every `Notice` carries `level: "error" | "warn" | "info"`, set by the **producer** at the emit site. The level is client presentation, not operation status: even an `error` notice cannot terminalize work or substitute for a durable Problem. A forwarded `grammar_unenforced` is `warn`; ordinary lifecycle and progress notices are `info`. Clients color straight off `level` without interpreting the open `kind` vocabulary.
3054
3635
 
@@ -3060,20 +3641,20 @@ retain distinct contracts and lifetimes.
3060
3641
 
3061
3642
  | Surface | Contract |
3062
3643
  | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
3063
- | Import `@plurnk/plurnk-service/digest` | Ships `Digest` and its co-located `digest.sql`; importing performs no I/O or process action. The CLI wrapper alone invokes it. |
3644
+ | Import `@plurnk/plurnk-service/digest` | Ships `Digest` and its package-owned SqlRite statements; importing performs no I/O or process action. The CLI wrapper alone invokes it. |
3064
3645
  | `run({ dbPath })` | Reads the required database and writes a complete digest to `./test/digest` relative to the caller's working directory. |
3065
3646
  | `digestDir` | Selects the output directory. `run` removes and recreates it so stale packet artifacts cannot survive; concurrent callers use distinct directories. |
3066
3647
  | `workerId` | Narrows workers and every dependent loop, turn, logical model call, emission attempt, physical request, and log row to that one worker. |
3067
3648
  | `workspaceId` | Narrows workers and dependent evidence to one workspace; when both selectors are present they intersect. |
3068
3649
 
3069
- §digest-forensic-fidelity **Forensic fidelity and cardinality.** The digest's machine-readable JSON preserves every log row, including causal `source` and structured `attrs`, every exact OPEN/FOLD target effect from {§fold-open-meta-operations}, the exact Problem on every failed row, each loop's exact terminal result, and every ordered physical provider request. Accounting on broader rows is the shared exact derivation from that ledger, never a second stored fact. The human Markdown waterfall shows a present causal source and may preview only the Problem detail because it remains a triage projection, not the machine record. Targets reconstruct the model-visible address, including hostname, port, serialized query, and fragment; an authority-bearing URL must never degrade from `https://host/path` to `https:///path`, and folded network-entry storage paths render back to their authority form. Its human Markdown waterfall groups identical per-turn op outcomes and typed `entry_materialized` narrations, reporting the exact count and sequence span (`xN (seq A-B)`). Grouping keys include source and the complete target, so distinct causes, authorities, or channels never collapse. Thus amplification is conspicuous without making the diagnostic artifact itself pathological; packet files remain byte-identical records of what the model saw.
3650
+ §digest-forensic-fidelity **Forensic fidelity and cardinality.** The digest's machine-readable JSON preserves every log row, including causal `source` and structured `attrs`, every exact OPEN/FOLD target effect from {§fold-open-meta-operations}, the exact Problem on every failed row, each loop's exact terminal result, and every ordered physical provider request. Accounting on broader rows is the shared exact derivation from that ledger, never a second stored fact. The human Markdown waterfall shows a present causal source and may preview only the Problem detail because it remains a triage projection, not the machine record. Targets reconstruct the model-visible address, including hostname, port, serialized query, and fragment; an authority-bearing URL must never degrade from `https://host/path` to `https:///path`, and durable resource coordinates render back to their authority form. Its human Markdown waterfall groups identical per-turn op outcomes and typed `entry_materialized` narrations, reporting the exact count and sequence span (`xN (seq A-B)`). Grouping keys include source and the complete target, so distinct causes, authorities, or channels never collapse. Thus amplification is conspicuous without making the diagnostic artifact itself pathological; packet files remain byte-identical records of what the model saw.
3070
3651
 
3071
3652
  §digest-requiem **A requiem is an out-of-band forensic interview, not a worker
3072
3653
  turn.** It cannot execute operations or alter the audited history.
3073
3654
 
3074
3655
  | Aspect | Contract |
3075
3656
  |-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
3076
- | Scope | One interview for each worker with model-bearing turns; journal-only workers are omitted. |
3657
+ | Scope | One interview for each worker with model-bearing inference turns; workers without inference evidence are omitted. |
3077
3658
  | Evidence | The worker's final packet plus every attempt's exact normalized response and admission evidence; opaque raw transport remains in durable forensic artifacts. |
3078
3659
  | Witness | An explicitly supplied provider or the active configured provider; absence fails hard. |
3079
3660
  | Identity | The worker's durable provider identity ({§worker-provider-identity}) is sent as both `workerId` and `primaryWorkerId`, making the synthetic interview its own root without asserting a live worker topology. |
@@ -3082,49 +3663,158 @@ turn.** It cannot execute operations or alter the audited history.
3082
3663
 
3083
3664
  §turn-lifecycle **Turn-lifecycle liveness.** Provider generation is the long, opaque window in a turn — one or more same-packet emission attempts may occur before the first committed op. A static client screen there is indistinguishable from a hang. The engine brackets the complete attempt window with two `notice/event` notices (`source: "engine:turn"`, `level: "info"`): `turn_awaiting_model` before the first call and `turn_generated` when an emission is accepted or the attempt budget is exhausted. Rejected content never rides the notice channel. Both are suppressed on an aborted loop and broadcast to the workspace like any notice ({§notice-event-notify}).
3084
3665
 
3085
- §notice-content-offset-pointer **Content-offset position.** A non-fatal diagnosis on an accepted emission (for example `grammar_unenforced` or `parse_advisory`) carries `position: { type: "content-offset", line, column }` into the model's own folded mirror row. A bounded hard parse error becomes a durable failed operation whose Problem Details preserve its line, column, source, and parser-owned diagnostic. Hard errors that make the frame untrustworthy remain only with their rejected forensic attempt.
3666
+ §notice-content-offset-pointer **Content-offset position.** A non-fatal diagnosis on an accepted emission (for example `grammar_unenforced` or `parse_advisory`) carries `position: { type: "content-offset", line, column }` into the model's own folded `turnOps`. A bounded hard parse error becomes a durable failed operation whose Problem Details preserve its line, column, source, and parser-owned diagnostic. Hard errors that make the frame untrustworthy remain only with their rejected forensic attempt.
3667
+
3668
+ ### §tools Executable tool resources
3669
+
3670
+ §tools-resource-discovery **Executable capability discovery uses ordinary
3671
+ Plurnk resources.** No generated tool table rides the system packet. Every
3672
+ runtime enabled for the current worker with an admitted invocation materializes exactly one
3673
+ family document at `worker://~/_plurnk/skills/plurnk/<runtime>.md`. A general runtime's
3674
+ document contains its {§executor-tool-document}; a runtime with an exact
3675
+ {§executor-tool-registry} materializes the same single document — per-target
3676
+ child documents do not exist, shown or stored. The family document summarizes
3677
+ the server or runtime, lists every enabled target as a directly copyable
3678
+ `## EXEC0` heading with its input signature ({§operation-annotation} carries the
3679
+ target one-liner; no invocation dispatch would reject is ever advertised), and
3680
+ carries each detailed target's richer input-side contract as a
3681
+ `## <target>` section of the same document, that target's own headings demoted
3682
+ one level beneath it. A detail-less target's invocation line is its whole
3683
+ teaching. Tool-result/output schemas remain ordinary evidence and never enter
3684
+ this document.
3086
3685
 
3087
- ### §tools user.tools — the capability sheet
3088
-
3089
- §tools-capability-sheet The tools capability sheet renders under `## Registered Tools`, after the policy sections. One generated Markdown table is the closed set of valid executor selectors. Its columns state `[executor]`, the `(target)` role and any concrete target witness, the body role, and `Invocation`: a body example, a schema-derived signature, or `bodyless`. The Invocation cell never repeats the `## EXEC0 [executor] (target)` syntax already defined by the headers and columns. A runtime exposing {§executor-tool-registry} contributes exactly one row per enabled exact target instead of its general row; an empty exact registry contributes no row and has no fallback. The compact legend leaves required inputs unmarked, marks optional inputs with `?`, pairs mutually exclusive alternatives with `↔`, marks refused buckets with `—`, and locates optional `<timeout,poll>` on the heading. The preface prefers purpose-built Plurnk operations over EXEC scripts. For a declaration with `target.directory: "cwd"`, the target cell distinguishes a local-directory working context from the plugin-authored non-directory target role. Optional non-EXEC operations render separately under `## Enabled Optional Operations` in a `plurnk` fence, so the catalogue remains truthful. `PacketBuilder.#collectTools` assembles both; a prose notice (e.g. the EXEC-disabled line) stays beside the table, and empty sections are omitted.
3090
-
3091
- §tools-loop-affinity **The capability sheet describes the current loop.** The
3092
- sheet filters registered capabilities through the same
3093
- `SchemeRegistry.resolveForLoop(flags)` predicate the dispatcher enforces. When
3094
- registered executors exist but EXEC is inactive, their table is replaced by
3095
- an explicit disabled notice rather than silent absence. The dispatch 403 remains
3096
- the backstop and names the non-retryable loop restriction.
3686
+ ```mermaid
3687
+ flowchart LR
3688
+ Survey["Turn 0 FIND<br/>tools/*.md"] --> Families["family paths + summaries"]
3689
+ Families --> Read["READ selected family<br/>only when needed"]
3690
+ Read --> Exec["EXEC annotated invocation"]
3691
+ ```
3097
3692
 
3098
- **Contributors: the workspace executor snapshot.** Every available executor tag
3099
- contributes its general {§executor-invocation} row or the closed rows and
3100
- documentation from its {§executor-tool-registry} snapshot. Its doc is
3101
- materialized at `worker://plurnk/docs/<tag>.md` and discovered via the turn-0
3102
- `## FIND0 [+init,+docs] (worker://plurnk/docs/**)` foist, not linked inline.
3103
- `PLURNK_SERVICE_DOCS_EXCLUDE` drops a named tag's rows and doc. Installed
3104
- executors are probed once; workspace providers publish only prepared runnable
3105
- selectors, so the table never presumes that another workspace's capability is
3106
- available here.
3693
+ §tools-resource-materialization The runtime registry, worker executor policy,
3694
+ tool resources, and dispatch use one effective worker snapshot. A
3695
+ worker-disabled, unavailable, detached, replaced, or removed runtime has no
3696
+ tool resource; an exact registry's empty set publishes no executable family and
3697
+ admits no invocation. Reconciliation deletes stale documents
3698
+ before upserting the current set. `PLURNK_SERVICE_DOCS_EXCLUDE` does not hide an
3699
+ enabled executable; executor enablement is the sole user-configured filter
3700
+ shared by discovery and dispatch. A runtime declaration may carry
3701
+ `resourcesPath` — its generated-doc root relative to the worker's generated
3702
+ subtree ({§worker-generated-subtree}). Absent, its docs live in the internal
3703
+ `_plurnk/skills/plurnk` namespace; present (attached MCP families: `/tools`),
3704
+ the family document materializes at `_plurnk` + that root in the
3705
+ worker's private entry space. Turn 0 surveys the families (`## FIND0 [+init,+tools]
3706
+ (worker://~/_plurnk/tools/*.md)`, one row per
3707
+ server carrying its summary) and, for each server named in
3708
+ `PLURNK_MCP_EXPANDED`, adds one complete family-document READ
3709
+ (`_plurnk/tools/<server>.md <1,-1>`) so turn 0 names every tool it exposes.
3710
+ Attached tools are capabilities like every other runtime; the model never
3711
+ learns an origin.
3712
+
3713
+ §skills-functionality **Agent Skills are one Worker Functionality family.**
3714
+ Core registers the `skills` family with the coordinator ({§functionality-coordinator});
3715
+ its adapter owns protocol truth for standard Agent Skills and nothing else. A
3716
+ definition is `SkillDefinition` — the standard skill `name`, the universal
3717
+ root `scope` (`project` = `<projectRoot>/.agents/skills`, `global` =
3718
+ `~/.agents/skills`), and for a Worker-installed skill the standard installer
3719
+ `source` that provides it. Plurnk bundles no skills of its own and never
3720
+ seeds or mutates a universal root absent an explicit `add`/`remove`.
3721
+
3722
+ *Available definitions.* The filesystem is the only truth about installation:
3723
+ every `<root>/<name>/SKILL.md` directory under the project then the global
3724
+ root is one service-origin definition, enabled by default, project shadowing
3725
+ global by name; when the standard installer's `skills-lock.json` records a
3726
+ source it rides the definition. A Worker's durable state owns enablement
3727
+ ({§functionality-state}); a disabled skill stays client-visible and leaves no
3728
+ model-facing trace.
3729
+
3730
+ *Discovery is inert.* `discover {query}` searches the ecosystem registry
3731
+ (`PLURNK_SERVICE_SKILLS_REGISTRY_URL`, default `https://skills.sh`; empty disables it
3732
+ with 501 `registry-not-configured`) and returns one candidate per hit with
3733
+ `registry` provenance and the exact `owner/repo` source. `discover {source}`
3734
+ lists the skills one standard package reference contains with `source`
3735
+ provenance. Neither installs, persists, or enables. Client `configuration`
3736
+ contributes nothing and is refused with 400.
3737
+
3738
+ *Admission.* `add {alias, definition}` requires `alias = name`, a `source`,
3739
+ and a project root when `scope` is `project`; the Worker's own definition may
3740
+ shadow a service skill of the same name.
3741
+
3742
+ *Preparation.* For each enabled alias the adapter locates the directory at the
3743
+ definition's scope; a Worker definition whose directory is absent is installed
3744
+ through the standard CLI (`PLURNK_SERVICE_SKILLS_CLI`, default `npx --yes skills`:
3745
+ `add <source> --agent universal --skill <name> --yes [--global]`, run with
3746
+ `HOME` set to the service's user home so the installer's `~` is the global
3747
+ root) and the installed `SKILL.md` — never the installer's output — is the
3748
+ evidence.
3749
+ Each admitted skill requires standard `name` and `description` frontmatter
3750
+ with `name` matching its directory. A missing, uninstallable, or invalid skill
3751
+ is `unavailable` with its exact Problem (`skill-missing`, `install-failed`,
3752
+ `skill-invalid`) under the coordinator's failure policy
3753
+ ({§functionality-model-mutation}); one bad skill never fails the family.
3754
+
3755
+ *Documents.* The family publishes `worker://~/_plurnk/skills/index.md` —
3756
+ which always exists and lists the active skills by name and description — and
3757
+ one `worker://~/_plurnk/skills/<name>.md` per active skill, with an exact H2
3758
+ `Summary` carrying the standard `description` and the instruction body
3759
+ preserved verbatim ({§functionality-documents}). They are discovered by the
3760
+ turn-0 `+init,+skills` FIND survey; disabled and unavailable skills are
3761
+ absent from model teaching.
3762
+
3763
+ §skills-remove **`remove` uninstalls what the Worker installed.** Before the
3764
+ coordinator forgets a Worker-origin skill definition the adapter removes that
3765
+ skill from the definition's scope through the standard CLI (`remove <name>
3766
+ --yes [--global]`), verified by the directory's absence; a failed removal
3767
+ rejects the mutation. A same-named skill at a lower-precedence root is then
3768
+ revealed as a service definition, disabled ({§functionality-coordinator}).
3769
+ Service definitions are disable-only.
3770
+
3771
+ §skills-hotload **Out-of-band installers are admitted at the next turn.** The
3772
+ family keeps one signature of the installed roots per resident Worker; turn
3773
+ admission recomputes it under the workspace gate before packet assembly and
3774
+ republishes the family through the coordinator when it changed, so a skill
3775
+ installed or removed by any other tool is discoverable in the first subsequent
3776
+ model turn while an unchanged set dispatches nothing. The model manages skills
3777
+ only through the generated `EXEC [skills]` family
3778
+ ({§functionality-model-projection}); it is never taught a package manager.
3779
+
3780
+ The catalog describes this worker's Functionality, not temporary authority. Loop
3781
+ mode remains a dispatch concern: an ask-mode EXEC receives the ordinary exact
3782
+ 403 restriction instead of requiring a second per-loop documentation overlay.
3783
+ Optional non-EXEC operations remain a separate `## Enabled Optional Operations`
3784
+ section because they are language extensions rather than executable tools.
3107
3785
 
3108
3786
  ### §schemes user.schemes — the resource directory
3109
3787
 
3110
- §schemes-directory A `## Resources` section renders in the system slot **after the policy sections and tools sheet** — a terse directory of the scheme families available this workspace, so the model knows what URI resources and operations exist before it acts. Each scheme that ships a `manifest.example` contributes one or more concise canonical ops (no scheme prefix; each example self-documents) into a `plurnk` fence. Scheme example sets are separated by one blank line. The doc is NOT linked inline — it is materialized at `worker://plurnk/docs/<scheme>.md` and discovered via the turn-0 `## FIND0 [+init,+docs] (worker://plurnk/docs/**)` foist, keeping the raw packet free of doc links. Meta-owned `log` and `worker` depth is required teaching ({§teaching-corpus}); a failed source read rejects materialization with its cause and never falls back. Other core and plugin schemes may supply optional `manifest.documentation`; absence contributes no pull doc. The verbose semantics live in that pull doc (materialized like any entry, READ on demand), not the hot path — terse pushes, depth pulls. A scheme with no example (provisional) is omitted; `PLURNK_SERVICE_DOCS_EXCLUDE` drops a named scheme's examples + doc.
3788
+ §schemes-directory A `## Resources` section renders in the system slot **after the policy sections** — a terse directory of the scheme families available to this worker, so the model knows what URI resources and operations exist before it acts. Each scheme that ships a `manifest.example` contributes one or more concise canonical ops (no scheme prefix; each example self-documents) into a `plurnk` fence. Scheme example sets are separated by one blank line. The doc is NOT linked inline — it is materialized as the worker-private skill `worker://~/_plurnk/skills/plurnk/<scheme>.md` and discovered via the turn-0 `## FIND0 [+init,+skills] (worker://~/_plurnk/skills/plurnk/*.md)` survey ({§skills-functionality}), keeping the raw packet free of doc links. Meta-owned `worker` depth is required teaching ({§teaching-corpus}); a failed source read rejects materialization with its cause and never falls back. Other core and plugin schemes may supply optional `manifest.documentation`; absence contributes no pull doc. The verbose semantics live in that pull doc (materialized like any entry, READ on demand), not the hot path — terse pushes, depth pulls. A scheme with no example (provisional) is omitted; `PLURNK_SERVICE_DOCS_EXCLUDE` drops a named scheme's examples + doc.
3111
3789
 
3112
3790
  ### §inject system.inject — the operator injection
3113
3791
 
3114
- §packet-inject When `PLURNK_SERVICE_PACKET_INJECT` names a readable markdown file, its content renders as an `## Operator Notes` section in the system slot after policy and capability teaching (definition → policy → project policy → tools → resources → inject). Read per-turn so the operator's edits take effect live; a set-but-unreadable path fails the turn hard (a deliberate setting with a broken path is a misconfig, surfaced not hidden). `~/` expands to home. It's the operator-side complement to the plugin section hook — a pressure valve so reshaping the packet edits operator content, never the core. Unset → no section.
3792
+ §packet-inject When `PLURNK_SERVICE_PACKET_INJECT` names a readable markdown file, its content renders as an `## Operator Notes` section in the system slot after policy and capability teaching (definition → policy → project policy → resources → inject). Read per-turn so the operator's edits take effect live; a set-but-unreadable path fails the turn hard (a deliberate setting with a broken path is a misconfig, surfaced not hidden). `~/` expands to home. It's the operator-side complement to the plugin section hook — a pressure valve so reshaping the packet edits operator content, never the core. Unset → no section.
3115
3793
 
3116
3794
  ### §policy system.policy — the client's policy injection
3117
3795
 
3118
- §policy-sections Two sections ride the system slot **after the definition and before loop-dependent capabilities**: `## Policy` from `PLURNK_SERVICE_POLICY` (default `~/.plurnk/AGENTS.md`) and `## Project Policy` from `PLURNK_SERVICE_PROJECT` (default `<projectRoot>/AGENTS.md`, resolved relative to the workspace root). AGENTS.md is **policy** — the client's authoritative rules promoted into the privileged zone — NOT a curatable, foldable, READ-able entry; the model cannot FOLD it away. A default-absent path is silent (the section is omitted); an explicit override (env set) that fails to read fails the turn hard — a deliberate setting with a broken path is a misconfig, surfaced not hidden. Read per-turn so edits take effect live. Reference and scratch docs are NOT policy; `PLURNK_SERVICE_MD_*` materializes them as READ-able entries ({§operator-config}).
3796
+ §policy-sections One section rides the system slot **after the definition and before capability teaching**: `## Policy` from `PLURNK_SERVICE_POLICY` (default `$XDG_CONFIG_HOME/plurnk/AGENTS.md`, {§host-path-layout}). Policy is the client's authoritative rules promoted into the privileged zone — NOT a curatable, foldable, READ-able entry; the model cannot FOLD it away. A default-absent path is silent (the section is omitted); an explicit override (env set) that fails to read fails the turn hard — a deliberate setting with a broken path is a misconfig, surfaced not hidden. Read per-turn so edits take effect live. The PROJECT `AGENTS.md` is local guidance, not policy: it rides turn 0 as the foisted `worker://~/_plurnk/agents.md` entry ({§turn0-agents-stunt}); all other reference material is skills under the worker's private skills tree ({§skills-functionality}).
3119
3797
 
3120
- On first run, and only when `~/.plurnk` itself is absent, the service seeds
3798
+ On first run, and only when `$XDG_CONFIG_HOME/plurnk` itself is absent, the service seeds
3121
3799
  `AGENTS.md` from `@plurnk/plurnk-meta/PLURNK_PERSONALITY.md` ({§teaching-corpus}).
3122
3800
  It reads that required source before creating the service home; a failed read
3123
3801
  surfaces with its cause and leaves no apparently initialized home.
3124
3802
  After that bootstrap the file is user-owned: edits and deletion persist, and a
3125
3803
  later boot never refreshes or recreates it.
3126
3804
 
3127
- §schemes-self-doc-materialization **The scheme self-doc contract.** `@plurnk/plurnk-schemes` owns `example` and `documentation` in `SchemeManifest` ({§manifest-self-doc}); the former is the hot-path operation example set and the latter is the deep pull doc. `SchemeRegistry.teach(workspaceId)` renders the effective directory, `SchemeRegistry.docs(workspaceId)` resolves corpus-or-manifest documentation, and `docEntries(workspaceId)` supplies the current pull-document set when core publishes capabilities for a workspace. Materialization reconciles `worker://plurnk/docs/` exactly under the workspace capability gate: vanished contributions are deleted before current documents are upserted, so an excluded, disabled, detached, or replaced capability cannot leave a stale model-facing contract.
3805
+ §legacy-home-transition A legacy `~/.plurnk` is never an ambient fallback. If
3806
+ legacy state exists while canonical destinations do not, ordinary startup
3807
+ fails with the exact `plurnk-service paths migrate` recovery. That explicit,
3808
+ idempotent command refuses destination conflicts and a live database owner,
3809
+ moves known user configuration and durable SQLite files to their semantic
3810
+ homes, byte-verifies the complete copied set before removing any source,
3811
+ discards only recognized generated references, and removes the empty legacy
3812
+ directory. A pre-commit failure rolls back canonical files and directories
3813
+ created by that attempt. Unknown legacy members or simultaneous
3814
+ legacy/canonical state fail without guessing. No dual read or dual write survives
3815
+ the transition.
3816
+
3817
+ §schemes-self-doc-materialization **The scheme self-doc contract.** `@plurnk/plurnk-schemes` owns `example` and `documentation` in `SchemeManifest` ({§manifest-self-doc}); the former is the hot-path operation example set and the latter is the deep pull doc. Every published pull doc carries an exact H2 `Summary` for ordinary catalog projection. `SchemeRegistry.teach(workerId)` renders the effective directory, `SchemeRegistry.docs(workerId)` resolves corpus-or-manifest documentation, and `referenceEntries(workerId)` supplies the current `/skills/plurnk/` generated-skill set when core publishes worker Functionality ({§skills-functionality}). One materializer reconciles the worker's private scope exactly: vanished contributions are deleted before current documents are upserted, so an excluded scheme or disabled, detached, replaced, or removed runtime cannot leave a stale model-facing contract.
3128
3818
 
3129
3819
  ### §packet-git-status The Git status section — compact repository state
3130
3820
 
@@ -3134,7 +3824,7 @@ active direct child of a running branch batch additionally receives its assigned
3134
3824
  branch and the requirement to commit any project changes and leave the checkout
3135
3825
  clean before concluding ({§worker-branch-batch-return}); no other worker receives
3136
3826
  that instruction. The section never repeats an unbounded path list. Per-path state belongs to
3137
- the durable causal observation: a `source=file` environment-delta row carries
3827
+ the runtime actor's durable causal evidence: its `source=file` row carries
3138
3828
  the exact two-character porcelain `XY` value as `git` metadata when the status
3139
3829
  snapshot names that path. The engine takes one snapshot after membership
3140
3830
  reconciliation and uses it for both projections; no per-file Git process exists.
@@ -3285,15 +3975,16 @@ projection, and binary handling. Text scope meaning does not vary by mimetype.
3285
3975
  §render-rule-line-navigable-prefix Every textual content body with a source
3286
3976
  `startLine` renders with a coordinate prefix on each physical line, independent
3287
3977
  of mimetype. A successful exact READ whose active scheme declares
3288
- `textEditScopes: true` and model write authority supplies `@hash N:` with one
3978
+ `lineAnchors: true`, or `textEditScopes: true` with model write authority, supplies `@hash N:` with one
3289
3979
  or more ASCII spaces before `N` under
3290
- {§line-anchors}; every other body renders `N:`. JSON, XML, and HTML are therefore just as
3980
+ {§line-anchors}; generated FIND rows render a result ordinal left-padded to the
3981
+ complete result total's width; every other body renders `N:` left-padded to its own largest line number's width, so every body keeps one stable content column. JSON, XML, and HTML are therefore just as
3291
3982
  line-addressable as markdown and source code. The prefix is a packet
3292
3983
  presentation aid, never part of canonical content; matchers and mutations
3293
3984
  consume canonical bytes before rendering. A producer may set `startLine: null`
3294
3985
  only when its content is already source-numbered, such as an effect receipt.
3295
3986
 
3296
- §render-rule-find-renders-result A log row's canonical full body is resolved once by `LogBody`: READ/FIND, model-emission, prompt, and extension result content comes from `rx.content`; EDIT uses its structured receipt or an environment-delta span; COPY/MOVE concatenate the textual receipt contexts in their ordered `effects`; EXEC and the composed PLAN/SEND/WORK/FORK family use their statement body. Whole-channel COPY/MOVE effects are bodyless rather than fabricating a text projection. Packet rendering applies {§body-projection} and the coordinate projection in {§render-rule-line-navigable-prefix}. READ/FIND over `log:///` and search consume the complete canonical body instead. Status and content are orthogonal: a failed terminal stream READ retains its Problem Details and failure status while rendering captured diagnostic output; failure never erases evidence.
3987
+ §render-rule-find-renders-result A log row's canonical full body is resolved once by `LogBody`: READ/FIND, actionless source artifacts, prompt, and extension result content comes from `rx.content`; EDIT uses its structured receipt or an environment-delta span; COPY/MOVE concatenate the textual receipt contexts in their ordered `effects`; PLAN serializes its canonical value through the shared {§json-result-rendering} spread as `application/json`; EXEC and SEND/WORK/FORK use their statement body. Whole-channel COPY/MOVE effects are bodyless rather than fabricating a text projection. Packet rendering applies {§body-projection} and the coordinate projection in {§render-rule-line-navigable-prefix}. READ/FIND over `log:///` and search consume the complete canonical body instead. Status and content are orthogonal: a failed terminal stream READ retains its Problem Details and failure status while rendering captured diagnostic output; failure never erases evidence.
3297
3988
 
3298
3989
  An `EDIT` log row renders its bounded effect receipt (`rx.receipt`) as row
3299
3990
  metadata and join context, not its input statement. Proposal-gated file EDITs
@@ -3343,7 +4034,7 @@ Carried from the contract walk; durable.
3343
4034
  {§copy-move-observation}.
3344
4035
  - **READ rx** prefixes every textual line under {§render-rule}; eligible
3345
4036
  editable resources carry `@hash N:`, and all others carry `N:`.
3346
- - **FIND body matcher** applies to entry content (all dialects), per-candidate via the in-tree `Matcher.matchAgainstContent` ({§matcher-dispatch}; status 200 = content hit → entry selected). The target scope selects candidates; the path-glob is the (target). FIND's signal classifies its own log item ({§log-item-tags}).
4037
+ - **FIND body matcher** applies to the addressed entry channel (all dialects), per-candidate via the in-tree `Matcher.matchAgainstContent` ({§matcher-dispatch}; status 200 = content hit → entry selected). The target scope and channel select candidates; the path-glob is the (target). FIND's signal classifies its own log item ({§log-item-tags}).
3347
4038
  - **OPEN/FOLD** operate on the **log** (`log:///`), not entries ({§open-fold}) — FOLD collapses a log row to its path, OPEN restores its body. Aimed at an entry scheme they return 501.
3348
4039
  - **SEND signal `410`** deletes as a side-effect (not the model idiom; {§move}): with `#fragment`, that channel only; without, the whole entry. **SEND signal `499`** resolves the durable open-subscription row and invokes that subscription's exact callable owner through the process-local live registry ({§subscriptions}).
3349
4040
  - **File scheme** detects with `Mimetypes.detect({ path })` and classifies with the same configured service ({§mimetype-classification-consumption}). Handler-declared binary sources materialize through {§membership-source-projection}; projected bodies are READ-able, while source-aware EDIT remains 415.