Introduction¶
DSH’s built-in web_search pins ctx.web to the deepseek-official provider by default. This provider requires DEEPSEEK_API_KEY. When this credential is missing, searchReady() returns false, web_search is disabled, and the model is left with only web_fetch at each step. Those who want to self-host a search engine but don’t want to hand over keys face this barrier.
The Jfreey/dsh-searxng-search introduced below fills this gap: install a SearXNG locally, run it, and point web_search at it.
What is it¶
A DeepSeek Harness plugin maintained by Jfreey, belonging to the Networking Tools category. It does not bypass DSH’s search interface but registers a provider named searxng on ctx.web, keeping the built-in web_search schema, format, and result cards unchanged.
Users do not need to apply for an API key or pay per query volume. SearXNG is self-hosted, aggregating engines like Bing, Sogou, and 360search, without ads, tracking, or wrapper redirects.
Core Capabilities¶
The README breaks the plugin into five parts, with the following responsibilities:
- Provider: Registers the
searxngprovider. Existingweb_searchtools keep the same schema, format, and result cards. - Supervision: Probes
/healthzbefore each search; if the server is down, it starts it up via launchd, systemd, Windows Task Scheduler, or the plugin’s own subprocess. - Installer:
scripts/bootstrap-searxng.sh(macOS, Linux) andscripts/bootstrap-searxng.ps1(WSL) install or repair instances idempotently, never overwriting existing settings files. - Settings page: Engine tables grouped by category, one-click detection of locally reachable engines, a recommended list, and outbound proxy settings.
- Proxy: Reads/writes SearXNG’s
outgoing.proxies.all://to route engine requests through a local proxy.
Installation & Enablement¶
The order is to prepare SearXNG first, then install the plugin.
# 1. Prepare a reachable SearXNG (skip if already running)
./scripts/bootstrap-searxng.sh # macOS / Linux
./scripts/bootstrap-searxng.sh --print # View plan before execution
# 2. Install the plugin into the DSH profile
# In DSH go to Plugins → install from a directory, or
dsh plugin install /path/to/dsh-searxng-search
The installation script requires the environment to have git, Python 3.11+, and macOS, Linux, or WSL. SearXNG must also have JSON output enabled, i.e., search.formats must contain json.
To point to an existing instance, just change config.baseUrl; to point to another machine, use ensure.enabled: false to disable supervision to prevent the plugin from trying to start a process on the remote machine.
Port is an implicit convention that must match on both sides. The installation script directly rejects it if the port is occupied by a process not belonging to SearXNG and prints who is occupying it:
Port 8888 is taken by another process:
python3.1 (pid 835)
Nothing was installed. Use another port, and set the plugin's baseUrl to match:
SEARXNG_PORT=8899 ./scripts/bootstrap-searxng.sh
config.baseUrl: 'http://127.0.0.1:8899'
To change to another port, pass SEARXNG_PORT in the script and synchronously change config.baseUrl on the plugin side. There is no automatic port fallback: the script and the plugin must agree on the same port. If the port pointed to by the plugin is dead, it will scan 8888–8896 to find an instance that responds to /healthz and returns an engine list from /config, and prompt for the correct address.
Configuration¶
Plugin configuration resides in the profile. A complete example is as follows:
- id: searxng-search
name: 'dsh-searxng-search'
config:
baseUrl: 'http://127.0.0.1:8888'
settingsPath: '~/.local/share/searxng/searxng.yml' # Optional, default value
id: searxng # Provider id pinned to the web service
maxResults: 20 # Lower limit on the provider side; the tool caps it again
timeoutMs: 20000
safesearch: 0
probeTimeoutMs: 12000 # Single engine probe
# Optional SearXNG query parameters, omitted if empty:
# language: zh-CN
# categories: general
# engines: google,bing
ensure:
enabled: true
healthPath: /healthz
probeTimeoutMs: 1500
startupTimeoutMs: 20000
probeIntervalMs: 400
retryCooldownMs: 15000
launchAgent: com.searxng.server # macOS
systemdUnit: '' # Linux, e.g. searxng.service
windowsTask: '' # Windows (WSL only)
windowsService: ''
command: '' # Generic fallback, owned by the plugin
args: []
cwd: ''
env: {}
How Supervision Works¶
Every web_search probes GET /healthz first, with a budget of 1.5 seconds. When the server is not up, it processes according to the following three-level order, then polls until healthy (budget 20 seconds), and then performs the search:
- The platform’s supervisor, provided it is configured and installed. The process is owned by that manager; the plugin does not kill it.
- Otherwise, use
ensure.command. The plugin starts it viactx.subprocessand owns it, terminating when the plugin is uninstalled. - If neither exists, the search fails. The error message lists which methods were tried, which configuration to change, or which part to install.
Startup failures are remembered via retryCooldownMs, and concurrent searches share a single recovery attempt. The provider does not implement ready(), so web_search remains open for every model call—when the server crashes, it manifests as an actionable tool error rather than the tool silently disappearing.
Platform Support¶
| Platform | Supervisor | Installer | Status |
|---|---|---|---|
| macOS | LaunchAgent, launchctl kickstart -k gui/<uid>/<label> |
bootstrap-searxng.sh |
Verified installation, self-healing, and clean uninstallation on physical devices |
| Linux | systemd user unit, systemctl --user restart, fallback systemctl restart |
bootstrap-searxng.sh |
Installer, settings, JSON API and plugin round-trip verified in Ubuntu 24.04 container; unit itself verified using stubbed systemctl |
| Windows | — | bootstrap-searxng.ps1 rejects directly outside of WSL |
Not supported natively: SearXNG’s searx/valkeydb.py imports the POSIX-exclusive pwd module, causing the process to exit at import. Use WSL, Docker, or point config.baseUrl to a Linux/macOS instance |
The plugin half is pure Node and can run on any platform; only the server itself is bound to POSIX.
Engine Page Scoring¶
When the Settings page opens, it immediately probes the already checked engines, so the table is never empty, and it can be re-probed on demand. Each item is scored 0–100, composed as follows:
| Component | Score | Rules |
|---|---|---|
| Response | 55 | Returns valid JSON, and there is no unresponsive_engines entry for it |
| Latency | 25 / 18 / 10 / 4 / 0 | ≤0.8s / ≤2s / ≤5s / ≤15s / Slower |
| Volume | 20 / 12 / 4 | ≥5 results / 1–4 results / None |
This is an availability score, not an accuracy score—no component compares engine answers with ground truth. There is no labeled corpus, nor cross-engine consistency sampling; the page does not make such claims.
Above the scores, two types of suggestions are marked: engines that are unresponsive (CAPTCHA, blocked, disabled) and engines that respond slower than 5 seconds. Both offer a one-click “select the working set”, which simply unchecks these. Zero results do not count as suggestions: the probe only sends a short query. Currency or translation engines may reasonably return empty within 5ms but are functioning normally; these are only listed as notes.
Apply writes an explicit switch for each engine (- name: "<engine>" + disabled: true|false) and removes use_default_settings.engines.keep_only. The whitelist is a one-way gate—after writing it, /config only returns the retained engines; other engines disappear from the page and cannot be opened again. The first apply moves the file there; the page also lists engines parsed from SearXNG’s own searx/settings.yml, so even if not yet migrated, the directory is complete.
Use Cases & Notes¶
Suitable for the following types of people:
- DSH profile users who want to run search locally and reject third-party keys and pay-per-query.
- People who already know how to self-host SearXNG and need DSH to point to it.
- People in network environments where some engines are unreachable and want to select an engine set based on local network testing results.
Points to note:
- The plugin runs with the current dsh process permissions; the plugin source code and license (MIT) should be checked before installation.
- The server cannot run natively on Windows; it must use WSL or Docker, or point to a remote instance.
- The engine table scoring only reflects availability, latency, and return volume, not search quality. To judge quality, one must build a labeled corpus or perform consistency sampling; the plugin does not do this.
Closing¶
The value of this plugin lies not in swapping a search interface, but in turning “keyless local search” into a plugin switch in the DSH profile: install once, web_search can point to a SearXNG on your own machine; if the server crashes, it self-heals according to the configuration; the engine set is adjusted based on local testing results. All code is open source on GitHub; the directory page is a community site and has no official affiliation with DeepSeek / Hypothesis.
- Directory page: https://www.skillhub.cn/plugins/Jfreey/dsh-searxng-search
- GitHub: https://github.com/Jfreey/dsh-searxng-search