Tool Schema Catalog
Every model-facing tool a shipped plugin contributes to ctx.tools: the name, description, and JSON-Schema parameters the model receives via the system-prompt assembly. It complements the subsystem pages (the types plus each page's generated Cordis API region) — this page is the tools the agent is offered.
This file is GENERATED and verified fresh by pnpm run verify-tool-catalog (part of doc-sync) — do not edit it by hand. Unlike the cordis catalog (a pure source-AST pass), this generator BOOTS each tool plugin on a real context and reads ctx.tools.schemas(), because a tool schema is not statically knowable (runtime-spread enums, concatenated descriptions, config-driven names, raw-JSON-Schema MCP tools). A completeness guard globs packages/*/tool-* and fails if any package is missing from the generator's boot manifest, so a new tool cannot be silently undocumented. See the tool-schema-catalog Agent Note.
Scope: shipped product tools under packages/*/tool-*, each booted with its DEFAULT config, except where a Config field is REQUIRED with no default — there the generator must choose, and the per-package note records which branch this page shows. The registered tool NAME can be a load-time config (e.g. tool-subagent's toolName), so a deployment may expose a package under a different or additional name — a per-package note records those shipped aliases where they exist. The examples/ demo tools (e.g. echo) are excluded, matching the cordis catalog's packages-only scope.
Tool Package Map
This table connects model-visible tool names to the plugin package and service seams behind them. Exact JSON Schemas follow in the package sections below.
| Tool package | Model-visible names | Requires | Writes / affects | Shipped aliases | Deployment note |
|---|---|---|---|---|---|
@deepseek-ai/dsh-tool-ask-user | ask_user_question | ctx.tools, ctx.userQuestions | tool/call, tool/result after a UI/provider answers the question | - | ask_user_question pauses the tool call until the active UI provider returns a human answer. |
@deepseek-ai/dsh-tools | run_code | ctx.tools, ctx.codeRuntime (execution time), ctx.systemPrompt | tool/call, one tool/code-dispatch-start + tool/code-dispatch pair per bridged sub-call, tool/result | - | Owned by the tool registry as a reserved transport outside filterable capability layers under mode: code / mode: both (see the Code Mode Agent Note). Under code it is the registry's only wire contribution; the other visible capabilities are declared in a generated SDK section in the loaded runtime's language, and a program calls them through bindings scheduled under the native concurrency contract (submission-ordered starts and policy; concurrency-safe bodies overlap up to maxParallelSubCalls) that re-enter the complete guarded tool pipeline and link each nested execution to this outer result. |
@deepseek-ai/dsh-plan-mode | exit_plan_mode | ctx.tools, ctx.systemPrompt, ctx.userQuestions (execution time, opportunistic) | tool/call, plan/mode inactive on an approved review, tool/result | - | exit_plan_mode stays in the model-facing schema while planning is inactive so transitions add no tool-catalog churn on top of the plan-policy change. Its execute path rejects calls outside plan mode; in plan mode it presents the plan over the user-questions seam (approve / keep planning with feedback), and approval logs plan mode inactive at the step boundary. |
@deepseek-ai/dsh-tool-bash | bash | ctx.tools, ctx.shell, ctx.systemPrompt, ctx.shellEnv, ctx.jobs at call time for run_in_background | tool/call, tool/result | - | The bash tool is the model-facing consumer of the bash executor seam. A run_in_background run registers with the generic ctx.jobs runtime and is collected/stopped through the job_* tools from @deepseek-ai/dsh-tool-jobs; the enableRunInBackground config (default true) removes the parameter entirely when disabled. |
@deepseek-ai/dsh-tool-pwsh | pwsh | ctx.tools, ctx.shell, ctx.systemPrompt, ctx.shellEnv, ctx.jobs at call time for run_in_background | tool/call, tool/result | - | The pwsh tool is the PowerShell-dialect consumer of the bash executor seam for Windows compositions (a PowerShell executor such as @deepseek-ai/dsh-pwsh-local backs ctx.shell); it mirrors the bash tool call-for-call minus sandbox controls — run_in_background runs register with the generic ctx.jobs runtime and are collected/stopped through the job_* tools, and the managed DSH_* environment comes from @deepseek-ai/dsh-shell-env. Each call runs in a fresh process (no persistent PTY session), with native C:\... paths and $env:NAME variables. |
@deepseek-ai/dsh-tool-cordis | cordis_define, cordis_inspect_list, cordis_inspect_query, cordis_inspect_self, cordis_run, cordis_stop, cordis_undefine | ctx.tools, ctx.dynamicCordisRunner | tool/call, tool/result, process-local dynamic package lifecycle | - | Not in any shipped tree (a deliberate opt-in — dynamic package code reaches the real runtime, see .agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md). The toolset injects ctx.dynamicCordisRunner from @deepseek-ai/dsh-cordis-host-runner, which owns the definition registry and the vm sandbox; a composition missing it never activates the tools. A running package may register ADDITIONAL model-visible tools until it is stopped, undefined, or DSH restarts; a full changed request header logs those tool-set changes. |
@deepseek-ai/dsh-tool-bash-persistent | bash | ctx.tools, ctx.terminals, an owning Agent at execution time | tool/call, PTY shell state, tool/result | - | One owner-isolated persistent bash tool; deployment composition supplies the PTY backend and may override the model-facing environment description. |
@deepseek-ai/dsh-tool-str-replace-editor | str_replace_editor | ctx.tools, ctx.fs | tool/call, fs/observed after view presence/absence, edit absence, or successful mutation, tool/result | - | Standalone view/create/unique literal replace/line insert tool over the filesystem seam; it composes with any shell or terminal API. |
@deepseek-ai/dsh-tool-fs | edit, read, read_image, write | ctx.tools, ctx.fs, ctx.systemPrompt, ctx.attachments (read_image registration), ctx.llm + an image-capable route (read_image execution) | tool/call, fs/write-intent or fs/edit-intent for mutations, fs/observed after read presence/absence or successful file operation, durable attachment (read_image), tool/result | - | The read-before-write/edit policy is added by @deepseek-ai/dsh-fs-observation-policy (an fs/* event-gate plugin, no schema change); a deployment that loads these tools is expected to also load it. read_image is not registered without ctx.attachments; its schema is route-independent, and execution refuses unless the exact routed model declares image input. |
@deepseek-ai/dsh-tool-fs-search | glob, grep | ctx.tools, ctx.subprocess, ctx.systemPrompt | tool/call, tool/result | - | glob and grep are unconditional discovery tools that spawn the packaged ripgrep binary (@vscode/ripgrep) through ctx.subprocess as ordinary foreground calls (never background jobs) — no host rg install and no shell layer. The catalog uses sampleOverCapGlobResults: true; deployments must choose that behavior explicitly. Capped results save the complete formatted list through the optional ctx.spillStore backend; returned locators are follow-up-readable/searchable when the backend exposes local paths in co-located deployments. |
@deepseek-ai/dsh-tool-terminal | terminal_close, terminal_list, terminal_open, terminal_read, terminal_send, terminal_signal | ctx.tools, ctx.terminals, ctx.systemPrompt, ctx.jobs at call time for run_in_background | tool/call, tool/result | - | The six terminal tools are opt-in and complement one-shot shell/filesystem tools. terminal_send(run_in_background: true) registers with ctx.jobs; TUI, named key sequences, BEL, resize, auto-start, and cross-agent sharing are absent from the schema. |
@deepseek-ai/dsh-tool-goal | create_goal, get_goal, update_goal | ctx.tools, ctx.agents, ctx.goals, ctx.systemPrompt, a calling Agent in an authorized open turn | tool/call, goal/change for mutations, tool/result | - | create, edit, pause, and resume require direct-human root authority; complete and blocked also accept the exact current goal round. The default blocked lower bound is three admitted rounds. |
@deepseek-ai/dsh-schedule | schedule_create, schedule_delete, schedule_list | ctx.tools, ctx.sessions, Session persistence, a future live root Agent | tool/call, schedule/change create or delete, tool/result | - | Registered only inside live root Agent scopes created after the opt-in Schedule plugin loads. Version 1 accepts after_seconds, explicit absolute at, and bounded fixed-rate every_seconds, and discloses session-local delivery; management reads and mutations require the shared Session persistence barrier. |
@deepseek-ai/dsh-tool-lsp | lsp | ctx.tools, ctx.lsp, ctx.systemPrompt | tool/call, tool/result | - | The lsp tool keeps provider selection and language-server subprocesses behind ctx.lsp, so its model-visible schema stays stable across providers. Requires a registered provider (e.g. @deepseek-ai/dsh-lsp-stdio) at runtime; without one, a query returns the structured LSP_UNAVAILABLE error rather than changing the schema. |
@deepseek-ai/dsh-tool-ralph | ralph | ctx.tools, ctx.workflowEngine, ctx.subagents, ctx.systemPrompt, a calling Agent (exec.agent parents every fresh round) | tool/call, tool/result, workflow and child session events during execution | - | A fixed foreground workflow starts one fresh structured child per round; the model selects only the immutable objective and an optional round cap. |
@deepseek-ai/dsh-tool-skill | skill | ctx.tools, ctx.agents, ctx.skills | tool/call, tool/result, user/message replacement catalogs via agent.inject() | - | - |
@deepseek-ai/dsh-tool-session-query | session_event_read, session_event_search, session_event_trace, session_search, session_trace | ctx.tools, ctx.systemPrompt, ctx.sessionQuery, a calling Agent for workspace authority | tool/call, tool/result | - | The five read-only tools hide provider cursors and authorize every result from the immutable calling agent session. The package is opt-in; compositions that need enforced deadlines or bounded inline output also mount the generic timeout or spill policies. |
@deepseek-ai/dsh-tool-subagent | subagent | ctx.tools, ctx.subagents, ctx.systemPrompt | tool/call, tool/result, child session events through the chosen provider | subagent, subagent_fork | The registered tool name is the load-time toolName config (default subagent); the schema above is that default. The shipped compositions load this package once per subagent backend, so the model additionally sees subagent_fork bound to the fork backend. Each instance's description, run_in_background parameter, and system-prompt policy follow its own backgroundMode and enableRunInBackground, so the two shipped schemas are not identical: subagent is continuable and defaults omitted calls to background with automatic settlement delivery, while subagent_fork stays one-shot and defaults them to foreground — see packages/bundle/base/cordis.patch.yml and examples/acp-agent/cordis.yml. |
@deepseek-ai/dsh-tool-subagent-control | interrupt_agent, list_agents, send_message | ctx.tools, ctx.subagents, ctx.agents and ctx.sessionProjections (list_agents only) | tool/call, tool/result, child session events through ctx.subagents | - | The globally named control tools over continuable background subagents: provider-bound tool-subagent instances register distinct delegation tools, while this package registers send_message and interrupt_agent once, plus list_agents from its separately loaded /list-agents plugin (whose catalog rows use the sessionProjections and live Agent registries). |
@deepseek-ai/dsh-tool-subagent-report | report | ctx.subagents, ctx.systemPrompt, a live continuable in-process child Agent | tool/call, tool/result, a user-role message in the direct parent session | - | Registered per continuable in-process child rather than globally, so this schema is visible only inside such a child and survives its global toolFilter. The same contribution installs the child-scoped tool:report prompt section, which this catalog does not render. The parent-facing send_message tool is installed independently. |
@deepseek-ai/dsh-tool-jobs | job_kill, job_list, job_output | ctx.tools, ctx.jobs, ctx.systemPrompt | tool/call, tool/result, user/message via agent.inject() for background completion notices | - | The kind-agnostic background-job controller: background bash commands, PTY sends, and subagents are read, listed, and killed through the same three tools. Loading the plugin attaches the controller that arms producers' ctx.jobs.start(). |
@deepseek-ai/dsh-tool-todo | todo_write | ctx.tools, owning Agent session | tool/call, todo/write, tool/result | - | todo_write is session-owned state; UIs render the latest todo/write event as a checklist. allowParallelInProgress is required with no default, so the catalog states its choice: true, whose description invites several in_progress items. A deployment choosing false receives the same tool with a description asking for exactly one active task. |
@deepseek-ai/dsh-tool-workflow | workflow | ctx.tools, ctx.workflowEngine, ctx.systemPrompt, a calling Agent (exec.agent parents the script children) | tool/call, tool/result | - | - |
@deepseek-ai/dsh-tool-web | web_fetch, web_search | ctx.tools, ctx.web, ctx.systemPrompt | tool/call, tool/result | - | web_search and web_fetch keep provider selection behind ctx.web so model-visible schemas stay stable across backend swaps. |
@deepseek-ai/dsh-tool-ask-user
ask_user_question
Ask the user a concise question when you need confirmation, a choice, or missing information before proceeding. Send one or more questions, each with a stable id that will be echoed in the answer.
{
"type": "object",
"properties": {
"questions": {
"type": "array",
"description": "Questions to ask the user before continuing.",
"items": {
"type": "object",
"additionalProperties": true,
"properties": {
"id": {
"type": "string",
"description": "Stable id for this question; echoed in the answer."
},
"question": {
"type": "string",
"description": "The specific question to ask the user."
},
"header": {
"type": "string",
"description": "Optional short heading for the question, such as \"Confirm\" or \"Choose Mode\"."
},
"options": {
"type": "array",
"description": "Optional choices to show the user. If you recommend one, put it first and append \"(Recommended)\" to that label.",
"items": {
"type": "object",
"additionalProperties": true,
"properties": {
"label": {
"type": "string",
"description": "Short user-facing option label."
},
"description": {
"type": "string",
"description": "One sentence explaining the tradeoff or impact."
}
},
"required": [
"label"
]
}
},
"multi_select": {
"type": "boolean",
"description": "Whether the user may select more than one option. Defaults to false."
}
},
"required": [
"id",
"question"
]
}
}
},
"required": [
"questions"
]
}Source: packages/interaction/tool-ask-user/src/index.ts
ask_user_question pauses the tool call until the active UI provider returns a human answer.
@deepseek-ai/dsh-tools
run_code
Execute a TypeScript program against the available tools. Takes two required arguments: code, the BODY of an async function (erasable syntax only; top-level await and return work), and description, a short summary of what the program does. Call tools as await tools.name(args) per the declarations in the system prompt. Only what you print or return comes back — curate it.
{
"type": "object",
"properties": {
"code": {
"type": "string",
"description": "The program: the body of an async TypeScript function."
},
"description": {
"type": "string",
"description": "Clear, concise description of what this program does in active voice, 5-10 words (shown in the UI). Examples: \"Count TODO markers across packages\"; \"Read failing test and its fixture\"; \"Rename config key in every cordis.yml\"."
}
},
"required": [
"code",
"description"
]
}Source: packages/core/tools/src/code-mode.ts
Owned by the tool registry as a reserved transport outside filterable capability layers under mode: code / mode: both (see the Code Mode Agent Note). Under code it is the registry's only wire contribution; the other visible capabilities are declared in a generated SDK section in the loaded runtime's language, and a program calls them through bindings scheduled under the native concurrency contract (submission-ordered starts and policy; concurrency-safe bodies overlap up to maxParallelSubCalls) that re-enter the complete guarded tool pipeline and link each nested execution to this outer result.
@deepseek-ai/dsh-plan-mode
exit_plan_mode
Use only in plan mode. Present your plan for the user's review and, on approval, leave plan mode. Send the COMPLETE plan as markdown, starting with a # heading that names it. The user may approve (carry out the plan from your next step) or keep planning — their feedback comes back in the tool result; revise and present again.
{
"type": "object",
"properties": {
"plan": {
"type": "string",
"description": "The complete plan, as markdown, starting with a # heading that names it."
}
},
"required": [
"plan"
]
}Source: packages/plan/plan-mode/src/index.ts
exit_plan_mode stays in the model-facing schema while planning is inactive so transitions add no tool-catalog churn on top of the plan-policy change. Its execute path rejects calls outside plan mode; in plan mode it presents the plan over the user-questions seam (approve / keep planning with feedback), and approval logs plan mode inactive at the step boundary.
@deepseek-ai/dsh-tool-bash
bash
Execute a bash command (bash -c) and return its stdout/stderr. Each call runs in a fresh shell: no state (cwd, variables, functions) persists between calls — pass workdir instead of using cd. Non-zero exits are reported as [exit code: N]. Current harness environment facts are exposed through managed $DSH_* variables; inspect them when needed. Commands may run under a file sandbox; a blocked file operation is reported as [sandbox: file access denied under <mode> mode] — a policy denial, not a bug in the command; do not retry another way. Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. Set run_in_background: true for long-running commands: the call returns a job id immediately; read its output with job_output and stop it with job_kill.
{
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The bash command to execute."
},
"description": {
"type": "string",
"description": "Clear, concise description of what this command does in active voice, 5-10 words (shown in the UI). Examples: \"ls\" → \"List files in current directory\"; \"git status\" → \"Show working tree status\"; \"npm install\" → \"Install package dependencies\"."
},
"timeoutMs": {
"type": "number",
"description": "Timeout in milliseconds. The executor applies its configured default and cap, and kills the command on expiry."
},
"workdir": {
"type": "string",
"description": "Working directory for this command. Defaults to the session workspace; a relative path is resolved against it."
},
"run_in_background": {
"type": "boolean",
"description": "Run in the background and return a job id immediately (collect with job_output, stop with job_kill). No timeout applies."
}
},
"required": [
"command",
"description"
]
}Source: packages/shell/tool-bash/src/index.ts
The bash tool is the model-facing consumer of the bash executor seam. A run_in_background run registers with the generic ctx.jobs runtime and is collected/stopped through the job_* tools from @deepseek-ai/dsh-tool-jobs; the enableRunInBackground config (default true) removes the parameter entirely when disabled.
@deepseek-ai/dsh-tool-pwsh
pwsh
Execute a PowerShell command (pwsh -Command) and return its stdout/stderr. Each call runs in a fresh pwsh process: no state (cwd, variables, functions) persists between calls — pass workdir instead of using cd. Paths use native Windows form (C:\...); read environment variables with $env:NAME. Non-zero exits are reported as [exit code: N]. Current harness environment facts are exposed through managed $env:DSH_* variables; inspect them when needed. Commands may run under a file sandbox; a blocked file operation is reported as [sandbox: file access denied under <mode> mode] — a policy denial, not a bug in the command; do not retry another way. Long output is truncated to its tail; the full output is saved to a file whose path is reported when available. On Windows a force-killed command settles as [exit code: 1] without a signal marker — treat it as an interruption, not a command failure. Set run_in_background: true for long-running commands: the call returns a job id immediately; read its output with job_output and stop it with job_kill.
{
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The PowerShell command to execute."
},
"description": {
"type": "string",
"description": "Clear, concise description of what this command does in active voice, 5-10 words (shown in the UI). Examples: \"ls\" → \"List files in current directory\"; \"git status\" → \"Show working tree status\"; \"Get-Process\" → \"List running processes\"."
},
"timeoutMs": {
"type": "number",
"description": "Timeout in milliseconds. The executor applies its configured default and cap, and kills the command on expiry."
},
"workdir": {
"type": "string",
"description": "Working directory for this command. Defaults to the session workspace; a relative path is resolved against it."
},
"run_in_background": {
"type": "boolean",
"description": "Run in the background and return a job id immediately (collect with job_output, stop with job_kill). No timeout applies."
}
},
"required": [
"command",
"description"
]
}Source: packages/shell/tool-pwsh/src/index.ts
The pwsh tool is the PowerShell-dialect consumer of the bash executor seam for Windows compositions (a PowerShell executor such as @deepseek-ai/dsh-pwsh-local backs ctx.shell); it mirrors the bash tool call-for-call minus sandbox controls — run_in_background runs register with the generic ctx.jobs runtime and are collected/stopped through the job_* tools, and the managed DSH_* environment comes from @deepseek-ai/dsh-shell-env. Each call runs in a fresh process (no persistent PTY session), with native C:\... paths and $env:NAME variables.
@deepseek-ai/dsh-tool-cordis
cordis_define
Define an immutable Cordis Package. For a new Plugin, use kind:"new" and provide only a semantic prefix of 3–6 lowercase English letters; the Host returns the final pluginId and packageId. To modify an existing Plugin, use kind:"existing" with its exact pluginId to append a Package without overwriting older versions. Provide at least one of code.host and code.client. Each value is a plain JavaScript function body that returns a Cordis Plugin; no TypeScript, JSX, or import transformation occurs. Query Inspect before depending on a Service, Event, Builtin, Slot, or token. Define only validates parameters and syntax and records source: it does not request approval, execute apply, or change currentPackageId. On success, call cordis_run with the returned IDs.
{
"type": "object",
"properties": {
"plugin": {
"oneOf": [
{
"type": "object",
"additionalProperties": false,
"properties": {
"kind": {
"type": "string",
"const": "new"
},
"idPrefix": {
"type": "string",
"description": "Suggested semantic prefix of 3–6 lowercase English letters; the Host adds a unique numeric suffix."
}
},
"required": [
"kind",
"idPrefix"
]
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"kind": {
"type": "string",
"const": "existing"
},
"pluginId": {
"type": "string",
"description": "Exact ID of an existing Plugin; the new Package is appended to that instance."
}
},
"required": [
"kind",
"pluginId"
]
}
]
},
"name": {
"type": "string",
"description": "Short, readable Package name."
},
"purpose": {
"type": "string",
"description": "One-sentence, user-facing description of the Package purpose."
},
"code": {
"type": "object",
"additionalProperties": false,
"properties": {
"host": {
"type": "string",
"description": "Plain JavaScript function body that returns the Host-half Cordis Plugin."
},
"client": {
"type": "string",
"description": "Plain JavaScript function body that returns the browser Client-half Cordis Plugin."
}
}
}
},
"required": [
"plugin",
"name",
"purpose",
"code"
]
}Source: packages/extensions/tool-cordis/src/index.ts
cordis_inspect_list
List every Cordis Inspect Provider currently known to the Host, including local Host Providers and the latest manifests synchronized from the Client. Each entry includes its platform, purpose, read-only methods, and input/output schemas. Call this Tool before creating or modifying a Package, then select the provider and method for cordis_inspect_query from its result. Do not guess names or treat an Inspect method as a business Service that Plugin code can call.
{
"type": "object",
"properties": {}
}Source: packages/extensions/tool-cordis/src/index.ts
cordis_inspect_query
Run a read-only query explicitly declared by an Inspect Provider. platform, provider, and method must come from cordis_inspect_list, and input must satisfy that method's schema. Use this Tool before cordis_define to read exact Service methods, Event modes, Builtin signatures, Tool schemas, theme tokens, or live Slot trees and props. Host queries run locally. A Client query waits for the first valid page response and remains pending until a page answers or the Tool is cancelled. This Tool cannot invoke business Service methods or modify the runtime. For Service.listService and Event.listEvents, query without input to navigate the compact signature directory, then query the exact service or event for its structured contract and referenced types. For Slots.listSubTree, query without root to navigate the compact tree, then query the exact root for its complete registration contract and props.
{
"type": "object",
"properties": {
"platform": {
"type": "string",
"description": "Runtime platform that owns the Provider.",
"enum": [
"host",
"client"
]
},
"provider": {
"type": "string",
"description": "Exact Provider ID returned by cordis_inspect_list."
},
"method": {
"type": "string",
"description": "Exact method name declared by the Provider manifest."
},
"input": {
"description": "Optional query input; it must satisfy the method input schema."
}
},
"required": [
"platform",
"provider",
"method"
]
}Source: packages/extensions/tool-cordis/src/index.ts
cordis_inspect_self
Inspect dynamic Cordis objects owned by the current Session at increasing levels of detail. With no IDs, list only Plugin summaries. With pluginId alone, return version pointers, the latest Run, and every Package summary. Only pluginId plus packageId returns that immutable Package's Host/Client source and runtime diagnostics. packageId cannot be supplied alone. Query an exact Package before handling @pluginId, repairing an asynchronous failure, or defining an updated version. This Tool is read-only: it neither executes code nor changes version pointers.
{
"type": "object",
"properties": {
"pluginId": {
"type": "string",
"description": "Stable Plugin ID returned by cordis_define or injected by @pluginId; omit it to list every current Plugin."
},
"packageId": {
"type": "string",
"description": "Exact immutable Package ID owned by pluginId; when specified, source and diagnostics are returned."
}
}
}Source: packages/extensions/tool-cordis/src/index.ts
cordis_run
Activate one exact Package of a dynamic Plugin. Use mode:"run" for the first activation, restarting currentPackageId, or rollback. When current exists, use mode:"update" to switch to a different Package, even if the Plugin is currently stopped. An unauthorized Client Package creates an approval request and returns awaiting-approval; an authorized Package returns starting and continues asynchronously in the browser. Neither result waits for the final outcome inside the Tool. currentPackageId changes only after complete success; on failure, the old current and target next remain. Asynchronous success, rejection, or technical failure is reported through state and steering. After a technical failure, read diagnostics with cordis_inspect_self, correct the same Plugin, and retry autonomously. Do not request approval again after the user rejects it.
{
"type": "object",
"properties": {
"pluginId": {
"type": "string",
"description": "Stable Plugin ID returned by cordis_define."
},
"packageId": {
"type": "string",
"description": "Exact immutable Package ID to activate under that Plugin."
},
"mode": {
"type": "string",
"description": "Use run for the first activation, restarting current, or rollback; use update to switch from current to a different Package.",
"enum": [
"run",
"update"
]
}
},
"required": [
"pluginId",
"packageId",
"mode"
]
}Source: packages/extensions/tool-cordis/src/index.ts
cordis_stop
Stop the current Run of a dynamic Plugin and cancel unfinished approval or activation requests. Retain the Plugin, every immutable Package, grants, currentPackageId, and nextPackageId so it can later run or update directly. Stopping an already stopped Plugin succeeds idempotently. Use this Tool to disable effects temporarily; use cordis_undefine for permanent removal.
{
"type": "object",
"properties": {
"pluginId": {
"type": "string",
"description": "Stable dynamic Plugin ID to stop."
}
},
"required": [
"pluginId"
]
}Source: packages/extensions/tool-cordis/src/index.ts
cordis_undefine
Permanently remove a dynamic Plugin owned by the current Session. If it is running or awaiting approval, first stop it and cancel the request, then delete every Package, grant, and version pointer. After this returns, its pluginId, packageIds, @ reference, and Package business views are invalid; historical cards retain only a "Plugin removed" record. Do not call this Tool when versions must remain available for restart or rollback; use cordis_stop instead.
{
"type": "object",
"properties": {
"pluginId": {
"type": "string",
"description": "Stable dynamic Plugin ID to remove permanently."
}
},
"required": [
"pluginId"
]
}Source: packages/extensions/tool-cordis/src/index.ts
Not in any shipped tree (a deliberate opt-in — dynamic package code reaches the real runtime, see .agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md). The toolset injects ctx.dynamicCordisRunner from @deepseek-ai/dsh-cordis-host-runner, which owns the definition registry and the vm sandbox; a composition missing it never activates the tools. A running package may register ADDITIONAL model-visible tools until it is stopped, undefined, or DSH restarts; a full changed request header logs those tool-set changes.
@deepseek-ai/dsh-tool-bash-persistent
bash
Run commands in a persistent bash shell. State, including the current directory and exported environment variables, persists across calls for this agent.
{
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The bash command to run. Relative path is preferred in the command."
}
},
"required": [
"command"
]
}Source: packages/shell/tool-bash-persistent/src/index.ts
One owner-isolated persistent bash tool; deployment composition supplies the PTY backend and may override the model-facing environment description.
@deepseek-ai/dsh-tool-str-replace-editor
str_replace_editor
Custom editing tool for viewing, creating and editing files
- State is persistent across command calls and discussions with the user
- If
pathis a file,viewdisplays the result of applyingcat -n. Ifpathis a directory,viewlists non-hidden files and directories up to 2 levels deep - The
createcommand cannot be used if the specifiedpathalready exists as a file - If a
commandgenerates a long output, it will be truncated and marked with<response clipped>
Notes for using the str_replace command:
- The
old_strparameter should match EXACTLY one or more consecutive lines from the original file. Be mindful of whitespaces! - If the
old_strparameter is not unique in the file, the replacement will not be performed. Make sure to include enough context inold_strto make it unique - The
new_strparameter should contain the edited lines that should replace theold_str
{
"type": "object",
"properties": {
"command": {
"type": "string",
"description": "The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`.",
"enum": [
"view",
"create",
"str_replace",
"insert"
]
},
"path": {
"type": "string",
"description": "Absolute path to file or directory, e.g. `/repo/file.py` or `/repo`."
},
"file_text": {
"type": "string",
"description": "Required parameter of `create` command, with the content of the file to be created."
},
"insert_line": {
"type": "integer",
"description": "Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."
},
"new_str": {
"type": "string",
"description": "Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."
},
"old_str": {
"type": "string",
"description": "Required parameter of `str_replace` command containing the string in `path` to replace."
},
"view_range": {
"type": "array",
"description": "Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file.",
"items": {
"type": "integer"
}
}
},
"required": [
"command",
"path"
]
}Source: packages/fs/tool-str-replace-editor/src/index.ts
Standalone view/create/unique literal replace/line insert tool over the filesystem seam; it composes with any shell or terminal API.
@deepseek-ai/dsh-tool-fs
edit
Edit an existing UTF-8 text file by replacing literal text.
{
"type": "object",
"properties": {
"file_path": {
"type": "string",
"description": "Path to edit, resolved by the filesystem backend."
},
"old_string": {
"type": "string",
"description": "Literal text to replace. Must match exactly."
},
"new_string": {
"type": "string",
"description": "Literal replacement text. Use an empty string to delete the match."
},
"replace_all": {
"type": "boolean",
"description": "Replace all matches. Defaults to false; when false, old_string must appear exactly once."
}
},
"required": [
"file_path",
"old_string",
"new_string"
]
}Source: packages/fs/tool-fs/src/index.ts
read
Read a UTF-8 text file and return line-numbered content.
{
"type": "object",
"properties": {
"file_path": {
"type": "string",
"description": "Path to read, resolved by the filesystem backend."
},
"offset": {
"type": "number",
"description": "1-based first line to return. Defaults to 1."
},
"limit": {
"type": "number",
"description": "Maximum number of lines to return. Defaults to 2000."
}
},
"required": [
"file_path"
]
}Source: packages/fs/tool-fs/src/index.ts
read_image
Read a PNG/JPEG/WebP/GIF file and return the image itself. Requires the current model to accept image input.
{
"type": "object",
"properties": {
"file_path": {
"type": "string",
"description": "Path to the image file, resolved by the filesystem backend."
}
},
"required": [
"file_path"
]
}Source: packages/fs/tool-fs/src/index.ts
write
Create or fully replace a UTF-8 text file.
{
"type": "object",
"properties": {
"file_path": {
"type": "string",
"description": "Path to write, resolved by the filesystem backend."
},
"content": {
"type": "string",
"description": "Full UTF-8 text content to write."
}
},
"required": [
"file_path",
"content"
]
}Source: packages/fs/tool-fs/src/index.ts
The read-before-write/edit policy is added by @deepseek-ai/dsh-fs-observation-policy (an fs/* event-gate plugin, no schema change); a deployment that loads these tools is expected to also load it. read_image is not registered without ctx.attachments; its schema is route-independent, and execution refuses unless the exact routed model declares image input.
@deepseek-ai/dsh-tool-fs-search
glob
Find files whose paths match a glob pattern. Returns matching file paths — never directories — including hidden and ignored files (VCS metadata directories are excluded). Up to 100 paths come back in modification-time order; a larger result instead returns 100 paths sampled across top-level entries, says so, and reports where the complete sorted list was saved. This tool does not enumerate directory entries.
{
"type": "object",
"properties": {
"pattern": {
"type": "string",
"description": "Glob pattern to match file paths against (e.g. \"**/*.ts\", \"src/**/*.test.js\"). A pattern with no \"/\" matches the basename at any depth, so \"*\" and \"*.ts\" both search the whole tree; include a separator to anchor the depth."
},
"path": {
"type": "string",
"description": "Directory to search in. Defaults to the session workspace; a relative path resolves against it."
}
},
"required": [
"pattern"
]
}Source: packages/fs/tool-fs-search/src/index.ts
grep
Search file contents with a ripgrep regular expression. Returns matching lines with line numbers, grouped by file. Returns the first 250 matches inline; a capped result reports where the complete match list was saved. Use read on a matched file for surrounding context.
{
"type": "object",
"properties": {
"pattern": {
"type": "string",
"description": "Regular expression to search for (ripgrep syntax)."
},
"path": {
"type": "string",
"description": "File or directory to search. Defaults to the session workspace; a relative path resolves against it."
},
"include": {
"type": "string",
"description": "One glob filter for which files to search (e.g. \"*.ts\", \"*.{js,jsx}\"). Not a list; negation is not supported."
}
},
"required": [
"pattern"
]
}Source: packages/fs/tool-fs-search/src/index.ts
glob and grep are unconditional discovery tools that spawn the packaged ripgrep binary (@vscode/ripgrep) through ctx.subprocess as ordinary foreground calls (never background jobs) — no host rg install and no shell layer. The catalog uses sampleOverCapGlobResults: true; deployments must choose that behavior explicitly. Capped results save the complete formatted list through the optional ctx.spillStore backend; returned locators are follow-up-readable/searchable when the backend exposes local paths in co-located deployments.
@deepseek-ai/dsh-tool-terminal
terminal_close
Close one persistent terminal and wait until its captured owned process tree is gone.
{
"type": "object",
"properties": {
"sessionId": {
"type": "string",
"description": "Terminal session id."
}
},
"required": [
"sessionId"
]
}Source: packages/terminal/tool-terminal/src/index.ts
terminal_list
List persistent terminal sessions owned by the current agent.
{
"type": "object",
"properties": {}
}Source: packages/terminal/tool-terminal/src/index.ts
terminal_open
Create a persistent, owner-isolated terminal session from a registered backend type. Use this for shell or REPL state that must survive across tool calls.
{
"type": "object",
"properties": {
"type": {
"type": "string",
"description": "Registered terminal backend type, usually \"shell\"."
},
"name": {
"type": "string",
"description": "Optional owner-local display name such as \"main\" or \"gdb\"."
},
"cwd": {
"type": "string",
"description": "Initial working directory. Defaults to the deployment workspace root."
}
},
"required": [
"type"
]
}Source: packages/terminal/tool-terminal/src/index.ts
terminal_read
Read a bounded page of retained output from a persistent terminal without sending input.
{
"type": "object",
"properties": {
"sessionId": {
"type": "string",
"description": "Terminal session id."
},
"offset": {
"type": "number",
"description": "Newest-relative line offset (default 0)."
},
"count": {
"type": "number",
"description": "Requested line count (default 500; backend caps apply)."
}
},
"required": [
"sessionId"
]
}Source: packages/terminal/tool-terminal/src/index.ts
terminal_send
Send text to a persistent terminal. By default Enter is submitted and the call waits for a prompt, stdin wait, output silence, timeout, or session exit. Background mode returns a job id for job_output/job_kill.
{
"type": "object",
"properties": {
"sessionId": {
"type": "string",
"description": "Terminal session id returned by terminal_open or terminal_list."
},
"text": {
"type": "string",
"description": "UTF-8 text to write to the terminal."
},
"submit": {
"type": "boolean",
"description": "Submit Enter after text (default true). Set false for control characters or incomplete REPL input."
},
"run_in_background": {
"type": "boolean",
"description": "Return a job id immediately; collect with job_output or stop with job_kill."
}
},
"required": [
"sessionId",
"text"
]
}Source: packages/terminal/tool-terminal/src/index.ts
terminal_signal
Send an allowed signal to the current foreground process group of a persistent terminal.
{
"type": "object",
"properties": {
"sessionId": {
"type": "string",
"description": "Terminal session id."
},
"signal": {
"type": "string",
"description": "Signal to deliver. Shell-targeted SIGKILL is rejected; use terminal_close.",
"enum": [
"SIGINT",
"SIGTERM",
"SIGKILL",
"SIGTSTP",
"SIGHUP"
]
}
},
"required": [
"sessionId",
"signal"
]
}Source: packages/terminal/tool-terminal/src/index.ts
The six terminal tools are opt-in and complement one-shot shell/filesystem tools. terminal_send(run_in_background: true) registers with ctx.jobs; TUI, named key sequences, BEL, resize, auto-start, and cross-agent sharing are absent from the schema.
@deepseek-ai/dsh-tool-goal
create_goal
Create one persisted same-session completion goal when the current direct human request is a long-running objective that should continue across autonomous goal rounds. You may infer that intent without requiring the user to say "create a goal". Do not use this for trivial single-turn work. Execution rejects non-human and subagent authority.
{
"type": "object",
"properties": {
"objective": {
"type": "string",
"description": "The concrete completion objective inferred from the direct human request."
},
"max_goal_rounds": {
"type": "number",
"description": "Optional positive safe-integer limit on automatic continuation rounds."
}
},
"required": [
"objective"
]
}Source: packages/goal/tool-goal/src/index.ts
get_goal
Read the current same-session goal, including its exact id/revision, objective, phase, completed continuation rounds, round limit, blocker reason when present, and whether another continuation is armed. Call this before updating a goal.
{
"type": "object",
"properties": {}
}Source: packages/goal/tool-goal/src/index.ts
update_goal
Update the exact current goal revision. edit, pause, and resume require a direct top-level human request. During an automatic continuation of the current goal, complete and blocked are also allowed. blocked is rejected before the configured minimum round count; the model remains responsible for judging that the same condition persisted across those rounds and must explain it in blocked_reason.
{
"type": "object",
"properties": {
"goal_id": {
"type": "string",
"description": "Exact id returned by get_goal."
},
"revision": {
"type": "number",
"description": "Exact positive revision returned by get_goal."
},
"action": {
"type": "string",
"description": "edit | pause | resume | complete | blocked",
"enum": [
"edit",
"pause",
"resume",
"complete",
"blocked"
]
},
"objective": {
"type": "string",
"description": "Replacement objective; valid only with action edit."
},
"max_goal_rounds": {
"type": "number",
"description": "Replacement cap; valid only with action edit."
},
"blocked_reason": {
"type": "string",
"description": "Concrete blocking condition; required only with action blocked."
}
},
"required": [
"goal_id",
"revision",
"action"
]
}Source: packages/goal/tool-goal/src/index.ts
create, edit, pause, and resume require direct-human root authority; complete and blocked also accept the exact current goal round. The default blocked lower bound is three admitted rounds.
@deepseek-ai/dsh-schedule
schedule_create
Create one reminder in the current session. Supply a non-empty prompt and exactly one selector: a positive safe-integer after_seconds delay, at as a strict offset date-time or local date/time object, or safe-integer every_seconds of at least 300. Fixed-rate reminders stay creation-aligned, skip missed occurrences, and batch one latest occurrence per overdue rule. Delivery is session-local: the reminder runs on time only while this session is live and otherwise becomes overdue until the session is resumed.
{
"type": "object",
"properties": {
"prompt": {
"type": "string",
"description": "Reminder content to present when the target becomes due."
},
"after_seconds": {
"type": "number",
"description": "Positive safe-integer delay in seconds."
},
"every_seconds": {
"type": "number",
"description": "Fixed-rate safe-integer interval in seconds, at least 300."
},
"at": {
"oneOf": [
{
"type": "string"
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"date": {
"type": "string"
},
"time": {
"type": "string"
},
"time_zone": {
"type": "string"
}
},
"required": [
"date",
"time",
"time_zone"
]
}
],
"description": "Absolute target as strict offset RFC 3339 or local date/time with an explicit IANA zone."
}
},
"required": [
"prompt"
]
}Source: packages/schedule/schedule/src/tools.ts
schedule_delete
Delete one active reminder in the current session by the exact id returned by schedule_create or schedule_list. Unknown or already-finished ids return deleted false.
{
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Exact session-local schedule id."
}
},
"required": [
"id"
]
}Source: packages/schedule/schedule/src/tools.ts
schedule_list
List every active reminder in the current session in creation order, including its exact id, UTC target, scheduled or overdue state, and session-local delivery mode.
{
"type": "object",
"properties": {}
}Source: packages/schedule/schedule/src/tools.ts
Registered only inside live root Agent scopes created after the opt-in Schedule plugin loads. Version 1 accepts after_seconds, explicit absolute at, and bounded fixed-rate every_seconds, and discloses session-local delivery; management reads and mutations require the shared Session persistence barrier.
@deepseek-ai/dsh-tool-lsp
lsp
Query a language server for precise code navigation. operation is one of goToDefinition, findReferences, goToImplementation, hover. line and character are one-based UTF-16 cursor coordinates. findReferences includes the declaration.
{
"type": "object",
"properties": {
"operation": {
"type": "string",
"description": "goToDefinition, findReferences, goToImplementation, or hover.",
"enum": [
"goToDefinition",
"findReferences",
"goToImplementation",
"hover"
]
},
"file_path": {
"type": "string",
"description": "The source file to query, relative to the workspace or absolute."
},
"line": {
"type": "number",
"description": "One-based line of the cursor."
},
"character": {
"type": "number",
"description": "One-based UTF-16 column of the cursor."
}
},
"required": [
"operation",
"file_path",
"line",
"character"
]
}Source: packages/lsp/tool-lsp/src/index.ts
The lsp tool keeps provider selection and language-server subprocesses behind ctx.lsp, so its model-visible schema stays stable across providers. Requires a registered provider (e.g. @deepseek-ai/dsh-lsp-stdio) at runtime; without one, a query returns the structured LSP_UNAVAILABLE error rather than changing the schema.
@deepseek-ai/dsh-tool-ralph
ralph
Run a foreground fresh-agent Ralph loop toward one immutable objective. Use only when the direct human explicitly asks for Ralph or fresh-agent iteration. Each round opens a new child with no parent conversation or prior child session; the shared workspace is long-term memory, and only a bounded structured report crosses rounds. The call returns when a worker reports completion or a concrete blocker, or at the round limit. Ordinary long-running same-session work belongs to goal tools.
{
"type": "object",
"properties": {
"objective": {
"type": "string",
"description": "The immutable completion objective for every fresh Ralph round."
},
"maxRounds": {
"type": "number",
"description": "Optional positive safe-integer round cap, bounded by the deployment ceiling."
}
},
"required": [
"objective"
]
}Source: packages/workflow/tool-ralph/src/index.ts
A fixed foreground workflow starts one fresh structured child per round; the model selects only the immutable objective and an optional round cap.
@deepseek-ai/dsh-tool-skill
skill
Load the full instructions for an available skill. Call this with the exact skill name from the session skill catalog before acting on a task that names or clearly matches that skill.
{
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "The exact skill name from the available skills list."
}
},
"required": [
"name"
]
}Source: packages/skill/tool-skill/src/index.ts
@deepseek-ai/dsh-tool-session-query
session_event_read
Read one full unabridged event and optional neighboring raw-event summaries from an authorized session.
{
"type": "object",
"properties": {
"session_id": {
"type": "string",
"description": "Target session id. Omit for the current session."
},
"seq": {
"type": "integer",
"description": "Target event sequence number."
},
"before": {
"type": "integer",
"description": "Number of preceding raw events to summarize. Omit for none."
},
"after": {
"type": "integer",
"description": "Number of following raw events to summarize. Omit for none."
}
},
"required": [
"seq"
]
}Source: packages/session-query/tool-session-query/src/index.ts
session_event_search
Search prior events in one authorized session; the current session excludes the step performing this call.
{
"type": "object",
"properties": {
"session_id": {
"type": "string",
"description": "Target session id. Omit for the current session."
},
"query": {
"type": "string",
"description": "Literal full-text query over the target session."
},
"seq_from": {
"type": "integer",
"description": "Inclusive event sequence lower bound."
},
"seq_to": {
"type": "integer",
"description": "Inclusive event sequence upper bound."
},
"time_from": {
"type": "string",
"description": "Inclusive timezone-qualified ISO 8601 event-time lower bound."
},
"time_to": {
"type": "string",
"description": "Inclusive timezone-qualified ISO 8601 event-time upper bound."
},
"event_types": {
"type": "array",
"description": "Event types to include.",
"items": {
"type": "string"
}
},
"surfaces": {
"type": "array",
"description": "Event surfaces to include.",
"items": {
"type": "string",
"enum": [
"current",
"shadowed",
"log-only"
]
}
}
},
"required": [
"query"
]
}Source: packages/session-query/tool-session-query/src/index.ts
session_event_trace
Read every direct replacement and relationship to a cited source event for one event in an authorized session.
{
"type": "object",
"properties": {
"session_id": {
"type": "string",
"description": "Target session id. Omit for the current session."
},
"seq": {
"type": "integer",
"description": "Target event sequence number."
}
},
"required": [
"seq"
]
}Source: packages/session-query/tool-session-query/src/index.ts
session_search
Search prior sessions in the caller workspace and return the strongest matching event from each session.
{
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Literal full-text query over prior session history."
},
"session_ids": {
"type": "array",
"description": "Optional session ids to include.",
"items": {
"type": "string"
}
},
"created_at_from": {
"type": "string",
"description": "Inclusive timezone-qualified ISO 8601 creation-time lower bound."
},
"created_at_to": {
"type": "string",
"description": "Inclusive timezone-qualified ISO 8601 creation-time upper bound."
},
"parent_session_ids": {
"type": "array",
"description": "Optional direct parent session ids.",
"items": {
"type": "string"
}
},
"include_root_sessions": {
"type": "boolean",
"description": "Include sessions with no parent in the parent filter."
},
"availability": {
"type": "array",
"description": "Require at least one selected source availability.",
"items": {
"type": "string",
"enum": [
"live",
"persisted"
]
}
},
"event_seq_from": {
"type": "integer",
"description": "Inclusive event sequence lower bound."
},
"event_seq_to": {
"type": "integer",
"description": "Inclusive event sequence upper bound."
},
"event_time_from": {
"type": "string",
"description": "Inclusive timezone-qualified ISO 8601 event-time lower bound."
},
"event_time_to": {
"type": "string",
"description": "Inclusive timezone-qualified ISO 8601 event-time upper bound."
},
"event_types": {
"type": "array",
"description": "Event types to include.",
"items": {
"type": "string"
}
},
"event_surfaces": {
"type": "array",
"description": "Event surfaces to include.",
"items": {
"type": "string",
"enum": [
"current",
"shadowed",
"log-only"
]
}
}
},
"required": [
"query"
]
}Source: packages/session-query/tool-session-query/src/index.ts
session_trace
Read the authorized session lineage around one session, including complete visible ancestor and descendant relationships.
{
"type": "object",
"properties": {
"session_id": {
"type": "string",
"description": "Target session id. Omit for the current session."
}
}
}Source: packages/session-query/tool-session-query/src/index.ts
The five read-only tools hide provider cursors and authorize every result from the immutable calling agent session. The package is opt-in; compositions that need enforced deadlines or bounded inline output also mount the generic timeout or spill policies.
@deepseek-ai/dsh-tool-subagent
subagent
Delegate a self-contained task to a subagent (a separate agent that works in its own context) to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent returns its result, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. This call waits for the result by default. Set run_in_background: true to return a job id; collect with job_output and stop with job_kill.
{
"type": "object",
"properties": {
"description": {
"type": "string",
"description": "A short (3-5 word) description of the delegated task, for display."
},
"prompt": {
"type": "string",
"description": "The complete, self-contained task for the subagent. It does not share this conversation's context, so include everything it needs."
},
"run_in_background": {
"type": "boolean",
"description": "Whether to run as a background job and return its id. Defaults to false; collect with job_output or stop with job_kill."
}
},
"required": [
"description",
"prompt"
]
}Source: packages/subagent/tool-subagent/src/index.ts
The registered tool name is the load-time toolName config (default subagent); the schema above is that default. The shipped compositions load this package once per subagent backend, so the model additionally sees subagent_fork bound to the fork backend. Each instance's description, run_in_background parameter, and system-prompt policy follow its own backgroundMode and enableRunInBackground, so the two shipped schemas are not identical: subagent is continuable and defaults omitted calls to background with automatic settlement delivery, while subagent_fork stays one-shot and defaults them to foreground — see packages/bundle/base/cordis.patch.yml and examples/acp-agent/cordis.yml.
@deepseek-ai/dsh-tool-subagent-control
interrupt_agent
Request cancellation of a background agent's current turn by its agent id. The target may be your direct child or a deeper agent created under you. Only the current turn stops: messages already queued for the agent stay parked until a later send_message, agents it started keep running, and the agent itself stays available for follow-ups. This call returns as soon as the stop request is accepted, so the target may keep running briefly; interrupting an agent that already finished is an accepted no-op.
{
"type": "object",
"properties": {
"agent_id": {
"type": "string",
"description": "The agent id of the running agent to interrupt."
}
},
"required": [
"agent_id"
]
}Source: packages/subagent/tool-subagent-control/src/index.ts
list_agents
List your continuable background subagents by durable id and label. Use it to recall which ones you started, not to poll for completion — you are told when one finishes. Status comes from the live registry: running means the agent is working right now, idle means it is loaded but between turns (it may be waiting on agents it started), and ready means it exists only in storage — resumable, not terminal, and not a result waiting to be collected; a send_message starts a new turn on the same conversation, and a direct child remains a send_message candidate in every status. The snapshot is not a delivery promise — send_message performs the authoritative check and may still fail. Children that could not be read are reported as diagnostics instead of being silently dropped. Scope descendants walks the whole tree below you in stable pre-order, annotating each entry with its durable direct-parent session id and depth. You may use send_message only for depth-1 entries; deeper entries are candidates for interrupt_agent only.
{
"type": "object",
"properties": {
"scope": {
"type": "string",
"description": "children (default) lists direct children only; descendants walks the complete tree below you.",
"enum": [
"children",
"descendants"
]
}
}
}Source: packages/subagent/tool-subagent-control/src/list-agents.ts
send_message
Send a message to a background subagent by its subagent id, continuing the same conversation. It becomes the subagent's next turn: if it is still working, the message waits until its current turn finishes, so it cannot redirect work already underway. This call returns no answer from the subagent — only confirmation that the message was delivered — so use it to give it more work. A failure means the message was NOT delivered.
{
"type": "object",
"properties": {
"subagent_id": {
"type": "string",
"description": "The subagent id returned when the background subagent was started."
},
"message": {
"type": "string",
"description": "The message to deliver to the subagent."
}
},
"required": [
"subagent_id",
"message"
]
}Source: packages/subagent/tool-subagent-control/src/index.ts
The globally named control tools over continuable background subagents: provider-bound tool-subagent instances register distinct delegation tools, while this package registers send_message and interrupt_agent once, plus list_agents from its separately loaded /list-agents plugin (whose catalog rows use the sessionProjections and live Agent registries).
@deepseek-ai/dsh-tool-subagent-report
report
Report selected content to the agent that started you. Call this once before you finish, with a self-contained final result, and earlier for progress or findings that change what that agent does next. That agent shares your workspace but does not automatically receive your transcript, tool output, or reasoning, so finishing your work is not itself a result. Reporting does not end your turn or finish your work, and only your direct parent receives it. A failed call may still have arrived, so do not blindly repeat it.
{
"type": "object",
"properties": {
"output": {
"type": "string",
"description": "Actionable content for your parent; summarize conclusions and reference relevant shared paths."
}
},
"required": [
"output"
]
}Source: packages/subagent/tool-subagent-report/src/index.ts
Registered per continuable in-process child rather than globally, so this schema is visible only inside such a child and survives its global toolFilter. The same contribution installs the child-scoped tool:report prompt section, which this catalog does not render. The parent-facing send_message tool is installed independently.
@deepseek-ai/dsh-tool-jobs
job_kill
Request cancellation of a running background job by job id. Returns immediately; the job settles as killed once its work actually stops.
{
"type": "object",
"properties": {
"job_id": {
"type": "string",
"description": "Job id returned by the tool that started the background work."
},
"reason": {
"type": "string",
"description": "Optional short reason, recorded in the log and forwarded to the job."
}
},
"required": [
"job_id"
]
}Source: packages/jobs/tool-jobs/src/index.ts
job_list
List your background jobs (running and finished) with their ids, kinds, and statuses.
{
"type": "object",
"properties": {}
}Source: packages/jobs/tool-jobs/src/index.ts
job_output
Read a background job. Stream jobs return only output since the previous read; final-output jobs return their result after settlement. Every response ends with [status: ...]. Reads are non-blocking unless wait: true, which waits up to the configured cap.
{
"type": "object",
"properties": {
"job_id": {
"type": "string",
"description": "Job id returned by the tool that started the background work."
},
"wait": {
"type": "boolean",
"description": "Block until the job reaches a terminal status or the timeout expires. A timed-out wait returns [status: running] and leaves the job alive."
},
"timeout_ms": {
"type": "number",
"description": "Max wait in milliseconds (only meaningful with wait: true). Defaults to the configured wait timeout; capped by the configured maximum."
}
},
"required": [
"job_id"
]
}Source: packages/jobs/tool-jobs/src/index.ts
The kind-agnostic background-job controller: background bash commands, PTY sends, and subagents are read, listed, and killed through the same three tools. Loading the plugin attaches the controller that arms producers' ctx.jobs.start().
@deepseek-ai/dsh-tool-todo
todo_write
Record and update a structured task list for the current work. Send the ENTIRE list every call — it REPLACES the previous list (there are no partial updates, no per-item edits). Use it to plan multi-step work and show progress: add one todo per concrete step before you start. Mark every todo being actively worked on in_progress — several at once when work genuinely runs in parallel (e.g. concurrent subagents or background commands), one for sequential work; while work remains, at least one task should be in_progress. Mark a todo completed the moment it is done (do not batch completions), and allow no in_progress item only once all work is complete. Skip the list for trivial single-step tasks. Statuses: pending (not started), in_progress (being worked on now), completed (finished).
{
"type": "object",
"properties": {
"todos": {
"type": "array",
"description": "The COMPLETE task list, replacing any previous list.",
"items": {
"type": "object",
"additionalProperties": false,
"properties": {
"content": {
"type": "string",
"description": "What the task is — a short imperative line."
},
"status": {
"type": "string",
"description": "pending (not started) | in_progress (now) | completed (done).",
"enum": [
"pending",
"in_progress",
"completed"
]
}
},
"required": [
"content",
"status"
]
}
}
},
"required": [
"todos"
]
}Source: packages/todo/tool-todo/src/index.ts
todo_write is session-owned state; UIs render the latest todo/write event as a checklist. allowParallelInProgress is required with no default, so the catalog states its choice: true, whose description invites several in_progress items. A deployment choosing false receives the same tool with a description asking for exactly one active task.
@deepseek-ai/dsh-tool-workflow
workflow
Run a JavaScript workflow script that orchestrates subagents at scale. Use this for work that fans out across many independent pieces — an audit over many files, a migration, multi-angle research, adversarial verification of findings — where you write the orchestration as a script instead of delegating turn by turn.
The workflow's identity rides the meta parameter as JSON: required name (short kebab-case) and description strings, optional whenToUse string and phases array ({title, detail?, provider?, model?}). The script parameter is the plain JavaScript body ONLY (NOT TypeScript, and NO export const meta statement — meta is a parameter, not code), running with top-level await; end with return <value> — the value must be JSON-serializable and is this tool's result.
Script-body hooks:
agent(prompt, opts?): Promise<any>— run one subagent to completion. Withoutopts.schemait resolves to the child's final text; withopts.schema(an object-rooted JSON Schema using ONLY type/properties/required/additionalProperties/items/enum/const/oneOf — no pattern/format/numeric bounds) it resolves to the validated object. Resolvesnullwhen the child fails (filter with.filter(Boolean)). Other opts:label(display),phase(progress group), and independentprovider/modelLLM target overrides (either may be provided alone). Anything else (effort/isolation/agentType) is rejected loudly.pipeline(items, ...stages): Promise<any[]>— run each item through the stages independently with NO barrier between stages (prefer this for multi-stage work). Each stage receives(prev, item, index). An ordinary stage throw drops that ITEM tonulland skips its remaining stages.parallel(thunks): Promise<any[]>— run zero-argument functions concurrently and await ALL of them (a barrier; use only when a stage genuinely needs every prior result together). A throwing thunk resolves tonull.phase(title)— start a progress phase;log(message)— narrate progress;args— the tool call'sargsinput, verbatim.
Misused hooks (bad arguments, unknown options, unsupported schemas, tripped caps) throw errors that ALWAYS kill the script — they never dissolve into a per-item null.
Constraints: concurrency and total-agent caps apply; no filesystem, network, timers, or Node.js APIs are provided — the agents do the work, the script only coordinates them. The run executes in the foreground: this call returns when the whole script finishes.
{
"type": "object",
"properties": {
"script": {
"type": "string",
"description": "The plain-JS workflow script body (top-level await allowed; NO `export const meta` statement; end with `return <json-value>`)."
},
"meta": {
"type": "object",
"description": "The workflow identity block (plain JSON — never code).",
"additionalProperties": true,
"properties": {
"name": {
"type": "string",
"description": "Short kebab-case workflow name."
},
"description": {
"type": "string",
"description": "One-line description of what the workflow does."
},
"whenToUse": {
"type": "string",
"description": "Optional guidance on when this workflow applies."
},
"phases": {
"type": "array",
"description": "Optional phase declarations matched by phase() calls.",
"items": {
"type": "object",
"additionalProperties": true,
"properties": {
"title": {
"type": "string",
"description": "The phase title phase() calls match by exact string."
},
"detail": {
"type": "string",
"description": "Optional one-line description of the phase."
},
"provider": {
"type": "string",
"description": "Optional provider override this phase is expected to use."
},
"model": {
"type": "string",
"description": "Optional model override this phase is expected to use."
}
},
"required": [
"title"
]
}
}
},
"required": [
"name",
"description"
]
},
"args": {
"type": "object",
"description": "Optional JSON input exposed to the script as the `args` global (wrap a bare list as a field, e.g. {\"files\": [...]}).",
"additionalProperties": true
}
},
"required": [
"script",
"meta"
]
}Source: packages/workflow/tool-workflow/src/index.ts
@deepseek-ai/dsh-tool-web
web_fetch
Fetch the content of a specific HTTP(S) URL and return it decoded to text.
{
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "The HTTP(S) URL to fetch."
}
},
"required": [
"url"
]
}Source: packages/web/tool-web/src/index.ts
web_search
Search the web for current information. Returns an optional summary answer and a list of source URLs.
{
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "The search query."
}
},
"required": [
"query"
]
}Source: packages/web/tool-web/src/index.ts
web_search and web_fetch keep provider selection behind ctx.web so model-visible schemas stay stable across backend swaps.