← All notes

Your First Afternoon with dsh web and a Bundle Plugin

Get a local Web UI running, install one bundle from a git or npm source, verify it with dump-config, and avoid the three mistakes that waste the first hour.

This is the practical companion to the “everything is a plugin” overview. Goal: in one afternoon you can start DeepSeek Harness’s Web UI, install a single bundle plugin, prove it landed in the config tree, and restart so it actually loads. Commands below follow the public CLI shape from the Harness docs; package names in examples are illustrative—always prefer a source you have read.

If you only remember four steps, remember these: isolate the home directory, start web, install against the same profile you will run, then prove the row with --dump-config before you blame the UI.

Prerequisites and an isolated home

You need a current Node.js toolchain. Before you install anything community-shaped, give Harness its own home directory. Official safety guidance pushes isolation for a reason: plugins run with the privileges of the host process, and mixing experimental agents with your daily shell profile is how accidents happen.

export DSH_HOME="$HOME/.dsh-playground"
mkdir -p "$DSH_HOME"

Keep production API keys out of that environment. If you must authenticate a model provider, use the narrowest credential you can rotate, and assume any installed plugin could eventually see process environment that the agent runtime exposes. A playground that can read your main ~/.ssh or company .env files is not a playground.

Optional but useful: open a fresh shell, export only the variables you intend, and keep a short note of what you installed. Future-you will not remember why a random github source is in the patch file.

Start the Web UI

The shortest path from npm:

npx @deepseek-ai/dsh web

By default the UI listens on http://127.0.0.1:3080 and opens a browser for a local launch. If you start Harness over SSH, the CLI tends to print the host URL and leave port forwarding to your client or editor—pass --no-open when you do not want a browser attempt on the remote side.

npx @deepseek-ai/dsh web --no-open

From a repository checkout the flow is the longer pnpm install && pnpm run build && pnpm dsh web path. Both land you in the same mental model: a profile named web composing base services plus the browser app. Confirm the page loads before you install anything. Separating “Harness boots” from “my plugin boots” saves false debugging.

Bundle install only (repository comes later)

For this afternoon, stay on bundle installs: one distribution unit that carries config rows and code. The CLI shape looks like:

dsh plugin --profile web add "github:owner/repo"
# or an npm-style source your docs support
dsh plugin --profile web add "npm:@scope/dsh-plugin-example"

Pick a small, well-documented community package whose repository you can skim in fifteen minutes. Do not treat a marketplace listing as a trust root. Read the package.json, the Cordis entry, and anything that shells out or opens network sockets. If the README cannot explain why it needs shell access, do not install it into a home directory that matters.

Always pass the profile you intend to run. Installing into a default you are not launching is a classic “it installed, nothing changed” story.

Prove it landed, then restart

Installation that only mutates disk is incomplete until you can see the row:

dsh --profile web --dump-config | less

Search for the plugin id or package name. If the insert is missing, stop—do not keep restarting hoping the UI invents it. Check the CLI exit status, the home directory you exported, and whether the source string resolved. If the row is present but the feature is absent in the browser, restart the web process. Many first-time installs look “broken” only because the running tree was composed before the patch existed.

# stop the old web process, then:
npx @deepseek-ai/dsh web

After restart, exercise one obvious behavior the plugin claims to add. If nothing is obvious, the plugin may be runtime-only; dump-config plus the author’s docs become your acceptance test.

Common pitfalls

SymptomLikely causeWhat to try
Bare name fails to resolveExpecting a magic short idUse a full github: / npm: source string
Install succeeded, UI unchangedForgot restart / wrong profileRestart dsh web; re-check dump-config for web
Remove did not clean behaviorPatch row still presentInspect home cordis.patch.yml; align manually
Works in headless, missing in webWrong profileRepeat install with --profile web
Strange path permissionsDSH_HOME unset / mixed homesEcho $DSH_HOME; keep one playground

One security sentence before you go wild

A successful install is not a security review. Before you add a second and third plugin, skim for filesystem reads, shell execution, and remote code loading. The longer security note on this site covers what recent public audits imply for everyday users; the short version is: Harness is closer to “load native extensions into your agent host” than to “install a phone app from a curated store.”

Checklist to close the afternoon

  1. DSH_HOME points at a playground directory.
  2. dsh web serves on 3080 (or your chosen port).
  3. One bundle source is installed against the web profile.
  4. --dump-config shows the insert.
  5. Web was restarted after the install.
  6. You can name one behavior you verified.

Next up: when to prefer repository plugins over bundles, and why plugin remove is not the same thing as “the patch forgot this ever happened.”