# NousResearch/hermes-agent · Platform-disabled skills appearing in <available_skills> prompt

## Open now

- Nothing open on GitHub.

All four members concern disabled skills still showing up in the <available_skills> prompt; one is a bug report that also mentions false loads, and three reference #46201 with proposed fixes. One of them also mentions unifying resolution sites. Their status is not established here.

## TL;DR

- 4 member(s): 0 open issue(s), 1 closed issue(s), 0 open PR(s), 1 merged PR(s), 2 PR(s) closed without merging.
- A fix was merged to main in PR #46236. Verify it addresses your case.
- **Recommended:** read PR #46236 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `resolved` · deciding PR(s): `pr-46236`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_SPANNING`): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
- Pairwise link density `0.50`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Closed / duplicate issues

- #46201: \[Bug\]: Disabled skills still appear in <available_skills> prompt and trigger false loads

## Prior & competing PRs

- **#46236: fix(skills): platform-disabled skills still appear in <available_skills> + unify all resolution sites (#46201)**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `agent/prompt_builder.py`, `agent/skill_utils.py`, `hermes_cli/skills_config.py`, `tests/hermes_cli/test_skills_config.py`, `tools/skills_tool.py`
  - fix hunks:
  - `agent/prompt_builder.py`

    ```diff
    @@ -1164,7 +1164,7 @@ def build_skills_system_prompt(
             or get_session_env("HERMES_SESSION_PLATFORM")
             or ""
         )
    -    disabled = get_disabled_skill_names()
    +    disabled = get_disabled_skill_names(_platform_hint or None)
         cache_key = (
             str(skills_dir.resolve()),
             tuple(str(d) for d in external_dirs),
    ```
  - `agent/skill_utils.py`

    ```diff
    @@ -278,8 +278,10 @@ def get_disabled_skill_names(platform: str | None = None) -> Set[str]:
         Args:
             platform: Explicit platform name (e.g. ``"telegram"``).  When
                 *None*, resolves from ``HERMES_PLATFORM`` or
    -            ``HERMES_SESSION_PLATFORM`` env vars.  Falls back to the
    -            global disabled list when no platform is determined.
    +            ``HERMES_SESSION_PLATFORM`` env vars.  Returns the global
    +            disabled list, unioned with the platform-specific list when a
    +            platform is resolved (a globally-disabled skill stays disabled
    +            on every platform).
     
         Reads the config file directly (no CLI config imports) to stay
         lightweight.
    ```

    ```diff
    @@ -305,13 +307,14 @@ def get_disabled_skill_names(platform: str | None = None) -> Set[str]:
             or os.getenv("HERMES_PLATFORM")
             or get_session_env("HERMES_SESSION_PLATFORM")
         )
    +    global_disabled = _normalize_string_set(skills_cfg.get("disabled"))
         if resolved_platform:
             platform_disabled = (skills_cfg.get("platform_disabled") or {}).get(
                 resolved_platform
             )
             if platform_disabled is not None:
    -            return _normalize_string_set(platform_disabled)
    -    return _normalize_string_set(skills_cfg.get("disabled"))
    +            return global_disabled | _normalize_string_set(platform_disabled)
    +    return global_disabled
     
     
     def _normalize_string_set(values) -> Set[str]:
    ```
  - `hermes_cli/skills_config.py`

    ```diff
    @@ -25,7 +25,13 @@
     # ─── Config Helpers ───────────────────────────────────────────────────────────
     
     def get_disabled_skills(config: dict, platform: Optional[str] = None) -> Set[str]:
    -    """Return disabled skill names. Platform-specific list falls back to global."""
    +    """Return disabled skill names: the global list unioned with the
    +    platform-specific list when a platform is given.
    +
    +    A globally-disabled skill stays disabled on every platform, so the
    +    platform list adds to the global list rather than replacing it. This
    +    mirrors ``agent.skill_utils.get_disabled_skill_names``.
    +    """
         skills_cfg = config.get("skills", {})
         global_disabled = set(skills_cfg.get("disabled", []))
         if platform is None:
    ```

    ```diff
    @@ -33,7 +39,7 @@ def get_disabled_skills(config: dict, platform: Optional[str] = None) -> Set[str
         platform_disabled = cfg_get(skills_cfg, "platform_disabled", platform)
         if platform_disabled is None:
             return global_disabled
    -    return set(platform_disabled)
    +    return global_disabled | set(platform_disabled)
     
     
     def save_disabled_skills(config: dict, disabled: Set[str], platform: Optional[str] = None):
    ```
  - `tests/hermes_cli/test_skills_config.py`

    ```diff
    @@ -22,7 +22,19 @@ def test_reads_platform_disabled(self):
                 "disabled": ["skill-a"],
                 "platform_disabled": {"telegram": ["skill-b"]}
             }}
    -        assert get_disabled_skills(config, platform="telegram") == {"skill-b"}
    +        # Union of global + platform: a globally-disabled skill stays disabled
    +        # on every platform, and the platform list adds to it.
    +        assert get_disabled_skills(config, platform="telegram") == {"skill-a", "skill-b"}
    +
    +    def test_platform_list_unions_with_global(self):
    +        from hermes_cli.skills_config import get_disabled_skills
    +        config = {"skills": {
    +            "disabled": ["global-skill"],
    +            "platform_disabled": {"telegram": []}
    +        }}
    +        # An explicit empty platform list does NOT re-enable a globally-disabled
    +        # skill (matches issue #46201 — global disables hold everywhere).
    +        assert get_disabled_skills(config, platform="telegram") == {"global-skill"}
     
         def test_platform_falls_back_to_global(self):
             from hermes_cli.skills_config import get_disabled_skills
    ```

    ```diff
    @@ -102,14 +114,27 @@ def test_platform_disabled(self, mock_load):
             assert _is_skill_disabled("tg-skill", platform="telegram") is True
     
         @patch("hermes_cli.config.load_config")
    -    def test_platform_enabled_overrides_global(self, mock_load):
    +    def test_globally_disabled_stays_disabled_on_platform(self, mock_load):
    +        mock_load.return_value = {"skills": {
    +            "disabled": ["skill-a"],
    +            "platform_disabled": {"telegram": ["tg-skill"]}
    +        }}
    +        from tools.skills_tool import _is_skill_disabled
    +        # Union: a globally-disabled skill stays disabled on a platform that
    +        # has its own platform_disabled list (matches issue #46201).
    +        assert _is_skill_disabled("skill-a", platform="telegram") is True
    +        assert _is_skill_disabled("tg-skill", platform="telegram") is True
    +
    +    @patch("hermes_cli.config.load_config")
    +    def test_empty_platform_list_keeps_global_disabled(self, mock_load):
             mock_load.return_value = {"skills": {
                 "disabled": ["skill-a"],
                 "platform_disabled": {"telegram": []}
             }}
             from tools.skills_tool import _is_skill_disabled
    -        # telegram has explicit empty list -> skill-a is NOT disabled for telegram
    -        assert _is_skill_disabled("skill-a", platform="telegram") is False
    +        # An explicit empty platform list does NOT re-enable a globally-disabled
    +        # skill — global disables hold on every platform.
    +        assert _is_skill_disabled("skill-a", platform="telegram") is True
     
         @patch("hermes_cli.config.load_config")
         def test_platform_falls_back_to_global(self, mock_load):
    ```

    ```diff
    @@ -164,7 +189,7 @@ def test_explicit_platform_param(self, tmp_path, monkeypatch):
     
             from agent.skill_utils import get_disabled_skill_names
             result = get_disabled_skill_names(platform="telegram")
    -        assert result == {"tg-only-skill"}
    +        assert result == {"tg-only-skill", "global-skill"}
     
         def test_session_platform_env_var(self, tmp_path, monkeypatch):
             """HERMES_SESSION_PLATFORM should be used when HERMES_PLATFORM is unset."""
    ```

    ```diff
    @@ -183,7 +208,7 @@ def test_session_platform_env_var(self, tmp_path, monkeypatch):
     
             from agent.skill_utils import get_disabled_skill_names
             result = get_disabled_skill_names()
    -        assert result == {"discord-skill"}
    +        assert result == {"discord-skill", "global-skill"}
     
         def test_hermes_platform_takes_precedence(self, tmp_path, monkeypatch):
             """HERMES_PLATFORM should win over HERMES_SESSION_PLATFORM."""
    ```
  - `tools/skills_tool.py`

    ```diff
    @@ -583,11 +583,15 @@ def _is_skill_disabled(name: str, platform: str = None) -> bool:
             config = load_config()
             skills_cfg = config.get("skills", {})
             resolved_platform = platform or os.getenv("HERMES_PLATFORM") or _get_session_platform()
    +        global_disabled = skills_cfg.get("disabled", [])
             if resolved_platform:
                 platform_disabled = cfg_get(skills_cfg, "platform_disabled", resolved_platform)
                 if platform_disabled is not None:
    -                return name in platform_disabled
    -        return name in skills_cfg.get("disabled", [])
    +                # A globally-disabled skill stays disabled on every platform;
    +                # the platform list adds to it rather than replacing it. Keep
    +                # in sync with agent.skill_utils.get_disabled_skill_names.
    +                return name in platform_disabled or name in global_disabled
    +        return name in global_disabled
         except Exception:
             return False
     
    ```
- **#46203: fix: platform-disabled skills still appear in <available_skills> prompt (#46201)**. closed without merge
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `7bbe7024c207a6dad982967780995ad18ac7e7be`, `#46201`, `#46236`
- **#46220: fix(skills): filter platform-disabled skills from prompt (#46201)**. closed without merge
  - maintainer direction: category `implemented_elsewhere`; implication `superseded`; refs `7bbe7024c207a6dad982967780995ad18ac7e7be`, `ce19fdb7ce27d94462a650ade8a2b94882590a38`, `#46236`

## Fix status

- Merged to main in PR #46236 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-06-14`.
- Subsystem: `skills`
