Skip to content

Hermes Agent

Installing more than one agent framework? The one-line curl covers Claude Code, OpenCode, OpenClaw and Pi in a single pass, and can select several at once. Hermes is installed manually, below.

The Telem plugin gives Hermes Agent two native tools:

  • telem_search — web search across Telem’s provider set, with several queries batched into one call.
  • telem_fetch — read whole pages, a small batch of URLs per call.

It ships inside the telem-sdk Python package and Hermes discovers it through a standard Python entry point — no separate plugin package, no npm.

Install telem-sdk into the same Python environment Hermes runs in, then enable the plugin:

Terminal window
pip install telem-sdk
hermes plugins enable telem

Confirm Hermes found it — telem should be listed, as enabled, with source entrypoint:

Terminal window
hermes plugins list

Hermes requires Python 3.11, 3.12 or 3.13 (requires-python = ">=3.11,<3.14"); telem-sdk supports 3.10 and up, so any Hermes-compatible environment works. On 3.14, see troubleshooting.

Registering a plugin is not the same as the model being able to call it:

  1. The toolset. Both tools live in a toolset named telem, enabled by default. If you have narrowed your enabled toolsets, add telem back.
  2. tool_search. Hermes defers non-core tools behind its catalog by default, so the model discovers them by searching rather than finding them in its initial tool list.

The plugin uses the SDK’s own credential resolution: TELEM_API_KEY in the environment, then ~/.telem/credentials.json (what --login writes). Because the second exists, the tools register either way rather than being gated on the environment variable. TELEM_BASE_URL overrides the hosted service endpoint.

Hermes reads the same unified .telem/telem.json as every other file-reading Telem tool — one project file, one user file, then TELEM_*, resolved per tool call and per key. There are no Hermes-specific config files.

.telem/telem.json
{
"tier": "extended",
"providersInclude": ["exa", "brave"]
}

The two keys most people reach for:

File key Env fallback Meaning
tier TELEM_TIER Named result-field tier: minimalist, default, extended, or max
providersInclude TELEM_PROVIDERS_INCLUDE (comma-separated) Replace the deployment’s provider set

Full parameter reference → — every key, its env fallback and how the levels compose.

“The project” is Hermes’s own TERMINAL_CWD, falling back to the process working directory when that is unset or gone. Anything ignored is reported to the Hermes log, never into the text the model reads.

Batch related queries into one call. They run concurrently as a single search and come back grouped per query — faster and cheaper than repeated calls:

{"queries": ["hermes agent plugin api", "hermes agent toolsets"], "goal": "plugin docs"}

goal is an optional short label for what the search is trying to establish.

Reach for telem_fetch when a snippet is not enough. Search returns titles, URLs, summaries and short excerpts; fetch returns the readable page:

{"urls": ["https://example.com/docs/plugins"]}

Results are capped so one page cannot crowd out a batch, and the whole result stays under 90,000 characters so Hermes returns it inline rather than spilling it to a file.

Hermes’s URL screening is keyed to its built-in web_extract by name, so a plugin tool inherits none of it; telem_fetch runs the same checks itself, calling Hermes’s own helpers. A URL is refused, before any request, when it:

  • carries something shaped like an API key or token — checked in the raw URL, in the normalized form a redirect resolves to, and in the percent-decoded version of either;
  • carries a credential-bearing query parameter (api_key, token, …);
  • embeds a username or password;
  • resolves to a private, loopback, or cloud-metadata address.

These checks are fail-closed: if they cannot run, the fetch is refused rather than performed unscreened.

Hermes wraps its built-in web tools’ output in untrusted-content delimiters by tool name, so telem_* output would otherwise arrive unmarked. Both tools apply the same wrapper themselves and defang any delimiter the fetched content contains — without which a page carrying a closing tag could end the trust boundary early.

It is a mitigation, not a guarantee: web content reaching a model is attacker-influenced input.

“Plugin enabled but the tools are not visible.” Almost always tool_search rather than a broken install. Confirm the plugin is loaded with hermes plugins list, and check that the telem toolset is enabled.

Delegating to a subagent fails with 'DaemonThreadPoolExecutor' object has no attribute '_initializer'. Hermes is running on Python 3.14, which it does not support: CPython 3.14 stopped setting _initializer on ThreadPoolExecutor and Hermes’s thread pool still reads it, so every delegation dies at spawn — with or without this plugin. pip install hermes-agent refuses 3.14; a source-tarball install (a Homebrew formula, say) skips that check and lands here. Run Hermes on 3.11–3.13: python3.13 -m venv ~/.hermes-venv && ~/.hermes-venv/bin/pip install hermes-agent telem-sdk.

Every fetch is refused. The URL-safety checks are fail-closed and call into Hermes’s internals; if a Hermes upgrade moved them, telem_fetch refuses everything by design rather than fetching unscreened. The refusal message names the cause; telem_search is unaffected.

Searches fail with a version error. The plugin requires the router’s normalized response and rejects an older one rather than rendering something misleading.

  • The built-in web_search and web_extract tools are left registered. This plugin adds tools; it does not replace Hermes’s own.
  • Telem is not registered as a Hermes WebSearchProvider. That interface takes one query at a time with no goal and no provider attribution, which would drop most of what these tools return.