dsh-plugin-dev-kb 1.0.8 → 1.1.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 (188) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.en.md +6 -6
  3. package/README.md +6 -6
  4. package/kb/INDEX.md +21 -5
  5. package/kb/README.md +11 -10
  6. package/kb/extra/AGENTS.md +4 -4
  7. package/kb/extra/cookbook/adding-a-remote-api.md +197 -0
  8. package/kb/extra/cookbook/adding-a-remote-api.zh.md +197 -0
  9. package/kb/extra/cookbook/adding-a-vendored-package.md +2 -2
  10. package/kb/extra/cookbook/adding-a-vendored-package.zh.md +2 -2
  11. package/kb/extra/deepseek-llm-api-wire-extensions.md +163 -0
  12. package/kb/extra/deepseek-llm-api-wire-extensions.zh.md +163 -0
  13. package/kb/extra/development.md +8 -14
  14. package/kb/extra/development.zh.md +8 -14
  15. package/kb/extra/event-producer-consumer.md +55 -48
  16. package/kb/extra/event-producer-consumer.zh.md +58 -51
  17. package/kb/extra/glossary.md +1 -1
  18. package/kb/extra/glossary.zh.md +1 -1
  19. package/kb/extra/graph-atlas.md +0 -2
  20. package/kb/extra/graph-atlas.zh.md +0 -2
  21. package/kb/extra/i18n/README.md +4 -4
  22. package/kb/extra/i18n/README.zh.md +4 -4
  23. package/kb/extra/i18n/style-samples.md +2 -2
  24. package/kb/extra/module-graph.md +646 -926
  25. package/kb/extra/module-graph.zh.md +648 -928
  26. package/kb/extra/postmortem/0001-acp-default-export-drops-inject.md +2 -2
  27. package/kb/extra/postmortem/0001-acp-default-export-drops-inject.zh.md +2 -2
  28. package/kb/extra/postmortem/0002-js-expression-disabled-filesystem-tools.md +2 -2
  29. package/kb/extra/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md +2 -2
  30. package/kb/extra/postmortem/0003-web-agent-gui-feedback-loop.md +2 -2
  31. package/kb/extra/postmortem/0003-web-agent-gui-feedback-loop.zh.md +2 -2
  32. package/kb/extra/postmortem/0004-landlock-partial-notice-misclassified-child-failures.md +1 -1
  33. package/kb/extra/postmortem/0004-landlock-partial-notice-misclassified-child-failures.zh.md +1 -1
  34. package/kb/extra/rescope.md +2 -2
  35. package/kb/extra/rescope.zh.md +2 -2
  36. package/kb/extra/subsystems/agent-team.md +28 -4
  37. package/kb/extra/subsystems/agent-team.zh.md +28 -4
  38. package/kb/extra/subsystems/attachment.md +168 -7
  39. package/kb/extra/subsystems/attachment.zh.md +168 -7
  40. package/kb/extra/subsystems/extensions.md +18 -0
  41. package/kb/extra/subsystems/extensions.zh.md +18 -0
  42. package/kb/extra/subsystems/feedback.md +4 -4
  43. package/kb/extra/subsystems/feedback.zh.md +4 -4
  44. package/kb/extra/subsystems/todo.md +32 -0
  45. package/kb/extra/subsystems/todo.zh.md +32 -0
  46. package/kb/extra/subsystems/webhook.md +70 -0
  47. package/kb/extra/subsystems/webhook.zh.md +70 -0
  48. package/kb/extra/testing.md +15 -10
  49. package/kb/extra/testing.zh.md +13 -8
  50. package/kb/extra/web-styling.md +4 -0
  51. package/kb/extra/web-styling.zh.md +4 -0
  52. package/kb/meta/search-index.json +309 -177
  53. package/kb/meta/site-pages.txt +183 -167
  54. package/kb/meta/source.json +5 -5
  55. package/kb/meta/topics.md +14 -6
  56. package/kb/site/develop/basic/publish.md +2 -2
  57. package/kb/site/develop/basic/tool.md +1 -1
  58. package/kb/site/develop/cordis-tutorial/07-into-the-harness.md +5 -4
  59. package/kb/site/develop/framework/events.md +1 -1
  60. package/kb/site/develop/practice/dynamic-cordis.md +17 -0
  61. package/kb/site/develop/practice/llm-adapter.md +4 -3
  62. package/kb/site/en/develop/basic/publish.md +2 -2
  63. package/kb/site/en/develop/basic/tool.md +1 -1
  64. package/kb/site/en/develop/cordis-tutorial/07-into-the-harness.md +5 -4
  65. package/kb/site/en/develop/framework/events.md +1 -1
  66. package/kb/site/en/develop/practice/dynamic-cordis.md +17 -0
  67. package/kb/site/en/develop/practice/llm-adapter.md +4 -3
  68. package/kb/site/en/guide/github-review.md +104 -0
  69. package/kb/site/en/guide/mcp-memory.md +103 -0
  70. package/kb/site/en/guide/network-proxy.md +87 -0
  71. package/kb/site/en/guide/providers.md +70 -17
  72. package/kb/site/en/guide/python-sdk.md +80 -34
  73. package/kb/site/en/guide/schedule.md +23 -0
  74. package/kb/site/en/reference/agent-lifecycle.md +6 -4
  75. package/kb/{extra → site/en/reference}/api-gateway.md +12 -10
  76. package/kb/site/en/reference/capability-seams.md +128 -73
  77. package/kb/site/en/reference/config-catalog.md +481 -360
  78. package/kb/site/en/reference/cookbook/adding-a-package.md +3 -4
  79. package/kb/site/en/reference/cookbook/adding-a-settings-card.md +12 -10
  80. package/kb/site/en/reference/cookbook/adding-a-tool.md +11 -4
  81. package/kb/site/en/reference/cookbook/adding-an-llm-adapter.md +1 -1
  82. package/kb/site/en/reference/cookbook/extension-cookbook.md +20 -17
  83. package/kb/site/en/reference/cordis-api/inherited.md +1 -1
  84. package/kb/site/en/reference/cordis-primer.md +2 -1
  85. package/kb/site/en/reference/index.md +30 -11
  86. package/kb/site/en/reference/persistence-catalog.md +148 -80
  87. package/kb/site/en/reference/subsystems/approval.md +10 -10
  88. package/kb/site/en/reference/subsystems/client-modules.md +58 -16
  89. package/kb/site/en/reference/subsystems/code-runtime.md +10 -6
  90. package/kb/site/en/reference/subsystems/commands.md +25 -16
  91. package/kb/site/en/reference/subsystems/compaction.md +11 -11
  92. package/kb/site/en/reference/{cookbook/adding-a-conversation-node.md → subsystems/conversation.md} +50 -24
  93. package/kb/site/en/reference/subsystems/core.md +156 -17
  94. package/kb/site/en/reference/subsystems/credentials.md +44 -3
  95. package/kb/site/en/reference/subsystems/filesystem.md +12 -2
  96. package/kb/site/en/reference/subsystems/goal.md +1 -1
  97. package/kb/site/en/reference/subsystems/index.md +7 -2
  98. package/kb/site/en/reference/subsystems/jobs.md +1 -1
  99. package/kb/site/en/reference/subsystems/llm-streaming.md +154 -12
  100. package/kb/site/en/reference/subsystems/permission-presets.md +6 -6
  101. package/kb/site/en/reference/subsystems/persistence.md +185 -175
  102. package/kb/site/en/reference/subsystems/plan.md +2 -2
  103. package/kb/site/en/reference/subsystems/sandbox.md +2 -0
  104. package/kb/site/en/reference/subsystems/schedule.md +9 -3
  105. package/kb/site/en/reference/subsystems/session-projection.md +115 -48
  106. package/kb/site/en/reference/subsystems/session-query.md +28 -14
  107. package/kb/site/en/reference/subsystems/session-reference.md +53 -8
  108. package/kb/site/en/reference/subsystems/session-telemetry.md +8 -8
  109. package/kb/site/en/reference/subsystems/session-title.md +6 -6
  110. package/kb/site/en/reference/subsystems/session.md +401 -99
  111. package/kb/site/en/reference/subsystems/settings.md +101 -6
  112. package/kb/site/en/reference/subsystems/skills.md +23 -0
  113. package/kb/site/en/reference/subsystems/slots.md +178 -0
  114. package/kb/site/en/reference/subsystems/spill.md +2 -2
  115. package/kb/site/en/reference/subsystems/storage.md +34 -3
  116. package/kb/site/en/reference/subsystems/subagent.md +122 -109
  117. package/kb/site/en/reference/subsystems/system-prompt.md +17 -4
  118. package/kb/site/en/reference/subsystems/token-meter.md +27 -12
  119. package/kb/site/en/reference/subsystems/tools.md +39 -39
  120. package/kb/site/en/reference/subsystems/typert.md +62 -55
  121. package/kb/site/en/reference/subsystems/user-questions.md +33 -33
  122. package/kb/site/en/reference/subsystems/web-client.md +98 -0
  123. package/kb/site/en/reference/subsystems/web-server.md +11 -5
  124. package/kb/site/en/reference/subsystems/web.md +7 -1
  125. package/kb/site/en/reference/subsystems/workspace.md +102 -9
  126. package/kb/site/en/reference/tool-catalog.md +86 -82
  127. package/kb/site/en/reference/tool-execution-pipeline.md +1 -1
  128. package/kb/site/guide/github-review.md +104 -0
  129. package/kb/site/guide/mcp-memory.md +103 -0
  130. package/kb/site/guide/network-proxy.md +87 -0
  131. package/kb/site/guide/providers.md +70 -17
  132. package/kb/site/guide/python-sdk.md +87 -41
  133. package/kb/site/guide/schedule.md +23 -0
  134. package/kb/site/reference/agent-lifecycle.md +6 -4
  135. package/kb/{extra/api-gateway.zh.md → site/reference/api-gateway.md} +12 -10
  136. package/kb/site/reference/capability-seams.md +128 -73
  137. package/kb/site/reference/config-catalog.md +481 -360
  138. package/kb/site/reference/cookbook/adding-a-package.md +3 -4
  139. package/kb/site/reference/cookbook/adding-a-settings-card.md +12 -10
  140. package/kb/site/reference/cookbook/adding-a-tool.md +11 -4
  141. package/kb/site/reference/cookbook/adding-an-llm-adapter.md +1 -1
  142. package/kb/site/reference/cookbook/extension-cookbook.md +20 -17
  143. package/kb/site/reference/cordis-api/inherited.md +1 -1
  144. package/kb/site/reference/cordis-primer.md +2 -1
  145. package/kb/site/reference/index.md +30 -11
  146. package/kb/site/reference/persistence-catalog.md +148 -80
  147. package/kb/site/reference/subsystems/approval.md +10 -10
  148. package/kb/site/reference/subsystems/client-modules.md +58 -16
  149. package/kb/site/reference/subsystems/code-runtime.md +10 -6
  150. package/kb/site/reference/subsystems/commands.md +25 -16
  151. package/kb/site/reference/subsystems/compaction.md +11 -11
  152. package/kb/site/reference/{cookbook/adding-a-conversation-node.md → subsystems/conversation.md} +50 -24
  153. package/kb/site/reference/subsystems/core.md +156 -17
  154. package/kb/site/reference/subsystems/credentials.md +44 -3
  155. package/kb/site/reference/subsystems/filesystem.md +12 -2
  156. package/kb/site/reference/subsystems/goal.md +1 -1
  157. package/kb/site/reference/subsystems/index.md +7 -2
  158. package/kb/site/reference/subsystems/jobs.md +1 -1
  159. package/kb/site/reference/subsystems/llm-streaming.md +154 -12
  160. package/kb/site/reference/subsystems/permission-presets.md +5 -5
  161. package/kb/site/reference/subsystems/persistence.md +184 -174
  162. package/kb/site/reference/subsystems/plan.md +2 -2
  163. package/kb/site/reference/subsystems/schedule.md +9 -3
  164. package/kb/site/reference/subsystems/session-projection.md +115 -48
  165. package/kb/site/reference/subsystems/session-query.md +28 -14
  166. package/kb/site/reference/subsystems/session-reference.md +53 -8
  167. package/kb/site/reference/subsystems/session-telemetry.md +8 -8
  168. package/kb/site/reference/subsystems/session-title.md +6 -6
  169. package/kb/site/reference/subsystems/session.md +401 -99
  170. package/kb/site/reference/subsystems/settings.md +101 -6
  171. package/kb/site/reference/subsystems/skills.md +23 -0
  172. package/kb/site/reference/subsystems/slots.md +178 -0
  173. package/kb/site/reference/subsystems/spill.md +2 -2
  174. package/kb/site/reference/subsystems/storage.md +34 -3
  175. package/kb/site/reference/subsystems/subagent.md +122 -109
  176. package/kb/site/reference/subsystems/system-prompt.md +17 -4
  177. package/kb/site/reference/subsystems/token-meter.md +27 -12
  178. package/kb/site/reference/subsystems/tools.md +39 -39
  179. package/kb/site/reference/subsystems/typert.md +62 -55
  180. package/kb/site/reference/subsystems/user-questions.md +33 -33
  181. package/kb/site/reference/subsystems/web-client.md +98 -0
  182. package/kb/site/reference/subsystems/web-server.md +11 -5
  183. package/kb/site/reference/subsystems/web.md +7 -1
  184. package/kb/site/reference/subsystems/workspace.md +102 -9
  185. package/kb/site/reference/tool-catalog.md +85 -81
  186. package/kb/site/reference/tool-execution-pipeline.md +1 -1
  187. package/package.json +2 -2
  188. package/skills/dsh-plugin-dev-kb.md +8 -6
@@ -127,13 +127,19 @@ A provider's `available(): boolean` is a cheap LOCAL check (credential presence,
127
127
 
128
128
  Selection never depends on registration, config, or HMR order: a capability has an explicit provider id (config `searchProvider`/`fetchProvider`, or the matching env var feeding the same field), or auto-selects when exactly one usable provider is registered; multiple usable providers with no configured id is `WEB_PROVIDER_AMBIGUOUS`, not first-wins.
129
129
 
130
+ ## Fetch network policy
131
+
132
+ The shipped Cordis, Code, and Standard presets expose `web_fetch` in every sandbox and approval mode without per-call confirmation. File sandbox presets do not govern Web network access. A deployment that needs confirmation must add a `tools/pre-execute` policy or disable fetch.
133
+
134
+ The HTTP provider resolves each actual request, rejects non-public answers including private IPv4 reached through the active DNS64 prefix, pins the validated address set, and repeats enforcement for each same-origin redirect. A cross-origin redirect requires a new tool call and fresh public-address validation. These checks prevent SSRF access to non-public destinations but do not stop a model from sending data to a public URL.
135
+
130
136
  ## Errors
131
137
 
132
138
  `WebError extends HarnessError` ([core.md](./core.md) error taxonomy) with a `code: string` (open, like every other seam's error — `LlmError`, `SubagentError`), not a closed union: a provider may raise its own codes without editing `dsh-web`, and consumers must tolerate an unknown code. The codes split by owner. Seam-neutral codes are raised by the shared `WebRuntime` contract: `WEB_PROVIDER_UNAVAILABLE`, `WEB_PROVIDER_CONFIGURED_MISSING`, `WEB_PROVIDER_CONFIGURED_UNAVAILABLE`, `WEB_PROVIDER_AMBIGUOUS`, `WEB_DUPLICATE_PROVIDER` (a registration-time programming error, the analogue of `LlmRuntime`'s `DUPLICATE_ADAPTER`), `WEB_ABORTED`, and `WEB_PROVIDER_ERROR` (the catch-all for a provider's own failure surfaced through the seam, including network/transport failure — DNS, connection refused, TLS). Fetch-transport codes are owned by the `dsh-web-fetch-http` implementation and a different fetch backend need not raise them: `WEB_INVALID_URL`, `WEB_BLOCKED_URL`, `WEB_REDIRECT_BLOCKED`, `WEB_FETCH_TOO_LARGE`, `WEB_FETCH_TIMEOUT`, `WEB_UNSUPPORTED_CONTENT_TYPE`.
133
139
 
134
140
  ## The service
135
141
 
136
- `WebRuntime` registers search and fetch providers, rejects duplicate ids with `WEB_DUPLICATE_PROVIDER`, and resolves providers at execution time with structured selection errors. The local fetch backend accepts only HTTP(S), rejects credentials, caps redirects, bytes, characters, and time, revalidates every same-origin redirect hop, and decodes the body; the tool owns presentation. The local backend does not block private-network targets; do not enable `web_fetch` where it can reach sensitive internal ones.
142
+ `WebRuntime` registers search and fetch providers, rejects duplicate ids with `WEB_DUPLICATE_PROVIDER`, and resolves providers at execution time with structured selection errors. The local fetch backend accepts only HTTP(S), rejects credentials, resolves each hostname once, rejects any answer set containing a non-public IPv4 or IPv6 destination or an active-prefix NAT64 translation to non-public IPv4, pins the request connection to the validated addresses, repeats those checks for every same-origin redirect hop, caps redirects, bytes, characters, and time, and decodes the body; the tool owns presentation.
137
143
 
138
144
  <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
139
145
 
@@ -43,7 +43,7 @@ interface Workspace {
43
43
  */
44
44
  readonly path: string
45
45
 
46
- /** Display title. Defaults to `basename(path)` at create; duplicates are allowed. */
46
+ /** Display title. Defaults to the final path segment, or a filesystem root's own spelling; duplicates are allowed. */
47
47
  readonly title: string
48
48
 
49
49
  /** ISO-8601 creation instant, stamped at create and never rewritten. */
@@ -120,13 +120,13 @@ Ownership truth is the record's ordered `sessionIds`, never derived from session
120
120
 
121
121
  ## The registry: `ctx.workspaceRegistry`
122
122
 
123
- `WorkspaceRegistry` ([signatures](#ctxworkspaceregistry--workspaceregistry)) owns registration and resolution. `create(path, title?)` canonicalizes the path, rejects a nonexistent path (the original `ENOENT`) or a non-directory, returns the existing entity unchanged when the canonical path is already owned, and otherwise creates a record with `title ?? basename(path)` prepended to the durable registry order a new record cannot duplicate an existing display title (`WorkspaceNameConflictError`). `get(id)` and the ordered `list()` are synchronous cache reads; `resolveByPath(path)` applies the same realpath canon without creating. `delete(id)` removes only the registration, order entry, and session account — the directory, user files, live sessions, and persisted logs are never touched, so those sessions become Ungrouped ([decision](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-07-27-workspace-registration-deletion.md)); unknown ids return `false`. Create and delete persist a pending-mutation marker before their two writes (record + order) can diverge; startup resolves exactly the marked mutation — by deleting the marked table row, which completes an interrupted delete and rolls back an interrupted create (the registration is re-creatable, so rollback is the safe direction) — and an unmarked order/table mismatch fails loud as corruption.
123
+ `WorkspaceRegistry` ([signatures](#ctxworkspaceregistry--workspaceregistry)) owns registration and resolution. `create(path, title?)` requires a fully qualified path, canonicalizes it, rejects a nonexistent path (the original `ENOENT`) or a non-directory, returns the existing entity unchanged when the canonical path is already owned, and otherwise creates a record with `title ?? defaultWorkspaceTitle(path)` prepended to the durable registry order (different canonical paths may share a display title, and a path with no final segment uses its root spelling). `get(id)` and the ordered `list()` are synchronous cache reads; `resolveByPath(path)` applies the same fully qualified realpath canon without creating. `delete(id)` removes only the registration, order entry, and session account — the directory, user files, live sessions, and persisted logs are never touched, so those sessions become Ungrouped ([decision](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/feature/2026-07-27-workspace-registration-deletion.md)); unknown ids return `false`. Create and delete persist a pending-mutation marker before their two writes (record + order) can diverge; startup resolves exactly the marked mutation — by deleting the marked table row, which completes an interrupted delete and rolls back an interrupted create (the registration is re-creatable, so rollback is the safe direction) — and an unmarked order/table mismatch fails loud as corruption.
124
124
 
125
125
  Sessions get their cwd at create time from whoever creates them, not from this registry — the API gateway resolves a new session's cwd from the chosen workspace's `path` (falling back to an explicit or default cwd), creates the session so the cwd lands in its immutable [`SessionHeader`](./persistence.md#sessionheader--metadata-beside-the-log), then calls `attachSession`, which re-validates that stored header cwd against the workspace path. On the first successful start, the registry bootstraps history from persisted headers alone (`id`, `cwd`, `createdAt` — never event bodies), grouping sessions with a valid canonical cwd into per-directory workspaces, newest first; the initialized marker is written last so an interrupted bootstrap resumes safely. The bootstrap is one-time: cwd-less legacy sessions stay Ungrouped, and sessions created afterwards join a workspace only through `attachSession`.
126
126
 
127
127
  ## Consumers
128
128
 
129
- [dsh-host-apiproxy](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/host/apiproxy) is the product consumer: it serves workspace CRUD to GUI clients over `ctx.workspaceRegistry` and performs the create-session-then-attach flow above. [dsh-agent-instructions](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/context/agent-instructions) is **not** a consumer despite the name: it discovers AGENTS.md-style instruction files under an agent's own cwd and never touches `ctx.workspaceRegistry` — the shared word refers to the user's working directory, not to this registry's entities.
129
+ [`dsh-workspace-controller`](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/api/workspace-controller) serves workspace CRUD to GUI clients over `ctx.workspaceRegistry`, and [`dsh-session-controller`](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/api/session-controller) performs the create-session-then-attach flow above. [dsh-agent-instructions](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/context/agent-instructions) is **not** a consumer despite the name: it discovers AGENTS.md-style instruction files under an agent's own cwd and never touches `ctx.workspaceRegistry` — the shared word refers to the user's working directory, not to this registry's entities.
130
130
 
131
131
  <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
132
132
 
@@ -152,6 +152,99 @@ abstract capability(): DirectoryPickerCapability
152
152
 
153
153
  Source: [`packages/host/directory-picker/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/host/directory-picker/src/index.ts)
154
154
 
155
+ <a id="ctxdirectorypickercontroller--directorypickercontroller"></a>
156
+
157
+ ### `ctx.directoryPickerController` — `DirectoryPickerController`
158
+
159
+ Host service backing the generated `ctx.remote.directoryPicker` namespace. The seam it exports is abstract and therefore never a Loader entry of its own, so this controller carries the wire verbs: one composed backend serves either the native chooser or the browse primitives, and a verb the composition cannot serve is refused rather than approximated.
160
+
161
+ ```ts cordis-catalog
162
+ /**
163
+ * Open the host's OS chooser for a Remote caller.
164
+ * @param signal - caller lifetime; abort terminates the chooser.
165
+ * @returns the chosen absolute path, or null when the operator cancels.
166
+ */
167
+ @Remote('pick') async pick(signal: AbortSignal): Promise<string | null>
168
+
169
+ /**
170
+ * List one directory level for a Remote caller's in-app browser.
171
+ * @param path - absolute directory to list; absent lists the home directory.
172
+ * @param signal - caller lifetime; abort stops the backend's scan instead of
173
+ * letting it outlive a disconnected caller.
174
+ * @returns the level's listing with its ancestry.
175
+ */
176
+ @Remote('list') async list(path: string | undefined, signal: AbortSignal): Promise<DirectoryListing>
177
+
178
+ /**
179
+ * Create one child directory for a Remote caller's in-app browser.
180
+ * @param path - absolute existing parent directory.
181
+ * @param name - single non-blank path segment.
182
+ * @returns the created directory's absolute path.
183
+ */
184
+ @Remote('createDirectory') async createDirectory(path: string, name: string): Promise<string>
185
+ ```
186
+
187
+ Source: [`packages/api/workspace-controller/src/directory-picker.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/api/workspace-controller/src/directory-picker.ts)
188
+
189
+ <a id="ctxworkspacecontroller--workspacecontroller"></a>
190
+
191
+ ### `ctx.workspaceController` — `WorkspaceController`
192
+
193
+ Host service backing the generated `ctx.remote.workspace` namespace.
194
+
195
+ ```ts cordis-catalog
196
+ /**
197
+ * Create or idempotently resolve one Workspace over an existing directory.
198
+ * @param request - directory path to register.
199
+ * @returns the Workspace and whether this call created it.
200
+ */
201
+ @Remote('create') create(request: WorkspaceCreateRequest): Promise<WorkspaceCreateValue>
202
+
203
+ /**
204
+ * Rename one Workspace to a unique non-blank title.
205
+ * @param request - Workspace identity and proposed title.
206
+ * @returns the updated Workspace projection.
207
+ */
208
+ @Remote('rename') rename(request: WorkspaceRenameRequest): Promise<WorkspaceValue>
209
+
210
+ /**
211
+ * Remove one Workspace registration while retaining files and Sessions.
212
+ * @param request - Workspace identity to remove.
213
+ * @returns deletion confirmation.
214
+ */
215
+ @Remote('delete') delete(request: WorkspaceDeleteRequest): Promise<WorkspaceDeleteValue>
216
+
217
+ /**
218
+ * Move one Workspace within the registry display order.
219
+ * @param request - moved Workspace and optional anchor.
220
+ * @returns the complete resulting Workspace order.
221
+ */
222
+ @Remote('insertBefore') insertBefore(request: WorkspaceInsertBeforeRequest): Promise<WorkspaceOrderValue>
223
+
224
+ /**
225
+ * Move one accounted Session within a Workspace.
226
+ * @param request - Workspace, Session, and optional anchor identities.
227
+ * @returns the updated Workspace projection.
228
+ */
229
+ @Remote('insertSessionBefore') insertSessionBefore(request: WorkspaceInsertSessionBeforeRequest): Promise<WorkspaceValue>
230
+
231
+ /**
232
+ * Hide one known Session from Workspace grouping surfaces.
233
+ * @param request - Session identity to archive.
234
+ * @returns the complete resulting archive set.
235
+ */
236
+ @Remote('archiveSession') archiveSession(request: WorkspaceArchiveSessionRequest): Promise<WorkspaceArchiveValue>
237
+
238
+ /**
239
+ * Stream a complete Workspace baseline followed by ordered increments.
240
+ * @param signal - generation cancellation.
241
+ * @returns baseline followed by ordered Workspace increments.
242
+ */
243
+ @Remote({ mode: 'stream' }) follow(signal: AbortSignal): AsyncIterable<WorkspaceFollowFrame>
244
+ ```
245
+
246
+ Source: [`packages/api/workspace-controller/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/api/workspace-controller/src/index.ts)
247
+
155
248
  <a id="ctxworkspaceregistry--workspaceregistry"></a>
156
249
 
157
250
  ### `ctx.workspaceRegistry` — `WorkspaceRegistry`
@@ -160,13 +253,13 @@ Durable workspace registry. Startup waits for `sessionPersistence`, builds one c
160
253
 
161
254
  ```ts cordis-catalog
162
255
  /**
163
- * Create or reuse a workspace for an existing directory. The path is
164
- * canonicalized through `fs.realpath`; a nonexistent path rejects with the
165
- * original error and a non-directory rejects. Repeated calls for the same
166
- * canonical path return the existing entity without changing its title.
256
+ * Create or reuse a workspace for an existing directory. The fully qualified
257
+ * path is canonicalized through `fs.realpath`; a relative, nonexistent, or
258
+ * non-directory path rejects. Repeated calls for the same canonical path
259
+ * return the existing entity without changing its title.
167
260
  * A newly created workspace is prepended to the durable registry order.
168
261
  * Different canonical paths may share a display title.
169
- * @param path - Existing directory to own, in any path spelling.
262
+ * @param path - Existing directory to own, in a fully qualified path spelling.
170
263
  * @param title - Display title used only when a new record is created.
171
264
  * @returns the existing or newly durable workspace.
172
265
  */
@@ -219,7 +312,7 @@ archiveSession(sessionId: SessionId): Promise<void>
219
312
  * Resolve by canonical directory path without creating or mutating a
220
313
  * workspace. A missing path rejects during `realpath`; an existing unowned
221
314
  * directory returns `undefined`.
222
- * @param path - Existing directory path in any spelling.
315
+ * @param path - Existing directory path in a fully qualified spelling.
223
316
  * @returns the workspace owning the canonical path, when one exists.
224
317
  */
225
318
  async resolveByPath(path: string): Promise<Workspace | undefined>
@@ -20,7 +20,7 @@ This table connects model-visible tool names to the plugin package and service s
20
20
  | Tool package | Model-visible names | Requires | Writes / affects | Shipped aliases | Deployment note |
21
21
  | --- | --- | --- | --- | --- | --- |
22
22
  | `@deepseek-ai/dsh-tool-ask-user` | `ask_user_question` | `ctx.tools`, `ctx.userQuestions` | `tool/call`, `tool/result after a UI/provider answers the question` | - | ask_user_question pauses the tool call until the active UI provider returns a human answer. |
23
- | `@deepseek-ai/dsh-tools` | `run_code` | `ctx.tools`, `ctx.codeRuntime (execution time)`, `ctx.systemPrompt` | `tool/call`, `one tool/code-dispatch-start + tool/code-dispatch pair per bridged sub-call`, `tool/result` | - | Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: code` / `mode: both` (see the Code Mode Agent Note). Under `code` it is the registry's only wire contribution; the other visible capabilities are declared in a generated SDK section in the loaded runtime's language, and a program calls them through bindings scheduled under the native concurrency contract (submission-ordered starts and policy; concurrency-safe bodies overlap up to `maxParallelSubCalls`) that re-enter the complete guarded tool pipeline and link each nested execution to this outer result. |
23
+ | `@deepseek-ai/dsh-tools` | `run_code` | `ctx.tools`, `ctx.codeRuntime (execution time)`, `ctx.systemPrompt` | `tool/call`, `one tool/code-dispatch-start + tool/code-dispatch pair per bridged sub-call`, `tool/result` | - | Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: ptc` / `mode: both` (see the PTC mode Agent Note). Under `ptc` it is the registry's only wire contribution; the other visible capabilities are declared in a generated SDK section in the loaded runtime's language, and a program calls them through bindings scheduled under the native concurrency contract (submission-ordered starts and policy; concurrency-safe bodies overlap up to `maxParallelSubCalls`) that re-enter the complete guarded tool pipeline and link each nested execution to this outer result. |
24
24
  | `@deepseek-ai/dsh-plan-mode` | `exit_plan_mode` | `ctx.tools`, `ctx.systemPrompt`, `ctx.userQuestions (execution time, opportunistic)` | `tool/call`, `plan/mode inactive on an approved review`, `tool/result` | - | exit_plan_mode stays in the model-facing schema while planning is inactive so transitions add no tool-catalog churn on top of the plan-policy change. Its execute path rejects calls outside plan mode; in plan mode it presents the plan over the user-questions seam (approve / keep planning with feedback), and approval logs plan mode inactive at the step boundary. |
25
25
  | `@deepseek-ai/dsh-tool-bash` | `bash` | `ctx.tools`, `ctx.shell`, `ctx.systemPrompt`, `ctx.shellEnv`, `ctx.jobs at call time for run_in_background` | `tool/call`, `tool/result` | - | The bash tool is the model-facing consumer of the bash executor seam. A `run_in_background` run registers with the generic `ctx.jobs` runtime and is collected/stopped through the `job_*` tools from `@deepseek-ai/dsh-tool-jobs`; the `enableRunInBackground` config (default true) removes the parameter entirely when disabled. |
26
26
  | `@deepseek-ai/dsh-tool-pwsh` | `pwsh` | `ctx.tools`, `ctx.shell`, `ctx.systemPrompt`, `ctx.shellEnv`, `ctx.jobs at call time for run_in_background` | `tool/call`, `tool/result` | - | The pwsh tool is the PowerShell-dialect consumer of the bash executor seam for Windows compositions (a PowerShell executor such as `@deepseek-ai/dsh-pwsh-local` backs `ctx.shell`); it mirrors the bash tool call-for-call minus sandbox controls — `run_in_background` runs register with the generic `ctx.jobs` runtime and are collected/stopped through the `job_*` tools, and the managed `DSH_*` environment comes from `@deepseek-ai/dsh-shell-env`. Each call runs in a fresh process (no persistent PTY session), with native `C:\...` paths and `$env:NAME` variables. |
@@ -37,11 +37,10 @@ This table connects model-visible tool names to the plugin package and service s
37
37
  | `@deepseek-ai/dsh-tool-ralph` | `ralph` | `ctx.tools`, `ctx.workflowEngine`, `ctx.subagents`, `ctx.systemPrompt`, `a calling Agent (exec.agent parents every fresh round)` | `tool/call`, `tool/result`, `workflow and child session events during execution` | - | A fixed foreground workflow starts one fresh structured child per round; the model selects only the immutable objective and an optional round cap. |
38
38
  | `@deepseek-ai/dsh-tool-skill` | `skill` | `ctx.tools`, `ctx.agents`, `ctx.skills` | `tool/call`, `tool/result`, `user/message replacement catalogs via agent.inject()` | - | - |
39
39
  | `@deepseek-ai/dsh-tool-session-query` | `session_event_read`, `session_event_search`, `session_event_trace`, `session_search`, `session_trace` | `ctx.tools`, `ctx.systemPrompt`, `ctx.sessionQuery`, `a calling Agent for workspace authority` | `tool/call`, `tool/result` | - | The five read-only tools hide provider cursors and authorize every result from the immutable calling agent session. The package is opt-in; compositions that need enforced deadlines or bounded inline output also mount the generic timeout or spill policies. |
40
- | `@deepseek-ai/dsh-tool-subagent` | `subagent` | `ctx.tools`, `ctx.subagents`, `ctx.systemPrompt` | `tool/call`, `tool/result`, `child session events through the chosen provider` | `subagent`, `subagent_fork` | The registered tool name is the load-time `toolName` config (default `subagent`); the schema above is that default. The shipped compositions load this package once per subagent backend, so the model additionally sees `subagent_fork` bound to the fork backend. Each instance's description, `run_in_background` parameter, and system-prompt policy follow its own `backgroundMode` and `enableRunInBackground`, so the two shipped schemas are not identical: `subagent` is `continuable` and defaults omitted calls to background with automatic settlement delivery, while `subagent_fork` stays `one-shot` and defaults them to foreground see `packages/bundle/base/cordis.patch.yml` and `examples/acp-agent/cordis.yml`. |
40
+ | `@deepseek-ai/dsh-tool-subagent` | `list_subagent_models`, `subagent` | `ctx.tools`, `ctx.subagents`, `ctx.systemPrompt`, `ctx.llm for model discovery and selected-route validation` | `tool/call`, `tool/result`, `child session events through the chosen provider` | `subagent`, `subagent_fork` | The registered delegation name is the load-time `toolName` config (default `subagent`); the default schema above has model selection off, while the discovery schema is shown as the fixed companion available in an enabled Session. Web presets sample the Plugins preference for each new top-level Session and preserve that decision for its child Sessions; `subagent_fork` remains fixed-route. Each instance independently controls whether it reads model-selection settings and its background behavior through `modelSelectionSettings`, `backgroundMode`, and `enableRunInBackground`. |
41
41
  | `@deepseek-ai/dsh-tool-subagent-control` | `interrupt_agent`, `list_agents`, `send_message` | `ctx.tools`, `ctx.subagents`, `ctx.agents and ctx.sessionProjections (list_agents only)` | `tool/call`, `tool/result`, `child session events through ctx.subagents` | - | The globally named control tools over continuable background subagents: provider-bound `tool-subagent` instances register distinct delegation tools, while this package registers `send_message` and `interrupt_agent` once, plus `list_agents` from its separately loaded `/list-agents` plugin (whose catalog rows use the sessionProjections and live Agent registries). |
42
- | `@deepseek-ai/dsh-tool-subagent-report` | `report` | `ctx.subagents`, `ctx.systemPrompt`, `a live continuable in-process child Agent` | `tool/call`, `tool/result`, `a user-role message in the direct parent session` | - | Registered per continuable in-process child rather than globally, so this schema is visible only inside such a child and survives its global `toolFilter`. The same contribution installs the child-scoped `tool:report` prompt section, which this catalog does not render. The parent-facing `send_message` tool is installed independently. |
43
42
  | `@deepseek-ai/dsh-tool-jobs` | `job_kill`, `job_list`, `job_output` | `ctx.tools`, `ctx.jobs`, `ctx.systemPrompt` | `tool/call`, `tool/result`, `user/message via agent.inject() for background completion notices` | - | The kind-agnostic background-job controller: background bash commands, PTY sends, and subagents are read, listed, and killed through the same three tools. Loading the plugin attaches the controller that arms producers' `ctx.jobs.start()`. |
44
- | `@deepseek-ai/dsh-experimental-tool-agent-team` | `followup_task`, `interrupt_agent`, `list_agents`, `send_message`, `spawn_teammate`, `team_task_create`, `team_task_get`, `team_task_list`, `team_task_update`, `wait_agent` | `ctx.tools`, `ctx.systemPrompt`, `ctx.agentTeams`, `an exact live Team member Agent` | `tool/call`, `team/member`, `team/message/queued`, `team/message/delivered`, `team/task`, `tool/result` | - | All ten tools are scoped to implicit Team Leads and durable teammates. The shipped dsh-base bundle keeps the package disabled; the documented Agent Teams profile patch enables it while disabling the legacy continuable-child control names. |
43
+ | `@deepseek-ai/dsh-experimental-tool-agent-team` | `interrupt_agent`, `list_agents`, `send_message`, `spawn_teammate`, `team_task_create`, `team_task_get`, `team_task_list`, `team_task_update`, `wait_agent` | `ctx.tools`, `ctx.systemPrompt`, `ctx.agentTeams`, `an exact live Team member Agent` | `tool/call`, `team/member`, `team/message/queued`, `team/message/delivered`, `team/task`, `tool/result` | - | All nine tools are scoped to implicit Team Leads and durable teammates. The shipped dsh-base bundle keeps the package disabled; the documented Agent Teams profile patch enables it while disabling the legacy continuable-child control names. |
45
44
  | `@deepseek-ai/dsh-tool-todo` | `todo_write` | `ctx.tools`, `owning Agent session` | `tool/call`, `todo/write`, `tool/result` | - | todo_write is session-owned state; UIs render the latest todo/write event as a checklist. `allowParallelInProgress` is required with no default, so the catalog states its choice: `true`, whose description invites several `in_progress` items. A deployment choosing `false` receives the same tool with a description asking for exactly one active task. |
46
45
  | `@deepseek-ai/dsh-tool-workflow` | `workflow` | `ctx.tools`, `ctx.workflowEngine`, `ctx.systemPrompt`, `a calling Agent (exec.agent parents the script children)` | `tool/call`, `tool/result` | - | - |
47
46
  | `@deepseek-ai/dsh-tool-web` | `web_fetch`, `web_search` | `ctx.tools`, `ctx.web`, `ctx.systemPrompt` | `tool/call`, `tool/result` | - | web_search and web_fetch keep provider selection behind ctx.web so model-visible schemas stay stable across backend swaps. |
@@ -148,9 +147,9 @@ Execute a TypeScript program against the available tools. Takes two required arg
148
147
  }
149
148
  ```
150
149
 
151
- Source: [`packages/core/tools/src/code-mode.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/tools/src/code-mode.ts)
150
+ Source: [`packages/core/tools/src/ptc.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/tools/src/ptc.ts)
152
151
 
153
- Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: code` / `mode: both` (see the Code Mode Agent Note). Under `code` it is the registry's only wire contribution; the other visible capabilities are declared in a generated SDK section in the loaded runtime's language, and a program calls them through bindings scheduled under the native concurrency contract (submission-ordered starts and policy; concurrency-safe bodies overlap up to `maxParallelSubCalls`) that re-enter the complete guarded tool pipeline and link each nested execution to this outer result.
152
+ Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: ptc` / `mode: both` (see the PTC mode Agent Note). Under `ptc` it is the registry's only wire contribution; the other visible capabilities are declared in a generated SDK section in the loaded runtime's language, and a program calls them through bindings scheduled under the native concurrency contract (submission-ordered starts and policy; concurrency-safe bodies overlap up to `maxParallelSubCalls`) that re-enter the complete guarded tool pipeline and link each nested execution to this outer result.
154
153
 
155
154
  <a id="deepseek-aidsh-plan-mode"></a>
156
155
 
@@ -570,6 +569,7 @@ Custom editing tool for viewing, creating and editing files
570
569
  * If `path` is a file, `view` displays the result of applying `cat -n`. If `path` is a directory, `view` lists non-hidden files and directories up to 2 levels deep
571
570
  * The `create` command cannot be used if the specified `path` already exists as a file
572
571
  * If a `command` generates a long output, it will be truncated and marked with `<response clipped>`
572
+ * A null placeholder for a parameter unused by the selected command is treated as omitted. Required parameters still need values; omit `str_replace.new_str` rather than setting it to null when deleting a match
573
573
 
574
574
  Notes for using the `str_replace` command:
575
575
  * The `old_str` parameter should match EXACTLY one or more consecutive lines from the original file. Be mindful of whitespaces!
@@ -595,27 +595,62 @@ Notes for using the `str_replace` command:
595
595
  "description": "Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`."
596
596
  },
597
597
  "file_text": {
598
- "type": "string",
599
- "description": "Required parameter of `create` command, with the content of the file to be created."
598
+ "oneOf": [
599
+ {
600
+ "type": "string"
601
+ },
602
+ {
603
+ "type": "null"
604
+ }
605
+ ],
606
+ "description": "Required string parameter of `create` command, with the content of the file to be created. A null placeholder is treated as omitted by commands that do not use this parameter."
600
607
  },
601
608
  "insert_line": {
602
- "type": "integer",
603
- "description": "Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."
609
+ "oneOf": [
610
+ {
611
+ "type": "integer"
612
+ },
613
+ {
614
+ "type": "null"
615
+ }
616
+ ],
617
+ "description": "Required integer parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`. A null placeholder is treated as omitted by commands that do not use this parameter."
604
618
  },
605
619
  "new_str": {
606
- "type": "string",
607
- "description": "Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."
620
+ "oneOf": [
621
+ {
622
+ "type": "string"
623
+ },
624
+ {
625
+ "type": "null"
626
+ }
627
+ ],
628
+ "description": "Optional string parameter of `str_replace` command containing the new string (if omitted, no string will be added). Required string parameter of `insert` command containing the string to insert. A null placeholder is accepted only by commands that do not use this parameter."
608
629
  },
609
630
  "old_str": {
610
- "type": "string",
611
- "description": "Required parameter of `str_replace` command containing the string in `path` to replace."
631
+ "oneOf": [
632
+ {
633
+ "type": "string"
634
+ },
635
+ {
636
+ "type": "null"
637
+ }
638
+ ],
639
+ "description": "Required string parameter of `str_replace` command containing the string in `path` to replace. A null placeholder is treated as omitted by commands that do not use this parameter."
612
640
  },
613
641
  "view_range": {
614
- "type": "array",
615
- "description": "Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file.",
616
- "items": {
617
- "type": "integer"
618
- }
642
+ "oneOf": [
643
+ {
644
+ "type": "array",
645
+ "items": {
646
+ "type": "integer"
647
+ }
648
+ },
649
+ {
650
+ "type": "null"
651
+ }
652
+ ],
653
+ "description": "Optional parameter of `view` command when `path` points to a file. If omitted or null, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file."
619
654
  }
620
655
  },
621
656
  "required": [
@@ -699,7 +734,7 @@ Source: [`packages/fs/tool-fs/src/index.ts`](https://github.com/deepseek-ai/deep
699
734
 
700
735
  ### `read_image`
701
736
 
702
- Read a PNG/JPEG/WebP/GIF file and return the image itself. Harness validates and downscales large supported images before the next model request, so use this tool directly instead of installing image libraries or creating thumbnails merely to inspect an image. Independent files may be read concurrently in small batches. Requires the current model to accept image input.
737
+ Read a PNG/JPEG/WebP/GIF file and return the image itself. A path without a file extension is accepted; the format is detected from the file content, so normalized attachment paths can be passed directly without copying or renaming. Harness validates and downscales large supported images before the next model request, so use this tool directly instead of installing image libraries or creating thumbnails merely to inspect an image. Independent files may be read concurrently in small batches. Requires the current model to accept image input.
703
738
 
704
739
  ```json
705
740
  {
@@ -1505,6 +1540,28 @@ The five read-only tools hide provider cursors and authorize every result from t
1505
1540
 
1506
1541
  ## `@deepseek-ai/dsh-tool-subagent`
1507
1542
 
1543
+ ### `list_subagent_models`
1544
+
1545
+ Discover LLM routes for subagents without changing the current Agent. Call with no arguments to list registered providers, with `provider` to list its advertised models, or with `provider` and `model` to inspect that exact model and its reasoning efforts. Catalog membership is advisory: an adapter may accept an unlisted model id. Use the returned ids with a delegation tool's `provider`, `model`, and `reasoning_effort` fields.
1546
+
1547
+ ```json
1548
+ {
1549
+ "type": "object",
1550
+ "properties": {
1551
+ "provider": {
1552
+ "type": "string",
1553
+ "description": "Registered LLM provider id. Omit to list providers."
1554
+ },
1555
+ "model": {
1556
+ "type": "string",
1557
+ "description": "Exact model id to inspect. Requires provider; omit to list that provider's advertised models."
1558
+ }
1559
+ }
1560
+ }
1561
+ ```
1562
+
1563
+ Source: [`packages/subagent/tool-subagent/src/list-models.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subagent/tool-subagent/src/list-models.ts)
1564
+
1508
1565
  ### `subagent`
1509
1566
 
1510
1567
  Delegate a self-contained task to a subagent (a separate agent that works in its own context) to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent returns its result, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. This call waits for the result by default. Set `run_in_background: true` to return a job id; collect with `job_output` and stop with `job_kill`.
@@ -1535,7 +1592,7 @@ Delegate a self-contained task to a subagent (a separate agent that works in its
1535
1592
 
1536
1593
  Source: [`packages/subagent/tool-subagent/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subagent/tool-subagent/src/index.ts)
1537
1594
 
1538
- The registered tool name is the load-time `toolName` config (default `subagent`); the schema above is that default. The shipped compositions load this package once per subagent backend, so the model additionally sees `subagent_fork` bound to the fork backend. Each instance's description, `run_in_background` parameter, and system-prompt policy follow its own `backgroundMode` and `enableRunInBackground`, so the two shipped schemas are not identical: `subagent` is `continuable` and defaults omitted calls to background with automatic settlement delivery, while `subagent_fork` stays `one-shot` and defaults them to foreground see `packages/bundle/base/cordis.patch.yml` and `examples/acp-agent/cordis.yml`.
1595
+ The registered delegation name is the load-time `toolName` config (default `subagent`); the default schema above has model selection off, while the discovery schema is shown as the fixed companion available in an enabled Session. Web presets sample the Plugins preference for each new top-level Session and preserve that decision for its child Sessions; `subagent_fork` remains fixed-route. Each instance independently controls whether it reads model-selection settings and its background behavior through `modelSelectionSettings`, `backgroundMode`, and `enableRunInBackground`.
1539
1596
 
1540
1597
  <a id="deepseek-aidsh-tool-subagent-control"></a>
1541
1598
 
@@ -1564,7 +1621,7 @@ Source: [`packages/subagent/tool-subagent-control/src/index.ts`](https://github.
1564
1621
 
1565
1622
  ### `list_agents`
1566
1623
 
1567
- List your continuable background subagents by durable id and label. Use it to recall which ones you started, not to poll for completion — you are told when one finishes. Status comes from the live registry: running means the agent is working right now, idle means it is loaded but between turns (it may be waiting on agents it started), and ready means it exists only in storage — resumable, not terminal, and not a result waiting to be collected; a `send_message` starts a new turn on the same conversation, and a direct child remains a `send_message` candidate in every status. The snapshot is not a delivery promise — `send_message` performs the authoritative check and may still fail. Children that could not be read are reported as diagnostics instead of being silently dropped. Scope `descendants` walks the whole tree below you in stable pre-order, annotating each entry with its durable direct-parent session id and depth. You may use `send_message` only for depth-1 entries; deeper entries are candidates for `interrupt_agent` only.
1624
+ List your continuable background subagents by durable id and label. Use it to recall which ones you started, not to poll for completion — you are told when one finishes. Status comes from the live registry: running means the agent is working right now, idle means it is loaded but between turns (it may be waiting on agents it started), and ready means it exists only in storage — resumable, not terminal, and not a result waiting to be collected; a `send_message` steers a running child at its nearest step boundary or starts a turn for an idle or ready child, and a direct child remains a `send_message` candidate in every status. The snapshot is not a delivery promise — `send_message` performs the authoritative check and may still fail. Children that could not be read are reported as diagnostics instead of being silently dropped. Scope `descendants` walks the whole tree below you in stable pre-order, annotating each entry with its durable direct-parent session id and depth. You may use `send_message` only for depth-1 entries; deeper entries are candidates for `interrupt_agent` only.
1568
1625
 
1569
1626
  ```json
1570
1627
  {
@@ -1586,23 +1643,23 @@ Source: [`packages/subagent/tool-subagent-control/src/list-agents.ts`](https://g
1586
1643
 
1587
1644
  ### `send_message`
1588
1645
 
1589
- Send a message to a background subagent by its subagent id, continuing the same conversation. It becomes the subagent's next turn: if it is still working, the message waits until its current turn finishes, so it cannot redirect work already underway. This call returns no answer from the subagent — only confirmation that the message was delivered — so use it to give it more work. A failure means the message was NOT delivered.
1646
+ Send a message to a direct continuable child by its agent id. If you are a resident continuable child, you may also target your direct parent. If the target is still working, the message steers its nearest step; if it is idle, the message starts a turn. This call returns no answer from the agent — only confirmation that the message was delivered. A failure means the message was NOT delivered.
1590
1647
 
1591
1648
  ```json
1592
1649
  {
1593
1650
  "type": "object",
1594
1651
  "properties": {
1595
- "subagent_id": {
1652
+ "agent_id": {
1596
1653
  "type": "string",
1597
- "description": "The subagent id returned when the background subagent was started."
1654
+ "description": "The agent id of your direct continuable child, or your direct parent when you are a resident continuable child."
1598
1655
  },
1599
1656
  "message": {
1600
1657
  "type": "string",
1601
- "description": "The message to deliver to the subagent."
1658
+ "description": "The message to deliver to the agent."
1602
1659
  }
1603
1660
  },
1604
1661
  "required": [
1605
- "subagent_id",
1662
+ "agent_id",
1606
1663
  "message"
1607
1664
  ]
1608
1665
  }
@@ -1612,33 +1669,6 @@ Source: [`packages/subagent/tool-subagent-control/src/index.ts`](https://github.
1612
1669
 
1613
1670
  The globally named control tools over continuable background subagents: provider-bound `tool-subagent` instances register distinct delegation tools, while this package registers `send_message` and `interrupt_agent` once, plus `list_agents` from its separately loaded `/list-agents` plugin (whose catalog rows use the sessionProjections and live Agent registries).
1614
1671
 
1615
- <a id="deepseek-aidsh-tool-subagent-report"></a>
1616
-
1617
- ## `@deepseek-ai/dsh-tool-subagent-report`
1618
-
1619
- ### `report`
1620
-
1621
- Report selected content to the agent that started you. Call this once before you finish, with a self-contained final result, and earlier for progress or findings that change what that agent does next. That agent shares your workspace but does not automatically receive your transcript, tool output, or reasoning, so finishing your work is not itself a result. Reporting does not end your turn or finish your work, and only your direct parent receives it. A failed call may still have arrived, so do not blindly repeat it.
1622
-
1623
- ```json
1624
- {
1625
- "type": "object",
1626
- "properties": {
1627
- "output": {
1628
- "type": "string",
1629
- "description": "Actionable content for your parent; summarize conclusions and reference relevant shared paths."
1630
- }
1631
- },
1632
- "required": [
1633
- "output"
1634
- ]
1635
- }
1636
- ```
1637
-
1638
- Source: [`packages/subagent/tool-subagent-report/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/subagent/tool-subagent-report/src/index.ts)
1639
-
1640
- Registered per continuable in-process child rather than globally, so this schema is visible only inside such a child and survives its global `toolFilter`. The same contribution installs the child-scoped `tool:report` prompt section, which this catalog does not render. The parent-facing `send_message` tool is installed independently.
1641
-
1642
1672
  <a id="deepseek-aidsh-tool-jobs"></a>
1643
1673
 
1644
1674
  ## `@deepseek-ai/dsh-tool-jobs`
@@ -1716,32 +1746,6 @@ The kind-agnostic background-job controller: background bash commands, PTY sends
1716
1746
 
1717
1747
  ## `@deepseek-ai/dsh-experimental-tool-agent-team`
1718
1748
 
1719
- ### `followup_task`
1720
-
1721
- Send a durable follow-up task to another Team member and start a turn when needed.
1722
-
1723
- ```json
1724
- {
1725
- "type": "object",
1726
- "properties": {
1727
- "target": {
1728
- "type": "string",
1729
- "description": "Team member name, or lead."
1730
- },
1731
- "message": {
1732
- "type": "string",
1733
- "description": "Self-contained message for the target."
1734
- }
1735
- },
1736
- "required": [
1737
- "target",
1738
- "message"
1739
- ]
1740
- }
1741
- ```
1742
-
1743
- Source: [`packages/experimental/tool-agent-team/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/experimental/tool-agent-team/src/index.ts)
1744
-
1745
1749
  ### `interrupt_agent`
1746
1750
 
1747
1751
  Interrupt one teammate's current turn while preserving its pending inbox. Team Lead only.
@@ -1778,7 +1782,7 @@ Source: [`packages/experimental/tool-agent-team/src/index.ts`](https://github.co
1778
1782
 
1779
1783
  ### `send_message`
1780
1784
 
1781
- Send durable information to another Team member without starting an idle member.
1785
+ Send one durable message to another Team member. A running target receives it at the nearest step boundary; an idle target starts a turn; an inactive teammate cold-resumes.
1782
1786
 
1783
1787
  ```json
1784
1788
  {
@@ -2026,7 +2030,7 @@ Wait for the next teammate status, mailbox, or shared-task change after this cal
2026
2030
 
2027
2031
  Source: [`packages/experimental/tool-agent-team/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/experimental/tool-agent-team/src/index.ts)
2028
2032
 
2029
- All ten tools are scoped to implicit Team Leads and durable teammates. The shipped dsh-base bundle keeps the package disabled; the documented Agent Teams profile patch enables it while disabling the legacy continuable-child control names.
2033
+ All nine tools are scoped to implicit Team Leads and durable teammates. The shipped dsh-base bundle keeps the package disabled; the documented Agent Teams profile patch enables it while disabling the legacy continuable-child control names.
2030
2034
 
2031
2035
  <a id="deepseek-aidsh-tool-todo"></a>
2032
2036
 
@@ -61,6 +61,6 @@ flowchart TD
61
61
  allResults --> context
62
62
  ```
63
63
 
64
- Filesystem read-before-edit checks stay below `tool-fs` on `fs/*` events. Generic pre/post waterfalls host hooks and approval policy; `ctx.approval` resolves asks before monotonic guards, and owner policy that must not be reordered remains a registered guard. Around-dispatch concerns such as timeouts wrap `tools/execute`. The registry losslessly snapshots the candidate result and normalizes a snapshot failure before the visible definition's snapshotted `finalizeContent` callback enforces its synchronous content-only invariant. `tools/result` then observes the immutable, lossless-JSON outcome. This lets hooks span tool families without coupling the tools to one policy service. Code Mode sends both the reserved `run_code` transport and its serialized sub-calls through the pipeline; sub-calls carry the parent token, log `tool/code-dispatch`, return denials as binding rejections, and omit `additionalContexts` to preserve call/result adjacency.
64
+ Filesystem read-before-edit checks stay below `tool-fs` on `fs/*` events. Generic pre/post waterfalls host hooks and approval policy; `ctx.approval` resolves asks before monotonic guards, and owner policy that must not be reordered remains a registered guard. Around-dispatch concerns such as timeouts wrap `tools/execute`. The registry losslessly snapshots the candidate result and normalizes a snapshot failure before the visible definition's snapshotted `finalizeContent` callback enforces its synchronous content-only invariant. `tools/result` then observes the immutable, lossless-JSON outcome. This lets hooks span tool families without coupling the tools to one policy service. PTC mode sends both the reserved `run_code` transport and its serialized sub-calls through the pipeline; sub-calls carry the parent token, log `tool/code-dispatch`, return denials as binding rejections, and omit `additionalContexts` to preserve call/result adjacency.
65
65
 
66
66
  Maintenance mode: curated Mermaid flow; exact tool schemas and event signatures live in generated catalogs.
@@ -0,0 +1,104 @@
1
+ ---
2
+ editSource: "docs/user/guide/github-review.zh.md"
3
+ ---
4
+
5
+ # 通过 GitHub Webhook 创建评审会话
6
+
7
+ 此可选 overlay 会为 `dsh web` 增加一个签名 GitHub 端点。当已配置仓库中的 pull request 从 draft 变为 ready for review 时,规则会在该仓库的 Web Workspace 下创建带标题的根 Session,并启动只读评审提示词。
8
+
9
+ ## 前置条件
10
+
11
+ - 一个可由 DSH 注册为 Web Workspace 的本地 checkout。
12
+ - 一个可通过 `DSH_GITHUB_WEBHOOK_SECRET` 凭据引用访问的高熵 GitHub webhook 密钥。
13
+ - 一个可以把单个公共 URL 转发到 loopback 监听器的 TLS 反向代理或 tunnel。
14
+ - GitHub webhook 订阅 Pull requests 事件,且 content type 为 `application/json`。
15
+
16
+ overlay 默认使用启动目录作为 Workspace,并监听 `127.0.0.1:3081`。可通过 `DSH_GITHUB_REVIEW_WORKSPACE` 与 `DSH_GITHUB_WEBHOOK_PORT` 覆盖它们。
17
+
18
+ ## 启动 DSH
19
+
20
+ 生成密钥,并在重启后继续使用同一值:
21
+
22
+ ```sh
23
+ export DSH_GITHUB_WEBHOOK_SECRET="$(openssl rand -hex 32)"
24
+ printf '%s\n' "$DSH_GITHUB_WEBHOOK_SECRET"
25
+ ```
26
+
27
+ 在开发 checkout 中运行:
28
+
29
+ ```sh
30
+ export DSH_GITHUB_REVIEW_WORKSPACE=/path/to/deepseek-harness
31
+ pnpm dsh web --patch apps/cli/config/examples/github-review/cordis.yml
32
+ ```
33
+
34
+ 安装版 DSH 通过绝对路径使用同一 overlay:
35
+
36
+ ```sh
37
+ dsh web --patch /absolute/path/to/github-review/cordis.yml
38
+ ```
39
+
40
+ 对于永久 profile,把 `github-ready-review-rule.mjs` 放在 `$DSH_HOME/profiles/web/cordis.patch.yml` 旁边,把 `cordis.yml` 中的行追加到该 patch,然后运行 `dsh web`。随附 CLI 已经包含两个 webhook 包;只需 overlay 即可激活它们。
41
+
42
+ ## 暴露专用端点
43
+
44
+ 主 Web UI 与 `/api` 继续位于端口 3080。overlay 会在隔离 realm 中挂载第二个 WebServer;其中只注册 `POST /github`,其他路径均返回 `404`。
45
+
46
+ Caddy 配置可以只暴露该监听器:
47
+
48
+ ```caddyfile
49
+ hooks.example.com {
50
+ route {
51
+ @github path /github
52
+ reverse_proxy @github 127.0.0.1:3081
53
+ respond 404
54
+ }
55
+ }
56
+ ```
57
+
58
+ GitHub 配置如下:
59
+
60
+ ```text
61
+ Payload URL: https://hooks.example.com/github
62
+ Content type: application/json
63
+ Secret: DSH_GITHUB_WEBHOOK_SECRET value
64
+ Events: Pull requests
65
+ Active: yes
66
+ ```
67
+
68
+ ## 规则行为
69
+
70
+ 规则只接受来源 `primary-github`、仓库 `deepseek-harness/deepseek-harness`、事件 `pull_request` 与动作 `ready_for_review`。它会把精确 head SHA 和选定 PR 字段传给评审提示词,把 JSON 标为不受信任的元数据,并禁止修改文件、分支、PR 或 GitHub 状态。
71
+
72
+ Session 请求选择 `standard` agent preset 与 `read-only` permission preset。`workspacePath` 通过 `WorkspaceRegistry.create()` 规范化,因此第一次匹配交付会在 Workspace 不存在时创建它,后续交付会复用它。
73
+
74
+ HTTP 响应刻意弱于 Agent 结果:`202` 表示签名与 JSON 已被接受,规则调用已在内存中调度。它不表示此规则已经匹配,也不表示已创建 Session。
75
+
76
+ ## 程序化扩展
77
+
78
+ `run()` 是普通受信任 JavaScript。部署可以在返回 Session 请求前查询内部策略服务:
79
+
80
+ ```js
81
+ const response = await fetch('https://policy.internal/pr-review', {
82
+ method: 'POST',
83
+ headers: { 'content-type': 'application/json' },
84
+ body: JSON.stringify({ repository: payload.repository.full_name }),
85
+ signal,
86
+ })
87
+ if (!response.ok || (await response.json()).automaticReview !== true) return null
88
+ ```
89
+
90
+ 它还可以把仓库映射到不同本地路径:
91
+
92
+ ```js
93
+ const workspacePath = {
94
+ 'deepseek-harness/deepseek-harness': '/path/to/deepseek-harness',
95
+ 'deepseek-harness/dsh-sdk': '/path/to/dsh-sdk',
96
+ }[payload.repository.full_name]
97
+ if (workspacePath === undefined) return null
98
+ ```
99
+
100
+ ## 交付语义
101
+
102
+ webhook runtime 不存储交付或执行状态。重复交付会运行规则,并可能创建另一个 Session。崩溃会丢失尚未接纳提示词的规则调用。提示词接纳后,工作由普通 Session 日志、persistence、Workspace 与 Agent 生命周期拥有。
103
+
104
+ webhook 密钥只验证入站 GitHub 数据。它不会向规则代码或所创建 Agent 授予出站 GitHub 访问权;规则或 Agent 需要时应单独配置该权限。