Files
deepseek-harness/examples/headless-agent/cordis.yml
Yichen Jiang 03b534de16 feat(credentials): move the store to .credentials.yaml and layer $DSH_HOME/.env
$DSH_HOME/.env carried two incompatible jobs. As credentials-local's writable
secret store it could not be hoisted into process.env — hoisting makes every
stored key read as a read-only launch override and blocks rotation from the
TUI and the web page. But its name and dotenv format promise an environment
file, so a DEEPSEEK_BASE_URL sitting beside a working DEEPSEEK_API_KEY in the
same file was silently ignored: only the credential provider read the
document, and it addresses credential references alone.

Split the two jobs into two files.

.credentials.yaml is the provider-managed store: a strict YAML mapping of
CredentialRef to non-empty string, no version field, no wrapper level. Because
it holds credentials and nothing else, a non-mapping root, a non-identifier
key, a non-string value, an empty string, a duplicate key, and malformed YAML
are all rejections rather than skipped entries — loud at boot and at a write,
warn-and-keep-last-good on a live reload. The dotenv physical-line editor
gives way to a patch of the parsed document, so comments and untouched entries
keep their formatting and any string value round-trips, multi-line included.
Writer lock, read-modify-write, atomic 0600 write under a 0700 directory,
watcher, self-write suppression, and quiescent disposal are unchanged.

$DSH_HOME/.env becomes the user's ordinary environment layer. app-boot's new
loadLayeredEnv loads the invoking directory's .env then the Harness home's,
giving user < project < inherited; the home resolves from the inherited
environment first, so a project .env cannot redirect it.

Credential precedence is unchanged: the live environment still wins read-only
over the file, and shadowed writes still reject. Whether a provider-managed
store should instead win over the environment is a separate decision.

No migration: a key already in $DSH_HOME/.env keeps resolving through the new
environment layer, as a read-only env source that shadows the stored one.
2026-08-04 14:50:38 +08:00

145 lines
4.5 KiB
YAML

# One-shot coding agent with format-pure stdout. The app bin loads the
# gitignored root `.env` into the process environment; entry configs here are
# the composition base, while user-plane values resolve per request through
# the two providers below.
# User-settings document (`$DSH_HOME/settings.yaml`, hot-reloaded): a
# `llm-deepseek:` section there overrides the adapter entry below without a
# restart.
- id: settings
name: '@deepseek-ai/dsh-settings-local'
# Credential store: the live process environment over `$DSH_HOME/.credentials.yaml`
# (owner-only file, hot-reloaded). The adapter resolves `DEEPSEEK_API_KEY`
# through it at each request, so no key is inlined in this file.
- id: credentials
name: '@deepseek-ai/dsh-credentials-local'
# The DeepSeek adapter. Swap to '@deepseek-ai/dsh-llm-pi-ai' for the pi-ai-backed
# twin (a `providers` dict keyed by route; `reasoning: high` replaces
# thinking/reasoningEffort). Shipped default: full thinking at max effort on
# every request. Exact-model resolution materializes request defaults before
# the request header is logged.
- id: llm-deepseek
name: '@deepseek-ai/dsh-llm-deepseek'
config:
thinking: enabled
reasoningEffort: max
models:
- id: deepseek-v4-pro
contextWindow: 128000
- id: deepseek-v4-flash
contextWindow: 128000
# Managed child-process groups for the bash executor (spawn/kill/output plumbing).
- id: subprocess
name: '@deepseek-ai/dsh-subprocess-local'
- id: bash
name: '@deepseek-ai/dsh-bash-local'
config:
timeoutMs: 60000
# The app bundle pre-creates one fresh `main` agent per invocation.
- id: cli-agent
name: '@deepseek-ai/dsh-cli-demo'
config:
provider: deepseek-official
# Stays on flash: the goal/ralph replay corpora were recorded on it, and
# their nested-include overlays cannot re-pin the app config (a config
# patch cannot target an entry behind a nested include).
model: deepseek-v4-flash
persistenceRoot: './.sessions'
persistenceCompression: !!js "process.env.DSH_SNAPSHOT === undefined ? 'zstd' : 'none'"
workspaceContext:
maxBytes: 65536
persona: |
You are headless-agent, a coding assistant powered by the {{model}} model.
Verify your work by running the code or tests. Keep answers brief and
factual.
# Summarize an older range when derived history approaches the context window.
- id: token-meter
name: '@deepseek-ai/dsh-token-meter'
- id: compact-basic
name: '@deepseek-ai/dsh-compact-basic'
config:
thresholdRatio: 0.8
retainRatio: 0.16
maxTokens: 8192
compactionRetries: 1
# Expose fresh-child `spawn` and completed-prefix `fork` through independent
# in-process backends.
- id: subagent
name: '@deepseek-ai/dsh-subagent'
- id: subagent-spawn
name: '@deepseek-ai/dsh-subagent-spawn'
config:
providerName: spawn
- id: subagent-fork
name: '@deepseek-ai/dsh-subagent-fork'
config:
providerName: fork
# Continuable background children are selected per delegation tool. The
# separately loaded control registers global `send_message`; `report` is
# installed only in continuable child scopes.
- id: tool-subagent-control
name: '@deepseek-ai/dsh-tool-subagent-control'
- id: tool-subagent-report
name: '@deepseek-ai/dsh-tool-subagent-report'
- id: tool-subagent
name: '@deepseek-ai/dsh-tool-subagent'
config:
provider: spawn
toolName: subagent
backgroundMode: continuable
maxDepth: 1
- id: tool-subagent-fork
name: '@deepseek-ai/dsh-tool-subagent'
config:
provider: fork
toolName: subagent_fork
backgroundMode: continuable
maxDepth: 1
# The worker-thread workflow engine fans a model-written JavaScript script's
# `agent()` calls out through the spawn backend.
- id: workflow-workerthread
name: '@deepseek-ai/dsh-workflow-workerthread'
config:
provider: spawn
- id: tool-workflow
name: '@deepseek-ai/dsh-tool-workflow'
# A separate fixed consumer demonstrates fresh-agent Ralph iteration without
# changing the workflow tool or same-session goal behavior.
- id: tool-ralph
name: '@deepseek-ai/dsh-tool-ralph'
# `todo_write` replaces the logged whole list.
- id: tool-todo
name: '@deepseek-ai/dsh-tool-todo'
# Policy loads before the model-facing filesystem tools so writes and edits
# require an observed file. Relative paths resolve from the process cwd.
- id: fs-local
name: '@deepseek-ai/dsh-fs-local'
config:
cwd: !!js process.cwd()
- id: fs-policy
name: '@deepseek-ai/dsh-fs-policy'
- id: tool-fs
name: '@deepseek-ai/dsh-tool-fs'