@plurnk/plurnk-service 1.28.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. package/.env.defaults +7 -18
  2. package/INSTALL.md +65 -15
  3. package/README.md +8 -5
  4. package/SPEC.md +217 -449
  5. package/dist/build-info.json +1 -1
  6. package/dist/content/body-preview.d.ts +5 -0
  7. package/dist/content/body-preview.d.ts.map +1 -1
  8. package/dist/content/body-preview.js +25 -0
  9. package/dist/content/body-preview.js.map +1 -1
  10. package/dist/content/line-marker.js +1 -1
  11. package/dist/content/line-marker.js.map +1 -1
  12. package/dist/content/path-mimetype.js +1 -1
  13. package/dist/content/path-mimetype.js.map +1 -1
  14. package/dist/core/AdmittedTurnExecutor.d.ts +4 -3
  15. package/dist/core/AdmittedTurnExecutor.d.ts.map +1 -1
  16. package/dist/core/AdmittedTurnExecutor.js +19 -17
  17. package/dist/core/AdmittedTurnExecutor.js.map +1 -1
  18. package/dist/core/BareBatchRunner.d.ts +2 -2
  19. package/dist/core/BareBatchRunner.d.ts.map +1 -1
  20. package/dist/core/BareBatchRunner.js.map +1 -1
  21. package/dist/core/ChannelWrite.d.ts +5 -0
  22. package/dist/core/ChannelWrite.d.ts.map +1 -1
  23. package/dist/core/ChannelWrite.js +5 -0
  24. package/dist/core/ChannelWrite.js.map +1 -1
  25. package/dist/core/ChannelWrite.sql +10 -0
  26. package/dist/core/DataStatementRunner.d.ts.map +1 -1
  27. package/dist/core/DataStatementRunner.js +8 -3
  28. package/dist/core/DataStatementRunner.js.map +1 -1
  29. package/dist/core/Dispatcher.d.ts +2 -2
  30. package/dist/core/Dispatcher.d.ts.map +1 -1
  31. package/dist/core/Dispatcher.js +21 -15
  32. package/dist/core/Dispatcher.js.map +1 -1
  33. package/dist/core/Engine.d.ts +1 -1
  34. package/dist/core/Engine.d.ts.map +1 -1
  35. package/dist/core/Engine.js +1 -1
  36. package/dist/core/Engine.js.map +1 -1
  37. package/dist/core/ExecutorRegistry.d.ts +3 -17
  38. package/dist/core/ExecutorRegistry.d.ts.map +1 -1
  39. package/dist/core/ExecutorRegistry.js +6 -6
  40. package/dist/core/ExecutorRegistry.js.map +1 -1
  41. package/dist/core/HostPaths.d.ts +2 -0
  42. package/dist/core/HostPaths.d.ts.map +1 -1
  43. package/dist/core/HostPaths.js +14 -0
  44. package/dist/core/HostPaths.js.map +1 -1
  45. package/dist/core/KillHandler.d.ts.map +1 -1
  46. package/dist/core/KillHandler.js +9 -3
  47. package/dist/core/KillHandler.js.map +1 -1
  48. package/dist/core/PacketBuilder.d.ts.map +1 -1
  49. package/dist/core/PacketBuilder.js +8 -2
  50. package/dist/core/PacketBuilder.js.map +1 -1
  51. package/dist/core/ResourceSelector.d.ts.map +1 -1
  52. package/dist/core/ResourceSelector.js +4 -2
  53. package/dist/core/ResourceSelector.js.map +1 -1
  54. package/dist/core/ResourceTransfers.d.ts.map +1 -1
  55. package/dist/core/ResourceTransfers.js +2 -2
  56. package/dist/core/ResourceTransfers.js.map +1 -1
  57. package/dist/core/SchemeRegistry.d.ts +5 -4
  58. package/dist/core/SchemeRegistry.d.ts.map +1 -1
  59. package/dist/core/SchemeRegistry.js +9 -9
  60. package/dist/core/SchemeRegistry.js.map +1 -1
  61. package/dist/core/ToolResources.js +5 -5
  62. package/dist/core/ToolResources.js.map +1 -1
  63. package/dist/core/Turn.js +1 -1
  64. package/dist/core/Turn.js.map +1 -1
  65. package/dist/core/TurnOps.d.ts +1 -1
  66. package/dist/core/TurnOps.d.ts.map +1 -1
  67. package/dist/core/TurnOps.js +4 -12
  68. package/dist/core/TurnOps.js.map +1 -1
  69. package/dist/core/TurnRunner.d.ts +1 -2
  70. package/dist/core/TurnRunner.d.ts.map +1 -1
  71. package/dist/core/TurnRunner.js +11 -24
  72. package/dist/core/TurnRunner.js.map +1 -1
  73. package/dist/core/WorkerControlHandler.d.ts.map +1 -1
  74. package/dist/core/WorkerControlHandler.js +5 -1
  75. package/dist/core/WorkerControlHandler.js.map +1 -1
  76. package/dist/core/caps/DbNotifyCaps.js +2 -2
  77. package/dist/core/caps/DbNotifyCaps.js.map +1 -1
  78. package/dist/core/caps/DbProjectionCaps.js +1 -1
  79. package/dist/core/caps/DbProjectionCaps.js.map +1 -1
  80. package/dist/core/env-defaults.d.ts +2 -1
  81. package/dist/core/env-defaults.d.ts.map +1 -1
  82. package/dist/core/env-defaults.js +17 -9
  83. package/dist/core/env-defaults.js.map +1 -1
  84. package/dist/core/packet-wire.d.ts +1 -2
  85. package/dist/core/packet-wire.d.ts.map +1 -1
  86. package/dist/core/packet-wire.js +9 -6
  87. package/dist/core/packet-wire.js.map +1 -1
  88. package/dist/core/plurnk-uri.d.ts +7 -0
  89. package/dist/core/plurnk-uri.d.ts.map +1 -1
  90. package/dist/core/plurnk-uri.js +21 -0
  91. package/dist/core/plurnk-uri.js.map +1 -1
  92. package/dist/core/unregistered-scheme.d.ts +4 -0
  93. package/dist/core/unregistered-scheme.d.ts.map +1 -0
  94. package/dist/core/unregistered-scheme.js +14 -0
  95. package/dist/core/unregistered-scheme.js.map +1 -0
  96. package/dist/evidence/EvidenceReader.d.ts +14 -0
  97. package/dist/evidence/EvidenceReader.d.ts.map +1 -0
  98. package/dist/evidence/EvidenceReader.js +134 -0
  99. package/dist/evidence/EvidenceReader.js.map +1 -0
  100. package/dist/index.d.ts +0 -1
  101. package/dist/index.d.ts.map +1 -1
  102. package/dist/index.js +2 -4
  103. package/dist/index.js.map +1 -1
  104. package/dist/schemes/Exec.d.ts.map +1 -1
  105. package/dist/schemes/Exec.js +17 -6
  106. package/dist/schemes/Exec.js.map +1 -1
  107. package/dist/schemes/ExecOutputScheme.d.ts +1 -1
  108. package/dist/schemes/ExecOutputScheme.d.ts.map +1 -1
  109. package/dist/schemes/File.d.ts.map +1 -1
  110. package/dist/schemes/File.js +11 -6
  111. package/dist/schemes/File.js.map +1 -1
  112. package/dist/schemes/Log.d.ts.map +1 -1
  113. package/dist/schemes/Log.js +49 -5
  114. package/dist/schemes/Log.js.map +1 -1
  115. package/dist/schemes/{Skill.d.ts → ResourceTreeScheme.d.ts} +5 -6
  116. package/dist/schemes/ResourceTreeScheme.d.ts.map +1 -0
  117. package/dist/schemes/{Skill.js → ResourceTreeScheme.js} +63 -43
  118. package/dist/schemes/ResourceTreeScheme.js.map +1 -0
  119. package/dist/schemes/Worker.js +1 -1
  120. package/dist/schemes/Worker.js.map +1 -1
  121. package/dist/schemes/_entry-crud.js +9 -9
  122. package/dist/schemes/_entry-crud.js.map +1 -1
  123. package/dist/schemes/_entry-crud.sql +1 -1
  124. package/dist/schemes/_entry-find.js +5 -5
  125. package/dist/schemes/_entry-find.js.map +1 -1
  126. package/dist/schemes/_entry-find.sql +1 -1
  127. package/dist/schemes/_entry-fts.d.ts.map +1 -1
  128. package/dist/schemes/_entry-fts.js +7 -3
  129. package/dist/schemes/_entry-fts.js.map +1 -1
  130. package/dist/schemes/_entry-manifest.d.ts.map +1 -1
  131. package/dist/schemes/_entry-manifest.js +3 -5
  132. package/dist/schemes/_entry-manifest.js.map +1 -1
  133. package/dist/schemes/_entry-ops.js +4 -4
  134. package/dist/schemes/_entry-ops.js.map +1 -1
  135. package/dist/server/AgentRoots.d.ts +2 -1
  136. package/dist/server/AgentRoots.d.ts.map +1 -1
  137. package/dist/server/AgentRoots.js +13 -10
  138. package/dist/server/AgentRoots.js.map +1 -1
  139. package/dist/server/ConfigurationDiagnostics.d.ts +4 -3
  140. package/dist/server/ConfigurationDiagnostics.d.ts.map +1 -1
  141. package/dist/server/ConfigurationDiagnostics.js +15 -8
  142. package/dist/server/ConfigurationDiagnostics.js.map +1 -1
  143. package/dist/server/Daemon.d.ts +13 -8
  144. package/dist/server/Daemon.d.ts.map +1 -1
  145. package/dist/server/Daemon.js +91 -49
  146. package/dist/server/Daemon.js.map +1 -1
  147. package/dist/server/EnvFunctionality.d.ts +2 -2
  148. package/dist/server/EnvFunctionality.d.ts.map +1 -1
  149. package/dist/server/EnvFunctionality.js +2 -2
  150. package/dist/server/EnvFunctionality.js.map +1 -1
  151. package/dist/server/Functionality.d.ts +3 -2
  152. package/dist/server/Functionality.d.ts.map +1 -1
  153. package/dist/server/Functionality.js +1 -1
  154. package/dist/server/Functionality.js.map +1 -1
  155. package/dist/server/HttpListener.d.ts +2 -0
  156. package/dist/server/HttpListener.d.ts.map +1 -1
  157. package/dist/server/HttpListener.js +17 -9
  158. package/dist/server/HttpListener.js.map +1 -1
  159. package/dist/server/MembersFunctionality.d.ts +1 -1
  160. package/dist/server/MembersFunctionality.d.ts.map +1 -1
  161. package/dist/server/MembersFunctionality.js.map +1 -1
  162. package/dist/server/ModuleHost.d.ts +33 -0
  163. package/dist/server/ModuleHost.d.ts.map +1 -0
  164. package/dist/server/ModuleHost.js +2 -0
  165. package/dist/server/ModuleHost.js.map +1 -0
  166. package/dist/server/PlurnkSkill.d.ts.map +1 -1
  167. package/dist/server/PlurnkSkill.js +54 -6
  168. package/dist/server/PlurnkSkill.js.map +1 -1
  169. package/dist/server/ServiceModules.d.ts +0 -2
  170. package/dist/server/ServiceModules.d.ts.map +1 -1
  171. package/dist/server/ServiceModules.js +5 -9
  172. package/dist/server/ServiceModules.js.map +1 -1
  173. package/dist/server/WorkspacePlugins.d.ts +2 -11
  174. package/dist/server/WorkspacePlugins.d.ts.map +1 -1
  175. package/dist/server/WorkspacePlugins.js.map +1 -1
  176. package/dist/server/WorkspaceResidency.d.ts +2 -1
  177. package/dist/server/WorkspaceResidency.d.ts.map +1 -1
  178. package/dist/server/WorkspaceStorage.d.ts +1 -0
  179. package/dist/server/WorkspaceStorage.d.ts.map +1 -1
  180. package/dist/server/WorkspaceStorage.js +31 -5
  181. package/dist/server/WorkspaceStorage.js.map +1 -1
  182. package/dist/server/module-discovery.d.ts +11 -3
  183. package/dist/server/module-discovery.d.ts.map +1 -1
  184. package/dist/server/module-discovery.js +32 -18
  185. package/dist/server/module-discovery.js.map +1 -1
  186. package/dist/server/workspace-storage.sql +5 -0
  187. package/dist/service.d.ts.map +1 -1
  188. package/dist/service.js +37 -34
  189. package/dist/service.js.map +1 -1
  190. package/migrations/016_selection_statements.sql +43 -0
  191. package/migrations/017_skills_module.sql +5 -0
  192. package/package.json +71 -72
  193. package/dist/core/EmissionHead.d.ts +0 -8
  194. package/dist/core/EmissionHead.d.ts.map +0 -1
  195. package/dist/core/EmissionHead.js +0 -29
  196. package/dist/core/EmissionHead.js.map +0 -1
  197. package/dist/core/operation-target-groups.d.ts +0 -3
  198. package/dist/core/operation-target-groups.d.ts.map +0 -1
  199. package/dist/core/operation-target-groups.js +0 -77
  200. package/dist/core/operation-target-groups.js.map +0 -1
  201. package/dist/digest/Digest.d.ts +0 -10
  202. package/dist/digest/Digest.d.ts.map +0 -1
  203. package/dist/digest/Digest.js +0 -252
  204. package/dist/digest/Digest.js.map +0 -1
  205. package/dist/digest/DigestEvidence.d.ts +0 -11
  206. package/dist/digest/DigestEvidence.d.ts.map +0 -1
  207. package/dist/digest/DigestEvidence.js +0 -66
  208. package/dist/digest/DigestEvidence.js.map +0 -1
  209. package/dist/digest/DigestRender.d.ts +0 -18
  210. package/dist/digest/DigestRender.d.ts.map +0 -1
  211. package/dist/digest/DigestRender.js +0 -1035
  212. package/dist/digest/DigestRender.js.map +0 -1
  213. package/dist/digest/DigestRequiem.d.ts +0 -13
  214. package/dist/digest/DigestRequiem.d.ts.map +0 -1
  215. package/dist/digest/DigestRequiem.js +0 -337
  216. package/dist/digest/DigestRequiem.js.map +0 -1
  217. package/dist/digest/digest-db.d.ts +0 -3
  218. package/dist/digest/digest-db.d.ts.map +0 -1
  219. package/dist/digest/digest-db.js +0 -68
  220. package/dist/digest/digest-db.js.map +0 -1
  221. package/dist/digest/digest-paths.d.ts +0 -6
  222. package/dist/digest/digest-paths.d.ts.map +0 -1
  223. package/dist/digest/digest-paths.js +0 -14
  224. package/dist/digest/digest-paths.js.map +0 -1
  225. package/dist/digest/digest-rows.d.ts +0 -346
  226. package/dist/digest/digest-rows.d.ts.map +0 -1
  227. package/dist/digest/digest-rows.js +0 -2
  228. package/dist/digest/digest-rows.js.map +0 -1
  229. package/dist/schemes/Skill.d.ts.map +0 -1
  230. package/dist/schemes/Skill.js.map +0 -1
  231. package/dist/server/DaemonModule.d.ts +0 -101
  232. package/dist/server/DaemonModule.d.ts.map +0 -1
  233. package/dist/server/DaemonModule.js +0 -2
  234. package/dist/server/DaemonModule.js.map +0 -1
  235. package/dist/server/SkillSource.d.ts +0 -37
  236. package/dist/server/SkillSource.d.ts.map +0 -1
  237. package/dist/server/SkillSource.js +0 -267
  238. package/dist/server/SkillSource.js.map +0 -1
  239. package/dist/server/SkillsFunctionality.d.ts +0 -45
  240. package/dist/server/SkillsFunctionality.d.ts.map +0 -1
  241. package/dist/server/SkillsFunctionality.js +0 -405
  242. package/dist/server/SkillsFunctionality.js.map +0 -1
  243. package/dist/server/skills-problems.d.ts +0 -8
  244. package/dist/server/skills-problems.d.ts.map +0 -1
  245. package/dist/server/skills-problems.js +0 -18
  246. package/dist/server/skills-problems.js.map +0 -1
  247. package/dist/share/Share.d.ts +0 -15
  248. package/dist/share/Share.d.ts.map +0 -1
  249. package/dist/share/Share.js +0 -106
  250. package/dist/share/Share.js.map +0 -1
  251. package/dist/share/share.sql +0 -6
  252. package/docs/skills.md +0 -73
  253. /package/dist/{digest → evidence}/digest.sql +0 -0
package/SPEC.md CHANGED
@@ -18,7 +18,7 @@ Canonical contracts plurnk-service exposes, architecture it implements, promises
18
18
  - [Proposals and client interactions](#proposal-proposals-and-client-interactions)
19
19
  - [Stream Model](#stream-stream-model)
20
20
  - [Storage Model](#storage-model)
21
- - [Plugin composition](#core-plugin-composition-plugin-composition)
21
+ - [Extension composition](#core-extension-composition-extension-composition)
22
22
  - [Bundled Set](#bundled-set-bundled-set)
23
23
  - [Grammar Dependency](#grammar-dependency)
24
24
  - [Operator Configuration](#operator-config-operator-configuration)
@@ -55,7 +55,7 @@ flowchart LR
55
55
  | **workspace** | Core | Durable user-named shared world. Persists across workers and process restarts. Identity: `workspaces.id` + unique `workspaces.name`. |
56
56
  | **worker** | Core | Durable actor and 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. |
57
57
  | **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 execution timeout ({§operator-config-loop-timeout}) · 508 runaway}. Many loops may belong to one worker. |
58
- | **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)`. |
58
+ | **turn** | Core | One durable, producer-neutral batch of ordered operations. A turn may be authored by a model, client, 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)`. |
59
59
  | **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)`. |
60
60
  | **op** | Producer/core | One DSL operation a producer submits, parsed into a `PlurnkStatement`. Admission follows {§turn-ops-admission-path}. |
61
61
  | **statement** | Model/core | A parsed op: the `PlurnkStatement` AST from `@plurnk/plurnk-contracts`. |
@@ -72,7 +72,7 @@ flowchart LR
72
72
  |---|---|
73
73
  | **entry** | The unit of canonical state. Identity: `(workspace_id, scheme, authority, pathname)` ({§entry-identity-no-null}). Holds one or more `channels` of content plus scheme-private `attributes`. |
74
74
  | **channel** | A named content buffer on an entry. Examples: `body`, `stdout`, `stderr`, `headers`, `symbols`. Each channel has `content`, `mimetype`, curation `weight`, and lifecycle `state`. |
75
- | **scheme** | An addressed capability family + handler. Built-ins include `worker`, `log`, `ops`, `reasoning`, and bare/file paths; discovered schemes and executor-runtime tags extend that set. Internal `exec` routes executions but is not an addressable model namespace. Consumption surface {§scheme-surface}; author contract: [plurnk-schemes](../plurnk-schemes/SPEC.md). |
75
+ | **scheme** | An addressable namespace and its handler. Built-ins include `worker`, `log`, `ops`, `reasoning`, and bare/file paths; discovered schemes and executor-runtime tags extend that set. Internal `exec` routes executions but is not an addressable model namespace. Consumption surface {§scheme-surface}; author contract: [plurnk-schemes](../plurnk-schemes/SPEC.md). |
76
76
  | **mimetype** | A channel's content type. Drives the handler that produces the structural projections (`symbols`, `deepJson`, `deepXml`). Consumption surface {§mimetype}; author contract: [plurnk-mimetypes](../plurnk-mimetypes/SPEC.md). |
77
77
  | **provider** | An LLM transport implementing the `@plurnk/plurnk-providers` `Provider` interface. Core supplies an assembled request and generation context; the provider owns endpoint adaptation and normalized response evidence. Consumption surface {§provider-surface}; author contract: [plurnk-providers](../plurnk-providers/SPEC.md). |
78
78
 
@@ -91,9 +91,9 @@ Independent axes on entries and channels. Confusion across them is a recurring s
91
91
 
92
92
  | Term | Meaning |
93
93
  |---|---|
94
- | **writer** | The identity authoring a write. One of `model \| client \| _plurnk \| plugin`. Carried on `ctx.writer` for schemes; engine enforces `manifest.writableBy`. |
94
+ | **writer** | The identity authoring a write. One of `model \| client \| _plurnk`. Carried on `ctx.writer` for schemes; engine enforces `manifest.writableBy`. |
95
95
  | **origin** | Synonym for writer in log_entries (`log_entries.origin`). Synonym for writer. |
96
- | **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). |
96
+ | **writable_by** | The set of writers a scheme accepts. Subset of `{model, client, _plurnk}`; empty means no operation writes the scheme. Engine rejects writes outside the set with 403; the rejection is logged as the action-entry ({§subscriptions} action-entry-as-outcome). |
97
97
 
98
98
  ### Execution terms
99
99
 
@@ -133,7 +133,7 @@ package map. The default installed composition is specified in {§bundled-set}.
133
133
 
134
134
  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.
135
135
 
136
- 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 makes observability unavailable with a configuration diagnostic ({§configuration-repair-path}); offline checking rejects the same input before loading an SDK. 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.
136
+ 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 makes observability unavailable with a configuration diagnostic ({§configuration-repair-path}); offline checking rejects the same input before loading an SDK. 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 extension 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.
137
137
 
138
138
  §observability-genai-conventions **GenAI convention projection.** Provider
139
139
  request spans follow the [GenAI registry at `c88d504`](https://github.com/open-telemetry/semantic-conventions-genai/tree/c88d504ab3d9879f8e50d3cc87e69775e11db234),
@@ -157,39 +157,39 @@ draft convention is projected.
157
157
  The process and package map is ARCHITECTURE.md's; this package's AGENTS.md maps core's internal
158
158
  owners. Capability-specific behavior remains with the owning plug point.
159
159
 
160
- §service-worker-composition The service launcher and the live/demo workspace
161
- helper share one registration of default worker-facing modules: MCP, outbound
162
- A2A, and Schedule. Their management families and readable reference documents are
160
+ §service-worker-composition The service launcher composes no module: it and the live/demo
161
+ workspace helper both discover AG-UI, A2A, MCP, Schedule and command hooks ({§module-discovery}). The
162
+ management families and readable reference documents are
163
163
  present even with no enabled definitions. Workspace capability policy controls every actor's
164
164
  surface; registering a family does not enable its definitions. The real-model
165
165
  profile ({§operator-config-real-model-profile}) leaves ambient MCP attachments and
166
166
  service schedules disabled by default; specimens may add their own through the
167
- ordinary management surface. Client and
168
- inbound-A2A listeners and host hooks remain launcher-owned.
167
+ ordinary management surface. The one listener is the launcher's ({§http-host}); the helper binds
168
+ none, so its daemon leaves out AG-UI ({§module-http-mounts}).
169
169
 
170
170
  ### §service-package-exports Package export surface
171
171
 
172
172
  | Export path | Current contract |
173
173
  |---------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
174
- | `@plurnk/plurnk-service` | Frozen 1.x compatibility barrel of the exports below. It gains no new APIs and is not the client boundary. Removal is SemVer-major. |
175
- | `@plurnk/plurnk-service/digest` | Supported programmatic forensic surface owned by {§digest-programmatic-surface}. |
174
+ | `@plurnk/plurnk-service` | Legacy internal exports listed below. It gains no new APIs and is not the client boundary. Extracted capabilities belong to their owning packages, without compatibility aliases. |
175
+ | `@plurnk/plurnk-service/evidence` | Canonical evidence reader consumed by the separate report package ({§digest-evidence-reader}). |
176
176
  | `@plurnk/plurnk-service/package.json` | Supported package metadata surface. |
177
177
 
178
178
  | Root exports | Names |
179
179
  |--------------|-------|
180
- | Runtime | `Daemon`, `Engine`, `EnvFlags`, `Exec`, `File`, `Log`, `Mimetypes`, `Mock`, `Paths`, `SchemeRegistry`, `Skill` |
180
+ | Runtime | `Daemon`, `Engine`, `EnvFlags`, `Exec`, `File`, `Log`, `Mimetypes`, `Mock`, `Paths`, `SchemeRegistry` |
181
181
  | Types | `ChatMessage`, `EditResult`, `FlagDescriptor`, `MockAssistant`, `MockResponse`, `OpenFoldResult`, `ReadResult` |
182
182
 
183
183
  New clients use AG-UI. A new library contract belongs in its owning package or
184
- an explicitly specified subpath, not in the frozen root barrel.
184
+ an explicitly specified subpath, not in the legacy root barrel.
185
185
 
186
186
  ### §startup-admission Startup admission
187
187
 
188
188
  ```mermaid
189
189
  flowchart LR
190
- LISTENER["Bind client listener<br/>unready: HTTP 503"] --> DB["Acquire daemon lock<br/>and admit SQLite schema"]
191
- DB --> DAEMON["Construct and start<br/>daemon composition"]
192
- DAEMON --> CLIENT["Activate client transport"]
190
+ LISTENER["Bind the daemon's listener<br/>unadmitted: HTTP 503"] --> DB["Acquire daemon lock<br/>and admit SQLite schema"]
191
+ DB --> DAEMON["Start the daemon:<br/>discover and start modules"]
192
+ DAEMON --> CLIENT["Admit the listener"]
193
193
  CLIENT --> SELECT["Worker selects or first uses a model"]
194
194
  SELECT --> PROVIDER["Construct and verify<br/>selected provider"]
195
195
  LISTENER -. failure .-> FAIL["Fail startup<br/>durable state untouched"]
@@ -202,9 +202,9 @@ flowchart LR
202
202
  ({§http-host}) before creating, opening, replacing, rotating, migrating, or
203
203
  otherwise mutating anything in the durable data directory. A process that loses
204
204
  the listener race fails with the originating address error and byte-identical
205
- durable storage. Core owns the socket continuously; it answers 503 until the
206
- client-interface module mounts the root at daemon activation, so early
207
- ownership introduces neither traffic nor a close/rebind race.
205
+ durable storage. Core owns the socket continuously; it answers 503 until daemon
206
+ activation admits it after every module has started ({§module-http-mounts}), so
207
+ early ownership introduces neither traffic nor a close/rebind race.
208
208
 
209
209
  §http-host **The daemon opens exactly one transport.** Core binds the HTTP
210
210
  listener on `PLURNK_HOST:PLURNK_PORT` and offers it to every exterior adapter as
@@ -212,11 +212,11 @@ listener on `PLURNK_HOST:PLURNK_PORT` and offers it to every exterior adapter as
212
212
  ({§application-port}). A prefix is an absolute pathname. Each request goes to the
213
213
  longest mounted prefix; a prefix claims itself and the subtree beneath it, never
214
214
  a longer sibling name; `/` is the root and receives whatever nothing more
215
- specific claimed. Until a root is mounted the listener answers `503
215
+ specific claimed. Until daemon activation admits it the listener answers `503
216
216
  service-starting` to every request: the service has not admitted its client
217
- interface. Adapters mount at `start()`, after durable lifecycle recovery, and
218
- none opens a socket of its own under the daemon — a module hosted *without* a
219
- daemon may bind a private one, which is outside this contract. The standards
217
+ interface. Adapters claim their prefixes before setup and mount them at
218
+ `start()`, after durable lifecycle recovery ({§module-http-mounts}), and
219
+ none opens a socket of its own. The standards
220
220
  address by URL, never by port (#641): AG-UI mounts `/` and `/agui`, A2A the
221
221
  well-known card and its endpoint path, on the same address.
222
222
 
@@ -277,7 +277,7 @@ filter a row.
277
277
 
278
278
  §actor-boundary-attached-functionality **Attachment selects a conversation,
279
279
  not an environment owner.** Client management commands mutate workspace
280
- Functionality ({§module-workspace-capabilities}); executable families, runtime
280
+ Functionality ({§module-workspace-capabilities}); runtimes, runtime
281
281
  schemes, and tools resolve by `workspaceId`. Operations journal in the
282
282
  submitting actor's `workerId` ({§connection-lifecycle}), which must belong to
283
283
  the workspace. Runtime and policy resolution require no second worker identity.
@@ -363,7 +363,6 @@ narrow or omit the reference catalogs under {§capability-admission}.
363
363
  | Project filesystem | `*` | File cap below; `project root member files` |
364
364
  | Workspace entries | `worker:///*` | Markerless; `workspace knowledgebase entries` |
365
365
  | Named scratch entries | `worker://<worker>/*` | Markerless; `worker knowledgebase entries` |
366
- | The worker's own reasoning | `reasoning://<worker>/**` | Markerless; `this worker's reasoning, by loop and turn` |
367
366
 
368
367
  Only the three namespace surveys carry asides; the other targets name
369
368
  their surface. The word `skills` names Agent Skills and nothing else.
@@ -371,7 +370,7 @@ Catalogs select documents independently of their authored bodies; ordinary READ
371
370
  supplies examples and complete instructions on demand. A shallow
372
371
  result renders direct entries normally and every deeper first-segment directory
373
372
  as an actionable `dir/**` summary with its recursive `items` and `tokens`;
374
- tool-family rows also carry the concise `{§scheme-catalog-aside}` that drives
373
+ runtime rows also carry the concise `{§scheme-catalog-aside}` that drives
375
374
  on-demand capability discovery. Ordinary surveys use FIND without a scope
376
375
  ({§markerless-first-page}), whose range metadata reports the returned set against the
377
376
  complete result total; only the small capability-reference surfaces
@@ -460,7 +459,7 @@ existing workspace worker in its own right.
460
459
 
461
460
  §machine-processes-model-worker-readable **Packet membership is per-worker, not an access policy.** A packet contains its worker's log plus explicitly delivered activity ({§actor-boundary}). `readLog({ workspaceId, workerId })` may inspect any worker belonging to that workspace, and `listWorkers` enumerates them. A client-interface module chooses its conversation binding. Inspection does not inject another log into a model's packet.
462
461
 
463
- §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 WORK/FORK from the parent. A turn's producer is independent: a plugin-produced program in a model worker still delegates model workers. `listWorkers` returns actor class without interpreting names; a retained worker's name is immutable ({§machine-processes-worker-is-its-log}).
462
+ §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 WORK/FORK from the parent. A turn's producer is independent: a client-produced program in a model worker still delegates model workers. `listWorkers` returns actor class without interpreting names; a retained worker's name is immutable ({§machine-processes-worker-is-its-log}).
464
463
 
465
464
  §worker-provider-identity **A worker owns a durable provider identity distinct
466
465
  from its database id.** Creation mints a globally unique, opaque 128-bit value;
@@ -914,12 +913,6 @@ move it. The digest reports, per loop, the claim time and how long after it the
914
913
  first model turn started, so a stall between claim and inference (a heartbeat has
915
914
  waited 7.5 h, #703) is a number rather than a gap.
916
915
 
917
- §digest-storage **The digest states the file's health.** Beside the database path it
918
- reports the file size, the free pages it holds, its `auto_vacuum` mode, and the six
919
- largest tables and indexes by allocated bytes (`dbstat`), so growth is a number in
920
- every digest (#764). The digest reads loops as stored, so it tolerates databases
921
- missing later lifecycle columns.
922
-
923
916
  §loop-execution-allowance **One task has one execution allowance.** The first
924
917
  execution snapshots `PLURNK_SERVICE_LOOP_TIMEOUT` on the loop. Active segments
925
918
  consume that allowance cumulatively, measured with a monotonic clock; waits and
@@ -1093,11 +1086,11 @@ boundary.
1093
1086
 
1094
1087
  A turn is the durable container for one producer's ordered operations. Packet
1095
1088
  and provider fields are optional evidence belonging only to model inference;
1096
- their absence never makes a client, plugin, or `_plurnk` turn exceptional.
1089
+ their absence never makes a client or `_plurnk` turn exceptional.
1097
1090
 
1098
1091
  | Field | Contract |
1099
1092
  |---|---|
1100
- | `producer` | Required actor class: `model`, `client`, `plugin`, or `_plurnk`. |
1093
+ | `producer` | Required actor class: `model`, `client`, or `_plurnk`. |
1101
1094
  | `kind` | Required purpose: `inference`, `initialization`, `operation`, or `maintenance`. Model iff inference; initialization and maintenance require `_plurnk`. Producer and kind are immutable. A maintenance turn's successful rows are packet-suppressed — a receipt answers an asker, and maintenance has none ({§actor-boundary-doc-injection}). |
1102
1095
  | `status`, `completed_at` | A new turn is open at status 102 with `completed_at=NULL`. Completion records the program outcome and timestamp; a completed 102 is distinct from an open 102. A successful administrative program completes at 200 without concluding its host model loop. |
1103
1096
  | 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. |
@@ -1106,9 +1099,8 @@ their absence never makes a client, plugin, or `_plurnk` turn exceptional.
1106
1099
 
1107
1100
  One lifecycle owner opens, optionally records inference evidence, and completes
1108
1101
  every turn. Initialization, maintenance, client dispatch, and model
1109
- inference use that same path. `plugin` is the producer identity for
1110
- plugin-authored operation turns; exposing that path must not introduce a
1111
- parallel record or lifecycle. Producer and kind never change. Process-restart
1102
+ inference use that same path; a new producer joins it without a parallel
1103
+ record or lifecycle. Producer and kind never change. Process-restart
1112
1104
  recovery completes any turn whose producer vanished.
1113
1105
 
1114
1106
  §turn-exception-outcome An exceptional inference exit completes every still-open
@@ -1122,7 +1114,7 @@ The turn owner propagates the original exception unchanged.
1122
1114
  | An `AggregateError` combining cancellation with other failures | 500; cancellation does not conceal another failure. |
1123
1115
 
1124
1116
  §turn-ops-admission-path **Source acquisition varies; admitted-turn execution does not.**
1125
- A provider response, deterministic `_plurnk` program, or future client/plugin
1117
+ A provider response, deterministic `_plurnk` program, or future client
1126
1118
  program crosses one admission boundary into the same executor. That executor
1127
1119
  parses once, dispatches the admitted statements in order, records their ordinary
1128
1120
  outcomes, and completes the turn from its lifecycle ruling. Exact source is retained before dispatch.
@@ -1333,7 +1325,11 @@ Provider interruption is owned by {§provider-interrupted-attempt}. Accepted sou
1333
1325
  and positions remain exact; execution follows {§op-execution-order}. WAIT remains
1334
1326
  optional, with no omission warning or invented operation ({§turn-shape}).
1335
1327
 
1336
- §safe-uri-target-groups After source and authored-command admission, Core expands one target group on READ or KILL into one ordinary statement per member, each with an independent dispatch outcome and log row, in authored member order at that operation's position under {§op-execution-order}. A group is either the heading's slot group ({§target-group}) — any target kind, each member with the scope, metadata and matcher its own slot carried, the heading's naked pattern every member's, and a distilling body landing once with the first member — or one slot whose raw target splits at top-level comma or whitespace separators into at least two members that each independently parse as an explicit `scheme://` URI, the selection shared; request-metadata blocks are opaque to that split, and otherwise the slot's target remains exactly singular, including local filenames containing spaces or commas. The same expansion meets a client-authored group at the client seam. The stored `turnOps` and authored command count remain unexpanded, a group never reaches dispatch unexpanded, and no other operation admits target groups.
1328
+ The parser compiles target groups ({§target-group}, {§safe-uri-target-groups}) into ordinary
1329
+ statements before model or client admission. Core does not reinterpret target syntax. Each
1330
+ admitted member receives its independent dispatch outcome and log row, in authored order under
1331
+ {§op-execution-order}; one member's runtime failure does not suppress later members. The original
1332
+ emission in `turn_sources` remains exact and unexpanded.
1337
1333
 
1338
1334
  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 `inference_calls` row with its `model_calls` specialization and 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 logical 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 `<stem>.attemptNNN.rejected.*` and every physical request in its machine-readable ledger.
1339
1335
 
@@ -1371,10 +1367,10 @@ interrupted response evidence, Core stores it unaccepted without duplicating its
1371
1367
  accounting. The failed turn still stores the exact request and never fabricates
1372
1368
  an assistant or a zero-valued observation.
1373
1369
 
1374
- ### §attribution Plugin-authored attribution folksonomy
1370
+ ### §attribution Extension-authored attribution folksonomy
1375
1371
 
1376
- A plugin may declare opaque attribution tags statically or at runtime under the
1377
- shared contract {§plugin-attribution}:
1372
+ An extension may declare opaque attribution tags statically or at runtime under the
1373
+ shared contract {§extension-attribution}:
1378
1374
 
1379
1375
  ```jsonc
1380
1376
  { "plurnk": { "attribution": "@acme/widgets" } } // always-on string or string[]
@@ -1382,14 +1378,14 @@ shared contract {§plugin-attribution}:
1382
1378
 
1383
1379
  | Stage | Contract |
1384
1380
  | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1385
- | Collection | Immediately before each emission attempt, Core pulls the admitted scheme, executor, loaded mimetype-handler, and selected provider sources. A BARE call pulls only its selected provider source because it admits no other plugin capability. |
1381
+ | Collection | Immediately before each emission attempt, Core pulls the admitted scheme, executor, loaded mimetype-handler, and selected provider sources. A BARE call pulls only its selected provider source because it admits no other extension. |
1386
1382
  | Composition | Core flattens, deduplicates, and sorts the tags. The resulting non-empty array rides `generate({ attributions })`; an empty set omits that provider field. |
1387
- | Meaning | Core neither verifies nor infers contribution. Tags are plugin-authored folksonomy for telemetry, optimization, attribution, or downstream rules. The `@plurnk/` reservation is the only namespace policy ({§plugin-attribution}). |
1383
+ | Meaning | Core neither verifies nor infers contribution. Tags are extension-authored folksonomy for telemetry, optimization, attribution, or downstream rules. The `@plurnk/` reservation is the only namespace policy ({§extension-attribution}). |
1388
1384
  | Request evidence | The stored request packet carries the exact set most recently forwarded for that turn. Every generation-kind `inference_calls` row carries that call's exact set, including response-less failures. |
1389
1385
  | Derived reporting | Turn, loop, digest, and client views project the recorded sets. `loop/terminated.attributions` is their deduplicated sorted union and remains separate from provider usage and charge evidence. |
1390
1386
 
1391
- Runtime hooks are synchronous and receive only the attempt coordinates. A hook
1392
- failure is an internal plugin-contract failure; Core does not silently discard
1387
+ Runtime `attributions` functions are synchronous and receive only the attempt coordinates.
1388
+ A function's failure is an internal extension-contract failure; Core does not silently discard
1393
1389
  it or reinterpret a malformed tag list.
1394
1390
 
1395
1391
  §client-metadata **The workspace records which frontend opened it.** A frontend self-identifies (e.g. `@plurnk/plurnk-tui/1.4.0`) at `workspace.create({ settings: { client } })` and the daemon stores it with the workspace. It is validated on write, never forwarded to a provider, and never model-facing. Workspace-stable and self-reported — distinct from attribution's install-grounded tags — and omitted when unset.
@@ -1402,7 +1398,7 @@ it or reinterpret a malformed tag list.
1402
1398
  service-side caching, per-loop selection, context-cap handling, and admission
1403
1399
  of an operator's grammar. Cataloged providers use Models.dev metadata and official AI SDK
1404
1400
  bindings; an operator declaration covers an uncataloged compatible endpoint;
1405
- plugin discovery is the last protocol-extension seam. Cache identity includes
1401
+ a provider extension is the last seam for a new protocol. Cache identity includes
1406
1402
  the alias, wire route, and complete provider-knob projection; a registered
1407
1403
  preconstructed handle occupies that same identity and cannot shadow changed
1408
1404
  tuning.
@@ -1445,7 +1441,7 @@ First path segment = provider name; rest = provider-native model id.
1445
1441
 
1446
1442
  ### Mock provider (sibling fixture)
1447
1443
 
1448
- §mock-provider-mock-fixture `Mock` (exported from `@plurnk/plurnk-providers`) — intg fixture + reference implementation. `{ contextWindow, responses }` constructor; `generate` shifts from the queue. `MockResponse.assistant.ops?: PlurnkStatement[]` is a pre-parsed escape hatch the engine consumes directly when present; production providers don't expose this — and being a plugin export, this contract has no service-side `§`-ref.
1444
+ §mock-provider-mock-fixture `Mock` (exported from `@plurnk/plurnk-providers`) — intg fixture + reference implementation. `{ contextWindow, responses }` constructor; `generate` shifts from the queue. `MockResponse.assistant.ops?: PlurnkStatement[]` is a pre-parsed escape hatch the engine consumes directly when present; production providers don't expose this — and being a package export, this contract has no service-side `§`-ref.
1449
1445
 
1450
1446
  ---
1451
1447
 
@@ -1528,7 +1524,7 @@ Folders and globs select members in those same filesystem coordinates. Parent-di
1528
1524
 
1529
1525
  ### File scheme: creation and misses
1530
1526
 
1531
- §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`. A COPY or MOVE destination scope on an absent channel resolves against its empty pre-mutation value under {§empty-mutation-scope}; a valid scope creates the channel with the selected source as its complete value. A coordinate outside that empty value is 416. Binary scopes remain numeric byte positions or ranges under {§binary-parity}.
1527
+ §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, or `_plurnk`. A COPY or MOVE destination scope on an absent channel resolves against its empty pre-mutation value under {§empty-mutation-scope}; a valid scope creates the channel with the selected source as its complete value. A coordinate outside that empty value is 416. Binary scopes remain numeric byte positions or ranges under {§binary-parity}.
1532
1528
 
1533
1529
  | Case | Required admission | Accepted result |
1534
1530
  |------|--------------------|-----------------|
@@ -1583,7 +1579,7 @@ Every fact names the canonical key, never the host root or an echo of the
1583
1579
  model's spelling. These classes let a caller distinguish a wrong address, an
1584
1580
  invalid range, read-only authority, and occupied hidden state without guessing.
1585
1581
 
1586
- §membership-read-refusal **A file miss speaks of membership, never of the disk.** A file is read only as a member, so every `file` miss — READ, FIND of an exact path, KILL, a COPY or MOVE source — is 404 `entry-not-found`, `No member of this workspace is at '<key>'.` Recovery treats path correction with FIND, creation with EDIT, and admission with `members (add)` as alternatives; it must not presume a missing READ requires creation or admission. Admission takes a `{"glob": "<path>"}` body. The sentence is about the address and is true whether or not a file is there: it neither claims absence nor hints at presence. Beyond the root the engine does not look at the disk at all, so two reads of `../` paths differ only in the name they echo. Inside the root occupancy is not secret ({§fs-write-nonmember}), so an exact-path READ of a path that exists on disk but is not a member says so instead — 404 `entry-not-member`, `'<key>' exists on disk but is not a member of this workspace.`, with admission-only recovery. Occupancy may surface there; content never does ({§membership}).
1582
+ §membership-read-refusal **A file miss speaks of membership, never of the disk.** A file is read only as a member, so every `file` miss — READ, FIND of an exact path, KILL, a pattern EDIT's source, a COPY or MOVE source — is 404 `entry-not-found`, `No member of this workspace is at '<key>'.`, its target rendered as the member key, never a `file://` URI. Recovery treats path correction with FIND, creation with EDIT, and admission with `members (add)` as alternatives; it must not presume a missing READ requires creation or admission. Admission takes a `{"glob": "<path>"}` body. The sentence is about the address and is true whether or not a file is there: it neither claims absence nor hints at presence. Beyond the root the engine does not look at the disk at all, so two reads of `../` paths differ only in the name they echo, and their recovery speaks of the address too, true under every members scope: `'<key>' is outside the project root: only a members definition under the operator's namespace scope admits it, so keep working files inside the root.` Inside the root occupancy is not secret ({§fs-write-nonmember}), so an exact-path READ of a path that exists on disk but is not a member says so instead — 404 `entry-not-member`, `'<key>' exists on disk but is not a member of this workspace.`, with admission-only recovery; a path the repository ignores, which no model definition admits, carries the members discovery verdict instead: `The repository ignores it: a client or operator members definition can include it, a model definition cannot.` Occupancy may surface there; content never does ({§membership}).
1587
1583
 
1588
1584
  §file-directory-target **A directory is named as a directory.** Inside the root, a READ (or other exact-path read), KILL or EDIT whose target is a directory on disk — with or without a trailing slash — is refused `path-is-directory`, never as a missing or non-member file, since admitting it is not what the model needs: READ and KILL answer 404, EDIT 403. The detail is `'<key>' is a directory, not a file; <OP> reads/removes/writes one file.` and the recovery names the listing that reaches its files, `` List its files with `FIND (<key>/)`, then READ one by its path. `` (KILL: `then KILL each by its path`; EDIT: `` Name a file inside it, as `EDIT (<key>/<file>)`; list its files with `FIND (<key>/)`. ``). Beyond the root the disk stays dark and {§membership-read-refusal} holds unchanged.
1589
1585
 
@@ -2425,28 +2421,29 @@ like any other row.
2425
2421
  | When | An inference turn that admitted at least one content statement. Reasoning-only turns, including initialization ({§worker-initialization-entry}), a programmatic batch, an empty turn ({§empty-turn}), a client operation and a rejected attempt ({§rejected-emission-entry}) announce nothing. |
2426
2422
  | Place | After the turn's inputs (arrivals, deltas, open-path READs) and before its reasoning NOTEs and operations, written after the selection snapshot ({§turn-ops-selection-snapshot}): the emission sits between what the worker had seen and what it caused. |
2427
2423
  | Row | A `_plurnk` READ of the turn's own source, `ops://<worker>/L/T`, with `attrs.kind="emission"` and the canonical leaf `/emission`: `### log:///L/T/S/emission → ops://<worker>/L/T · N`. It renders its author, the turn's producer, as `origin`, so a model's row carries none. It is no operation: no receipt, tool call or strike, and outside the op mix. |
2428
- | Body | Frozen at announcement: the canonical rendering ({§statement-rendering}) of admitted content statements, each in a closed fence. Each body appears as its head, about a hundred tokens of curation weight — enough to recognise the turn, never enough to matter to the budget ({§context-fit}) — and a longer body ends in an ellipsis (`…`) with its closing fence carrying `<!-- … READ (ops://<worker>/L/T) -->`; nothing the harness writes enters a fence. Absent and empty bodies remain empty. All heading operands, scopes, metadata, patterns and asides remain. Free text and unadmitted forms are absent; a recovered native call ({§native-tool-calls}) appears as the operation it was read as; an operation whose receipt failed stays. Reasoning operations retain their own source and normal receipts, never an assistant-content copy. No body text is inspected for nested operations. |
2429
- | Sources and memory | Dispatch and immutable `ops://` sources retain complete bodies ({§turn-source-resources}); an explicit source READ returns them normally. The wire omits NOTE and WAIT blocks, whose own rows show them whole ({§body-projection}), so curating a NOTE row removes its text; an emission of only NOTE and WAIT delivers nothing, its row stands, and no assistant message follows it ({§packet-wire-envelope}); reasoning-only NOTEs never enter this projection. |
2424
+ | Body | Frozen at announcement: the canonical rendering ({§statement-rendering}) of the admitted content statements, each whole in a closed fence. All heading operands, scopes, metadata, patterns and asides remain. Free text and unadmitted forms are absent; a recovered native call ({§native-tool-calls}) appears as the operation it was read as; an operation whose receipt failed stays. Reasoning operations retain their own source and normal receipts, never an assistant-content copy. No body text is inspected for nested operations. |
2425
+ | Wire | Bodies are logged, never replayed (#1018). The wire shows a statement with a body as its heading and an empty closer, and one without a body as its heading closed on the same line, so the shape says whether a body was left out. A NOTE or WAIT, and a parameterless KILL or SEND, is not replayed at all, since its own row shows it whole ({§body-projection}); an emission of only those delivers nothing, its row stands, and no assistant message follows it ({§packet-wire-envelope}). Dispatch and the immutable `ops://` source keep complete bodies ({§turn-source-resources}); an explicit READ returns them, as it returns a receipt. |
2430
2426
  | Stability | The projection is fixed from its first appearance, never aged or resized under budget pressure. Already frozen announcements and historical request captures are not rewritten. |
2431
2427
  | Presentation | Born folded: the record shows its header, and its body follows the record as the worker's assistant message. |
2432
- | Accounting | `tokens` charges the record and the emission the wire delivers, truncation asides included, never the omitted NOTE and WAIT blocks or the cut remainder ({§packet-token-accounting}). An explicit source READ has its own ordinary charge. |
2428
+ | Accounting | `tokens` charges the record and the emission the wire delivers, never what the wire leaves out ({§packet-token-accounting}). An explicit source READ has its own ordinary charge. |
2433
2429
  | Curation | Curated whole ({§log-kill-scope}): KILL retires it, and so does a scope covering every line (`<1,-1>`); on its exact coordinate a narrower scope is 422 `emission-curated-whole`, and a sweep whose scope would only trim it leaves it intact. |
2434
2430
  | Schema | Migration 12 admits `kind="emission"` only on this shape: one per turn, the turn's newest row when written, frozen, and curated whole. A database from before version 12 keeps its rows and gains no announcement. FORK copies it with the inherited turns, still naming its writer. |
2435
- | Echoes | A worker that repeats the heading in its own text is tolerated ({§fabricated-log-entry}); the digest counts the echoes. A worker that copies the truncation aside onto its own closer keeps its body intact; the aside is outside text ({§outside-text}). |
2431
+ | Echoes | A worker that repeats the heading in its own text is tolerated ({§fabricated-log-entry}); the digest counts the echoes. |
2436
2432
 
2437
2433
  ### §reasoning-row The reasoning row
2438
2434
 
2439
2435
  The model's memory of its own reasoning, behind `PLURNK_SERVICE_REASONING_ROWS` (default `1`):
2440
2436
  when it is `1`, every model turn that reasoned lands its reasoning as one row of its
2441
2437
  own, `log:///<loop>/<turn>/<sequence>/reasoning → reasoning://<worker>/<loop>/<turn>`, the harness's
2442
- READ of the turn's reasoning source, immediately before the turn's emission row, so the transcript
2438
+ READ of the turn's reasoning source, immediately before the turn's emission row (or its first
2439
+ operation or diagnostic when there is no content emission), so the transcript
2443
2440
  reads what the model thought and then what it emitted, and the assistant message that follows stays
2444
2441
  the canonical program ({§emission-row}, {§packet-wire-envelope}).
2445
2442
 
2446
2443
  | Concern | Rule |
2447
2444
  |---|---|
2448
- | Room | The row lands whole only when the packet has room for it after everything else the turn lands, one receipt's reserve kept for the emission row's head ({§context-fit}); without room, no row lands and nothing else in the turn changes: no prefix, no receipt, no other row touched. |
2449
- | Body | The model's own text, complete ({§markerless-first-page}); the complete reasoning stays readable at its address by any scope ({§turn-source-resources}). |
2445
+ | Room | Admission occurs after all mandatory turn rows, including the emission and diagnostics, using the remaining room under {§context-fit}. Its earlier chronological coordinate is reserved without inserting a placeholder; if it does not fit, that coordinate remains unused. Nothing else changes: no partial preview, refusal, or other row touched. Reasoning-only and empty model turns follow the same rule; content operations are not required. |
2446
+ | Body | The model's own text when it fits the row's page — `PLURNK_SERVICE_REASONING_TRAILING_LINES` lines, unset meaning the shared `PLURNK_SERVICE_PREVIEW_LINES`, within `PLURNK_SERVICE_PREVIEW_CHARS` — and otherwise its **last page**. Keep complete final lines where possible; if the last line alone exceeds the character bound, select its suffix with the ordinary exact column scope. Unicode code points count once and CRLF is one indivisible separator, as in {§body-projection}. The statement carries the scope it took and the receipt its `range` ({§packet-extent-metadata}); the complete reasoning stays readable at its address by any scope ({§turn-source-resources}). |
2450
2447
  | Weight | Charged like any row, visible in the gauge and its `largest` ({§context-gauge}). |
2451
2448
  | Curation | The verbs alone: a KILL retires it like any row ({§context-verbs}); the daemon reorders nothing and un-bodies nothing on its account. |
2452
2449
  | Absence | Means no room or no reasoning; the model tells them apart by reading `reasoning://` for the turn. |
@@ -2456,7 +2453,7 @@ the canonical program ({§emission-row}, {§packet-wire-envelope}).
2456
2453
  | Surface | Contract |
2457
2454
  |---|---|
2458
2455
  | Identity | `ops://<worker>/<loop>/<turn>`, `reasoning://<worker>/<loop>/<turn>`, and `note://<worker>/<loop>/<turn>/<item>` name a worker in the current workspace and its durable coordinates. A note's item is its dispatched NOTE ordinal. The `outside` source ({§outside-text}) has no address: no `outside://` scheme exists, and it is reached only through `outside/event`, FORK and the digest. The worker authority is required and case-sensitive; userinfo, ports, and queries are invalid. Source identity never depends on the reading worker. `log:///` remains local; READ, FIND and KILL reject log authorities, userinfo, ports and queries with 400, never substitute the caller's log. |
2459
- | Source | `ops` is exact admitted `text/vnd.plurnk`, and its turn's emission row carries the preview-bounded projection ({§emission-row}); `reasoning` is `text/plain` containing the selected original provider reasoning or a non-model producer's authored rationale. Producer identity comes from the owning turn; a harness rationale is not provider evidence. The turn decides existence and the source decides content: a turn that exists but has no source of that kind reads as the ordinary empty resource (204, empty body), never a fabricated one; a worker or turn that does not exist is 404. |
2456
+ | Source | `ops` is exact admitted `text/vnd.plurnk`, and its turn's emission row carries its canonical projection ({§emission-row}); `reasoning` is `text/plain` containing the selected original provider reasoning or a non-model producer's authored rationale. Producer identity comes from the owning turn; a harness rationale is not provider evidence. The turn decides existence and the source decides content: a turn that exists but has no source of that kind reads as the ordinary empty resource (204, empty body), never a fabricated one; a worker or turn that does not exist is 404. |
2460
2457
  | Notes | Each dispatched NOTE stores its exact literal body as an immutable `text/plain` source and returns its worker-qualified address. There may be multiple notes in a turn, from reasoning, content, or another producer. A missing note is 404, not an empty invented note. Sharing its URI uses ordinary SEND; the receiver deliberately READs it. NOTE itself sends no ambient update. |
2461
2458
  | Retention | One ops source, one reasoning source and one outside source per turn; one note source per NOTE ordinal. An optional inference-call link records provenance. Source removal follows deletion of its owning turn, never log curation. |
2462
2459
  | Operations | Ordinary scoped READ, FIND, content search and COPY from any named worker's source within the workspace. FIND accepts authority and path patterns, retaining complete worker-qualified identities in results and folder selectors. READ returns data and never executes it. Sources are read-only for every actor and have no edit hashes. |
@@ -2467,6 +2464,7 @@ the canonical program ({§emission-row}, {§packet-wire-envelope}).
2467
2464
  §rejected-emission-entry A rejected provider response is not `turnOps`: it never became an admitted turn program, and no emission row announces it ({§emission-row}). The one bounded invalid-emission recovery item under {§emission-admission} has `attrs.kind="emissionAttempt"`, `origin="model"`, the canonical model-facing `/attempt` leaf, and the exact latest rejected response. The packet does not duplicate that identity as `kind` metadata. It is born durably body-suppressed and projected visibly only in the informed recovery packet; every other rejected attempt remains forensic-only.
2468
2465
 
2469
2466
  - §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 ```` ```READ (worker:///docs/) ````. A complete `[start-end]` segment in any numeric coordinate slot selects that inclusive decimal interval; brackets elsewhere retain ordinary path-glob meaning. Every rendered row appends one canonical model-facing leaf: the native operation name or invoked executor name, `/attempt` for a rejected emission, `/emission` for an admitted one's announcement ({§emission-row}). An executor leaf is derived from the durable submitted statement (its `runtime`), never an internal dispatch type or the current tool registry. Digits and punctuation in executor names remain part of the leaf. The leaf names identity rather than adding a resource level. Exact consumers tolerate the unsuffixed three-part shorthand; when supplied, the case-insensitive leaf is authoritative and a disagreement resolves 404. READ anchors use the canonical suffixed identity even when addressed by shorthand. 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`, `log:///**/python3`, `log:///**/attempt`, and `log:///**/emission` deliberately filter canonical leaves. Executor outputs instead use workspace-wide claims such as `sh:///ab3d5678#stdout` ({§execution-output-identity}); their source operation has log coordinates, but resource lifetime and identity are independent of that observation. Error pointers, Problem instances, source attribution, and search use this same identity; client stream coordinates retain the numeric triple. Within a turn, sequence is arrival order. Inbound SEND rows publish before the program runs ({§message-arrival}); a turn receiving messages holds the first at `log:///L/T/1/SEND`, followed by further arrivals oldest first, then its emission's announcement, then the model's operations ({§packet-current-turn} names `L/T`).
2467
+ - §log-near-miss **A log miss beside rows that exist names them.** A READ, FIND or KILL of an exact coordinate that names no row carries a recovery from the worker's own active rows: the turn's rows carrying the leaf written come first, since the leaf is what the model asked for and the sequence its guess, followed by the row at that coordinate under its own leaf (`` Turn 1/44's reasoning is `log:///1/44/2/reasoning`; the entry at log:///1/44/1 is `log:///1/44/1/READ`. ``); with no row of that leaf, the row at the coordinate alone (`` The entry at log:///1/25/8 is `log:///1/25/8/sh`. ``), else the turn's rows, at most six named, else the loop's latest turn. A coordinate in a loop with no rows carries none. Recorded misses were near misses every time: a READ of `1/25/8/READ` when the row was `sh`, an EDIT one sequence off, and a KILL under the 413 that must curate (#1005).
2470
2468
  - §log-curation-folder-idiom **Log curation speaks the folder idiom; a zero-match sweep is a no-op success** — KILL takes 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: ```` ```KILL (log:///1/2) <1,-1> ```` suppresses turn 1/2's bodies and retires its emission ({§emission-row}). A **well-formed selection that matches nothing is 204 with `matched: 0`**; a successful sweep's rx carries `matched: N`. Parameterless KILL instead requests completion ({§kill-conclusion}).
2471
2469
  - §log-curation-set-selection **Row selection and body scope are independent** — target/glob and an optional heading pattern (```` ```KILL (log:///**) [{"pattern": "~stale"}] ````, every dialect a FIND over rows accepts) 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. An emission row is curated whole instead: the scope retires it when it covers every line and otherwise leaves it ({§emission-row}). Thus ```` ```KILL (log:///**/READ) <17,-1> ```` may change long READs and no-op on short ones while reporting every selected row in `matched`.
2472
2470
 
@@ -2686,12 +2684,12 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
2686
2684
 
2687
2685
  ### §find FIND
2688
2686
 
2689
- - §log-uniform-query **Log speaks the universal query contract** — ```` ```FIND (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`; `~` full-text 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}). 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.
2687
+ - §log-uniform-query **Log speaks the universal query contract** — ```` ```FIND (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`; `~` full-text 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}). 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 an extension seam and grants no protocol scheme an alternate READ path.
2690
2688
  - §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.
2691
2689
  - §find-line-anchors **A FIND regex anchors each line**, as READ, EDIT and KILL do ({§read-pattern}, {§edit-pattern}): `^` and `$` are a line's ends in every FIND content match — over entries, log rows, turn sources and a binary channel's bytes — so ```` ```FIND (django/urls/resolvers.py) /^from|^import/ ```` locates the same import lines a READ with that pattern shows, never a false 204.
2692
2690
  - §find-candidate-containment **One candidate's crash is that candidate's problem** — arbitrary member content can crash a mimetype handler mid-match (an unbalanced template partial crashed Readability and killed a 1,916-file FIND as a blank 500, #449). `Matcher.matchCandidates` contains a per-candidate handler throw: the candidate drops out exactly like unsupported content, the cause goes to daemon stderr, and only a FIND whose every candidate crashed reports a 415 whose Problem names the first crashing member and handler. The operation's other candidates always answer.
2693
2691
 
2694
- - §find-scope-prefix-filter Filters entries within scope. A **bare** path is the exact entry unless the file scheme resolves a directory under {§file-find-directory}; an explicit **shell glob**, classified once by {§path-glob}, expands to a scope. Path globs use segment semantics: `*` and `?` never cross `/`; `**` does — in every spelling: a `**` glued to a name (`**.go`, `src/**.ts`) is matched as `**/*.go` / `src/**/*.ts`, never demoted to a one-level `*` the way a native matcher reads it. 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.
2692
+ - §find-scope-prefix-filter Filters entries within scope. A **bare** path is the exact entry unless the file scheme resolves a directory under {§file-find-directory}; an explicit **shell glob**, classified once by {§path-glob}, expands to a scope. Path globs use segment semantics: `*` and `?` never cross `/`; `**` does — in every spelling: a `**` glued to a name (`**.go`, `src/**.ts`) is matched as `**/*.go` / `src/**/*.ts`, never demoted to a one-level `*` the way a native matcher reads it. 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 extension contract, never inferred from URL punctuation.
2695
2693
 
2696
2694
  Resource-authority globs select authorities independently of the path scope.
2697
2695
  Matching resources retain their full addresses through pattern matching,
@@ -2706,7 +2704,7 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
2706
2704
  matches the selected channel's content or derivation; path globs select
2707
2705
  resources through `(target)` ({§path-glob}).
2708
2706
  - §find-fulltext-selection Every matcher operates only over the candidate set selected by `(target)`; indexed matchers do not bypass that selection. `~query` passes the native FTS5 expression to SQLite and ranks matching candidates by ascending BM25, with resource identity breaking ties. Native BM25 uses the shared index's term statistics; candidate visibility, owner, channel and target filters determine which resources can be returned. The ordinary FIND pager selects resources for broad targets or match locations for exact targets: markerless search uses {§markerless-first-page}, `<N>` selects position N and `<N,M>` selects an inclusive range. Fractions are invalid result coordinates, not similarity thresholds. Results expose addressable matched text regions; neither cosine scores nor percentage similarity is invented. Native query-syntax failures return 400 with SQLite's diagnostic; database and implementation failures propagate.
2709
- - §fts-word-phrase **A word with inner punctuation is the phrase of its tokens.** FTS5 barewords hold only letters, digits, `_` and non-ASCII, so before the query reaches SQLite each word outside a quoted string or `NEAR(…)` group that is not a bareword (with optional leading `^` and trailing `*`) is quoted as a phrase: `~inherited-members` searches `"inherited-members"` — the adjacent tokens `inherited members` — instead of failing as `no such column: members`, and `c++`, `x.y`, `a/b` likewise. FTS5's own syntax passes untouched: `AND`/`OR`/`NOT`/`NEAR`, `+`, quoted phrases, parentheses, and column filters (a word containing `:`, `{` or `}`, or opening with `-`). A column-filter failure keeps SQLite's diagnostic and its recovery says what the filter is and gives the bare-word and `NOT` forms: `` `members:` and `-members` are FTS5 column filters, and the index has one column; to search for a word write it bare, as `~members`, and to exclude one write `NOT` between terms, as `~a NOT members`. ``
2707
+ - §fts-word-phrase **A word with inner punctuation is the phrase of its tokens.** FTS5 barewords hold only letters, digits, `_` and non-ASCII, so before the query reaches SQLite each word outside a quoted string or `NEAR(…)` group that is not a bareword (with optional leading `^` and trailing `*`) is quoted as a phrase: `~inherited-members` searches `"inherited-members"` — the adjacent tokens `inherited members` — instead of failing as `no such column: members`, and `c++`, `x.y`, `a/b` likewise. FTS5's own syntax passes untouched: `AND`/`OR`/`NOT`/`NEAR`, `+`, quoted phrases, parentheses, and column filters (a word containing `:`, `{` or `}`, or opening with `-`). A column-filter failure keeps SQLite's diagnostic and its recovery says what the filter is and gives the bare-word and `NOT` forms: `` `members:` and `-members` are FTS5 column filters, and the index has one column; to search for a word write it bare, as `~members`, and to exclude one write `NOT` between terms, as `~a NOT members`. `` A syntax error over parentheses or quotes, which FTS5 reads as its own syntax, recovers to the phrase and to the regex for the same characters: `` FTS5 reads parentheses and quotes as query syntax: quote the phrase, as `~"all("`, or match the characters with a regex, as `/all\(/`. `` (#1005).
2710
2708
  - §find-scoped-isolation Workspace + scheme scoped — no cross-workspace/cross-scheme leakage.
2711
2709
  - §find-result-projection **The resolved target selection determines the result unit; result cardinality never changes it** ({§find-result-unit}). Returns `FindResult { status, content, mimetype, results, range, matchingPathCount, matchLocationCount, itemsWeightTotal, returnedItemsWeightTotal }`:
2712
2710
 
@@ -2741,7 +2739,7 @@ Log history preserved — `log_entries` stores path tuple as text, not FK to `en
2741
2739
  derivation's `{§mimetype-summary}`. Prose is clipped to at most `PLURNK_SERVICE_CATALOG_SUMMARY_CHARS` Unicode
2742
2740
  code points including a visible terminal ellipsis, so a row stays one line
2743
2741
  of orientation; an invocation-form witness — a summary that is one fenced
2744
- operation, the shape every tool family's summary takes
2742
+ operation, the shape a runtime's tool summary takes
2745
2743
  ({§tools-resource-materialization}) — is shown whole, every tool named,
2746
2744
  because the discovery row exists so the model can invoke without a READ and
2747
2745
  a menu that is cut is no menu. Absent metadata is omitted.
@@ -2967,7 +2965,7 @@ of which Worker launched it ({§execution-output-identity}).
2967
2965
  | Backpressure | `PLURNK_SERVICE_EXEC_INPUT_TIMEOUT_MS` bounds each accepted delivery, including its queue residence. Expiry returns `504 input-timeout`; cancellation returns `499 input-cancelled`. Once delivery has begun, retire and abort input on either; delivery may be partial and is never replayed. The execution itself is not implicitly killed. |
2968
2966
  | Settlement or teardown | Retire and abort input immediately when the execution settles or is cancelled. Existing stream completion and worker wake mechanics remain the only completion path. |
2969
2967
 
2970
- Stored runtime entries retain plugin-only writers. Input and termination are
2968
+ No operation writes a stored runtime entry: its scheme's `writableBy` is empty, and the execution writes its own streams. Input and termination are
2971
2969
  control capabilities, not exceptions granting write access to stdout/resources.
2972
2970
 
2973
2971
  ### §exec Executions
@@ -3125,6 +3123,11 @@ catalogue.
3125
3123
 
3126
3124
  Per-tool programs such as `go`, `cargo`, `make`, and `npm` do not earn executor tags merely because they are executables; they are complete shell commands in a `sh` executable fence. Registered tags exist only for tools that own a distinct body, target, or output contract. {§exec-registry-resolves}
3127
3125
 
3126
+ §exec-near-miss **An execution id under the wrong runtime names its address.** A KILL or input
3127
+ addressed to `<runtime>:///<id>` when the id holds an execution only under another runtime refuses
3128
+ `stream-not-found` as before, and its recovery names every address the id holds:
3129
+ `` The execution at /5e8ea474 is `python3:///5e8ea474`. `` (#1005).
3130
+
3128
3131
  §exec-lifetime **How long a spawn may live is the fence's metadata, one field.**
3129
3132
  `[{"lifetime": …}]` takes a duration (`30s`, `30m`, `2h`), or one of three words;
3130
3133
  absent is `loop`. The key is one of the service's reserved metadata keys, withheld
@@ -3133,7 +3136,7 @@ executor target is refused `scope-unsupported` (400), naming the field.
3133
3136
 
3134
3137
  | `lifetime` | The spawn |
3135
3138
  | ------------ | --------- |
3136
- | a duration | Aborted at the deadline — a bounded reap, polite signal then SIGKILL after `PLURNK_SERVICE_EXEC_KILL_GRACE_MS` — and the stream is stamped **504**, distinct from a deliberate kill (499) or a clean exit (200). |
3139
+ | a duration | Aborted at the deadline — a bounded reap, polite signal then SIGKILL after `PLURNK_SERVICE_EXEC_KILL_GRACE_MS` — and the stream is stamped **504** `execution-timeout`, distinct from a deliberate kill (499) or a clean exit (200): `` Execution of '*runtime*' outlived its *lifetime* lifetime. `` Recovery: `` Run it again with a longer lifetime, such as [{"lifetime": "30m"}], or with none to let it run as long as the loop. `` |
3137
3140
  | `loop` (absent) | Loop-life bounded: reaped on every loop terminal except 202, the background-stream behavior. |
3138
3141
  | `turn` | Reaped at the worker's next pre-turn via the registry abort, before the turn's own spawns, so it never survives into the subsequent turn; its terminal output surfaces born visible like any close ({§exec-stream}). |
3139
3142
  | `detached` | Outlives its loop's terminal, 200 included. It never binds to the loop's teardown and is nobody's obligation — completion is not gated by it, WAIT does not park on it, optimistic settlement looks past it — and it ends only by KILL, the worker's total reap, or daemon shutdown; its late conclusion surfaces without opening a loop. |
@@ -3339,7 +3342,7 @@ body prefixes.
3339
3342
  wholesale ({§log-sensitive-request-evidence}); the spawn's record names each such value's
3340
3343
  provenance as the modifier's.
3341
3344
  - §exec-hold-until-concluded **The turn-hold exception** — for runtimes in `PLURNK_SERVICE_EXEC_HOLD` (a decision-table env), 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 an executor fence, optionally followed by WAIT; 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.
3342
- - §exec-entry-sink **The entry() sink** implements {§executor-entry-sink} over ordinary scheme-owned entries. Core owns allocation, materialization, and persistence; executors receive only the returned resource address. Web acquisition and materialization are the `https` handler's {§web-materialization-contract}, reached through the scheme registry; core names no leaf package.
3345
+ - §exec-entry-sink **The entry() sink** implements {§executor-entry-sink} over ordinary scheme-owned entries. Core owns allocation, materialization, and persistence; executors receive only the returned resource address. Web acquisition and materialization are the `https` handler's {§web-materialization-contract}, reached through the scheme registry; core names no extension package.
3343
3346
 
3344
3347
  | Input / effect | Consumer behavior |
3345
3348
  | --- | --- |
@@ -3347,7 +3350,7 @@ body prefixes.
3347
3350
  | Null path + supplied content | Publish beneath the invocation's `resources/` using {§resource-publication-names}, owned by the calling Worker. |
3348
3351
  | Supplied bytes | Retain the original bytes and declared mimetype in an ordinary channel ({§binary-parity}). |
3349
3352
  | Supplied text | Preserve text resources; HTTP/HTML materialization retains source and derived channels under {§html-materialization}. |
3350
- | Null content | Acquire an HTTP(S) resource through the checked WebFetcher, using the same configured materializers as exact HTTP acquisition ({§http-materializer-plugins}). |
3353
+ | Null content | Acquire an HTTP(S) resource through the checked WebFetcher, using the same configured materializers as exact HTTP acquisition ({§http-materializer-extensions}). |
3351
3354
  | Durable evidence | One typed EDIT event in the runtime actor, with the calling Worker as causal source. Binary evidence describes the resource; its complete bytes live in the resource channel. |
3352
3355
  | Model orientation | The executor includes returned addresses in its result. Publication does not independently wake inference or broadcast an observer row ({§env-delta-entry-materialization}). READ controls content acquisition and native delivery. |
3353
3356
 
@@ -3532,7 +3535,7 @@ Capability admission precedes this decision, so proposal disposition cannot gran
3532
3535
 
3533
3536
  ### §subscriptions Subscriptions
3534
3537
 
3535
- §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. 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.
3538
+ §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. 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 extension contract.
3536
3539
 
3537
3540
  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.
3538
3541
 
@@ -3553,7 +3556,7 @@ the producer's already obtained outcome into a fictitious cancellation result.
3553
3556
  At process restart every still-open row is necessarily missing its callable owner. Boot
3554
3557
  settles it as interruption (`500`) and errors active channels before evaluating parked
3555
3558
  loops ({§worker-lifecycle-restart-recovery}); it never reports cancellation (`499`) or
3556
- pretends to reconstruct an opaque plugin connection.
3559
+ pretends to reconstruct an opaque extension connection.
3557
3560
 
3558
3561
  §subscriptions-causal-resource A subscription's causal Worker belongs to the
3559
3562
  entry's workspace. The active entry has
@@ -3639,7 +3642,7 @@ No generator. SQLite-optimal: STRICT (3.37+), `INTEGER PRIMARY KEY` aliasing, ex
3639
3642
  - Tokenization (provider-bound; hot-swap re-tokenizes per {§tokenomics}).
3640
3643
  - Provider dispatch, request-accounting validation, and exact-decimal aggregate projection through the shared contracts-owned path.
3641
3644
  - Scheme-handler invocation (connections, subprocesses, fetch).
3642
- - Plugin loading ({§plugin-discovery}).
3645
+ - Extension loading ({§extension-discovery}).
3643
3646
  - Stream AbortController lifecycle.
3644
3647
  - CLI + daemon.
3645
3648
 
@@ -3647,16 +3650,16 @@ When SQL becomes onerous for a specific case, retreat for that case and document
3647
3650
 
3648
3651
  ---
3649
3652
 
3650
- ## §core-plugin-composition Plugin composition
3653
+ ## §core-extension-composition Extension composition
3651
3654
 
3652
3655
  The metaproject contract owns installed membership, the one-family manifest
3653
- shape, and the shared pre-import trust boundary ({§plugin-discovery}). Each
3654
- capability framework owns its typed discovery result and trusted loading path.
3656
+ shape, and the shared pre-import trust boundary ({§extension-discovery}). Each
3657
+ framework owns its typed discovery result and trusted loading path.
3655
3658
  Core owns only cross-family composition, arbitration, and operator presentation
3656
3659
  of skipped-package evidence.
3657
3660
 
3658
- §plugin-namespace-arbitration **Every addressable scheme name has one claim.**
3659
- For an installed plugin, claim identity is the capability family plus its npm
3661
+ §extension-namespace-arbitration **Every addressable scheme name has one claim.**
3662
+ For an installed extension, claim identity is its kind plus its npm
3660
3663
  package name. Core's bundled names are reserved claims. A daemon module's
3661
3664
  runtime registration names its module owner and makes one composite executor
3662
3665
  claim: its ordinary output scheme and optional resource facet do not compete
@@ -3667,8 +3670,8 @@ claiming either name, for process-wide and workspace-scoped registrations alike.
3667
3670
  |--------------------------------|---------------------------------------------------------|---------|
3668
3671
  | None | Any valid claim | Register it. |
3669
3672
  | Same installed family/package | Rescan of the same name | No-op; retain the one registered handler. |
3670
- | Reserved core name | Any plugin or module | Fail naming the reserved owner and claimant. |
3671
- | Any plugin/module | A different owner, including scheme/executor either way | Fail naming both owners. |
3673
+ | Reserved core name | Any extension, a module included | Fail naming the reserved owner and claimant. |
3674
+ | Any extension | A different owner, including scheme/executor either way | Fail naming both owners. |
3672
3675
  | Module runtime | Its optional same-registration scheme facet | Compose one handler under the runtime's single claim. |
3673
3676
 
3674
3677
  Arbitration precedes host registry mutation. External scheme descriptors are
@@ -3684,15 +3687,21 @@ registration.
3684
3687
 
3685
3688
  ## §bundled-set Bundled Set
3686
3689
 
3687
- Family discovery ({§plugin-discovery}) scans installed scoped and unscoped
3690
+ Family discovery ({§extension-discovery}) scans installed scoped and unscoped
3688
3691
  packages carrying the applicable `plurnk.kind` declaration.
3689
3692
 
3690
- §default-plugin-ownership `@plurnk/plurnk-service` is the sole manifest owner
3691
- of the default leaf set. Capability frameworks own contracts, discovery, and
3692
- loading; their runtime dependency graphs contain no leaf consumers. A required
3693
- default leaf missing from a service install is a broken install. A direct
3693
+ §default-extension-ownership `@plurnk/plurnk-service` is the sole manifest owner
3694
+ of the default extensions. Frameworks own contracts, discovery, and loading;
3695
+ their runtime dependency graphs contain no extension of their kind. A required
3696
+ default extension missing from a service install is a broken install. A direct
3694
3697
  framework consumer may intentionally omit leaves and receives that framework's
3695
3698
  documented unavailable-capability behavior.
3699
+
3700
+ `@plurnk/plurnk-tavily-plugin` is the separately installed, opt-in plugin showcase,
3701
+ not a service dependency. Its own tests own installation, native discovery,
3702
+ configuration, and HTTP materialization; service installation coverage proves it
3703
+ is absent from the default composition.
3704
+
3696
3705
  Packed executor coverage distinguishes installation from enablement: verify
3697
3706
  the package floor, explicit opt-in, and composed allowlist/disable behavior
3698
3707
  through discovery and registration outside the development dependency graph
@@ -3705,19 +3714,19 @@ the checkout's development dependency graph, and proves each optional language
3705
3714
  degrades by name when its leaf is absent.
3706
3715
 
3707
3716
  §install-root-advisory-ownership **The composed service install owns
3708
- third-party advisory detection.** Only that install resolves the default leaves
3717
+ third-party advisory detection.** Only that install resolves the default extensions
3709
3718
  and their combined transitive tree. Its audit reports advisories at the
3710
3719
  moderate floor without blocking by default; strict mode makes the same floor a
3711
3720
  gate. A chain rooted through an `@plurnk/*` dependency routes to that package's
3712
3721
  owner, while other direct roots remain service-owned. First-party package-pin
3713
3722
  freshness remains the owning family's concern.
3714
3723
 
3715
- | Family | Lean framework | Service-owned default leaves |
3724
+ | Kind | Lean framework | Service-owned default extensions |
3716
3725
  |-----------|------------------------------------|----------------------------------------------------------------------------------------------------------------------------------|
3717
3726
  | Schemes | `@plurnk/plurnk-schemes` | `@plurnk/plurnk-schemes-http` |
3718
3727
  | Mimetypes | `@plurnk/plurnk-mimetypes` | `application-ipynb`, `application-json`, `application-jsonl`, and `application-xml` format leaves. |
3719
3728
  | | | `text-csv`, `text-diff`, `text-dotenv`, `text-html`, `text-ini`, `text-markdown`, and `text-plain` format leaves. |
3720
- | | | `image`, `application-pdf` (header-only, {§mimetype-pdf-facts}), and every `grammar-{slug}` leaf in the framework's tree-sitter registry ({§mimetype-grammar-leaves}), all under `@plurnk/plurnk-mimetypes-*`. |
3729
+ | | | `image`, `application-pdf` (header-only, {§mimetype-pdf-facts}), and every `grammar-{slug}` package in the framework's tree-sitter registry ({§mimetype-grammar-packages}), all under `@plurnk/plurnk-mimetypes-*`. |
3721
3730
  | Executors | `@plurnk/plurnk-execs` | `common`, `jq`, and `sqlite` leaves under the `@plurnk/plurnk-execs-*` prefix. |
3722
3731
 
3723
3732
  The independently published `tokenizers` artifact is an opt-in leaf. Installing
@@ -3727,7 +3736,7 @@ native attachment like an image, and the daemon does no extraction (#542).
3727
3736
 
3728
3737
  **Providers:** `@plurnk/plurnk-providers` resolves the Models.dev catalog,
3729
3738
  operator declarations, local adapters, and finally installed AI SDK provider
3730
- plugins. `Mock` is its integration fixture. Core contains no vendor protocol.
3739
+ extensions. `Mock` is its integration fixture. Core contains no vendor protocol.
3731
3740
 
3732
3741
  **Core schemes:** `file`, `log`, `prompt`, `skill`, and `worker` expose daemon
3733
3742
  state or filesystem orchestration owned by core. `exec` is internal dispatch
@@ -3738,8 +3747,8 @@ dispatcher contract.
3738
3747
 
3739
3748
  The executor registry discovers installed runtimes, probes availability, and
3740
3749
  routes ```` ```<runtime> ````; core contributes orchestration and the output-scheme
3741
- adapter, not runtime implementations. Optional and third-party leaves extend
3742
- each family by installation and discovery; they never require a framework or
3750
+ adapter, not runtime implementations. Optional and third-party extensions extend
3751
+ each kind by installation and discovery; they never require a framework or
3743
3752
  service manifest edit.
3744
3753
 
3745
3754
  ---
@@ -3807,11 +3816,11 @@ Node's pre-script env-file form and the executable's post-script form share the
3807
3816
 
3808
3817
  | Source | Panel | Admission |
3809
3818
  |---|---|---|
3810
- | Platform capability package | `.env.defaults` at the package root | `@plurnk/*` or a `plurnk` package field; {§plugin-trust-boundary} |
3811
- | Agent Plugin native extension | `ai.plurnk/.env.defaults` | The winning daemon-wide plugin in {§agent-plugins-hosting}, a valid native declaration, and the same trust gate |
3819
+ | Extension package | `.env.defaults` at the package root | `@plurnk/*` or a `plurnk` package field; {§extension-trust-boundary} |
3820
+ | Agent Plugin extension | `ai.plurnk/.env.defaults` | The winning daemon-wide plugin in {§agent-plugins-hosting}, a valid native declaration, and the same trust gate |
3812
3821
 
3813
3822
  Root and trust flags apply before collection. A project plugin contributes no native panel.
3814
- Non-module native panels follow their npm-only family discovery ({§plugin-manifest-read});
3823
+ Non-module native panels follow their npm-only family discovery ({§extension-manifest-read});
3815
3824
  a plain-folder declaration does not suppress an installed capability's panel.
3816
3825
  Linked packages resolve panels against the same canonical root as native code;
3817
3826
  an absent panel is optional, but a panel escaping that root is rejected.
@@ -3865,6 +3874,7 @@ names the offending variable or file/entry and retains its cause.
3865
3874
  | A2A | Whole outbound definitions and controls, timeout/diagnostic bounds, configured inbound exposure |
3866
3875
  | Schedule | Whole definitions and controls, recurrence syntax, time zone and preview count |
3867
3876
  | Hooks | Command/argument/event configuration and delivery bounds |
3877
+ | Discovered modules | Each module's own configuration, as its factory constructs it ({§module-self-activation}) |
3868
3878
 
3869
3879
  Disabled definitions and controls without a resource are validated, not skipped.
3870
3880
  Checking creates no database, starts no process or listener, arms no schedule,
@@ -3893,7 +3903,7 @@ Each knob's value lives on its panel and nowhere else (`plurnk-service config de
3893
3903
  | §operator-config-file-create-scope `PLURNK_SERVICE_FILE_CREATE_SCOPE` | 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. |
3894
3904
  | `PLURNK_SERVICE_FILE_MATERIALIZE_MAX_BYTES` | Byte ceiling in `1..104857600` for one workspace-file snapshot ({§membership-materialization-limit}). |
3895
3905
  | `PLURNK_SERVICE_MAX_TURNS` | Operator model-call **ceiling** — `-1` = no cap; a positive value clamps `runLoop({maxTurns})`. The durable worker-tree budget includes descendant calls, BARE, and park/resume under {§turn-cap-counts-the-tree}; non-model chronology consumes none. |
3896
- | `PLURNK_SERVICE_MAX_COMMANDS` | Per-emission action ceiling; `-1` = no cap — 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. The final disposition always dispatch. Tightened per workspace via `settings.maxCommands` (min wins). |
3906
+ | `PLURNK_SERVICE_MAX_COMMANDS` | Per-emission action ceiling; `-1` = no cap — every compiled op dispatches. Each resolved target statement counts once, whether authored separately or in a group ({§target-group}). Overflow ops drop with one durable `max-commands-exceeded` error row on the next packet. Lifecycle operations remain exempt ({§operator-config-workspace-max-commands-floor}). Tightened per workspace via `settings.maxCommands` (min wins). |
3897
3907
  | §operator-config-loop-timeout `PLURNK_SERVICE_LOOP_TIMEOUT` | Positive ms of cumulative active execution per loop ({§loop-execution-allowance}); excludes parked/queued time. Snapshotted on first execution, retained across wakes. Exhaustion aborts in-flight work and terminates `504 loop_timeout`, including a stuck provider call. |
3898
3908
  | `PLURNK_SERVICE_PROVIDER_RECOVERY` | ms of recovery after the first recoverable provider failure; `0` disables reissue. Expiry parks attended loops, concludes unattended loops, or returns BARE's failure under {§provider-recovery}. |
3899
3909
  | `PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF` | First recovery delay (ms); doubles per failure up to `PLURNK_SERVICE_PROVIDER_RECOVERY_BACKOFF_MAX` ({§provider-recovery}). |
@@ -3904,8 +3914,6 @@ Each knob's value lives on its panel and nowhere else (`plurnk-service config de
3904
3914
  | `PLURNK_SERVICE_EDIT_RECEIPT_CONTEXT_LINES` | Surrounding and landed lines shown at each EDIT result boundary ({§edit-result-receipt-projection}). |
3905
3915
  | `PLURNK_SERVICE_MIN_CYCLES` | Min repetitions before cycle detection fires ({§engine-rails}). |
3906
3916
  | `PLURNK_SERVICE_MAX_CYCLE_PERIOD` | Max period length cycle detection examines ({§engine-rails}). |
3907
- | `PLURNK_SERVICE_REQUIEM_MAX_TOKENS` | Initial forensic witness output allowance ({§digest-requiem}). |
3908
- | `PLURNK_SERVICE_REQUIEM_RETRY_MAX_TOKENS` | Retry allowance; must be at least the initial requiem allowance ({§digest-requiem}). |
3909
3917
  | `PLURNK_SERVICE_FILES_ITEMS` | 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}). |
3910
3918
  | `PLURNK_SERVICE_MEMBERS_MODEL_SCOPE` | Ceiling for a model's `members` definitions in the lattice `none < root < namespace`; `none` refuses every model definition ({§members-model-scope}). |
3911
3919
  | `PLURNK_SERVICE_EXEC_CONCURRENCY` | Executions admitted at once per workspace; the rest queue FIFO with `202 queued` receipts; `-1` unbounded ({§exec-concurrency}). |
@@ -3929,9 +3937,9 @@ instead of a user's boot, and a dead knob cannot ship.
3929
3937
 
3930
3938
  Feature-flag bools use `process.env.X === "1"` exactly — never `=== "true"`.
3931
3939
 
3932
- External plugins declare their own env vars in their own `.env.defaults`, assembled at boot ({§operator-config-env-defaults}).
3940
+ External extensions declare their own env vars in their own `.env.defaults`, assembled at boot ({§operator-config-env-defaults}).
3933
3941
 
3934
- §operator-config-cli-flags **Admin CLI flags derive only from the service package's `.env.defaults`.** Every `PLURNK_*` declared there becomes `--<kebab-cased-name>` (prefix stripped, lowercased, underscores → dashes). A comment immediately above the declaration becomes its `-h` description. Installed plugin defaults join the environment floor and catalog but do not implicitly expand the service executable's flag surface.
3942
+ §operator-config-cli-flags **Admin CLI flags derive only from the service package's `.env.defaults`.** Every `PLURNK_*` declared there becomes `--<kebab-cased-name>` (prefix stripped, lowercased, underscores → dashes). A comment immediately above the declaration becomes its `-h` description. Installed extension defaults join the environment floor and catalog but do not implicitly expand the service executable's flag surface.
3935
3943
 
3936
3944
  ### Loop limits
3937
3945
 
@@ -3978,9 +3986,9 @@ leak into another.
3978
3986
  workspace: a client tightens the runaway-op guard and never raises it past
3979
3987
  the operator's.
3980
3988
  - §operator-config-workspace-max-commands-floor The cap bounds *actions* only.
3981
- The final disposition (`102`, `200`, `202`,
3982
- `300`, or `499`) are never counted and always dispatch, so `0` is a valid
3983
- floor — the tightest — admitting a plan and disposition with zero actions.
3989
+ WAIT and parameterless KILL are never counted and always dispatch, so `0` is a valid
3990
+ floor, admitting lifecycle intent with zero actions. Dropped actions still prevent
3991
+ successful completion under {§turn-disposition}.
3984
3992
  - §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.
3985
3993
  - §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`.
3986
3994
  - `settings.membersModelScope` narrows `PLURNK_SERVICE_MEMBERS_MODEL_SCOPE` ({§members-model-scope}).
@@ -4037,9 +4045,10 @@ a fresh-user configuration.
4037
4045
 
4038
4046
  ## §rpc Module seam
4039
4047
 
4040
- Core implements the contracts-owned {§application-port} and owns the typed
4041
- module setup seam. It owns no external listener, public
4042
- action-name catalog, or generic string-dispatched method registry. A
4048
+ Core implements the contracts-owned {§application-port} and hosts the module
4049
+ contract published in `@plurnk/plurnk-modules` ({§module-contract}). It owns the one
4050
+ listener modules mount on ({§http-host}), but no public action-name catalog or generic
4051
+ string-dispatched method registry. A
4043
4052
  client-interface module such as `plurnk-agui` owns its public protocol, action
4044
4053
  names, request validation, discovery result, and event projection.
4045
4054
 
@@ -4047,13 +4056,13 @@ names, request validation, discovery result, and event projection.
4047
4056
 
4048
4057
  ```mermaid
4049
4058
  flowchart LR
4050
- bind["Host may pre-bind client-interface listener<br/>unready"] --> register
4051
- register["Daemon.registerModule"] --> setup["module.setup(ModuleSetupSeam)"]
4059
+ bind["Host binds the daemon's listener<br/>unadmitted"] --> register
4060
+ register["Register explicit, then discovered modules"] --> setup["module.setup(ModuleSetupSeam)"]
4052
4061
  setup --> capabilities["Register static capabilities,<br/>workspace activators, and actions"]
4053
4062
  capabilities --> ready["Process-wide schemes ready"]
4054
4063
  ready --> recovery["Reconcile durable lifecycle"]
4055
4064
  recovery --> start["module.start(ApplicationPort)"]
4056
- start --> interface["Module-owned client protocol<br/>ready"]
4065
+ start --> interface["Listener admitted:<br/>module-owned client protocol ready"]
4057
4066
  recovery -->|durable workspace work| demand["First workspace demand"]
4058
4067
  interface -->|client workspace work| demand
4059
4068
  demand --> lease["Acquire capability residency"]
@@ -4070,17 +4079,17 @@ flowchart LR
4070
4079
  ```
4071
4080
 
4072
4081
  Every registered module's `setup` runs in registration order before any
4073
- module's `start`. Core then readies process-wide schemes, reconciles durable
4074
- lifecycle, and starts modules in registration order. The production
4075
- client-interface module may already own its socket under
4076
- {§startup-listener-admission}; its `start` activates request handling without
4077
- rebinding. Persisted workspaces with
4082
+ module's `start` ({§module-phases}; failures follow {§module-failure}). Core
4083
+ then readies process-wide schemes, reconciles durable lifecycle, and starts
4084
+ modules in registration order. The daemon's listener is bound before durable admission
4085
+ ({§startup-listener-admission}) and admitted once every module has started
4086
+ ({§module-http-mounts}). Persisted workspaces with
4078
4087
  no durable work stay passive until first demand; activation publishes their
4079
4088
  complete capabilities and documentation before the demanding operation
4080
4089
  proceeds. `setup` is the readiness boundary for every capability registered
4081
- with Core: recovery may demand a workspace provider before `start`. For a
4082
- pre-bound client interface, requests remain unavailable until `start`; every
4083
- other module opens its module-owned exterior ingress only after recovery. No
4090
+ with Core: recovery may demand a workspace provider before `start`. Requests on
4091
+ the listener remain unavailable until it is admitted; a module opens any other exterior
4092
+ ingress only after recovery. No
4084
4093
  registered capability may depend on exterior ingress. A module, and any distinct
4085
4094
  lifetime object returned by `start`, may implement the following phases:
4086
4095
 
@@ -4097,21 +4106,26 @@ even if setup fails. A returned object identical to its module is tracked once.
4097
4106
 
4098
4107
  | Source | Declaration | Lifetime |
4099
4108
  |---|---|---|
4100
- | Platform capability package | `package.json#plurnk` with `kind: "module"` and `module` | Daemon-wide |
4109
+ | Extension package | `package.json#plurnk` with `kind: "module"` and `module`, an export subpath resolved through the package's own exports as in {§executor-dynamic-runtimes} | Daemon-wide; the form every first-party default module uses |
4101
4110
  | Agent Plugin | `plugin.json#extensions.ai.plurnk` with `kind: "module"` and a `module` path under `ai.plurnk/` | Daemon-wide; npm and selected user roots only |
4102
4111
  | Project Agent Plugin | Portable components only | Workspace-scoped; native code is not imported |
4103
4112
 
4104
- The export is one DaemonModule object or no-argument factory. Standard bundles follow
4113
+ The export is one DaemonModule ({§module-contract}) object or no-argument factory. The host
4114
+ records each module's owner, the package it came from, and its diagnostics name that owner. The
4115
+ service registers no module itself; a host that registers one explicitly, such as a test
4116
+ substituting a package, names it by its package the same way. Standard bundles follow
4105
4117
  {§agent-plugins-hosting} source order, then other installed module packages load in package-name
4106
- order. All trusted modules register before setup. The service's explicit AG-UI, hooks and MCP
4107
- composition is never duplicated. Untrusted modules are reported and not imported. Invalid
4118
+ order. All trusted modules register before setup; a daemon without a listener then leaves out
4119
+ every one that declares mounts ({§module-http-mounts}). A package the host registered explicitly is
4120
+ never also discovered: discovery skips that owner before importing it. Untrusted modules are reported and not imported. Invalid
4108
4121
  declarations, unavailable module files and configuration errors during construction are diagnosed
4109
- at the affected native extension; healthy siblings remain available. A factory validates startup
4122
+ at the affected extension, a declaration's error owned by `extensions` and a
4123
+ module's own configuration error by `module:<package>`; healthy siblings remain available. A factory validates startup
4110
4124
  configuration before `setup` acquires resources. Failures after registration begins follow
4111
4125
  {§module-lifecycle} cleanup, not a partial-registration fallback.
4112
4126
  An invalid module object, factory result or lifecycle member is an implementation contract failure,
4113
- not configuration, and fails loudly. Native capabilities register through their owning public
4114
- interfaces and release registrations during {§module-lifecycle} resource teardown.
4127
+ not configuration, and fails loudly. What a module contributes registers through its owning public
4128
+ interfaces and is released during {§module-lifecycle} resource teardown.
4115
4129
 
4116
4130
  §module-shutdown-order `Daemon.stop()` first rejects new capability demand and
4117
4131
  aborts proposals, branches, derivations, and worker scopes. It begins module
@@ -4157,18 +4171,21 @@ flowchart LR
4157
4171
  observers --> database[Maintain and release database]
4158
4172
  ```
4159
4173
 
4174
+ §module-host-capabilities **The coordinator's host interface is core's own.**
4175
+ The daemon passes one object implementing every published slice
4176
+ ({§module-seam-slices}); these functions are on it too, for core's
4177
+ Functionality coordinator and core's own witnesses, and are not part of the
4178
+ published module contract.
4179
+
4160
4180
  | Setup function | Contract |
4161
4181
  |---|---|
4162
4182
  | `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. |
4163
- | `registerScheme(name, handler)` | Adds one process-wide addressable scheme handler; scheme readiness and model-facing capability publication remain core-owned. |
4164
- | §module-action-registration `registerModuleAction({ name, scope, residency, 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. `residency` is explicitly `required` or `none`: only the former acquires workspace capabilities and reconciles worker documents. Worldless actions require `none`. 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. |
4165
4183
  | §module-workspace-provider `registerWorkspaceCapabilityProvider(namespaceOwner, provider)` | Registers one extension-unique Functionality provider. `activate({ workspaceId, retain })` reconstructs the workspace snapshot; idempotent `deactivate({ workspaceId })` releases process resources. Core coalesces demand and supplies residency leases for work that outlives its caller. |
4166
4184
  | §module-workspace-state `readWorkspaceModuleState(workspaceId, namespaceOwner)` | Reads one nullable JSON state value per workspace and provider. Core owns storage and lifecycle; the provider owns its schema. Store symbolic credential references, not copied secrets. A worker-scoped family's coordinator reads and replaces the same shape per worker in `worker_module_state` ({§functionality-scope}). |
4167
- | `readWorkspaceEnvironment(workspaceId)` | Captures the workspace env layer ({§workspace-env}) and returns its composer. No argument uses admitted host values; a supplied environment supplies a module's reference-resolution context. Both apply the same captured values and masks, without worker overrides. |
4168
- | §module-workspace-directory `workspaceStateDirectory(workspaceId, namespaceOwner)` | Returns and creates the module's absolute operational-state directory under the daemon's XDG state home. Core owns path resolution and a stable random workspace storage key in its own `workspace_module_state` row. The key survives workspace renames and daemon restarts; independently created workspaces, including in other databases, receive different keys. The module owns its contents and child-directory lifetimes. |
4169
- | §module-functionality-adapter `registerFunctionalityAdapter(adapter)` | Registers one family beneath the shared coordinator ({§functionality-coordinator}). |
4170
4185
  | §module-workspace-capabilities `replaceWorkspaceCapabilities({ workspaceId, namespaceOwner, state, runtimes })` | Atomically replaces one provider's durable state and runtime/scheme snapshot at the workspace operation boundary. Namespace claims are validated before mutation. Failure restores the prior state and publication. |
4171
4186
 
4187
+ Core keys each {§module-workspace-directory} by a stable random workspace
4188
+ storage key in its own `workspace_module_state` row.
4172
4189
  Module directory allocation is lazy, atomic in SQLite, and independent of the
4173
4190
  project root, daemon CWD, and workspace/worker environment overrides. New
4174
4191
  directories use mode `0700`; existing permissions are not rewritten. Module
@@ -4180,6 +4197,14 @@ workspace forgets its storage key through the existing foreign key; old disk
4180
4197
  state is not reassigned or automatically purged. A database copy preserves its
4181
4198
  storage identities; the directory is operational state, not a backup of it.
4182
4199
 
4200
+ §skills-storage-upgrade **Skills ownership upgrades without a second identity.**
4201
+ The database migration renames the family state to `@plurnk/plurnk-skills`.
4202
+ Before module setup, core renames the former skills directory within each storage root
4203
+ recorded by this database. Fetched bytes are not refetched or deleted. A missing former
4204
+ directory needs no work; a completed rename is repeatable. Conflicting destinations and
4205
+ filesystem failures stop admission without replacing either directory. No runtime alias
4206
+ recognizes the former owner.
4207
+
4183
4208
  §workspace-environment-sharing **The workspace owns its shared environment.**
4184
4209
  Workers own their logs; delegation retains its existing lifecycle.
4185
4210
  Creating, attaching, forking, cancelling, or deleting a worker does not create,
@@ -4319,7 +4344,10 @@ composition boundaries, not arbitrary exceptions:
4319
4344
  | Internal invariant, state, or implementation failure | Preserve the exception; never reclassify it as an operator configuration error. |
4320
4345
 
4321
4346
  Client discovery and passive synchronization report startup diagnostics through the
4322
- existing Notice channel, even without a usable model. The first turn of a drain, and a changed diagnostic
4347
+ existing Notice channel, even without a usable model. Each is a Notice from `engine:configuration`
4348
+ of kind `configuration_unavailable` that names the failed setting's `key` and its `owner`: the
4349
+ setting's reader (such as `packet`, `model` or `executor:<runtime>`), a family, `extensions` for an
4350
+ extension declaration, or a module as `module:<package>`. The first turn of a drain, and a changed diagnostic
4323
4351
  thereafter, reports unresolved configuration to both client and model. An
4324
4352
  unchanged diagnostic is not repeated every turn. Operation failures remain Problems.
4325
4353
 
@@ -4350,32 +4378,6 @@ publication contract, and creates no log entries or model Notices. Published
4350
4378
  failures retain their exact Problems in `list`. Concurrent consumers share the
4351
4379
  workspace activity; a client disconnect does not clear another consumer's work.
4352
4380
 
4353
- §functionality-adapter **An adapter owns protocol truth.** It declares its
4354
- family, namespace owner, definition schema, contributed defaults, discovery,
4355
- admission, preparation, and teardown, and its alias grammar when that is not
4356
- the shared lowercase-hyphen one: the coordinator enforces whichever grammar the
4357
- family declares, at admission, in the service projection, and on persisted
4358
- state, so an environment variable's name is an alias exactly as a skill name
4359
- is. Admission distinguishes explicit client
4360
- actions from model operations where the family contract requires it
4361
- ({§members-model-scope}). Preparation receives each complete definition with optional
4362
- adapter-owned interpretation context. Context is source semantics, not policy or provenance;
4363
- it participates in runtime identity and hot-load comparisons, is never projected as configuration
4364
- or persisted into a workspace override, and cannot survive replacement by a local definition.
4365
- Removing that override restores the current inherited definition and context together.
4366
- Descriptive provenance alone does not change runtime identity. Preparation returns runtimes, documents, per-alias
4367
- outcomes, and a snapshot with `commit`/`abort`. Successful publication commits;
4368
- failure aborts; cooling tears down. Protocol continuations remain ordinary
4369
- module actions. Optional `forget` releases an installed or provisioned
4370
- definition before removal; failure rejects removal. The
4371
- seam's shapes — the identity a verb acts under, its options, definition
4372
- sources, outcomes, preparation, the prepared result and the family handle —
4373
- are declared once in `plurnk-contracts` and imported by core and every
4374
- module; core adds only its own face of the seam, the runtime registration a
4375
- resident family prepares and the scheme facet it may expose.
4376
- An adapter may expose current partial-source `configurationNotices`; these join the ordinary
4377
- workspace diagnostics without preventing independently valid definitions from preparing.
4378
-
4379
4381
  §functionality-hotload **Out-of-band state is admitted before the next turn.** An adapter whose
4380
4382
  `available` reads state that changes outside the daemon, such as skill roots ({§skills-hotload}) or
4381
4383
  installed plugins ({§agent-plugins-hosting}), implements `refreshIfChanged`. Turn admission calls it
@@ -4415,9 +4417,10 @@ its discovery roots explicitly ({§operator-config-real-model-profile}), so
4415
4417
  operator roots do not shape a gate. Root selection does not restrict explicit
4416
4418
  source definitions. Skills mutations change workspace bindings, not these roots
4417
4419
  ({§skills-functionality}); MCP mutations likewise remain workspace-owned. The module setup seam's
4418
- `workspaceConfigurationDirectories` supplies selected `<project>/.agents`,
4419
- `$XDG_CONFIG_HOME/plurnk`, and `~/.agents` directories in precedence order, omitting
4420
- project when no project is bound. Modules own their file formats; core owns discovery roots.
4420
+ `workspacePaths` supplies selected `<project>/.agents`, `$XDG_CONFIG_HOME/plurnk`,
4421
+ and `~/.agents` directories in precedence order with their scopes, omitting project
4422
+ when no project is bound ({§module-workspace-paths}). Modules own their file formats;
4423
+ core owns discovery roots.
4421
4424
 
4422
4425
  An adapter may expose a `scheme` facet beneath its family's runtime namespace
4423
4426
  ({§runtime-resource-binding}). A facet claims a path subtree and is the scheme's
@@ -4853,13 +4856,13 @@ adding a loop to it. LOOK text anchors resolve through the same
4853
4856
  | §notifications-loop-interaction `loop/interaction` | contracts-owned `ClientInteractionProjection` | An operation is paused on client input. Live delivery and reconnect discovery share {§client-interactions}; workspace scope remains the event envelope. |
4854
4857
  | §notifications-workspace-created `workspace/created` | `{ id, name, projectRoot }` | A workspace is created. This is the only current global event. |
4855
4858
  | `workspace/preparation` | `{ workspaceId, preparation: FunctionalityPreparationActivity[] }` | Workspace capability preparation changes; snapshot and clearing semantics follow {§functionality-preparation-visibility}. |
4856
- | §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 initiating actor used for conversation routing, never entry ownership or access control. `target` is the canonical resource URI. Optional numeric coordinates identify the causal log item, independently of that URI. 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 by canonical workspace address. |
4859
+ | §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 initiating actor used for conversation routing, never entry ownership or access control. `target` is the canonical resource URI. Optional numeric coordinates identify the causal log item, independently of that URI. Core-managed channel writes include the current stored `mimetype`, which may change per call ({§channel-mimetype}); the generic extension notification capability does not require it. It carries metadata, not content; consumers read bytes by canonical workspace address. |
4857
4860
  | §notifications-stream-concluded `stream/concluded` | `{ entryId, workerId, target, subscriptionId, scheme, result, summary, wakeAction, loop_seq?, turn_seq?, sequence? }` | A subscription closes. `workerId` identifies the initiating actor; `target` is the canonical resource URI. Optional numeric fields identify the causal log item, never parsed from `target`. Exact result truth is preserved. `wakeAction` reports `wake-pending` before settlement, `no-op-active-loop` when work is already executing, `no-loop`, or `skipped-aborted`/`skipped-cancelled` for an aborted worker scope. A pending wake predicts neither execution nor recipient count; subsequent ordinary loop events report actual progress and completion. |
4858
4861
  | §notifications-notice-event `notice/event` | `{ workerId, loopId, notice: Notice }` | A transient observation or progress notice occurs. `workerId` owns loop activity; only workspace derivation progress uses `null` with `loopId=0`. It cannot alter durable history, scheduling, recovery, or model-visible failure truth. |
4859
4862
  | §notifications-outside-event `outside/event` | `{ workerId, loopId, turnId, coordinate, text, tokens }` | An admitted emission carried text outside every operation ({§outside-text}): once per admitted emission, the exact stored text, its packet weight, and the turn's `<worker>-<loop>-<turn>` coordinate. It is transient presentation evidence; the turn's `outside` source remains the durable authority. |
4860
4863
  | §notifications-reasoning-event `reasoning/event` | `{ workerId, loopId, turnId, modelCallId, requestSequence, phase, delta? }` | A main emission call exposes readable reasoning. Each physical request that emits reasoning owns a distinct positive `requestSequence` and balanced start/content/end stream; opening a retry closes the preceding stream before any retry delta. 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. |
4861
4864
 
4862
- §notifications-stream-event-failure-isolation The plugin-facing
4865
+ §notifications-stream-event-failure-isolation The extension-facing
4863
4866
  `NotifyCaps.streamEvent()` remains a synchronous advisory call while core
4864
4867
  resolves its entry identity asynchronously.
4865
4868
 
@@ -4897,7 +4900,7 @@ without an origin filter ({§actor-boundary-isolation}).
4897
4900
  ## §packet-assembly Packet assembly
4898
4901
 
4899
4902
  `PacketBuilder.buildRequestPacket` owns the engine's default ordered section
4900
- list. Trusted scheme plugins may transform that first-class list before it is
4903
+ list. Trusted scheme extensions may transform that first-class list before it is
4901
4904
  rendered or measured; {§context-fit} remains an engine-owned post-build rail.
4902
4905
 
4903
4906
  ```mermaid
@@ -4922,11 +4925,12 @@ The packet reaches the provider as a transcript, under the roles the model was t
4922
4925
  Only role boundaries are added: joined by blank lines, the user messages are the user slot's
4923
4926
  bytes, in record order. An emission is placed exactly when its row is present in the final log
4924
4927
  section, so curation governs the transcript: a KILLed emission row, or one a trusted transform
4925
- removed ({§packet-plugin-transform}), takes its emission with it, and a log without emission rows
4928
+ removed ({§packet-extension-transform}), takes its emission with it, and a log without emission rows
4926
4929
  is one user message. An emission of only NOTE and WAIT delivers nothing, so its record runs on
4927
4930
  into the next user message. The Worker block and the status clump always follow the log, so a
4928
4931
  request never ends on an emission, and the projection refuses one that would. The digest's packet
4929
- artifacts record the sections, and `.wire.json` the messages ({§share-packet-names}).
4932
+ artifacts record the sections, and `.wire.json` reconstructs their text-message
4933
+ envelope ({§share-packet-names}); it is not a serialized HTTP capture.
4930
4934
 
4931
4935
  ### §packet-cache-monotone Default order and cache locality
4932
4936
 
@@ -4957,7 +4961,7 @@ operator notes and policies can change. Trust is a separate
4957
4961
  admission rule. The system slot contains trusted control-plane material;
4958
4962
  attacker-reachable content stays in the user slot.
4959
4963
 
4960
- ### §packet-plugin-transform Trusted whole-list extension seam
4964
+ ### §packet-extension-transform Trusted whole-list extension seam
4961
4965
 
4962
4966
  `SchemeRegistry.transformSections` pipes the complete default list through
4963
4967
  every registered scheme implementing `transformSections(sections) -> sections`,
@@ -4970,7 +4974,7 @@ sections. It receives no separate engine, database, actor, or request context.
4970
4974
  Emission placement reads the final log section, so a transform that removes an
4971
4975
  emission row's record removes its emission from the transcript ({§packet-wire-envelope}).
4972
4976
 
4973
- This is strictly a trusted in-process seam, admitted through the common plugin
4977
+ This is strictly a trusted in-process seam, admitted through the common extension
4974
4978
  trust gate; an external client action cannot invoke it. Whole-list transformation is
4975
4979
  the fork-avoidance valve for alternate packet shapes, while
4976
4980
  overflow recovery and packet projection remain closed engine concerns.
@@ -5123,8 +5127,8 @@ header. A null header renders only its content. Empty content is omitted, traili
5123
5127
  newlines are removed from each section, and rendered sections are separated by one
5124
5128
  blank line. Any node whose content is empty is absent from the wire, except the
5125
5129
  child-orientation sections, which state emptiness as `[]` ({§packet-empty-sections}).
5126
- Core owns the order at {§packet-cache-monotone}; a trusted plugin may transform the
5127
- section list before rendering ({§packet-plugin-transform}). The projection preserves
5130
+ Core owns the order at {§packet-cache-monotone}; a trusted extension may transform the
5131
+ section list before rendering ({§packet-extension-transform}). The projection preserves
5128
5132
  the evidence section owners supply: paths, URI fragments, log coordinates, scopes and
5129
5133
  coordinate-prefixed body lines remain usable without translation; curation and log-row
5130
5134
  measurements stay attached to what they measure ({§tokenomics-agnostic-ruler});
@@ -5173,7 +5177,7 @@ whose INSTEAD OF trigger refuses a turn that is not an open model inference turn
5173
5177
  items, the composition, the bag, and the provider metadata together. Readers of a whole packet
5174
5178
  select from `turn_packets`, which assembles `sections` back into the bag byte for byte (the digest,
5175
5179
  and every test that inspects a stored packet); statements that need one field read the bag
5176
- directly with `json_extract`. A packet transformed by a plugin, or any non-log section, is one
5180
+ directly with `json_extract`. A packet transformed by an extension, or any non-log section, is one
5177
5181
  item. Items no composition references are transient data: `retention_collect_packet_items`
5178
5182
  collects them under the retention policy ({§retention-policy}), which is how a deleted worker's or
5179
5183
  workspace's packets release their space while shared items survive. A fork copies the composition
@@ -5197,42 +5201,12 @@ operation turns and therefore store `NULL`. Digest projects exact operation
5197
5201
  source independently from this optional model-exchange record; a request-only
5198
5202
  turn receives a note instead of a fabricated response.
5199
5203
 
5200
- §digest-turn-artifact-identity **Digest packet artifacts project durable turns.**
5201
- After selectors are applied, digest retains every turn with exact content or reasoning source, a
5202
- valid stored provider request, or malformed stored packet evidence; orders those
5203
- turns by durable chronology; and names each by its log coordinate ({§share-packet-names}). The
5204
- producer does not affect projection.
5205
-
5206
- §share-packet-names **Packet artifacts carry the coordinate the log uses.** A turn's files are named
5207
- `<worker>-<loop>-<turn>`, the worker's name and the loop and turn sequences that `log:///<loop>/<turn>/…`
5208
- addresses: the model's first turn in its first loop is `<worker>-1-2`, because the initialization
5209
- survey is turn 1 and writes no packet. A digest spanning several workspaces nests each workspace's
5210
- files in a folder named for it. `digest.json` records each turn's stem as `artifact`, so no
5211
- consumer reconstructs a name. A name that cannot be a file name, or two turns sharing one, fails.
5212
-
5213
- | Artifact | Present when | Authority |
5214
- |----------|--------------|-----------|
5215
- | `<stem>.assistant.md` | The turn has an `ops` source | Exact `turn_sources.content`, independent of log rows |
5216
- | `<stem>.reasoning.md` | The turn has a `reasoning` source | Exact `turn_sources.content`, without relabeling it as content |
5217
- | `<stem>.system.md`, `<stem>.user.md` | The turn stored a provider request | Stored text sections projected through `PacketWire`; native parts are not Markdown |
5218
- | `<stem>.wire.json` | The turn stored a provider request | The request's text messages in order, its worker's emission rows placed ({§packet-wire-envelope}); `<stem>.wire.invalid.json` names a stored log that cannot be projected |
5219
- | `digest.json` turn `attachments` | Every turn | Stored native attachment descriptors; `[]` means a request without attachments, `null` means no valid stored request. Selection is not proof of provider acceptance. |
5220
- | `<stem>.assistantRaw.json` | The request has an admitted provider response | Stored opaque provider response |
5221
- | `<stem>.response.md`, attempt artifacts | The request received no admitted response | Stored request and attempt state |
5222
- | `<stem>.packet.raw.txt` | The stored packet fails typed validation | Exact stored packet text |
5223
- | `<stem>.packet.invalid.json` | The stored packet fails typed validation | Turn identity and complete validation error chain |
5224
-
5225
- A source-backed turn without provider participation produces only its source-channel
5226
- artifacts; a request-only turn produces no fabricated assistant. A
5227
- source-less programmatic turn with no provider request has no forensic payload
5228
- to project and writes no files.
5229
-
5230
- The external tokenless draft and transformation boundary is owned by
5204
+ he external tokenless draft and transformation boundary is owned by
5231
5205
  {§scheme-packet-transform}. Core alone extends each validated draft with its
5232
5206
  measured `weight` field for storage. #74 tracks coverage that mistakes the sum
5233
5207
  of section weights for the rendered request weight.
5234
5208
 
5235
- §definition-table-projection The authored `plurnk.md` remains human-aligned. Its `definition` section deterministically removes Markdown table-cell padding and shortens separator cells to three dashes before plugin transforms, measurement, storage, and wire rendering; alignment colons survive, while fenced blocks and all non-table whitespace remain exact.
5209
+ §definition-table-projection The authored `plurnk.md` remains human-aligned. Its `definition` section deterministically removes Markdown table-cell padding and shortens separator cells to three dashes before extension transforms, measurement, storage, and wire rendering; alignment colons survive, while fenced blocks and all non-table whitespace remain exact.
5236
5210
 
5237
5211
  §lexicon **Vocabulary follows the standard of its audience.**
5238
5212
 
@@ -5261,11 +5235,11 @@ Retired terms stay retired: the lexicon guard rejects `thinking`, the unqualifie
5261
5235
  | inbound `SEND` from outside the workspace | the operator's: complete when it fit, otherwise its size and address ({§context-fit}, {§message-projection}); a peer worker's: its first page ({§markerless-first-page}) |
5262
5236
  | structured `EDIT` receipt or textual `COPY`/`MOVE` effects | complete receipt-owned join context |
5263
5237
  | every other nonempty body | the model's own: complete; what it did not author: its first page ({§markerless-first-page}); then {§context-fit} |
5264
- | the `reasoning` row | the model's own reasoning, complete, or no row at all ({§reasoning-row}) |
5238
+ | the `reasoning` row | the optional reasoning preview under {§reasoning-row} |
5265
5239
  | a row the wall took | its size and address, no body and no native part ({§context-own-rows-fit}) |
5266
5240
  | bodyless row | heading and any facts; no coordinate lines; `tokens` includes any selected native part |
5267
5241
 
5268
- §markerless-first-page **What the model did not ask for in size arrives as its first page.** A READ or FIND without a scope, a stream delivered when a command closes, a peer worker's message, an environment delta, an extension's body and a rejected emission shown back all arrive as their first page: `PLURNK_SERVICE_PREVIEW_LINES` lines and at most `PLURNK_SERVICE_PREVIEW_CHARS` characters, in the projection's own units — lines of text, bytes of a byte view ({§read-bytes}), results of a FIND — with one fact in one notation stating the page and the whole, `<1,100> of 4812 lines` (`range` on a retrieval, `preview` on a stored body, {§packet-extent-metadata}). What the model authored stands whole: a NOTE, a WAIT, the body of its SEND, the prompt of its WORK or FORK, the command it handed an executor, and its own reasoning when it lands as a row ({§reasoning-row}). What it asked for exactly stands whole: an explicit scope — `<a,b>`, `<1,-1>`, a pattern — and an EDIT receipt, bounded by its own rule ({§edit-result-receipt-truth}). The operator's message keeps its own rule ({§message-projection}) and an emission row its head ({§emission-row}); those are the only exceptions, so the model can reason about every page the same way. A page lands under {§context-fit} like any result: whole when it fits the remaining budget, otherwise the prefix and receipt. Retrievals take their page at the source, before storage, and the packet applies no second cut to a stored result; a stored body takes its page in the packet, and the rest stays readable at the row's address. No operation carries a page size of its own.
5242
+ §markerless-first-page **What the model did not ask for in size arrives as its first page.** A READ or FIND without a scope, a stream delivered when a command closes, a peer worker's message, an environment delta, an extension's body and a rejected emission shown back all arrive as their first page: `PLURNK_SERVICE_PREVIEW_LINES` lines and at most `PLURNK_SERVICE_PREVIEW_CHARS` characters, in the projection's own units — lines of text, bytes of a byte view ({§read-bytes}), results of a FIND — with one fact in one notation stating the page and the whole, `<1,100> of 4812 lines` (`range` on a retrieval, `preview` on a stored body, {§packet-extent-metadata}). What the model authored stands whole: a NOTE, a WAIT, the body of its SEND, the prompt of its WORK or FORK, and the command it handed an executor. Its own reasoning, when it lands as a row, stands whole only when it fits the row's page and otherwise takes its last page ({§reasoning-row}). What it asked for exactly stands whole: an explicit scope — `<a,b>`, `<1,-1>`, a pattern — and an EDIT receipt, bounded by its own rule ({§edit-result-receipt-truth}). The operator's message keeps its own rule ({§message-projection}) and an emission row its head ({§emission-row}); those are the only exceptions, so the model can reason about every page the same way. A page lands under {§context-fit} like any result: whole when it fits the remaining budget, otherwise the prefix and receipt. Retrievals take their page at the source, before storage, and the packet applies no second cut to a stored result; a stored body takes its page in the packet, and the rest stays readable at the row's address. No operation carries a page size of its own.
5269
5243
 
5270
5244
  READ and FIND own their range or pagination before packet rendering; the packet never applies a second hidden substring bound to their selected result. Reasoning arrives through ordinary scoped READs ({§reasoning-history}). When a visible projection differs from its canonical body, metadata carries `preview` under {§packet-extent-metadata}; complete and fully suppressed bodies omit it. ```` ```READ (log:///<coordinate>/<OP>) ```` selects untrimmed lines in original coordinates under {§log-readable-projection}; the unsuffixed exact shorthand and authoritative suffix behavior are defined by {§log-coordinate-hierarchy}. ```` ```FIND (log:///...) ```` and search match that same readable view. 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.
5271
5245
 
@@ -5416,83 +5390,14 @@ the same deadline through {§application-loop-observation}, not a restarted cloc
5416
5390
 
5417
5391
  §share **A share is the database's record, ready to send.** `plurnk-service share [<file.db>] [<folder>]`, and `npm run share` from a checkout, take a consistent copy of the database (`VACUUM INTO`; a live database is never read in place), and write its digest into `<folder>`, an ordinary folder the user archives or attaches however they like. Without a database the service's own is shared. Nothing is overwritten: a folder that exists and is not empty is refused, and a caller reusing a place removes it first. The share is the user's bug report and our dogfood, benchmark and forensics artifact alike.
5418
5392
 
5419
- §share-snapshot **A database is copied by SQLite, never by the filesystem.** `Share.snapshot(dbPath, copy)`, exported as `@plurnk/plurnk-service/share` with `Share.write`, is the one consistent copy: a byte copy of a WAL-mode database drops every committed page still in its `-wal` file. A harness that keeps the database beside its digest takes it through `snapshot`; an existing `copy` is refused.
5420
-
5421
5393
  §share-scope **A share is unredacted.** `--workspace=<id>` limits a share to one workspace; without it the whole database is shared. Nothing is filtered, redacted or scanned: a share holds what the models saw and wrote in scope, including prompts, file contents read, command output and reasoning, and the command says so. `--requiem` adds the forensic interview ({§digest-requiem}), which calls a model; `plurnk-service requiem <file.db> <folder>` adds it later to a digest already written.
5422
5394
 
5423
5395
  §share-folder **Shares land in one place.** With no folder named, a share is a stamped child, `share-<UTC stamp>`, of `PLURNK_SERVICE_SHARE_FOLDER` (a leading `~/` expands, as for every explicit Plurnk path) or of `$XDG_STATE_HOME/plurnk/shares`.
5424
5396
 
5425
- §digest-programmatic-surface **The digest is an importable forensic surface.**
5426
-
5427
- | Surface | Contract |
5428
- | -------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
5429
- | 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. |
5430
- | `run({ dbPath })` | Reads the required database and writes a complete digest to `./test/digest` relative to the caller's working directory. |
5431
- | `digestDir` | Selects a nonempty output path. `run` refuses a folder that exists and is not empty, and `requiem` refuses an existing `requiem.json` or `requiem.md`, before database or provider I/O; neither deletes ({§share}). Concurrent callers use distinct folders. |
5432
- | Reader lifetime | `run` reads heavy evidence on demand while rendering, then closes its reader on success or failure. `requiem` closes its reader before awaiting witness inference. |
5433
- | §candidate-pinned-runtime Candidate runtime | At launch, after its optional build, the candidate copies every workspace's package projection (`files`) into `<state>/runtime`, links third-party dependencies, and resolves `@plurnk/*` to those copies. Its daemon and its digest export both run from that copy, never the shared checkout, so neither source edits nor a concurrent candidate's or developer's rebuild after launch changes the code a run finishes on. The copy is removed once the digest is written. |
5434
- | Export completion | Packet and response bodies are read and serialized one record at a time, without discarding evidence. `digest.json` is promoted from a partial file only after every artifact is written; its absence identifies an incomplete export. |
5435
- | `workerId` | Narrows workers and every dependent loop, turn, turn-attached logical inference, specialization, physical request, and log row to that one worker. |
5436
- | `workspaceId` | Narrows workers plus every logical inference and dependent evidence owned by one workspace, when both selectors are present they intersect. |
5437
-
5438
- §digest-cost-kind **Cost basis named.** A rendered Cost line carries the basis of its dollar figure: `(charged)` only when every settled request's cost is provider-charged; `(estimated — catalog rates)` when any settled request's cost is an estimate, because a mixed sum is no more trustworthy than its weakest term. A dollar figure without its basis reads as billed truth, and an estimate must never impersonate a charge.
5397
+ §candidate-pinned-runtime **Candidate runtime stays pinned.** At launch, after its optional build, the candidate copies every workspace's package projection (`files`) into `<state>/runtime`, links third-party dependencies, and resolves `@plurnk/*` to those copies. Its daemon and its digest export both run from that copy, never the shared checkout, so neither source edits nor a concurrent candidate's or developer's rebuild after launch changes the code a run finishes on. The copy is removed once the digest is written.
5439
5398
 
5440
5399
  §output-allowance-notice **The output allowance is not disclosed; a ceiling cut names its cause.** The packet's budget section carries the curation state and no response allowance: a model does not plan in tokens and no harness tells it its output ceiling, so the number is a fact without a use (#826). Overflow tolerance (#482) is likewise never advertised; a cut's notice names the true per-call grant from the response's own capacity record. When a provider finish is `length`, the engine emits an `output_truncated` notice (source `engine:capacity`) naming the allowance — the fact alone, never advice on what to do about it — on every path — railed or not — and the rails verdict never blames the model's grammar for a cut the engine's own ceiling made. The same precedence governs a cut so deep no operation parses: the rejection notice names the truncation as the cause, not the parser's symptom, overriding {§invalid-emission-attempts}'s parser diagnostic for `length` finishes.
5441
5400
 
5442
- §digest-wire-line **Wire health aggregated.** Each worker summary renders a `Wire:` line — total physical provider requests, error-outcome count, and the error percentage when nonzero. Provider-level failures are absorbed by retries below the packet stream, so without this aggregate a rate-limit storm is invisible in every summary while the model's experience stays clean.
5443
-
5444
- §digest-cache-ledger **Measured cache reuse and estimated prompt overlap are separate.**
5445
-
5446
- | Projection | Meaning |
5447
- |---|---|
5448
- | `digest.json` provider-request `cachedTokens`, `inputTokens` | Exact provider-reported cache reads and input tokens; absent quantities remain `null`, reported zero remains zero. Every physical request counts, including retries and first requests of new loops. Stored packet availability is irrelevant to these counters. |
5449
- | Turn `cache=<cached>/<input>` | Sum each measured quantity over that turn's requests. If any request omits a quantity, that sum is `?`. |
5450
- | Workspace `Cache: <cached> of <input> reported input tokens read from cache (<pct>%) over <n> requests` | Sum only requests reporting both counters. Percentage is cache reads / input, rounded to one decimal; zero input is `n/a`. Requests missing either counter are counted separately as `missing input or cache usage (excluded)`. |
5451
- | `digest.json` provider-request `adjacentPrefixTokensEstimate` | Optional loop-local diagnostic: the longest common character prefix with the preceding request, weighted under {§tokenomics-agnostic-ruler} as a share of the current stored prompt, multiplied by reported input tokens. First request: `0`; missing current/preceding packet or current input: `null`. Empty prompts have zero overlap. |
5452
-
5453
- The prefix estimate uses the stored emission packet's wire message order, roles
5454
- and content. A BARE request's input is not that packet; its prefix estimate and
5455
- the following request's comparison are unknown. The estimate is
5456
- neither provider tokenization nor a cache ceiling, and never supplies a cache-ratio
5457
- denominator. Caching across loops or against other provider-resident prefixes
5458
- does not make the measured counters inconsistent.
5459
-
5460
- §digest-edit-census **Every model EDIT by the form it authored, how it landed, and whether it came back.** For each worker the digest reads every model-authored EDIT row and classifies the form from the row's stored marker and the durable statement's pattern: `hash` (one anchor), `line` (one line number), `range` (two marks), `insert` (the zero-width `<L,1,L,1>` form, {§zero-width-column-one-insert}), `column` (any other four-mark region), `prepend` / `append` (`<0>` / `<-1>`), `offset` (a tolerated anchor offset, {§anchor-offset}), `pattern` (a selection matcher), `whole` (no marker: a creation when it lands 201). It counts the EDITs, those refused (status ≥ 400), and the *revisits*: an EDIT of a path the same worker had edited within its previous two model turns — the shape of a repair without the claim of one. Each worker summary renders `EDITs: <n> · <form>=<count>… · refused=<k> · revisits=<r>` (`(no edits)` for none); `digest.json` carries the census as `edit_census` on every worker and stamps every EDIT log entry with its `edit_form` and `edit_revisit`. A form is a fact about what was written, never about intent; the bench sheet reads the counts as friction and leaves the judgement to the reader.
5461
-
5462
- §digest-forensic-fidelity **Forensic fidelity and cardinality.** The digest's machine-readable JSON preserves every log event with its initial and current projection, causal `source`, and structured `attrs`; every exact log-KILL target effect; the exact Problem on every failed row; each loop's exact terminal result, settlement time, scheduled due time, recurring interval, and recurrence lineage; and every ordered physical provider request. Programs still produce chronological `assistant.md` artifacts after every READ receipt is KILLed; source is independent of log curation. Each worker summary's `Emissions:` line counts its announced emission rows, those the worker KILLed, and the headings it echoed ({§emission-row}); its `Reasonings:` line counts its landed reasoning rows, those the worker KILLed, and the turns that reasoned ({§reasoning-row}); the op mix leaves both harness rows out. Each stored packet validates independently: one malformed historical packet remains exact raw evidence with its complete validation error chain and never prevents healthy turns from being projected. Accounting on broader rows is the shared exact derivation from that ledger, never a second stored fact. A worker's Cost line names how many settled requests carry no usage at all (errored or aborted exchanges) — their server-side spend is unrecorded rather than silently priced as zero. The reasoning chronology distinguishes readable reasoning content from provider-reported reasoning usage: when tokens were reported but no readable content was returned, it states both facts instead of implying that no reasoning occurred. 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 consecutive 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, and non-consecutive events preserve their chronological order. Thus amplification is conspicuous without making the diagnostic artifact itself pathological; valid packet files remain byte-identical records of what the model saw.
5463
-
5464
- Unrecognized actionless log rows are retained and labelled as such, not
5465
- interpreted as executable turnOps or allowed to prevent the remaining digest.
5466
-
5467
- §digest-executor-evidence **A red command is work, not a defect.** Engine-materialized
5468
- completion rows for a failed command carry the executor's problem identity
5469
- (`https://problems.plurnk.xyz/executor/*`), and the digest classifies them as
5470
- evidence: they render like any row but never count toward a loop's error total,
5471
- its health verdict, or the per-turn `errs=` badge — a loop that concluded green
5472
- over red test runs is CLEAN, not DEGENERATE-WIN. This is the digest mirror of the
5473
- strike rail's exemption ({§engine-rails}, #425 F1): structural violations count,
5474
- executor evidence never does.
5475
-
5476
- §digest-requiem **A requiem is an out-of-band forensic interview, not a worker
5477
- turn.** It cannot execute operations or alter the audited history.
5478
-
5479
- | Aspect | Contract |
5480
- |-----------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|
5481
- | Scope | One interview for each worker with model-bearing inference turns; workers without inference evidence are omitted. |
5482
- | Evidence | The worker's final packet plus every attempt's exact normalized response and admission evidence; opaque raw transport remains in durable forensic artifacts. Quoted evidence is budgeted to the witness window ({§digest-requiem-evidence-budget}). |
5483
- | Witness | An explicitly supplied provider or the active configured provider; absence fails hard. |
5484
- | Identity | The worker's durable provider identity ({§worker-provider-identity}) is sent as the `workerId`, without asserting a live worker topology. |
5485
- | Attempts | One call at `PLURNK_SERVICE_REQUIEM_MAX_TOKENS`; only an empty length-limited response receives one retry at `PLURNK_SERVICE_REQUIEM_RETRY_MAX_TOKENS`. |
5486
- | Artifacts | `requiem.md` carries testimony and exact nullable USD accounting. `requiem.json` is durably materialized before each call and preserves logical call state, messages, normalized responses, every physical request's state and accounting, and their shared aggregate projection. |
5487
-
5488
- §digest-requiem-evidence-budget **Quoted evidence fits the witness.** The
5489
- interview's user message is budgeted against the witness provider's context
5490
- window minus the retry output allowance and system framing (chars/2, the
5491
- capacity gate's own estimator). Overflow elides the oldest provider attempts
5492
- behind an explicit `elidedOldestAttempts` count marker, never silently; the
5493
- final packet and the newest attempts always testify. A windowless witness
5494
- (`contextWindow` null) quotes unbudgeted.
5495
-
5496
5401
  §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. The completion beat carries the spend ({§turn-accounting-notice}). 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}).
5497
5402
 
5498
5403
  §turn-accounting-notice **The completion beat carries the spend.** `turn_generated`
@@ -5510,9 +5415,9 @@ content-offset position: reasoning coordinates do not address the content source
5510
5415
  §tools-resource-discovery **Executable capability discovery uses ordinary
5511
5416
  Plurnk resources.** No generated tool table rides the system packet. Every
5512
5417
  runtime enabled for the current worker with an admitted invocation materializes one
5513
- family document at `worker:///_plurnk/plurnk/<runtime>.md`. A general runtime's
5418
+ runtime document at `worker:///_plurnk/plurnk/<runtime>.md`. A general runtime's
5514
5419
  document contains its {§executor-tool-document}; a runtime with an exact
5515
- {§executor-tool-registry} materializes a compact catalog at the same address. The family document summarizes
5420
+ {§executor-tool-registry} materializes a compact catalog at the same address. The runtime document summarizes
5516
5421
  the server or runtime, lists every enabled target as a directly copyable
5517
5422
  executable fence named for the runtime, with its input preview ({§operation-aside} carries the
5518
5423
  target one-liner; no invocation dispatch would reject is ever advertised).
@@ -5523,13 +5428,13 @@ preserve the full tool description and raw input schema under
5523
5428
  Turn0 rows. A schema-backed general runtime uses `<runtime>/input.md`.
5524
5429
  Non-schema targets retain supplemental details in family sections.
5525
5430
  Tool-result/output schemas remain ordinary evidence, not teaching. Unknown-target
5526
- recovery names the published family document through the same path owner as
5431
+ recovery names the published runtime document through the same path owner as
5527
5432
  materialization, including a runtime's declared `resourcesPath`.
5528
5433
 
5529
5434
  ```mermaid
5530
5435
  flowchart LR
5531
- Survey["Turn 0 FIND<br/>tools/*.md"] --> Families["family paths + summaries"]
5532
- Families --> Read["READ selected family<br/>only when needed"]
5436
+ Survey["Turn 0 FIND<br/>tools/*.md"] --> Runtimes["runtime paths + summaries"]
5437
+ Runtimes --> Read["READ selected runtime<br/>only when needed"]
5533
5438
  Read --> Exec["execution with an aside"]
5534
5439
  Read --> Schema["READ linked input schema<br/>when the preview is insufficient"]
5535
5440
  Schema --> Exec
@@ -5538,19 +5443,19 @@ flowchart LR
5538
5443
  §tools-resource-materialization The runtime registry, workspace capability policy,
5539
5444
  tool resources, and dispatch use one effective workspace snapshot. A
5540
5445
  disabled, unavailable, detached, replaced, or removed runtime has no
5541
- tool resource; an exact registry's empty set publishes no executable family and
5446
+ tool resource; an exact registry's empty set publishes no runtime and
5542
5447
  admits no invocation. Reconciliation deletes stale documents
5543
5448
  before upserting the current set. `PLURNK_SERVICE_DOCS_EXCLUDE` does not hide an
5544
5449
  enabled executable; executor enablement is the sole user-configured filter
5545
5450
  shared by discovery and dispatch. A runtime declaration may carry
5546
5451
  `resourcesPath` — its generated-doc root relative to the workspace's generated
5547
5452
  subtree ({§worker-generated-subtree}). Absent, its docs live in the internal
5548
- `_plurnk/plurnk` namespace; present (attached MCP families: `/tools`),
5549
- the family document materializes at `_plurnk` + that root in the
5550
- shared scratch. Turn 0 surveys the families (`FIND
5453
+ `_plurnk/plurnk` namespace; present (attached MCP servers: `/tools`),
5454
+ the runtime document materializes at `_plurnk` + that root in the
5455
+ shared scratch. Turn 0 surveys the runtimes (`FIND
5551
5456
  (worker:///_plurnk/tools/*.md)`, one row per
5552
5457
  server carrying its summary) and, for each server named in
5553
- `PLURNK_MCP_EXPANDED`, adds one FIND over its family document matching the
5458
+ `PLURNK_MCP_EXPANDED`, adds one FIND over its runtime document matching the
5554
5459
  complete executable blocks (`FIND (worker:///_plurnk/tools/<server>.md)`
5555
5460
  with a multiline regex over matching fences), so turn 0 names every tool with its aside and
5556
5461
  signature — one row per tool, paged like every survey. Capability attenuation
@@ -5630,155 +5535,27 @@ definitions ({§actor-boundary-catalog-preview}), so the model sees why a file i
5630
5535
  not a member before it asks. There is no other membership path: the client's `/members`
5631
5536
  verbs are these verbs.
5632
5537
 
5633
- §skills-functionality **Agent Skills are one workspace Functionality family.**
5634
- Core registers the `skills` family with the coordinator ({§functionality-coordinator});
5635
- its adapter owns protocol truth for standard Agent Skills and nothing else. A
5636
- definition is `SkillDefinition`: the standard skill `name`, its `source`, and
5637
- optional Git `ref`/resolved `commit` ({§skills-sources}). Only a host-provided
5638
- resource tree omits `source`. Source location is not mutation ownership: standard
5639
- project/global roots are read-only configuration inputs; live changes belong to
5640
- the workspace. Plurnk neither installs into nor deletes from those roots.
5641
-
5642
- *Available definitions.* The filesystem is the only truth about installation:
5643
- every `<root>/<name>/SKILL.md` directory under the project, plurnk, then global
5644
- root is one service-origin definition, a nearer root shadowing a farther one and
5645
- all of them shadowing host-provided trees by name. Each filesystem definition
5646
- names its actual source directory. The workspace's durable state owns
5647
- enablement ({§functionality-state}); a disabled skill stays client-visible and
5648
- leaves no model-facing trace.
5649
-
5650
- §skills-configuration **Skills use the shared definition cascade.**
5651
-
5652
- | Layer, low to high | Definition source |
5653
- |---|---|
5654
- | Service | Host-provided trees |
5655
- | Standard locations | Global, plurnk, then project roots selected by {§agent-roots} |
5656
- | Cascading environment | `PLURNK_SKILLS_<name>={"name":"<name>","source":"…","ref"?:"…"}` replaces the complete definition |
5657
- | Live workspace | `skills (add)` creates a workspace definition through {§functionality-coordinator} |
5658
-
5659
- `PLURNK_SKILLS_ENABLED` supplies default enabledness; `<name>_ENABLED` overrides
5660
- it independently ({§resource-environment}). The decoded environment alias must
5661
- equal the standard skill name, including digit-leading and Unicode names.
5662
- Blank definitions are invalid; controls may precede a definition. Environment
5663
- validation checks shape, names, remote URL rules, and Git-only `ref` without
5664
- fetching or opening a source; `commit` is service-recorded, not an input.
5665
-
5666
- *Discovery is inert.* `discover {source}` lists the standard skills one source
5667
- carries, each a candidate with `source` provenance and the exact definition to
5668
- add; it never installs, persists, or enables. Agent Skills have no standard
5669
- registry, so `discover {query}` is 400 `query-unsupported`, naming the source
5670
- forms. Client `configuration` contributes nothing and is refused with 400.
5671
-
5672
- *Admission.* `add {alias, definition}` requires `alias = name` and a `source`;
5673
- the workspace definition may shadow a service skill of the same name. Relative
5674
- sources require a project root; absolute sources work in headless workspaces.
5675
- A local source is recorded as its absolute path.
5676
- A git source records the `commit` its `ref` names at admission, or its default
5677
- branch's when no `ref` is given; `ref` belongs to git sources, and a supplied
5678
- `commit` is refused because the service records it. The family's aliases use
5679
- the standard skill-name grammar ({§agent-skills-name}), including digit-leading
5680
- and Unicode names, rather than the coordinator's generic default.
5681
-
5682
- *Preparation.* For each enabled alias the adapter selects the host-provided
5683
- tree or resolves the complete source definition ({§skills-sources}). Local
5684
- folders and their `SKILL.md` files remain live references, including supporting
5685
- resources and symlink retargeting. Git/archive sources are materialized only
5686
- inside {§module-workspace-directory}; different workspaces and complete source
5687
- definitions cannot reuse each other's materializations accidentally.
5688
- The first fetched Git/archive copy remains stable across enable, cooling, and
5689
- restart until the complete source definition changes. In particular, an
5690
- operator-configured symbolic Git ref is not an implicit update subscription.
5691
- Each admitted skill requires standard `name` and `description` frontmatter
5692
- with `name` matching its directory. A missing, uninstallable, or invalid skill
5693
- is `unavailable` with its exact Problem ({§problems-functionality}) under the
5694
- coordinator's failure policy ({§functionality-model-mutation}); one bad skill
5695
- never fails the family.
5696
-
5697
- Removal follows {§skills-remove}.
5698
-
5699
- §skills-sources **A source is a git remote, a folder, or a file, read with standard tools.**
5700
- Fetching runs nothing it fetched. Materialized copies cannot contain references
5701
- outside their skill; live resources retain {§agent-skills-directory} containment.
5702
-
5703
- | Source | How it is read |
5704
- |---|---|
5705
- | Git remote: a full `https://` or `ssh://` URL, or `user@host:path` | `git ls-remote` resolves the ref at admission; preparation shallow-clones it with hooks and submodules off, and a checkout at any other commit is 409 `source-moved` |
5706
- | Folder: absolute, `~/`, or relative to the project root | Live reference; standard directory/name matching applies |
5707
- | A file named `SKILL.md` | Live reference to its skill directory and supporting resources |
5708
- | A `.zip`, `.tar`, `.tgz`, `.tar.gz`, `.tar.bz2`, `.tar.xz`, or `.tar.zst` archive | Unpacked into private staging with `unzip` or `tar`; a lone top-level directory is the source's root |
5709
-
5710
- Any other scheme, plain `http`, `owner/repo` shorthand, and an https URL carrying
5711
- credentials are refused with `source-invalid` or `source-missing`: shorthand names no
5712
- forge, and a recorded source is listed to every client. Git runs with the
5713
- operator's configuration, credentials, and SSH agent, never plurnk's secrets, and
5714
- never prompts; `PLURNK_SERVICE_SKILLS_FETCH_TIMEOUT_MS` bounds each fetch. The
5715
- retired vendor-installer knobs (`PLURNK_SERVICE_SKILLS_CLI`, `_CLI_TIMEOUT_MS`,
5716
- `_REGISTRY_URL`, `_REGISTRY_LIMIT`, `_REGISTRY_TIMEOUT_MS`) make the skills family
5717
- unavailable when set, each naming what replaced it ({§configuration-repair-path}).
5718
-
5719
- A source's skills are the directories holding a `SKILL.md`, found by walking
5720
- from its root without entering `.git` or a skill already found. A fetched skill at
5721
- the root is named by its frontmatter ({§agent-skills-name}); local references and
5722
- directories below the root use the standard folder rule. A source with `plugin.json` at its root is an
5723
- Agent Plugin and is refused with 422 `source-is-plugin`, so its skills keep the
5724
- plugin's identity. Materialization copies the named skill beside its workspace-owned destination
5725
- and renames it to `<root>/<name>`; a copy that holds a link out of the skill, or
5726
- anything but files, directories, and inward links, is refused with 422
5727
- `source-unsafe` and leaves nothing behind.
5728
-
5729
- §skills-resources **A skill is a resource tree, not a rewritten document.**
5730
- The family exposes enabled, available {§agent-skills-tree} sources through
5731
- `skill://<name>/`. The source owns its bytes; commons entries are demand-loaded
5732
- projections, not writable installations. Filesystem skills retain their original
5733
- directories; service-provided trees need no generated filesystem directory.
5734
- The authority is the name's WHATWG URI representation, including percent-encoding
5735
- for non-ASCII names. Installation names remain unchanged; a raw spelling and its
5736
- serialized URI address the same resource, not separate skill identities.
5737
-
5738
- | Operation | Contract |
5739
- | --- | --- |
5740
- | Turn0 `FIND (skill://*/SKILL.md)` | One ordinary resource catalog: name, address, and standard frontmatter description via {§mimetype-summary}. No synthetic index, body injection, or execution. |
5741
- | `READ (skill://<name>/SKILL.md)` | Original frontmatter and Markdown, unchanged; relative links remain relative to the source layout. |
5742
- | `READ` / `FIND` below the authority | References, scripts, and assets retain their source paths and ordinary pattern, channel, byte, and multimodal semantics. Acquisition observes current source contents, including disappearance. |
5743
- | ```` ```runtime (skill://<name>/scripts/program.ext) ```` | Ordinary resource execution and proposal policy; preserve the native file and its siblings under {§exec-source-temporary}. Discovery and READ never execute scripts. |
5744
- | Model mutation | Read-only; no EDIT, SEND, or KILL of skill resources. Manage definitions and enablement through ```` ```skills ````. |
5745
- | Disable / unavailable / remove | Withdraw the authority from new resource access and discovery. Existing log receipts remain historical evidence. |
5746
- | WORK / FORK | Use the same workspace Functionality, not copied definitions or resource caches. |
5747
-
5748
- Explicit skill URIs address these resources; bare operation paths still address
5749
- project files, with no implicit current-skill directory. Source resolution follows
5750
- {§agent-skills-directory}, including symlinked skill directories and containment of references.
5751
- An uninstalled Git skill is not manufactured by repository detection.
5538
+ The skills module owns the Agent Skills family ({§skills-functionality}) and its resource trees
5539
+ ({§skills-resources}); core supplies the Plurnk reference through {§provided-skills-module-slice}.
5752
5540
 
5753
5541
  §plurnk-skill **Plurnk's own reference is an ordinary service-provided skill.**
5754
5542
  `skill://plurnk/SKILL.md` is the standard frontmatter entry point, catalogued with
5755
- other enabled skills. It links package-owned configuration, model, and COPY/MOVE chapters,
5756
- the complete `.env.defaults` aggregate at `skill://plurnk/.env.defaults`, and the
5757
- Worker's existing tool/resource references. No chapter or defaults body is
5758
- injected merely because the skill is enabled. The defaults bytes come from the
5543
+ other enabled skills. It links package-owned configuration, model, COPY/MOVE and extensibility
5544
+ chapters, the complete `.env.defaults` aggregate at `skill://plurnk/.env.defaults`, the
5545
+ installed contracts at `skill://plurnk/packages/<package name>/SPEC.md`, and the
5546
+ Worker's existing tool/resource references. The contracts are the service's own `SPEC.md` and
5547
+ each installed ecosystem package's that ships one, the same membership as the defaults
5548
+ aggregate, with that package's published type declarations beside it at
5549
+ `packages/<package name>/dist/**/*.d.ts`; the service's declarations are its internals and are not
5550
+ served. Contracts are listed when the tree is listed and read where each package installed them,
5551
+ never through a symbolic link. No chapter, contract or defaults body is injected merely because the
5552
+ skill is enabled. The defaults bytes come from the
5759
5553
  same {§operator-config-env-defaults} renderer as the operator command, never the
5760
5554
  effective environment. Native chapter files retain their owners and locations;
5761
5555
  runtime-generated bytes have no invented disk location. Disable/enable,
5762
5556
  shared workspace visibility, and project/global shadowing use the ordinary Skills lifecycle.
5763
5557
  Service-provided skills are not installer targets; removal follows {§skills-remove}.
5764
5558
 
5765
- §skills-remove **`remove` forgets the workspace binding, not the source.**
5766
- It withdraws that definition and restores any inherited definition and enabledness
5767
- ({§functionality-coordinator}). External folders are never deleted. Fetched
5768
- materializations remain workspace-owned operational state, reusable only for the
5769
- same complete definition; they confer no availability without a definition.
5770
- Inherited definitions cannot be removed here; their enabledness can be overridden.
5771
-
5772
- §skills-hotload **Skills placed out of band are admitted at the next turn** ({§functionality-hotload}). The
5773
- family keeps one signature of the discovered roots, configured definitions, source locations, and `SKILL.md` sources
5774
- per resident workspace, read before a publication loads the skills it describes. Turn admission
5775
- recomputes it under the workspace gate before packet assembly: a changed signature republishes the
5776
- family, and an unchanged one republishes only when the skills the coordinator would publish differ
5777
- from the published ones. A skill installed, edited or removed by any other tool is therefore
5778
- discoverable in the first subsequent model turn, while an unchanged set dispatches nothing. The model manages skills
5779
- only through the generated ```` ```skills ```` family
5780
- ({§functionality-model-projection}); it is never taught a package manager.
5781
-
5782
5559
  The catalog and Turn0 describe Functionality under the current workspace
5783
5560
  capability policy and service ceiling. A direct denied attempt receives the
5784
5561
  same exact 403 from dispatch rather than a second documentation policy.
@@ -5800,7 +5577,7 @@ section because they are language extensions rather than executable tools.
5800
5577
 
5801
5578
  ### §inject system.inject — the operator injection
5802
5579
 
5803
- §packet-inject When `PLURNK_SERVICE_PACKET_INJECT` names a readable markdown file, its content renders as an `## Operator Notes` section in the system slot (definition → policy → inject). Read per-turn so the operator's edits take effect live; a set-but-unreadable path fails the turn hard as {§policy-sections} rules. `~/` 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.
5580
+ §packet-inject When `PLURNK_SERVICE_PACKET_INJECT` names a readable markdown file, its content renders as an `## Operator Notes` section in the system slot (definition → policy → inject). Read per-turn so the operator's edits take effect live; a set-but-unreadable path fails the turn hard as {§policy-sections} rules. `~/` expands to home. It's the operator-side complement to the extension packet transform — a pressure valve so reshaping the packet edits operator content, never the core. Unset → no section.
5804
5581
 
5805
5582
  ### §policy system.policy — the client's policy injection
5806
5583
 
@@ -6193,12 +5970,12 @@ caller's own run directory.
6193
5970
 
6194
5971
  Every Problem code core mints is named here under its family ({§problem-error-carrier} carries it); the root lint (`scripts/problem-codes.mjs`) refuses a code no owning SPEC names.
6195
5972
 
6196
- §problems-dispatch **Dispatch Problems.** Every code this family mints, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
5973
+ §problems-dispatch **Dispatch Problems.** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
6197
5974
 
6198
5975
  | code | status | contract |
6199
5976
  |---|---:|---|
6200
5977
  | `target-required` | 400 | *OP* requires a target path. Recovery: Write the target in parentheses on the opening fence line: `OP (path)`. |
6201
- | `scheme-not-found` | 501 | Scheme '*name*' is not registered. |
5978
+ | `scheme-not-found` | 501 | Scheme '*name*' is not registered. Recovery: ({§unregistered-scheme-recovery}) `` `*host*` is an executor: run ```*host* (*tool*)``` with its input in the body. `` when the address's authority is one, else `Registered schemes: *names*.` |
6202
5979
  | `scheme-metadata-unsupported` | 400 | *OP* on '*scheme*' does not accept the [metadata] modifier. |
6203
5980
  | `operation-not-implemented` | 501 | Scheme '*name*' does not implement *OP* (or exec). |
6204
5981
  | `entry-read-not-implemented` | 501 | The '*scheme*' scheme does not provide entry reads. |
@@ -6209,7 +5986,7 @@ Every Problem code core mints is named here under its family ({§problem-error-c
6209
5986
  | `exec-source-not-data` | 501 | Scheme '*name*' is not a data source for an execution. |
6210
5987
  | `writer-forbidden` | 403 | Writer '*origin*' cannot modify scheme '*name*'. |
6211
5988
  | `capability-denied` | 403 | Capability '*route*' is denied by *scope* policy. |
6212
- | `spawn-prompt-empty` | 422 | *OP* has no prompt text: the resource is empty and there is no body. |
5989
+ | `spawn-prompt-empty` | 422 | *OP* has no prompt text. Recovery: Write the prompt on the lines beneath the *OP* fence line. A prompt resource that is empty with no body says so: *OP* has no prompt text: the resource is empty and there is no body. Recovery: Write the prompt on the lines beneath the *OP* fence line, or name a resource that holds it. |
6213
5990
  | `message-not-found` | 404 | No accepted message exists at *address*. |
6214
5991
  | `edit-collision` | 409 | EDIT collided with the current resource state ({§edit-collision}). Recovery: *n* of *m* edits applied. READ the target for current coordinates. |
6215
5992
  | `edit-target-required` | 400 | A line-anchored EDIT requires a target resource. Recovery: Provide the target that rendered the line anchor. |
@@ -6225,7 +6002,13 @@ Every Problem code core mints is named here under its family ({§problem-error-c
6225
6002
  | `no-operation` | 422 | The turn performed no operation ({§empty-turn}). |
6226
6003
  | `send-target-not-a-recipient` | 400 | The addressed scheme is not a SEND recipient. Recovery: A targetless SEND answers the open messages; a directed SEND requires a recipient that implements SEND. |
6227
6004
 
6228
- §problems-content **Content and transfer Problems.** Every code this family mints, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
6005
+ §unregistered-scheme-recovery **An unregistered scheme's refusal names what does exist.** When the
6006
+ address's authority is an executor available to the workspace — an MCP server's tool written as
6007
+ `tool://gh/get_me` — the recovery is that executor's fence with the address's path as its target;
6008
+ otherwise it lists the schemes the workspace registers. READ, FIND, KILL and resource selection share
6009
+ the sentence.
6010
+
6011
+ §problems-content **Content and transfer Problems.** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
6229
6012
 
6230
6013
  | code | status | contract |
6231
6014
  |---|---:|---|
@@ -6242,7 +6025,7 @@ Every Problem code core mints is named here under its family ({§problem-error-c
6242
6025
  | `proposal-apply-missing` | 500 | The source scheme accepted its MOVE proposal without applying the source mutation. |
6243
6026
  | `line-anchor-collision` | 409 | READ coordinates collided with current content at *target*. |
6244
6027
 
6245
- §problems-file **File scheme Problems.** Every code this family mints, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
6028
+ §problems-file **File scheme Problems.** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
6246
6029
 
6247
6030
  | code | status | contract |
6248
6031
  |---|---:|---|
@@ -6259,18 +6042,18 @@ Every Problem code core mints is named here under its family ({§problem-error-c
6259
6042
  | `file-create-excluded` | 403 | A members exclusion (`!_glob_`) covers '*path*'. Recovery: Remove or disable the excluding members definition, or choose another path. |
6260
6043
  | `file-create-gitignored` | 403 | Active Git policy ignores '*path*', and no members definition includes it. Recovery: Choose a Git-admitted path or add a members definition that includes it. |
6261
6044
  | `file-materialization-limit` | 413 | The file exceeds the materialization byte limit and is not read into the workspace. |
6262
- | `entry-not-found` | 404 | No member of this workspace is at '*path*'. Recovery: Check the path with FIND. EDIT creates files; `members (add)` admits existing files with a `{"glob": "<path>"}` body. |
6045
+ | `entry-not-found` | 404 | No member of this workspace is at '*path*'. Recovery: Check the path with FIND. EDIT creates files; `members (add)` admits existing files with a `{"glob": "<path>"}` body. A path beyond the root recovers instead to: '*path*' is outside the project root: only a members definition under the operator's namespace scope admits it, so keep working files inside the root. |
6263
6046
 
6264
- §problems-exec **Execution Problems.** Every code this family mints, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
6047
+ §problems-exec **Execution Problems.** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
6265
6048
 
6266
6049
  | code | status | contract |
6267
6050
  |---|---:|---|
6268
6051
  | `invalid-input-target` | 400 | SEND input addresses an execution, without a channel or scope. |
6269
6052
  | `input-unavailable` | 409 | This execution's input receiver is no longer enabled. |
6270
- | `stream-not-found` | 404 | No execution exists at the requested address. |
6053
+ | `stream-not-found` | 404 | No execution exists at the requested address. Recovery, when the id holds an execution under another runtime ({§exec-near-miss}): The execution at /*id* is `*runtime*:///*id*`. |
6271
6054
  | `input-closed` | 410 | Execution input is closed. |
6272
6055
 
6273
- §problems-entries **Entry scheme Problems (log, worker, entries).** Every code this family mints, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
6056
+ §problems-entries **Entry scheme Problems (log, worker, entries).** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
6274
6057
 
6275
6058
  | code | status | contract |
6276
6059
  |---|---:|---|
@@ -6283,7 +6066,7 @@ Every Problem code core mints is named here under its family ({§problem-error-c
6283
6066
  | `message-empty` | 400 | SEND has no message text or attachments. |
6284
6067
  | `scope-unsupported` | 400 | A worker SEND takes no scope. |
6285
6068
 
6286
- §problems-functionality **Server and Functionality Problems.** Every code this family mints, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
6069
+ §problems-functionality **Server and Functionality Problems.** Every code minted here, its status, and the sentence that is its contract (placeholders in *italics* are filled at emission; a fixed recovery follows its detail).
6287
6070
 
6288
6071
  | code | status | contract |
6289
6072
  |---|---:|---|
@@ -6295,21 +6078,8 @@ Every Problem code core mints is named here under its family ({§problem-error-c
6295
6078
  | `env-invalid` | 400 | `env` must be an object of string values; '*name*' is not a name a shell can export. |
6296
6079
  | `query-required` | 400 | discover takes a path or a glob. Recovery: Supply `{ "query": "<path or glob>" }`. |
6297
6080
  | `headless` | 409 | The workspace has no project root, so there are no file members. Recovery: Open the workspace on a project root. |
6298
- | `definition-invalid` | 400 | A members definition is { glob }: a gitignore-style pattern, `!glob` to exclude; a skill definition names an installable skill. |
6081
+ | `definition-invalid` | 400 | A members definition is { glob }: a gitignore-style pattern, `!glob` to exclude. |
6299
6082
  | `model-scope` | 403 | The model may not change membership here: the members scope is none. Recovery: `git add` the file so git tracks it, or ask the operator to add it (/members add) or raise PLURNK_SERVICE_MEMBERS_MODEL_SCOPE. |
6300
- | `query-unsupported` | 400 | Agent Skills have no standard registry to search; discover takes a source: a git remote as a full https or ssh URL, a folder, a lone SKILL.md, or a zip or tar archive. |
6301
- | `source-invalid` | 400 | '*source*' is not a valid git remote URL; an https source carries no credentials (git's credential helper supplies them); is not a source: a git remote is a full https or ssh URL; is relative, and this workspace has no project root to resolve it against; or is neither a folder, a SKILL.md, nor a zip or tar archive. |
6302
- | `source-missing` | 404 | No folder or file is at '*source*' (; owner/repo shorthand names no forge, so give the repository's full https or ssh URL). |
6303
- | `source-unreadable` | 422 | '*source*' cannot be read: *cause*; or '*path*' could not be unpacked: *reason*. |
6304
- | `source-unreachable` | 502 | git could not reach '*remote*', or fetch it (at '*ref*'): *reason*. |
6305
- | `ref-missing` | 404 | '*remote*' has no branch or tag '*ref*', or names no default branch. |
6306
- | `source-moved` | 409 | '*source*' *ref* now names *current*; this skill was added at *commit*. Recovery: Remove the skill and add it again to take the current commit. |
6307
- | `source-is-plugin` | 422 | '*source*' is an Agent Plugin; install it as a plugin, so its skills keep the plugin's identity and servers. |
6308
- | `source-unsafe` | 422 | '*path*' links outside its skill, or is neither a file, a directory, nor an inward link. |
6309
- | `skill-not-found` | 404 | '*source*' carries no Agent Skill named '*name*'. |
6310
- | `skill-ambiguous` | 409 | '*source*' carries *count* skills named '*name*'. |
6311
- | `alias-mismatch` | 400 | Alias '*alias*' must equal the skill name '*name*'. |
6312
- | `source-required` | 400 | Adding '*alias*' requires the source that provides it. |
6313
6083
  | `workspace-not-found` | 404 | Workspace *id* does not exist. |
6314
6084
  | `state-not-json` | 400 | Worker module state is not JSON-serializable. |
6315
6085
  | `workspace-busy` | 409 | Workspace *id* is running an operation or another capability change. Recovery: Settle the current operation and retry the capability change. |
@@ -6322,9 +6092,6 @@ Every Problem code core mints is named here under its family ({§problem-error-c
6322
6092
  | `loop-policy-invalid` | 400 | An unattended loop cannot hold a proposal for review: nobody is present to answer. Recovery: State proposals accept or reject, or attend the loop. |
6323
6093
  | `scope-cancelled` | 499 | The worker scope was cancelled: *reason*. |
6324
6094
  | `range-not-satisfiable` | 416 | `Range <0,-1>` starts at 0, which is not a line; lines are numbered from 1. Recovery: Write `<1,-1>` to trim every line of the body; `KILL (log:///…/READ)` with no scope retires the item. |
6325
- | `install-failed` | 500 | Agent Skill '*name*' could not be placed under *root*: *cause*. |
6326
- | `skill-missing` | 404 | Agent Skill '*alias*' is not provided by this service. |
6327
- | `skill-invalid` | 422 | Agent Skill '*alias*' is not a valid standard skill: *cause*. |
6328
6095
 
6329
6096
  §pinned-wording-core **Pinned wording.** Verbatim sentences tests pin: each is contract, and a change here is a change of contract.
6330
6097
 
@@ -6343,3 +6110,4 @@ Every Problem code core mints is named here under its family ({§problem-error-c
6343
6110
  | The execution at ops://*worker*/*loop* has not concluded. | a bare READ of a running worker's result (425) |
6344
6111
  | The child provider failed. | a child's provider failure read back by its parent |
6345
6112
  | '*path*' exists on disk but is not a member of this workspace. Recovery: Admit it with `members (add)` and a `{"glob": "<path>"}` body. | a non-member on disk at the addressed path |
6113
+ | '*path*' exists on disk but is not a member of this workspace. Recovery: The repository ignores it: a client or operator members definition can include it, a model definition cannot. | a non-member the repository ignores ({§membership-read-refusal}) |