# Web Search Plus for Hermes: two tools, a provider fallback chain, and a 4.0 migration

> Web Search Plus gives a Hermes agent `web_search_plus` and `web_extract_plus`, routes each query through whichever provider answers, and can fall back when one fails. It is also a plugin that removed a provider in 4.0 and expects you to migrate.

**robbyczgw-cla/hermes-web-search-plus** — Give your Hermes agent the web as real sources, never a made-up answer — multi-provider search and extraction with an optional local, key-free DonSeTch option.

- Repository: https://github.com/robbyczgw-cla/hermes-web-search-plus
- Website: https://websearchplus.xyz
- Stars: 419 · Forks: 31
- Language: Python
- License: MIT
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/robbyczgw-cla-hermes-web-search-plus

## Two tools, and a provider contract that forbids a written answer

The plugin adds exactly two tools to a Hermes agent. `web_search_plus` searches the web and returns useful sources, `web_extract_plus` reads and cleans pages you already have. That split is the design: search finds candidate URLs, extract turns them into readable text, and the agent reasons over the pages rather than over a paragraph somebody wrote for it.

The rule that keeps it honest lives in the provider scaffolding rather than the prose. Each provider module implements `execute_search` and the template comment says never to return a synthesized answer, raise a typed `wsp_sdk` error for failures instead. A provider that cannot find anything is supposed to fail, not to improvise.

That contract is why results point back to the pages they came from. The project description and the Why use it section both make the same claim, that the web is not hidden behind a generated answer. For an agent that has to cite something, a provider returning three URLs and one honest failure is more useful than a provider returning a paragraph with no provenance.

The code is a port. This plugin was moved from `web-search-plus-plugin` to the Hermes Agent plugin API, so the plugin surface follows Hermes while the engine underneath kept its history.

## One configured provider is enough, and the rest is a fallback chain

Configuration starts with a single provider. Pick one to start and add more when a query comes back empty, which is the intended way to grow the setup rather than wiring six keys on day one.

When a provider is unavailable or returns nothing, the plugin tries another. The reasons given are practical: fewer dead ends, and quality reports that show which service worked and what happened along the way. Those reports are optional, so the same install can be quiet or diagnostic depending on what you ask for.

The provider names visible in the documentation span both hosted and local. Exa and Tavily appear in the 4.1.1 notes, Parallel gained its own routing mode in 4.0.2, and SearXNG, Keenable and DonSeTch are named as the local options that reduce dependence on paid APIs. SearXNG also has its own URL field in the Hermes Desktop settings form, and its instance is the piece most people already run.

The routing between them was, for most of the 3.x line, not adaptive at all. Details below.

## 4.0 deleted a provider, so the upgrade has a migration step

Web Search Plus 4.0.0 made DonSeTch 2.1.0 the optional local source provider for Search and Markdown Extract. It runs as a separately installed stdio MCP process configured through `DONSETCH_BIN`, and it is not bundled with the plugin.

The same release removed the Hound provider and the `HOUND_MCP_URL` integration, which is the one breaking change in a line the project otherwise describes as additive or opt-in since 3.0. If you arrived at this plugin through Hound, there is no configuration flag that brings it back.

DonSeTch's own versioning then moved under the adapter several times. 4.0.3 tested against 3.2.1, 4.2.1 tested against 4.2.9, and each release tells you what to install:

```bash
npm install -g donsetch@4.2.9
```

An older 2.x binary reports `incompatible_major`. Other parsed versions, including 3.x, report `compatible_unverified`, which is a warning rather than a refusal. Two details make a long extract call survivable: DonSeTch reuses one stdio MCP session for every URL in a single extract call instead of spawning per URL, and the child is reaped on timeout or MCP failure rather than left behind. `setup.py status` reports whether the binary is ready at all.

## Keys go to .env, and the plugin itself stays stdlib-only

API keys have one home and it is not the config file. Hermes Desktop can configure the plugin from its settings form, covering country, language, max results, auto-routing, the SearXNG URL and one API key field per provider, and every key it collects is written to `.env`. `config.json` never receives a key. A `.env.template` sits at the root as the shape of that file.

The optional Jev layer follows the same rule with a twist. Its key belongs in `TYPESAFE_API_KEY_FILE` at mode 600, not in `config.json`, and enabling it means installing `typesafe-sdk` separately. Without that dependency the plugin stays on the standard library, which is why an opt-in feature cannot quietly pull a new transitive tree into your install.

Jev is not a search provider and stays off until you pass `setup --jev`. What it does is narrow. It can confirm a `news` search type, but only at confidence of 0.95 or above; keywords may propose `news` and anything less confident leaves the request as `search`. An explicit `--search-type news` is untouched. On extract it scores bodies, and it may keep a long page that looked like a bot wall or reject page chrome. Language fill happens only when the plugin inferred none.

One portability fix is worth noting for Windows users: as of 4.2.0 the import path no longer requires `fcntl`.

## Routing was static from 3.0 until 4.3.0 restored the samples

The 4.3.0 notes describe an honest regression. Since the 3.0 engine, searches no longer recorded provider samples, so adaptive routing fell back to static priority. Every routing decision during that window was a fixed order, whatever the providers had actually been doing.

The fix was to make the statistics file safe to write from several places: `provider_stats.json` writes are now locked across processes. The same release made the agent tool honour `defaults.max_results` when `count` is omitted, so the configured default is no longer ignored on the tool path.

Parallel Search has its own knob. `parallel.mode` takes `turbo`, `fast`, `basic` or `advanced`, with `fast` as the default, and as of 4.0.2 Parallel joins automatic routing when a key is configured, which means its cost per call is now something the router can weigh.

The routing code has its own file, `routing.py`, alongside `provider_health.py`, `provider_dispatch.py`, `provider_registry.py` and `provider_stats.py`. The split suggests health checking is separate from ordering, which is the part worth watching if your key set changes.

## 4.3.2 made failures quieter and redirects same-origin only

Extract hardened in 4.3.2, and the release note warns that some failures are now stricter or less detailed. The list is worth reading as a set: stricter extract URL validation, same-origin-only redirects in the HTTP client, response size limits, no provider error text passed to the model, and an untrusted-web-data notice attached to results.

Two of those change debugging. Withholding provider error text from the model is the right call for prompt injection, since a provider's error string is attacker-influenced text, and it means you read the quality report rather than the agent's paraphrase to find out what failed. The untrusted-web-data notice does the same job for page content.

4.3.3, released the same day as 4.3.2, fixes a specific rejection: extract now converts internationalized hostnames such as `muller.de` to punycode instead of refusing them.

Smaller correctness fixes sit around those. Since 4.0.4 a query beginning with `-`, such as `-site:reddit.com`, stays search text across both the API and subprocess paths instead of being parsed as a flag. In 4.1.1 Exa keeps the highlights you asked for rather than replacing them with the start of the page, Parallel passes result count and domain filters through `advanced_settings`, and Tavily maps the unified `freshness` filter onto its native `time_range`.

## Cache controls reached the plugin API, and providers are discovered files

Cache behaviour is now settable where the agent can reach it. Since 4.2.1 the plugin API accepts `no_cache` and `cache_ttl`, matching what the CLI already did. Recency queries cap the TTL, and a cached hit reports its age, so a stale answer looks stale instead of looking fresh.

Adding a provider is a scaffolding job rather than a patching one:

```bash
python3 setup.py status
python3 setup.py list
python3 setup.py new-provider donsetch
```

`new-provider` writes a module into `providers.d/`, where it is discovered automatically. The generated module derives its environment variable from the provider id in upper case plus `_API_KEY`, writes a config section with underscores, and imports only the stable `wsp_sdk` surface, which is `ProviderSpec`, `register_provider`, `search_result` and `source_result`. The id has to match a lowercase pattern of dash-separated alphanumeric groups, and `kind` starts as `search` with a note to change it to `extract` or `both` when needed. The scaffold even fills in a failing example, which raises rather than inventing a result.

The repository is MIT licensed, the homepage is websearchplus.xyz, and v4.3.3 shipped on 2026-10-01 after v4.3.2 the same day and v4.3.1 on 2026-09-23. Contract tests for the schema boundary run under Node with ajv, separate from the Python side.

## Conclusion

Web Search Plus is worth installing when your Hermes agent needs links it can actually cite, because the provider contract forbids synthesized answers and the fallback chain covers a dead key. Skip it if you wanted Hermes' native web_search to change behaviour on install, since the `wsp` backend is opt-in and installation does not select it. Three things to verify before you configure anything. The 4.0 release removed the Hound provider and `HOUND_MCP_URL`, so existing installs need the documented migration. DonSeTch is not bundled: you install it yourself and the adapter reports `incompatible_major` on a 2.x binary. And note the README on the repository page stops after the 4.x release notes and the Why use it section, so the install and CLI reference are in `docs/`, not on the page. Keys belong in `.env`, never `config.json`.

## FAQ

### Can Hermes Agents search the web?

With this plugin installed, a Hermes agent gets `web_search_plus` for search and `web_extract_plus` for reading and cleaning pages. An opt-in `wsp` backend can also route Hermes' own `web_search` and `web_extract` calls through the same engine in-process, and installation does not select it for you.

### Do I need a paid search API key to use Web Search Plus?

One configured provider is enough to start. SearXNG, Keenable and the optional DonSeTch provider exist to reduce dependence on paid APIs, and DonSeTch is installed separately with `npm install -g donsetch@4.2.9` rather than bundled.

### Where does Web Search Plus store API keys?

In `.env`, never in `config.json`. The Hermes Desktop plugin settings form writes one key field per provider there, and a Jev key belongs in `TYPESAFE_API_KEY_FILE` at mode 600.

### What happened to the Hound provider in Web Search Plus?

It was removed in 4.0.0 together with the `HOUND_MCP_URL` integration, which makes the 4.0 release the one migration step in an otherwise additive line. DonSeTch replaced it as the optional local source provider.

### How do I add my own search provider to Web Search Plus?

Run `setup.py new-provider <id>`, which writes a module into providers.d/ where it is discovered automatically. The generated code derives the API key environment variable from the id and must return source-only results, raising a typed wsp_sdk error rather than a synthesized answer.

## Sources

- [License: MIT](https://github.com/robbyczgw-cla/hermes-web-search-plus/blob/main/LICENSE)
- [Project website](https://websearchplus.xyz)
- [README](https://github.com/robbyczgw-cla/hermes-web-search-plus/blob/main/README.md)
- [Releases](https://github.com/robbyczgw-cla/hermes-web-search-plus/releases)
- [robbyczgw-cla/hermes-web-search-plus on GitHub](https://github.com/robbyczgw-cla/hermes-web-search-plus)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/robbyczgw-cla-hermes-web-search-plus
