Files
deepseek-harness/docs/config-catalog.md
2026-07-10 16:51:19 +08:00

43 KiB

Plugin Config Catalog

Every config: block a cordis.yml entry can set: for each loadable harness package, the verbatim config declaration (JSDoc included) its apply function or service constructor receives, with every referenced type pasted alongside (package-local types) or linked (everything else). The paste is the plugin's full declared config type — a field the runtime schema deliberately excludes is a runtime-only seam (its own JSDoc says so) and is not settable from cordis.yml. This is the deployment-axis reference — the wiring a plugin author works against is the cordis events + services catalogs, the model-facing tool schemas are the tool catalog, and core-data-structures/ documents the types these declarations reference.

This file is GENERATED from source (scripts/gen-config-catalog.ts) and verified fresh by pnpm run verify-config-catalog (part of doc-sync) — do not edit it by hand. Declaration blocks use a ts config-catalog fence (skipped by doc-typecheck, since a lone declaration referencing imports is not standalone-compilable). The generator also cross-checks the runtime schemastery schema against the pasted declaration — every schema-validated key, nested keys included, must be locatable on the declared config type — so the paste cannot hide a loader-accepted field.

A Requires: line lists the service keys the plugin injects: its cordis.yml tree must also load providers for those services. Scope is the harness tier (packages/); the vendored cordis plugins a config tree may also load (hmr, the console logger, …) are pinned upstream source (vendoring policy) and not catalogued here.

@deepseek-ai/dsh-acp

Requires: agents · sessions · sessionPersistence · tools · userInteraction

/** Plugin config: the agent template ACP sessions are created from. */
export interface AcpConfig {
  /** Model name for created agents (must have a registered adapter). */
  model?: string
  /**
   * Transport stream override. Production omits this (the plugin wires
   * `process.stdin`/`process.stdout` via `ndJsonStream`). Tests inject an
   * in-memory `Stream` (e.g. an `ndJsonStream` over a `Duplex` pair) to drive
   * the bridge without a subprocess. Not part of the schemastery `Config` —
   * it is a runtime-only seam, never set from a `cordis.yml`.
   */
  stream?: Stream
}

Depends on: Stream (@agentclientprotocol/sdk)

Source: packages/ui/acp/src/index.ts:236

@deepseek-ai/dsh-acp-agent

/**
 * App config: the swappable per-deployment values. `model` configures the
 * agent template the ACP bridge creates each session's agent from (NOT a
 * pre-created agent — ACP creates agents at `session/new`); `persona` is the
 * deployment persona (forwarded to the system-prompt plugin); `toolOrder` is
 * the explicit model-facing tool order (forwarded to the system-prompt plugin);
 * `tools` is the tool registry's config (its presentation `mode`, forwarded
 * through agent-core); `persistenceRoot` is the JSONL backend's directory.
 */
export interface Config {
  /** Model name for ACP-created agents (must have a registered adapter). */
  model: string
  /** Deployment persona (the system-prompt plugin's `persona` config). */
  persona?: string
  /** Explicit model-facing tool order (the system-prompt plugin's `toolOrder` config; see dsh-system-prompt). */
  toolOrder?: string[]
  /** Tool-registry config — its presentation `mode` (forwarded through agent-core; see dsh-tools). */
  tools?: ToolsConfig
  /** Directory the JSONL session backend writes under. Defaults to `./.sessions`. */
  persistenceRoot?: string
}

Depends on: ToolsConfig

Source: packages/ui/acp-agent/src/index.ts:52

@deepseek-ai/dsh-agent-core

/**
 * Bundle config: each field forwarded verbatim to the child that owns it —
 * `agents` to the agent loop (an app that pre-creates no agents, like the ACP
 * bridge, simply omits it), `persona` and `toolOrder` to the system-prompt
 * plugin (the deployment's persona section and the explicit model-facing tool
 * order), the `tools` object to the tool registry (its presentation `mode`).
 * Every field is optional INPUT here because each owner's schema
 * supplies the default (`[]` / `''` / absent — lexicographic / `native`); the
 * schema is the INTERSECTION of the owners' own schemas (the registry's
 * nested under its `tools` key), so validation and defaulting can never
 * drift from them.
 */
export interface Config {
  /** The agent-loop `agents` list (see dsh-agent-loop's `Config`). */
  agents?: AgentLoopConfig['agents']
  /** The deployment persona (see dsh-system-prompt's `Config`). */
  persona?: SystemPromptConfig['persona']
  /** The explicit model-facing tool order (see dsh-system-prompt's `Config`). */
  toolOrder?: SystemPromptConfig['toolOrder']
  /** The tool registry's config — its presentation `mode` (see dsh-tools' `Config`). */
  tools?: ToolsConfig
}

Depends on: AgentLoopConfig · SystemPromptConfig · ToolsConfig

Source: packages/core/agent-core/src/index.ts:71

@deepseek-ai/dsh-agent-loop

Requires: agents · sessions · llm · tools · systemPrompt

/**
 * Plugin config: the agents to create — or resume, via `resumeSessionId` —
 * declaratively at startup, so a cordis.yml deployment needs no code.
 */
export interface Config {
  /** Agents created from configuration at startup. */
  agents: (AgentOptions & {
    /** Agent id to register under; also seeds the fresh per-run session id (`${id}-session-<uuid>`). */
    id: AgentId
    /**
     * If set, the config agent RESUMES this persisted session id instead of
     * starting a fresh `${id}-session-<uuid>`. Sourced from an env var in
     * cordis.yml (`resumeSessionId: !!js process.env.RESUME_SESSION_ID`), so a
     * demo can continue a prior conversation without code changes. Requires a
     * `dsh-session-persistence` backend; the resume is deferred until that
     * service is available (via `ctx.inject`) and the loaded session's events
     * seed the live session so history continues.
     *
     * The schema accepts a plain string at runtime (cordis.yml values are
     * untyped); the brand is compile-time only — the config format is the
     * boundary where an id enters, so the TYPE declares the brand here.
     */
    resumeSessionId?: SessionId
  })[]
}

Depends on: AgentId · AgentOptions · SessionId

Source: packages/core/agent-loop/src/index.ts:36

@deepseek-ai/dsh-bash-local

/** Plugin config (all optional — `static Config` supplies the defaults). */
export interface Config {
  /** Default working directory for commands (default: process.cwd()). */
  cwd?: string
  /** Default foreground timeout in milliseconds. */
  timeoutMs?: number
  /** Upper bound for per-call timeout overrides. */
  maxTimeoutMs?: number
  /** Per-stream in-memory output cap; overflow spills to a temp file. */
  maxOutputBytes?: number
  /** Grace period between the SIGTERM and the SIGKILL escalation on a kill. */
  graceMs?: number
}

Source: packages/bash/bash-local/src/index.ts:29

@deepseek-ai/dsh-code-runtime-worker

/** Plugin config: every execution cap, changeable from `cordis.yml` (no hardcoded tunables). */
export interface Config {
  /**
   * Busy-time budget in milliseconds: the run fails with kind `'timeout'`
   * once the worker's MEASURED event-loop active time
   * (`worker.performance.eventLoopUtilization()`) exceeds this. Metering
   * measured busy time — not wall time, not host-side pending-call
   * bookkeeping — is what makes the budget both fair (a program awaiting a
   * slow tool accrues nothing) and ungameable (a hot loop accrues whether
   * or not a decoy dispatch is in flight).
   */
  computeMs?: number
  /**
   * Wall-clock ceiling in milliseconds; never pauses for anything. The
   * backstop for what busy-time cannot see (a program awaiting a promise
   * nobody will resolve).
   */
  maxWallMs?: number
  /** Shared byte budget for captured log text (console + raw stream writes), truncation marked in-band. */
  maxLogBytes?: number
  /**
   * Byte cap for the completion value, measured by its real cross-boundary
   * size (string bytes, or structured-clone wire size); an oversized or
   * non-cloneable value crosses as a capped string rendering.
   */
  maxValueBytes?: number
  /** The worker's max old-generation heap in MiB (`resourceLimits`); overflow kills the worker, surfacing as kind `'worker-exit'`. */
  maxOldGenerationSizeMb?: number
}

Source: packages/code-runtime/code-runtime-worker/src/index.ts:29

@deepseek-ai/dsh-compact-basic

Requires: llm

/**
 * Backend configuration. Every knob is REQUIRED except `auto` and
 * `charsPerToken`: there is no concrete data yet to justify default
 * thresholds/budgets, so a consumer must state each value explicitly rather
 * than inherit a guessed default. `auto` alone defaults to `true`
 * (auto-compaction is the intended posture), and `charsPerToken` defaults to
 * the English-text heuristic its estimator was calibrated on.
 */
export interface BasicCompactConfig {
  /** Context window size in tokens. */
  contextWindow: number
  /** Compact when estimated token usage exceeds this fraction of context window. */
  thresholdRatio: number
  /** Number of tokens of recent context to retain during compaction. */
  retainTokens: number
  /** Model to use for summarization (`''` — uses the agent's model). */
  summarizationModel: string
  /** Provider generation cap for the summarization call. */
  maxTokens: number
  /** Extra compaction attempts when the first compacted surface is still over threshold. */
  compactionRetries: number
  /** Enable automatic compaction on the `agent/pre-step` seam (default true). */
  auto?: boolean
  /**
   * Text density for the token estimator: estimated tokens = chars /
   * `charsPerToken`. Defaults to 4 (typical English text). A CJK-heavy
   * deployment should set ~1-2 — CJK runs at roughly 1-2 chars per token, so
   * the default UNDERestimates several-fold and compaction fires far too late.
   * May be fractional.
   */
  charsPerToken?: number
}

Source: packages/compact/compact-basic/src/types.ts:20

@deepseek-ai/dsh-fs-local

/** Configuration for the local filesystem backend. */
export interface Config {
  /** Base directory for relative paths. Defaults to `process.cwd()`. */
  cwd?: string
}

Source: packages/fs/fs-local/src/index.ts:58

@deepseek-ai/dsh-hooks-claude

Requires: bash

/** Plugin config: where the CC hook config lives + substitution roots. */
export interface Config {
  /**
   * Path to a `hooks.json` or a settings file whose `hooks` key holds the config.
   * PROCESS-LEVEL: read once at load, a relative path resolves against the process
   * launch cwd, so one config applies to the whole process.
   * TODO(per-session-hook-config): per-session discovery of a project-local
   * `hooks.json` from each `session/new.cwd` is not yet implemented.
   */
  configPath: string
  /**
   * Replaces `${CLAUDE_PLUGIN_ROOT}` in command strings (the plugin's root dir).
   */
  pluginRoot?: string
  /**
   * Replaces `${CLAUDE_PROJECT_DIR}` in command strings AND is exported as the
   * `CLAUDE_PROJECT_DIR` env var for hook processes. When omitted, the env var
   * defaults per-run to the agent's session workspace (`session.header.cwd`, the
   * same dir the hook runs in) — Claude Code always exports this var, and common
   * unmodified hooks reference `$CLAUDE_PROJECT_DIR` for project-relative paths.
   */
  projectDir?: string
  /** Default per-hook timeout in ms when a hook sets none (CC default: 600000). */
  defaultTimeoutMs?: number
  /** Character cap for the `hook/result` event's persisted stderr summary. */
  stderrSummaryMaxChars?: number
}

Source: packages/hooks/hooks-claude/src/index.ts:56

@deepseek-ai/dsh-hooks-codex

Requires: bash

/** Plugin config: where the Codex hooks.json lives + the model name for payloads. */
export interface Config {
  /**
   * Path to a Codex `hooks.json`. PROCESS-LEVEL: read once at load, a relative
   * path resolves against the process launch cwd.
   * TODO(per-session-hook-config): per-session project-local discovery from each
   * `session/new.cwd` is not yet implemented.
   */
  configPath: string
  /** The model name stamped on every payload (Codex includes `model` on each event). */
  model?: string
  /** Default per-hook timeout in ms when a hook sets none (Codex default: 600000). */
  defaultTimeoutMs?: number
  /** Character cap for the `hook/result` event's persisted stderr summary. */
  stderrSummaryMaxChars?: number
}

Source: packages/hooks/hooks-codex/src/index.ts:43

@deepseek-ai/dsh-invariants

Requires: sessions

/** Plugin config. */
export interface Config {
  /**
   * Deep-freeze logged session-event data so mutating a logged event throws.
   * Default true — this plugin only runs in dev/test, where freezing is the
   * point. Set false to assert the event contract without freezing.
   */
  freeze?: boolean
}

Source: packages/support/invariants/src/index.ts:45

@deepseek-ai/dsh-llm-deepseek

Requires: llm

/**
 * Plugin config, validated by the same-named schemastery schema. Every field
 * is optional in yml: credentials/endpoint fall back to the environment (a
 * missing API key fails plugin load, not the first call), and omitted
 * thinking fields send nothing on the wire, so the provider default applies.
 */
export interface Config {
  /** API key; falls back to $DEEPSEEK_API_KEY. Required one way or the other. */
  apiKey?: string
  /** Endpoint base; falls back to $DEEPSEEK_BASE_URL, then the public API. */
  baseURL?: string
  /** Model names to register (sent verbatim on the wire). */
  models?: string[]
  /** Thinking-mode default for every request (provider default: enabled). */
  thinking?: 'enabled' | 'disabled'
  /** Thinking effort (only meaningful with thinking enabled). */
  reasoningEffort?: 'high' | 'max'
}

Source: packages/llm/llm-deepseek/src/index.ts:43

@deepseek-ai/dsh-llm-pi-ai

Requires: llm

/**
 * Plugin config, validated by the same-named schemastery schema. Every field
 * is optional in yml: credentials/endpoint fall back to the environment (a
 * missing API key fails plugin load, not the first call).
 */
export interface Config {
  /** API key; falls back to $DEEPSEEK_API_KEY. Required one way or the other. */
  apiKey?: string
  /** Endpoint base; falls back to $DEEPSEEK_BASE_URL, then the public API. */
  baseURL?: string
  /** Model names to register (sent verbatim on the wire). */
  models?: string[]
  /**
   * Thinking level for every request: 'off' disables thinking mode; 'high'
   * and 'xhigh' (wire 'max') set the effort. Omitted = provider default
   * (thinking enabled), matching llm-deepseek's omission semantics.
   */
  reasoning?: PiAiReasoning
}

/** Reasoning levels surfaced by this adapter (DeepSeek wire: high|max). */
export type PiAiReasoning = 'off' | 'high' | 'xhigh'

Source: packages/llm/llm-pi-ai/src/index.ts:37

@deepseek-ai/dsh-llm-replay

Requires: llm

/** Plugin config: the {@link ReplayConfig} inputs, each defaulting to its `DSH_SNAPSHOT_*` env var in `apply`. */
export interface Config {
  /** Override the fixture path; defaults to `$DSH_SNAPSHOT_FILE`. */
  file?: string
  /** Override the sidecar path; defaults to `$DSH_SNAPSHOT_OVERRIDE`. */
  overrideFile?: string
  /**
   * Override the child-log paths; defaults to `$DSH_SNAPSHOT_CHILD_FILES` (a
   * path-separator-delimited list). Each is a recorded subagent session log for
   * a nested-agent scenario; absent/empty for a single-session scenario.
   */
  childFiles?: string[]
}

Source: packages/support/llm-replay/src/index.ts:429

@deepseek-ai/dsh-repeat-tool-guard

/**
 * Plugin config, validated by the same-named schemastery schema plus the
 * load-time checks in `apply` (misconfiguration fails loud: an empty
 * `thresholds` list, a non-integer, a value below 2, or a duplicate throws at
 * plugin load, never a silent fall-back). `include`/`exclude` entries are
 * `*`-wildcard predicates over tool names at call time, not references to
 * registry entries — a pattern matching no currently registered tool is valid
 * (`exclude: [mcp_*]` must stay legal in a deployment that loads no MCP tools).
 */
export interface Config {
  /** Consecutive-repeat counts that trigger a reminder (default `[3, 5, 8]`). */
  thresholds?: number[]
  /** Tool-name patterns to track; empty means every tool is tracked. */
  include?: string[]
  /** Tool-name patterns transparent to the chain (neither count nor reset). */
  exclude?: string[]
  /**
   * Maximum characters of canonical arguments quoted in the DETAILED reminder
   * (default 500). Large payloads (a `write` body, a long command) would
   * otherwise ride into the next request unbounded — precisely in a loop
   * scenario; the cap bounds the reminder, never the detection (the chain key
   * always compares the FULL canonical string).
   */
  argumentsPreviewChars?: number
}

Source: packages/guard/repeat-tool-guard/src/index.ts:55

@deepseek-ai/dsh-session-persistence-jsonl

Requires: sessions

/** Plugin config: where the JSONL backend keeps its session logs (`root` is required — no default). */
export interface Config {
  /**
   * Root directory for all session files. Required (no default): a default of
   * `process.cwd()` would scatter session files as the process's cwd changes
   * (bash calls, subprocesses). Sessions group under per-cwd subdirectories.
   */
  root: string
}

Source: packages/session-persistence/session-persistence-jsonl/src/index.ts:35

@deepseek-ai/dsh-session-persistence-sqlite

Requires: sessions

/** Plugin configuration. */
export interface Config {
  /**
   * Filesystem path to the SQLite database file. The special value `:memory:`
   * opens an in-process database (tests); a file path is created (with parent
   * dirs) on construction.
   */
  path: string
  /**
   * SQLite `journal_mode` pragma. `wal` (the default) is the recorded
   * durability model; pick a rollback-journal mode (`delete`/`truncate`/
   * `persist`) on filesystems where WAL's shared-memory files do not work
   * (network mounts). See {@link JournalMode}.
   */
  journalMode?: JournalMode
}

/**
 * Journal modes the backend will run under. `wal` is the default and the
 * durability model the persistence ADR records; the rollback-journal modes
 * (`delete`/`truncate`/`persist`) exist for filesystems where WAL's
 * shared-memory files do not work (network mounts). `memory`/`off` are
 * excluded: dropping journal durability silently contradicts what this
 * backend promises.
 */
export type JournalMode = 'wal' | 'delete' | 'truncate' | 'persist'

Source: packages/session-persistence/session-persistence-sqlite/src/index.ts:50

@deepseek-ai/dsh-session-query

Requires: sessions

/** Configuration for the provider-neutral session-query service. */
export interface Config {
  /** Explicit provider id; omitted auto-selects exactly one usable provider. */
  searchProvider?: string
  /** Default search result page size. Defaults to 20. */
  defaultLimit?: number
  /** Maximum accepted search page size. Defaults to 100. */
  maxLimit?: number
  /** Maximum accepted raw read context on either side. Defaults to 50. */
  readWindowMax?: number
}

Source: packages/session-query/session-query/src/config.ts:17

@deepseek-ai/dsh-stdio-agent

/**
 * App config: the swappable per-demo values, each routed to where the app wires
 * it. `model`/`resumeSessionId` configure the pre-created `main` agent (through
 * {@link @deepseek-ai/dsh-agent-core}'s forwarded `agents` list); `persona` is
 * the deployment persona (forwarded to the system-prompt plugin); `toolOrder`
 * is the explicit model-facing tool order (forwarded to the system-prompt plugin);
 * `persistenceRoot` is the JSONL backend's directory; `welcome` is the UI banner.
 */
export interface Config {
  /** Model name for the `main` agent (must have a registered adapter). */
  model: string
  /** Deployment persona (the system-prompt plugin's `persona` config). */
  persona?: string
  /** Explicit model-facing tool order (the system-prompt plugin's `toolOrder` config; see dsh-system-prompt). */
  toolOrder?: string[]
  /** Tool-registry config — its presentation `mode` (forwarded through agent-core; see dsh-tools). */
  tools?: ToolsConfig
  /** Directory the JSONL session backend writes under. Defaults to `./.sessions`. */
  persistenceRoot?: string
  /** stdin-chat banner printed once on start. Defaults to `'ready.'`. */
  welcome?: string
  /**
   * If set, the `main` agent RESUMES this persisted session id instead of
   * starting fresh. Sourced from an env var in the leaf `cordis.yml`
   * (`resumeSessionId: !!js process.env.RESUME_SESSION_ID`).
   */
  resumeSessionId?: string
}

Depends on: ToolsConfig

Source: packages/ui/stdio-agent/src/index.ts:63

@deepseek-ai/dsh-subagent-acp

Requires: subagents

/** Config: how to spawn and drive the child ACP agent process. */
export interface Config {
  /** Provider name on `ctx.subagents` (default `acp`). */
  providerName: string
  /** The executable to spawn for each run (the child ACP agent). */
  command: string
  /** Arguments passed to {@link command}. */
  args: string[]
  /**
   * Working directory for the child process and its ACP session. Defaults to
   * the parent process's cwd when omitted.
   */
  cwd?: string
  /**
   * How to auto-answer the child's `session/request_permission` prompts:
   * `reject` (default — decline every prompt) or `allow` (approve via the first
   * allow-shaped option). The first cut surfaces no prompt to a human.
   */
  permission: PermissionPolicy
  /**
   * Extra environment variables for the child process — e.g. the child
   * harness's own `DEEPSEEK_API_KEY`. Forwarded on top of a credential-scrubbed
   * copy of the parent env, so an explicit key here reaches the child while
   * ambient secrets do not leak implicitly.
   */
  env: Record<string, string>
  /**
   * Grace period (ms) for the child's EOF-driven quiesce on dispose — its
   * window to flush persistence and tear down its own nested subprocesses
   * before the parent escalates to a signal.
   */
  disposeEofGraceMs?: number
  /** Grace period (ms) between `SIGTERM` and the `SIGKILL` escalation on dispose. */
  disposeGraceMs?: number
}

/**
 * How the client answers a child's `session/request_permission`. The first cut
 * does not surface permission prompts to a human, so every request is
 * auto-answered by this fixed policy:
 *
 * - `reject` — decline every prompt (answer `cancelled`). Safe default: a child
 *   that asks before a side effect does not get to take it.
 * - `allow` — approve every prompt by selecting its first `allow_*` option (or,
 *   if none is offered, `cancelled`). Use when the child is trusted to act.
 */
export type PermissionPolicy = 'allow' | 'reject'

Source: packages/subagent/subagent-acp/src/index.ts:30

@deepseek-ai/dsh-subagent-fork

Requires: subagents · agents

/** Config: the registry name to register the provider under. */
export interface Config {
  /** Provider name on `ctx.subagents` (default `fork`). */
  providerName: string
}

Source: packages/subagent/subagent-fork/src/index.ts:38

@deepseek-ai/dsh-subagent-mock

Requires: subagents

/** Config for the mock provider; all optional with test-friendly defaults. */
export interface Config {
  /** Registry name to register under. */
  name: string
  /** The text the scripted child "returns" as its final answer. */
  reply?: string
  /** The stop reason the run settles with. */
  stopReason?: SubagentStopReason
  /** Which start-time capabilities to advertise (default: all `true`). */
  capabilities?: Partial<SubagentCapabilities>
  /**
   * The context contract to declare ({@link SubagentProvider.inheritsParentContext});
   * default `false` (spawn-like). Set `true` to exercise the fork-shaped tool
   * wording in consumer tests.
   */
  inheritsParentContext?: boolean
  /**
   * Structured value surfaced when a request carries an `outputSchema` and the
   * `outputSchema` capability is on (default: `{ reply }`).
   */
  structured?: unknown
}

Depends on: SubagentCapabilities · SubagentStopReason

Source: packages/support/subagent-mock/src/index.ts:84

@deepseek-ai/dsh-subagent-spawn

Requires: subagents · agents

/** Config: the registry name to register the provider under. */
export interface Config {
  /** Provider name on `ctx.subagents` (default `spawn`). */
  providerName: string
}

Source: packages/subagent/subagent-spawn/src/index.ts:36

@deepseek-ai/dsh-system-prompt

/** Plugin config: the deployment-authored fragment of the system prompt (see {@link Config.persona} for its contract). */
export interface Config {
  /**
   * The deployment's persona — the ONE deployment-authored fragment of the
   * system prompt, rendered as the order-0 `deployment:persona` section
   * (after the harness identity, before all tool guidance). Every agent in
   * the context shares it, subagents included. Template, not free-form text:
   * every complete `{{…}}` group is interpreted strictly against the
   * registered prompt variables (the shipped agent loop registers `{{model}}`
   * and `{{cwd}}`), and there is no escape syntax for literal `{{…}}` prose
   * yet (a deliberate deferral; see the prompt-variables RFC). Defaults to
   * `''` — the empty section is dropped at render, so a persona-less
   * deployment opens with the harness identity alone.
   */
  persona?: string
  /**
   * Explicit model-facing tool order, as a list of `ToolSchema.name`s: listed
   * tools take their listed position, and tools absent from the list are
   * inserted at the {@link TOOL_ORDER_REST} (`'<unlisted-tools>'`) entry in
   * lexicographic name order. A configured list must contain the rest entry
   * exactly once, no duplicate names, and no name without a registered tool —
   * a misconfigured order blocks work instead of silently reaching a model
   * request: shape violations throw at load, and an unregistered name rejects
   * every assembly. `TOOL_ORDER_REST` is reserved for the list marker and may
   * not be a collected tool name; such a provider output also rejects the
   * assembly. The single assembly-time validation rejects either failure
   * before any model request — the earliest moment the registered tool set
   * exists to check against, since tool plugins register after this service
   * constructs. When omitted, tools are ordered lexicographically by name.
   * Applied to the tools
   * {@link SystemPrompt.assemble} collects, BEFORE the
   * `system-prompt/assemble` waterfall — like the sections' `order` sort, it
   * canonicalizes what the registry contributed (registration order is a
   * plugin-load artifact); a waterfall listener that mutates the tool list
   * owns the determinism of what it emits. Rationale (and why not per-plugin
   * weights): docs/rfc/implemented/feature/2026-07-06-explicit-tool-order.md.
   */
  toolOrder?: string[]
}

Source: packages/core/system-prompt/src/index.ts:179

@deepseek-ai/dsh-tool-cordis

Requires: tools

/** Config for the tool-cordis plugin: the sandbox evaluation bound. */
export interface Config {
  /**
   * Milliseconds the SYNCHRONOUS portion of mount code may run in the vm
   * before evaluation is aborted (default 5000). An async body escapes this
   * bound — see docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md for the trust stance.
   */
  vmTimeoutMs?: number
}

Source: packages/cordis/tool-cordis/src/index.ts:53

@deepseek-ai/dsh-tool-fs

Requires: tools · fs · systemPrompt

/** Plugin config (all optional — `Config` supplies the defaults). */
export interface Config {
  /** Default and maximum number of lines returned by one `read` call. */
  readLimit?: number
  /** Maximum characters returned for a single line before truncation. */
  readMaxLineLength?: number
  /** Maximum bytes returned for the selected lines of one `read` call. */
  readMaxBytes?: number
  /** Files at or above this size stream instead of loading whole into memory. */
  readStreamMinSize?: number
}

Source: packages/fs/tool-fs/src/index.ts:48

@deepseek-ai/dsh-tool-subagent

Requires: tools · subagents

/** Config: which registered provider this tool delegates to, plus child defaults. */
export interface Config {
  /** The `ctx.subagents` provider name to start runs on (e.g. `spawn`, `acp`). */
  provider: string
  /**
   * The model-facing tool name to register (default `subagent`). To expose more
   * than one transport, load this plugin once per provider — each load MUST set
   * a distinct `toolName` (the tool registry rejects a duplicate name), e.g.
   * `{ provider: 'spawn', toolName: 'subagent' }` and
   * `{ provider: 'acp', toolName: 'subagent_acp' }`.
   */
  toolName?: string
  /**
   * Default per-child agent options (model) applied to every spawned child.
   * Omitted fields fall back to the child loop's own defaults. There is no
   * per-child persona: the deployment persona (the system-prompt plugin's
   * `persona` config) is a context-wide section every agent shares.
   */
  agentOptions?: AgentOptions
}

Depends on: AgentOptions

Source: packages/subagent/tool-subagent/src/index.ts:44

@deepseek-ai/dsh-tool-web

Requires: tools · web · systemPrompt

/** Plugin config: which web tools to register, the source cap, and per-tool budgets. */
export interface Config {
  /** Register `web_search`. Defaults to true. */
  search?: boolean
  /** Register `web_fetch`. Defaults to true. */
  fetch?: boolean
  /** Upper bound on sources returned by one `web_search` call. */
  searchMaxResults?: number
  /** Cooperative timeout budget (ms) for `web_fetch`. Defaults to 30000. */
  fetchTimeoutMs?: number
  /** Cooperative timeout budget (ms) for `web_search`. Defaults to 30000. */
  searchTimeoutMs?: number
}

Source: packages/web/tool-web/src/index.ts:40

@deepseek-ai/dsh-tool-workflow

Requires: tools · workflows · systemPrompt

/** Config: the model-facing tool name plus result rendering caps. */
export interface Config {
  /** The model-facing tool name to register (default `workflow`). */
  toolName?: string
  /** Rendered-result ceiling, in characters: a longer JSON value is truncated with a notice (default 50000). */
  maxResultChars?: number
}

Source: packages/workflow/tool-workflow/src/index.ts:39

@deepseek-ai/dsh-tools

Requires: systemPrompt

/** Plugin config: how the registered tools are presented to the model. */
export interface Config {
  /**
   * The presentation mode. `'native'` (the default) contributes every
   * registered tool as a wire function definition — byte-for-byte today's
   * behavior. `'code'` contributes exactly ONE wire tool, `run_code`, plus
   * the generated `tools:sdk` prompt section declaring every other tool as a
   * TypeScript API the program calls. `'both'` contributes every native
   * definition AND `run_code` + the SDK section. Non-native modes require a
   * loaded `ctx.codeRuntime` whose `language` is `'typescript'` — a missing
   * or mismatched runtime rejects every prompt assembly with an actionable
   * error (misconfiguration fails loud, before any model request). A
   * configured `systemPrompt.toolOrder` naming native tools likewise rejects
   * every assembly under `'code'` (those names are no longer contributed) —
   * a deployment switching modes updates its order config or drops it.
   */
  mode?: ToolPresentationMode
}

/** How the registry presents its tools to the model (see {@link Config.mode}). */
export type ToolPresentationMode = 'native' | 'code' | 'both'

Source: packages/core/tools/src/index.ts:319

@deepseek-ai/dsh-web

/**
 * Config for the web seam. `searchProvider` / `fetchProvider` pin which provider
 * wins for each capability; both are optional (a single registered usable
 * provider auto-selects). Operational overrides such as environment variables
 * must feed these same fields rather than introduce a hidden priority chain.
 */
export interface WebServiceConfig {
  /** Explicit search provider id. Omitted = auto-select when exactly one usable. */
  readonly searchProvider?: string
  /** Explicit fetch provider id. Omitted = auto-select when exactly one usable. */
  readonly fetchProvider?: string
}

Source: packages/web/web/src/index.ts:68

@deepseek-ai/dsh-web-fetch-local

Requires: web

/** Plugin config: the provider's transport and size limits plus its `User-Agent` (all defaulted). */
export interface Config {
  /** Maximum accepted request URL length. */
  maxUrlLength?: number
  /** Maximum response body size in bytes. */
  maxResponseBytes?: number
  /** Maximum decoded body length in characters. */
  maxBodyChars?: number
  /** Default fetch timeout in milliseconds. */
  timeoutMs?: number
  /** Upper bound for a per-request timeout override. */
  maxTimeoutMs?: number
  /** Maximum number of same-origin redirect hops to follow. */
  maxRedirects?: number
  /** `User-Agent` header sent on every request. */
  userAgent?: string
}

Source: packages/web/web-fetch-local/src/index.ts:34

@deepseek-ai/dsh-web-search-deepseek

Requires: web

/** Plugin config (all optional — `apply` fills env-var and constant defaults). */
export interface Config {
  /** DeepSeek API key. Falls back to `$DEEPSEEK_API_KEY`. Empty → unavailable. */
  apiKey?: string
  /** Anthropic-compatible endpoint base; `/messages` is appended. */
  baseURL?: string
  /** Anthropic-format model name. Defaults to `deepseek-v4-flash`. */
  model?: string
  /** `anthropic-version` header value. Defaults to `2023-06-01`. */
  apiVersion?: string
  /** Upper bound on generated tokens for the Messages request. Defaults to 4096. */
  maxTokens?: number
  /** Maximum `web_search` server-tool uses per request. Defaults to 5. */
  maxUses?: number
}

Source: packages/web/web-search-deepseek/src/index.ts:48

@deepseek-ai/dsh-web-search-exa

Requires: web

/** Plugin config (all optional — `apply` fills env-var and constant defaults). */
export interface Config {
  /** Exa API key. Falls back to `$EXA_API_KEY`. Empty → provider unavailable. */
  apiKey?: string
  /** Endpoint base; `/search` is appended. Defaults to the public API. */
  baseURL?: string
  /** Retrieval mode sent as Exa's `type`. Defaults to `auto`. */
  searchType?: 'auto' | 'keyword' | 'neural'
  /** Default result count when a request carries no `maxResults`. Omitted = none. */
  numResults?: number
  /** Highlight sentences requested per result. Defaults to 1. */
  highlightsPerResult?: number
}

Source: packages/web/web-search-exa/src/index.ts:39

@deepseek-ai/dsh-web-search-perplexity

Requires: web

/** Plugin config (all optional — `apply` fills env-var and constant defaults). */
export interface Config {
  /** Perplexity API key. Falls back to `$PERPLEXITY_API_KEY`. Empty → unavailable. */
  apiKey?: string
  /** Endpoint base; `/chat/completions` is appended. Defaults to the public API. */
  baseURL?: string
  /** Search model name. Defaults to `sonar`. */
  model?: string
  /** Upper bound on generated answer tokens. Defaults to 1024. */
  maxTokens?: number
  /** Recency window sent as `search_recency_filter`. Omitted = no filter. */
  searchRecency?: 'day' | 'week' | 'month' | 'year'
}

Source: packages/web/web-search-perplexity/src/index.ts:33

@deepseek-ai/dsh-workflow-workerthread

Requires: subagents

/** Plugin config (all optional — `static Config` supplies the defaults). */
export interface Config {
  /** The `ctx.subagents` provider children run on (default `spawn`). */
  provider?: string
  /** Concurrent `agent()` ceiling; `0` (the default) auto-resolves to `min(16, max(1, cores - 2))`. */
  maxConcurrentAgents?: number
  /** Total `agent()` calls one run may start — the runaway-loop backstop (default 1000). */
  maxTotalAgents?: number
  /** Items accepted by a single `parallel()`/`pipeline()` call (default 4096). */
  maxItemsPerCall?: number
  /** vm timeout for the script's initial synchronous slice, inside the worker (default 5000 ms). */
  syncTimeoutMs?: number
  /**
   * How long after a cancellation an unsettled script may keep running before
   * the run force-settles `cancelled` and its worker is TERMINATED (default
   * 5000 ms); also bounds `dispose()`.
   */
  disposeGraceMs?: number
}

Source: packages/workflow/workflow-workerthread/src/index.ts:69

Loadable plugins with no config

These load from a cordis.yml entry with no config: block; they declare no config surface.

Seam packages (not directly loadable)

Abstract service classes — a deployment loads a concrete implementation package instead (capability seams).

Library packages (no plugin entry)

Imported as libraries by other packages; a cordis.yml cannot load them.