dsh plugins: wetin dem fit do before you install
dsh plugins dey run another person code with your agent permissions. See wetin dem fit reach and the checks to do before you install any one.
Wetin be dsh plugin, and wetin e fit do?
dsh plugins na Node packages wey DeepSeek Harness dey load inside im own process. When you install one, e go run another person code with your agent permissions, for the machine wey your agent fit already reach. Nothing dey between loaded plugin and the rest of the harness. So before you install one, ask wetin that code fit touch, and how you fit keep the access small.
dsh (DeepSeek Harness) na DeepSeek AI open-source agent harness, wey dem build with plugin framework wey dem call Cordis. Na that middle word carry the main matter, because agent harness na the program wey surround the model and control the loop, tools, and permissions. Plugin join am for exactly that level. The project own README talk say everything na plugin. The model adapter na plugin. The web interface wey you dey type into na plugin. Anything wey you install from outside the project go enter the same tree, with the same trust level as the parts wey come with am. If you never set one up yet, start with DeepSeek Harness for VPS and come back before you add anything to am.
The extension points wey plugin fit reach dey listed for repository AGENTS.md. As of August 2026, dem cover:
- LLM (large language model): provider wey your API key dey pay for
- Shell: bash capability, with local and pwsh providers
- Filesystem: file access wey policy dey control
- Web: search and fetch providers
- Subprocess: process-tree provider
- Workflow: worker threads
- Subagent: delegation go further agents
- Settings and credentials: your saved configuration and environment variables
Plugin still registers tools for ctx.tools, and the docs clear say registered tool schema join prompt assembly. Na this second part many people dey miss. Plugin fit change wetin your agent decide to do even when im own code no do anything unusual, because the description wey e contribute become text wey model dey read. Na the same kind problem as prompt injection against coding agents, but one difference dey: this text enter when you install am, and e go remain until you remove the plugin.
How dsh dey find and load plugins?
No global plugin directory dey. A running dsh na plugin tree wey e compose during boot from ordered layers, and the unit wey hold your choices na profile. $DSH_HOME default na ~/.dsh, and every profile dey inside $DSH_HOME/profiles/<name>. The web and headless profiles dey create themselves the first time you use dem from shipped templates.
A profile directory get two files wey decide everything:
package.json, wey get the out-of-tree plugin dependencies plus onedsh.profilemanifest wey carry the orderedbundleslistcordis.patch.yml, your own patch layer on top of those bundles
ls ~/.dsh
ls ~/.dsh/profiles/webDuring boot, e apply the layers for this order, and later layers dey override earlier ones:
- one empty root
- the profile bundles, for the order wey the manifest list dem
- the profile's
cordis.patch.yml $DSH_HOME/cordis.patch.yml- any
--patch <path>overlays wey you pass for the command line
Two flags fit print the composition result without starting anything:
dsh --profile web --dump-default-config
dsh --profile web --dump-config--dump-default-config print the composed tree by itself. --dump-config add the profile and home patch layers, so na the closest way to get a correct inventory of wetin your next boot go load. Read am before you trust machine wey you inherit.
One warning about those patch files. Config no be inactive data here, because the format allow !!js tagged values under a plugin's config block. One cordis.patch.yml snippet wey you copy from forum post na code, so treat am the same way you go treat shell script from that source.
Wetin dsh plugin add actually dey run?
dsh plugin --profile <name> <args> dey forward its arguments go pnpm inside that profile directory, so pnpm must dey for PATH. The verbs na pnpm verbs:
dsh plugin --profile web add '<package-or-git-spec>'
dsh plugin --profile web remove '<package-name>'
dsh plugin --profile web why '<package-name>'
dsh plugin --profile web updateThe security model for installing a dsh plugin na the same security model for installing any npm-style dependency, plus one extra step where the result gets loaded into your agent. The package bring its own dependency tree, and every package for that tree end up for the same process. Everything for how npm supply chain attacks reach server applies here without change.
pnpm 10 and later no dey run dependency build scripts by default, and approval dey per package through onlyBuiltDependencies or pnpm approve-builds. Check which pnpm you get:
pnpm --versionThat default good to keep, but na also the safety feature wey people dey misunderstand pass for the ecosystem. Blocked build scripts stop code from running during installation. Dem no do anything about the plugin itself, because the whole point of plugin na say the harness go import am and call am for the next boot. Plugin no need postinstall hook. You invite am enter.
Wetín to read before you install dsh plugin
Download the published tarball and read am. Nothing go execute when you unpack archive.
npm pack '<package-name>@<version>'
tar -tzf '<package-name>-<version>.tgz'
tar -xzf '<package-name>-<version>.tgz'
less package/package.jsonFour fields for that package.json go tell you most of wetin you need. Read scripts for preinstall, install and postinstall entries. Read dependencies for names wey you no recognise, or names wey dey just one character different from ones wey you recognise. Read bin for anything wey the package want for your PATH. Read main or exports for the entry file, then open that file and follow am.
Then read the code wey go actually load. Plugin wey advertise notification tool no get reason to read ~/.ssh, call host wey you never hear about, or spawn shell. If the package ships only bundled or minified JavaScript and no matching source dey for public repository, na your answer be that. Prefer plugins wey you fit read their source, and prefer small ones.
You fit also question the registry without installing anything:
pnpm view '<package-name>' dependencies
pnpm view '<package-name>' versionsPackage wey publish last week, get one version, no repository field and get name wey dey shadow popular thing, na the oldest trick for any registry. Verify downloads with checksums na the habit wey dey next door: know exactly wetin you fetch before you allow am run.
Pin the version, and keep the lockfile
Floating version range mean say code inside your agent process fit change for any install or update without you deciding am. Pin am.
dsh plugin --profile web add --save-exact '<package-name>@<version>'Where pnpm versions dey put flags fit differ, so check the result instead make you trust the command. Open the profile's package.json afterwards, then confirm say the dependency show as bare version with no ^ or ~ before am. Na that file dey decide wetin go install.
Then keep the lockfile, wey dey pin the complete transitive tree instead of only the top-level name:
find ~/.dsh -maxdepth 3 -name 'pnpm-lock.yaml'Copy am go somewhere wey you dey back up, together with the profile's package.json. Those two files fit rebuild the same tree for new box. Run dsh plugin --profile web update only when you don decide to change versions, never as routine cleanup, and read the lockfile diff afterwards.
For plugin wey you install from git instead of registry, pin the commit instead of the branch. Spec wey get form github:owner/repo#<full commit sha> go give you fixed tree. Branch name go give you anything wey that branch hold the next time pnpm resolve am, and na decision you don hand over to another person. The harness itself need the same discipline, because every published dsh build na release candidate, and unpinned install fit resolve to different one any day. Na from there most dsh install and version errors dey come.
Plugin market, and wetin “curated” mean
dsh get marketplace, and e dey install as plugin. This one show you something about how the architecture work:
dsh plugin --profile web add dshmarketAfter restart, e go show under Settings, then Plugin Market. The README talk clearly about the limits. Install dey restricted to sources wey dey listed for a curated registry, and e go reject anything else. Build scripts dey blocked by default. To enable one, you need approve each package. E go flag terminal plugins before dem enter web profile. The sentence wey matter pass be say listing no mean endorsement, because third-party code dey inside the plugins.
Curated list dey set a minimum standard. E no read the code for you, and e no fit tell you wetin the next plugin version go do after maintainer account change owner. Treat one-click install the same way you go treat curl | bash from the same author. Another line from that README worth repeating be this: exported backup fit contain credentials from your profile config, so never attach one to public issue or paste site. If you want starting list instead of method, dsh plugins wey worth installing na companion post for this one.
Run dsh as im own user, no be root
Vetting dey reduce how often bad thing fit enter. Least privilege dey decide wetin e fit reach when e enter. For VPS, to set up that second part cheap.
Give the harness im own unix account with im own home, and never run am as root:
sudo adduser --disabled-password --gecos "" dshrun
sudo -iu dshrunInside that session, start the harness so e go write im home under that account:
npx @deepseek-ai/dsh webThe web UI dey serve for http://127.0.0.1:3080 by default. Leave am there. If you don ever click that printed link from another machine and nothing come back, wetin dsh mean when e print that address explain why. Anything wey reach that port fit control an agent wey get shell, so publishing 3080 na the same as publishing root-less remote shell with friendly interface. Reach am from your laptop through SSH tunnel instead:
ssh -L 3080:127.0.0.1:3080 you@your-vpsThen confirm say nothing dey listen on public address:
ss -lnt | grep 3080The local address suppose read 127.0.0.1:3080. If e read 0.0.0.0:3080, na your firewall remain as the only thing between stranger and your agent. The reasoning behind how to run Claude Code safely for VPS apply to dsh the same way. Give the agent one workspace directory wey e allowed to spoil, and keep anything wey you no fit rebuild away from that machine. Better still, treat the box as disposable VM for coding agents, because rebuilding VPS fit cost one hour, while auditing one fit cost one week.
Keys go live for where, and why file permissions no reach everywhere
dsh dey keep API keys for $DSH_HOME/.credentials.yaml and environment values for $DSH_HOME/.env, while model settings dey for $DSH_HOME/settings.yaml and session history dey under $DSH_HOME/storages. Which key suppose dey for which file, and wetin actually comot from the machine for each mode, na the topic of configuring dsh API keys, models and endpoints. E good make you settle this before you add plugin, because every key wey you connect na another thing plugin fit read. Lock down the two sensitive files:
chmod 600 ~/.dsh/.credentials.yaml ~/.dsh/.env
ls -l ~/.dshMode 600 give owner permission to read and write, but e give everybody else nothing. This matter for both notations (numeric versus symbolic chmod modes). Make we clear about wetin this protection fit do. File modes protect those files from other accounts for the machine. Dem no protect against plugin, because plugin dey run as the user wey own the files, inside the process wey dey read dem. Na why keeping secrets away from AI agent mean say you no suppose put dem for the machine at all. dsh machine suppose hold only the one model key wey e need. Your cloud credentials and signing keys suppose dey somewhere else.
Wetin make plugin wey dey read web change threat model
Web seam dey give plugins search and fetch providers. Plugin wey pull page enter your session dey pull text wey attacker fit write. Model prompt no separate instructions from data, so fetched page fit carry line wey address your agent, and harness wey hold shell capability dey just one obedient step away from running am.
The control don already dey inside harness. dsh-base, na the first bundle for every profile, and e ship with sandbox and approval policy. Use am. Session wey fit fetch untrusted pages suppose require approval for anything wey go write or execute, so fetched instruction no fit become action by itself. How to put agent actions behind approval explain how to decide where that line go dey. The relationship dey work for both directions too, because your own server na page wey another person's agent fit fetch. Na this be the case for blocking AI crawlers for your server.
How I fit check wetin plugin change?
Take snapshot before, install am, take another snapshot after, then read the difference.
dsh --profile web --dump-config > /tmp/dsh-before.txt
dsh plugin --profile web add '<package-name>@<version>'
dsh --profile web --dump-config > /tmp/dsh-after.txt
diff -u /tmp/dsh-before.txt /tmp/dsh-after.txtThe diff go show which plugin entries the install add to the composed tree. If you install plugin for one small feature and e add several entries wey you no fit explain, stop and read the source before you boot am. dsh plugin --profile web why <package-name> answers the other question: which of your direct dependencies bring a particular package enter.
Installed packages dey under $DSH_HOME/profiles/node_modules, so you fit also check the tree for disk:
ls ~/.dsh/profiles/node_modulesKeep second profile wey you never use for experiments. If install spoil the harness, booting dsh --profile <clean-name> go tell you within seconds whether na the plugin cause am.
How I fit remove a dsh plugin?
dsh plugin --profile web remove '<package-name>'
dsh --profile web --dump-config > /tmp/dsh-after-removal.txt
diff -u /tmp/dsh-before.txt /tmp/dsh-after-removal.txtIf you remove dependency, e no always remove configuration. Entries wey dem write inside the profile cordis.patch.yml go still remain, because na your file and the harness no go rewrite am for you. Open the file and delete any block wey name the package wey you remove.
less ~/.dsh/profiles/web/cordis.patch.ymlThen face the part wey no uninstall command fit fix. If you remove plugin because you no trust am again, anything wey e fit read, e don already read am. Rotate the DeepSeek API key for the provider console, and rotate anything else wey dey inside $DSH_HOME. Then find out wetin the unix account wey run am fit reach for the rest of your network.
De short version
- Read the tarball wey dem publish before installation, start from
scriptsand the entry file - Pin the exact version, or the exact commit for a git spec, and keep the lockfile
- Install am inside one profile, and keep one clean profile wey you fit boot when something spoil
- Diff
--dump-configbefore and after every installation - Run the harness with its own unix user, for loopback, and reach am through SSH
- Keep one API key for the box, and rotate am the same day wey you remove plugin wey you no trust again
None of dis mean say you suppose avoid plugins. Na the plugin model make dsh useful, and harness wey you no fit extend na harness wey you go replace. E mean say you suppose know wetin you install, who provide am, the version wey you use, and run everything for place wey you fit rebuild.
FAQ
dsh dey sandbox plugins from each other?
No. Cordis dey load plugin inside the harness process, and plugin fit reach the capability seams wey documentation list, including shell, filesystem, web, subprocess, subagent and credentials. dsh-base, wey be the first bundle for every profile, dey ship the sandbox and approval policy wey control wetin agent tools fit do, and na that policy dey provide your protection. No permission boundary dey for each plugin, so the honest model be say installing plugin extend the trust you give the author and every package for the plugin dependency tree.
I fit install dsh plugin without running the install scripts?
pnpm 10 and later dey block dependency build scripts by default, and dsh plugin ... add dey forward go pnpm, so for current pnpm, install no dey run package scripts unless you approve that package. Confirm your version with pnpm --version. This no mean unread plugin safe. The plugin own code go run for the next boot because harness load am deliberately, and no install-time restriction fit stop that.
Where dsh plugins and their config dey actually stay?
$DSH_HOME default to ~/.dsh. Profiles dey inside $DSH_HOME/profiles/<name>. Each one get package.json with its plugin dependencies, plus dsh.profile manifest of ordered bundles, and cordis.patch.yml patch layer. Installed packages dey land under $DSH_HOME/profiles/node_modules. Keys dey inside $DSH_HOME/.credentials.yaml, environment values dey inside $DSH_HOME/.env, and home-level $DSH_HOME/cordis.patch.yml dey apply over every profile. Run dsh --profile web --dump-config to see the composed result without booting.
E safe to install from dsh plugin market?
The market restrict installs to sources wey dey for curated registry and block build scripts unless you approve dem per package. This na real improvement over pasting package name from chat window. But the market own README still talk say listing no be endorsement, because plugins na third-party code from other people. Read the source and pin the version. Keep the harness for user account, and ideally for machine, wey you fit afford to lose.