hermes - 💡(How to fix) Fix _get_platform_tools silently drops composite toolset (e.g. hermes-cli) when saved list mixes composite + configurable — entire native toolset disappears

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Error Message

  • Log a WARN at agent init when enabled_toolsets resolves to fewer toolsets than the requested composite would have produced — would have caught this in seconds.

Root Cause

hermes_cli/tools_config.py (current origin/main):

# 962-968
has_explicit_config = any(ts in configurable_keys for ts in toolset_names)

if has_explicit_config:
    enabled_toolsets = {
        ts for ts in toolset_names
        if ts in configurable_keys and _toolset_allowed_for_platform(ts, platform)
    }
else:
    # ... composite expansion via subset inference ...

hermes-cli is not in CONFIGURABLE_TOOLSETS, so it never makes it into enabled_toolsets in the explicit branch. The plugin-recovery loop (lines 1042-1055) re-adds spotify, but nothing in this function ever expands the composite. Result: 2 toolsets instead of 19.

Fix Action

Workaround

Remove the configurable toolset from platform_toolsets[<platform>] so the list is composite-only — falls into the else branch and resolves correctly. (i.e. drop spotify and lose the integration until upstream is fixed.)

Code Example

import yaml, copy
from hermes_cli import plugins as p; p.discover_plugins()
from hermes_cli.tools_config import _get_platform_tools

cfg = yaml.safe_load(open('~/.hermes/config.yaml').read())  # contains [hermes-cli, spotify]

# Bug: composite is dropped
print(sorted(_get_platform_tools(cfg, 'cli', include_default_mcp_servers=False)))
# → ['kanban', 'spotify']        (n=2, terminal absent)

cfg2 = copy.deepcopy(cfg)
cfg2['platform_toolsets']['cli'] = ['hermes-cli']
print(sorted(_get_platform_tools(cfg2, 'cli', include_default_mcp_servers=False)))
# → ['browser','clarify','code_execution','computer_use','cronjob','delegation',
#    'file','image_gen','kanban','memory','messaging','session_search','skills',
#    'terminal','todo','tts','vision','web']      (n=18, correct)

---

# 962-968
has_explicit_config = any(ts in configurable_keys for ts in toolset_names)

if has_explicit_config:
    enabled_toolsets = {
        ts for ts in toolset_names
        if ts in configurable_keys and _toolset_allowed_for_platform(ts, platform)
    }
else:
    # ... composite expansion via subset inference ...

---

if has_explicit_config:
    enabled_toolsets = {
        ts for ts in toolset_names
        if ts in configurable_keys and _toolset_allowed_for_platform(ts, platform)
    }
    composite_names = [
        ts for ts in toolset_names
        if ts not in configurable_keys
        and ts not in plugin_ts_keys
        and ts in TOOLSETS
    ]
    if composite_names:
        composite_tools = set()
        for ts_name in composite_names:
            composite_tools.update(resolve_toolset(ts_name))
        for ts_key, _, _ in CONFIGURABLE_TOOLSETS:
            if not _toolset_allowed_for_platform(ts_key, platform):
                continue
            ts_tools = set(resolve_toolset(ts_key))
            if ts_tools and ts_tools.issubset(composite_tools):
                enabled_toolsets.add(ts_key)
        # _DEFAULT_OFF_TOOLSETS subtraction here, preserving any keys the
        # user explicitly listed (so `[hermes-cli, spotify]` keeps spotify).
RAW_BUFFERClick to expand / collapse

Bug Description

_get_platform_tools() in hermes_cli/tools_config.py silently discards the platform's composite toolset (e.g. hermes-cli, hermes-telegram) whenever the saved platform_toolsets[<platform>] list contains both the composite and at least one configurable toolset (e.g. spotify, terminal, file, messaging).

The result: an interactive session loses every native tool — terminal, file ops, web, browser, vision, todo, skills, delegation, cronjob, memory, etc. The model is left with only the explicit configurable(s) plus MCP/plugin tools. From the user's perspective the assistant abruptly "loses" its tools after enabling a single optional integration like Spotify via hermes tools.

This is a regression introduced by #2624 / commit 868b3c07e ("fix: platform default toolsets silently override tool deselection in hermes tools"). That commit added the has_explicit_config direct-membership branch to fix one bug, but the new branch never expands composite toolset names that sit alongside the configurable keys — it just drops them on the floor.

Likely the same root cause as #22573 (different trigger path: Docker config v22→v23 migration there, hermes tools enable spotify here).

Steps to Reproduce

  1. Install Hermes (current origin/main, f6d45e5df reproduces).
  2. Configure a CLI profile with the composite toolset only — platform_toolsets.cli: [hermes-cli]. Confirm an interactive session sees the full ~18 native toolsets (terminal, file, web, browser, etc.).
  3. Enable any single configurable toolset for the same platform — e.g. hermes tools → toggle on Spotify, or hand-edit to platform_toolsets.cli: [hermes-cli, spotify].
  4. Restart the gateway and start a new CLI session.
  5. Inspect the session's tools list.

Expected Behavior

Session should expose the full hermes-cli core toolset (terminal, file, web, browser, vision, todo, skills, delegation, cronjob, memory, session_search, clarify, code_execution, image_gen, tts, computer_use, messaging, kanban) plus the newly-enabled spotify — i.e. ~19 toolsets, including terminal.

Actual Behavior

Session exposes only {spotify, kanban} — every native tool from hermes-cli is gone. The model genuinely cannot run terminal, read_file, delegate_task, etc. and reports back to the user that it has no shell access, while the user reasonably expects nothing to have changed except adding Spotify.

Minimal Repro (live config + standalone trace)

import yaml, copy
from hermes_cli import plugins as p; p.discover_plugins()
from hermes_cli.tools_config import _get_platform_tools

cfg = yaml.safe_load(open('~/.hermes/config.yaml').read())  # contains [hermes-cli, spotify]

# Bug: composite is dropped
print(sorted(_get_platform_tools(cfg, 'cli', include_default_mcp_servers=False)))
# → ['kanban', 'spotify']        (n=2, terminal absent)

cfg2 = copy.deepcopy(cfg)
cfg2['platform_toolsets']['cli'] = ['hermes-cli']
print(sorted(_get_platform_tools(cfg2, 'cli', include_default_mcp_servers=False)))
# → ['browser','clarify','code_execution','computer_use','cronjob','delegation',
#    'file','image_gen','kanban','memory','messaging','session_search','skills',
#    'terminal','todo','tts','vision','web']      (n=18, correct)

Root Cause

hermes_cli/tools_config.py (current origin/main):

# 962-968
has_explicit_config = any(ts in configurable_keys for ts in toolset_names)

if has_explicit_config:
    enabled_toolsets = {
        ts for ts in toolset_names
        if ts in configurable_keys and _toolset_allowed_for_platform(ts, platform)
    }
else:
    # ... composite expansion via subset inference ...

hermes-cli is not in CONFIGURABLE_TOOLSETS, so it never makes it into enabled_toolsets in the explicit branch. The plugin-recovery loop (lines 1042-1055) re-adds spotify, but nothing in this function ever expands the composite. Result: 2 toolsets instead of 19.

Proposed Fix

In the has_explicit_config branch, also expand any composite toolset names present in toolset_names and reverse-map to configurable keys (mirroring the else branch). Tested against my live config — produces the correct 19-toolset result. Sketch:

if has_explicit_config:
    enabled_toolsets = {
        ts for ts in toolset_names
        if ts in configurable_keys and _toolset_allowed_for_platform(ts, platform)
    }
    composite_names = [
        ts for ts in toolset_names
        if ts not in configurable_keys
        and ts not in plugin_ts_keys
        and ts in TOOLSETS
    ]
    if composite_names:
        composite_tools = set()
        for ts_name in composite_names:
            composite_tools.update(resolve_toolset(ts_name))
        for ts_key, _, _ in CONFIGURABLE_TOOLSETS:
            if not _toolset_allowed_for_platform(ts_key, platform):
                continue
            ts_tools = set(resolve_toolset(ts_key))
            if ts_tools and ts_tools.issubset(composite_tools):
                enabled_toolsets.add(ts_key)
        # _DEFAULT_OFF_TOOLSETS subtraction here, preserving any keys the
        # user explicitly listed (so `[hermes-cli, spotify]` keeps spotify).

Workaround

Remove the configurable toolset from platform_toolsets[<platform>] so the list is composite-only — falls into the else branch and resolves correctly. (i.e. drop spotify and lose the integration until upstream is fixed.)

Affected Component

Tools (toolset resolution, _get_platform_tools)

Defensive Suggestions

  • Log a WARN at agent init when enabled_toolsets resolves to fewer toolsets than the requested composite would have produced — would have caught this in seconds.
  • Surface tool count on /model switch confirmation (e.g. "Switched to gpt-5.5 — 19 tools active") so a silent drop is visible.

Related

  • #22573 — same symptom (native tools missing, only MCP/plugin tools load), different trigger (Docker config v22→v23 migration).
  • #5991 (closed) — earlier regression of the same _get_platform_tools collapse, fixed by adding messaging to CONFIGURABLE_TOOLSETS. The fix in #2624 (868b3c07e) introduced the new branch this issue describes.

Hermes Version

origin/main f6d45e5df (2026-05-09); reproduced on local checkout at 242da9db9 (2026-05-08).

Operating System

Debian bookworm aarch64 (Raspberry Pi 5).

Python Version

3.11 (whichever ships in ~/.hermes/hermes-agent/.venv).

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix _get_platform_tools silently drops composite toolset (e.g. hermes-cli) when saved list mixes composite + configurable — entire native toolset disappears