SLAPaper
dsh-self-checking-profile
A drop-in dsh web profile that adds the **Self Checking** sandbox mode to DeepSeek Harness (dsh)
- Stars
- 1
- Language
- JavaScript
- Created
- Aug 13, 2026
- Updated
- Aug 14, 2026
Introduction
dsh Self Checking profile

This project is based on dsh / DeepSeek Harness, the open-source AI agent
harness by DeepSeek (source
· @deepseek-ai/dsh on npm):
it ships as a dsh web profile that layers a reproducible fork set on top of a
pristine dsh install — upstream packages stay untouched.
A drop-in dsh web profile that adds the Self Checking sandbox mode on top
of workspace-write and danger-full-access, as a fully reproducible fork
layer plus release tooling.
- Fork layer — 11 forked
@deepseek-aipackages underprofile/forks/that shadow the identical upstream packages for the profile only; upstream installs stay pristine. - Patch set —
patches/*.json(machine-applied anchored replacements) andpatches/*.diff(human review) that rebuild the fork layer from a pristine dsh 0.1.0-rc.6 install, byte-for-byte. - Upstream tracking —
upstream/vendors the exact npm package bytes of the baseline, git-tracked and versioned inupstream/VERSION. Upgrading to a new dsh baseline is a three-way merge over that committed snapshot (tools/merge-upstream.mjs), not a blind re-patch: files changed only by upstream are taken, files changed only by the fork are kept, files changed on both sides are merged withgit merge-file(diff3), and genuine conflicts surface with markers instead of silently misapplying. - Release tooling — install scripts, an acceptance verifier, a rebuild tool for upstream upgrades, and a release packager.
What Self Checking does
Self Checking is "full access with a workspace boundary check":
-
Every command/operation runs under
workspace-writeconfinement by default. -
A command/operation denied for touching a path outside the workspace is intercepted once: the model sees
[sandbox: self-check intercepted — this command attempted to access a path outside the workspace; unless this access is intentional, do not re-run this command — if it IS intentional, re-run the exact same command and it will be allowed with full access]and nothing was executed.
The notice demands a deliberate self-check: a re-run is the sanctioned continuation only when the outside access is intentional.
-
Re-running the exact same command/operation executes it with full access (no approval prompt), for the rest of the session.
It is selectable like any other permission preset — Settings → Permission
(default for new sessions) or the composer permission picker / /permission self-checking (current session).
Repository layout
├── upstream/ vendored baseline snapshot (git-tracked)
│ ├── VERSION baseline version (e.g. 0.1.0-rc.6)
│ └── @deepseek-ai/ exact npm package bytes of the 11 packages
├── profile/ the installable profile template
│ ├── forks/ the 11 forked packages (source of truth)
│ ├── cordis.patch.yml Self Checking permission preset (+ layout notes)
│ ├── cordis.yml profile root (empty entry list)
│ ├── package.json bundles + fork `file:` dependencies
│ └── pnpm-workspace.yaml nodeLinker: hoisted
├── patches/ rebuild manifests (.json) + review diffs (.diff)
├── tools/
│ ├── snapshot-upstream.mjs vendor a new upstream baseline into upstream/
│ ├── merge-upstream.mjs three-way merge a new baseline into the forks
│ ├── gen-patches.mjs regenerate the patch set from pristine + forks
│ ├── rebuild-fork.mjs rebuild the fork layer from pristine + patches
│ └── build-release.mjs package the release zip
├── tests/
│ ├── verify-self-checking.mjs dev regression (vocabulary/gate/fence/executor)
│ ├── verify-acl-probe.mjs live windows-acl runner probe
│ └── profile-acl-test.mjs full ACL chain against an installed profile
├── install.ps1 / install.sh install the profile into $DSH_HOME
├── verify.mjs acceptance verifier (copied into each install)
├── docs/ screenshots referenced by the READMEs
├── CHANGELOG.md
└── LICENSE MIT (upstream packages keep their own LICENSE)
Requirements
- dsh 0.1.0-rc.6 (the fork baseline; run
npx @deepseek-ai/dshonce so the shared module fallback~/.dsh/profiles/node_modulesexists) - Windows, macOS, or Linux — the code is platform-neutral; the interception uses each platform's workspace-write backend (ACL restricted token on Windows, bwrap/Landlock on Linux, Seatbelt on macOS)
Install
From a checkout of this repository:
# Windows
powershell -ExecutionPolicy Bypass -File install.ps1 # installs as profile "self-checking"
# macOS / Linux
./install.sh
The script copies profile/ to ~/.dsh/profiles/<name>/ and assembles the
fork layer from profile/forks/ into node_modules/@deepseek-ai/
(node_modules is a build artifact and is not tracked by git). Then start:
npx @deepseek-ai/dsh --profile self-checking
pnpm-managed install (optional)
The profile also ships its forks as file: dependencies in package.json,
so the fork layer can be (re)installed by the package manager instead of by
the copy step — installs no longer prune it, and upgrading the fork set is one
dependency bump:
# pnpm must be on PATH; the profile's pnpm-workspace.yaml uses
# nodeLinker: hoisted so the forks land as top-level real directories
dsh plugin --profile self-checking install
Verified layout (pnpm 10, hoisted linker, real profile location): the forks
resolve from node_modules/@deepseek-ai/... first, fork-internal imports stay
on the forks, and every undeclared dependency (cordis, dsh-tools, ...)
resolves from the shared fallback through the ordinary parent walk. A second
pnpm install keeps the forks (declared dependencies). Peer-dependency and
koffi build-script warnings are expected and harmless (the native koffi
binding comes from the @koromix/koffi-<platform> optional package).
To publish the forks as registry packages instead of local directories,
replace each file: spec with an npm alias — "@deepseek-ai/dsh-sandbox": "npm:<your-scope>/dsh-sandbox-selfchecking@<version>" — the mechanism is
identical; you would need to publish the eleven fork packages first.
Verify
verify.mjs (copied into every install) checks, along the real boot path:
fork resolution from the profile directory (including the client-side
dsh-client-ui-conversation, which the web plugin table resolves through the
same profile walk), the forked SANDBOX_MODES, the extended windows-acl
denial dialect, preset config validation, and the live filesystem fence
(inside passes → outside intercepted → re-run allowed).
node ~/.dsh/profiles/self-checking/verify.mjs --profile ~/.dsh/profiles/self-checking
Development
# dev regression against the repo's own fork sources
node tests/verify-self-checking.mjs
# optional overrides: DSH_SC_FORKS=<fork dir> DSH_SC_UPSTREAM=<pristine @deepseek-ai dir>
# live ACL probe against the real windows-acl runner
node tests/verify-acl-probe.mjs
Upgrading to a new dsh baseline
The vendored snapshot pins the exact npm package bytes of the baseline; upgrading is a tracked three-way merge, not a blind re-patch:
# 1. obtain an npm-style extraction of the NEW dsh packages (e.g. the
# node_modules/@deepseek-ai of a matching new install, or unpacked
# tarballs) — keep it outside the repo
# 2. three-way merge it into the fork layer; on success the vendored
# snapshot is replaced and upstream/VERSION updated
node tools/merge-upstream.mjs 0.1.0-rc.7 <new-extraction-dir>
# merge rules: upstream-only changes are taken, fork-only changes are kept,
# both-changed files are merged with git merge-file (diff3); genuine
# conflicts are written into profile/forks with conflict markers and
# reported (exit code 1), new upstream files are adopted, deleted files are
# followed (or kept with a warning when the fork modified them)
# 3. resolve any conflict markers in profile/forks, then regenerate the patch
# set and verify the rebuild is byte-identical:
node tools/gen-patches.mjs
node tools/rebuild-fork.mjs --upstream upstream/@deepseek-ai --out <tmp> --check profile/forks
node tests/verify-self-checking.mjs
# 4. commit upstream/ + profile/forks + patches together
tools/snapshot-upstream.mjs <version> <extraction-dir> vendors a baseline
from scratch (used to (re)create upstream/, e.g. the initial 0.1.0-rc.6
snapshot); commit it before running a merge, because the merge reads its base
from git HEAD.
Rebuilding the fork layer without an upgrade (e.g. after editing
profile/forks/ by hand, or to check the baseline):
node tools/rebuild-fork.mjs --upstream upstream/@deepseek-ai --out <dir> --check profile/forks
If a rebuilt fork drifts from the builtAgainst baseline, rebuild-fork.mjs
fails loudly with the offending anchor; regenerate the patch manifests with:
node tools/gen-patches.mjs <upstream> <fork> <patches-out>
Building a release
node tools/build-release.mjs [version]
# → dsh-profile-self-checking-<version>.zip (profile/ minus node_modules,
# upstream/, patches, tools, tests, docs, install scripts)
Notes / known limitations
- The interception gate is per-session in-memory state: a server restart resets it (a fresh session simply re-intercepts).
- Reads outside the workspace are not intercepted (matching workspace-write semantics); only denied file effects are.
- Agentless (non-model) calls under self-checking probe but have no re-run escape hatch — they stay denied (fail closed).
- Persistent terminals confine as workspace-write (no re-run flow inside a terminal).
- Interception blind spot: process-level restrictions are not intercepted.
The interception fires only when the workspace-write probe fails with a
file ACL denial that matches the backend's stderr signatures. Other
restrictions of the restricted token leave no such signature, so they are
neither intercepted nor unlocked by a re-run:
- named pipes (
ssh.exe/sh.exe"couldn't create signal pipe", capturing a child process's piped stdio), - TLS / credential stores (schannel
SEC_E_NO_CREDENTIALS, Git Credential Manager prompts), - operations needing privileges or Write-DAC (e.g.
SetNamedSecurityInfo). When a command fails this way, the model should first try an alternative that runs under the probe (different flags, a different TLS backend, credentials supplied another way); if full access is genuinely required, it may request an escalation withsandbox_permissions: "danger-full-access"+justification— the Self Checking preset ships withapproval: ask, so the escalation prompt reaches the user (if the session's approval policy was switched toneverseparately, switch it back first). As a user, if you see the agent stuck re-failing on the same non-file error, prompt it to request the escalation.
- named pipes (
- Do not run
dsh plugin --profile <name> installin a profile whose forks were assembled by copy unless you keepforks/in sync (the package manager rebuilds node_modules from the declaredfile:deps).
Uninstall
Remove the profile directory (~/.dsh/profiles/self-checking). Nothing
else is touched — upstream packages stay pristine.
License
MIT. Each forked package retains its upstream LICENSE (Copyright (c) 2026
DeepSeek); the profile composition, patch set, tools, tests, and
documentation are MIT, Copyright (c) 2026 the profile author.