Introduction

The philosophy of DSH is “Everything is a plugin,” and profiles are used to divide different plugin environments. The safemode profile is positioned as a “clean environment”: it is the most suitable choice for troubleshooting, serving as a comparison baseline, or when you only want core capabilities.

However, the safemode profile is essentially just a set of ordinary files under $DSH_HOME/profiles/safemode/. One command dsh plugin --profile safemode add ..., one manual edit of package.json, or even a single mistaken edit in a script can make this environment no longer clean, and you might not discover it immediately. Manually verifying files one by one or manually cleaning them up is time-consuming and unreliable.

dsh-safemode-profile automates this: it forces restoration on startup and provides continuous guardianship during runtime, ensuring that dsh --profile safemode contains only the whitelisted core bundle at any moment.

What is it

dsh-safemode-profile is a DSH plugin by author jinsiyu, licensed under MIT. It has a single responsibility: to lock the safemode profile to the whitelist template—forcing restoration on startup and automatically detecting and restoring drift during runtime.

Prerequisites: DSH (@deepseek-ai/dsh) and Node.js (≥ 18) must be installed.

Core Features

Forced Restore on Startup

Every time DSH starts and loads this plugin, it unconditionally writes $DSH_HOME/profiles/safemode/ back to the whitelist template, involving three files:

File Forced Content
package.json dsh.profile.bundles is set to the whitelist (default @deepseek-ai/dsh-base + @deepseek-ai/dsh-web-app), dependencies is cleared
cordis.patch.yml Empty user patch layer
pnpm-workspace.yaml pnpm workspace settings

If consistent with the template, it remains unchanged (to avoid self-triggering). If inconsistent, it is rewritten.

Dual-Channel Guardian during Runtime

During the plugin’s lifetime, it monitors whether the profile has been modified using two channels:

  1. fs.watch real-time listening: Any change to the three files triggers an immediate restore after a 300ms debounce;
  2. 30-second polling fallback: detectDrift performs a full comparison, covering cases where fs.watch is unreliable (such as mount scenarios) or files are externally replaced.

If drift is detected—bundles are added/removed, the patch layer is written, or dependencies are modified—it automatically restores and logs a warning.

No Build Scripts, Install Once

There is no postinstall or any build scripts inside the package, so pnpm does not intercept it. dsh plugin add succeeds on the first try (exit code 0), and no configuration of approve-builds / allowBuilds is needed. All the work of restoration and guardianship is handled by the plugin when it loads during DSH startup.

Customizable Whitelist

The whitelist is the only entry point for customization, set via the environment variable DSH_SAFEMODE_BUNDLES. Both the guardian and restoration logic read the same whitelist, so changing one takes effect globally.

Installation and Enablement

First, confirm the prerequisites: DSH (@deepseek-ai/dsh) and Node.js (≥ 18) are installed. Choose one of the following three methods; the commands are based on the forms given in the official documentation:

Method A (Recommended, npm install):

dsh plugin --profile web add dsh-safemode-profile

Method B (GitHub Direct Install, Explicitly Specify main Branch):

dsh plugin --profile web add github:jinsiyu/dsh-safemode-profile#main

Method C (Local .tgz Pack):

npm pack                                          # Generates dsh-safemode-profile-<version>.tgz
dsh plugin --profile web add .\dsh-safemode-profile-<version>.tgz

After installation, restart DSH. Once the plugin is active, safemode enters the state of “forced restore + resident guardian.”

Typical Usage

Start with Zero Third-Party Plugins

dsh --profile safemode

Safemode also includes a webServer (default 3080). If running alongside the web profile, it is recommended to stagger the ports using --port:

dsh --profile safemode --port 3081

Customizing Whitelist

For example, if you only want to keep the pure CLI (no GUI):

$env:DSH_SAFEMODE_BUNDLES = "@deepseek-ai/dsh-base"

The dsh command will inherit this environment variable and take effect on startup. Note that you should not manually edit the safemode profile files; any changes will be restored by the guardian logic, and customizations should always go through this environment variable.

Manual Forced Restore

If you don’t want to restart DSH, or are troubleshooting an issue, you can trigger a restoration immediately:

node scripts/ensure-safemode.mjs

File System Hardening (Optional)

Beyond the plugin’s guardianship, you can set the three managed files to read-only to prevent dsh plugin --profile safemode add <package> from succeeding at the filesystem level: pnpm will fail to write these files, the installation will report an error directly, and the plugin will be unable to install; DSH startup remains unaffected. There are three levels:

  1. Basic Read-only (Recommended for daily use): Use attrib +R on Windows, chmod 444 on POSIX:
attrib +R "$env:USERPROFILE\.dsh\profiles\safemode\package.json" `
         "$env:USERPROFILE\.dsh\profiles\safemode\cordis.patch.yml" `
         "$env:USERPROFILE\.dsh\profiles\safemode\pnpm-workspace.yaml"
chmod 444 ~/.dsh/profiles/safemode/package.json \
          ~/.dsh/profiles/safemode/cordis.patch.yml \
          ~/.dsh/profiles/safemode/pnpm-workspace.yaml
  1. Windows ACL (icacls deny): Can be precise down to “write” and “delete,” but still cannot stop Administrators / SYSTEM (who have full control by default) or bypass via taking ownership;
  2. Linux immutable (chattr +i): The strongest tier; even root cannot modify it, but it requires sudo and the filesystem must support it (ext4/xfs support it).

Notes on Hardening:

  • Only lock these three managed files; do not lock the entire directory. Especially on Windows, do not use attrib +R <directory> /S to recursively lock—DSH rewrites cordis.yml on every startup, and a locked directory will cause safemode startup to fail (tested exit code 1).
  • Let the plugin create/restore the profile first (ensure content matches the whitelist template) before locking. If drift occurs after locking, the guardian restoration will fail due to read-only and log a warn—this is the expected behavior of locking: if locked, there should be no drift.
  • chattr +i will also block the plugin’s own self-healing restoration. You must run chattr -i before upgrading the plugin or modifying the whitelist. Basic read-only is sufficient for daily scenarios.

Use Cases and Considerations

Suitable Scenarios: You need a predictable, clean DSH environment for troubleshooting or comparison; or there are automated scripts or other people touching DSH configurations on the machine, and you want the safemode profile to be safe from accidental (or intentional) changes.

Things to clarify before use:

  1. Port Conflict: Safemode also includes a webServer with a default port of 3080. Running it alongside the web profile will fail to start due to EADDRINUSE. Use --port to stagger them (e.g., --port 3081).
  2. Session and Credential Isolation: sessions, settings.yaml, and .env are shared at the home level; safemode isolates only the plugins.
  3. Home Patch Stacking: ~/.dsh/cordis.patch.yml takes effect for every profile. Do not hang plugins there; the guardian logic only watches the safemode directory itself.
  4. Don’t manually edit cordis.yml: DSH automatically rewrites it on every startup. The safemode’s patch layer will be restored to empty by this plugin; customizations should go through DSH_SAFEMODE_BUNDLES.

Finally, a reminder as always: the plugin runs with the permissions of the current dsh process. It is recommended to read the source code (see the link at the end for the repository) and the license (MIT) before installing to ensure it meets your security requirements.

Summary

dsh-safemode-profile does one thing: keep dsh --profile safemode forever clean. With startup forced restoration, runtime dual-channel guardianship, and the optional file system read-only hardening, safemode will no longer quietly become “dirty.”

  • Plugin Directory Page: https://www.skillhub.cn/plugins/jinsiyu/dsh-safemode-profile
  • GitHub Repository: https://github.com/jinsiyu/dsh-safemode-profile

Note that the directory page is a community-maintained independent site with no official affiliation to DeepSeek / Huanfang, serving only as a search entry point.