Preface

The standard settings mechanism of DSH manages configuration through ctx.settings. Customizing these settings for a specific profile (such as web) usually requires manually managing complex override logic in the global settings.yaml. The xmoon/dsh-profile-settings plugin adds a transparent profile overlay on top of the official user settings mechanism, allowing each profile to have its own override file (settings.patch.yml) without breaking existing settings behavior.

Introduction

This is a DSH profile plugin maintained by XMoon. It adds profile-specific settings overrides, separating the global settings.yaml from profiles/<name>/settings.patch.yml, and allowing each profile to inherit global settings while overriding specific namespaces.

Core Features

  • Adds profile-specific settings overrides under ctx.settings.
  • Transparent layering: global settings.yaml + profiles/<name>/settings.patch.yml.
  • Recursive object merging, with arrays and scalars replaced as a whole.
  • Supports the YAML !unset directive to explicitly hide inherited values.
  • Provides a Web UI that displays a source marker for each field (Default / Composition / Global / Profile / Masked) and action buttons.
  • Supports hot reloading, with write locks and transactions to guarantee file integrity.

Installation and Enablement

This plugin requires the profile bundle to include @deepseek-ai/dsh-base (all built-in web / headless templates meet this requirement). The installation command is as follows:

dsh plugin --profile web add @xmoon76/dsh-profile-settings

The installation process automatically adds the package to dsh.profile.bundles. After restarting the Harness, the plugin performs the following actions:
1. Disables the base settings line (@deepseek-ai/dsh-settings-file).
2. Inserts a new line that owns ctx.settings.

Note: A composition can have only one ctx.settings owner. If the base line is still active and not fully disabled, bootstrapping fails with a Cordis duplicate service error.

Configuration

The inserted line is configured by default as follows (usually no modification is required):

Key Default Meaning
profile auto-detected Explicitly specified active profile name
globalPath $DSH_HOME/settings.yaml Path to the global settings document
profileFile settings.patch.yml Override file name inside the profile directory
dshHome $DSH_HOME or ~/.dsh Harness home directory
watch true Hot-reload both documents
debounceMs 100 Stabilization window for listener writes
writable true Allow in-process writes to the override file

The resolution order for the active profile is: explicit profile configuration -> installation location (profiles/<name>/node_modules/…) -> launcher argument --profile <name> -> DSH_PROFILE environment variable. If it cannot be determined, bootstrapping fails.

Overlay File Example

The overlay file is located at $DSH_HOME/profiles/<name>/settings.patch.yml. The file can be edited manually or modified through the settings command. In-process writes go to this file, rather than to settings.yaml.

# $DSH_HOME/profiles/web/settings.patch.yml
agent-default-model:
  provider: pi-ai
  model: gpt-5.6

permission:
  mode: danger-full-access

some-plugin:
  endpoint: !unset

Plain YAML values are used for overrides; !unset hides values from lower layers (inherited values are removed unless the overlay provides a new value). These masks do not enter the final resolved JSON document, and the UI does not display them as values.

Settings Commands

After the plugin is mounted, the ctx.profileSettings and settings command families are available:

settings layers [ns [path]]        查看每个叶子节点的来源证明
settings get <ns.path>              获取有效值
settings set <ns.path> <value>      写入配置文件覆盖
settings unset <ns.path>            删除覆盖值(重新继承)
settings mask <ns.path>             写入 !unset
settings unmask <ns.path>           移除掩码
settings reset <ns>                 对覆盖层执行 replace({})
settings promote <ns.path>          将值上移至全局文档
settings demote <ns.path>           将值下移至配置文件覆盖
settings migrate <ns.path> [--copy] 移动全局值到覆盖层(带 .bak 时间戳备份,--copy 保留原值)
settings diff [ns]                  叶子级全局与覆盖的差异
settings ui [ns]                    机器可读的层快照(Web UI)
settings profile                    查看活动配置文件和文档路径

Web UI

The plugin includes a browser-side component (dsh.client). The Web settings panel adds a “Profile Settings” section, showing the source marker, effective value, and actions (set/unset/mask/promote/reset, etc.) for each field. All host interactions are performed through the host-registered /profile-settings loopback RPC channel and do not involve session context or command logs.

Concurrency Model and Limitations

  • In-process operations: Ordinary update/replace/mutate calls follow the official settings semantics (namespace serialization queue, expectedRevision conflict detection).
  • Cross-process file integrity: Guaranteed using a write lock + atomic rename.
  • Cross-process custom layer operations (promote/demote/migrate/mask/unmask): Uses fixed-order locks and fences to ensure transactional consistency; each textual change advances the layer revision.

Limitations and failure modes:
* Requires Node >= 22.6.
* Bootstrapping fails if the profile cannot be resolved, the overlay root is not a map, a namespace is not an object, !unset appears inside an array, an unsupported YAML tag is used, the overlay path escapes the profile directory, the global and overlay files point to the same file, or a duplicate ctx.settings owner exists.
* Temporarily invalid YAML during hot reloading triggers a warning, but the last valid version is retained.

Summary

This plugin provides a standardized settings management solution for DSH profiles, enabling isolation across multiple profiles without modifying the underlying settings logic. For more details, refer to the directory page or the GitHub repository.