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
@@ -20,7 +20,7 @@ A turn flows through the six packages in one loop: the driver in [`agent-loop`](
20
20
  | `agent-loop/` | The concrete driver implementing the public `Agent` contract (`ctx.agentLoop`) | this page |
21
21
  | `scope/` | The scoped-registration primitive the registries and loop build per-agent scoping on | [scope.md](./scope.md) |
22
22
 
23
- `scope/` is the one non-service package: a dependency-free library (`createScope`/`scopeOf`/`scopeTarget`) that sits below `session/` and `system-prompt/` in the module graph precisely so they can consume it without a cycle. `agent-loop` is the one concrete implementation of the public `Agent` contract and lives here because it is the harness's default product loop; it runs each driver inside `ctx.agents.withInitiator()`. Extension plugins depend on `agent` — including when they need the initiating Agent — and never on `agent-loop` directly, so the loop stays swappable. The default composition that wires this spine into a runnable agent is [`examples/agent-spine-demo`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/examples/agent-spine-demo/README.md).
23
+ `scope/` is the one non-service package: a dependency-free library (`createScope`/`scopeOf`/`scopeTarget`) that sits below `session/` and `system-prompt/` in the module graph precisely so they can consume it without a cycle. `agent-loop` is the one concrete implementation of the public `Agent` contract and lives here because it is the harness's default product loop; it runs each driver inside `ctx.agents.withInitiator()`. Extension plugins depend on `agent` — including when they need the initiating Agent — and never on `agent-loop` directly, so the loop stays swappable. [`dsh-base`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/base/README.md) is the default product composition, while [`dsh-sdk-minimal`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/sdk-minimal/README.md) declares a smaller standalone tree.
24
24
 
25
25
  ## Creation and ownership
26
26
 
@@ -49,7 +49,7 @@ interface AgentHandle {
49
49
  }
50
50
  ```
51
51
 
52
- `CreateAgentOptions` carries the shared identity and everything a fresh agent needs before publication: session metadata (`meta` — validated `cwd`, fork lineage, seed boundary, origin classification, delegation depth), an optional `seed` replay prefix for forks, per-agent `AgentOptions`, a creation-only cancellation `signal`, and `setup`. `ResumeAgentOptions` is the persisted-identity counterpart: `resumeSessionId`, `agentOptions`, `signal`, and `setup`. The `setup` callback (`AgentSetup`) composes the agent's scoped world while both ids are still unpublished — everything registered through `agentCtx` exists before `agent/created` and the first prompt assembly — and may return a synchronous commit invoked immediately before publication; a setup rejection, commit throw, or owner disposal rolls the transaction back without publishing either id.
52
+ `CreateAgentOptions` carries the shared identity and everything a fresh agent needs before publication: session metadata (`meta` — validated `cwd`, fork lineage, the `isSeeded` marker, origin classification, delegation depth, and `agentPreset`), the exact fork cut in sibling field `inheritedEventCount`, an optional `seed` replay prefix, per-agent `AgentOptions`, a creation-only cancellation `signal`, and `setup`. `ResumeAgentOptions` is the persisted-identity counterpart: `resumeSessionId`, `agentOptions`, `signal`, and `setup`. The `setup` callback (`AgentSetup`) composes the agent's scoped world while both ids are still unpublished — everything registered through `agentCtx` exists before `agent/created` and the first prompt assembly — and may return a synchronous commit invoked immediately before publication; a setup rejection, commit throw, or owner disposal rolls the transaction back without publishing either id.
53
53
 
54
54
  `AgentFactory` is the creation interface behind the registry: the loop registers its factory via `ctx.agents.setFactory()`, so consumers use `ctx.agents` without depending on the concrete loop package. The exact `create`/`resume` signatures and rollback contracts are in the [generated section](#ctxagents--agentregistry) below.
55
55
 
@@ -60,9 +60,9 @@ interface AgentHandle {
60
60
  Source: [`packages/core/agent/src/types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/types.ts)
61
61
 
62
62
  ```ts type-equiv
63
- /** Public live-agent handle. */
63
+ /** Public live-agent handle; the runtime face augments its live capabilities. */
64
64
  interface Agent {
65
- /** The single identity shared with {@link session}. */
65
+ /** Session-backed Agent identity. */
66
66
  readonly id: SessionId
67
67
  /** The provider route and model this agent's requests use. */
68
68
  readonly options: AgentOptions
@@ -155,6 +155,44 @@ interface Agent {
155
155
  type AgentStatus = 'idle' | 'running'
156
156
  ```
157
157
 
158
+ ```ts type-equiv
159
+ /** One process-local live assistant streaming publication. */
160
+ type AssistantStreamFrame =
161
+ | {
162
+ readonly type: 'start'
163
+ readonly attemptId: LlmAttemptId
164
+ /** Monotone within one attached Agent lifecycle; replacement restarts at 1. */
165
+ readonly revision: number
166
+ readonly turn: number
167
+ readonly step: number
168
+ }
169
+ | {
170
+ readonly type: 'chunk'
171
+ readonly attemptId: LlmAttemptId
172
+ readonly revision: number
173
+ /** Dense zero-based position within the attempt. */
174
+ readonly index: number
175
+ /** Safe-integer timestamp reused by the durable embedded stream. */
176
+ readonly time: number
177
+ readonly chunk: StreamChunk
178
+ }
179
+ | {
180
+ readonly type: 'end'
181
+ readonly attemptId: LlmAttemptId
182
+ readonly revision: number
183
+ /** Number of chunk frames emitted by this attempt. */
184
+ readonly index: number
185
+ /** Durable settlement committed before this notification, or live abandonment without one. */
186
+ readonly outcome:
187
+ | {
188
+ readonly kind: 'committed'
189
+ readonly eventType: 'assistant/message' | 'assistant/attempt'
190
+ readonly seq: SessionSeq
191
+ }
192
+ | { readonly kind: 'abandoned' }
193
+ }
194
+ ```
195
+
158
196
  `running` describes the driver-wide drain interval and may span consecutive queued turns; it does not prove a turn is still open. Disposal removes the agent from the registry and emits `agent/disposed`; it is not a terminal status value. `followup()` returns no handle: its `MessageId` identifies durable inbox insertion, claim, and discard facts, not a later assistant output or turn ending. `whenIdle()` observes the whole agent, so callers may call a receipt-to-idle interval a run only when they explicitly own that interval ([decision](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-07-30-followup-enqueue-and-owned-runs.md)).
159
197
 
160
198
  ```ts type-equiv
@@ -164,12 +202,14 @@ interface AgentOptions {
164
202
  provider?: string
165
203
  /** Model id interpreted by the selected provider adapter. */
166
204
  model?: string
205
+ /** Adapter-owned reasoning effort for the selected provider/model route. */
206
+ reasoningEffort?: ReasoningEffortId
167
207
  /** Maximum output tokens for each conversation-model request. */
168
208
  maxTokens?: number
169
209
  }
170
210
  ```
171
211
 
172
- Dispatch requires `provider` and `model` after `agent/request`. When present, `maxTokens` must be a positive safe integer and caps every conversation-model request; omission allows the exact-model adapter default to materialize before the request header, or otherwise leaves provider behavior unchanged. An agent-scoped `deployment:persona` prompt section may shadow the global default persona.
212
+ Dispatch requires `provider` and `model` after `agent/request`. An explicit `reasoningEffort` seeds the first request on that route; exact-model resolution validates it, while omission allows the adapter default to materialize. When present, `maxTokens` must be a positive safe integer and caps every conversation-model request; omission allows the exact-model adapter default to materialize before the request header, or otherwise leaves provider behavior unchanged. An agent-scoped `deployment:persona` prompt section may shadow the global default persona.
173
213
 
174
214
  The inbox is the delivery vocabulary — two ordered pending-message lists the agent owns as a durable projection:
175
215
 
@@ -203,7 +243,7 @@ type AgentCancelCause =
203
243
  | { readonly kind: 'disposed' }
204
244
  ```
205
245
 
206
- The cause is a TypeScript-enforced same-process input. An active cancellation holder copies it into the runtime-only `AbortSignal.reason`; a signal grants cooperating listeners no classification authority. Durable `turn/end` retains the coarse `{ kind: 'aborted' }` outcome; recording who requested cancellation would require a separate durable event rather than overloading the terminal result.
246
+ The cause is a TypeScript-enforced same-process input. An active cancellation holder copies it into the runtime-only `AbortSignal.reason`; a signal grants cooperating listeners no classification authority. Durable `turn/end` records the outcome as `{ kind: 'aborted', reason: TurnEndCancelCause }`, so the cancel cause lands in the terminal result.
207
247
 
208
248
  The [event taxonomy](../index.md#events) owns the `agent/*` lifecycle, checkpoint, and waterfall contracts. Turn and step boundaries are durable session events rather than agent emits.
209
249
 
@@ -225,7 +265,12 @@ It returns a `PreStepDecision`. Reject opens no step. Enter supplies the complet
225
265
  /** Whether and with which messages the loop enters a proposed step. */
226
266
  type PreStepDecision =
227
267
  | { kind: 'reject' }
228
- | { kind: 'enter'; messages: UserMessage[] }
268
+ | {
269
+ kind: 'enter'
270
+ messages: UserMessage[]
271
+ /** Start a distinct model-message series before this step's admitted messages. */
272
+ startsRequestSeries?: true
273
+ }
229
274
  ```
230
275
 
231
276
  `agent/request-error` runs after a failed model step closes and before its turn closes. Listeners can repair durable state or await policy work while the failed turn's signal is still live. A handling listener returns `{ kind: 'retry' }` without calling `next()`; the default `undefined` leaves the failure terminal.
@@ -235,7 +280,7 @@ type PreStepDecision =
235
280
  type RequestErrorAction = { kind: 'retry' } | undefined
236
281
  ```
237
282
 
238
- `agent/pre-step` is the only serial listener chain before request derivation. `agent/turn-stopping` runs when a turn has no tool or steering continuation, before one final steering drain.
283
+ `agent/pre-step` is the only waterfall listener chain before request derivation. `agent/turn-stopping` runs when a turn has no tool or steering continuation, before one final steering drain.
239
284
 
240
285
  `agent/session-start` carries a `SessionStartSource` (why the session lifecycle began; a bridge keys its SessionStart matcher on it):
241
286
 
@@ -248,7 +293,7 @@ type SessionStartSource = 'startup' | 'resume' | 'clear' | 'compact'
248
293
 
249
294
  A `Session` is an **append-only log** of typed `SessionEvent`s — the single source of truth. The LLM message history is *derived* from the log (`deriveMessages()`), not stored separately. Every entry carries a monotonic `seq`, a `time`, and a `type`-discriminated `data` payload; surface variants may also list cited earlier events in `sourceEventSeqs` and carry a `surfaceOp`.
250
295
 
251
- The `SessionEvent` envelope's exact conditional fields, the twelve event variants (`turn/start`, `turn/end`, `step/start`, `step/end`, `user/message`, `assistant/chunk`, `assistant/message`, `tool/call`, `tool/result`, `steering/message`, `todo/write`, `request/header`), the `deriveMessages()` projection rules, the `TurnTrigger`/`TurnEndReason` reasons, and the execution-enclosure and standalone-event rules are on **[session.md](./session.md)**. How the log is made durable — the `SessionPersistence` interface, JSONL/SQLite backends, the `session/flush` checkpoint, crash recovery, and `SessionHeader` — is on **[persistence.md](./persistence.md)**.
296
+ The `SessionEvent` envelope's exact conditional fields, the twelve core event variants (`turn/start`, `turn/end`, `step/start`, `step/end`, `user/message`, `assistant/message`, `assistant/attempt`, `tool/call`, `tool/result`, `request/header`, `request/context`, `session/end-seed`), the `deriveMessages()` projection rules, the `TurnEndReason` reasons, and the execution-enclosure and standalone-event rules are on **[session.md](./session.md)**. How the log is made durable — the `SessionPersistence` interface, JSONL provider, `session/flush` checkpoint, crash recovery, and `SessionHeader` — is on **[persistence.md](./persistence.md)**.
252
297
 
253
298
  ## `ToolDefinition`
254
299
 
@@ -283,14 +328,13 @@ declare module '@deepseek-ai/dsh-llm' {
283
328
  }
284
329
  ```
285
330
 
286
- Six canonical maps use this pattern; a plugin author extends these:
331
+ Five canonical maps use this pattern; a plugin author extends these:
287
332
 
288
333
  | Map | Package | Derives | Catalog |
289
334
  |---|---|---|---|
290
335
  | `ContentBlockMap` | dsh-llm | `ContentBlock` | [llm-streaming.md](./llm-streaming.md#content-blocks-and-messages) |
291
336
  | `MessageSourceMap` | dsh-llm | `MessageSource` | [llm-streaming.md](./llm-streaming.md#content-blocks-and-messages) |
292
337
  | `FinishReasonMap` | dsh-llm | `FinishReason` | [llm-streaming.md](./llm-streaming.md#the-model-request-and-result) |
293
- | `TurnTriggerMap` | dsh-session | `TurnTrigger` | [session.md](./session.md) |
294
338
  | `TurnEndReasonMap` | dsh-session | `TurnEndReason` | [session.md](./session.md) |
295
339
  | `SessionEventMap` | dsh-session | `SessionEvent` | [session.md](./session.md) |
296
340
 
@@ -298,9 +342,9 @@ Two large discriminated unions are the ones consumers `switch` over most: **`Str
298
342
 
299
343
  ### Branded IDs
300
344
 
301
- IDs passed between packages are **branded** — structurally strings, but non-interchangeable at the type level (a `SessionId` cannot be passed where a `CallId` is expected). Construction goes through a per-type factory; comparison, logging, and JSON behave as ordinary strings.
345
+ IDs passed between packages are **branded** — structurally strings, but non-interchangeable at the type level (a `SessionId` cannot be passed where a `ToolCallId` is expected). Construction uses the shared `brandString<T>()` helper or an owner-defined validating factory; comparison, logging, and JSON behave as ordinary strings.
302
346
 
303
- The `Branded<B>` primitive lives in its own type-only package, [dsh-brand](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/util/brand) (no runtime code, no harness-package dependency), so any package can brand the ids it owns without depending on an unrelated capability package.
347
+ The `Branded<B>` primitive and stateless constructor live in [dsh-brand](https://github.com/deepseek-ai/deepseek-harness/tree/master/packages/util/brand), which has no harness capability dependency. `brandString<T>()` applies a compile-time-only string brand.
304
348
 
305
349
  Source: [`packages/util/brand/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/util/brand/src/index.ts)
306
350
 
@@ -309,7 +353,7 @@ Source: [`packages/util/brand/src/index.ts`](https://github.com/deepseek-ai/deep
309
353
  type Branded<B extends string> = string & { readonly [BRAND]: B }
310
354
  ```
311
355
 
312
- The two core IDs are `CallId` (correlates a tool call with its result; dsh-llm) and `SessionId` (the shared live agent and durable session identity; dsh-session). Capability packages brand their own ids too, such as `JobId` in [jobs.md](./jobs.md).
356
+ The two core IDs are `ToolCallId` (correlates a tool call with its result; dsh-llm) and `SessionId` (the shared live agent and durable session identity; dsh-session). Capability packages brand their own ids too, such as `JobId` in [jobs.md](./jobs.md).
313
357
 
314
358
  <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
315
359
 
@@ -353,13 +397,14 @@ Concrete agent factory and driver service.
353
397
  /**
354
398
  * Create an agent and session under one caller-supplied identity, owned by
355
399
  * the accessing fiber. Constructor-driven config calls mint a fresh combined
356
- * id before entering this boundary.
400
+ * id before entering this boundary. When a persistence backend is mounted,
401
+ * the session's durable identity and any seed are stored before publication.
357
402
  * @param id - shared agent/session identity.
358
403
  * @param options - concrete loop options.
359
404
  * @param meta - optional fresh-session workspace metadata.
360
405
  * @returns the published running agent.
361
406
  */
362
- create(id: SessionId, options: AgentOptions = {}, meta: Pick<SessionHeader, 'cwd'> = {}): Agent
407
+ async create(id: SessionId, options: AgentOptions = {}, meta: Pick<SessionHeader, 'cwd'> = {}): Promise<Agent>
363
408
 
364
409
  /**
365
410
  * Create an owned agent on a caller-supplied session id.
@@ -397,6 +442,35 @@ Discovery is unmemoized: `list()` and `resolve()` re-read the roots on every cal
397
442
  */
398
443
  async list(): Promise<AgentPreset[]>
399
444
 
445
+ /**
446
+ * The roster off the Host: {@link list} projected to path-free rows, with
447
+ * the default marked and this deployment's authoring capability beside it.
448
+ *
449
+ * Whether a client can open a preset's directory is the Host's own opener
450
+ * capability, not a roster property — a caller needing both joins them.
451
+ * @returns the rows and the authoring capability.
452
+ */
453
+ @Remote('list') async remoteExportList(): Promise<AgentPresetRoster>
454
+
455
+ /**
456
+ * Every preset's composition as flattened plugin rows, for plugin-listing
457
+ * surfaces beside the roster's own picker.
458
+ *
459
+ * A preset with a live standing mount answers from its newest generation's
460
+ * Loader entries — the composition new sessions join — even when the file
461
+ * behind it has since been edited into an unreadable state: the mount is
462
+ * what sessions actually run, so the broken verdict only applies to a
463
+ * preset nothing composed. One never composed since boot answers from its
464
+ * file, with `!!js` disabled gates evaluated against the Loader context so
465
+ * both answers reflect the same host. Reading never mounts: an unmounted
466
+ * preset is parsed, not composed, so listing a preset's plugins cannot
467
+ * activate them early. A composition that stopped reading between
468
+ * discovery's health verdict and this read is reported broken with the
469
+ * raced reason rather than dropped.
470
+ * @returns one composition per roster preset, in roster order.
471
+ */
472
+ async compositionInventory(): Promise<AgentPresetComposition[]>
473
+
400
474
  /**
401
475
  * Resolve one preset by id.
402
476
  *
@@ -471,6 +545,15 @@ composedPreset(agentCtx: Context): string | undefined
471
545
  */
472
546
  async read(id: string): Promise<string>
473
547
 
548
+ /**
549
+ * One preset's composition text with the roster row it belongs to.
550
+ * @param agentPreset - the preset id.
551
+ * @returns the composition beside its trust and published metadata.
552
+ * @throws {RemoteError} `gateway/bad-request` for an empty id, or
553
+ * `agent-preset/not-found` when no configured root supplies it.
554
+ */
555
+ @Remote('read') async readDocument(agentPreset: string): Promise<AgentPresetDocument>
556
+
474
557
  /**
475
558
  * Create a locally authored preset by copying an existing one whole.
476
559
  *
@@ -488,13 +571,34 @@ async read(id: string): Promise<string>
488
571
  */
489
572
  async copy(from: string, id: string, name?: string): Promise<void>
490
573
 
574
+ /**
575
+ * Copy one preset through the Remote API.
576
+ * @param from - the source preset id.
577
+ * @param id - the new preset id.
578
+ * @param name - the copy's optional display name.
579
+ * @returns once the copy is stored.
580
+ * @throws {RemoteError} with the corresponding stable preset code and
581
+ * details when the copy is refused.
582
+ */
583
+ @Remote('copy') async remoteExportCopy(from: string, id: string, name?: string): Promise<void>
584
+
491
585
  /**
492
586
  * Delete a locally authored preset.
587
+ *
493
588
  * @param id - the preset id.
494
589
  * @throws when the preset is unknown or ships with the deployment.
495
590
  */
496
591
  async remove(id: string): Promise<void>
497
592
 
593
+ /**
594
+ * Delete one preset through the Remote API.
595
+ * @param id - the preset id.
596
+ * @returns once the preset is deleted.
597
+ * @throws {RemoteError} with the corresponding stable preset code and
598
+ * details when deletion is refused.
599
+ */
600
+ @Remote('deletePreset') async remoteExportDelete(id: string): Promise<void>
601
+
498
602
  /**
499
603
  * One agent's instance of a service its preset mounted.
500
604
  *
@@ -527,7 +631,9 @@ serviceFor<K extends string & keyof Context>(agent: { ctx: Context }, name: K):
527
631
  * state to restore. The re-link runs through the binding this roster kept
528
632
  * from the agent's mount — dsh-scope's only re-link authority. An agent
529
633
  * that never composed one has nothing to re-link: the switch is then the
530
- * agent's first bind, exactly a mount.
634
+ * agent's first bind, exactly a mount. A committed re-link emits
635
+ * `tools/change` because changing the parent scope changes the Agent's
636
+ * resolved tool set without adding or removing registry entries.
531
637
  * @param agentCtx - the agent's scope context.
532
638
  * @param id - the preset to compose the agent from instead.
533
639
  * @returns the preset now installed.
@@ -535,6 +641,16 @@ serviceFor<K extends string & keyof Context>(agent: { ctx: Context }, name: K):
535
641
  */
536
642
  async recompose(agentCtx: Context, id: string): Promise<AgentPreset>
537
643
 
644
+ /**
645
+ * Compose a blank session's agent from a different preset and record it.
646
+ * @param agent - the session's live agent, resolved from the wire identity.
647
+ * @param agentPreset - the preset to compose the agent from instead.
648
+ * @returns the preset id that was recorded.
649
+ * @throws {RemoteError} with `gateway/bad-request`, `agent-preset/locked`,
650
+ * `agent-preset/not-found`, or `agent-preset/invalid` when refused.
651
+ */
652
+ @Remote('select') async select(agent: Agent, agentPreset: string): Promise<string>
653
+
538
654
  /**
539
655
  * The standing scope key of one preset, for a host reader with no agent.
540
656
  *
@@ -729,6 +845,29 @@ Source: [`packages/core/agent/src/index.ts`](https://github.com/deepseek-ai/deep
729
845
 
730
846
  ### `agent/*` events
731
847
 
848
+ <a id="agentassistant-stream--emit"></a>
849
+
850
+ #### `agent/assistant-stream` — emit
851
+
852
+ Process-local assistant-stream publication. Chunk frames are transient; the loop appends one final v2 `assistant/message` or `assistant/attempt` with the same stream before a committed end frame.
853
+
854
+ ```ts cordis-catalog
855
+ /**
856
+ * Process-local assistant-stream publication. Chunk frames are transient;
857
+ * the loop appends one final v2 `assistant/message` or `assistant/attempt`
858
+ * with the same stream before a committed end frame.
859
+ * @param payload.agent - the agent whose attempt produced the frame.
860
+ * @param payload.frame - one ordered start, chunk, or end publication.
861
+ * Scope-filtered dispatch (`@deepseek-ai/dsh-scope`): agent-scoped listeners receive only that agent.
862
+ * @mode emit
863
+ */
864
+ 'agent/assistant-stream'(this: Scoped<Agent>, payload: { agent: Agent; frame: AssistantStreamFrame }): void
865
+ ```
866
+
867
+ Types: [Scoped](./scope.md)
868
+
869
+ Source: [`packages/core/agent/src/runtime-types.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/agent/src/runtime-types.ts)
870
+
732
871
  <a id="agentcreated--emit"></a>
733
872
 
734
873
  #### `agent/created` — emit
@@ -37,13 +37,17 @@ interface ResolvedCredential {
37
37
  `describe(ref)` answers configuration surfaces without ever exposing a value: whether the reference resolves, from which layer, and whether `set` would currently succeed. The local provider reports a reference supplied by the live process environment as `writable: false` — a write would appear to succeed while resolution kept returning the shadowing value, so the seam rejects it and the UI can render the reference read-only up front.
38
38
 
39
39
  ```ts type-equiv
40
- /** Source and writability facts for one reference, safe for configuration UIs — never the value. */
40
+ /**
41
+ * Source and writability facts for one reference, safe for configuration UIs —
42
+ * never the value. The view has no slot a value could ride in, which is what
43
+ * lets the whole read half cross the Remote wire.
44
+ */
41
45
  interface CredentialInfo {
42
- /** Whether {@link CredentialProvider.resolve} would currently return a value. */
46
+ /** Whether resolving the reference would currently return a value. */
43
47
  configured: boolean
44
48
  /** Source layer currently supplying the value; absent while unconfigured. */
45
49
  source?: string
46
- /** Whether {@link CredentialProvider.set} would currently succeed for this reference. */
50
+ /** Whether the active provider can write this reference. */
47
51
  writable: boolean
48
52
  }
49
53
  ```
@@ -215,6 +219,43 @@ abstract deleteRecord(key: CredentialKey): Promise<void>
215
219
 
216
220
  Source: [`packages/credentials/credentials/src/index.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/credentials/credentials/src/index.ts)
217
221
 
222
+ <a id="ctxcredentialscontroller--credentialscontroller"></a>
223
+
224
+ ### `ctx.credentialsController` — `CredentialsController`
225
+
226
+ Host service backing the generated `ctx.remote.credentials` namespace. It carries every wire obligation the credential seam itself does not: the batch fan-out bound, the field-by-field view projection, the reference-grammar guard, and the refusal mapping. Secret values cross in one direction only — no method here returns one.
227
+
228
+ ```ts cordis-catalog
229
+ /**
230
+ * Describe several references for one configuration surface. Batched because
231
+ * a settings page describes every reference its rows name at once, and one
232
+ * round trip keeps those rows from settling separately.
233
+ * @param refs - reference names, at most {@link MAX_DESCRIBE_REFS}; a name outside the grammar
234
+ * rejects the whole call as `gateway/bad-request`.
235
+ * @returns one view per requested name, keyed by that name.
236
+ * @throws RemoteError when the request is invalid or no credential provider is mounted.
237
+ */
238
+ @Remote async describe(refs: string[]): Promise<Record<string, CredentialInfo>>
239
+
240
+ /**
241
+ * Store one value from a configuration surface. The value crosses the wire in
242
+ * this direction only: no read path returns it.
243
+ * @param ref - reference name to store under.
244
+ * @param value - the non-empty secret value.
245
+ * @throws RemoteError when the request is invalid, no provider is mounted, or the provider refuses the write.
246
+ */
247
+ @Remote async set(ref: string, value: string): Promise<void>
248
+
249
+ /**
250
+ * Remove one reference from a configuration surface.
251
+ * @param ref - reference name to remove.
252
+ * @throws RemoteError when the request is invalid, no provider is mounted, or the provider refuses the write.
253
+ */
254
+ @Remote async unset(ref: string): Promise<void>
255
+ ```
256
+
257
+ Source: [`packages/api/settings-controller/src/credentials.ts`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/api/settings-controller/src/credentials.ts)
258
+
218
259
  <a id="authorization-events"></a>
219
260
 
220
261
  ### `authorization/*` events
@@ -15,7 +15,7 @@ Provider source: [`packages/fs/fs/src/types.ts`](https://github.com/deepseek-ai/
15
15
 
16
16
  Every operation resolves a user-supplied path to an opaque backend target first. Consumers may display `displayPath`, but must not parse `targetKey` (a branded opaque id) or assume it is a local absolute path.
17
17
 
18
- Consumers that share the filesystem's execution world obtain cross-capability coordinates through the provider instead of interpreting that identity: `processPath(target)` returns the canonical absolute path a subprocess can open, `fileUrl(target)` returns its provider-platform `file:` URI, and `contains(parent, child)` tests canonical identity or descendant containment.
18
+ Consumers that share the filesystem's execution world obtain cross-capability coordinates through the provider instead of interpreting that identity: `processPath(target)` returns the canonical absolute path a subprocess can open, `processPathFromHostPath(hostPath)` maps an absolute harness-host file only when that execution world shares it, `fileUrl(target)` returns its provider-platform `file:` URI, and `contains(parent, child)` tests canonical identity or descendant containment.
19
19
 
20
20
  ```ts type-equiv
21
21
  /**
@@ -278,7 +278,7 @@ type FsErrorCode =
278
278
 
279
279
  ## The service and the plugin
280
280
 
281
- `FileSystem` (`ctx.fs`, abstract) owns the provider primitives: `resolve`, `processPath`, `fileUrl`, `contains`, `stat`, `lstat`, `readText`, `streamText`, `readBytes`, `listDir`, `writeText`, and `editText`. `dsh-fs-observation-policy` registers **no service** — it is a plugin that adds policy through the `fs/*` event gate: it decides the write/edit intent waterfalls from unseen/absent/present state and records `FsObservation` values. The executor is `dsh-tool-fs`: it reads/writes/edits through `ctx.fs`, dispatches the waterfalls, and emits the recording event. The generated [`ctx.fs` section](#ctxfs--filesystem-abstract-seam) below shows the exact signatures.
281
+ `FileSystem` (`ctx.fs`, abstract) owns the provider primitives: `resolve`, `processPath`, `processPathFromHostPath`, `fileUrl`, `contains`, `stat`, `lstat`, `readText`, `streamText`, `readBytes`, `listDir`, `writeText`, and `editText`. `dsh-fs-observation-policy` registers **no service** — it is a plugin that adds policy through the `fs/*` event gate: it decides the write/edit intent waterfalls from unseen/absent/present state and records `FsObservation` values. The executor is `dsh-tool-fs`: it reads/writes/edits through `ctx.fs`, dispatches the waterfalls, and emits the recording event. The generated [`ctx.fs` section](#ctxfs--filesystem-abstract-seam) below shows the exact signatures.
282
282
 
283
283
  <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
284
284
 
@@ -316,6 +316,16 @@ abstract resolve(path: string, opts?: { cwd?: string; signal?: AbortSignal }): P
316
316
  */
317
317
  abstract processPath(target: FsTarget): string
318
318
 
319
+ /**
320
+ * Map an absolute path from the harness host into this filesystem's
321
+ * execution world when both paths identify the same file. The base provider
322
+ * exposes no mapping; host-backed or explicitly shared backends override it.
323
+ * @param hostPath - absolute path in the harness host filesystem.
324
+ * @returns the process path for the same file, or undefined when this
325
+ * execution world cannot read that host file.
326
+ */
327
+ processPathFromHostPath(hostPath: string): string | undefined
328
+
319
329
  /**
320
330
  * Return the canonical `file:` URI for a target in this filesystem's
321
331
  * execution world. Backends own URI encoding because the host platform may
@@ -145,7 +145,7 @@ interface GoalChanged {
145
145
 
146
146
  ## Service behavior
147
147
 
148
- [`GoalService`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/goal/goal/src/index.ts) resolves creation defaults, folds strict replay from durable `goal/change` events, enforces exact-live-agent identity and compare-and-set mutations, and emits contained `goal/changed` notifications. The package [README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/goal/goal/README.md) defines the callable API and model-visible contract.
148
+ [`GoalService`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/goal/goal/src/index.ts) resolves creation defaults, reads strict replay from the optionally registered `goal` projection, enforces exact-live-agent identity and compare-and-set mutations, and emits contained `goal/changed` notifications. Its first dependent access fails if the projection registry or key is absent. The package [README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/goal/goal/README.md) defines the callable API and model-visible contract.
149
149
 
150
150
  <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
151
151
 
@@ -16,9 +16,10 @@ One page per subsystem of the DeepSeek Harness: what it is, the data structures
16
16
  | [typert.md](./typert.md) | Remote invocation descriptors, lookup/Context declarations, Typert registries, and the Host Gateway/Client API boundaries |
17
17
  | [goal.md](./goal.md) | persisted goal identity, lifecycle snapshots, activation, change records, and round attribution |
18
18
  | [schedule.md](./schedule.md) | Session-local reminder records, durable transitions, active views, and ordinary-conversation delivery |
19
+ | [todo.md](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/todo.md) | the todo package's whole-list item type, durable event ownership, projection, and open-turn invariant |
19
20
  | [commands.md](./commands.md) | the human-command registry service: definitions, adapter discovery, direct invocation, results, and parsing views |
20
- | [session.md](./session.md) | the full `SessionEventMap` variant catalog, `TurnTrigger`/`TurnEndReason`, `deriveMessages()`, execution enclosure, and standalone events |
21
- | [persistence.md](./persistence.md) | the durability seam: `SessionPersistence`, JSONL + SQLite backends, `session/flush`, crash recovery, `SessionHeader` |
21
+ | [session.md](./session.md) | the full `SessionEventMap` variant catalog, `TurnEndReason`, `deriveMessages()`, execution enclosure, and standalone events |
22
+ | [persistence.md](./persistence.md) | the durability seam: `SessionPersistence`, the JSONL provider, `session/flush`, crash recovery, `SessionHeader` |
22
23
  | [settings.md](./settings.md) | the user-settings seam: `SettingsNamespace` registration, layered resolution (defaults → composition `base` → user document), owner scopes, hot commits |
23
24
  | [credentials.md](./credentials.md) | the credential seam: `CredentialRef` references (never values) in configuration, per-operation resolution, UI-safe `CredentialInfo`, provider source layers |
24
25
  | [session-query.md](./session-query.md) | logical records, bounded exact-event reads, relationship traces, semantic filters/documents, and full-text result pages |
@@ -50,9 +51,13 @@ One page per subsystem of the DeepSeek Harness: what it is, the data structures
50
51
  | [plan.md](./plan.md) | plan mode: the log-only `plan/mode` state, pending-selection flush, `PlanModeConfig`, the `exit_plan_mode` review arc |
51
52
  | [invariants.md](./invariants.md) | the runtime-invariant registry: selection `Config`, `InvariantInstaller`/`InvariantFailure`, the empty-companion contract |
52
53
  | [web-server.md](./web-server.md) | the HTTP carrier: `WebRouteKind`/`WebRoute`, match order, the claimable fallback seat, index taps |
54
+ | [webhook.md](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/webhook.md) | authenticated provider deliveries, arbitrary programmatic rules, and fire-and-forget Workspace Session creation |
53
55
  | [storage.md](./storage.md) | the storage subsystem: the backend contract (`StorageBackend`), `StorageForms`, `DomainSpec`/`Domain`, `domain/changed` |
54
56
  | [workspace.md](./workspace.md) | the workspace registry: `Workspace`/`WorkspaceId`, registration and resolution, the session `cwd` relationship |
57
+ | [web-client.md](./web-client.md) | the browser architecture: boot, Remote communication, paired Client models, UI adapters, Conversation assembly, Slots, and reconnect semantics |
55
58
  | [client-modules.md](./client-modules.md) | the web plugin table: `dsh.client` declarations, `WebBootGraph` wire composition, the bundle route and index tap |
59
+ | [slots.md](./slots.md) | typed Web UI composition: declaration ownership, cardinality and scope, framework and feature injection, props derivation, and the shipped hierarchy |
60
+ | [conversation.md](./conversation.md) | target-neutral Session-event assembly: Context identity, Location data, replay paths, view builders, and target-owned render nodes |
56
61
  | [session-projection.md](./session-projection.md) | the projection seam: `SessionProjectionMap`, the pure `ProjectionDefinition` unit, `ProjectionSnapshot`'s consistent cut, the change feed |
57
62
  | [session-telemetry.md](./session-telemetry.md) | the outbound session-reporting capability seam: `SessionTelemetryRecord`/`SessionTelemetrySeverity`, the `SessionTelemetrySink` contract, and the `session-telemetry/record` redact waterfall |
58
63
 
@@ -157,7 +157,7 @@ interface JobRead {
157
157
 
158
158
  ## Service behavior
159
159
 
160
- The abstract [`JobRegistry`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/jobs/jobs/src/index.ts) Service Definition specifies atomic `start`, caller-scoped `get` and `list`, `read`, `kill`, bounded `wait`, failure-isolated `onJobDone` and `onJobsChanged` listeners, and when `attachController` becomes available; [`LocalJobRegistry`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/jobs/jobs-local/src/index.ts) is the process-local Service Provider. Authorization compares owner sessions; owner cleanup and admission use the exact registered `Agent` instance. The local provider's positive-safe-integer `maxConcurrentJobsPerOwner` config defaults to `10` and counts `running` plus `stopping` records per exact owner, with one shared bucket for unowned jobs; terminal producer settlement releases capacity. See [`dsh-jobs`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/jobs/jobs/README.md) for the Service Definition contract, [`dsh-jobs-local`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/jobs/jobs-local/README.md) for the registry lifecycle and admission policy, and [`dsh-tool-jobs`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/jobs/tool-jobs/README.md) for the model-facing Consumer.
160
+ The abstract [`JobRegistry`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/jobs/jobs/src/index.ts) Service Definition specifies atomic `start`, caller-scoped `get` and `list`, `read`, `kill`, bounded `wait`, failure-isolated `onJobDone` and `onJobsChanged` listeners, and `attachController`; [`LocalJobRegistry`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/jobs/jobs-local/src/index.ts) is the process-local Service Provider. Authorization compares owner sessions; owner cleanup and admission use the exact registered `Agent` instance. The local provider's positive-safe-integer `maxConcurrentJobsPerOwner` config defaults to `10` and counts `running` plus `stopping` records per exact owner, with one shared bucket for unowned jobs; terminal producer settlement releases capacity. See [`dsh-jobs`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/jobs/jobs/README.md) for the Service Definition contract, [`dsh-jobs-local`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/jobs/jobs-local/README.md) for the registry lifecycle and admission policy, and [`dsh-tool-jobs`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/jobs/tool-jobs/README.md) for the model-facing Consumer.
161
161
 
162
162
  <!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
163
163