dsh-plugin-dev-kb 1.5.2 → 1.8.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 (501) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.en.md +31 -9
  3. package/README.md +42 -14
  4. package/kb/INDEX.md +3 -3
  5. package/kb/README.md +9 -4
  6. package/kb/extra/AGENTS.md +1 -1
  7. package/kb/extra/cli-help.md +15 -7
  8. package/kb/extra/cli-help.zh.md +15 -7
  9. package/kb/extra/cookbook/adding-a-plugin-preview.md +18 -25
  10. package/kb/extra/cookbook/adding-a-plugin-preview.zh.md +18 -25
  11. package/kb/extra/cookbook/reviewing-persistence-type-changes.md +1 -1
  12. package/kb/extra/cookbook/reviewing-persistence-type-changes.zh.md +1 -1
  13. package/kb/extra/cookbook/reviewing-ui-design.md +166 -0
  14. package/kb/extra/cookbook/reviewing-ui-design.zh.md +166 -0
  15. package/kb/extra/deepseek-llm-api-wire-extensions.md +2 -2
  16. package/kb/extra/deepseek-llm-api-wire-extensions.zh.md +2 -2
  17. package/kb/extra/defensive-patterns/conversation-and-session.md +2 -2
  18. package/kb/extra/defensive-patterns/conversation-and-session.zh.md +2 -2
  19. package/kb/extra/defensive-patterns/general.md +2 -0
  20. package/kb/extra/defensive-patterns/general.zh.md +2 -0
  21. package/kb/extra/defensive-patterns/package-surface.md +1 -0
  22. package/kb/extra/defensive-patterns/package-surface.zh.md +1 -0
  23. package/kb/extra/defensive-patterns/remote-and-api.md +5 -3
  24. package/kb/extra/defensive-patterns/remote-and-api.zh.md +5 -3
  25. package/kb/extra/development.md +16 -9
  26. package/kb/extra/development.zh.md +16 -9
  27. package/kb/extra/event-producer-consumer.md +64 -51
  28. package/kb/extra/event-producer-consumer.zh.md +64 -51
  29. package/kb/extra/i18n/README.md +2 -0
  30. package/kb/extra/i18n/README.zh.md +2 -0
  31. package/kb/extra/module-graph.md +204 -92
  32. package/kb/extra/module-graph.zh.md +204 -92
  33. package/kb/extra/persistence-changes/2026-10-13-liveshare-share-viewer-principal.md +60 -0
  34. package/kb/extra/persistence-changes/2026-10-13-liveshare-share-viewer-principal.zh.md +60 -0
  35. package/kb/extra/persistence-changes/2026-10-19-session-team-mode.md +48 -0
  36. package/kb/extra/persistence-changes/2026-10-19-session-team-mode.zh.md +48 -0
  37. package/kb/extra/persistence-changes/2026-10-22-action-card-status.md +60 -0
  38. package/kb/extra/persistence-changes/2026-10-22-action-card-status.zh.md +60 -0
  39. package/kb/extra/persistence-changes/2026-10-25-skill-catalog-incomplete.md +60 -0
  40. package/kb/extra/persistence-changes/2026-10-25-skill-catalog-incomplete.zh.md +60 -0
  41. package/kb/extra/persistence-changes/2026-10-27-retry-control-input.md +60 -0
  42. package/kb/extra/persistence-changes/2026-10-27-retry-control-input.zh.md +60 -0
  43. package/kb/extra/persistence-changes/2026-10-27-subagent-settlement-attribution.md +60 -0
  44. package/kb/extra/persistence-changes/2026-10-27-subagent-settlement-attribution.zh.md +60 -0
  45. package/kb/extra/persistence-changes/2026-11-02-subagent-catalog-names.md +48 -0
  46. package/kb/extra/persistence-changes/2026-11-02-subagent-catalog-names.zh.md +48 -0
  47. package/kb/extra/persistence-changes/2026-11-02-team-task-owner-names.md +48 -0
  48. package/kb/extra/persistence-changes/2026-11-02-team-task-owner-names.zh.md +48 -0
  49. package/kb/extra/persistence-changes/README.md +2 -0
  50. package/kb/extra/persistence-changes/README.zh.md +2 -0
  51. package/kb/extra/persistence-changes/historical-formats/README.md +1 -1
  52. package/kb/extra/persistence-changes/historical-formats/README.zh.md +1 -1
  53. package/kb/extra/rescope.md +7 -5
  54. package/kb/extra/rescope.zh.md +7 -5
  55. package/kb/extra/subsystems/agent-team.md +38 -75
  56. package/kb/extra/subsystems/agent-team.zh.md +38 -75
  57. package/kb/extra/subsystems/attachment.md +36 -13
  58. package/kb/extra/subsystems/attachment.zh.md +36 -13
  59. package/kb/extra/subsystems/boot.md +179 -5
  60. package/kb/extra/subsystems/boot.zh.md +179 -5
  61. package/kb/extra/subsystems/computer-use.md +78 -0
  62. package/kb/extra/subsystems/computer-use.zh.md +78 -0
  63. package/kb/extra/subsystems/deliverables.md +2 -0
  64. package/kb/extra/subsystems/deliverables.zh.md +2 -0
  65. package/kb/extra/subsystems/forge.md +1226 -0
  66. package/kb/extra/subsystems/forge.zh.md +1226 -0
  67. package/kb/extra/subsystems/liveshare.md +158 -0
  68. package/kb/extra/subsystems/liveshare.zh.md +158 -0
  69. package/kb/extra/subsystems/mcp.md +96 -1
  70. package/kb/extra/subsystems/mcp.zh.md +96 -1
  71. package/kb/extra/subsystems/worktrees.md +54 -3
  72. package/kb/extra/subsystems/worktrees.zh.md +54 -3
  73. package/kb/extra/testing.md +1 -1
  74. package/kb/extra/testing.zh.md +1 -1
  75. package/kb/extra/ui-design-review-cases.md +445 -0
  76. package/kb/extra/ui-design-review-cases.zh.md +445 -0
  77. package/kb/extra/ui-radius.md +3 -1
  78. package/kb/extra/ui-radius.zh.md +3 -1
  79. package/kb/extra/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.md +1 -1
  80. package/kb/extra/upgrade-guide/v0.2.1-alpha.1/team-direct-inbox/guide.zh.md +1 -1
  81. package/kb/extra/upgrade-guide/v0.2.1-alpha.2/cordis-timer-wrappers/guide.md +24 -0
  82. package/kb/extra/upgrade-guide/v0.2.1-alpha.2/cordis-timer-wrappers/guide.zh.md +24 -0
  83. package/kb/extra/upgrade-guide/v0.2.1-alpha.2/plugin-manager-view-fields/guide.md +25 -0
  84. package/kb/extra/upgrade-guide/v0.2.1-alpha.2/plugin-manager-view-fields/guide.zh.md +25 -0
  85. package/kb/extra/upgrade-guide/v0.2.1-alpha.4/model-switch-compaction/guide.md +30 -0
  86. package/kb/extra/upgrade-guide/v0.2.1-alpha.4/model-switch-compaction/guide.zh.md +30 -0
  87. package/kb/extra/upgrade-guide/v0.2.1-alpha.4/session-model-selection/guide.md +28 -0
  88. package/kb/extra/upgrade-guide/v0.2.1-alpha.4/session-model-selection/guide.zh.md +28 -0
  89. package/kb/extra/upgrade-guide/v0.2.1-rc.1/agent-instructions-chain-budgets/guide.md +24 -0
  90. package/kb/extra/upgrade-guide/v0.2.1-rc.1/agent-instructions-chain-budgets/guide.zh.md +24 -0
  91. package/kb/extra/upgrade-guide/v0.2.1-rc.1/subagent-control-tools/guide.md +23 -0
  92. package/kb/extra/upgrade-guide/v0.2.1-rc.1/subagent-control-tools/guide.zh.md +23 -0
  93. package/kb/extra/upgrade-guide/v0.2.1-rc.2/agent-runtime-owner/guide.md +20 -0
  94. package/kb/extra/upgrade-guide/v0.2.1-rc.2/agent-runtime-owner/guide.zh.md +20 -0
  95. package/kb/extra/upgrade-guide/v0.2.1-rc.2/agent-team-subagents/guide.md +31 -0
  96. package/kb/extra/upgrade-guide/v0.2.1-rc.2/agent-team-subagents/guide.zh.md +31 -0
  97. package/kb/extra/upgrade-guide/v0.2.1-rc.2/approval-projection-dependency/guide.md +34 -0
  98. package/kb/extra/upgrade-guide/v0.2.1-rc.2/approval-projection-dependency/guide.zh.md +34 -0
  99. package/kb/extra/upgrade-guide/v0.2.1-rc.2/auto-review-shutdown/guide.md +20 -0
  100. package/kb/extra/upgrade-guide/v0.2.1-rc.2/auto-review-shutdown/guide.zh.md +20 -0
  101. package/kb/extra/upgrade-guide/v0.2.1-rc.2/auto-review-user-sources/guide.md +18 -0
  102. package/kb/extra/upgrade-guide/v0.2.1-rc.2/auto-review-user-sources/guide.zh.md +18 -0
  103. package/kb/extra/upgrade-guide/v0.2.1-rc.2/built-in-japanese/guide.md +18 -0
  104. package/kb/extra/upgrade-guide/v0.2.1-rc.2/built-in-japanese/guide.zh.md +18 -0
  105. package/kb/extra/upgrade-guide/v0.2.1-rc.2/conditional-tools/guide.md +25 -0
  106. package/kb/extra/upgrade-guide/v0.2.1-rc.2/conditional-tools/guide.zh.md +25 -0
  107. package/kb/extra/upgrade-guide/v0.2.1-rc.2/context-menu-services/guide.md +23 -0
  108. package/kb/extra/upgrade-guide/v0.2.1-rc.2/context-menu-services/guide.zh.md +23 -0
  109. package/kb/extra/upgrade-guide/v0.2.1-rc.2/cua-consent-storage/guide.md +22 -0
  110. package/kb/extra/upgrade-guide/v0.2.1-rc.2/cua-consent-storage/guide.zh.md +22 -0
  111. package/kb/extra/upgrade-guide/v0.2.1-rc.2/cua-preset-scope/guide.md +18 -0
  112. package/kb/extra/upgrade-guide/v0.2.1-rc.2/cua-preset-scope/guide.zh.md +18 -0
  113. package/kb/extra/upgrade-guide/v0.2.1-rc.2/cua-relative-coordinates/guide.md +17 -0
  114. package/kb/extra/upgrade-guide/v0.2.1-rc.2/cua-relative-coordinates/guide.zh.md +17 -0
  115. package/kb/extra/upgrade-guide/v0.2.1-rc.2/file-drag-callbacks/guide.md +19 -0
  116. package/kb/extra/upgrade-guide/v0.2.1-rc.2/file-drag-callbacks/guide.zh.md +19 -0
  117. package/kb/extra/upgrade-guide/v0.2.1-rc.2/headless-policy-composition/guide.md +27 -0
  118. package/kb/extra/upgrade-guide/v0.2.1-rc.2/headless-policy-composition/guide.zh.md +27 -0
  119. package/kb/extra/upgrade-guide/v0.2.1-rc.2/model-badge-package-removal/guide.md +18 -0
  120. package/kb/extra/upgrade-guide/v0.2.1-rc.2/model-badge-package-removal/guide.zh.md +18 -0
  121. package/kb/extra/upgrade-guide/v0.2.1-rc.2/new-session-blank-reuse/guide.md +22 -0
  122. package/kb/extra/upgrade-guide/v0.2.1-rc.2/new-session-blank-reuse/guide.zh.md +22 -0
  123. package/kb/extra/upgrade-guide/v0.2.1-rc.2/node-24/guide.md +17 -0
  124. package/kb/extra/upgrade-guide/v0.2.1-rc.2/node-24/guide.zh.md +17 -0
  125. package/kb/extra/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.md +18 -0
  126. package/kb/extra/upgrade-guide/v0.2.1-rc.2/official-bundle-lists/guide.zh.md +18 -0
  127. package/kb/extra/upgrade-guide/v0.2.1-rc.2/persistent-terminal-controls/guide.md +18 -0
  128. package/kb/extra/upgrade-guide/v0.2.1-rc.2/persistent-terminal-controls/guide.zh.md +18 -0
  129. package/kb/extra/upgrade-guide/v0.2.1-rc.2/pi-ai-default-capacities/guide.md +18 -0
  130. package/kb/extra/upgrade-guide/v0.2.1-rc.2/pi-ai-default-capacities/guide.zh.md +18 -0
  131. package/kb/extra/upgrade-guide/v0.2.1-rc.2/pi-ai-model-catalog/guide.md +53 -0
  132. package/kb/extra/upgrade-guide/v0.2.1-rc.2/pi-ai-model-catalog/guide.zh.md +53 -0
  133. package/kb/extra/upgrade-guide/v0.2.1-rc.2/pi-ai-protocol-replay/guide.md +30 -0
  134. package/kb/extra/upgrade-guide/v0.2.1-rc.2/pi-ai-protocol-replay/guide.zh.md +30 -0
  135. package/kb/extra/upgrade-guide/v0.2.1-rc.2/ptc-script-format/guide.md +20 -0
  136. package/kb/extra/upgrade-guide/v0.2.1-rc.2/ptc-script-format/guide.zh.md +20 -0
  137. package/kb/extra/upgrade-guide/v0.2.1-rc.2/sdk-desktop-context/guide.md +18 -0
  138. package/kb/extra/upgrade-guide/v0.2.1-rc.2/sdk-desktop-context/guide.zh.md +18 -0
  139. package/kb/extra/upgrade-guide/v0.2.1-rc.2/sdk-minimal-checkpoints/guide.md +18 -0
  140. package/kb/extra/upgrade-guide/v0.2.1-rc.2/sdk-minimal-checkpoints/guide.zh.md +18 -0
  141. package/kb/extra/upgrade-guide/v0.2.1-rc.2/session-projection-handles/guide.md +24 -0
  142. package/kb/extra/upgrade-guide/v0.2.1-rc.2/session-projection-handles/guide.zh.md +24 -0
  143. package/kb/extra/upgrade-guide/v0.2.1-rc.2/session-store-writes/guide.md +25 -0
  144. package/kb/extra/upgrade-guide/v0.2.1-rc.2/session-store-writes/guide.zh.md +25 -0
  145. package/kb/extra/upgrade-guide/v0.2.1-rc.2/session-team-mode/guide.md +22 -0
  146. package/kb/extra/upgrade-guide/v0.2.1-rc.2/session-team-mode/guide.zh.md +22 -0
  147. package/kb/extra/upgrade-guide/v0.2.1-rc.2/subagent-activation-options/guide.md +18 -0
  148. package/kb/extra/upgrade-guide/v0.2.1-rc.2/subagent-activation-options/guide.zh.md +18 -0
  149. package/kb/extra/upgrade-guide/v0.2.1-rc.2/subagent-service-methods/guide.md +19 -0
  150. package/kb/extra/upgrade-guide/v0.2.1-rc.2/subagent-service-methods/guide.zh.md +19 -0
  151. package/kb/extra/upgrade-guide/v0.2.1-rc.2/subagent-user-controls/guide.md +26 -0
  152. package/kb/extra/upgrade-guide/v0.2.1-rc.2/subagent-user-controls/guide.zh.md +26 -0
  153. package/kb/extra/upgrade-guide/v0.2.1-rc.2/tool-executor-plugins/guide.md +35 -0
  154. package/kb/extra/upgrade-guide/v0.2.1-rc.2/tool-executor-plugins/guide.zh.md +35 -0
  155. package/kb/extra/upgrade-guide/v0.2.1-rc.2/web-fetch-private-destinations/guide.md +21 -0
  156. package/kb/extra/upgrade-guide/v0.2.1-rc.2/web-fetch-private-destinations/guide.zh.md +21 -0
  157. package/kb/extra/upgrade-guide/v0.2.1-rc.2/webserver-index-peer/guide.md +17 -0
  158. package/kb/extra/upgrade-guide/v0.2.1-rc.2/webserver-index-peer/guide.zh.md +17 -0
  159. package/kb/extra/upgrade-guide/v0.2.1-rc.3/attachment-read-access/guide.md +23 -0
  160. package/kb/extra/upgrade-guide/v0.2.1-rc.3/attachment-read-access/guide.zh.md +23 -0
  161. package/kb/extra/upgrade-guide/v0.2.1-rc.3/computer-use-helper-permissions/guide.md +21 -0
  162. package/kb/extra/upgrade-guide/v0.2.1-rc.3/computer-use-helper-permissions/guide.zh.md +21 -0
  163. package/kb/extra/upgrade-guide/v0.2.1-rc.3/cua-bundle-id-consent/guide.md +20 -0
  164. package/kb/extra/upgrade-guide/v0.2.1-rc.3/cua-bundle-id-consent/guide.zh.md +20 -0
  165. package/kb/extra/upgrade-guide/v0.2.1-rc.3/generated-worktree-names/guide.md +20 -0
  166. package/kb/extra/upgrade-guide/v0.2.1-rc.3/generated-worktree-names/guide.zh.md +20 -0
  167. package/kb/extra/upgrade-guide/v0.2.1-rc.3/inbox-only-agent-wait/guide.md +19 -0
  168. package/kb/extra/upgrade-guide/v0.2.1-rc.3/inbox-only-agent-wait/guide.zh.md +19 -0
  169. package/kb/extra/upgrade-guide/v0.2.1-rc.3/independent-session-forks/guide.md +23 -0
  170. package/kb/extra/upgrade-guide/v0.2.1-rc.3/independent-session-forks/guide.zh.md +23 -0
  171. package/kb/extra/upgrade-guide/v0.2.1-rc.3/ptc-caller-cancellation/guide.md +20 -0
  172. package/kb/extra/upgrade-guide/v0.2.1-rc.3/ptc-caller-cancellation/guide.zh.md +20 -0
  173. package/kb/extra/upgrade-guide/v0.2.1-rc.3/session-follow-activation/guide.md +21 -0
  174. package/kb/extra/upgrade-guide/v0.2.1-rc.3/session-follow-activation/guide.zh.md +21 -0
  175. package/kb/extra/upgrade-guide/v0.2.1-rc.3/subagent-runtime-ownership/guide.md +21 -0
  176. package/kb/extra/upgrade-guide/v0.2.1-rc.3/subagent-runtime-ownership/guide.zh.md +21 -0
  177. package/kb/extra/upgrade-guide/v0.2.1-rc.3/team-mode-menu/guide.md +18 -0
  178. package/kb/extra/upgrade-guide/v0.2.1-rc.3/team-mode-menu/guide.zh.md +18 -0
  179. package/kb/extra/upgrade-guide/v0.2.1-rc.3/team-projection/guide.md +20 -0
  180. package/kb/extra/upgrade-guide/v0.2.1-rc.3/team-projection/guide.zh.md +20 -0
  181. package/kb/extra/upgrade-guide/v0.2.1-rc.3/web-file-downloads/guide.md +19 -0
  182. package/kb/extra/upgrade-guide/v0.2.1-rc.3/web-file-downloads/guide.zh.md +19 -0
  183. package/kb/extra/upgrade-guide/v0.2.1-rc.3/web-search-defaults/guide.md +18 -0
  184. package/kb/extra/upgrade-guide/v0.2.1-rc.3/web-search-defaults/guide.zh.md +18 -0
  185. package/kb/extra/upgrade-guide/v0.2.1-rc.4/model-listing-refresh/guide.md +22 -0
  186. package/kb/extra/upgrade-guide/v0.2.1-rc.4/model-listing-refresh/guide.zh.md +22 -0
  187. package/kb/extra/upgrade-guide/v0.2.1-rc.4/reasoning-body-props/guide.md +20 -0
  188. package/kb/extra/upgrade-guide/v0.2.1-rc.4/reasoning-body-props/guide.zh.md +20 -0
  189. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/context-menu-target/guide.md +19 -0
  190. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/context-menu-target/guide.zh.md +19 -0
  191. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/cordis-loader-entry-trees/guide.md +24 -0
  192. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/cordis-loader-entry-trees/guide.zh.md +24 -0
  193. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/css-anchored-menus/guide.md +21 -0
  194. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/css-anchored-menus/guide.zh.md +21 -0
  195. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/cua-source-dev-helper/guide.md +19 -0
  196. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/cua-source-dev-helper/guide.zh.md +19 -0
  197. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/desktop-stable-channel/guide.md +18 -0
  198. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/desktop-stable-channel/guide.zh.md +18 -0
  199. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/forge-git-permissions/guide.md +21 -0
  200. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/forge-git-permissions/guide.zh.md +21 -0
  201. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/forge-worktree-entry/guide.md +29 -0
  202. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/forge-worktree-entry/guide.zh.md +29 -0
  203. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/fs-observation-policy-default-off/guide.md +29 -0
  204. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/fs-observation-policy-default-off/guide.zh.md +29 -0
  205. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/llm-request-purpose-declarations/guide.md +29 -0
  206. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/llm-request-purpose-declarations/guide.zh.md +29 -0
  207. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/pi-ai-request-image-count/guide.md +18 -0
  208. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/pi-ai-request-image-count/guide.zh.md +18 -0
  209. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/projection-event-frames/guide.md +32 -0
  210. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/projection-event-frames/guide.zh.md +32 -0
  211. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/projection-released-checkpoint/guide.md +30 -0
  212. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/projection-released-checkpoint/guide.zh.md +30 -0
  213. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/projection-snapshot-scope/guide.md +19 -0
  214. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/projection-snapshot-scope/guide.zh.md +19 -0
  215. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/retained-ptc-timeout/guide.md +21 -0
  216. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/retained-ptc-timeout/guide.zh.md +21 -0
  217. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/schedule-agent-tools/guide.md +37 -0
  218. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/schedule-agent-tools/guide.zh.md +37 -0
  219. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/schedule-remote-host-tasks/guide.md +22 -0
  220. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/schedule-remote-host-tasks/guide.zh.md +22 -0
  221. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/sdk-run-commands/guide.md +24 -0
  222. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/sdk-run-commands/guide.zh.md +24 -0
  223. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/session-header-menu/guide.md +20 -0
  224. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/session-header-menu/guide.zh.md +20 -0
  225. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/subagent-explicit-reasoning/guide.md +20 -0
  226. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/subagent-explicit-reasoning/guide.zh.md +20 -0
  227. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/web-search-credential-modes/guide.md +17 -0
  228. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/web-search-credential-modes/guide.zh.md +17 -0
  229. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/web-search-default-provider/guide.md +19 -0
  230. package/kb/extra/upgrade-guide/v0.2.2-alpha.2/web-search-default-provider/guide.zh.md +19 -0
  231. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/chat-process-activity-context/guide.md +18 -0
  232. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/chat-process-activity-context/guide.zh.md +18 -0
  233. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/subagent-names/guide.md +29 -0
  234. package/kb/extra/upgrade-guide/v0.2.2-alpha.3/subagent-names/guide.zh.md +29 -0
  235. package/kb/extra/web-styling.md +19 -1
  236. package/kb/extra/web-styling.zh.md +19 -1
  237. package/kb/meta/search-index.json +1272 -1098
  238. package/kb/meta/source.json +8 -4
  239. package/kb/site/develop/cordis-tutorial/04-events.md +1 -1
  240. package/kb/site/develop/cordis-tutorial/07-into-the-harness.md +5 -4
  241. package/kb/site/develop/framework/events.md +1 -1
  242. package/kb/site/develop/practice/dynamic-cordis.md +1 -1
  243. package/kb/site/en/develop/cordis-tutorial/04-events.md +1 -1
  244. package/kb/site/en/develop/cordis-tutorial/07-into-the-harness.md +5 -4
  245. package/kb/site/en/develop/framework/events.md +1 -1
  246. package/kb/site/en/develop/practice/dynamic-cordis.md +1 -1
  247. package/kb/site/en/guide/network-proxy.md +1 -1
  248. package/kb/site/en/guide/plugin-market.md +10 -10
  249. package/kb/site/en/guide/providers.md +5 -1
  250. package/kb/site/en/guide/python-sdk.md +17 -2
  251. package/kb/site/en/guide/schedule.md +45 -26
  252. package/kb/site/en/reference/agent-lifecycle.md +3 -1
  253. package/kb/site/en/reference/api-gateway.md +4 -4
  254. package/kb/site/en/reference/capability-seams.md +65 -17
  255. package/kb/site/en/reference/config-catalog.md +560 -238
  256. package/kb/site/en/reference/cookbook/adding-a-package.md +4 -2
  257. package/kb/site/en/reference/cookbook/extension-cookbook.md +1 -1
  258. package/kb/site/en/reference/cordis-api/context.md +1 -1
  259. package/kb/site/en/reference/cordis-api/events.md +9 -9
  260. package/kb/site/en/reference/cordis-api/fiber.md +85 -32
  261. package/kb/site/en/reference/cordis-api/inherited.md +10 -9
  262. package/kb/site/en/reference/experimental-persistence-catalog.md +3 -0
  263. package/kb/site/en/reference/index.md +14 -8
  264. package/kb/site/en/reference/persistence-catalog.md +532 -246
  265. package/kb/site/en/reference/subsystems/client-modules.md +19 -11
  266. package/kb/site/en/reference/subsystems/compaction.md +1 -1
  267. package/kb/site/en/reference/subsystems/conversation.md +2 -0
  268. package/kb/site/en/reference/subsystems/core.md +119 -65
  269. package/kb/site/en/reference/subsystems/filesystem.md +202 -28
  270. package/kb/site/en/reference/subsystems/index.md +3 -1
  271. package/kb/site/en/reference/subsystems/llm-streaming.md +92 -4
  272. package/kb/site/en/reference/subsystems/persistence.md +17 -7
  273. package/kb/site/en/reference/subsystems/plan.md +4 -4
  274. package/kb/site/en/reference/subsystems/ptc-runtime.md +12 -5
  275. package/kb/site/en/reference/subsystems/sandbox.md +11 -4
  276. package/kb/site/en/reference/subsystems/schedule.md +194 -430
  277. package/kb/site/en/reference/subsystems/session-projection.md +186 -44
  278. package/kb/site/en/reference/subsystems/session-reference.md +4 -3
  279. package/kb/site/en/reference/subsystems/session.md +119 -31
  280. package/kb/site/en/reference/subsystems/sidebar-right.md +12 -11
  281. package/kb/site/en/reference/subsystems/skills.md +4 -4
  282. package/kb/site/en/reference/subsystems/slots.md +30 -3
  283. package/kb/site/en/reference/subsystems/storage.md +26 -9
  284. package/kb/site/en/reference/subsystems/subagent.md +119 -102
  285. package/kb/site/en/reference/subsystems/system-prompt.md +13 -11
  286. package/kb/site/en/reference/subsystems/token-meter.md +45 -0
  287. package/kb/site/en/reference/subsystems/tools.md +222 -82
  288. package/kb/site/en/reference/subsystems/typert.md +21 -11
  289. package/kb/site/en/reference/subsystems/user-questions.md +22 -6
  290. package/kb/site/en/reference/subsystems/web-client.md +1 -1
  291. package/kb/site/en/reference/subsystems/web-server.md +68 -23
  292. package/kb/site/en/reference/subsystems/web.md +79 -21
  293. package/kb/site/en/reference/tool-catalog.md +270 -395
  294. package/kb/site/en/reference/tool-execution-pipeline.md +5 -4
  295. package/kb/site/guide/network-proxy.md +1 -1
  296. package/kb/site/guide/plugin-market.md +10 -10
  297. package/kb/site/guide/providers.md +5 -1
  298. package/kb/site/guide/python-sdk.md +17 -2
  299. package/kb/site/guide/schedule.md +45 -26
  300. package/kb/site/reference/agent-lifecycle.md +3 -1
  301. package/kb/site/reference/api-gateway.md +4 -4
  302. package/kb/site/reference/capability-seams.md +65 -17
  303. package/kb/site/reference/config-catalog.md +560 -238
  304. package/kb/site/reference/cookbook/adding-a-package.md +4 -2
  305. package/kb/site/reference/cookbook/extension-cookbook.md +1 -1
  306. package/kb/site/reference/cordis-api/context.md +1 -1
  307. package/kb/site/reference/cordis-api/events.md +9 -9
  308. package/kb/site/reference/cordis-api/fiber.md +87 -32
  309. package/kb/site/reference/cordis-api/inherited.md +10 -9
  310. package/kb/site/reference/experimental-persistence-catalog.md +3 -0
  311. package/kb/site/reference/index.md +14 -8
  312. package/kb/site/reference/persistence-catalog.md +532 -246
  313. package/kb/site/reference/subsystems/client-modules.md +19 -11
  314. package/kb/site/reference/subsystems/compaction.md +1 -1
  315. package/kb/site/reference/subsystems/conversation.md +4 -0
  316. package/kb/site/reference/subsystems/core.md +119 -65
  317. package/kb/site/reference/subsystems/filesystem.md +202 -28
  318. package/kb/site/reference/subsystems/index.md +3 -1
  319. package/kb/site/reference/subsystems/llm-streaming.md +92 -4
  320. package/kb/site/reference/subsystems/persistence.md +17 -7
  321. package/kb/site/reference/subsystems/plan.md +4 -4
  322. package/kb/site/reference/subsystems/ptc-runtime.md +12 -5
  323. package/kb/site/reference/subsystems/sandbox.md +11 -4
  324. package/kb/site/reference/subsystems/schedule.md +197 -433
  325. package/kb/site/reference/subsystems/session-projection.md +186 -44
  326. package/kb/site/reference/subsystems/session-reference.md +4 -3
  327. package/kb/site/reference/subsystems/session.md +119 -31
  328. package/kb/site/reference/subsystems/sidebar-right.md +12 -11
  329. package/kb/site/reference/subsystems/skills.md +4 -4
  330. package/kb/site/reference/subsystems/slots.md +30 -3
  331. package/kb/site/reference/subsystems/storage.md +26 -9
  332. package/kb/site/reference/subsystems/subagent.md +119 -102
  333. package/kb/site/reference/subsystems/system-prompt.md +13 -11
  334. package/kb/site/reference/subsystems/token-meter.md +45 -0
  335. package/kb/site/reference/subsystems/tools.md +222 -82
  336. package/kb/site/reference/subsystems/typert.md +21 -11
  337. package/kb/site/reference/subsystems/user-questions.md +22 -6
  338. package/kb/site/reference/subsystems/web-client.md +1 -1
  339. package/kb/site/reference/subsystems/web-server.md +68 -23
  340. package/kb/site/reference/subsystems/web.md +79 -21
  341. package/kb/site/reference/tool-catalog.md +273 -399
  342. package/kb/site/reference/tool-execution-pipeline.md +4 -3
  343. package/lib/index.js +268 -11
  344. package/lib/kb-search.js +261 -0
  345. package/lib/kb-version.js +118 -0
  346. package/package.json +5 -3
  347. package/scripts/refresh-kb.mjs +153 -0
  348. package/scripts/selfcheck.mjs +28 -0
  349. package/scripts/smoke.mjs +77 -0
  350. package/skills/dsh-plugin-dev-kb.md +8 -7
  351. package/skills/dsh-plugin-starter.md +65 -0
  352. package/skills/dsh-upgrade-assistant.md +62 -0
  353. package/kb/extra/agent-lifecycle.md +0 -91
  354. package/kb/extra/agent-lifecycle.zh.md +0 -93
  355. package/kb/extra/api-gateway.md +0 -172
  356. package/kb/extra/api-gateway.zh.md +0 -178
  357. package/kb/extra/architecture.md +0 -165
  358. package/kb/extra/architecture.zh.md +0 -169
  359. package/kb/extra/capability-seams.md +0 -714
  360. package/kb/extra/capability-seams.zh.md +0 -716
  361. package/kb/extra/config-catalog.md +0 -4801
  362. package/kb/extra/config-catalog.zh.md +0 -4803
  363. package/kb/extra/cookbook/adding-a-package.md +0 -170
  364. package/kb/extra/cookbook/adding-a-package.zh.md +0 -170
  365. package/kb/extra/cookbook/adding-a-settings-card.md +0 -72
  366. package/kb/extra/cookbook/adding-a-settings-card.zh.md +0 -72
  367. package/kb/extra/cookbook/adding-a-tool.md +0 -101
  368. package/kb/extra/cookbook/adding-a-tool.zh.md +0 -103
  369. package/kb/extra/cookbook/adding-an-llm-adapter.md +0 -43
  370. package/kb/extra/cookbook/adding-an-llm-adapter.zh.md +0 -43
  371. package/kb/extra/cookbook/extension-cookbook.md +0 -132
  372. package/kb/extra/cookbook/extension-cookbook.zh.md +0 -136
  373. package/kb/extra/cordis-api/context.md +0 -364
  374. package/kb/extra/cordis-api/context.zh.md +0 -366
  375. package/kb/extra/cordis-api/events.md +0 -207
  376. package/kb/extra/cordis-api/events.zh.md +0 -209
  377. package/kb/extra/cordis-api/fiber.md +0 -375
  378. package/kb/extra/cordis-api/fiber.zh.md +0 -377
  379. package/kb/extra/cordis-api/inherited.md +0 -38
  380. package/kb/extra/cordis-api/registry.md +0 -152
  381. package/kb/extra/cordis-api/registry.zh.md +0 -154
  382. package/kb/extra/cordis-api/service.md +0 -102
  383. package/kb/extra/cordis-api/service.zh.md +0 -104
  384. package/kb/extra/cordis-tutorial/01-first-plugin.md +0 -95
  385. package/kb/extra/cordis-tutorial/01-first-plugin.zh.md +0 -95
  386. package/kb/extra/cordis-tutorial/02-lifecycle-and-effects.md +0 -98
  387. package/kb/extra/cordis-tutorial/02-lifecycle-and-effects.zh.md +0 -98
  388. package/kb/extra/cordis-tutorial/03-services.md +0 -98
  389. package/kb/extra/cordis-tutorial/03-services.zh.md +0 -98
  390. package/kb/extra/cordis-tutorial/04-events.md +0 -144
  391. package/kb/extra/cordis-tutorial/04-events.zh.md +0 -144
  392. package/kb/extra/cordis-tutorial/05-config.md +0 -111
  393. package/kb/extra/cordis-tutorial/05-config.zh.md +0 -111
  394. package/kb/extra/cordis-tutorial/06-composition-and-hmr.md +0 -113
  395. package/kb/extra/cordis-tutorial/06-composition-and-hmr.zh.md +0 -113
  396. package/kb/extra/cordis-tutorial/07-into-the-harness.md +0 -108
  397. package/kb/extra/cordis-tutorial/07-into-the-harness.zh.md +0 -108
  398. package/kb/extra/cordis-tutorial/index.md +0 -60
  399. package/kb/extra/cordis-tutorial/index.zh.md +0 -62
  400. package/kb/extra/experimental-persistence-catalog.md +0 -17
  401. package/kb/extra/experimental-persistence-catalog.zh.md +0 -17
  402. package/kb/extra/persistence-catalog.md +0 -9140
  403. package/kb/extra/persistence-catalog.zh.md +0 -9142
  404. package/kb/extra/subsystems/README.md +0 -76
  405. package/kb/extra/subsystems/README.zh.md +0 -76
  406. package/kb/extra/subsystems/approval.md +0 -170
  407. package/kb/extra/subsystems/approval.zh.md +0 -170
  408. package/kb/extra/subsystems/client-modules.md +0 -198
  409. package/kb/extra/subsystems/client-modules.zh.md +0 -198
  410. package/kb/extra/subsystems/client-resources.md +0 -92
  411. package/kb/extra/subsystems/client-resources.zh.md +0 -92
  412. package/kb/extra/subsystems/commands.md +0 -223
  413. package/kb/extra/subsystems/commands.zh.md +0 -223
  414. package/kb/extra/subsystems/compaction.md +0 -284
  415. package/kb/extra/subsystems/compaction.zh.md +0 -284
  416. package/kb/extra/subsystems/conversation.md +0 -301
  417. package/kb/extra/subsystems/conversation.zh.md +0 -303
  418. package/kb/extra/subsystems/core.md +0 -1113
  419. package/kb/extra/subsystems/core.zh.md +0 -1125
  420. package/kb/extra/subsystems/credentials.md +0 -493
  421. package/kb/extra/subsystems/credentials.zh.md +0 -493
  422. package/kb/extra/subsystems/filesystem.md +0 -530
  423. package/kb/extra/subsystems/filesystem.zh.md +0 -530
  424. package/kb/extra/subsystems/goal.md +0 -313
  425. package/kb/extra/subsystems/goal.zh.md +0 -313
  426. package/kb/extra/subsystems/jobs.md +0 -554
  427. package/kb/extra/subsystems/jobs.zh.md +0 -554
  428. package/kb/extra/subsystems/llm-streaming.md +0 -1196
  429. package/kb/extra/subsystems/llm-streaming.zh.md +0 -1202
  430. package/kb/extra/subsystems/lsp.md +0 -202
  431. package/kb/extra/subsystems/lsp.zh.md +0 -202
  432. package/kb/extra/subsystems/permission-presets.md +0 -167
  433. package/kb/extra/subsystems/permission-presets.zh.md +0 -167
  434. package/kb/extra/subsystems/persistence.md +0 -418
  435. package/kb/extra/subsystems/persistence.zh.md +0 -418
  436. package/kb/extra/subsystems/plan.md +0 -87
  437. package/kb/extra/subsystems/plan.zh.md +0 -87
  438. package/kb/extra/subsystems/ptc-runtime.md +0 -250
  439. package/kb/extra/subsystems/ptc-runtime.zh.md +0 -250
  440. package/kb/extra/subsystems/sandbox.md +0 -221
  441. package/kb/extra/subsystems/sandbox.zh.md +0 -221
  442. package/kb/extra/subsystems/schedule.md +0 -550
  443. package/kb/extra/subsystems/schedule.zh.md +0 -550
  444. package/kb/extra/subsystems/scope.md +0 -59
  445. package/kb/extra/subsystems/scope.zh.md +0 -61
  446. package/kb/extra/subsystems/session-projection.md +0 -356
  447. package/kb/extra/subsystems/session-projection.zh.md +0 -356
  448. package/kb/extra/subsystems/session-query.md +0 -511
  449. package/kb/extra/subsystems/session-query.zh.md +0 -511
  450. package/kb/extra/subsystems/session-reference.md +0 -224
  451. package/kb/extra/subsystems/session-reference.zh.md +0 -224
  452. package/kb/extra/subsystems/session-telemetry.md +0 -212
  453. package/kb/extra/subsystems/session-telemetry.zh.md +0 -212
  454. package/kb/extra/subsystems/session-title.md +0 -213
  455. package/kb/extra/subsystems/session-title.zh.md +0 -213
  456. package/kb/extra/subsystems/session.md +0 -1339
  457. package/kb/extra/subsystems/session.zh.md +0 -1343
  458. package/kb/extra/subsystems/settings.md +0 -155
  459. package/kb/extra/subsystems/settings.zh.md +0 -155
  460. package/kb/extra/subsystems/shell.md +0 -314
  461. package/kb/extra/subsystems/shell.zh.md +0 -314
  462. package/kb/extra/subsystems/sidebar-right.md +0 -160
  463. package/kb/extra/subsystems/sidebar-right.zh.md +0 -160
  464. package/kb/extra/subsystems/skills.md +0 -352
  465. package/kb/extra/subsystems/skills.zh.md +0 -352
  466. package/kb/extra/subsystems/slots.md +0 -200
  467. package/kb/extra/subsystems/slots.zh.md +0 -204
  468. package/kb/extra/subsystems/spill.md +0 -124
  469. package/kb/extra/subsystems/spill.zh.md +0 -124
  470. package/kb/extra/subsystems/storage.md +0 -259
  471. package/kb/extra/subsystems/storage.zh.md +0 -259
  472. package/kb/extra/subsystems/subagent.md +0 -686
  473. package/kb/extra/subsystems/subagent.zh.md +0 -688
  474. package/kb/extra/subsystems/subprocess.md +0 -321
  475. package/kb/extra/subsystems/subprocess.zh.md +0 -321
  476. package/kb/extra/subsystems/system-prompt.md +0 -254
  477. package/kb/extra/subsystems/system-prompt.zh.md +0 -254
  478. package/kb/extra/subsystems/terminal.md +0 -184
  479. package/kb/extra/subsystems/terminal.zh.md +0 -184
  480. package/kb/extra/subsystems/token-meter.md +0 -106
  481. package/kb/extra/subsystems/token-meter.zh.md +0 -106
  482. package/kb/extra/subsystems/tools.md +0 -747
  483. package/kb/extra/subsystems/tools.zh.md +0 -747
  484. package/kb/extra/subsystems/typert.md +0 -690
  485. package/kb/extra/subsystems/typert.zh.md +0 -690
  486. package/kb/extra/subsystems/user-questions.md +0 -307
  487. package/kb/extra/subsystems/user-questions.zh.md +0 -307
  488. package/kb/extra/subsystems/web-client.md +0 -100
  489. package/kb/extra/subsystems/web-client.zh.md +0 -100
  490. package/kb/extra/subsystems/web-server.md +0 -302
  491. package/kb/extra/subsystems/web-server.zh.md +0 -302
  492. package/kb/extra/subsystems/web.md +0 -206
  493. package/kb/extra/subsystems/web.zh.md +0 -206
  494. package/kb/extra/subsystems/workflow.md +0 -278
  495. package/kb/extra/subsystems/workflow.zh.md +0 -278
  496. package/kb/extra/subsystems/workspace.md +0 -647
  497. package/kb/extra/subsystems/workspace.zh.md +0 -647
  498. package/kb/extra/tool-catalog.md +0 -2824
  499. package/kb/extra/tool-catalog.zh.md +0 -2832
  500. package/kb/extra/tool-execution-pipeline.md +0 -65
  501. package/kb/extra/tool-execution-pipeline.zh.md +0 -67
@@ -69,8 +69,10 @@ interface SessionEventMap {
69
69
  * The rendered system prompt on the model-visible surface. The loop appends
70
70
  * the first one as surface node 0 before the step's first `user/message`.
71
71
  * A prepared in-history route can append nonempty changes in a continuing
72
- * series. An incapable route or new series normalizes text to the first system
73
- * node. Normalization empties nonempty later nodes, then rewrites the head if
72
+ * series. An incapable route, or a new series whose effective text differs,
73
+ * normalizes text to the first system node; a series start whose latest
74
+ * surviving node already holds the rendering leaves it in place.
75
+ * Normalization empties nonempty later nodes, then rewrites the head if
74
76
  * needed, through logged per-node replacements. An empty rendering always
75
77
  * clears all active system nodes, leaving no older instructions model-visible.
76
78
  * Empty later nodes are dormant and project to no message; an empty head with
@@ -582,6 +584,9 @@ declare class Session {
582
584
  * the log, the append is committed: observer failures are logged and
583
585
  * contained per listener, so they do not change the return value or prevent
584
586
  * later listeners from observing the same accepted event.
587
+ * Independent Sessions append without notifying store observers. Once a store
588
+ * prepares or enters the instance, writes require a completed creation
589
+ * announcement and remain disabled after removal.
585
590
  *
586
591
  * @param type - The event type (key of {@link SessionEventMap}).
587
592
  * @param data - The event payload; must be JSON-serializable.
@@ -597,7 +602,9 @@ declare class Session {
597
602
  * @returns the logged event — its assigned `seq`/`time` plus the SNAPSHOT of
598
603
  * `data` that entered the log, so reading `event.data` back sees the logged
599
604
  * value, never the caller's still-mutable input.
600
- * @throws if `data` or surface metadata is not losslessly JSON-serializable
605
+ * @throws if a store-owned Session is unentered or its creation announcement
606
+ * has not completed, or if `data` or surface
607
+ * metadata is not losslessly JSON-serializable
601
608
  * (BigInt, function, symbol, undefined, negative zero, non-finite number,
602
609
  * circular reference, sparse array, or an exotic object such as
603
610
  * Map/Set/Date/class instance), or when the candidate violates the
@@ -682,7 +689,7 @@ Everything else (`turn/*`, `step/*`, `assistant/attempt`, plugin-owned `llm/retr
682
689
 
683
690
  `ctx.sessions.create(id, { seed, meta })` is the low-level replay/fork primitive. For ordinary live-session forks, `SessionStore` exposes one policy API:
684
691
 
685
- - `fork(source, boundary?, childSessionId?)` accepts a live `Session` object or live `SessionId`, selects source events through the inclusive `SessionSeq` boundary (default: current last event), requires the selected prefix to end outside an open turn, then creates a live child session with deep-cloned seed events, `parentSession`, `isSeeded: true`, the exact `inheritedEventCount`, and inherited `cwd`.
692
+ - `fork(source, boundary?, childSessionId?)` accepts a live `Session` object or live `SessionId`, selects source events through the inclusive `SessionSeq` boundary (default: current last event), closes any open tail, then creates an independent live session with deep-cloned seed events, `isSeeded: true`, the exact `inheritedEventCount`, and inherited `cwd`, without `parentSession`.
686
693
 
687
694
  An explicit `boundary` lets callers fork from any stable between-turn position, including a previous `turn/end` or a later standalone log-only event, even if the source has newer events or an open current turn. The API rejects a prefix that ends inside an open turn instead of clipping silently. `dsh-subagent-fork-in-process` keeps its completed-prefix clipping because tool-time delegation usually starts while the parent turn is open; ordinary session branching should make the requested boundary explicit.
688
695
 
@@ -707,8 +714,9 @@ interface TurnEndReasonMap {
707
714
  blocked: { kind: 'blocked' }
708
715
  /**
709
716
  * The turn failed. `error` is always a structured failure: the `LlmError`
710
- * facts verbatim, or `{ message: errorChain(error), code: 'UNKNOWN' }`
711
- * flattened from any other error.
717
+ * facts verbatim, or `{ message: errorChain(error), code }` flattened from
718
+ * any other error, where `code` is `TOOL_ACTIVATION_FAILED` for a failed
719
+ * tool condition and `UNKNOWN` otherwise.
712
720
  */
713
721
  error: { kind: 'error'; error: LlmFailure }
714
722
  /** At least one step reached its output-token ceiling, even if a plugin continued the turn. */
@@ -813,6 +821,29 @@ The backends that consume this contract are on [persistence.md](./persistence.md
813
821
 
814
822
  The optional `application` selects a registered file handler without changing the system default; `workspacePathApplications({ path })` returns current handlers, names, icons, and default selection after Host path verification.
815
823
 
824
+ ## Session-log upload exclusions
825
+
826
+ `ctx.sessionLogDeepSeek.registerExclusion()` registers a caller-owned predicate over `SessionLogUploadRequest`. Any match omits the log contribution and its acceptance callback before reading Session events. No match preserves normal upload eligibility. The [package README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/session/session-log-deepseek/README.md#upload-exclusions) defines failure and disposal behavior.
827
+
828
+ ```ts type-equiv
829
+ /** Request identity inspected before preparing a Session-log contribution. */
830
+ interface SessionLogUploadRequest {
831
+ /** Live Session whose canonical log would be contributed. */
832
+ readonly sessionId: SessionId
833
+ /** Auxiliary request classification; absent for ordinary conversation requests. */
834
+ readonly purpose?: string
835
+ }
836
+ ```
837
+
838
+ ```ts type-equiv
839
+ /**
840
+ * Synchronous, side-effect-free upload exclusion owned by its registering plugin.
841
+ * @param request - request identity; the predicate must not mutate it.
842
+ * @returns `true` to omit the log field and acceptance callback, or `false` to keep checking eligibility.
843
+ */
844
+ type SessionLogUploadExclusion = (request: SessionLogUploadRequest) => boolean
845
+ ```
846
+
816
847
  <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
817
848
 
818
849
  <a id="cordis-surface"></a>
@@ -835,14 +866,6 @@ Host service backing the generated `ctx.remote.session` namespace.
835
866
  */
836
867
  resolveAgent(sessionId: SessionId): Promise<ApiSessionAgentResult>
837
868
 
838
- /**
839
- * Inspect one attached or persisted Session without activating its Agent.
840
- * @param sessionId - durable Session identity.
841
- * @param signal - optional caller cancellation for persistence reads.
842
- * @returns the current attached state or persisted header and event prefix.
843
- */
844
- inspect( sessionId: SessionId, signal?: AbortSignal, ): Promise<SessionInspection>
845
-
846
869
  /**
847
870
  * Read all visible Session rows without resuming an Agent.
848
871
  * @param _request - reserved empty list request.
@@ -942,8 +965,8 @@ workspaceDesktop(): { name: string; available: boolean; fileManager: 'finder' |
942
965
  @Remote('prompt') async prompt(request: SessionPromptRequest, signal: AbortSignal): Promise<SessionPromptValue>
943
966
 
944
967
  /**
945
- * Read one image proven reachable from the addressed Session log.
946
- * @param request - Session and attachment identities used for authorization.
968
+ * Read one image from the attachment store after gateway authorization.
969
+ * @param request - image reference and gateway permission scope; Session existence is not checked.
947
970
  * @returns the durable attachment reference and base64-encoded bytes.
948
971
  */
949
972
  @Remote('attachment') attachment(request: SessionAttachmentRequest): Promise<SessionAttachmentValue>
@@ -964,11 +987,51 @@ workspaceDesktop(): { name: string; available: boolean; fileManager: 'finder' |
964
987
 
965
988
  /**
966
989
  * Read one cold-safe, message-aligned Session history page.
967
- * @param request - durable address, backward cursor, and page budget.
990
+ * @param request - durable address, optional fixed cut, backward cursor, and page budget.
968
991
  * @param signal - cancellation for persistence reads.
969
- * @returns one chronological page.
992
+ * @returns one chronological page with its inclusive cursor.
993
+ */
994
+ @Remote events(request: SessionPageRequest, signal: AbortSignal): Promise<SessionEventsPage>
995
+
996
+ /**
997
+ * Subscribe to Session events without reading a snapshot.
998
+ * @param request - Session address.
999
+ * @param signal - subscription cancellation.
1000
+ * @returns readiness and subsequent events, without a snapshot.
1001
+ */
1002
+ @Remote({ mode: 'stream' }) observeEvent(request: SessionObserveEventRequest, signal: AbortSignal): AsyncIterable<SessionEventFrame>
1003
+
1004
+ /**
1005
+ * Subscribe to Session projection changes.
1006
+ * @param request - target Session.
1007
+ * @param signal - subscription cancellation.
1008
+ * @returns readiness followed by one projection change frame per committed event.
1009
+ */
1010
+ @Remote({ mode: 'stream' }) observeProjections(request: SessionProjectionsRequest, signal: AbortSignal): AsyncIterable<SessionProjectionFrame>
1011
+
1012
+ /**
1013
+ * Read passive Session state.
1014
+ * @param request - target Session.
1015
+ * @param signal - read cancellation.
1016
+ * @returns current passive state.
1017
+ */
1018
+ @Remote state(request: SessionStateRequest, signal: AbortSignal): Promise<SessionState>
1019
+
1020
+ /**
1021
+ * Subscribe to complete Session state replacements.
1022
+ * @param request - target Session.
1023
+ * @param signal - subscription cancellation.
1024
+ * @returns complete passive state replacements.
1025
+ */
1026
+ @Remote({ mode: 'stream' }) observeState(request: SessionStateRequest, signal: AbortSignal): AsyncIterable<SessionState>
1027
+
1028
+ /**
1029
+ * Wait for Session quiescence or pending input with bounded assistant output.
1030
+ * @param request - Session, wait bounds and output window.
1031
+ * @param signal - caller cancellation.
1032
+ * @returns stopping state and bounded assistant output.
970
1033
  */
971
- @Remote({ name: 'page', resources: { session: addressedSession } }) page(request: SessionPageRequest, signal: AbortSignal): Promise<SessionPage>
1034
+ @Remote wait(request: SessionWaitRequest, signal: AbortSignal): Promise<SessionWaitValue>
972
1035
 
973
1036
  /**
974
1037
  * Follow one Session log from its opening or resume cursor.
@@ -977,7 +1040,7 @@ workspaceDesktop(): { name: string; available: boolean; fileManager: 'finder' |
977
1040
  * @returns a complete opening snapshot followed by gap-free durable event
978
1041
  * frames and optional cursorless assistant-stream frames.
979
1042
  */
980
- @Remote({ mode: 'stream', resources: { session: addressedSession } }) follow(request: SessionFollowRequest, signal: AbortSignal): AsyncIterable<SessionFollowFrame>
1043
+ @Remote({ mode: 'stream' }) follow(request: SessionFollowRequest, signal: AbortSignal): AsyncIterable<SessionFollowFrame>
981
1044
 
982
1045
  /**
983
1046
  * Read exact projections, returning cached hints only when migration is required.
@@ -985,7 +1048,7 @@ workspaceDesktop(): { name: string; available: boolean; fileManager: 'finder' |
985
1048
  * @param signal - cancellation for the Session read.
986
1049
  * @returns a sequenced baseline, cached hints when migration is deferred, or null when absent.
987
1050
  */
988
- @Remote('projections') async projections(request: SessionProjectionsRequest, signal: AbortSignal): Promise<SessionProjectionsValue>
1051
+ @Remote('projections') projections(request: SessionProjectionsRequest, signal: AbortSignal): Promise<SessionProjectionsValue>
989
1052
 
990
1053
  /**
991
1054
  * Stream a complete live-control baseline followed by replacement frames.
@@ -995,10 +1058,30 @@ workspaceDesktop(): { name: string; available: boolean; fileManager: 'finder' |
995
1058
  @Remote({ mode: 'stream' }) async *control(signal: AbortSignal): AsyncIterable<SessionControlFrame>
996
1059
  ```
997
1060
 
998
- Types: [SessionId](./core.md) · [SessionInspection](./persistence.md) · [SessionSearchRequest](./session-query.md)
1061
+ Types: [SessionId](./core.md) · [SessionSearchRequest](./session-query.md)
999
1062
 
1000
1063
  Source: [`packages/api/session-controller/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/api/session-controller/src/index.ts)
1001
1064
 
1065
+ <a id="ctxsessionlogdeepseek--sessionlogdeepseekservice"></a>
1066
+
1067
+ ### `ctx.sessionLogDeepSeek` — `SessionLogDeepSeekService`
1068
+
1069
+ Incremental Session-log contributor with caller-owned upload exclusions.
1070
+
1071
+ ```ts cordis-catalog
1072
+ /**
1073
+ * Exclude matching requests before reading or preparing their log contribution.
1074
+ * Any matching rule suppresses both the field and its acceptance callback. With
1075
+ * no matching rules, normal upload eligibility applies. A throwing rule fails
1076
+ * this contribution; the request-extension registry omits it and reports the error.
1077
+ * @param exclude - synchronous, side-effect-free predicate; `true` skips this upload.
1078
+ * @returns effect disposer that removes this registration when called or when the caller unloads.
1079
+ */
1080
+ registerExclusion(exclude: SessionLogUploadExclusion): () => Promise<void>
1081
+ ```
1082
+
1083
+ Source: [`packages/session/session-log-deepseek/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/session/session-log-deepseek/src/index.ts)
1084
+
1002
1085
  <a id="ctxsessions--sessionstore"></a>
1003
1086
 
1004
1087
  ### `ctx.sessions` — `SessionStore`
@@ -1054,7 +1137,7 @@ create(id?: SessionId, options?: CreateSessionOptions): Session
1054
1137
  * `eventState`, every seed event is either independently owned or any
1055
1138
  * shared value is deeply frozen; {@link Session.fromRestore} validates and
1056
1139
  * adopts those values without copying or freezing them.
1057
- * @returns the constructed session, NOT yet in the store.
1140
+ * @returns the store-owned session, not yet entered and read-only until announced.
1058
1141
  * @throws if a session with `id` already exists, metadata is not a plain
1059
1142
  * lossless-JSON record with valid scalar fields, or `meta.cwd` is a
1060
1143
  * non-absolute path.
@@ -1062,8 +1145,9 @@ create(id?: SessionId, options?: CreateSessionOptions): Session
1062
1145
  prepare(id?: SessionId, options?: PrepareSessionOptions): Session
1063
1146
 
1064
1147
  /**
1065
- * Enter a {@link prepare}d session into the store: install the module-private
1066
- * append publication hooks and add it to the store. Returns the DETACH
1148
+ * Enter a session into the store: install the module-private
1149
+ * append publication hooks and add it to the store. Writes remain disabled
1150
+ * until {@link announce} completes successfully. Returns the DETACH
1067
1151
  * disposer (hooks + store removal). Does NOT emit `session/created` —
1068
1152
  * the caller yields this disposer inside its effect and THEN calls
1069
1153
  * {@link announce}, so a throwing `session/created` listener rolls the attach
@@ -1077,7 +1161,7 @@ prepare(id?: SessionId, options?: PrepareSessionOptions): Session
1077
1161
  * the two back-to-back so they never trip this, but the public API cannot
1078
1162
  * assume that.
1079
1163
  *
1080
- * @param session - a {@link prepare}d session not yet in the store.
1164
+ * @param session - an unentered session; independent instances become store-owned.
1081
1165
  * @returns the detach disposer (publication hooks + store removal). When called from
1082
1166
  * a synchronous `session/created` listener, removal and disposal wait until
1083
1167
  * that creation dispatch unwinds.
@@ -1088,7 +1172,9 @@ enter(session: Session): () => void
1088
1172
  /** Emit `session/created` exactly once for an {@link enter}ed session (with
1089
1173
  * the carrier {@link enter} captured). Separate from {@link enter} so the
1090
1174
  * caller can yield the detach disposer first (rollback safety — see
1091
- * {@link enter}).
1175
+ * {@link enter}). The Session remains read-only throughout synchronous
1176
+ * dispatch; successful completion enables appends. A failed announcement
1177
+ * leaves it read-only and cannot be retried.
1092
1178
  * @param session - the entered session to announce to listeners.
1093
1179
  * @throws if the session is not live or its announcement already began,
1094
1180
  * including a reentrant call from a creation listener. */
@@ -1123,7 +1209,7 @@ get(id: SessionId): Session | undefined
1123
1209
  list(): Session[]
1124
1210
 
1125
1211
  /**
1126
- * Create a live child session from an exact prefix of a live source.
1212
+ * Create an independent live session from an exact prefix of a live source.
1127
1213
  * `boundary` is an inclusive source event seq; omitted means the source's
1128
1214
  * current last event. An open tail receives synthetic tool results and
1129
1215
  * step/turn closers with the forked cause. Closed steps and turns remain
@@ -1254,12 +1340,14 @@ Source: [`packages/api/session-controller/src/types.ts`](https://github.com/deep
1254
1340
 
1255
1341
  #### `session/created` — emit
1256
1342
 
1257
- Creation announcement during session publication. A synchronous throw vetoes and rolls back with a paired disposal; detach requested during dispatch is deferred. A returned-promise rejection is logged but cannot retroactively veto this synchronous boundary. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only sessions entered through that agent's context.
1343
+ Read-only creation announcement after store entry. New events reject until every synchronous listener has returned successfully. A synchronous throw vetoes creation and rolls back with a paired disposal; detach requested during dispatch is deferred. A returned-promise rejection is logged but cannot retroactively veto this synchronous boundary. Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only sessions entered through that agent's context.
1258
1344
 
1259
1345
  ```ts cordis-catalog
1260
1346
  /**
1261
- * Creation announcement during session publication. A synchronous throw vetoes and rolls
1262
- * back with a paired disposal; detach requested during dispatch is deferred.
1347
+ * Read-only creation announcement after store entry.
1348
+ * New events reject until every synchronous listener has returned successfully.
1349
+ * A synchronous throw vetoes creation and rolls back with a paired disposal;
1350
+ * detach requested during dispatch is deferred.
1263
1351
  * A returned-promise rejection is logged but cannot retroactively veto this
1264
1352
  * synchronous boundary.
1265
1353
  * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners
@@ -48,7 +48,7 @@ Tab identity is the pair `(kind, address)`: the registry's claim uses the addres
48
48
  | `canOpen(address)` | Optional synchronous veto of a glob match; it runs on every routing decision. |
49
49
  | `title(address)` | The chip's text, captured into the layout record when the tab opens and never rewritten. |
50
50
  | `keepMounted` | Optional lazy retention of visited bodies across hiding, Session switches and docking; the owning View holds the Session reference. |
51
- | `guide` | Optional entry boxes for the guide page: `{ order, title(), description?(), icon? }`. Picking a box opens the contributing type as a page; omit to stay off the page. |
51
+ | `guide` | An **array** of entry boxes for the guide page: `[{ id, order, title(), description?(), icon? }, …]` — each entry carries its own `id` (the registry checks entries for duplicates). Picking a box opens the contributing type as a page; omit (or pass an empty array) to stay off the page. ⚠️ Passing a single object throws "entries.map is not a function" (the client entry fails into FAILED → the web boot gate refuses to start) — the 0.2.x live contract is an array; do not use the legacy single-object form. Local fix (2026-11-08, verified on dsh 0.2.1-rc.3; a later upstream `npm run refresh-kb` sync may overwrite this line). |
52
52
 
53
53
  Whole-address patterns match the raw address: picomatch globstar (`**`) excludes standalone `.` and `..` segments even with `dot: true`, which includes dotfiles but does not change that exclusion. Resource-specific code parses addresses; the Host enforces file-read permissions.
54
54
 
@@ -79,22 +79,23 @@ export function apply(ctx: Context): void {
79
79
 
80
80
  ## Navigation: `ctx.sidebarRight`
81
81
 
82
- Two opens are the navigation controller, and every way into the column calls one of them: `openResource(address, options?)` for a `dsh-resource://` address — the conversation's file links, a tool row's line reference, a file tree's rows — and `openTab(kind, options?)` for a page — the strip's add control, a guide entry box, or an HTTP(S) link in Assistant Markdown. Both run four steps as one history entry — claim (the registry ranks the resource's types, or the named `kind`'s implementation in force answers); focus a tab already showing the same `(kind, address)`; otherwise seat a new tab; expand the column — and then record the navigation in the Tab domain ([service](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-sidebar-right/README.md#ctxsidebarright)). Content the user cannot see is not opened, so a collapsed column expands in the same step. `openResource` throws for an address outside `dsh-resource://` or one no type claims; `openTab` throws for a kind nothing registered: both are wiring mistakes, not user errors.
82
+ Two opens are the navigation controller, and every way into the column calls one of them: `openResource(address, options?)` for a `dsh-resource://` address — the conversation's file links, a tool row's line reference, a file tree's rows — and `openTab(kind, options?)` for a page — the strip's add control, a guide entry box, or an HTTP(S) link in Assistant Markdown. Both run four steps as one history entry — claim (the registry ranks the resource's types, or the named `kind`'s implementation in force answers); focus a tab already showing the same `(kind, address)`; otherwise seat a new tab; expand the column — and then record the navigation in the Tab domain ([service](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-sidebar-right/README.md#ctxsidebarright)). Content the user cannot see is not opened, so a collapsed column expands in the same step, unless the open replaces a floating tab or reveals a tab in a floating panel. A reveal of a tab already on screen makes the pane holding it glow once, for every tab type, and only while its Session is on screen; a reveal that switches tabs or expands the column does not glow. `openResource` throws for an address outside `dsh-resource://` or one no type claims; `openTab` throws for a kind nothing registered: both are wiring mistakes, not user errors.
83
83
 
84
84
  | Option | Meaning |
85
85
  |---|---|
86
86
  | `paneId` | Land a new tab in this pane; default is the active docked pane (the first docked pane while a floating pane is active). |
87
- | `replaceTab` | Take this tab's pane and strip slot, closing it in the same step; a floating tab lends no place, so the new tab lands as if unplaced. |
87
+ | `replaceTab` | New content takes this tab's place and the tab closes in the same step: a docked tab's pane and strip slot, or a floating tab's panel, keeping its pane id and rectangle. A reveal keeps the tab open ([semantics](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-sidebar-right/README.md#ctxsidebarright)). |
88
88
  | `revealIfOpened` | Default `true`: a tab already showing the same `(kind, address)` is focused and handed `params`. `false` opens another tab regardless. |
89
89
  | `preferNewPane` | Prefer a new docked pane under the normal pane budget and room rule; fall back to the target pane when it cannot split. Ignored with `replaceTab`. |
90
+ | `destination` (`openResource` only) | `'sidebar'` or `'float'`: settle in the active docked pane (the first docked pane while a floating pane is active) or a new floating panel, ignoring the four options above. A copy already there is revealed; else a copy in the other host moves there with its tab id and body state; else a new tab opens. `'float'` leaves the column's expansion unchanged, for a new tab as for a move ([semantics](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-sidebar-right/README.md#ctxsidebarright)). |
90
91
  | `kind` (`openResource` only) | Name the opening type instead of ranking claims; its implementation in force opens the address, and its `canOpen` still applies. |
91
92
  | `params` | Navigation parameters for the body, delivered as `navigation.params`. `openResource` types them by resource type through the merge-extensible `SidebarRightResourceParamsMap` (the text preview declares `{ line?: number }`); `openTab<K>` types them by kind through `SidebarRightTabParamsMap`, `undefined` for a kind that declares none; a body reads `SidebarRightNavigationParams`, the union of both. Values are JSON-shaped by convention and not validated at run time. |
92
93
 
93
- Placement is the caller's option, never a type's property. The conversation calls `openResource(fileAddressFor(sessionId, cwd, path))` and, from a `read` tool row, adds `{ params: { line } }` from the call's 1-based `offset`; a guide entry box calls `tab.actions.openTab(entry.kind, { replaceTab: true })`; a file-tree row calls `tab.actions.openResource(address)`; the strip's add control calls `openTab('guide', { paneId, revealIfOpened: false })`.
94
+ Placement belongs to the caller, not the tab type. The [files navigator reference](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-sidebar-files/README.md#the-navigator) defines its host-owned opening callbacks; the [guide reference](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-sidebar-right/README.md#the-guide) defines guide replacement and explicit close.
94
95
 
95
- `close(tabId)` closes a tab; `active()` returns the active pane's active tab; `isExpanded()` and `toggleExpanded()` read and flip the column, the flip recorded in the sequence. Reads answer for the no-Session case with `undefined` or `false`; writes need a mounted Session surface and throw without one rather than write into a surface nobody draws.
96
+ `close(tabId)` closes a tab; `hide(tabId)` closes a floating tab or collapses its docked column; `active()` returns the active pane's active tab; `isExpanded()` and `toggleExpanded()` read and flip the column, the flip recorded in the sequence. Reads answer for the no-Session case with `undefined` or `false`; writes need a mounted Session surface and throw without one rather than write into a surface nobody draws.
96
97
 
97
- `focus(tabId)` makes a tab its pane's active tab; `split(paneId?)` splits the active docked pane, or the named one, and returns the new pane's id — or `undefined`, recording nothing, when the pane budget or the column's width forbids a split; `float(tabId, rect?)` lifts a tab into a floating pane; `dock(paneId)` returns a floating pane to the docked area. All four run the store's existing actions and record one history entry each; a target that does not exist or is already in the requested state is a no-op, and like `open` they throw without a mounted Session surface. `TabId`, `PaneId`, `TabRecord`, and `FloatRect` are re-exported from the package's `/client` entry so a caller needs no dockkit import.
98
+ `focus(tabId)` makes a tab its pane's active tab; `split(paneId?)` splits the active docked pane, or the named one, and returns the new pane's id — or `undefined`, recording nothing, when the pane budget or the column's width forbids a split; `float(tabId, rect?)` lifts a tab into a floating pane; `dock(paneId)` returns a floating pane to the docked area and expands the column. All four run the store's existing actions and record one history entry each; a target that does not exist or is already in the requested state is a no-op, and like `open` they throw without a mounted Session surface. `TabId`, `PaneId`, `TabRecord`, and `FloatRect` are re-exported from the package's `/client` entry so a caller needs no dockkit import.
98
99
 
99
100
  `focusedTarget(element?)` captures the visible page under live DOM focus, including an embedding iframe; outside or stale sidebar markup yields no target. `commandTarget(element?)` also permits the mounted Session's active dock pane for an open initiated outside the sidebar. A `SidebarRightTarget` captures Session, pane, host, tab occurrence, and navigation revision. `isTargetCurrent(target)` checks that identity before execution, so reopening a record or navigating it invalidates a captured action; it never retargets to another page. See the [controller methods](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-sidebar-right/src/client/service.ts) for close and placement outcomes.
100
101
 
@@ -110,9 +111,9 @@ The Sidebar declares four extension slots; its document tab declares the additio
110
111
  | `sidebar.right.tab.menu.item` | list, Session scope | Content-level actions appended after the kit's own layout actions. An item that acts must call the owner's `dismiss()`. |
111
112
  | `sidebar.right.tab.document` | keyed by the document implementation's `id`, Session scope | The selected file renderer inside the document tab; the parent owns shared loading and toolbar controls. |
112
113
 
113
- A body, title and guide replacement receive the framework-injected `useTabInfo()`. It returns `{ sidebar, panel, tab }`: `sidebar` holds `expanded` and `fullscreen`, `panel.id` names the containing pane, and `tab` contains its record fields plus `visible`, `navigation`, `signal`, and `actions`. All tabs require a foreground Session. Docked bodies also require expansion and selection; docked titles require expansion; foreground floats survive collapse. `signal` aborts when the record disappears or the plugin unloads, not on hiding or Session switching. `tab.actions` provides `openResource`, `openTab`, and `close`, bound to the tab's own Session. Open placement defaults to its current pane; `revealIfOpened` defaults to `true`, and `replaceTab: true` replaces this record in the same history entry. Menu entries retain plain `tab` and `dismiss` owner parameters.
114
+ A body, title and guide replacement receive the framework-injected `useTabInfo()`. It returns `{ sidebar, panel, tab }`: `sidebar` holds `expanded` and `fullscreen`, `panel.id` names the containing pane and the required `panel.isFloating: boolean` distinguishes a floating panel from a docked pane. Both update through the hook when a tab moves, while `tab.id` stays unchanged. `tab` also contains its other record fields plus `visible`, `navigation`, `signal`, and `actions`. All tabs require a foreground Session. Docked bodies also require expansion and selection; docked titles require expansion; foreground floats survive collapse. `signal` aborts when the record disappears or the plugin unloads, not on hiding or Session switching. `tab.actions` provides `openResource`, `openTab`, and `close`, bound to the tab's own Session. Opens return `void` and default to its current docked pane, or the active docked pane when this tab floats; `revealIfOpened` defaults to `true`, and `replaceTab: true` lets new content replace this record in the same history entry; an `openResource` with `destination` passes neither this tab's pane nor this record. Menu entries retain plain `tab` and `dismiss` owner parameters.
114
115
 
115
- `navigation.revision` increments on every navigation to the tab whether or not `params` changed, so a body can act on "navigated again" alone; it is `1` for a tab opened by address and `0` for a record nobody opened by address — a seeded guide, or a tab restored by undo. The Tab domain holds one occurrence per open record: a record that appears is pinned in the resource model, so switching tabs unmounts a body without dropping its content; a record that vanishes is aborted and dropped; a record restored by undo is a new occurrence ([Tab domain](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-sidebar-right/README.md#the-tab-domain)).
116
+ `navigation.revision` increments on every navigation to the tab whether or not `params` changed, so a body can act on "navigated again" alone; it is `1` for a tab opened by address and `0` for a record nobody opened by address — a seeded guide, or a tab restored by reload or undo. The Tab domain holds one occurrence per open record: a record that appears is pinned in the resource model, so switching tabs unmounts a body without dropping its content; a record that vanishes is aborted and dropped; a record restored by undo is a new occurrence ([Tab domain](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-sidebar-right/README.md#the-tab-domain)).
116
117
 
117
118
  `tab.actions.bindCommands(commands)` contributes `SidebarRightTabCommands`, currently an optional `refresh` callback, for the mounted body. Omitted operations are unavailable; the returned disposer releases that registration without removing a newer body's commands. The tab lifetime also releases them. `tab.refreshShortcut` supplies the effective refresh catalog entry for page controls; it is optional when no entry is available. These fields are declared in the [slot owner types](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-sidebar-right/src/client/contract/slots.ts).
118
119
 
@@ -145,15 +146,15 @@ The Host `ctx.workspaceFiles` service and generated `workspaceFiles` Remote name
145
146
  ## Shipped types
146
147
 
147
148
  - **`guide`** — `builtin`, opened as `openTab('guide')`. A muted compass sits above one capsule per contributed `guide` entry, in `order`; short lists show registered descriptions, and every missing icon uses the shipped placeholder. Picking a capsule opens the contributing type as a page in the guide tab's place. A pane holds at most one guide tab, and the strip's add control appears only while its pane has none. A new pane receives the registered default page: the sole guide entry directly, or the guide when the entry count is not one ([guide](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-sidebar-right/README.md#the-guide)).
148
- - **`text`** — `fallback`, `dsh-resource://file/**`, claiming Session addresses only. Document Preview observes metadata through `useResource<'file'>`, loads content through Remote callbacks, and owns renderer selection, the toolbar, per-tab refresh, scroll, and source navigation; unknown extensions render as plain text ([README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-sidebar-documentpreview/README.md)).
149
- - **`files`** — `builtin`, opened as `openTab('files')`. The workspace directory tree, listed lazily through `list` and watched by expanded directory, opening a file with `tab.actions.openResource(fileAddressFor(sessionId, root, path))` into its own pane ([README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-sidebar-files/README.md)).
149
+ - **`text`** — `fallback`, `dsh-resource://file/**`, claiming Session addresses only. Document Preview observes metadata through `useResource<'file'>`, loads content through Remote callbacks, and owns renderer selection, the toolbar, per-tab refresh, scroll, and source navigation; unknown extensions render as plain text. It directly renders the files plugin's `sidebar.files.navigator` and `sidebar.files.navigator.toggle` Factories in docked and floating panes; unregistered Factories render nothing ([README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-sidebar-documentpreview/README.md)).
150
+ - **`files`** — `builtin`, opened as `openTab('files')`. The files page and navigator share one workspace tree per pane. [The package reference](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-sidebar-files/README.md) owns lazy listings, watches, opening callbacks, and navigation-driven visibility.
150
151
  - **`browser`** — multi-instance `builtin`, opened as `openTab('browser', { params: { url? } })`. Chat's [link preference](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-chat/README.md) controls whether Assistant Markdown opens HTTP(S) links here. It accepts public and loopback HTTP(S) targets under the default sandbox, rejects local files in favor of Document Preview, and uses application-known iframe history ([README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-sidebar-browser/README.md)).
151
152
  - **`subagentchat`** — `builtin`, `dsh-resource://subagentchat/session/<child>?parent=<parent>&mode=<mode>`. An explicitly addressed subagent Conversation retained by the resource provider and rendered through the shared Conversation Factory ([README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-subagent/README.md)).
152
153
 
153
154
  <a id="not-built"></a>
154
155
  ## Not built
155
156
 
156
- - Persistence: layout state is memory-only; a reload starts every session collapsed, and no session's tabs are visible from another.
157
+ - Cross-device layout synchronization: layouts are browser-local, with separate saved state per Session ([state](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-sidebar-right/README.md#state)).
157
158
  - A read-only layout snapshot or subscription on `ctx.sidebarRight`: the service exposes operations only, and dockkit's `LayoutState`/`LayoutOp` are internal.
158
159
  - A capability-discovery array (`features`) on the service.
159
160
  - An `option` priority band for tab types: nothing lists a tab type without letting it claim.
@@ -78,7 +78,7 @@ The shipped local provider scans roots in rank order:
78
78
  | 500 | `user-agents` | `<agentsHome>/skills` |
79
79
  | 600 | `bundled` | `Config.bundledSkillDir` when configured |
80
80
 
81
- The project root is the nearest ancestor containing `.git`; without one, the current cwd is used. When `ctx.fs` is available, the git-root walk probes `.git` through the filesystem service so remote or sandboxed workspaces do not fall back to the host filesystem boundary. The user DSH root skips its `.system` child. The local provider does not synthesize built-in system skills; deployments supply packaged skills through configured bundled roots or dedicated providers.
81
+ The project root is the nearest ancestor containing `.git`; without one, the current cwd is used. When `ctx.fs` is available, the git-root walk probes `.git` through the filesystem service so remote or sandboxed workspaces do not fall back to the host filesystem boundary. The user DSH root skips its `.system` child. The local provider does not synthesize built-in system skills; deployments supply packaged skills through configured bundled roots or dedicated providers. A failed root contributes no candidates, so a lower-priority same-name skill from another root may supply both the catalog description and loaded body until recovery.
82
82
 
83
83
  `dsh-skill-badge` registers one immutable `bundled` candidate at `BUNDLED_SKILL_RANK` and exposes its packaged asset directory through `resourceBase`. The shipped CLI declares the plugin disabled, so enabling its composition row is an explicit opt-in.
84
84
 
@@ -131,7 +131,7 @@ interface SkillSummary {
131
131
 
132
132
  `ctx.skills.list()` preserves all four policy combinations. `isModelInvocable(skill)` and `isUserInvocable(skill)` read the corresponding required field. A model-only skill sets `{ modelInvocable: true, userInvocable: false }`, a user-only skill sets `{ modelInvocable: false, userInvocable: true }`, and setting both fields to `false` keeps the skill available only through trusted `ctx.skills.get()` callers. The local provider reads the exact kebab-case frontmatter keys `disable-model-invocation` and `user-invocable`, defaults omitted fields to `true`, and projects every parsed skill into this normalized policy.
133
133
 
134
- `SkillCatalogSnapshot` distinguishes authoritative absence from transient provider failure or a catalog that kept changing during discovery. `skills` contains the sorted invocation-neutral summaries collected in that observation; `complete` is true only when every registered provider completed without a concurrent catalog revision. Incomplete snapshots are not cached, allowing each consumer to retain its last-good filtered catalog and retry.
134
+ `SkillCatalogSnapshot` distinguishes authoritative absence from transient provider failure or a catalog that kept changing during discovery. `skills` contains the sorted invocation-neutral summaries collected in that observation; `complete` is true only when every registered provider completed without a concurrent catalog revision. Incomplete snapshots are not cached, so the next lookup retries discovery; each consumer decides how to present the partial result.
135
135
 
136
136
  ```ts type-equiv
137
137
  /** One catalog observation plus whether discovery completed within a stable catalog revision. */
@@ -230,9 +230,9 @@ interface Config {
230
230
 
231
231
  ## Session catalog and tool contract
232
232
 
233
- `dsh-tool-skill` injects the initial durable user-role `<system-reminder>` at the first `agent/pre-step` of a live session that observes a non-empty complete view. The catalog contains sorted skill `name` and normalized, XML-escaped `description` only; it omits bodies, paths, sources, providers, and routing hints. Discovery forwards the step's abort signal through `SkillLookupOptions`. `catalogDescriptionMaxLength` is the consumer config for the description bound, with default `500` and integer minimum `3`.
233
+ `dsh-tool-skill` injects the initial durable user-role `<system-reminder>` at the first `agent/pre-step` of a live session that observes available skills or incomplete discovery. The catalog contains sorted skill `name` and normalized, XML-escaped `description` only; it omits bodies, paths, sources, providers, and routing hints. Discovery forwards the step's abort signal through `SkillLookupOptions`. `catalogDescriptionMaxLength` is the consumer config for the description bound, with default `500` and integer minimum `3`.
234
234
 
235
- Before each later model step, the consumer applies exact tool visibility and digests the exact rendered entries between the `<available_skills>` tags from a complete snapshot. It derives the comparison baseline from the same entries in the newest recognizable visible catalog message sourced by the plugin. A changed digest appends a durable full replacement through `agent.inject()`; deleting every skill appends an explicit empty replacement. Incomplete snapshots preserve the last-good model view. If compaction hides every historical catalog message, the next complete snapshot re-establishes the current catalog; an empty view with no prior catalog emits nothing. These catalog messages are session history, not World State.
235
+ Before each later model step, the consumer applies exact tool visibility and compares the entries and completeness with the newest recognizable visible catalog message in the session log. A changed observation contributes a durable replacement to the pre-step decision; deleting every skill appends an explicit empty replacement. Incomplete discovery publishes the available subset with a warning and optional `incomplete: true` source metadata; absence of that flag means complete. Recovery republishes the catalog even when its entries are unchanged. If compaction hides every historical catalog message, the next observation re-establishes the current catalog; a complete empty view with no prior catalog emits nothing. These catalog messages are session history, not World State.
236
236
 
237
237
  The model-facing `skill({ name })` tool validates the kebab-case name, finds the summary in the invocation-neutral catalog, rejects it before loading unless `isModelInvocable` permits access, then rereads the complete definition for the calling agent cwd and rechecks the policy before returning content. It reports an unresolved skill as unknown or no longer available and returns a tool result containing `<skill_content name="...">`, `<skill_resources>`, and `<skill_instructions>`. `resourceBase` resolves explicitly referenced scripts, references, and assets only as needed; the loaded result does not enumerate a skill directory. Body-only edits therefore change later tool calls without producing catalog messages or rewriting earlier tool results.
238
238
 
@@ -14,6 +14,12 @@ This page documents slot ownership, component inputs, extension APIs, and the sh
14
14
 
15
15
  The plugin catalog declares `plugins.add.actions`, a root-scoped list for `MenuItemButton` rows after installation in the Add plugin menu. Its owner supplies `onDismiss()` to close the menu before starting an action. The slot follows the owning Plugins page declaration lifetime.
16
16
 
17
+ The root-scoped lists `sidebar.panellist.actions`, `conversation.session.header.views.actions`, and `sidebar.right.tab.guide.actions` supply the rows of the More menus after the panel rows, the View tabs, and the right-sidebar guide cards. A region draws its More button and menu only while its list has registrations, and passes the customizable entries with their pin state, `onOpen`, `onPinnedChange`, and `onDismiss`. Panel and View entries also carry optional `active` state for the current selection, independently of pin state. The `sidebar.panel.icon` root-scoped factory owns the `sidebar.panellist` list and renders its registered icon by `id`, `size`, and `active` for both sidebar rows and More entries. Each region keeps its own unpinned entry ids in memory; [`ui-entry-customization`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-entry-customization/README.md) registers the shipped rows.
18
+
19
+ [ui-workspace](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-workspace/README.md#understand-the-implementation) documents Session-row extension positions, visibility, and keyboard behavior.
20
+
21
+ [ui-settings](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-settings/README.md#filling-the-settings-slots) documents the settings page and navigation-icon extension points.
22
+
17
23
  ## Declaration and lifecycle
18
24
 
19
25
  `SlotMap` is the compile-time registry. A package declaration-merges the key, cardinality, scope, owner props, keyed props, and optional slot-level inject face. The runtime declaration is the matching `children` entry on the component that owns the render location.
@@ -59,11 +65,24 @@ The slot declaration fixes two independent axes.
59
65
  | cardinality | `list` | Cells are addressed by required `id` and ordered by `order`, then registration order. |
60
66
  | cardinality | `keyed` | The owner dispatches an `entryKey`; the matching cell renders with any key-specific props. |
61
67
  | cardinality | `chain` | Each entry supplies a pure `select(owner)` function. The first non-null result in priority order renders and receives that result as `matched`; otherwise the owner fallback renders. |
68
+ | cardinality | `hoc` | Entries nest around the owner's `renderSlot(key, owner, { children })` content, lowest outermost; see [Hoc layers](#hoc-layers). |
62
69
  | scope | `root` | One root-scoped component and store instance. |
63
70
  | scope | `session-maybe` | Inherits the surrounding Provider binding but stays renderable without one; Session values are optional. |
64
71
  | scope | `session` | Requires a resolved surrounding Provider binding and receives definite Session values. |
65
72
 
66
- `priority` is a shadowing rank for `single`, `list`, and `keyed` cells and an election order for `chain`. Lower values run or render first. Ordinary additive contributions should choose a fresh list `id` or keyed `key`; intentionally reusing a shipped cell replaces its presentation.
73
+ `priority` is a shadowing rank for `single`, `list`, `keyed`, and `hoc` cells and an election order for `chain`. Lower values run or render first. Ordinary additive contributions should choose a fresh list or hoc `id`, or keyed `key`; intentionally reusing a shipped cell replaces its presentation.
74
+
75
+ <a id="hoc-layers"></a>
76
+
77
+ ### Hoc layers
78
+
79
+ A hoc entry is a layer addressed by its required `id`. Layers nest by ascending `order`, then `priority`, then registration order, lowest outermost. Each layer receives the same owner props plus the next inner layer as `children`, the owner's content at the innermost, and renders it exactly once; owner props must not use the name `children`. Omitted `children` renders the layers around nothing, and with no live layer the content renders unchanged.
80
+
81
+ - Remounting: adding or removing a layer remounts the content inside it, including a crashed layer leaving the slot; a `session` or `session-maybe` layer also remounts it when its Session binding changes.
82
+ - Errors: a crashed layer renders its `children` and leaves the slot. An error thrown by the wrapped content passes every layer and is reported against none; a layer that wraps its `children` in its own error boundary catches it as an internal wrapper error rather than the original.
83
+ - Layout: the outlet inserts a `display: contents` `[data-slot]` element between the owner and its content, so owner selectors cannot rely on the content being a direct child. A layer must not create a box of its own — for example, use `display: contents` — or the content leaves its parent's layout.
84
+
85
+ The [context-menu plugin](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-context-menu/README.md) contributes `useContextMenu` through `provideRoot`; every scope receives the same plugin-owned trigger factory. Its prop and retained handlers retire when the provider unloads. Its root-scoped keyed `contextMenu.icon` Slot renders business-owned icons from action metadata.
67
86
 
68
87
  ## Component inputs
69
88
 
@@ -77,6 +96,7 @@ A registered component receives inputs assembled at its binding site. Components
77
96
  | private data, callbacks, and observable hooks | the registration's `inject` factory | `InjectFace<I>` |
78
97
  | localized `t` function | the registration's `locale` namespace | `PropsLocale<N>` |
79
98
  | selected chain value | the registration's `select` result | `matched` through `ComposedProps` |
99
+ | wrapped owner content | the `SlotMap` row's `hoc` kind | `children` through `ComposedProps` |
80
100
 
81
101
  `SessionProvider` is also present in `PropsRenderSlots` when an entry declares a `session` or `session-maybe` child. With no `session` prop it inherits the surrounding binding; an explicit `SessionReference` or `undefined` overrides only that subtree. The Provider does not key its whole body. A strict `session` entry remounts when its binding generation changes. A blank `session-maybe` entry adopts its first binding without remounting, then remounts for a later generation or a return to absence.
82
102
 
@@ -129,6 +149,7 @@ root [AppFrame]
129
149
  │ ├─ conversation.session.header.lineage
130
150
  │ ├─ conversation.session.header.actions
131
151
  │ ├─ conversation.session.header.utilities
152
+ │ ├─ conversation.session.header.views.actions
132
153
  │ └─ conversation.session.header.corner
133
154
  └─ calls Factory: conversation.content
134
155
 
@@ -136,9 +157,13 @@ Factory: conversation.content [ConversationContent]
136
157
  ├─ conversation.session [ConversationSession / DefaultConversationViews]
137
158
  │ └─ conversation.view
138
159
  │ ├─ id=chat [ChatView]
160
+ │ │ ├─ conversation.chat.text-interaction [list]
139
161
  │ │ └─ conversation.chat.flow [ChatFlow]
140
162
  │ │ └─ conversation.chat.node [ChatNodeSeat dispatch]
141
- │ │ ├─ key=user,steering [UserMessageNodeView]
163
+ │ │ ├─ key=user [UserMessageNodeView]
164
+ │ │ │ ├─ conversation.chat.user.before [chain]
165
+ │ │ │ └─ calls Factory: conversation.chat.user.content
166
+ │ │ ├─ key=steering [UserMessageNodeView]
142
167
  │ │ │ └─ calls Factory: conversation.chat.user.content
143
168
  │ │ ├─ key=assistant-step [AssistantNodeView / AssistantMarkdown]
144
169
  │ │ │ ├─ conversation.chat.message.images [MessageImages]
@@ -173,6 +198,8 @@ Factory: conversation.content [ConversationContent]
173
198
  ├─ conversation.input.dock
174
199
  │ └─ id=queue [QueueDock]
175
200
  │ └─ calls Factory: conversation.user.text
201
+ ├─ conversation.hero.frame [hoc]
202
+ │ └─ id=pixel-whale [PixelWhale]
176
203
  ├─ conversation.hero.brand.mark
177
204
  ├─ conversation.hero.workspace
178
205
  │ └─ conversation.hero.workspace.directoryFlow
@@ -201,4 +228,4 @@ The generated [Client inspect catalog](https://github.com/deepseek-ai/deepseek-h
201
228
  - Keep business and transport state in their owning Cordis services or Client models. Slot stores hold shared viewing and interaction state only.
202
229
  - Keep observable source and snapshot identities stable between changes. Republish through the same source whenever its value changes.
203
230
  - Pass JSON-compatible data and callbacks between UI domains. The `hooks` compartment is the sole exception for bare observables; React content travels through slots.
204
- - Treat `single` and an occupied keyed cell as replacement points. Use list ids or an unoccupied key for additive extensions.
231
+ - Treat `single` and an occupied keyed cell as replacement points. Use fresh list or hoc ids, or an unoccupied key, for additive extensions.
@@ -48,7 +48,7 @@ interface StorageBackend {
48
48
  }
49
49
  ```
50
50
 
51
- A backend owns one medium (a file-tree root, a database file) and exposes optional operation groups; `kv` is the only shipped group. `KvFacet.open(descriptor)` opens one named unit — `KvUnitDescriptor` carries the name, current format version, optional compatible record versions, table names, and whether a global singleton slot exists — and returns a `KvUnit` with `loadAll`, `putRecord`, `deleteRecord`, `setGlobal`, and `close`. Unit and table names must match `UNIT_NAME_RE` (safe as a file name and as a SQL identifier segment); record keys are arbitrary strings that never reach file paths. A unit does not serialize concurrent writes — ordering belongs to the caller — but each single call is atomic on the medium and durable once resolved. A `single` medium stamped with a different version rejects `version-mismatch`; a `per-record` document stamped outside the accepted set reads as absent. A medium that cannot be parsed as the unit rejects `malformed-medium`. [`backend.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/storage/storage/src/backend.ts) is the normative clause-by-clause contract, and the shared conformance suite in [`tests/contract.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/storage/storage/tests/contract.ts) checks every clause against each backend. The [json backend](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/storage/storage-json/README.md) republishes one whole human-readable file per unit atomically; the [sqlite backend](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/storage/storage-sqlite/README.md) stores one document per row in one database for frequently updated data.
51
+ A backend owns one medium (a file-tree root, a database file) and exposes optional operation groups; `kv` is the only shipped group. `KvFacet.open(descriptor)` opens one named unit — `KvUnitDescriptor` carries the name, current format version, optional compatible versions, table names, and whether a global singleton slot exists — and returns a `KvUnit` with `loadAll`, `putRecord`, `deleteRecord`, `deleteRecords`, `setGlobal`, and `close`. Unit and table names must match `UNIT_NAME_RE` (safe as a file name and as a SQL identifier segment); record keys are opaque strings in the `single` layout and match `[a-zA-Z0-9_-]+` path segments in the `per-record` layout. A unit does not serialize concurrent writes — ordering belongs to the caller — whole-document and row-store calls are atomic on the medium, while a per-record batch interrupted before resolution can be partially applied. Resolved writes are durable; per-record deletions sync directory changes on POSIX. `deleteRecords` applies a whole batch in one call: it resolves once every listed record is absent from the readable state and the backend accepted the batch, and a rejection normally leaves the batch unapplied; a backend that cannot establish or restore the batch's state rejects with `unknown-state`, after which every later operation on that unit rejects with the same error until `close()` releases it (calls after close reject `closed`). A `single`-layout failure after the atomic replacement (a directory-fsync error) can leave the new file on the medium while the caller sees a rejection; close the backend and its domains, then reopen to inspect saved state before retrying. A `single` medium stamped outside the current and declared compatible versions rejects `version-mismatch`; a `per-record` document stamped outside the accepted set reads as absent. A medium that cannot be parsed as the unit rejects `malformed-medium`. [`backend.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/storage/storage/src/backend.ts) is the normative clause-by-clause contract, and the shared conformance suite in [`tests/contract.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/storage/storage/tests/contract.ts) checks the shared clauses against each backend. The [json backend](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/storage/storage-json/README.md) republishes one whole human-readable file per unit atomically; the [sqlite backend](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/storage/storage-sqlite/README.md) stores one document per row in one database for frequently updated data.
52
52
 
53
53
  ## Declaring a domain
54
54
 
@@ -62,20 +62,20 @@ interface DomainSpec {
62
62
  /** Current domain format version; reads enforce it according to the selected layout. */
63
63
  readonly version: number
64
64
  /**
65
- * Medium layout for the backend unit: `single` (the default) stores the
65
+ * Document layout for the backend unit: `single` (the default) stores the
66
66
  * whole unit as one document; `per-record` stores each record as its own
67
67
  * document, for units whose records are large, sparse, or individually
68
- * disposable — the projection cache — and scopes version checks per record
69
- * (an unaccepted record document is discarded, never migrated).
68
+ * disposable — the projection cache — with per-record version checks.
69
+ * Row stores retain unit-wide versioning for either layout request.
70
70
  */
71
71
  readonly layout?: 'single' | 'per-record'
72
72
  /**
73
73
  * Older domain versions whose stored records the current record schemas
74
74
  * also accept (the declaring owner vouches for that, typically by
75
- * declaring the fields older records lack as optional). `per-record` backends
76
- * read documents stamped with a listed version instead of discarding them,
77
- * and accept a legacy whole-unit file so stamped for the one-time
78
- * bootstrap; writes always stamp {@link version}.
75
+ * declaring the fields older records lack as optional). Ordinary reads admit
76
+ * listed versions without restamping saved data; writes stamp {@link version}
77
+ * while leaving untouched records as saved. Current schemas must therefore
78
+ * accept mixed generations even under the current unit stamp.
79
79
  */
80
80
  readonly compatibleVersions?: readonly number[]
81
81
  /**
@@ -98,6 +98,23 @@ interface DomainSpec {
98
98
 
99
99
  `defineDomain(spec)` pins the spec's literal types and fails loud at the owner's module load, before any medium is touched: a domain or table name outside `UNIT_NAME_RE`, a version that is not a non-negative integer, or a global schema that accepts `null` all throw (`null` is the medium's "never written" sentinel, so a stored nullable global could not round-trip). `domainTable<K, V>(schema)` declares one table with a phantom compile-time key type (typically a [branded id](./core.md#branded-ids)); `descriptorOf(spec)` projects the backend-facing unit descriptor.
100
100
 
101
+ <a id="domain-versioning"></a>
102
+ ## Domain versioning
103
+
104
+ `version` names the current read/write format. `compatibleVersions` lists older versions whose records and global value the owner can decode with its current schemas; only nonnegative integers below `version` are allowed. Without that declaration, reads stay exact-version. Acceptance does not weaken record validation or permit a newer unknown version. Each row's saved fields must determine its meaning unambiguously; a unit stamp cannot distinguish different meanings of identical fields in mixed rows.
105
+
106
+ Ordinary compatible opens and reads do not restamp or normalize saved values. Whole-unit JSON publishes the current stamp and changed data in one atomic file replacement; SQLite commits its first updated unit stamp and mutation in one transaction; batch deletes always use one transaction. Deleting missing records or an empty batch does not advance the stamp. The stamp identifies an accepted format, not completion of value normalization; readers must accept mixed generations. A backend with a unit-wide stamp rejects an unsupported unit version.
107
+
108
+ Serialization failure before publication or successful SQLite rollback preserves the previous data and stamp. An I/O failure after JSON replacement, or a failure of SQLite rollback itself, can leave the saved outcome unknown despite rejection. Stop using and close the backend and its domains, then reopen to inspect saved state before deciding whether to retry. The backend READMEs define these failure cases.
109
+
110
+ JSON's `per-record` layout checks and stamps each document independently; an unsupported document reads as absent. Its existing whole-unit bootstrap is an exception to read-only loading: it copies accepted historical values into current-stamped documents without converting them. An existing declared table directory, even when empty, or a declared global document suppresses bootstrap. SQLite retains unit-wide version checks regardless of the layout request. See the [JSON backend](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/storage/storage-json/README.md) and [SQLite backend](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/storage/storage-sqlite/README.md) for layout and recovery behavior.
111
+
112
+ For a compatible successor, bump `version`, keep all still-readable stamps in `compatibleVersions`, and extend the same schema's decoding/defaults. Consumers normalize values when rewriting selected records; Storage does not assign application record versions. Verify historical and skipped upgrades, mixed values, reads without writes, failure rollback, restart, other-unit isolation, and unknown-version refusal. Table removal and layout changes require their own retention and upgrade policy; a compatible stamp alone does not define either.
113
+
114
+ A v2 unit may contain untouched v1 values. A v3 reader accepting stamp 2 must still decode those values; accepting stamp 1 is also necessary for users who skipped v2 entirely. Removing old decoding requires rewriting and validating every affected record, including those already under a current unit stamp. An incompatible change needs an explicit, recoverable upgrade before opening with the new schema; the storage domain has no value-migration runner.
115
+
116
+ Keep a consistent backup before writing a new format if return to an older reader is required: that reader can refuse the new stamp after the first mutation. Lowering a saved stamp by hand does not reverse value conversion. Domain compatibility does not migrate SQLite's physical schema or JSON envelope formats, and changing a backend route does not transfer stored data. Session-format migrations and SQLite physical-layout versioning have separate owners and do not migrate domain values.
117
+
101
118
  ## The open domain
102
119
 
103
120
  ```ts type-equiv
@@ -127,7 +144,7 @@ interface Domain<S extends DomainSpec> {
127
144
  }
128
145
  ```
129
146
 
130
- Reads are synchronous from authoritative in-memory state: `KvTable` exposes `get`/`entries`/`keys`/`size` (snapshot iterators that stay stable while queued writes land), and the global handle's `get()` serves the spec's `initial` until the first `set` materializes the slot on the medium. Every write — `put`, `delete`, `update`, `global.set` — queues on one per-domain chain and reaches backend durability first, then mutates memory, then emits `domain/changed`; a rejected backend write leaves memory untouched, so reads never diverge from the medium. `update(key, fn)` is an atomic read-modify-write at its chain slot (a missing key rejects `missing-key`); `delete` of an absent key resolves `false` with no write and no event. Returned records are the stored objects themselves, not copies — replace via `put`/`update`, never mutate in place.
147
+ Reads are synchronous from authoritative in-memory state: `KvTable` exposes `get`/`entries`/`keys`/`size` (snapshot iterators that stay stable while queued writes land), and the global handle's `get()` serves the spec's `initial` until the first `set` materializes the slot on the medium. Every write — `put`, `delete`, `deleteMany`, `update`, `global.set` — queues on one per-domain chain and reaches backend durability first, then mutates memory, then emits `domain/changed`; a rejected backend write does not publish a domain change; an unknown durable outcome requires reopening before further use of that snapshot; a backend that reports `unknown-state` instead quarantines the domain, and its reads and later writes reject until `close()` releases it. `update(key, fn)` is an atomic read-modify-write at its chain slot (a missing key rejects `missing-key`); `delete` of an absent key resolves `false` with no write and no event. `deleteMany(keys)` removes the present keys as one backend batch in one chain slot, resolves the removed count, and emits one `domain/changed` per removed key; a rejected backend write leaves every record in place and emits nothing; an `unknown-state` rejection quarantines the domain. Returned records are the stored objects themselves, not copies — replace via `put`/`update`, never mutate in place.
131
148
 
132
149
  ## The domain facility: `ctx.storageDomain`
133
150