hermes-yandex-search-api
Give your Hermes Agent first-class Yandex search. This plugin wires the Yandex Search API into Hermes as a drop-in web-search backend and adds a grounded-answer tool — excellent results for Russian-language queries, on infrastructure you may already have in Yandex Cloud.
- 🔎
yandexweb-search backend — routes Hermes' built-inweb_searchtool to Yandex web search (links with titles and snippets). Nothing new for the model to learn. - 💬
yandex_generative_searchtool — a single grounded answer synthesised from live web sources, with the source URLs it cites.
Quick start
# 1. Install into Hermes (other ways: see Installing the plugin). It asks for
# your Yandex Cloud API key and folder id (see "Getting a token" below)
hermes plugins install akinfold/hermes-yandex-search-api/hermes_yandex_search --enable
# 2. Skipped the questions, or installed another way? Add the credentials yourself:
printf 'YANDEX_API_KEY=%s\nYANDEX_FOLDER_ID=%s\n' 'your-api-key' 'your-folder-id' >> ~/.hermes/.env
# 3. Select Yandex as the web-search backend
hermes config set web.search_backend yandex
Steps 1 and 3 leave this in ~/.hermes/config.yaml, if you would rather write it
yourself:
web:
search_backend: yandex
plugins:
enabled:
- yandex
That's it — web_search now goes through Yandex, and the
yandex_generative_search tool is available to the agent. Don't have an API key
and folder id yet? See
Getting a Yandex Search API token. Other
ways to install, and how to upgrade: see
Installing the plugin into Hermes.
Why these two search modes
The Yandex Search API offers several modes — classic web search, generative search, image search, deferred (async) web search, and Wordstat keyword statistics. This plugin deliberately wires up the two that fit an autonomous agent, each in the shape Hermes expects:
- Web search → a
web_searchbackend. Hermes already ships aweb_searchtool whose backend returns a list of{title, url, description}results. The classic Yandex web search maps onto that contract exactly, so the model can use the search tool it already knows without learning a new one. - Generative search → its own tool. Generative search returns a synthesised
answer with citations, not a list of links. That is a fundamentally different
result shape, so it is exposed as a distinct
yandex_generative_searchtool. It is the best fit when the agent wants a direct, grounded answer to a factual question.
The other modes are intentionally left out: image search returns image URLs
an agent cannot usefully consume, Wordstat is SEO keyword analytics unrelated
to agentic search, and deferred web search has a multi-minute latency that is
unusable for interactive turns. All of them can be added later on top of the same
YandexSearchClient if a use case appears.
About the Yandex Search API
The Yandex Search API is Yandex Cloud's paid programmatic access to Yandex web search and its generative answer engine. Requests are authenticated with a Yandex Cloud API key and are billed to the Yandex Cloud folder that owns the key. Both search modes used here run synchronously:
POST /v2/web/searchreturns Base64-encoded XML search results.POST /v2/gen/searchreturns a JSON grounded answer with cited sources.
See the pricing and quotas pages for current limits (roughly 10k web requests/hour and 1k generative requests/hour by default).
Requirements
- Hermes Agent
>= 0.19. Checked before every release against the latest Hermes release and Hermesmain, each installed by its official installer. - Python
>= 3.11; the tests run on 3.11–3.14. - The Python packages
httpx >= 0.24anddefusedxml >= 0.7. Option C (PyPI) installs both. Options A and B install neither, and a Hermes set up by its official installer normally has both — see the note under Option B. - A Yandex Cloud account with the Search API enabled, an API key, and the folder id that owns it.
Getting a Yandex Search API token
- Create or open a Yandex Cloud account and a folder (catalog). Note its folder id — you can copy it from the console URL or with the CLI: how to get the folder id.
- Create a service account in that folder and grant it the
search-api.webSearch.userrole. - Create an API key for that service account (Console → the service account
→ API keys → Create API key), or via CLI:
yc iam api-key create --service-account-name <sa-name> --format json
Copy thesecretvalue — this is yourYANDEX_API_KEY. - Make sure the Search API is enabled for the folder and that billing is active.
You now have the two values the plugin needs: YANDEX_API_KEY and
YANDEX_FOLDER_ID.
Installing the plugin into Hermes
Option A — install from Git (recommended)
hermes plugins install akinfold/hermes-yandex-search-api/hermes_yandex_search --enable
Note the /hermes_yandex_search at the end. The plugin lives in that directory,
not at the repository root, and Hermes reads the manifest from whatever you point
it at. Name the directory and the install is a plugin: Hermes prompts for
YANDEX_API_KEY and YANDEX_FOLDER_ID, installs under the manifest name
yandex, and --enable enables that name. It also scans only that directory, so
the tests and workflows in this repository stay out of the security report.
Point it at the repository root instead and Hermes copies a directory with no
manifest and no register(ctx) in it: it warns that it "may not be a valid Hermes
plugin", asks for no credentials, and does not enable the plugin. hermes plugins list then still shows yandex — the package nested in the clone is found — but
shows it as not enabled, which is the symptom to look for. If you installed
that way, remove ~/.hermes/plugins/hermes-yandex-search-api and install again
with the directory named.
Option B — drop-in directory
From a clone of this repository, copy the plugin directory into your Hermes
plugins folder under the web category, then enable it:
mkdir -p ~/.hermes/plugins/web
cp -r hermes_yandex_search ~/.hermes/plugins/web/yandex
hermes plugins enable yandex
Or download hermes-yandex-search-plugin-<version>.zip from a
GitHub Release
and unzip it there instead:
unzip hermes-yandex-search-plugin-<version>.zip -d ~/.hermes/plugins/web/
hermes plugins enable yandex
Either way you end up with ~/.hermes/plugins/web/yandex/plugin.yaml. Nothing
asks for credentials on this path — add them to ~/.hermes/.env as in the
Quick start, and select the backend the same way.
Options A and B install no dependencies. Both copy the plugin's sources only, and the plugin directory declares nothing for Hermes to install. A Hermes set up by its official installer normally has both packages the plugin needs:
httpxis a Hermes dependency, anddefusedxmlcomes withyoutube-transcript-api, from Hermes'youtubeextra, which is part of its[all]set. The install check confirms both before every release, on the latest Hermes release and onmain. Hermes does not support adding packages to that environment by hand, so there is no command for it here.Hermes itself declares
defusedxmldirectly only in itswecomextra, so an environment built without theyoutubeandwecomextras can lack it, and the plugin then fails to load withModuleNotFoundError: No module named 'defusedxml'. If you manage that environment yourself, install the plugin there by Option C instead, which brings both packages. An install in the older layout (see Option C) can lack it too, when its installer could not install the full set and fell back to its "core only (no extras)" tier: the installer then ends by saying it installed via a fallback tier, and what to re-run.
Option C — from PyPI
For a Hermes whose Python environment you manage yourself — your own virtualenv,
a Nix build: install hermes-yandex-search-api into that environment, then enable
the plugin. Hermes finds it through the hermes_agent.plugins entry point, and the
package brings httpx and defusedxml with it.
hermes plugins enable yandex
Not for a standard Hermes install. Since 24 September 2026 the official installer runs Hermes from environments its package manager builds and replaces, and Hermes does not support adding packages to them by hand: use Option A or B.
A Hermes in the older layout — one that runs from ~/.hermes/hermes-agent/venv
and keeps its own uv in ~/.hermes/bin, with no ~/.hermes/installs, which is
what Hermes 0.21.5 and anything installed before that date and not updated since
look like — takes the package like this:
~/.hermes/bin/uv pip install --python ~/.hermes/hermes-agent/venv/bin/python hermes-yandex-search-api
hermes plugins enable yandex
Switch such an install to Option A before you run hermes update: the update
moves Hermes onto the new environments, and a package installed this way does not
come along. A bare pip install hermes-yandex-search-api never reached Hermes at
all — the pip on your PATH belongs to some other Python.
Nothing asks for credentials on this path — add them to ~/.hermes/.env as in
the Quick start, and select the backend the same way.
Upgrading
Upgrade the way you installed. Option A — Hermes 0.21.5 and later install the new version from the source they recorded:
hermes plugins update yandex
Older Hermes cannot update an install from a plugin directory, and no Hermes
updates one pinned with --ref: run the install command again with --force,
which replaces the installed copy and keeps your credentials and backend
selection.
hermes plugins install akinfold/hermes-yandex-search-api/hermes_yandex_search --enable --force
Both scan the new version again, but unlike a first install neither stops to ask when Hermes' security scan reports a caution.
Option B from a clone — pull it, then copy the directory's contents over the
installed copy. Running the cp -r above again would put the new copy inside the
old one instead:
cp -r hermes_yandex_search/. ~/.hermes/plugins/web/yandex/
Option B from a release — unzip the new release's archive over the old one:
unzip -o hermes-yandex-search-plugin-<version>.zip -d ~/.hermes/plugins/web/
Option C — upgrade the package in the same environment: in the older layout,
~/.hermes/bin/uv pip install --upgrade --python ~/.hermes/hermes-agent/venv/bin/python hermes-yandex-search-api
Options A and B, and their upgrades, are checked before every release by
installing the build into a real Hermes — the latest release and main, each set
up by its official installer — exactly as written here; the Option C install is
checked on the latest release while it still has the older layout. See
Checking the install paths.
Configuring the token in Hermes
The plugin reads its credentials from the environment, resolved the way every
Hermes web backend resolves them: os.environ first, then ~/.hermes/.env.
The simplest, persistent option is to put them in ~/.hermes/.env:
YANDEX_API_KEY=your-api-key
YANDEX_FOLDER_ID=your-folder-id
# Optional: market/domain, default SEARCH_TYPE_RU.
# One of SEARCH_TYPE_RU | SEARCH_TYPE_COM | SEARCH_TYPE_TR | SEARCH_TYPE_KK | SEARCH_TYPE_BE | SEARCH_TYPE_UZ
YANDEX_SEARCH_TYPE=SEARCH_TYPE_RU
# Optional: override the API base URL (for a private gateway / testing).
# YANDEX_SEARCH_API_URL=https://searchapi.api.cloud.yandex.net
hermes plugins install akinfold/hermes-yandex-search-api/hermes_yandex_search
prompts for both values, because the manifest declares them. Installing any other
way, or declining the prompt, leaves you to add them to ~/.hermes/.env yourself,
as shown above.
Selecting Yandex as the web-search backend
To route Hermes' built-in web_search tool to Yandex, set the backend:
hermes config set web.search_backend yandex
That writes web.search_backend into ~/.hermes/config.yaml, which, with the
plugin enabled, then reads:
web:
search_backend: yandex
plugins:
enabled:
- yandex
The yandex backend is search-only: the Yandex Search API returns result
snippets, not page content, so the plugin does not serve web_extract. Page
extraction keeps using whichever extract-capable backend Hermes resolves, which
is why the snippet above sets web.search_backend rather than web.backend.
The yandex_generative_search tool becomes available as soon as the plugin is
enabled — no extra configuration needed. It is registered in the yandex_search
toolset, which Hermes enables by default; you can switch it off (or back on) per
platform with hermes tools.
The yandex_generative_search tool
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string | yes | The question to answer. Must be a non-empty string. |
sites |
array of strings | no | Site domains to restrict the answer's sources to, e.g. ["example.com"]. The Yandex API accepts up to 5; the plugin forwards the list as it is. Omit it to search the whole web. |
The search market is not a tool parameter; it comes from YANDEX_SEARCH_TYPE.
The tool returns a JSON string. On success:
{
"success": true,
"answer": "Paris is the capital of France.",
"sources": [{"url": "https://en.wikipedia.org/wiki/Paris", "title": "Paris", "used_text": ""}],
"search_queries": ["capital of France"],
"fixed_query": "",
"is_answer_rejected": false,
"is_bullet_answer": false
}
answer— the synthesised answer text.sources— the sources the answer cites (url,title,used_text; the last two may be empty).search_queries— the queries Yandex actually ran.fixed_query— the typo-corrected query, or an empty string.is_answer_rejected—truewhen Yandex declined to answer.is_bullet_answer—truewhen the answer is formatted as a bullet list.
The tool never raises. Any failure — missing credentials, invalid arguments, an
HTTP or API error — comes back as {"success": false, "error": "<message>"}.
Configuration reference
| Variable | Required | Default | Description |
|---|---|---|---|
YANDEX_API_KEY |
yes | – | Yandex Cloud API key. |
YANDEX_FOLDER_ID |
yes | – | Yandex Cloud folder ("catalog") id. |
YANDEX_SEARCH_TYPE |
no | SEARCH_TYPE_RU |
Search market/domain enum. |
YANDEX_SEARCH_API_URL |
no | https://searchapi.api.cloud.yandex.net |
API base URL override. |
YANDEX_SEARCH_TYPE applies to both web and generative search and is case-sensitive:
an unrecognised value makes every call fail with an error naming the accepted values.
The rest of the request options are fixed and cannot be configured. Every request
times out after 30 seconds, and on expiry the call fails with an error such as
HTTP request to /v2/gen/search failed: .... Web search returns at most the number
of results Hermes asks for (clamped to 1–100), one document per site group, first
page only. The family filter stays at FAMILY_MODE_MODERATE, Yandex typo correction
is always on for both modes, and region and snippet localisation are left at the
Yandex defaults for the selected market.
Development
python -m venv .venv && source .venv/bin/activate
pip install -e '.[dev]'
ruff check . # lint
ruff format --check . # code style
pytest # unit tests (live E2E tests are deselected by default)
radon cc -s -n C hermes_yandex_search # complexity gate; must print nothing
The package layout separates a Hermes-independent API client from the host integration:
hermes_yandex_search/client.py— theYandexSearchClient(pure HTTP + parsing, no Hermes imports).hermes_yandex_search/provider.py— theyandexweb-search backend provider.hermes_yandex_search/generative.py— theyandex_generative_searchtool.hermes_yandex_search/config.py— builds a client from environment variables.hermes_yandex_search/__init__.py—register(ctx), the plugin entry point.
Running the live E2E tests
The E2E suite (marked e2e, deselected by default) hits the live Yandex
Search API and, when hermes-agent is installed, a live Hermes host.
Locally
Store your API key in a file (created with restrictive permissions), and the folder id in a companion file:
umask 077 && printf '%s' 'your-yandex-search-api-key' > ~/.yandex-search-api-key
umask 077 && printf '%s' 'your-yandex-folder-id' > ~/.yandex-folder-id
(Alternatively, export YANDEX_API_KEY and YANDEX_FOLDER_ID in your shell —
environment variables take precedence over the files.) Then:
pytest -m e2e -v
The Hermes-host test (tests/e2e/test_live_hermes.py) skips automatically unless
Hermes is importable. The hermes-agent on PyPI is far behind the Hermes users
run, so run the suite in the Python of a real Hermes install instead, as the
workflow below does: tests/install/hermes_env.py finds that Python in either
layout the installer makes, this checkout goes on its path, and pytest goes on
it after Hermes' own packages, so Hermes keeps its own versions. Nothing is
installed into Hermes' environment, which Hermes builds itself. From the root of
this checkout, with the development virtualenv active:
site=$(mktemp -d)
python -m pip install --quiet --target "$site" pytest
PYTHONPATH="$PWD" "$(python tests/install/hermes_env.py)" -c 'import sys; sys.path.append(sys.argv.pop(1)); import pytest; raise SystemExit(pytest.main(sys.argv[1:]))' "$site" tests/e2e -m e2e -v
For a Hermes you run from a checkout of your own rather than the installer's, put
the Python that checkout runs on in place of $(python tests/install/hermes_env.py).
On GitHub Actions
The E2E (live) workflow (.github/workflows/e2e.yml) is manual
(Actions → E2E (live) → Run workflow). It reads credentials from a GitHub
Environment
so they are never committed to the repo. It runs the plugin inside a real Hermes,
installed by its official installer: the latest Hermes release by default, and its
hermes input switches to Hermes main or to no Hermes at all. With Hermes, the
tests run in Hermes' own Python, with this checkout on its path rather than
installed into Hermes' environment, and the run fails outright if the plugin
cannot import Hermes, rather than skipping the Hermes-host test.
If you fork this repository and want to run the live E2E workflow, set up the Environment once:
- Open Settings → Environments → New environment and name it
yandex-e2e(the name the workflow references). - Under that environment, add two secrets:
YANDEX_API_KEY— your Yandex Cloud API key.YANDEX_FOLDER_ID— your Yandex Cloud folder id.
- Optionally add an environment variable
YANDEX_SEARCH_TYPE(e.g.SEARCH_TYPE_COM) to change the default market. You can also override it per-run via the workflow input. - (Recommended) Add required reviewers to the environment so live runs must be approved — this gates access to the paid API.
- Run the workflow from the Actions tab.
Checking the install paths
The install-marked tests in tests/install/ install the built plugin into a
real Hermes, set up by its official installer, by each option in
Installing the plugin into Hermes — both
forms of Option B and the upgrades included, running the README's own commands —
and then ask Hermes what it loaded: the plugin must be listed as enabled, load
without error, give the agent yandex_generative_search, and, with the backend
selected, be the provider web_search calls. They also check that installing
from the repository root still looks the way this README describes. A fast unit
test keeps the commands in the tests and in this README identical.
The Install check workflow runs them against the latest Hermes release and
against Hermes main on every pull request, and on every release tag before
anything is published: the GitHub Release and the PyPI upload both wait for it.
They install into a real ~/.hermes, so run them yourself only in a container or
VM — see the docstring of tests/install/test_install.py.
Related Hermes plugins
Part of a family of Yandex plugins for Hermes Agent:
- hermes-yandex-disk — browse, read, write, and share files on Yandex Disk (REST API).
- hermes-yandex-mail — search, read, flag, move, and delete Yandex Mail messages over IMAP, and send over SMTP when sending is switched on.
- hermes-yandex-calendar — list, create, update, respond to, move, and delete Yandex Calendar events (CalDAV).
Contributing
Contributions are welcome — see CONTRIBUTING.md for the dev setup and checks to run.
License
MIT © Roman Akinfeev
Metadata
Release files for hermes-yandex-search-api 0.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| hermes_yandex_search_api-0.1.4.tar.gz | 35.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hermes_yandex_search_api-0.1.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 57.8 kB
Release files / hermes_yandex_search_api-0.1.4.tar.gz
| Download URL | hermes_yandex_search_api-0.1.4.tar.gz |
|---|---|
| Size | 35.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
8eb132a1c9a9ba1dbdfe156a0a69792f8cedec5f4e3cfdd5a6f474c7f43e4af0
|
|
BLAKE2b-256 checksum How to use checksums |
ef75962e17894261d9704b2b5069eb25fbbfe8c26b3f3b23900e2ebf76eeec14
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency logRelease files / hermes_yandex_search_api-0.1.4-py3-none-any.whl
| Download URL | hermes_yandex_search_api-0.1.4-py3-none-any.whl |
|---|---|
| Size | 22.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
bb260eda2a01a77671a94813dfaed2a12455c2bd83d175495ef183ad55efdd7b
|
|
BLAKE2b-256 checksum How to use checksums |
97baa3b1021e052621a2065685e5f72e3d25f988487811e152481a27eff1930f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 26, 2026.
Transparency log