dsh-plugin-dev-kb 1.0.8 → 1.0.9
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.
- package/CHANGELOG.md +11 -0
- package/README.en.md +6 -6
- package/README.md +6 -6
- package/kb/INDEX.md +19 -5
- package/kb/README.md +11 -10
- package/kb/extra/AGENTS.md +4 -4
- package/kb/extra/cookbook/adding-a-vendored-package.md +2 -2
- package/kb/extra/cookbook/adding-a-vendored-package.zh.md +2 -2
- package/kb/extra/deepseek-llm-api-wire-extensions.md +159 -0
- package/kb/extra/deepseek-llm-api-wire-extensions.zh.md +159 -0
- package/kb/extra/development.md +8 -14
- package/kb/extra/development.zh.md +8 -14
- package/kb/extra/event-producer-consumer.md +47 -41
- package/kb/extra/event-producer-consumer.zh.md +47 -41
- package/kb/extra/glossary.md +1 -1
- package/kb/extra/glossary.zh.md +1 -1
- package/kb/extra/graph-atlas.md +0 -2
- package/kb/extra/graph-atlas.zh.md +0 -2
- package/kb/extra/i18n/README.md +4 -4
- package/kb/extra/i18n/README.zh.md +4 -4
- package/kb/extra/module-graph.md +680 -413
- package/kb/extra/module-graph.zh.md +681 -414
- package/kb/extra/postmortem/0001-acp-default-export-drops-inject.md +2 -2
- package/kb/extra/postmortem/0001-acp-default-export-drops-inject.zh.md +2 -2
- package/kb/extra/postmortem/0002-js-expression-disabled-filesystem-tools.md +2 -2
- package/kb/extra/postmortem/0002-js-expression-disabled-filesystem-tools.zh.md +2 -2
- package/kb/extra/postmortem/0003-web-agent-gui-feedback-loop.md +2 -2
- package/kb/extra/postmortem/0003-web-agent-gui-feedback-loop.zh.md +2 -2
- package/kb/extra/postmortem/0004-landlock-partial-notice-misclassified-child-failures.md +1 -1
- package/kb/extra/postmortem/0004-landlock-partial-notice-misclassified-child-failures.zh.md +1 -1
- package/kb/extra/rescope.md +2 -2
- package/kb/extra/rescope.zh.md +2 -2
- package/kb/extra/subsystems/agent-team.md +24 -1
- package/kb/extra/subsystems/agent-team.zh.md +24 -1
- package/kb/extra/subsystems/attachment.md +12 -4
- package/kb/extra/subsystems/attachment.zh.md +12 -4
- package/kb/extra/subsystems/extensions.md +18 -0
- package/kb/extra/subsystems/extensions.zh.md +18 -0
- package/kb/extra/subsystems/feedback.md +2 -2
- package/kb/extra/subsystems/feedback.zh.md +2 -2
- package/kb/extra/subsystems/todo.md +32 -0
- package/kb/extra/subsystems/todo.zh.md +32 -0
- package/kb/extra/subsystems/webhook.md +70 -0
- package/kb/extra/subsystems/webhook.zh.md +70 -0
- package/kb/extra/testing.md +11 -10
- package/kb/extra/testing.zh.md +8 -7
- package/kb/meta/search-index.json +269 -161
- package/kb/meta/site-pages.txt +182 -168
- package/kb/meta/source.json +5 -5
- package/kb/meta/topics.md +14 -6
- package/kb/site/develop/basic/publish.md +2 -2
- package/kb/site/develop/basic/tool.md +1 -1
- package/kb/site/develop/cordis-tutorial/07-into-the-harness.md +4 -4
- package/kb/site/develop/framework/events.md +1 -1
- package/kb/site/develop/practice/dynamic-cordis.md +17 -0
- package/kb/site/develop/practice/llm-adapter.md +3 -3
- package/kb/site/en/develop/basic/publish.md +2 -2
- package/kb/site/en/develop/basic/tool.md +1 -1
- package/kb/site/en/develop/cordis-tutorial/07-into-the-harness.md +4 -4
- package/kb/site/en/develop/framework/events.md +1 -1
- package/kb/site/en/develop/practice/dynamic-cordis.md +17 -0
- package/kb/site/en/develop/practice/llm-adapter.md +3 -3
- package/kb/site/en/guide/github-review.md +104 -0
- package/kb/site/en/guide/mcp-memory.md +103 -0
- package/kb/site/en/guide/python-sdk.md +80 -34
- package/kb/site/en/guide/schedule.md +21 -0
- package/kb/site/en/reference/agent-lifecycle.md +1 -1
- package/kb/{extra → site/en/reference}/api-gateway.md +11 -9
- package/kb/site/en/reference/capability-seams.md +115 -67
- package/kb/site/en/reference/config-catalog.md +358 -164
- package/kb/site/en/reference/cookbook/adding-a-package.md +2 -2
- package/kb/site/en/reference/cookbook/adding-a-settings-card.md +2 -2
- package/kb/site/en/reference/cookbook/adding-a-tool.md +11 -4
- package/kb/site/en/reference/cookbook/adding-an-llm-adapter.md +1 -1
- package/kb/site/en/reference/cookbook/extension-cookbook.md +6 -6
- package/kb/site/en/reference/cordis-api/inherited.md +1 -1
- package/kb/site/en/reference/cordis-primer.md +2 -1
- package/kb/site/en/reference/index.md +19 -7
- package/kb/site/en/reference/persistence-catalog.md +91 -44
- package/kb/site/en/reference/subsystems/approval.md +10 -10
- package/kb/site/en/reference/subsystems/client-modules.md +58 -16
- package/kb/site/en/reference/subsystems/code-runtime.md +3 -3
- package/kb/site/en/reference/subsystems/compaction.md +2 -2
- package/kb/site/en/reference/{cookbook/adding-a-conversation-node.md → subsystems/conversation.md} +43 -24
- package/kb/site/en/reference/subsystems/core.md +70 -12
- package/kb/site/en/reference/subsystems/credentials.md +43 -3
- package/kb/site/en/reference/subsystems/filesystem.md +12 -2
- package/kb/site/en/reference/subsystems/index.md +6 -1
- package/kb/site/en/reference/subsystems/jobs.md +1 -1
- package/kb/site/en/reference/subsystems/llm-streaming.md +132 -11
- package/kb/site/en/reference/subsystems/permission-presets.md +1 -1
- package/kb/site/en/reference/subsystems/persistence.md +22 -3
- package/kb/site/en/reference/subsystems/plan.md +1 -1
- package/kb/site/en/reference/subsystems/session-projection.md +74 -33
- package/kb/site/en/reference/subsystems/session-query.md +9 -1
- package/kb/site/en/reference/subsystems/session-reference.md +28 -7
- package/kb/site/en/reference/subsystems/session-telemetry.md +2 -3
- package/kb/site/en/reference/subsystems/session.md +260 -41
- package/kb/site/en/reference/subsystems/settings.md +78 -1
- package/kb/site/en/reference/subsystems/skills.md +23 -0
- package/kb/site/en/reference/subsystems/slots.md +177 -0
- package/kb/site/en/reference/subsystems/spill.md +2 -2
- package/kb/site/en/reference/subsystems/storage.md +9 -1
- package/kb/site/en/reference/subsystems/subagent.md +90 -23
- package/kb/site/en/reference/subsystems/system-prompt.md +4 -4
- package/kb/site/en/reference/subsystems/token-meter.md +25 -10
- package/kb/site/en/reference/subsystems/tools.md +39 -39
- package/kb/site/en/reference/subsystems/typert.md +44 -37
- package/kb/site/en/reference/subsystems/user-questions.md +33 -33
- package/kb/site/en/reference/subsystems/web-client.md +98 -0
- package/kb/site/en/reference/subsystems/web-server.md +11 -5
- package/kb/site/en/reference/subsystems/web.md +7 -1
- package/kb/site/en/reference/subsystems/workspace.md +95 -2
- package/kb/site/en/reference/tool-catalog.md +76 -18
- package/kb/site/en/reference/tool-execution-pipeline.md +1 -1
- package/kb/site/guide/github-review.md +104 -0
- package/kb/site/guide/mcp-memory.md +103 -0
- package/kb/site/guide/python-sdk.md +87 -41
- package/kb/site/guide/schedule.md +21 -0
- package/kb/site/reference/agent-lifecycle.md +1 -1
- package/kb/{extra/api-gateway.zh.md → site/reference/api-gateway.md} +11 -9
- package/kb/site/reference/capability-seams.md +115 -67
- package/kb/site/reference/config-catalog.md +357 -163
- package/kb/site/reference/cookbook/adding-a-package.md +2 -2
- package/kb/site/reference/cookbook/adding-a-settings-card.md +2 -2
- package/kb/site/reference/cookbook/adding-a-tool.md +11 -4
- package/kb/site/reference/cookbook/adding-an-llm-adapter.md +1 -1
- package/kb/site/reference/cookbook/extension-cookbook.md +6 -6
- package/kb/site/reference/cordis-api/inherited.md +1 -1
- package/kb/site/reference/cordis-primer.md +2 -1
- package/kb/site/reference/index.md +19 -7
- package/kb/site/reference/persistence-catalog.md +87 -40
- package/kb/site/reference/subsystems/approval.md +10 -10
- package/kb/site/reference/subsystems/client-modules.md +58 -16
- package/kb/site/reference/subsystems/code-runtime.md +3 -3
- package/kb/site/reference/subsystems/compaction.md +2 -2
- package/kb/site/reference/{cookbook/adding-a-conversation-node.md → subsystems/conversation.md} +43 -24
- package/kb/site/reference/subsystems/core.md +70 -12
- package/kb/site/reference/subsystems/credentials.md +43 -3
- package/kb/site/reference/subsystems/filesystem.md +12 -2
- package/kb/site/reference/subsystems/index.md +6 -1
- package/kb/site/reference/subsystems/jobs.md +1 -1
- package/kb/site/reference/subsystems/llm-streaming.md +132 -11
- package/kb/site/reference/subsystems/persistence.md +22 -3
- package/kb/site/reference/subsystems/plan.md +1 -1
- package/kb/site/reference/subsystems/session-projection.md +74 -33
- package/kb/site/reference/subsystems/session-query.md +9 -1
- package/kb/site/reference/subsystems/session-reference.md +28 -7
- package/kb/site/reference/subsystems/session-telemetry.md +2 -3
- package/kb/site/reference/subsystems/session.md +260 -41
- package/kb/site/reference/subsystems/settings.md +78 -1
- package/kb/site/reference/subsystems/skills.md +23 -0
- package/kb/site/reference/subsystems/slots.md +177 -0
- package/kb/site/reference/subsystems/spill.md +2 -2
- package/kb/site/reference/subsystems/storage.md +9 -1
- package/kb/site/reference/subsystems/subagent.md +90 -23
- package/kb/site/reference/subsystems/system-prompt.md +4 -4
- package/kb/site/reference/subsystems/token-meter.md +25 -10
- package/kb/site/reference/subsystems/tools.md +39 -39
- package/kb/site/reference/subsystems/typert.md +44 -37
- package/kb/site/reference/subsystems/user-questions.md +33 -33
- package/kb/site/reference/subsystems/web-client.md +98 -0
- package/kb/site/reference/subsystems/web-server.md +11 -5
- package/kb/site/reference/subsystems/web.md +7 -1
- package/kb/site/reference/subsystems/workspace.md +95 -2
- package/kb/site/reference/tool-catalog.md +76 -18
- package/kb/site/reference/tool-execution-pipeline.md +1 -1
- package/package.json +2 -2
- package/skills/dsh-plugin-dev-kb.md +8 -6
|
@@ -22,7 +22,7 @@ packages/<group>/<pkg>/
|
|
|
22
22
|
# (or a whitelist entry in scripts/verify-package-readme-limitations.ts)
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
Choose an existing group when one matches the package's role (`core`, `llm`, `
|
|
25
|
+
Choose an existing group when one matches the package's role (`core`, `llm`, `shell`, `compaction`, `subagent`, `todo`, `session`, `client`/`host`, `util`, or `test-support`). A new group is allowed, but it is a pure container: no `package.json`, no source files, and packages still sit exactly one level below it.
|
|
26
26
|
|
|
27
27
|
package.json invariants (enforced by `pnpm run constraints` / `scripts/check-workspace-constraints.ts`): `private: true`, a `version` matching the root `package.json`, `type: module`, `main: "lib/index.js"`, `types: "lib/types/index.d.ts"`, `exports["."].types: "./lib/types/index.d.ts"`, `exports["."].default: "./lib/index.js"`, `@deepseek-ai/cordis` in BOTH peerDependencies and devDependencies (same range). Mirror every dsh peer dependency in devDependencies. `@deepseek-ai/schemastery` goes in `dependencies` (it is a runtime validator), matching agent-loop. The `files` list contains exactly `lib/index.js`, `lib/invariant.js`, `lib/types/**/*.d.ts`, and package-specific runtime artifacts recognized by the gate; a package whose runtime export points into the emitted tree also includes `lib/types/**/*.js`. Do not publish `src`, declaration maps, JS maps, or stale root declaration files. CLI app packages with a package `bin` include `lib/bin.js` immediately after `lib/index.js` in `files`.
|
|
28
28
|
|
|
@@ -74,7 +74,7 @@ Use `SDK` only for the JSON-RPC client/server protocol used by the supported Pyt
|
|
|
74
74
|
|
|
75
75
|
## 4. Write the package README
|
|
76
76
|
|
|
77
|
-
Keep package-specific service API, config, events, extension points, and design notes first. The limitations section records durable consumer gaps and non-obvious maintainer constraints owned by this package; ordinary cleanup stays in its source TODO or Agent Note. An indirect Model Experience sentence may name the consumer that surfaces this package's contribution, but it does not restate that consumer's implementation. End a package README with this canonical sequence:
|
|
77
|
+
Keep package-specific service API, config, events, extension points, and design notes first. Choose the frontmatter `kind` from the four kind labels in the [dsh-doc metadata reference](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/skills/dsh-doc/references/metadata-links-i18n.md#the-kind-system) — group, reference, library, or bundle — matching the package's repository position and entry shape; each kind selects one README template. The limitations section records durable consumer gaps and non-obvious maintainer constraints owned by this package; ordinary cleanup stays in its source TODO or Agent Note. An indirect Model Experience sentence may name the consumer that surfaces this package's contribution, but it does not restate that consumer's implementation. End a package README with this canonical sequence:
|
|
78
78
|
|
|
79
79
|
````markdown
|
|
80
80
|
## Model Experience
|
|
@@ -50,7 +50,7 @@ export function apply(ctx: Context, config: Config) {
|
|
|
50
50
|
The card registers into `settings.plugin.item` under its namespace and owns everything inside it — chrome, controls, and copy. It reads and writes through `ctx.settingsScope`, which fences each write with the revision it read:
|
|
51
51
|
|
|
52
52
|
```ts ignore-check
|
|
53
|
-
import type { ClientContext } from '@deepseek-ai/
|
|
53
|
+
import type { Context as ClientContext } from '@deepseek-ai/cordis'
|
|
54
54
|
// Type-only: the keyed slot's declaration. Cross-plugin collaboration goes
|
|
55
55
|
// through cordis services; a value import fails the client bundle-purity gate.
|
|
56
56
|
import type {} from '@deepseek-ai/dsh-client-ui-settings-plugins/client'
|
|
@@ -99,4 +99,4 @@ import { clientBundle } from '../tsdown.client.ts'
|
|
|
99
99
|
export default clientBundle('@deepseek-ai/dsh-client-my-plugin', ['lib/types/index.js', 'lib/types/invariant.js'])
|
|
100
100
|
```
|
|
101
101
|
|
|
102
|
-
|
|
102
|
+
No published preset exposes this package, so a package outside this repository has to reproduce the same output format itself. The bundle-purity gate also rejects value imports across plugins, so a card cannot import this section's card chrome or its staged-form model — it renders its own, and owns its own staging and revision fencing. Both limits are recorded under [the section's known limitations](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/client/ui-settings-plugins/README.md#known-limitations-and-deferred-work).
|
|
@@ -52,7 +52,7 @@ Registration is effect-based: disposing the plugin fiber unregisters the tool. S
|
|
|
52
52
|
|
|
53
53
|
## Long-running work
|
|
54
54
|
|
|
55
|
-
Gate `run_in_background` with producer config, then register through `ctx.jobs.start({ kind, label, owner: exec.agent, run })`. The registry rejects a pre-aborted invocation before the producer body; the runtime validates ownership and task-controller availability before `run()` starts work, then supplies the id, session fence, generic control tools, notices, and owner cleanup. A successful background branch returns a typed canonical handle such as `{ kind: 'background', jobId }`; its Native renderer may keep human prose such as `started background job bash-1`, but
|
|
55
|
+
Gate `run_in_background` with producer config, then register through `ctx.jobs.start({ kind, label, owner: exec.agent, run })`. The registry rejects a pre-aborted invocation before the producer body; the runtime validates ownership and task-controller availability before `run()` starts work, then supplies the id, session fence, generic control tools, notices, and owner cleanup. A successful background branch returns a typed canonical handle such as `{ kind: 'background', jobId }`; its Native renderer may keep human prose such as `started background job bash-1`, but PTC mode must never parse that prose to recover the id.
|
|
56
56
|
|
|
57
57
|
The producer supplies synchronous `cancel`, non-rejecting `done` that settles after resource cleanup, and optional consuming `readOutput` with bounded-output formatting. A pre-aborted call is a failure because no task exists whose id could satisfy the successful output schema. Once `ctx.jobs.start()` publishes the id, use a task-owned cancellation signal rather than `exec.signal`: later outer-call cancellation stops waiting for the call but does not kill published work; `job_kill`, owner disposal, and service teardown own that lifetime. Foreground work remains coupled to `exec.signal`. See the [background job runtime Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-20-generic-long-running-tool-runtime.md) and `dsh-tool-bash` for a stream producer.
|
|
58
58
|
|
|
@@ -60,9 +60,9 @@ The producer supplies synchronous `cancel`, non-rejecting `done` that settles af
|
|
|
60
60
|
|
|
61
61
|
Prefer not to build deployment policy into the tool. Use `tools/pre-execute` for extensible allow/deny/ask policy (the [permission-gate example](./extension-cookbook.md#a-hook-plugin-permission-gate-example)), `ctx.tools.guard()` for a final monotonic deny that later listeners cannot undo, `tools/execute` to wrap dispatch with a deadline, retry, or metrics collection, `tools/post-execute` to replace presentation content or the returned value, block the result, or attach model-facing context, and `tools/result` to observe the immutable normalized outcome. A content replacement leaves programmatic access to `value` intact; confidentiality policy blocks or replaces the value. A sandboxing implementation can also run inside the tool's executor implementation; the [`dsh-tools` README](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/tools/README.md#extension-points) defines each extension point's inputs, order, return values, and failure behavior.
|
|
62
62
|
|
|
63
|
-
##
|
|
63
|
+
## PTC mode reaches your tool for free
|
|
64
64
|
|
|
65
|
-
In [
|
|
65
|
+
In [PTC mode](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/core/tools/README.md), every visible registered tool is available as `await tools.<name>(args)` without extra integration. The generated `ToolArgsMap` and `ToolOutputMap` derive exact argument and canonical-return types from the same schemas, and calls re-enter the normal execution pipeline. A successful call resolves to the final canonical JSON value after policy, not to rendered Native content. A failed call rejects with the real `ToolCallError`; programs can inspect only its `name`, `toolName`, and human-readable `message`, not internal error codes or a failure union.
|
|
66
66
|
|
|
67
67
|
Design `output.schema` as a useful programmatic API: return handles and fields directly, allow scalar/array/null roots when they are the honest value, and keep human explanation in `output.render`. Intermediate values are execution-local, are not persisted or prompt-truncated, and have no byte cap, so the producer's truthful acquisition bounds and process memory still matter. Only the outer `run_code` logs/result cross the configurable output cap and model-facing spill pipeline.
|
|
68
68
|
|
|
@@ -80,6 +80,7 @@ Both methods return a **`card`-tagged render intent** — pick the card kind tha
|
|
|
80
80
|
- `generic` supplies an optional title and content.
|
|
81
81
|
- `terminal` supplies raw output and optional exit metadata; each UI renders its capable or fallback view.
|
|
82
82
|
- `diff` supplies applied hunks, often derived by `output.presentationMeta` and carried in persisted `result.meta` so replay reproduces them. Mutation tools keep a diff result because the completed view replaces the pending card.
|
|
83
|
+
- `read` supplies a completed file window reconstructed from persisted `result.meta`: the file `path`, a 1-based `offset`, the returned `lines` (each keeping its file line number), `totalLines`, and an optional `lang` highlight hint; a UI without the `read` capability falls back to the raw result content. There is no `read` call view — a read call's pending state stays a generic card, since content exists only after `execute`. (tool-fs `read`.)
|
|
83
84
|
- `search` supplies a discovery result reconstructed from persisted `result.meta`: grouped-by-file matches (`shape: 'matches'`, grep) or a flat path list (`shape: 'paths'`, glob), plus `truncated`/`total` so a UI never presents a capped result as complete. The view carries no result text (a UI without a search card falls back to the raw result content), and there is no `search` call view — a discovery call's pending state stays a generic card, since matches exist only after `execute`. (tool-fs-search `grep`/`glob`.)
|
|
84
85
|
- `web` supplies a completed web retrieval, discriminated by `kind: 'search' | 'fetch'` (the structured search sources or the fetch summary), derived from `result.meta`; it carries no body copy, so a UI without the `web` capability falls back to the raw result content. (tool-web `web_search`/`web_fetch`.)
|
|
85
86
|
|
|
@@ -89,7 +90,13 @@ Hard rules (they bite if broken):
|
|
|
89
90
|
- **UI-only formatting stays out of the model result.** A fenced ` ```console ` block, a diff, a relativized path—none of these belongs in the canonical value or Native content merely to serve a UI. `output.render` owns model-facing prose; `presentationMeta` plus the card presenters own replayable UI state. A `terminal` result view carries raw output and the adapter adds any fallback framing.
|
|
90
91
|
- **`defineTool` soft-validates the display path.** Malformed or older logged arguments make the wrapper return `undefined` (a generic fallback) rather than throw — display must never crash a replay.
|
|
91
92
|
|
|
92
|
-
The neutral vocabulary lives in `dsh-tools`; tools never import a UI or transport type.
|
|
93
|
+
The neutral vocabulary lives in `dsh-tools`; tools never import a UI or transport type. Consumers of this API map each `card` into their own view. The design and the why are in [the render-intent-union Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-07-02-tool-render-intent-union.md); `dsh-tool-fs` (generic/diff) and `dsh-tool-bash` (terminal) are the reference implementations.
|
|
94
|
+
|
|
95
|
+
## Web Client presentation
|
|
96
|
+
|
|
97
|
+
The built-in Web Client does not consume `presentCall` or `presentResult`. Session `page` and `follow` transport raw `tool/call` and `tool/result` events, including persisted `result.meta`. A Client plugin registers its wire tool name in the `tool.call.toolview` keyed slot and derives component props from the `ToolCallBlock` arguments, content, error, metadata, existing Code Dispatch `parentCallId`, and Session path facts. It validates these wire values locally and returns the generic row for malformed or unsupported input.
|
|
98
|
+
|
|
99
|
+
Use `output.presentationMeta(args, value)` when an existing Web card needs bounded structured result facts that model-facing content cannot preserve losslessly. Do not store React props or a selected card in metadata, import a Host tool implementation into a browser bundle, or create another Client presenter registry. Defining Host presentation methods alone does not add a specialized Web card. The [Client-derived presentation Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-08-23-client-derived-tool-presentation.md) defines ownership, fallback, and equivalence requirements.
|
|
93
100
|
|
|
94
101
|
## Verification
|
|
95
102
|
|
|
@@ -31,7 +31,7 @@ Registration is effect-based (HMR-safe); one adapter per provider route — dupl
|
|
|
31
31
|
- Allocate block `index`es in first-seen stream order; reuse the index for every delta of the same block.
|
|
32
32
|
- Errors have exactly two sanctioned paths: THROW from `stream()` (transport and protocol failures — use `LlmError` with a stable code), or end the stream with `finish {kind: 'error' | 'aborted'}` (provider in-band failures). Consumers handle both; pick per failure class and document it.
|
|
33
33
|
- Honor `options.signal` (pass it to fetch / your SDK).
|
|
34
|
-
- A `GenerateOptions` field your provider cannot honor (e.g. a `stop` list on a provider without stop sequences): throw `LlmError(..., '
|
|
34
|
+
- A `GenerateOptions` field your provider cannot honor (e.g. a `stop` list on a provider without stop sequences): throw `LlmError(..., 'UNSUPPORTED_OPTION')` rather than silently dropping it.
|
|
35
35
|
- If the provider requires response ids, signatures, or other native metadata on follow-up calls, emit the minimal lossless-JSON projection as `finish.replayState`. Validate it when rebuilding history. `LlmRuntime` passes it only when the historical provider route and target provider route are currently owned by the exact same adapter instance; your adapter decides whether same-model, cross-model, or cross-provider restoration is legal. Never infer native replay from provider/model names alone when state is absent.
|
|
36
36
|
|
|
37
37
|
Provider-specific thinking-mode toggles remain in the adapter's Config. Exact model metadata uses one provider-neutral capability seam: implement `resolveModel()` with provider/model identity and optional `context` and `reasoning` fields, declare a configured `defaultEffort` only when one exists, and honor the resolver's optional `AbortSignal`. Reasoning efforts are ordered opaque ids mapped to provider requests by the adapter. Preserve the adapter's authoritative selectable list, including an adapter-defined `off` when supported, without exposing final wire spellings or clamping unsupported values; an id need not equal its wire representation.
|
|
@@ -32,11 +32,11 @@ export function apply(ctx: Context) {
|
|
|
32
32
|
}
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
This waterfall is the reorderable policy layer. Use `ctx.tools.guard()` when an invariant needs a monotonic final denial, `tools/execute` when a plugin must wrap the
|
|
35
|
+
This waterfall is the reorderable policy layer. Use `ctx.tools.guard()` when an invariant needs a monotonic final denial, `tools/execute` when a plugin must wrap the dispatch lifetime (timeouts/retries/metrics; only `exec.signal` is replaceable), `tools/post-execute` for explicit result transformation, and `tools/result` for contained observation of the immutable final outcome. The [adding-a-tool guide](./adding-a-tool.md#execution-policy-and-observation) gives the selection rule.
|
|
36
36
|
|
|
37
37
|
## A UI plugin
|
|
38
38
|
|
|
39
|
-
A UI plugin renders from the `session/event` feed (the assistant token stream as `assistant/chunk`, plus turn/step boundaries and tool activity), and drives input back in via `agent.followup()` / `agent.steer()`. A browser plugin contributing a business row to the built-in Web Client instead registers a `ConversationNodeDefinition` and keyed Chat renderer; follow the [Conversation
|
|
39
|
+
A UI plugin renders from the `session/event` feed (the assistant token stream as `assistant/chunk`, plus turn/step boundaries and tool activity), and drives input back in via `agent.followup()` / `agent.steer()`. A browser plugin contributing a business row to the built-in Web Client instead registers a `ConversationNodeDefinition` and keyed Chat renderer; follow the [Conversation subsystem reference](../subsystems/conversation.md).
|
|
40
40
|
|
|
41
41
|
```ts
|
|
42
42
|
import type { Context } from '@deepseek-ai/cordis'
|
|
@@ -92,13 +92,13 @@ export function apply(ctx: Context) {
|
|
|
92
92
|
|
|
93
93
|
## Runnable wirings
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
Shipped applications contribute profile layers through `packages/bundle/*/cordis.patch.yml`, and the product `dsh` launcher owns Web, ACP, SDK, and one-shot headless execution through named profiles. Optional user-facing overlays live under `apps/cli/config/examples/`; profile integration tests live under `apps/cli/tests/profiles/`, while package-specific Loader compositions stay with their package tests.
|
|
96
96
|
|
|
97
97
|
## The feature → mechanism map
|
|
98
98
|
|
|
99
99
|
Every product feature maps to a listener on a documented extension point — the microkernel claim made checkable ([microkernel Agent Note](https://github.com/deepseek-ai/deepseek-harness/blob/master/.agents/notes/implemented/architecture/2026-06-11-microkernel-event-taxonomy.md)). No row modifies the loop.
|
|
100
100
|
|
|
101
|
-
`system-prompt/assemble` is an expert cooperative whole-assembly transform: its returned assembly is authoritative, so listener authors own preserving active
|
|
101
|
+
`system-prompt/assemble` is an expert cooperative whole-assembly transform: its returned assembly is authoritative, so listener authors own preserving active PTC mode and structured-output protocol contributions. Prefer `ctx.tools.restrict()` for tool filtering that must stay aligned across presentation, lookup, and execution.
|
|
102
102
|
|
|
103
103
|
| Product feature | Plugin mechanism |
|
|
104
104
|
|---|---|
|
|
@@ -119,11 +119,11 @@ Every product feature maps to a listener on a documented extension point — the
|
|
|
119
119
|
| Subprocess sandbox (landlock / sandbox-exec) | use a `ctx.sandbox` backend through `dsh-bash-sandbox`; use `tools/pre-execute` for capability-level denial |
|
|
120
120
|
| Permission system / AskUserQuestion | return `ask` from `tools/pre-execute` and answer through `ctx.approval`; register a separate model-facing ask tool for ordinary user questions |
|
|
121
121
|
| Plan mode | [`@deepseek-ai/dsh-plan-mode`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/plan/plan-mode/README.md) — logged `plan/mode` state, the `plan:policy` guidance section, `/plan [message]` entry, `/plan off` direct exit, and the user-reviewed `exit_plan_mode` exit; enforcement stays on the independent sandbox/approval axes |
|
|
122
|
-
| Sub-agent delegation | the `ctx.subagents` provider registry (`dsh-subagent-spawn-in-process
|
|
122
|
+
| Sub-agent delegation | the `ctx.subagents` provider registry (`dsh-subagent-spawn-in-process`/`dsh-subagent-fork-in-process`/`dsh-subagent-acp`/`dsh-subagent-codex`/`dsh-subagent-claude-code`/`dsh-subagent-dsh-sdk`) + `dsh-tool-subagent` exposing one configured provider to the model |
|
|
123
123
|
| MCP | one plugin per server: discover tools → `ctx.tools.register()` |
|
|
124
124
|
| Skills | section + tool registration; `inject()` skill content on invocation |
|
|
125
125
|
| Memory | section provider + tool |
|
|
126
|
-
| Scheduled tasks (cron) | a plugin registers model-callable scheduling tools; timer fires → `followup(…, {source: {kind: '
|
|
126
|
+
| Scheduled tasks (cron) | a plugin registers model-callable scheduling tools; timer fires → `followup(…, {source: {kind: 'plugin', plugin: 'schedule'}})` when idle / `inject()` notification when busy |
|
|
127
127
|
| UI (GUI; CLI emits JSONL) | listen `session/event` (assistant chunks, boundaries, tool activity); input → `followup()` |
|
|
128
128
|
| Web Client Chat business node | register a `ConversationNodeDefinition` and `conversation.chat.node` keyed renderer |
|
|
129
129
|
| SessionTelemetryBackend / replayable trace | `session/event` → JSONL; replay = `sessions.create(id, { seed })` |
|
|
@@ -19,7 +19,7 @@ This file is GENERATED from source (`scripts/gen-cordis-catalog.ts`) and verifie
|
|
|
19
19
|
- `ctx.effect` — Register a disposable side effect tied to the fiber. ([`vendor/cordis/src/fiber.ts:9`](https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/cordis/src/fiber.ts))
|
|
20
20
|
- `ctx.get / ctx.set / ctx.provide / ctx.accessor / ctx.mixin` — Low-level service-store access and binding. ([`vendor/cordis/src/reflect.ts:7`](https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/cordis/src/reflect.ts))
|
|
21
21
|
- `ctx.extend / ctx.isolate / ctx.intercept` — Derive a child context (scoped services / isolation / interception). ([`vendor/cordis/src/context.ts:42`](https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/cordis/src/context.ts))
|
|
22
|
-
- `ctx.root / ctx.
|
|
22
|
+
- `ctx.root / ctx.fiber / ctx.registry / ctx.reflect / ctx.events / ctx.logger` — Ambient handles onto the running context graph. ([`vendor/cordis/src/context.ts:16`](https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/cordis/src/context.ts))
|
|
23
23
|
- `ctx.timer (+ interval / timeout / throttle / debounce)` — Disposable timer helpers. The `timer` key is provided at runtime; the four supported helpers are mixed onto ctx directly (declared via Pick). ([`vendor/timer/src/index.ts:4`](https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/timer/src/index.ts))
|
|
24
24
|
- `ctx.loader` — The config Loader that booted the app (present under the loader). ([`vendor/loader/src/index.ts:30`](https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/loader/src/index.ts))
|
|
25
25
|
- `ctx.hmr` — The hot-module-reload watcher (present under the hmr plugin). ([`vendor/hmr/src/index.ts:15`](https://github.com/deepseek-ai/deepseek-harness/blob/master/vendor/hmr/src/index.ts))
|
|
@@ -11,7 +11,7 @@ Cordis is the vendored plugin framework underneath DeepSeek Harness. This primer
|
|
|
11
11
|
- **A plugin is a object that implements Service.** It can be a function with optional `inject` and `apply(ctx)` fields, or a `Service` subclass whose lifecycle Cordis mounts into the current context.
|
|
12
12
|
- **A context is a repository of services.** A service claims a stable `ctx.<key>` such as `ctx.tools`, `ctx.llm`, or `ctx.sessions` from a context; other plugins find services via key instead of importing a concrete implementation.
|
|
13
13
|
- **Declare service dependency via `inject`.** A plugin that names required services waits until those services exist, so load order is expressed through service requirements rather than manual boot sequencing.
|
|
14
|
-
- **Typed Events for communication.** Services declare event names through TypeScript declaration merging, then dispatch them as `emit`, `waterfall`, `parallel`, or `
|
|
14
|
+
- **Typed Events for communication.** Services declare event names through TypeScript declaration merging, then dispatch them as `emit`, `waterfall`, `parallel`, `serial`, or `bail` depending on whether listeners observe, wrap, fan out, run in order, or stop at the first bail value.
|
|
15
15
|
- **Registrations are reversible effects.** Prompt sections, tool schemas, adapters, providers, and listeners are installed through `ctx.effect()` or `ctx.on()` so reload and teardown unwind them predictably.
|
|
16
16
|
|
|
17
17
|
## Dispatch Modes
|
|
@@ -24,6 +24,7 @@ Every event can have one of the following dispatch mode and can only be dispatch
|
|
|
24
24
|
| `waterfall` | No | listeners observe in registration order | Yes |
|
|
25
25
|
| `parallel` | Yes | all listeners observe the event in parallel | No |
|
|
26
26
|
| `serial` | Yes | listeners observe in registration order | Yes |
|
|
27
|
+
| `bail` | No | listeners observe in registration order until one bails | Yes |
|
|
27
28
|
|
|
28
29
|
The dispatch mode is part of the event's public contract. New harness events document it with an `@mode` tag so the generated catalog can check declarations against dispatch sites.
|
|
29
30
|
|
|
@@ -10,7 +10,7 @@ We recommend using an agent to explore the codebase and understand its architect
|
|
|
10
10
|
|
|
11
11
|
## Cordis
|
|
12
12
|
|
|
13
|
-
[Cordis](./cordis-primer.md) is the framework under dsh: plugins contribute services, typed events, and reversible effects to a shared context. Every part of the product is a plugin, including the model adapter, the tool registry, the session log, and the agent loop itself, so
|
|
13
|
+
[Cordis](./cordis-primer.md) is the framework under dsh: plugins contribute services, typed events, and reversible effects to a shared context. Every part of the product is a plugin, including the model adapter, the tool registry, the session log, and the agent loop itself, so each is replaceable from configuration.
|
|
14
14
|
|
|
15
15
|
There is no privileged core to patch: you extend dsh by mounting a plugin beside the others, and registrations are effects that unwind when their plugin unloads.
|
|
16
16
|
|
|
@@ -18,17 +18,19 @@ There is no privileged core to patch: you extend dsh by mounting a plugin beside
|
|
|
18
18
|
|
|
19
19
|
A running `dsh` is a plugin tree composed at boot from ordered layers.
|
|
20
20
|
|
|
21
|
-
A **profile** is a named composition stored in the Harness home. It lists the bundles it stacks, holds any out-of-tree plugins it installs, and keeps the user's own `cordis.patch.yml`. `web` and `
|
|
21
|
+
A **profile** is a named composition stored in the Harness home. It lists the bundles it stacks, holds any out-of-tree plugins it installs, and keeps the user's own `cordis.patch.yml`. `web`, `headless`, `sdk`, `sdk-minimal`, and `acp` ship as templates.
|
|
22
22
|
|
|
23
23
|
A **bundle** is a distribution format for Cordis config rows and the code they mount, so whatever it inserts stays patchable by the layers above it.
|
|
24
24
|
|
|
25
25
|
Each declares itself in its own `package.json` under a `dsh` field: `dsh.profile` lists a profile's bundles, and `dsh.bundle` points at a bundle's patch file.
|
|
26
26
|
|
|
27
|
-
[`dsh-base`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/base/README.md) is the first layer of
|
|
27
|
+
[`dsh-base`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/base/README.md) is the shared first layer of the `web`, `headless`, `sdk`, and `acp` profiles: model adapters, tools, persistence, sandbox and approval policy, settings, credentials, telemetry. [`dsh-web-app`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/web-app/README.md) adds the browser application, [`dsh-headless`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/headless/README.md) adds a one-shot runner with no server, [`dsh-sdk-app`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/sdk-app/README.md) adds the SDK JSON-RPC server, and [`dsh-acp-app`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/acp-app/README.md) adds the automation-only ACP server. [`dsh-sdk-minimal`](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/bundle/sdk-minimal/README.md) is the deliberate exception: one bundle owns its complete explicit SDK tree and does not apply `dsh-base`.
|
|
28
28
|
|
|
29
29
|
Layers apply to an empty entry list in this order: each bundle in the profile's listed order, then the profile's `cordis.patch.yml`, then the home-level one, then any `--patch` overlay. A patch targets a row by id and replaces its whole config, or inserts new rows.
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
Custom profiles default to live patch reload. The shipped `web` profile is live; `headless`, `sdk`, `sdk-minimal`, and `acp` apply all layers once at startup because replacing a one-shot or stdio application's dependencies after it owns work would invalidate that lifecycle.
|
|
32
|
+
|
|
33
|
+
To see the tree your machine boots:
|
|
32
34
|
|
|
33
35
|
```sh
|
|
34
36
|
dsh --profile web --dump-config
|
|
@@ -38,6 +40,14 @@ Any row it prints can be replaced by a patch of your own.
|
|
|
38
40
|
|
|
39
41
|
Composition mechanics are in [app-boot](https://github.com/deepseek-ai/deepseek-harness/blob/master/packages/boot/app-boot/README.md#profiles); config fields are in the generated [config catalog](./config-catalog.md).
|
|
40
42
|
|
|
43
|
+
## Application launch
|
|
44
|
+
|
|
45
|
+
Every supported Node application starts at the `dsh` CLI with a named profile. The shipped applications are `dsh web` (the deliberate alias for `--profile web`), `dsh --profile headless`, `dsh --profile sdk`, `dsh --profile sdk-minimal`, and `dsh --profile acp`. The TypeScript SDK resolves its same-version `dsh` dependency and selects `sdk`; custom plugin composition remains a profile plus ordered patch files, not another executable or inline application tree. `sdk-minimal` is a repository-owned standalone bundle behind the same launcher, not a caller-supplied Cordis tree.
|
|
46
|
+
|
|
47
|
+
Vendored CLIs, build-only and test-only executables, direct in-process plugin mounting, and the private browser WebWorker preview are not Harness application launchers. [`verify-application-entrypoints`](https://github.com/deepseek-ai/deepseek-harness/blob/master/scripts/verify-application-entrypoints.ts) keeps every package bin, executable source, and root demo in an explicit class and rejects a Node application path that bypasses `dsh`.
|
|
48
|
+
|
|
49
|
+
The Python SDK follows the same application architecture. Its runtime wheel packages the normal `dsh` CLI as `deepseek-harness-sdk-runtime-<platform>-<arch>`, and the client launches `dsh --profile sdk` with an explicit Harness home by default. The minimal example selects the shipped `sdk-minimal` profile. Python exposes profile selection and ordered patch files rather than a complete Cordis tree; persistent external plugins are installed through `dsh plugin`. The removed private direct-config carrier has no compatibility bin or fallback parser.
|
|
50
|
+
|
|
41
51
|
## Core packages
|
|
42
52
|
|
|
43
53
|
Here are some core packages that contribute to the Cordis tree.
|
|
@@ -51,6 +61,7 @@ Here are some core packages that contribute to the Cordis tree.
|
|
|
51
61
|
| [`core/agent-loop`](./subsystems/core.md) | The default driver implementing that interface | `ctx.agentLoop` |
|
|
52
62
|
| [`core/scope`](./subsystems/scope.md) | The per-agent scoped-registration primitive | library, no key |
|
|
53
63
|
| [`llm/llm`](./subsystems/llm-streaming.md) | Message and stream vocabulary plus the adapter seam | `ctx.llm` |
|
|
64
|
+
| [`webhook/webhook`](https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/webhook.md) | Authenticated-delivery dispatch and Workspace Session creation | `ctx.webhookRuntime` |
|
|
54
65
|
|
|
55
66
|
## Events
|
|
56
67
|
|
|
@@ -70,7 +81,7 @@ A **step** is one model request plus the tools it calls. A **turn** is zero or m
|
|
|
70
81
|
turn/start
|
|
71
82
|
claim next-step input plus one queued message
|
|
72
83
|
assemble prompt sections + tool schemas
|
|
73
|
-
-> agent/pre-step reject | enter(messages)
|
|
84
|
+
-> agent/pre-step reject | enter(messages, startsRequestSeries?)
|
|
74
85
|
reject, or a first enter rewritten empty -> close the turn with no step
|
|
75
86
|
step/start
|
|
76
87
|
append entered messages as user/message
|
|
@@ -87,7 +98,7 @@ turn/end
|
|
|
87
98
|
|
|
88
99
|
Input reaches the driver through one inbox. Some messages wake it immediately; injected context waits in the inbox until another message does.
|
|
89
100
|
|
|
90
|
-
`agent/pre-step` decides what the model sees. Listeners may rewrite the claimed messages or reject them outright; a rejected or empty first claim still closes a durable turn that spent no step, so the log records the attempt. Each step reads the prompt sections and tool schemas that plugins registered.
|
|
101
|
+
`agent/pre-step` decides what the model sees. Listeners may rewrite the claimed messages or reject them outright; a rejected or empty first claim still closes a durable turn that spent no step, so the log records the attempt. An enter decision may also set `startsRequestSeries` to begin a distinct model-message series: the loop then logs a fresh `request/header` (reason `series`, or `change` carrying `startsSeries: true` when the envelope changed too). A listener that rebuilds a downstream enter decision must spread it (`{ ...decision, messages }`) so the declaration survives. Each step reads the prompt sections and tool schemas that plugins registered.
|
|
91
102
|
|
|
92
103
|
Details: the [sequence diagram](./agent-lifecycle.md), the [tool pipeline](./tool-execution-pipeline.md), and [cancellation and error recovery](./subsystems/core.md#the-agent-handle).
|
|
93
104
|
|
|
@@ -118,6 +129,7 @@ New behavior attaches to a documented extension point. Changing the loop itself
|
|
|
118
129
|
| Add persistent terminal execution | register a `ctx.terminals` backend plus `dsh-tool-terminal` |
|
|
119
130
|
| Add a human command | register on `ctx.commands`; it dispatches without a model turn |
|
|
120
131
|
| Add background work | register on `ctx.jobs`; `job_*` tools collect or stop it |
|
|
132
|
+
| Start a Session from an external webhook | register a trusted rule on `ctx.webhookRuntime` and mount a provider adapter |
|
|
121
133
|
| Add filesystem access or policy | register a `ctx.fs` provider or listen to `fs/*` events |
|
|
122
134
|
| Confine spawned processes | use a `ctx.sandbox` backend; consumers wrap argv before spawning |
|
|
123
135
|
| Intercept a request, tool, or turn | use its `agent/*` or `tools/*` event; `agent/turn-stopping` stops a turn |
|
|
@@ -130,4 +142,4 @@ New behavior attaches to a documented extension point. Changing the loop itself
|
|
|
130
142
|
| Fork a live session | `ctx.sessions.fork(source, boundary?, childSessionId?)` |
|
|
131
143
|
| Scope a registration to one agent | use that agent's `agent.ctx` |
|
|
132
144
|
|
|
133
|
-
The [extension cookbook](./cookbook/extension-cookbook.md) maps features to capabilities and indexes the step-by-step guides for [packages](./cookbook/adding-a-package.md), [tools](./cookbook/adding-a-tool.md), [LLM adapters](./cookbook/adding-an-llm-adapter.md), [
|
|
145
|
+
The [extension cookbook](./cookbook/extension-cookbook.md) maps features to capabilities and indexes the step-by-step guides for [packages](./cookbook/adding-a-package.md), [tools](./cookbook/adding-a-tool.md), [LLM adapters](./cookbook/adding-an-llm-adapter.md), and [settings cards](./cookbook/adding-a-settings-card.md). The [Conversation subsystem](./subsystems/conversation.md) owns Chat-node assembly.
|