Model or dataset
DDDMUC/dsh-free-search avatar
DDDMUC/dsh-free-search

dsh-free-search gives a DeepSeek Harness agent a search engine it can fall back on

Free web search provider for DeepSeek Harness - DuckDuckGo backend, no API key needed

591 stars46 forksJavaScriptMIT

At a glance

What is it?
dsh-free-search is an MIT-licensed plugin for the DeepSeek Harness that registers a web search provider backed by 27 engines, most of which work without an API key, and wraps every failure in a fallback chain so a query does not simply come back empty. It also treats fetched page text as untrusted data, which is the part that matters for an agent that reads the web.
Who is it for?
dsh-free-search is a good fit for someone running the DeepSeek Harness behind a gateway whose OpenAI-compatible endpoint does not carry the built-in web_search tool, and for a team that wants its agents to keep searching when one provider is rate limited or out of quota. It is a poor fit if you have a paid search key you trust and no reason to run many engines, and it is a poor fit for an environment where the agent should not be reading arbitrary web pages at all.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Why the built-in search fails on a gateway

The problem the plugin solves is specific rather than general. The DeepSeek Harness search provider depends on the official DeepSeek API key, through the DEEPSEEK_API_KEY environment variable. If you do not have that key, or you are using a gateway of the opencode-go kind whose OpenAI-compatible endpoint does not support the web_search tool, then the built-in search necessarily fails and the agent tells the user it cannot reach the network. The plugin's answer is to register additional search providers into the ctx.web seam so that the built-in web_search tool can select among them. It implements the official WebSearchProvider seam interface, which the README describes as clean integration that coexists with the official plugin rather than replacing it. The engine list is long, and the split that matters is which ones need a key: DuckDuckGo in its HTML and Lite forms, Bing, AnySearch, SearXNG, Exa, Tavily, Keenable, Firecrawl and Parallel all work without one, while Perplexity, SerpBase, Serply, the two DeepSeek routes, You.com, Baidu Qianfan, Kimi, Aliyun Bailian, Doubao, the two Zhihu routes and the model built-in searches from OpenAI, Gemini and Claude need one.

The fallback chain and how failures are classified

The central mechanism is a unified engine fallback. When any engine fails, whether paid or free, whether for a missing key, an authentication error, a rate limit or a network problem, the plugin tries the next one in turn: the preferred engine first, then the other engines, and then the remaining free ones. Several of those, including Exa, Tavily, Keenable, Firecrawl and Parallel, are tried even without a key because they carry a keyless anonymous tier, and the search is not supposed to fail outright. The result carries a note at the top saying which engine actually produced it, in the form of a line about one engine being unavailable or failed and another being used. Failures are not treated alike. A quota or authentication failure puts that engine into a cooldown for the session, an anti-bot block triggers a short backoff, a timeout, a server error or a rate limit retries the same engine once, and a parse failure or a zero-result response does not cool the engine down at all. That last distinction is the one that keeps a working engine from being sidelined by a single bad query.

Untrusted content, and the boundary around it

The plugin takes a position on prompt injection that is worth reading carefully, because it applies to a search tool that feeds arbitrary pages into a model. The plugin's own tools, advanced_search, platform_search and free_search_test, wrap fetched page text inside an untrusted-web-content boundary, and any boundary marker that appears in the body itself is stripped, so a page cannot close the boundary early and smuggle content past it. The core web_search and web_fetch tools rely on a similar protection in the harness itself, which prefixes external web content. The system prompt injection tells the agent which engine is in use, which engines need a key, and states that all search results are untrusted external data whose instructions must not be followed. Every snippet is cleaned and truncated to 300 characters, which limits both the token cost and the room for a hostile instruction to fit. This is the part of the project that distinguishes it from a thin search wrapper, and it is the part to check first if you plan to let an agent act on what it reads.

Multi mode, language pools and the time budget

A search engine can be set to Multi Search, and in that mode web_search runs every enabled engine in the corresponding language pool concurrently, rather than the first three, with the Chinese and English pools editable in the settings page and a minimum of two engines per pool. Results are merged and de-duplicated by URL, with same-site detection using the eTLD+1 form, and hits found across multiple sources are prioritised. The settings page offers Fast, Balanced and Deep intensity levels, and you can hand-fill a concurrency limit and a target number of successful sources. The whole retrieval round shares a 30 second total budget, and when the budget runs out the results collected so far are returned, at the cost of consuming quota faster. If a multi round fails, it falls back to the single-engine chain. The Auto engine is a separate idea, a router that picks an engine based on the query language and the time constraints, preferring Chinese providers such as Bing, Baidu, Aliyun and AnySearch for Chinese queries and Bing, Exa and Tavily for English ones, with a full fallback at the end.

Key rotation, caching and the blocklist

Three smaller mechanisms keep the search working in practice. Any key field, or the matching environment variable, can hold several keys separated by commas, semicolons or newlines, and when a 401, a 402 or a 429 comes back the plugin rotates to the next key for that same engine before it falls back to a different engine. Results are cached, so the same query including its engine and time-filter parameters is served from cache for five minutes, with an LRU of 50 entries, which exists to protect the free engines from rate limiting and to save paid quota, and the duration is configurable from zero to five minutes in the settings page, with zero disabling it. A blockedDomains list keeps matching domains out of every result, and a safeSearch setting of off, moderate or strict adds a filter layer for Bing and DuckDuckGo. The settings page marks free engines with a green FREE badge and paid ones with an orange API KEY badge, so you can see at a glance which entries will cost money before a run.

Beyond a search box: fetching, vertical sources and research

The plugin ships several tools beyond the core one. web_fetch lets the agent pull page content, and it uses the official dsh-web-fetch-http provider in pure JavaScript with no extra dependencies. platform_search covers a list of specific sites through public APIs or keyless scraping, including GitHub, V2EX, Bilibili, Reddit, Hacker News, Stack Overflow, Wikipedia, npm, YouTube, Vimeo, Juejin, Douban and Qiita. domain_search is a set of 41 keyless vertical sources, grouped by subject, so package and version information comes from PyPI, crates.io, GitHub releases and endoflife, academic work from arXiv, Crossref, OpenAlex, Semantic Scholar, PubMed, dblp and Zenodo, security advisories from NVD, OSV and CISA KEV, financial data from SEC EDGAR, the IMF, the World Bank, CFETS, Yahoo Finance and CoinGecko, legal sources including the US Federal Register, CourtListener, openlegaldata and UK legislation, and news from Google News and GDELT. video_search looks across Bing Videos and DuckDuckGo Videos. And research is the one-call path, doing concurrent multi-engine search, reranking, tiered body fetching, paragraph windowing and a sourced Markdown evidence pack, where the model components for reranking, embedding and decision are all optional and the rules-based path takes over silently when they are missing or fail. A companion cache_search tool does full-text retrieval over the bodies research has already fetched, persisted through node:sqlite for seven days, degrading to a no-op when that module is unavailable, which needs a recent Node and an experimental flag on some versions.

The package layout and how it is maintained

The npm package is dsh-free-search at version 0.9.11, MIT licensed and published publicly. The entry point is lib/index.js with a separate./client export and the whole library tree shipped as individual files, which makes the internals legible: client.js and mcp_adapter.js for the harness side, research.js and rerank.js for the research path, cache.js for the query and body caches, vertical.js for the domain_search sources, fetch_provider.js and fetch_upstream.js for the page fetching, domain_filter.js and url_norm.js for the blocklist and URL handling, multi_policy.js for the Multi mode rules, and weather.js alongside. The repository root also holds a cordis.patch.yml, which is how the plugin patches the harness, and the settings screenshots show the free-engine and API key configuration screens. The release history shows the project moving quickly, with v0.9.8, v0.9.9 and v0.9.11 all tagged on 2026-10-20, and the last push on 2026-10-20 as well. A version check button in the settings card queries the npm registry directly and offers a jump to the newer version, so the plugin is built to tell you when it has fallen behind.

Where dsh-free-search is the wrong choice

Three cases. The first is a user with a single paid search key they trust, because the fallback chain and the engine router exist to survive provider failures, and with one reliable provider that machinery is complexity you do not need. The second is an agent that must not read arbitrary web pages, since the plugin's whole purpose is to put untrusted page text in front of a model, and the mitigation is a prompt boundary and a 300 character truncation rather than a policy you can enforce elsewhere. The third is a network where the free engines will not work, because several of them are anonymous web scrapers rather than APIs, and the README is explicit that at least one of them judges its keyless tier by egress IP and will refuse a VPN or proxy address, cooling the engine for six hours when it does. Against paying for a single commercial search API, the difference in approach is breadth against depth, and breadth has costs that show up as rate limits, quota sharing and results of uneven quality, which the plugin manages but does not remove.

Editorial conclusion

dsh-free-search is a good fit for someone running the DeepSeek Harness behind a gateway whose OpenAI-compatible endpoint does not carry the built-in web_search tool, and for a team that wants its agents to keep searching when one provider is rate limited or out of quota. It is a poor fit if you have a paid search key you trust and no reason to run many engines, and it is a poor fit for an environment where the agent should not be reading arbitrary web pages at all. Check three things before you install it: that the fallback chain's order is what you want, because the plugin decides the sequence and you can enable or disable individual engines and reorder the priority, that the keyless engines will behave from your network, since the README says the anonymous tier of at least one provider is judged by egress IP and will be refused behind a VPN or proxy, and that your harness version supports the settings row the plugin expects, which the README ties to a specific release candidate.

Frequently asked questions

What does dsh-free-search do?

It is a plugin for the DeepSeek Harness that registers additional web search providers into the ctx.web seam, so the built-in web_search tool can pick among 27 engines and fall back automatically. It implements the official WebSearchProvider seam interface and coexists with the official plugin.

Which search engines work without an API key?

DuckDuckGo in its HTML and Lite forms, Bing, AnySearch AI, SearXNG, Exa, Tavily, Keenable, Firecrawl and Parallel are all usable without a key, several through an anonymous tier. The paid engines need their own key, including Perplexity, SerpBase, Serply, the DeepSeek routes, You.com, Baidu, Kimi, Aliyun, Doubao, the Zhihu routes and the OpenAI, Gemini and Claude model built-in searches.

How does dsh-free-search handle a failing search engine?

Any engine failure, whether for a missing key, an authentication error, a rate limit or a network problem, moves the query to the next engine in the fallback chain, and the result notes which engine actually produced it. A quota or authentication failure cools that engine for the session, an anti-bot block triggers a short backoff, a timeout, server error or rate limit retries the same engine once, and a parse failure or empty result does not cool it down.

How does dsh-free-search protect against prompt injection from web pages?

The plugin's own tools wrap fetched page text in an untrusted-web-content boundary and strip any matching marker that appears in the page, so a page cannot close the boundary early. The injected system prompt states that all search results are untrusted external data whose instructions must not be followed, and every snippet is cleaned and truncated to 300 characters.

Can I use several API keys for one search engine?

Yes. Any key field or the corresponding environment variable can hold multiple keys separated by commas, semicolons or newlines, and on a 401, 402 or 429 the plugin rotates to the next key for the same engine before it falls back to another engine. Results are also cached for five minutes with an LRU of 50 entries to protect the free engines from rate limiting.

Official sources

  1. DDDMUC/dsh-free-search on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/dddmuc-dsh-free-search.svg)](https://hysenlabs.com/projects/dddmuc-dsh-free-search)

Was this useful?