# 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 cordis [events](cordis-catalog/events.md) & [services](cordis-catalog/services.md) catalogs (the wiring a plugin listens to and calls) and [core-data-structures/](core-data-structures/core.md) (the types those signatures move) — 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](../.agents/notes/implemented/process/2026-07-02-tool-schema-catalog.md). 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 surface 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.userInteraction` | `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.userInteraction (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-interaction 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.bash`, `ctx.systemPrompt`, `ctx.bashEnv`, `ctx.tasks 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.tasks` runtime and is collected/stopped through the `task_*` tools from `@deepseek-ai/dsh-tool-tasks`; the `enableRunInBackground` config (default true) removes the parameter entirely when disabled. | | `@deepseek-ai/dsh-tool-pwsh` | `pwsh` | `ctx.tools`, `ctx.bash`, `ctx.systemPrompt`, `ctx.bashEnv`, `ctx.tasks 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.bash`); it mirrors the bash tool call-for-call minus the sandbox surface — `run_in_background` runs register with the generic `ctx.tasks` runtime and are collected/stopped through the `task_*` tools, and the managed `DSH_*` environment comes from `@deepseek-ai/dsh-bash-env`. Each call runs in a fresh process (no persistent PTY session; ConPTY is roadmap work), with native `C:\...` paths and `$env:NAME` variables. | | `@deepseek-ai/dsh-tool-cordis` | `cordis_inspect`, `cordis_mount`, `cordis_unmount` | `ctx.tools` | `tool/call`, `tool/result`, `process-local temporary Plugin lifecycle` | - | Not in any shipped tree (a deliberate opt-in — temporary Plugin code reaches the real runtime, see .agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md). Plugins created by cordis_mount may register ADDITIONAL model-visible tools until unmounted or DSH restarts; a full changed request header logs those tool-set changes. | | `@deepseek-ai/dsh-tool-bash-persistent` | `bash` | `ctx.tools`, `ctx.pty`, `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 successful file operations`, `tool/result` | - | Standalone view/create/unique literal replace/line insert tool over the filesystem seam; it composes with any shell or terminal surface. | | `@deepseek-ai/dsh-tool-fs` | `edit`, `read`, `write` | `ctx.tools`, `ctx.fs`, `ctx.systemPrompt` | `tool/call`, `fs/write-intent or fs/edit-intent for mutations`, `fs/observed after successful file operations`, `tool/result` | - | The read-before-write/edit policy is added by `@deepseek-ai/dsh-fs-policy` (an `fs/*` event-gate plugin, no schema change); a deployment that loads these tools is expected to also load it. The tool schemas above are identical with or without the policy plugin. | | `@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 tasks) — 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-pty` | `terminal_close`, `terminal_list`, `terminal_open`, `terminal_read`, `terminal_send`, `terminal_signal` | `ctx.tools`, `ctx.pty`, `ctx.systemPrompt`, `ctx.tasks at call time for run_in_background` | `tool/call`, `tool/result` | - | The six terminal tools are opt-in and complement one-shot bash/filesystem tools. `terminal_send(run_in_background: true)` registers with `ctx.tasks`; 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-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-local`) 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.workflows`, `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` | `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 example agents load this package once per subagent backend, so the model additionally sees `subagent_fork` (bound to the fork backend) with an identical schema — see `packages/bundle/base/cordis.patch.yml` and `examples/acp-agent/cordis.yml`. | | `@deepseek-ai/dsh-tool-subagent-control` | `list_agents`, `send_message` | `ctx.tools`, `ctx.subagents`, `ctx.sessionProjections (list_agents catalog rows)` | `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` once, plus `list_agents` from its separately loaded `/list-agents` plugin (whose catalog rows are served through the sessionProjections registry). | | `@deepseek-ai/dsh-tool-subagent-report` | `report` | `ctx.subagents`, `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 parent-facing `send_message` tool is installed independently. | | `@deepseek-ai/dsh-tool-tasks` | `task_kill`, `task_list`, `task_output` | `ctx.tools`, `ctx.tasks`, `ctx.systemPrompt` | `tool/call`, `tool/result`, `user/message via agent.inject() for background completion notices` | - | The kind-agnostic background-task control surface: background bash commands, PTY sends, and subagents are read, listed, and killed through the same three tools. Loading the plugin attaches the control surface that arms producers' `ctx.tasks.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.workflows`, `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. ```json { "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/ui/tool-ask-user/src/index.ts`](../packages/ui/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. Write the BODY of an async function (erasable syntax only; top-level `await` and `return` work) and call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return comes back — curate it. ```json { "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`](../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. ```json { "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`](../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-interaction 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]` — 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 task id immediately; read its output with `task_output` and stop it with `task_kill`. ```json { "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 task id immediately (collect with task_output, stop with task_kill). No timeout applies." } }, "required": [ "command", "description" ] } ``` Source: [`packages/bash/tool-bash/src/index.ts`](../packages/bash/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.tasks` runtime and is collected/stopped through the `task_*` tools from `@deepseek-ai/dsh-tool-tasks`; 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. 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 task id immediately; read its output with `task_output` and stop it with `task_kill`. ```json { "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 task id immediately (collect with task_output, stop with task_kill). No timeout applies." } }, "required": [ "command", "description" ] } ``` Source: [`packages/bash/tool-pwsh/src/index.ts`](../packages/bash/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.bash`); it mirrors the bash tool call-for-call minus the sandbox surface — `run_in_background` runs register with the generic `ctx.tasks` runtime and are collected/stopped through the `task_*` tools, and the managed `DSH_*` environment comes from `@deepseek-ai/dsh-bash-env`. Each call runs in a fresh process (no persistent PTY session; ConPTY is roadmap work), with native `C:\...` paths and `$env:NAME` variables. ## `@deepseek-ai/dsh-tool-cordis` ### `cordis_inspect` Inspect the live Cordis runtime in the current DSH process. Read-only. Sections: `services` (every provided ctx service and the plugin fiber that owns it), `plugins` (all live plugin fibers with their lifecycle states), `tools` (the model-facing tools currently registered, i.e. what you can call), `temporary` (only temporary Plugins created by cordis_mount: id, name, state, provided services, awaited services, and lifetime), `api` (method signatures AND argument/return type shapes for every LIVE service — read this before writing plugin code that calls a service), `events` (every harness event with its dispatch mode and exact signature — pick listener targets here). Temporary Plugins exist only in memory, remain active across later turns, and disappear after cordis_unmount, toolset unload, or DSH restart; they are not restored automatically. The `temporary` section is a subset of `plugins`. Omit `what` to get all six sections. With `what:"api"` or `what:"events"`, pass an exact `name` to narrow to one service/event and include its original source JSDoc. ```json { "type": "object", "properties": { "what": { "type": "string", "description": "Limit the report to one section. Omit for all sections.", "enum": [ "services", "plugins", "tools", "temporary", "api", "events" ] }, "name": { "type": "string", "description": "Exact service key or event name whose original JSDoc to include; valid only with what:\"api\" or what:\"events\"." } } } ``` Source: [`packages/cordis/tool-cordis/src/index.ts`](../packages/cordis/tool-cordis/src/index.ts) ### `cordis_mount` Mount a temporary Cordis Plugin in the current DSH process. This creates an in-memory runtime Plugin, not an installed or configured Plugin. It remains active across later turns until cordis_unmount, toolset unload, or DSH restart. It does not create files, install a package, change cordis.yml or personal/project config, survive restart, or automatically become permanent. To keep it, ask the Agent to implement a normal local, project, or repository Plugin through the regular development workflow. It may affect other sessions in the same process; the sandbox is not a security boundary, and injected services reach the real runtime. `code` runs now as the body of an async JavaScript function in an isolated sandbox and MUST `return` a plugin. Two forms: FUNCTION form `return (ctx) => { … }` — declares no inject, so it can register tools, listen to events, and provide services, but reaching ANY service (e.g. ctx.bash) throws; use it only when you need no services. OBJECT form `return { name?, inject: ['bash', 'llm', …], apply(ctx) { … } }` — declares dependencies, and cordis activates the plugin only after the services exist; PREFER this form. You may reach ONLY the services you list in inject: an undeclared service throws even if it exists, because an undeclared dependency would not be cleaned up if its provider is unmounted. BEFORE calling a service from your code, read cordis_inspect what:"api" — it lists method signatures AND the type shapes of their arguments/returns (do not guess a field's type; e.g. a bash run's stdout is an object, not a string). Inside `apply`, use the standard cordis API: `ctx.on(event, listener)` to observe events (see cordis_inspect what:"events"), or call `harness.registerTool(ctx, harness.defineTool({ name, description, parameters: { text: { type: 'string', required: true } }, output: { schema: { type: 'string' }, render(_args, value) { return [{ type: 'text', text: value }] } }, async execute(args) { return args.text } }))` to give yourself a new tool — it becomes callable on your NEXT step. Tool parameters: each key IS a property — { type: 'string'|'number'|'integer'|'boolean'|'null'|'object'|'array'|'json', required?: true, description?, enum?, const?, items?, properties? }; every direct DSL object declares additionalProperties: true|false, and oneOf: [schema, schema, ...] replaces type for an exact-one union. A raw JSON-Schema { type: 'object', properties, required?: […] } wrapper is also accepted with open-by-default objects. A tool's `execute` MUST return the lossless JSON value declared by `output.schema`; `output.render(args, value)` separately returns Native/model content blocks. Temporary Plugins can COMPOSE: one Plugin may `ctx.provide('name', value)` a service and another may declare `inject: ['name']` to consume it — the consumer stays pending until the provider exists and returns to pending when the provider is unmounted. Everything registered inside `apply` is cleaned up automatically by cordis_unmount. Sandbox globals: `console` (tagged `[cordis:]`, writes through to the harness terminal), `harness.defineTool`, `harness.registerTool`, `btoa`, `atob`, `TextEncoder`, `TextDecoder`. Node APIs are DISABLED — do filesystem/network/timer work through the cordis services, never Node built-ins: `require`, `setTimeout`/`setInterval`, and `fetch` throw redirect errors; `process` and `Buffer` are undefined. Instead use inject: ['fs'] + ctx.fs for files, inject: ['web'] + ctx.web for HTTP, inject: ['bash'] + ctx.bash for processes, and inject: ['timer'] + ctx.setTimeout/ctx.setInterval for timing (fiber effects, auto-cleaned when unmounted) — cordis_inspect what:"api" shows what THIS runtime provides. Write PLAIN JavaScript, not TypeScript (no `as`, no type annotations). Cautions: (1) waterfall events (e.g. tools/pre-execute) hand the listener a trailing `next` callback which MUST be called — returning without `next()` VETOES the call; prefer plain notification events unless you intend to intercept. (2) Never await something that only resolves after the current turn (your code runs INSIDE a tool call of that turn — it would deadlock). (3) Your `ctx` is a restricted façade: you can register tools, observe events, provide/consume services, and use timers, but framework internals (ctx.root, ctx.fiber, ctx.extend, ctx.plugin, …) are withheld. It is not a security boundary though — the services you inject (e.g. ctx.bash) reach the real runtime. ```json { "type": "object", "properties": { "code": { "type": "string", "description": "JavaScript body returning a temporary Plugin; evaluated now and saved nowhere." } }, "required": [ "code" ] } ``` Source: [`packages/cordis/tool-cordis/src/index.ts`](../packages/cordis/tool-cordis/src/index.ts) ### `cordis_unmount` Unmount a current-process temporary Plugin created by cordis_mount. Waits for its tools, listeners, services, timers, and other owned effects to clean up completely. Only dyn-N temporary ids are accepted; this cannot remove Loader, configured, or installed Plugins. ```json { "type": "object", "properties": { "id": { "type": "string", "description": "The temporary Plugin id returned by cordis_mount (for example \"dyn-1\"); valid only in this process and invalid after unmount or restart." } }, "required": [ "id" ] } ``` Source: [`packages/cordis/tool-cordis/src/index.ts`](../packages/cordis/tool-cordis/src/index.ts) Not in any shipped tree (a deliberate opt-in — temporary Plugin code reaches the real runtime, see .agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md). Plugins created by cordis_mount may register ADDITIONAL model-visible tools until unmounted 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. ```json { "type": "object", "properties": { "command": { "type": "string", "description": "The bash command to run. Relative path is preferred in the command." } }, "required": [ "command" ] } ``` Source: [`packages/pty/tool-bash-persistent/src/index.ts`](../packages/pty/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 `path` is a file, `view` displays the result of applying `cat -n`. If `path` is a directory, `view` lists non-hidden files and directories up to 2 levels deep * The `create` command cannot be used if the specified `path` already exists as a file * If a `command` generates a long output, it will be truncated and marked with `` Notes for using the `str_replace` command: * The `old_str` parameter should match EXACTLY one or more consecutive lines from the original file. Be mindful of whitespaces! * If the `old_str` parameter is not unique in the file, the replacement will not be performed. Make sure to include enough context in `old_str` to make it unique * The `new_str` parameter should contain the edited lines that should replace the `old_str` ```json { "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`](../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 surface. ## `@deepseek-ai/dsh-tool-fs` ### `edit` Edit an existing UTF-8 text file by replacing literal text. ```json { "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`](../packages/fs/tool-fs/src/index.ts) ### `read` Read a UTF-8 text file and return line-numbered content. ```json { "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`](../packages/fs/tool-fs/src/index.ts) ### `write` Create or fully replace a UTF-8 text file. ```json { "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`](../packages/fs/tool-fs/src/index.ts) The read-before-write/edit policy is added by `@deepseek-ai/dsh-fs-policy` (an `fs/*` event-gate plugin, no schema change); a deployment that loads these tools is expected to also load it. The tool schemas above are identical with or without the policy plugin. ## `@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. ```json { "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`](../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. ```json { "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`](../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 tasks) — 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-pty` ### `terminal_close` Close one persistent terminal and wait until its captured owned process tree is gone. ```json { "type": "object", "properties": { "sessionId": { "type": "string", "description": "Terminal session id." } }, "required": [ "sessionId" ] } ``` Source: [`packages/pty/tool-pty/src/index.ts`](../packages/pty/tool-pty/src/index.ts) ### `terminal_list` List persistent terminal sessions owned by the current agent. ```json { "type": "object", "properties": {} } ``` Source: [`packages/pty/tool-pty/src/index.ts`](../packages/pty/tool-pty/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. ```json { "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/pty/tool-pty/src/index.ts`](../packages/pty/tool-pty/src/index.ts) ### `terminal_read` Read a bounded page of retained output from a persistent terminal without sending input. ```json { "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/pty/tool-pty/src/index.ts`](../packages/pty/tool-pty/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 task id for task_output/task_kill. ```json { "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 task id immediately; collect with task_output or stop with task_kill." } }, "required": [ "sessionId", "text" ] } ``` Source: [`packages/pty/tool-pty/src/index.ts`](../packages/pty/tool-pty/src/index.ts) ### `terminal_signal` Send an allowed signal to the current foreground process group of a persistent terminal. ```json { "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/pty/tool-pty/src/index.ts`](../packages/pty/tool-pty/src/index.ts) The six terminal tools are opt-in and complement one-shot bash/filesystem tools. `terminal_send(run_in_background: true)` registers with `ctx.tasks`; 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. ```json { "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`](../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. ```json { "type": "object", "properties": {} } ``` Source: [`packages/goal/tool-goal/src/index.ts`](../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. ```json { "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`](../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-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. ```json { "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`](../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-local`) 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. ```json { "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`](../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. ```json { "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`](../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. ```json { "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`](../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. ```json { "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`](../packages/session-query/tool-session-query/src/index.ts) ### `session_event_trace` Read every direct replacement and provenance relationship for one event in an authorized session. ```json { "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`](../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. ```json { "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`](../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. ```json { "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`](../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) and return its final result. Use this to offload focused, independent work — research, a scoped implementation, an analysis — so it does not consume this conversation's context. The subagent runs to completion and you receive only its final answer, not its intermediate steps. Give it a complete, standalone prompt: it does not see this conversation. Set `run_in_background: true` to return a task id; collect with `task_output` and stop with `task_kill`. ```json { "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": "Run as a background task and return its id; collect with task_output or stop with task_kill." } }, "required": [ "description", "prompt" ] } ``` Source: [`packages/subagent/tool-subagent/src/index.ts`](../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 example agents load this package once per subagent backend, so the model additionally sees `subagent_fork` (bound to the fork backend) with an identical schema — see `packages/bundle/base/cordis.patch.yml` and `examples/acp-agent/cordis.yml`. ## `@deepseek-ai/dsh-tool-subagent-control` ### `list_agents` List your continuable background subagents by durable id and label. Status is a snapshot of the stored record: running means the subagent session is currently live in this process, complete means it exists only in storage and a `send_message` starts a new turn on the same conversation. 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. ```json { "type": "object", "properties": {} } ``` Source: [`packages/subagent/tool-subagent-control/src/list-agents.ts`](../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. ```json { "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`](../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` once, plus `list_agents` from its separately loaded `/list-agents` plugin (whose catalog rows are served through the sessionProjections registry). ## `@deepseek-ai/dsh-tool-subagent-report` ### `report` Report selected content to the agent that started you. Call this zero or more times for progress, findings, or a final answer. 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. ```json { "type": "object", "properties": { "output": { "type": "string", "description": "Self-contained content for your parent; it does not see your private work." } }, "required": [ "output" ] } ``` Source: [`packages/subagent/tool-subagent-report/src/index.ts`](../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 parent-facing `send_message` tool is installed independently. ## `@deepseek-ai/dsh-tool-tasks` ### `task_kill` Request cancellation of a running background task by task id. Returns immediately; the task settles as killed once its work actually stops. ```json { "type": "object", "properties": { "task_id": { "type": "string", "description": "Task 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 task." } }, "required": [ "task_id" ] } ``` Source: [`packages/tasks/tool-tasks/src/index.ts`](../packages/tasks/tool-tasks/src/index.ts) ### `task_list` List your background tasks (running and finished) with their ids, kinds, and statuses. ```json { "type": "object", "properties": {} } ``` Source: [`packages/tasks/tool-tasks/src/index.ts`](../packages/tasks/tool-tasks/src/index.ts) ### `task_output` Read a background task. Stream tasks return only output since the previous read; final-output tasks return their result after settlement. Every response ends with `[status: ...]`. Reads are non-blocking unless `wait: true`, which waits up to the configured cap. ```json { "type": "object", "properties": { "task_id": { "type": "string", "description": "Task id returned by the tool that started the background work." }, "wait": { "type": "boolean", "description": "Block until the task reaches a terminal status or the timeout expires. A timed-out wait returns [status: running] and leaves the task 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": [ "task_id" ] } ``` Source: [`packages/tasks/tool-tasks/src/index.ts`](../packages/tasks/tool-tasks/src/index.ts) The kind-agnostic background-task control surface: background bash commands, PTY sends, and subagents are read, listed, and killed through the same three tools. Loading the plugin attaches the control surface that arms producers' `ctx.tasks.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). ```json { "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`](../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 ` — the value must be JSON-serializable and is this tool's result. Script-body hooks: - `agent(prompt, opts?): Promise` — run one subagent to completion. Without `opts.schema` it resolves to the child's final text; with `opts.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. Resolves `null` when the child fails (filter with `.filter(Boolean)`). Other opts: `label` (display), `phase` (progress group), and independent `provider`/`model` LLM target overrides (either may be provided alone). Anything else (`effort`/`isolation`/`agentType`) is rejected loudly. - `pipeline(items, ...stages): Promise` — 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 to `null` and skips its remaining stages. - `parallel(thunks): Promise` — 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 to `null`. - `phase(title)` — start a progress phase; `log(message)` — narrate progress; `args` — the tool call's `args` input, 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. ```json { "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 `)." }, "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`](../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. ```json { "type": "object", "properties": { "url": { "type": "string", "description": "The HTTP(S) URL to fetch." } }, "required": [ "url" ] } ``` Source: [`packages/web/tool-web/src/index.ts`](../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. ```json { "type": "object", "properties": { "query": { "type": "string", "description": "The search query." } }, "required": [ "query" ] } ``` Source: [`packages/web/tool-web/src/index.ts`](../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.