2026-07-15 18:08:28 +08:00
# Configuration
English | [中文 ](config.zh.md )
docs: purge chain-of-thought leakage from prose
Delete design-session citations (decision/audit/plan ordinals, stack
positions), change narration, review choreography, and reviewer-addressed
justification from comments, JSDoc, docs, READMEs, Agent Notes, tests, and
generator templates; restate every affected fact as current-state contract
prose. Fix generated docs at their sources and regenerate the catalogs and
cordis-surface regions; re-paste type-equiv blocks; update every bilingual
counterpart and re-record the pairs. Record the citation rule in the
committed-artifact-citations Agent Note.
2026-08-09 15:09:19 +08:00
Harness uses `cordis.yml` to describe which plugins an agent loads and the configuration passed to each one. The file composes capabilities; the generated configuration catalog records the fields and defaults each package actually supports.
2026-07-15 18:08:28 +08:00
## Start from a real configuration
The repository examples are runnable configurations and the most reliable starting points for a new project:
2026-08-06 04:40:40 +08:00
- [the `dsh-base` bundle patch ](../../../packages/bundle/base/cordis.patch.yml ) provides the common model, tools, persistence, policy, and telemetry rows every profile starts from.
- [the `dsh-web-app` bundle patch ](../../../packages/bundle/web-app/cordis.patch.yml ) adds the browser host, Workspace management, browser interaction, and client plugins.
2026-07-20 19:26:04 +08:00
- [headless-agent ](../../../examples/headless-agent/cordis.yml ) exposes the coding composition as a one-shot task.
2026-07-24 01:40:25 +08:00
- [acp-agent ](../../../examples/acp-agent/cordis.yml ) exposes fresh sessions to programmatic ACP clients.
2026-07-15 18:08:28 +08:00
A minimal configuration is a list of plugin entries:
```yaml
- id: llm-deepseek
name: '@deepseek -ai/dsh-llm-deepseek'
2026-08-07 15:43:26 +08:00
config:
apiKey: !!js process.env.DEEPSEEK_API_KEY
models:
- deepseek-v4-flash
2026-07-15 18:08:28 +08:00
2026-07-20 19:26:04 +08:00
- id: bash
name: '@deepseek -ai/dsh-bash-local'
refactor(cli)!: one shared base config with per-surface overlays
`dsh` shipped two config trees that were 43 rows the same: apps/cli/cordis.yml
composed web as 74 flat rows, while the TUI booted examples/tui-agent/cordis.yml
whose single `@deepseek-ai/dsh-tui-demo` row mounted twelve plugins behind a
twenty-key pass-through Config. Neither file was what its location claimed —
apps/cli hardcoded the "example" as the product default and the "demo" bundle
was the application — and every capability change had to be made twice.
- apps/cli/base.cordis.yml holds the 43 shared rows; tui.cordis.yml and
web.cordis.yml are patch lists stating only what differs per surface
- overlays apply as SIBLING patch lists at one include level, because include
patches never cross an include boundary. Precedence: base < surface <
(--config | personal ~/.dsh/config.yaml) < launcher flag/profile patches
- `--config` now applies an overlay INSTEAD OF the personal one, so a demo or
test tree never inherits the user's route; new `--config-replace` boots a file
as the entire tree (the old `--config` behaviour). Both survive /resume
- vendor/include: index each `insert`ed row as it is added so a later patch can
configure or disable it. Upstream built the id index once before the patch
loop, leaving every surface-only row — the whole TUI front door — silently
unpatchable from user config. Logged as local modification 8
- session identity moves to dsh-agent-loop's CONFIGURED_AGENT_IDENTITIES_KEY;
dsh-tui's MAIN_SESSION_ID_KEY is deleted (only the bundle read it)
- delete examples/tui-agent, examples/cordis-agent, packages/examples/tui-demo;
TUI tests → apps/cli/tests, cordis e2e → packages/cordis/tool-cordis/tests,
examples/code-mode survives as an overlay leaf
- `dsh web` gains --config, threaded into AppCLIEntry as an extra overlay
Three latent defects surfaced and are fixed here: the TUI captured the optional
sessionQuery service once at construction and could permanently disable /resume
when it won the mount race; the session-store root silently reverted to a
project-local ./.sessions; --config-replace was dropped by the resume handoff.
Verified by booting each tree through the real Loader (TUI 55 entries, web 75,
zero unsettled) rather than reading YAML. All eight terminal snapshots replay
byte-identically; 14/14 PTY smoke, 112/112 snapshots, 25/25 doc-sync, hygiene
and lint clean.
2026-07-29 13:58:21 +08:00
- id: agent-loop
name: '@deepseek -ai/dsh-agent-loop'
2026-07-15 18:08:28 +08:00
config:
refactor(cli)!: one shared base config with per-surface overlays
`dsh` shipped two config trees that were 43 rows the same: apps/cli/cordis.yml
composed web as 74 flat rows, while the TUI booted examples/tui-agent/cordis.yml
whose single `@deepseek-ai/dsh-tui-demo` row mounted twelve plugins behind a
twenty-key pass-through Config. Neither file was what its location claimed —
apps/cli hardcoded the "example" as the product default and the "demo" bundle
was the application — and every capability change had to be made twice.
- apps/cli/base.cordis.yml holds the 43 shared rows; tui.cordis.yml and
web.cordis.yml are patch lists stating only what differs per surface
- overlays apply as SIBLING patch lists at one include level, because include
patches never cross an include boundary. Precedence: base < surface <
(--config | personal ~/.dsh/config.yaml) < launcher flag/profile patches
- `--config` now applies an overlay INSTEAD OF the personal one, so a demo or
test tree never inherits the user's route; new `--config-replace` boots a file
as the entire tree (the old `--config` behaviour). Both survive /resume
- vendor/include: index each `insert`ed row as it is added so a later patch can
configure or disable it. Upstream built the id index once before the patch
loop, leaving every surface-only row — the whole TUI front door — silently
unpatchable from user config. Logged as local modification 8
- session identity moves to dsh-agent-loop's CONFIGURED_AGENT_IDENTITIES_KEY;
dsh-tui's MAIN_SESSION_ID_KEY is deleted (only the bundle read it)
- delete examples/tui-agent, examples/cordis-agent, packages/examples/tui-demo;
TUI tests → apps/cli/tests, cordis e2e → packages/cordis/tool-cordis/tests,
examples/code-mode survives as an overlay leaf
- `dsh web` gains --config, threaded into AppCLIEntry as an extra overlay
Three latent defects surfaced and are fixed here: the TUI captured the optional
sessionQuery service once at construction and could permanently disable /resume
when it won the mount race; the session-store root silently reverted to a
project-local ./.sessions; --config-replace was dropped by the resume handoff.
Verified by booting each tree through the real Loader (TUI 55 entries, web 75,
zero unsettled) rather than reading YAML. All eight terminal snapshots replay
byte-identically; 14/14 PTY smoke, 112/112 snapshots, 25/25 doc-sync, hygiene
and lint clean.
2026-07-29 13:58:21 +08:00
agents:
- id: main
2026-07-30 20:15:40 +08:00
provider: deepseek-official
refactor(cli)!: one shared base config with per-surface overlays
`dsh` shipped two config trees that were 43 rows the same: apps/cli/cordis.yml
composed web as 74 flat rows, while the TUI booted examples/tui-agent/cordis.yml
whose single `@deepseek-ai/dsh-tui-demo` row mounted twelve plugins behind a
twenty-key pass-through Config. Neither file was what its location claimed —
apps/cli hardcoded the "example" as the product default and the "demo" bundle
was the application — and every capability change had to be made twice.
- apps/cli/base.cordis.yml holds the 43 shared rows; tui.cordis.yml and
web.cordis.yml are patch lists stating only what differs per surface
- overlays apply as SIBLING patch lists at one include level, because include
patches never cross an include boundary. Precedence: base < surface <
(--config | personal ~/.dsh/config.yaml) < launcher flag/profile patches
- `--config` now applies an overlay INSTEAD OF the personal one, so a demo or
test tree never inherits the user's route; new `--config-replace` boots a file
as the entire tree (the old `--config` behaviour). Both survive /resume
- vendor/include: index each `insert`ed row as it is added so a later patch can
configure or disable it. Upstream built the id index once before the patch
loop, leaving every surface-only row — the whole TUI front door — silently
unpatchable from user config. Logged as local modification 8
- session identity moves to dsh-agent-loop's CONFIGURED_AGENT_IDENTITIES_KEY;
dsh-tui's MAIN_SESSION_ID_KEY is deleted (only the bundle read it)
- delete examples/tui-agent, examples/cordis-agent, packages/examples/tui-demo;
TUI tests → apps/cli/tests, cordis e2e → packages/cordis/tool-cordis/tests,
examples/code-mode survives as an overlay leaf
- `dsh web` gains --config, threaded into AppCLIEntry as an extra overlay
Three latent defects surfaced and are fixed here: the TUI captured the optional
sessionQuery service once at construction and could permanently disable /resume
when it won the mount race; the session-store root silently reverted to a
project-local ./.sessions; --config-replace was dropped by the resume handoff.
Verified by booting each tree through the real Loader (TUI 55 entries, web 75,
zero unsettled) rather than reading YAML. All eight terminal snapshots replay
byte-identically; 14/14 PTY smoke, 112/112 snapshots, 25/25 doc-sync, hygiene
and lint clean.
2026-07-29 13:58:21 +08:00
model: deepseek-v4-flash
2026-07-15 18:08:28 +08:00
```
## Plugin entries
`name` identifies an npm package or a local module relative to `cordis.yml` ; `id` gives the plugin instance a stable identity; and `config` supplies plugin-specific configuration. Set `disabled: true` to skip an entry temporarily.
```yaml
- id: local-tool
name: './src/my-tool.ts'
disabled: false
config:
toolName: my_tool
```
2026-08-05 12:46:38 +08:00
Cordis starts sibling entries concurrently. A plugin declares required services through `inject` ; Cordis waits for those services before applying the plugin, so file order does not establish dependency readiness. Missing models, tools, and plugins fail as early as possible instead of being silently ignored.
2026-07-15 18:08:28 +08:00
2026-08-06 04:40:40 +08:00
## CLI patch layers
2026-07-29 21:47:20 +08:00
2026-08-07 15:43:26 +08:00
`dsh --profile <name>` composes the profile's bundle patch layers (its manifest's `dsh.profile.bundles` list, in order) over an empty root, then the profile's own `~/.dsh/profiles/<name>/cordis.patch.yml` , the home-level `$DSH_HOME/cordis.patch.yml` , and each `--patch <path>` overlay. Later layers win per row. App flags are not another patch layer: the bundle's `cmdlineArgs` -injected startup row resolves them into a service, and rows that retain a `!!js` read of that service give the invocation value precedence.
2026-07-29 21:47:20 +08:00
2026-08-07 15:43:26 +08:00
A patch replaces a row's entire `config` value; it does not deep-merge keys. For example, patching `llm-deepseek` with only `config: { thinking: disabled }` also removes that row's configured `apiKey` and `baseURL` , so restate every key the row must retain.
2026-07-29 21:47:20 +08:00
2026-07-15 18:08:28 +08:00
## JavaScript values and environment variables
2026-08-07 15:43:26 +08:00
The Cordis loader evaluates runtime expressions tagged with `!!js` . Keep API keys and other secrets in the gitignored `.env` file at the repository root, never in committed configuration.
2026-07-15 18:08:28 +08:00
```yaml
config:
2026-08-07 15:43:26 +08:00
apiKey: !!js process.env.DEEPSEEK_API_KEY
2026-07-15 18:08:28 +08:00
cwd: !!js process.cwd()
```
The tag is `!!js` , not `!js` .
## Exact configuration reference
2026-08-09 15:34:32 +08:00
The generated [plugin configuration catalog ](../../config-catalog.md ) lists every current field, type, and default. For composition concepts, continue to the [architecture ](../../architecture.md ) and [capability seams ](../../capability-seams.md ). To create a configuration, copy the closest entry from the [examples overview ](../../../examples/README.md ) and adapt it.