dsh-plugin-dev-kb 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (234) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +56 -0
  3. package/cordis.patch.yml +12 -0
  4. package/kb/INDEX.md +210 -0
  5. package/kb/README.md +69 -0
  6. package/kb/extra/AGENTS.md +75 -0
  7. package/kb/extra/api-gateway.md +164 -0
  8. package/kb/extra/api-gateway.zh.md +164 -0
  9. package/kb/extra/cookbook/adding-a-vendored-package.md +59 -0
  10. package/kb/extra/cookbook/adding-a-vendored-package.zh.md +59 -0
  11. package/kb/extra/cookbook/maintaining-dsh-code-review.md +64 -0
  12. package/kb/extra/cookbook/maintaining-dsh-code-review.zh.md +64 -0
  13. package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.md +32 -0
  14. package/kb/extra/cookbook/responding-to-pr-review-on-a-stack.zh.md +32 -0
  15. package/kb/extra/defensive-patterns.md +33 -0
  16. package/kb/extra/defensive-patterns.zh.md +33 -0
  17. package/kb/extra/development.md +171 -0
  18. package/kb/extra/development.zh.md +171 -0
  19. package/kb/extra/event-producer-consumer.md +76 -0
  20. package/kb/extra/event-producer-consumer.zh.md +78 -0
  21. package/kb/extra/glossary.md +45 -0
  22. package/kb/extra/glossary.zh.md +45 -0
  23. package/kb/extra/graph-atlas.md +24 -0
  24. package/kb/extra/graph-atlas.zh.md +26 -0
  25. package/kb/extra/i18n/README.md +60 -0
  26. package/kb/extra/i18n/README.zh.md +60 -0
  27. package/kb/extra/i18n/style-samples.md +87 -0
  28. package/kb/extra/i18n/terminology.md +214 -0
  29. package/kb/extra/i18n/translation-prompt.md +263 -0
  30. package/kb/extra/i18n/translation-rules.md +69 -0
  31. package/kb/extra/i18n/translation-rules.zh.md +69 -0
  32. package/kb/extra/module-graph.md +1641 -0
  33. package/kb/extra/module-graph.zh.md +1643 -0
  34. package/kb/extra/postmortem/0001-acp-default-export-drops-inject.md +113 -0
  35. package/kb/extra/postmortem/0001-acp-default-export-drops-inject.zh.md +113 -0
  36. package/kb/extra/postmortem/0002-js-expression-disabled-filesystem-tools.md +47 -0
  37. package/kb/extra/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md +47 -0
  38. package/kb/extra/postmortem/0003-web-agent-gui-feedback-loop.md +53 -0
  39. package/kb/extra/postmortem/0003-web-agent-gui-feedback-loop.zh.md +53 -0
  40. package/kb/extra/postmortem/0004-landlock-partial-notice-misclassified-child-failures.md +55 -0
  41. package/kb/extra/postmortem/0004-landlock-partial-notice-misclassified-child-failures.zh.md +55 -0
  42. package/kb/extra/postmortem/README.md +18 -0
  43. package/kb/extra/postmortem/README.zh.md +18 -0
  44. package/kb/extra/rescope.md +53 -0
  45. package/kb/extra/rescope.zh.md +53 -0
  46. package/kb/extra/subsystems/attachment.md +125 -0
  47. package/kb/extra/subsystems/attachment.zh.md +125 -0
  48. package/kb/extra/subsystems/extensions.md +364 -0
  49. package/kb/extra/subsystems/extensions.zh.md +364 -0
  50. package/kb/extra/subsystems/feedback.md +266 -0
  51. package/kb/extra/subsystems/feedback.zh.md +266 -0
  52. package/kb/extra/testing.md +49 -0
  53. package/kb/extra/testing.zh.md +49 -0
  54. package/kb/extra/web-styling.md +25 -0
  55. package/kb/extra/web-styling.zh.md +25 -0
  56. package/kb/meta/search-index.json +1328 -0
  57. package/kb/meta/site-pages.txt +168 -0
  58. package/kb/meta/source.json +13 -0
  59. package/kb/meta/topics.md +75 -0
  60. package/kb/site/develop/basic/config.md +108 -0
  61. package/kb/site/develop/basic/index.md +146 -0
  62. package/kb/site/develop/basic/publish.md +185 -0
  63. package/kb/site/develop/basic/tool.md +54 -0
  64. package/kb/site/develop/cordis-tutorial/01-first-plugin.md +95 -0
  65. package/kb/site/develop/cordis-tutorial/02-lifecycle-and-effects.md +98 -0
  66. package/kb/site/develop/cordis-tutorial/03-services.md +98 -0
  67. package/kb/site/develop/cordis-tutorial/04-events.md +144 -0
  68. package/kb/site/develop/cordis-tutorial/05-config.md +84 -0
  69. package/kb/site/develop/cordis-tutorial/06-composition-and-hmr.md +113 -0
  70. package/kb/site/develop/cordis-tutorial/07-into-the-harness.md +107 -0
  71. package/kb/site/develop/cordis-tutorial/index.md +62 -0
  72. package/kb/site/develop/framework/events.md +145 -0
  73. package/kb/site/develop/framework/index.md +139 -0
  74. package/kb/site/develop/framework/service.md +152 -0
  75. package/kb/site/develop/practice/index.md +157 -0
  76. package/kb/site/develop/practice/llm-adapter.md +190 -0
  77. package/kb/site/en/develop/basic/config.md +108 -0
  78. package/kb/site/en/develop/basic/index.md +146 -0
  79. package/kb/site/en/develop/basic/publish.md +185 -0
  80. package/kb/site/en/develop/basic/tool.md +54 -0
  81. package/kb/site/en/develop/cordis-tutorial/01-first-plugin.md +95 -0
  82. package/kb/site/en/develop/cordis-tutorial/02-lifecycle-and-effects.md +98 -0
  83. package/kb/site/en/develop/cordis-tutorial/03-services.md +98 -0
  84. package/kb/site/en/develop/cordis-tutorial/04-events.md +144 -0
  85. package/kb/site/en/develop/cordis-tutorial/05-config.md +84 -0
  86. package/kb/site/en/develop/cordis-tutorial/06-composition-and-hmr.md +113 -0
  87. package/kb/site/en/develop/cordis-tutorial/07-into-the-harness.md +107 -0
  88. package/kb/site/en/develop/cordis-tutorial/index.md +60 -0
  89. package/kb/site/en/develop/framework/events.md +145 -0
  90. package/kb/site/en/develop/framework/index.md +139 -0
  91. package/kb/site/en/develop/framework/service.md +150 -0
  92. package/kb/site/en/develop/practice/index.md +157 -0
  93. package/kb/site/en/develop/practice/llm-adapter.md +190 -0
  94. package/kb/site/en/guide/providers-custom-form.png +0 -0
  95. package/kb/site/en/guide/providers-models-page.png +0 -0
  96. package/kb/site/en/guide/providers.md +100 -0
  97. package/kb/site/en/guide/python-sdk.md +106 -0
  98. package/kb/site/en/guide/quickstart.md +32 -0
  99. package/kb/site/en/index.md +8 -0
  100. package/kb/site/en/reference/agent-lifecycle.md +86 -0
  101. package/kb/site/en/reference/capability-seams.md +475 -0
  102. package/kb/site/en/reference/config-catalog.md +3155 -0
  103. package/kb/site/en/reference/cookbook/adding-a-conversation-node.md +235 -0
  104. package/kb/site/en/reference/cookbook/adding-a-package.md +120 -0
  105. package/kb/site/en/reference/cookbook/adding-a-settings-card.md +102 -0
  106. package/kb/site/en/reference/cookbook/adding-a-tool.md +96 -0
  107. package/kb/site/en/reference/cookbook/adding-an-llm-adapter.md +45 -0
  108. package/kb/site/en/reference/cookbook/extension-cookbook.md +131 -0
  109. package/kb/site/en/reference/cordis-api/context.md +368 -0
  110. package/kb/site/en/reference/cordis-api/events.md +211 -0
  111. package/kb/site/en/reference/cordis-api/fiber.md +379 -0
  112. package/kb/site/en/reference/cordis-api/inherited.md +43 -0
  113. package/kb/site/en/reference/cordis-api/registry.md +156 -0
  114. package/kb/site/en/reference/cordis-api/service.md +106 -0
  115. package/kb/site/en/reference/cordis-primer.md +46 -0
  116. package/kb/site/en/reference/index.md +131 -0
  117. package/kb/site/en/reference/persistence-catalog.md +949 -0
  118. package/kb/site/en/reference/subsystems/approval.md +173 -0
  119. package/kb/site/en/reference/subsystems/client-modules.md +121 -0
  120. package/kb/site/en/reference/subsystems/code-runtime.md +194 -0
  121. package/kb/site/en/reference/subsystems/commands.md +190 -0
  122. package/kb/site/en/reference/subsystems/compaction.md +241 -0
  123. package/kb/site/en/reference/subsystems/core.md +1073 -0
  124. package/kb/site/en/reference/subsystems/credentials.md +136 -0
  125. package/kb/site/en/reference/subsystems/filesystem.md +498 -0
  126. package/kb/site/en/reference/subsystems/goal.md +280 -0
  127. package/kb/site/en/reference/subsystems/index.md +58 -0
  128. package/kb/site/en/reference/subsystems/invariants.md +91 -0
  129. package/kb/site/en/reference/subsystems/jobs.md +293 -0
  130. package/kb/site/en/reference/subsystems/llm-streaming.md +920 -0
  131. package/kb/site/en/reference/subsystems/lsp.md +205 -0
  132. package/kb/site/en/reference/subsystems/permission-presets.md +134 -0
  133. package/kb/site/en/reference/subsystems/persistence.md +388 -0
  134. package/kb/site/en/reference/subsystems/plan.md +90 -0
  135. package/kb/site/en/reference/subsystems/sandbox.md +221 -0
  136. package/kb/site/en/reference/subsystems/schedule.md +189 -0
  137. package/kb/site/en/reference/subsystems/scope.md +62 -0
  138. package/kb/site/en/reference/subsystems/session-projection.md +265 -0
  139. package/kb/site/en/reference/subsystems/session-query.md +498 -0
  140. package/kb/site/en/reference/subsystems/session-reference.md +111 -0
  141. package/kb/site/en/reference/subsystems/session-telemetry.md +197 -0
  142. package/kb/site/en/reference/subsystems/session-title.md +207 -0
  143. package/kb/site/en/reference/subsystems/session.md +852 -0
  144. package/kb/site/en/reference/subsystems/settings.md +313 -0
  145. package/kb/site/en/reference/subsystems/shell.md +306 -0
  146. package/kb/site/en/reference/subsystems/skills.md +334 -0
  147. package/kb/site/en/reference/subsystems/spill.md +120 -0
  148. package/kb/site/en/reference/subsystems/storage.md +232 -0
  149. package/kb/site/en/reference/subsystems/subagent.md +737 -0
  150. package/kb/site/en/reference/subsystems/subprocess.md +327 -0
  151. package/kb/site/en/reference/subsystems/system-prompt.md +210 -0
  152. package/kb/site/en/reference/subsystems/terminal.md +187 -0
  153. package/kb/site/en/reference/subsystems/token-meter.md +93 -0
  154. package/kb/site/en/reference/subsystems/tools.md +723 -0
  155. package/kb/site/en/reference/subsystems/typert.md +339 -0
  156. package/kb/site/en/reference/subsystems/user-questions.md +181 -0
  157. package/kb/site/en/reference/subsystems/web-server.md +111 -0
  158. package/kb/site/en/reference/subsystems/web.md +202 -0
  159. package/kb/site/en/reference/subsystems/workflow.md +281 -0
  160. package/kb/site/en/reference/subsystems/workspace.md +231 -0
  161. package/kb/site/en/reference/tool-catalog.md +1877 -0
  162. package/kb/site/en/reference/tool-execution-pipeline.md +66 -0
  163. package/kb/site/guide/providers-custom-form.zh.png +0 -0
  164. package/kb/site/guide/providers-models-page.zh.png +0 -0
  165. package/kb/site/guide/providers.md +100 -0
  166. package/kb/site/guide/python-sdk.md +106 -0
  167. package/kb/site/guide/quickstart.md +32 -0
  168. package/kb/site/index.md +8 -0
  169. package/kb/site/reference/agent-lifecycle.md +86 -0
  170. package/kb/site/reference/capability-seams.md +475 -0
  171. package/kb/site/reference/config-catalog.md +3154 -0
  172. package/kb/site/reference/cookbook/adding-a-conversation-node.md +235 -0
  173. package/kb/site/reference/cookbook/adding-a-package.md +120 -0
  174. package/kb/site/reference/cookbook/adding-a-settings-card.md +102 -0
  175. package/kb/site/reference/cookbook/adding-a-tool.md +98 -0
  176. package/kb/site/reference/cookbook/adding-an-llm-adapter.md +45 -0
  177. package/kb/site/reference/cookbook/extension-cookbook.md +133 -0
  178. package/kb/site/reference/cordis-api/context.md +368 -0
  179. package/kb/site/reference/cordis-api/events.md +211 -0
  180. package/kb/site/reference/cordis-api/fiber.md +379 -0
  181. package/kb/site/reference/cordis-api/inherited.md +43 -0
  182. package/kb/site/reference/cordis-api/registry.md +156 -0
  183. package/kb/site/reference/cordis-api/service.md +106 -0
  184. package/kb/site/reference/cordis-primer.md +52 -0
  185. package/kb/site/reference/index.md +135 -0
  186. package/kb/site/reference/persistence-catalog.md +949 -0
  187. package/kb/site/reference/subsystems/approval.md +173 -0
  188. package/kb/site/reference/subsystems/client-modules.md +121 -0
  189. package/kb/site/reference/subsystems/code-runtime.md +194 -0
  190. package/kb/site/reference/subsystems/commands.md +190 -0
  191. package/kb/site/reference/subsystems/compaction.md +241 -0
  192. package/kb/site/reference/subsystems/core.md +1081 -0
  193. package/kb/site/reference/subsystems/credentials.md +136 -0
  194. package/kb/site/reference/subsystems/filesystem.md +498 -0
  195. package/kb/site/reference/subsystems/goal.md +280 -0
  196. package/kb/site/reference/subsystems/index.md +58 -0
  197. package/kb/site/reference/subsystems/invariants.md +91 -0
  198. package/kb/site/reference/subsystems/jobs.md +293 -0
  199. package/kb/site/reference/subsystems/llm-streaming.md +926 -0
  200. package/kb/site/reference/subsystems/lsp.md +205 -0
  201. package/kb/site/reference/subsystems/permission-presets.md +134 -0
  202. package/kb/site/reference/subsystems/persistence.md +388 -0
  203. package/kb/site/reference/subsystems/plan.md +90 -0
  204. package/kb/site/reference/subsystems/sandbox.md +221 -0
  205. package/kb/site/reference/subsystems/schedule.md +189 -0
  206. package/kb/site/reference/subsystems/scope.md +62 -0
  207. package/kb/site/reference/subsystems/session-projection.md +265 -0
  208. package/kb/site/reference/subsystems/session-query.md +498 -0
  209. package/kb/site/reference/subsystems/session-reference.md +111 -0
  210. package/kb/site/reference/subsystems/session-telemetry.md +197 -0
  211. package/kb/site/reference/subsystems/session-title.md +207 -0
  212. package/kb/site/reference/subsystems/session.md +854 -0
  213. package/kb/site/reference/subsystems/settings.md +313 -0
  214. package/kb/site/reference/subsystems/shell.md +306 -0
  215. package/kb/site/reference/subsystems/skills.md +334 -0
  216. package/kb/site/reference/subsystems/spill.md +120 -0
  217. package/kb/site/reference/subsystems/storage.md +232 -0
  218. package/kb/site/reference/subsystems/subagent.md +739 -0
  219. package/kb/site/reference/subsystems/subprocess.md +327 -0
  220. package/kb/site/reference/subsystems/system-prompt.md +210 -0
  221. package/kb/site/reference/subsystems/terminal.md +187 -0
  222. package/kb/site/reference/subsystems/token-meter.md +93 -0
  223. package/kb/site/reference/subsystems/tools.md +723 -0
  224. package/kb/site/reference/subsystems/typert.md +339 -0
  225. package/kb/site/reference/subsystems/user-questions.md +181 -0
  226. package/kb/site/reference/subsystems/web-server.md +111 -0
  227. package/kb/site/reference/subsystems/web.md +202 -0
  228. package/kb/site/reference/subsystems/workflow.md +281 -0
  229. package/kb/site/reference/subsystems/workspace.md +231 -0
  230. package/kb/site/reference/tool-catalog.md +1880 -0
  231. package/kb/site/reference/tool-execution-pipeline.md +66 -0
  232. package/package.json +40 -0
  233. package/scripts/rebuild-index.mjs +88 -0
  234. package/skills/dsh-plugin-dev-kb.md +66 -0
@@ -0,0 +1,334 @@
1
+ ---
2
+ editSource: "docs/subsystems/skills.md"
3
+ outline: [2,3]
4
+ ---
5
+
6
+ # Skills
7
+
8
+ The [skill capability family](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/skill) includes the Service Definition ([dsh-skill](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/skill/skill), `ctx.skills`), the local Service Provider ([dsh-skill-filesystem](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/skill/skill-filesystem)), the optional packaged badge provider ([dsh-skill-badge](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/skill/skill-badge)), and the Consumer ([dsh-tool-skill](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/skill/tool-skill)). The registry merges provider catalogs across its host and per-scope layers; providers contribute local or packaged skills; the Consumer owns the initial and replacement catalogs plus the model-facing `skill` tool. Skills are optional instructions, not session events, so their vocabulary lives here rather than in [core.md](./core.md).
9
+
10
+ Source: [`packages/skill/skill/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/skill/skill/src/index.ts), [`packages/skill/skill-filesystem/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/skill/skill-filesystem/src/index.ts), [`packages/skill/skill-badge/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/skill/skill-badge/src/index.ts), and [`packages/skill/tool-skill/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/skill/tool-skill/src/index.ts).
11
+
12
+ ## Provider registry
13
+
14
+ `ctx.skills` combines local, embedded, remote, or other providers. Registration is synchronous; remote initialization and discovery belong in awaited `list()`. Provider objects, options, and candidates are borrowed readonly, while semantic fields are validated.
15
+
16
+ The registry is host+per-scope layered, the shape the [tools registry](./tools.md) established over [dsh-scope](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/core/scope): a registration files into the layer of its calling context's scope, so host rows and repository plugins land in the global layer while a plugin mounted by an agent preset's standing composition lands in that preset's layer, and provider names are unique per layer rather than process-wide. A read merges the global layer with the viewing scope's chain — the nearest layer's entry wins a duplicate skill name outright, and the rank order below decides duplicates only within one layer. Discovery caches are keyed by the resolved scope chain, so re-parenting a scope (a blank-session recompose) is visible to the next read without a registry mutation.
17
+
18
+ Within one layer, duplicate names resolve by rank, provider order, then local order; summaries sort by name. A rejected `list()` is logged and omitted from an incomplete observation, while an explicit incomplete observation contributes usable candidates without making the result cacheable; malformed candidates fail fast. Each provider factory receives a registration-scoped control whose `invalidate()` clears completed catalogs only while that exact registration remains active and whose signal aborts on failed registration or disposal. An in-flight discovery retries once when its provider generation changes; a second change returns the latest candidates incomplete and uncached. Provider and runtime mutations emit the unfiltered `skills/change` invalidation event; it carries no diff, so consumers refetch `snapshot()` with their own lookup options.
19
+
20
+ An array returned by `SkillProvider.list()` is complete-discovery shorthand. `SkillProviderObservation` lets a provider expose candidates that remain directly loadable while reporting that the observation is not authoritative.
21
+
22
+ ```ts type-equiv
23
+ /** Provider candidates plus whether the current discovery is authoritative. */
24
+ interface SkillProviderObservation {
25
+ /** Candidates available from the current provider discovery. */
26
+ readonly candidates: readonly SkillCandidate[]
27
+ /** Whether discovery completed and these candidates may be cached. */
28
+ readonly complete: boolean
29
+ }
30
+ ```
31
+
32
+ ```ts type-equiv
33
+ /** Provider interface for one source of skills, such as local directories or a remote registry. */
34
+ interface SkillProvider {
35
+ /** Unique provider name in the `ctx.skills` registry. */
36
+ readonly name: string
37
+ /**
38
+ * List available skill candidates for the current lookup context. Provider
39
+ * plugins register synchronously during `apply()`; remote initialization,
40
+ * authentication, and discovery are awaited inside this method. Implementations
41
+ * should settle promptly when `options.signal` aborts.
42
+ * @param options - lookup options; `cwd` selects workspace-sensitive skills and `signal` cancels work.
43
+ * @returns provider candidates as a complete-array shorthand, or an explicit
44
+ * observation when usable candidates came from incomplete discovery.
45
+ */
46
+ readonly list: (options: SkillLookupOptions) => Promise<readonly SkillCandidate[] | SkillProviderObservation>
47
+ /**
48
+ * Load a complete skill body for a previously listed candidate.
49
+ * @param candidate - the winning candidate originally returned by this provider.
50
+ * @param options - lookup options; `cwd` selects workspace-sensitive skills and `signal` cancels work.
51
+ * @returns the full skill body, or `undefined` if it is no longer loadable.
52
+ */
53
+ readonly get: (candidate: SkillCandidate, options: SkillLookupOptions) => Promise<SkillDefinition | undefined>
54
+ }
55
+ ```
56
+
57
+ ```ts type-equiv
58
+ /** Registration-scoped lifecycle and invalidation capability borrowed by one provider. */
59
+ interface SkillProviderControl {
60
+ /** Aborts if registration fails or when the exact provider registration is disposed. */
61
+ readonly signal: AbortSignal
62
+ /** Invalidate completed catalogs and notify consumers only while the exact registration remains active. */
63
+ readonly invalidate: () => void
64
+ }
65
+ ```
66
+
67
+ ## Local discovery priority
68
+
69
+ The shipped local provider scans roots in rank order:
70
+
71
+ | Rank | Source | Root |
72
+ |---|---|---|
73
+ | 100 | `project-dsh` | `<projectRoot>/.dsh/skills` |
74
+ | 200 | `project-agents` | `<projectRoot>/.agents/skills` |
75
+ | 300 | `custom` | `Config.customSkillDirs` |
76
+ | 400 | `user-dsh` | `<dshHome>/skills` |
77
+ | 500 | `user-agents` | `<agentsHome>/skills` |
78
+ | 600 | `bundled` | `Config.bundledSkillDir` when configured |
79
+
80
+ 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
+
82
+ `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.
83
+
84
+ Chokidar watches existing roots for direct bundle/flat-entry additions and removals plus direct skill-entry changes. A missing root is followed one absent path segment at a time from its nearest existing ancestor until Chokidar can attach. Resource files below a bundle are not catalog changes. Model-facing `write` and `edit` observations synchronously invalidate the provider when their target is catalog-relevant, while the host watcher covers IDE, Git, shell, and external-process mutations. Watcher failures make the current observation incomplete without hiding readable candidates from direct loads; project-scoped watchers use a configured bounded LRU.
85
+
86
+ ## Skill identity
87
+
88
+ Skill names are kebab-case (`^[a-z0-9]+(?:-[a-z0-9]+)*$`). The local provider accepts directory bundles (`<name>/SKILL.md`) and flat Markdown files (`<name>.md`). Nested recursive `**/SKILL.md` discovery is not supported.
89
+
90
+ ```ts type-equiv
91
+ /** Origin bucket for a skill contribution. The value is prompt-visible metadata, not precedence by itself. */
92
+ type SkillSource = 'project-dsh' | 'project-agents' | 'runtime' | 'user-dsh' | 'user-agents' | 'custom' | 'bundled' | (string & {})
93
+ ```
94
+
95
+ ## Summaries, candidates, and complete definitions
96
+
97
+ `SkillSummary` is the registry's invocation-neutral summary shape. Consumers choose which entries and fields to render; the model session catalog uses only model-invocable `name` and `description`, never the body or absolute file path. `SkillInvocationPolicy` normalizes the two independent invocation controls into positive booleans, and every resolved summary, candidate, and definition carries it without turning arbitrary frontmatter into the domain model.
98
+
99
+ ```ts type-equiv
100
+ /** Invocation controls shared by skill discovery consumers. */
101
+ interface SkillInvocationPolicy {
102
+ /** Whether model-facing catalogs and loaders include this skill. */
103
+ readonly modelInvocable: boolean
104
+ /** Whether human-facing command catalogs and loaders include this skill. */
105
+ readonly userInvocable: boolean
106
+ }
107
+ ```
108
+
109
+ ```ts type-equiv
110
+ /** Invocation-neutral skill metadata returned by `ctx.skills.list()`. */
111
+ interface SkillSummary {
112
+ /** Kebab-case identifier used to address the skill. */
113
+ readonly name: string
114
+ /** Short routing description shown by discovery consumers. */
115
+ readonly description: string
116
+ /** Optional extra routing guidance. */
117
+ readonly whenToUse?: string
118
+ /** Resolved model and user invocation controls. */
119
+ readonly invocation: SkillInvocationPolicy
120
+ /** Discovery source that produced this winning skill. */
121
+ readonly source: SkillSource
122
+ /** Provider that owns this skill body. */
123
+ readonly provider: string
124
+ /** Provider-specific base for relative resources. */
125
+ readonly resourceBase?: SkillResourceBase
126
+ }
127
+ ```
128
+
129
+ `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.
130
+
131
+ `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.
132
+
133
+ ```ts type-equiv
134
+ /** One catalog observation plus whether discovery completed within a stable catalog revision. */
135
+ interface SkillCatalogSnapshot {
136
+ /** Sorted invocation-neutral summaries collected in this observation. */
137
+ readonly skills: SkillSummary[]
138
+ /** Whether every registered provider completed without a concurrent catalog revision. */
139
+ readonly complete: boolean
140
+ }
141
+ ```
142
+
143
+ `SkillCandidate` is the provider-to-registry shape. `locator` is opaque provider state; the registry only stores it and gives it back to the winning provider's `get()`.
144
+
145
+ ```ts type-equiv
146
+ /** Provider catalog entry used by the registry to merge and later load skills. */
147
+ interface SkillCandidate extends SkillSummary {
148
+ /** Lower ranks win duplicate skill names before provider registration order is considered. */
149
+ readonly rank: number
150
+ /** Opaque provider-owned handle passed back to `provider.get()`. */
151
+ readonly locator: unknown
152
+ /** Absolute file path when the provider has one. */
153
+ readonly path?: string
154
+ /** Parsed optional metadata object from provider-specific skill frontmatter. */
155
+ readonly metadata?: Readonly<Record<string, unknown>>
156
+ }
157
+ ```
158
+
159
+ `SkillDefinition` is the complete parsed result returned by `ctx.skills.get()` and used by the `skill` tool. `resourceBase` tells the tool how to render relative-resource guidance for local, URL, or provider-managed skills.
160
+
161
+ ```ts type-equiv
162
+ /** Optional provider-specific base used by loaded skill bodies to resolve relative resources. */
163
+ type SkillResourceBase =
164
+ | { readonly kind: 'directory'; readonly path: string }
165
+ | { readonly kind: 'url'; readonly url: string }
166
+ | { readonly kind: 'opaque'; readonly description: string }
167
+ ```
168
+
169
+ ```ts type-equiv
170
+ /** Complete parsed skill definition, including the body loaded by `ctx.skills.get()`. */
171
+ interface SkillDefinition extends SkillSummary {
172
+ /** Markdown instruction body after any provider-specific metadata removal. */
173
+ readonly content: string
174
+ /** Absolute file path when the skill came from disk. */
175
+ readonly path?: string
176
+ /** Parsed optional metadata object from frontmatter. */
177
+ readonly metadata?: Readonly<Record<string, unknown>>
178
+ }
179
+ ```
180
+
181
+ Runtime skill inputs may omit invocation controls and the provider label. The registry resolves both defaults once, then uses the same complete definition shape and first-wins collection order as providers. The returned disposer removes the contribution and invalidates discovery caches.
182
+
183
+ ```ts type-equiv
184
+ /** Runtime skill contribution accepted by `ctx.skills.register()`. */
185
+ type SkillRegistration = Omit<SkillDefinition, 'invocation' | 'provider'> & {
186
+ /** Invocation controls; omission permits both model and user surfaces. */
187
+ readonly invocation?: SkillInvocationPolicy
188
+ /** Provider label; omission uses the registry-owned runtime provider. */
189
+ readonly provider?: string
190
+ }
191
+ ```
192
+
193
+ ## Lookup and configuration
194
+
195
+ Skill lookup is cwd-sensitive because providers may expose workspace-local skills, and its optional signal cancels provider work for the caller. Registry reads additionally take the viewing scope — consumers pass the calling agent, which is its own scope key — through `SkillViewOptions`; the registry consumes `scope` for layer selection, and providers read only their `SkillLookupOptions` contract from the same borrowed options object. Cancellation is checked before and after catalog selection, including cache hits, and races both discovery and full-definition loading. If no git root is found, the local provider treats the supplied cwd itself as the project root.
196
+
197
+ Full definitions are not cached by the registry. Each `get()` calls the winning provider with the selected candidate, so the local provider rereads the current body. A definition whose name no longer matches that candidate is rejected and invalidates the exact provider for rediscovery.
198
+
199
+ ```ts type-equiv
200
+ /** Caller context used for cwd-sensitive and abortable provider work. */
201
+ interface SkillLookupOptions {
202
+ /** Workspace selector for the current lookup. */
203
+ readonly cwd?: string | undefined
204
+ /** Abort discovery or loading work for the current caller. */
205
+ readonly signal?: AbortSignal | undefined
206
+ }
207
+ ```
208
+
209
+ ```ts type-equiv
210
+ /**
211
+ * Registry read options: provider lookup context plus the viewing scope.
212
+ * The registry consumes `scope` to select layers; providers receive the same
213
+ * borrowed options object and read only their {@link SkillLookupOptions}
214
+ * contract from it.
215
+ */
216
+ interface SkillViewOptions extends SkillLookupOptions {
217
+ /** Viewing scope (the calling agent); omitted reads the global layer alone. */
218
+ readonly scope?: ScopeKey | undefined
219
+ }
220
+ ```
221
+
222
+ The registry owns only its discovery-cache bound. The local provider owns filesystem roots (`dshHome`, `agentsHome`, `customSkillDirs`, and optional `bundledSkillDir`/`DSH_BUNDLED_SKILL_DIR`) plus watcher enablement, polling, stability, symlink, and project-capacity controls. The consumer owns its catalog description bound. Exact defaults and validation are in the generated [config catalog](../config-catalog.md).
223
+
224
+ ```ts type-equiv
225
+ /** Skill registry configuration. */
226
+ interface Config {
227
+ /** Maximum number of completed cwd/provider catalogs kept in memory. */
228
+ readonly collectCacheMaxEntries?: number
229
+ }
230
+ ```
231
+
232
+ ## Session catalog and tool contract
233
+
234
+ `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`.
235
+
236
+ 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.
237
+
238
+ 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.
239
+
240
+ <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
241
+
242
+ <a id="cordis-surface"></a>
243
+
244
+ ## Cordis API
245
+
246
+ Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — this section is byte-identical in both language sides of the page. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
247
+
248
+ <a id="ctxskills--skillregistry"></a>
249
+
250
+ ### `ctx.skills` — `SkillRegistry`
251
+
252
+ Layered registry of skill providers, the host+per-scope shape the tools registry established. A registration files into the layer of its calling context's scope (scopeOf): host rows and repository plugins land in the global layer, while a plugin mounted by an agent preset's standing composition lands in that preset's layer. A read merges the global layer with the viewing scope's chain — the nearest layer's entry wins a duplicate name outright, and the rank order decides duplicates only within one layer. It exposes sorted invocation-neutral summaries and loads full skill bodies on demand.
253
+
254
+ ```ts cordis-catalog
255
+ /**
256
+ * Register a borrowed same-process provider synchronously during plugin
257
+ * apply, into the calling context's layer: a scoped context (an agent
258
+ * preset's standing mount) registers for that scope alone, an unscoped
259
+ * context registers globally. Duplicate names within one layer and reserved
260
+ * names throw; remote initialization belongs in `list()`. Fiber disposal
261
+ * unregisters the provider and invalidates catalog caches.
262
+ * @param create - synchronous factory receiving this registration's lifecycle and invalidation control.
263
+ * @returns the exact Cordis effect disposer that unregisters this provider;
264
+ * composite effects may yield it directly to preserve teardown ordering.
265
+ */
266
+ registerProvider(create: (control: SkillProviderControl) => SkillProvider): () => void
267
+
268
+ /**
269
+ * Register a borrowed readonly runtime skill into the calling context's
270
+ * layer. Project entries outrank runtime entries, which outrank user
271
+ * entries, within one layer. Same-name runtime entries in one layer are
272
+ * first-wins; a duplicate logs a warning and receives a no-op disposer so
273
+ * it cannot remove the winner.
274
+ * @param skill - the skill definition input; omitted invocation and provider fields receive defaults.
275
+ * @returns the exact Cordis effect disposer, preserving composite teardown order and invalidating caches.
276
+ */
277
+ register(skill: SkillRegistration): () => void
278
+
279
+ /**
280
+ * List invocation-neutral skill summaries for a workspace. Consumers apply
281
+ * model or user invocation policy at their operational boundary. Lookup
282
+ * options and provider candidates are readonly same-process values borrowed
283
+ * throughout discovery.
284
+ * @param options - view options; `scope` selects the viewing agent's layers, `cwd` selects project roots, and `signal` cancels discovery.
285
+ * @returns all sorted winning summaries.
286
+ */
287
+ async list(options: SkillViewOptions = {}): Promise<SkillSummary[]>
288
+
289
+ /**
290
+ * Observe the current invocation-neutral catalog and whether discovery completed within a stable revision.
291
+ * Incomplete observations are never cached, allowing consumers to retain last-good state and
292
+ * retry on their next request boundary.
293
+ * @param options - view options; `scope` selects the viewing agent's layers, `cwd` selects project roots, and `signal` cancels discovery.
294
+ * @returns sorted summaries plus discovery-completeness state.
295
+ */
296
+ async snapshot(options: SkillViewOptions = {}): Promise<SkillCatalogSnapshot>
297
+
298
+ /**
299
+ * Load and validate the winning candidate, passing its opaque discovery locator back to the
300
+ * provider. Cancellation is rechecked after selection, including cache hits, and raced against
301
+ * loading so an uncooperative provider cannot hang the caller.
302
+ * @param name - kebab-case skill name.
303
+ * @param options - view options; `scope` selects the viewing agent's layers,
304
+ * `cwd` selects workspace-sensitive skills, and `signal` cancels work.
305
+ * @returns the full skill, including body content, or `undefined`.
306
+ */
307
+ async get(name: string, options: SkillViewOptions = {}): Promise<SkillDefinition | undefined>
308
+ ```
309
+
310
+ Source: [`packages/skill/skill/src/index.ts:357`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/skill/skill/src/index.ts)
311
+
312
+ <a id="skills-events"></a>
313
+
314
+ ### `skills/*` events
315
+
316
+ <a id="skillschange--emit"></a>
317
+
318
+ #### `skills/change` — emit
319
+
320
+ A skill provider, runtime contribution, or provider-backed catalog may have changed. This is an unfiltered invalidation notification; consumers refetch the catalog for their own lookup options. Listener failures are contained and cannot veto the registry mutation.
321
+
322
+ ```ts cordis-catalog
323
+ /**
324
+ * A skill provider, runtime contribution, or provider-backed catalog may
325
+ * have changed. This is an unfiltered invalidation notification; consumers
326
+ * refetch the catalog for their own lookup options. Listener failures are
327
+ * contained and cannot veto the registry mutation.
328
+ * @mode emit
329
+ */
330
+ 'skills/change'(): void
331
+ ```
332
+
333
+ Source: [`packages/skill/skill/src/index.ts:297`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/skill/skill/src/index.ts)
334
+ <!-- END GENERATED cordis-surface -->
@@ -0,0 +1,120 @@
1
+ ---
2
+ editSource: "docs/subsystems/spill.md"
3
+ outline: [2,3]
4
+ ---
5
+
6
+ # Spill Storage
7
+
8
+ The spill storage seam — a [capability seam](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-07-08-tool-output-spill-files.md) that persists a tool's oversized text and returns a model-facing locator plus retrieval guidance, split across packages: Service Definition ([dsh-spill](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/spill/spill), `ctx.spillStore`), Service Provider ([dsh-spill-local](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/spill/spill-local), private session-scoped files on the host filesystem), and Consumer ([dsh-spill-policy](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/spill/spill-policy), the `tools/post-execute` policy). Spill is **one optional capability**, not part of the agent-loop spine — so its vocabulary lives here, not in [core.md](./core.md). Preview mechanics stay in [dsh-output-retention](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/util/output-retention); this seam only saves the final text the policy hands it.
9
+
10
+ Source: [`packages/spill/spill/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/spill/spill/src/types.ts)
11
+
12
+ ## The save request
13
+
14
+ `saveText` is the sole service operation: persist `content` verbatim, return an opaque locator, a backend-supplied retrieval hint, and the exact byte count. The request carries the save-time storage namespace (`owner`), the tool and call that produced it (`source`, used for naming and inspection — not access control), and a `suggestedName` the backend may use as a naming hint (it is not a path).
15
+
16
+ ```ts type-equiv
17
+ /** One request to persist text to a spill artifact. */
18
+ interface SaveTextSpill {
19
+ owner: SpillOwner
20
+ source: SpillSource
21
+ /**
22
+ * A caller-suggested base name (e.g. `web_fetch.txt`). The backend sanitizes
23
+ * it to a single safe path segment before use — it is a hint, never a path.
24
+ */
25
+ suggestedName: string
26
+ /** The full text to persist (UTF-8). */
27
+ content: string
28
+ }
29
+ ```
30
+
31
+ ```ts type-equiv
32
+ /**
33
+ * Save-time storage namespace for a spilled artifact. The session id lets a
34
+ * backend group storage under the producing session, but the returned
35
+ * {@link SpillLocator} is the model-facing handle. Forked sessions inherit
36
+ * locators already present in the seeded log; those artifacts are not copied or
37
+ * re-owned, and spills produced after the fork use the child session id.
38
+ */
39
+ interface SpillOwner {
40
+ sessionId: SessionId
41
+ }
42
+ ```
43
+
44
+ `SpillOwner.sessionId` is the save-time storage namespace. Forked sessions inherit existing spill locators from the seeded log; those artifacts are not copied or re-owned, and spills produced after the fork use the child session id. A retention-period cleanup may expire old locators with other old session artifacts; the spill seam does not define a per-session cleanup policy.
45
+
46
+ ```ts type-equiv
47
+ /**
48
+ * Tool and call that produced one spilled artifact — recorded by the backend for a readable
49
+ * filename and inspection. Not interpreted for access control; purely
50
+ * descriptive.
51
+ */
52
+ interface SpillSource {
53
+ /** The tool whose result was spilled (e.g. `web_fetch`). */
54
+ toolName: string
55
+ /** The model-issued call id the result belongs to. */
56
+ callId: CallId
57
+ /** A short human label for the artifact (e.g. `result`). */
58
+ label: string
59
+ }
60
+ ```
61
+
62
+ ## The result
63
+
64
+ ```ts type-equiv
65
+ /** A saved spill artifact: its locator, byte length, and backend-specific retrieval guidance. */
66
+ interface SpillRef {
67
+ locator: SpillLocator
68
+ bytes: number
69
+ retrievalHint: string
70
+ }
71
+ ```
72
+
73
+ `SpillLocator` is a [branded](./core.md#branded-ids) model-facing handle returned by the backend. The local backend renders it as a filesystem path; a remote or database backend can render a URI, key, or command token. Consumers treat it as opaque and render it with `retrievalHint` instead of assuming `read` is always the right retrieval mechanism.
74
+
75
+ ```ts type-equiv
76
+ /**
77
+ * Opaque model-facing handle for one spilled artifact. A local backend may use a
78
+ * filesystem path; a remote or database backend may use a URI or key. Consumers
79
+ * render it with {@link SpillRef.retrievalHint}, but do not parse it.
80
+ */
81
+ type SpillLocator = Branded<'SpillLocator'>
82
+ ```
83
+
84
+ ## The service
85
+
86
+ `SpillStore` (`ctx.spillStore`, defined in [`packages/spill/spill/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/spill/spill/src/index.ts)) is a one-method abstract service: `saveText(input) → Promise<SpillRef>`. It persists the FULL `content` and REJECTS on a real storage failure (permissions, ENOSPC, backend unavailable). The seam owns storage only: no retention policy, no tool-result replacement, no retrieval/search API.
87
+
88
+ The local backend ([dsh-spill-local](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/spill/spill-local)) writes under `<root>/session-<hash>/<random>-<safeName>` — a configured or lazily-created private (0700) root, a `sha256(sessionId)` session subdir, and an exclusive owner-only (`open(path, 'wx', 0o600)`) write so a planted symlink cannot redirect it. Its `locator` is the local path and its `retrievalHint` tells the model to use `read` or `grep` on that path. The policy consumer ([dsh-spill-policy](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/spill/spill-policy)) replaces an over-`maxInlineBytes` plain-text final result with a retention-library head/tail preview plus the spill reference, best-effort: a save failure keeps the original inline result rather than turning a successful call into an `isError`.
89
+
90
+ <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
91
+
92
+ <a id="cordis-surface"></a>
93
+
94
+ ## Cordis API
95
+
96
+ Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — this section is byte-identical in both language sides of the page. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
97
+
98
+ <a id="ctxspillstore--spillstore-abstract-seam"></a>
99
+
100
+ ### `ctx.spillStore` — `SpillStore` (abstract seam)
101
+
102
+ Abstract spill storage service. Subclass, implement saveText, and load the subclass as a plugin — it registers as `ctx.spillStore` (one implementation per context; loading a second throws, cordis' standard duplicate-service behavior).
103
+
104
+ Semantics every implementation must honor:
105
+
106
+ - saveText persists the FULL `content` verbatim and returns an opaque locator, exact byte length, and model-facing retrieval guidance.
107
+ - Storage is scoped by the request's SaveTextSpill.owner session; the backend chooses a private (not world-readable) location and a collision-free name derived from — never equal to — the caller's `suggestedName`.
108
+ - `saveText` REJECTS on a real storage failure (permissions, ENOSPC, backend unavailable); the caller decides how to degrade (the spill policy treats a rejection as best-effort and keeps the inline result).
109
+
110
+ ```ts cordis-catalog
111
+ /**
112
+ * Persist `input.content` to a session-scoped spill artifact.
113
+ * @param input - the owner, caller-supplied source fields, suggested name, and full text to save.
114
+ * @returns the saved artifact's {@link SpillRef}; rejects on a storage failure.
115
+ */
116
+ abstract saveText(input: SaveTextSpill): Promise<SpillRef>
117
+ ```
118
+
119
+ Source: [`packages/spill/spill/src/index.ts:45`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/spill/spill/src/index.ts)
120
+ <!-- END GENERATED cordis-surface -->