Skip to content

Settings & Credentials

Dipanshu Kamboj edited this page Aug 31, 2026 · 1 revision

⚙️ Settings & Credentials

The harness keeps user configuration (settings.yaml) and secrets (.credentials.yaml) strictly separate — settings hold references, the credential store holds literals, and nothing crosses that line.

Files

File Holds Permissions
$DSH_HOME/settings.yaml Provider profiles, shell budgets, tool config, persona — everything user-tunable normal
$DSH_HOME/.credentials.yaml The literal API keys owner-only (0600)
$DSH_HOME/profiles/<name>/ Profile manifests + patch layers —

DSH_HOME overrides the default ~/.dsh for everything above.

Settings namespaces

Every plugin contributes its own namespace — the Settings page renders them from their declared schemas, and the same namespaces are the keys in settings.yaml:

Namespace Owns
llm-deepseek The direct DeepSeek route: models, capacities, baseURL, output cap
llm-pi-ai All other providers: one profile per route, apiKeyEnv, models, compat switches
shell namespaces Command budgets: timeouts, output caps, spill limits, kill grace
tool namespaces Per-tool defaults

Writes travel as path operations (set/unset on a field path) with an expectedRevision, so two surfaces editing simultaneously can't clobber each other — a stale writer gets a settings-conflict answer, not a silent overwrite.

The credential seam

Credentials are addressed by reference (credentialRef), not by value:

  • Settings say apiKeyEnv: DEEPSEEK_API_KEY — a name, not a secret.
  • The credential store resolves the reference to the literal at request time.
  • A key typed into the Models page lands in .credentials.yaml; the settings document only ever sees the reference.
  • The subprocess layer scrubs credential-shaped values from any environment handed to a child process.
  • Removing a key makes it unresolvable by design — no dangling half-credentials.

Launch environment

Environment facts (ambient credentials, launch-provided values) resolve in a defined order so a stored reference beats a stale ambient value, and a provider's own ambient discovery (AWS credential chains, gcloud, OAuth state) still works when it should — the auth context answers env() from the credential seam first, then the process environment.

Revision & conflict model

Every settings mutation bumps the namespace revision. The check happens at the front of the write queue — not at call time — so a writer holding a snapshot that a predecessor already superseded is rejected with settings-conflict instead of racing. Queued writes chain per-namespace, and one rejected write never poisons the queue for the next caller.

Practical notes

  • Changing model/provider config takes effect on the next request — no restart.
  • Every value is validated against its declared schema on write; invalid values are refused with the path that failed.
  • Read-only namespaces (pinned by deployment) render as such in the UI and refuse mutations.

Clone this wiki locally