Harness setup
August 22, 2026 · View on GitHub
English | 简体中文
DeepSeek Harness (dsh)
dsh is different from the other harnesses: modsearch plugs in natively, not as a prompt-triggered skill. The package itself is a dsh bundle, so one command installs it into a profile:
For plugin switches, profile patches, runtime verification, updating, and compatibility checks, use the dedicated dsh plugin guide.
npx -y @deepseek-ai/dsh plugin --profile web add @liustack/modsearch@5.9.0
Three things land at once:
web_searchstarts running on modsearch. dsh already ships a nativeweb_searchtool over a provider seam, pinned to DeepSeek's keyed search API. The bundle registers the modsearch engine chain as a provider and repoints the seam at it (searchProvider: modsearch), so search works with no API key at all: Firecrawl's keyless free quota answers out of the box, signed-in agy and configured keys take over when present, and the Web UI keeps its native citation cards. To switch back, pinsearchProviderto another provider in a later profile patch.x_searchcovers the corpus dsh has no seam for. Routed to Grok Build when it is installed and signed in; a web stand-in answer is marked degraded in the tool output, never silent.read_pagereads one URL into structured evidence (summary, extracted content, links, uncertainty), with an optional answer focus. dsh ships its ownweb_fetchdisabled because that provider defers SSRF protection. ModSearch blocks private-network targets by default, and the tool exposes no override. Public URLs go through Firecrawl's keyless cloud browser by default, which reads JavaScript-rendered pages; the result carries a warning naming the cloud route, andmodsearch config set firecrawl.keylessFetch falsekeeps automatic fetch local instead.
Engines, keys, and routing keep living in ~/.modsearch/config.json, shared with every other harness. dsh is in developer preview and its plugin surface may change. The plugin keeps its touch small (one provider registration and two raw tool registrations) and degrades loudly in the harness log if any of it moves. If dsh warns declares no dsh.bundle, pnpm's release-age gate installed an old version. Reinstall with the named version below.
The plugin also works when dsh runs inside an Electron desktop host. Electron exposes the desktop application as process.execPath, so the plugin explicitly starts its CLI child with ELECTRON_RUN_AS_NODE=1. The bundled dist/main.js then runs under Node instead of being passed back to the desktop application as arguments.
Keeping it up to date
To install the current release or refresh an existing profile, rerun add with the version named:
npx -y @deepseek-ai/dsh plugin --profile <name> add @liustack/modsearch@5.9.0
npm view @liustack/modsearch version prints the current version. This page is stamped with the package version by the release process. Reusing add is deliberate because it replaces the profile's recorded request with the exact version named above. Do not substitute update, which stays inside the recorded semver request and lets pnpm select through its release-age filter again.
The named version rather than @latest is deliberate. pnpm 11 holds back releases published in the last 24 hours through minimumReleaseAge, which is enabled by default, then resolves the dist-tag against the versions that survive the filter. As a result, @latest silently installs an older release instead of skipping the gate. An exact version avoids that dist-tag resolution. Since pnpm 11.1.3, the default loose mode records an immature exact pick under minimumReleaseAgeExclude in the profile's pnpm-workspace.yaml and continues, while leaving the release-age window in place for everything else.
Restart dsh, then confirm what actually landed:
npx -y @deepseek-ai/dsh plugin --profile <name> list
Codex (and other DeepSeek setups)
DeepSeek's official endpoints ship a server-side web_search tool, carried by the Responses API that Codex speaks and the Anthropic-compatible endpoint that Claude Code speaks. Point either at api.deepseek.com with web_search = "live" and you already have search (see the official integration guide).
So inside Codex, ModSearch is not about going from nothing to something. It is about the context bill: built-in search pushes whole pages into your model's context, measured at about 30,000 tokens for one search-heavy answer, against a few hundred for structured evidence.
To hand it the job, turn the built-in one off in ~/.codex/config.toml, or the model reaches for that one first and the skill never gets a word in:
web_search = "disabled"
Where built-in search does not exist at all
- The official
/chat/completionsendpoint does not offer the tool, which is what shuts OpenCode and Pi out. - DashScope and most third-party gateways expose the model's reasoning and nothing else.
- Reading one specific page, and reaching X, are outside built-in search's scope everywhere.
Skill locations per harness
| Harness | Reads skills from |
|---|---|
| Claude Code | ~/.claude/skills/ |
| Codex | ~/.codex/skills/ |
| Pi, OpenCode | ~/.agents/skills/ |
On Windows, ~ is the user profile, so these are %USERPROFILE%\.claude\skills\ and the like.
Symlinks work in all of them, so linking the skill folder once keeps every agent on the latest version.