hermes-anysearch
AnySearch web search and content extraction for
Hermes Agent, plus two real-time
fallback chains that keep the web tools working when a primary backend fails.
| Provider | What it does | Select with |
|---|---|---|
| anysearch | AnySearch alone (REST /v1/search + /v1/extract) | web.backend or per-capability keys |
| exa-anysearch | Exa first → AnySearch on any Exa failure | web.search_backend |
| firecrawl-anysearch | Firecrawl first → AnySearch on any Firecrawl failure | web.extract_backend |
Why the chains
Hermes' built-in runtime rescue only rescues a failed call to its keyless
anonymous ring, which is heavily throttled. AnySearch's free tier is
1,000 requests/day (20 QPS with a key; anonymous access works without one),
which makes it a strong second backend:
- Search: Exa's free credits drain under burst use; the chain retries Exa on
every call, so a reset quota is picked up automatically with no manual switch-back. - Extract: in a batch replay of 20 URLs that had previously failed on
Firecrawl, most failures were backend-level (unconfigured, 60s scrape
timeouts) rather than hard pages, and AnySearch recovered 65% of them.
Firecrawl stays first because it clears anti-bot walls AnySearch cannot
(npmjs, WeChat, z-lib).
Install
-
Clone into your Hermes plugin directory:
git clone https://github.com/<owner>/hermes-anysearch "$HERMES_HOME/plugins/anysearch" -
Enable the plugin (Hermes requires explicit opt-in for user plugins):
hermes plugins enable anysearch -
Optional but recommended — add an AnySearch API key. A free key raises the
quota to 1,000 requests/day; get one at
https://www.anysearch.com/console/api-keys.# $HERMES_HOME/.env ANYSEARCH_API_KEY=as_sk_... -
Point the web tools at the chains (or pick them via
hermes tools):# $HERMES_HOME/config.yaml web: search_backend: exa-anysearch extract_backend: firecrawl-anysearch -
Fully restart Hermes Desktop — plugins and config load at startup.
Multiple profiles
Plugins are per-profile ($HERMES_HOME/plugins), so naively this directory
would need a copy per profile and drift. Instead, make every other profile a
directory junction (Windows) or symlink (Unix) to the single checkout:
python scripts/link-to-profiles.py # create/repair links
python scripts/link-to-profiles.py --verify # check only
Hermes' plugin scanner follows junctions/symlinks, so one checkout serves every
profile. Note that plugins.enabled and .env stay per-profile: a new profile
still needs hermes plugins enable anysearch and its own ANYSEARCH_API_KEY.
Notes from testing against the live API
/v1/searchreturns bothsnippetandcontent, butcontentis an
abstract. Withformat: "markdown"it becomes a structured digest (roughly
2x the default length), never the full page — full text requires
/v1/extract. This provider requestsformat: "markdown"and mapscontent
to the result description.POST /v1/extractis the official REST endpoint and measured about 2x faster
than the MCPextracttool (0.45s vs 0.91s for the same page). The MCP path
is kept only as a fallback; itsresult.content[].textis a JSON string
that needs a second parse.- With an
Authorizationheader present but the key invalid, the API returns
401/403 — it does not silently fall back to anonymous.
Tests
Run with the Hermes venv Python:
<hermes-agent>/venv/Scripts/python tests/test_provider.py # providers + simulated failover
<hermes-agent>/venv/Scripts/python tests/test_chains.py # extract chain
<hermes-agent>/venv/Scripts/python tests/test_e2e.py normal # through tools.web_tools
<hermes-agent>/venv/Scripts/python tests/test_e2e.py broken # real failures → rescue
License
MIT
README from the reviewed commit 43c1757; it updates when the author re-pins.

vollegrewar