Preface

DeepSeek Harness (dsh) is an open-source agent runtime developed by DeepSeek, which is officially positioned as a developer preview version, with the slogan “Everything is a plugin”: model adaptation, tool registration, session logging, and Agent loops can all be replaced with plugins without modifying the runtime source code. The official entry point for launching the Web UI is:

npx @deepseek-ai/dsh web

When actually getting started, another gap quickly emerged: many mainstream models do not have native internet access themselves, or their official search only covers web pages, not specified pages or X (Twitter). Asking “What is the current Node.js LTS version”, pasting a blog post for it to summarize, or following a tweet discussion, the model can only guess based on training data. Although dsh comes with a web_search seam, it is pinned to DeepSeek’s search API with a key by default; the built-in web_fetch is disabled by default.

The community directory deepseek-harness-plugin.com is an independent site and has no official affiliation with DeepSeek / HyperGAN. It categorizes and collects extensions, and there is a plugin under “Interface Enhancements”: modsearch. The name sounds like a skin, but it actually connects search to dsh’s existing Web seams while retaining the Web UI’s citation cards.

This article is organized after cross-checking the directory details page, GitHub repository README / INSTALL.md / host access documentation / CLI manual / output contract / security instructions, and the official DeepSeek Harness repository: what it is, what it can do after installation, how to write commands, and what the results look like.

What is it

modsearch is an internet search plugin maintained by liustack (the author of package.json is listed as Leon Liu), with the npm package name @liustack/modsearch and the MIT license, primarily written in TypeScript. At the time of writing, the version in the repository’s package.json is 5.4.2 (2026-08-17), requiring Node.js >= 22.13. The community directory categorized it under “Interface Enhancements” and included it on 2026-08-15; the GitHub repository showed 113 stars on 2026-08-17 (the directory page snapshot had 100 stars, please refer to the repository page for the actual star count).

The one-sentence description on the directory page is: An internet search bridge for DeepSeek Harness, enabling models without native internet access to query web pages or X and get structured answers. The repository README, in both Chinese and English, states the same thing: search, crawl, cite, and output machine-readable JSON evidence.

In dsh, it is not a Skill triggered by prompts. The host access documentation clearly states: this package itself is a dsh bundle, accessed as a native plugin. The bundle does three things: register the modsearch engine chain as a provider for web_search and point the seam to it (searchProvider: modsearch); additionally register two tools that dsh does not have seams for — x_search for searching X, and read_page for focused reading of a single page. The model continues to use the original web_search schema, and the Web UI’s citation cards are also retained.

The same engine also appears as an Agent Skill on Claude Code, Codex, Pi, and OpenCode, with all configurations written in ~/.modsearch/config.json. This article focuses on dsh.

Core Features

1. Connect the built-in web_search to the engine chain

dsh already has a Web capability seam: search and crawling on ctx.web, which are exposed as model-callable web_search / web_fetch by dsh-tool-web. Modsearch does not create a competing tool, but instead registers a search provider with the id modsearch. cordis.patch.yml changes the searchProvider for the web layer from the default deepseek-official to modsearch.

The effect is: as long as you configure any of the following search engines locally, web_search can run without a DeepSeek search key; the citation cards still use the host’s original display. To switch back, pin the searchProvider back to another provider in a later profile patch.

When the plugin starts the CLI subprocess, it uses dist/main.js inside the package, does not check the PATH, and does not use npx, so the plugin and engine versions are locked together. When dsh runs in the Electron desktop host, it will explicitly set ELECTRON_RUN_AS_NODE=1 to avoid handing the CLI path back to the desktop application.

2. x_search and read_page

For the two areas not covered by the web seam, the plugin creates independent tools, and the schema is sent to the model with each request, without relying on keyword heuristics.

  • x_search: Query posts, threads, accounts, or discussions on X (Twitter). If Grok Build is installed and logged in, it routes traffic to it; otherwise, it uses the web engine as a fallback and marks it as degraded in the output, without silently pretending to have searched X.
  • read_page: Read an http(s) URL, return a summary, extract the main text, external links, and uncertainties, and you can specify a reading focus with query. The host access documentation notes that dsh’s built-in web_fetch is disabled by default because it offloads SSRF protection to others; modsearch’s crawler blocks private network targets by default, and this tool does not expose an override switch.

3. Multi-engine, automatic failover

The repository README lists six channels, and you only need to configure one of them to use it. Keys are stored in ~/.modsearch/config.json (permission 0600, masked when displayed), or you can use environment variables TAVILY_API_KEY, EXA_API_KEY, FIRECRAWL_API_KEY.

Engine What it can do Free conditions stated in the repository How to enable
Antigravity CLI (agy) Web search + single-page crawl Free, log in via browser Install agy and log in
Tavily Web search 1,000 credits per month, registration does not require a credit card per documentation modsearch config set tavily.apiKey <key>
Exa Web search ~1,400 requests per month ($10 recurring credit), registration does not require a credit card per documentation modsearch config set exa.apiKey <key>
Firecrawl Web search + single-page crawl 1,000 credits per month; documentation states that search can even be used without a key modsearch config set firecrawl.apiKey <key>
Grok Build X (Twitter) search Included with SuperGrok or X Premium Install grok and log in
local Single-page crawl Built-in No configuration required

If multiple engines are configured, it automatically switches by priority: if one channel fails or runs out of credits, the next one takes over. Credit cooling failover is enabled by default, and can be turned off with modsearch config set cooldown off. For third-party or self-hosted endpoints compatible with Tavily / Exa / Firecrawl, you can change the address with commands like modsearch config set tavily.baseURL <url>.

The local crawler rejects private network and cloud metadata addresses by default, and pins the IP address after each DNS resolution to avoid rebinding. When a VPN maps a public host into a reserved address range, you can enable it with --allow-private-network or modsearch config set allowPrivateNetwork true. The documentation explicitly states that this is for allowing local crawlers, not for exposing internal hostnames to cloud services.

4. Structured JSON, not unvetted prose

The CLI prints one envelope to stdout each time. The shape of the search mode comes from the official output contract (examples in the documentation):

{
  "mode": "search",
  "query": "current Node.js LTS",
  "url": null,
  "results": [
    {
      "source": "web",
      "requestedSource": "web",
      "engine": "antigravity-cli",
      "status": "ok",
      "summary": "The current Node.js LTS is v24.19.0 (Krypton), released 2026-08-03.",
      "items": [
        {
          "title": "Node.js v24.19.0 release",
          "url": "https://nodejs.org/en/blog/release/v24.19.0",
          "snippet": "Krypton is the active LTS line.",
          "published_at": "2026-08-03"
        }
      ],
      "uncertainty": [],
      "warnings": [],
      "attempts": []
    }
  ]
}

Several fields need to be read separately:
- summary + items: Summary and entries with source URLs, the order of items indicates relevance, and there is no numerical score (the documentation states that models easily round scores, so it was removed in v2)
- uncertainty: Areas where the engine is unsure about facts (conflicting sources, potentially outdated numbers, too thin pages)
- warnings: How the answer was obtained (fallbacks, X replaced by web, redirects)
- status: ok / degraded / unavailable. When X is unreachable, the web fallback must be marked degraded and not treated as X coverage

The crawl mode (-u) replaces items with content (main text) and up to 20 links. The output from agy is markdown-formatted main text; the local engine does not run JavaScript or generate summaries.

Installation and Enablement

Commands given by the community directory

The installation command on the plugin details page is:

dsh plugin add github:liustack/modsearch

For reproducible installations, the directory page requires fixing the commit hash:

dsh plugin add github:liustack/modsearch#<commit>

The directory page also reminds users: the plugin runs with the permissions of the current dsh process, and may execute code during installation; you should check the source code repository and license before installing.

Version-locked writing for dsh from the repository

The command given to dsh users in docs/harness-setup.md is a different one. At the time of writing, it is pinned to 5.4.2:

npx -y @deepseek-ai/dsh plugin --profile web add @liustack/modsearch@5.4.2

The repository deliberately avoids @latest: pnpm 11 enables minimumReleaseAge (24 hours) by default, and dist-tags are only resolved in versions that have passed the cooling-off period, so @latest may silently install an older version from a day ago. Specifying the version number explicitly is clear. Updates also use add instead of update: update only moves within recorded semver requests, and will also go through the release duration filter again.

You can query the current version with the following command, then replace the version number in the command with the output:

npm view @liustack/modsearch version

After installation, restart dsh and confirm what was actually installed:

npx -y @deepseek-ai/dsh plugin --profile web list

If declares no dsh.bundle appears, the repository’s judgment is that an old package was installed during the release cooling-off period. Follow the “Stay Updated” section in the host access documentation, do not try to copy the Skill directory.

web is just an example profile in the documentation. The actual profile name is subject to your local machine, just replace --profile with your own.

Prepare a search engine first

The plugin can hook up the tools, but the actual web search is done by the engine. The default channel Antigravity CLI requires you to complete the login in your browser, which is the “only step you need to do manually” stated in the repository:

curl -fsSL https://antigravity.google/cli/install.sh | bash
agy

Complete the login in your browser and then exit. If you do not want to install agy, register for free keys from Tavily, Exa, or Firecrawl according to the table in the previous section, then run modsearch config set .... If you only need to read pages, the built-in local crawler is already available, and no search engine configuration is needed. To search X, you also need to install and log in to Grok Build separately.

For headless environments or SSH without a desktop, the documentation recommends not using the browser login for agy, and instead using an API key.

Health Check

npx @liustack/modsearch doctor

It does not consume credits or send network requests. On a healthy machine (with agy logged in), the report looks roughly like this (extracted from INSTALL.md, simplified):

Node
  version: 22.13.0
  status:  OK

search (search the web)
  resolved: antigravity-cli
  - antigravity-cli   READY    binary "agy" found and runnable

fetch (fetch a page)
  resolved: local
  - local             READY    built in, needs nothing installed

social (search X)
  resolved: (none available)

If Node status: TOO OLD appears, stop and upgrade Node.js. If search resolved: (none available), you have not configured a search engine yet. A (none available) status for social only means Grok Build is not installed, and does not affect web search. Add --json to get a machine-readable report.

Run an end-to-end test (will consume one search credit):

modsearch -q "current Node.js LTS version"

The expected stdout is JSON: the first entry in the results array has an engine and items with urls. If it times out, increase --timeout to 300000; the documentation states that agy usually takes 10–30 seconds per run.

Typical Usage

After installing into dsh, you can have a normal conversation: ask questions that need verification, or paste a URL. The following examples are all from the repository documentation and the directory page, not made-up cases.

1. Drive the CLI directly

If you already have Node.js on your local machine, you can run it directly without going through a conversation:

modsearch -q "current Node.js LTS version"
modsearch -u "https://nodejs.org/en/about"
modsearch -q "reactions on X" --source x
modsearch -q "TypeScript 5.9 release notes" -o search.json --max-results 6

You can add -q along with -u to pass extraction focus to the engine. --source can be web, x, or web,x. When you use -e to pin to a specific engine, it will throw an error on failure and not switch channels.

2. Ask internet-connected questions in dsh

Pick models like DeepSeek-V4-Flash that cannot natively connect to the internet, or have weak internet capabilities, and directly ask about current events or version numbers. The model calls the original web_search of the host, and the backend is already the modsearch engine chain. The directory page summarizes this change as: models without native internet access can also query web pages and get structured answers.

Paste the URL of a document, changelog, or blog post into the conversation, and add a focus point if needed (for example, “What is the rate limit”). The model uses read_page, which returns a summary, extracted main text, and external links, instead of stuffing the entire page into the context.

The host access documentation mentions a comparison when talking about Codex (this is the repository’s own实测, not a third-party review): the built-in search pushes the entire page into the context, and a dense search answer uses about 30,000 tokens; structured evidence uses only hundreds of tokens. The read_page on dsh follows the same output contract.

4. Actual test records from the repository README

These are the original records marked in the README, tested in the Codex desktop app with DeepSeek-V4-Flash that cannot natively connect to the internet, to illustrate the granularity, not for benchmarking:
- Given a blog link and asked what the article is about: returned a full structured summary after about 25 seconds, no browser opened during the process
- Did not specify a target, just asked “What interesting AI news is there today”: returned six results with sources after about 36 seconds, and explained at the end which details came from retrieval aggregation and are worth rechecking — this reminder comes from the uncertainty field

5. The same engine used on other hosts

The Skill installation process (copy skills/modsearch, or npx -y skills add liustack/modsearch) only applies to Claude Code / Codex / Pi / OpenCode, do not use that path on dsh. If you have already turned on the official web_search = "live" in Codex, the documentation requires you to turn it off first in ~/.codex/config.toml, otherwise the model will first use the built-in search and the Skill will not be triggered.

Applicable Scenarios and Notes

It is suitable for:
- Using models without native internet access, or whose official search cannot cover specified pages / X, for coding and research in dsh
- Wanting answers with source URLs and uncertainties, instead of unvetted prose summaries
- Already being able to log in to agy, or having free credits from Tavily /