Skip to content

skills.create_dir skills are advertised in the prompt but skill_view / skills_list / slash commands can't find them #108157

Closed

Description

@neo-wanderer

Bug Description

With skills.create_dir configured (added in #100377), skills in that directory are advertised in the system-prompt skill index but cannot be loaded or listed:

  • skill_view(name) returns Skill '<name>' not found.
  • skills_list omits them
  • no /<skill-name> slash command is registered, and they are missing from the Telegram / Discord skill menus

skill_manage can create and patch them fine. So the agent creates a skill with skill_manage, sees it offered in its prompt on the next turn, then fails to load it.

Steps to Reproduce

This runs against a fresh synthetic HERMES_HOME. No gateway or provider is needed.

# repro_create_dir.py — usage: python repro_create_dir.py <hermes-agent checkout>
import json, os, sys, tempfile
from pathlib import Path

repo = Path(sys.argv[1]).resolve()
sys.path.insert(0, str(repo))
root = Path(tempfile.mkdtemp())
home = root / ".hermes"
(home / "skills").mkdir(parents=True)
brain = root / "brain-skills"
(home / "config.yaml").write_text(f"skills:\n  create_dir: {brain}\n")
os.environ["HERMES_HOME"] = str(home)

import tools.skills_tool as st
from tools.skill_manager_tool import skill_manage
from agent.prompt_builder import build_skills_system_prompt

created = json.loads(skill_manage("create", "demo-skill", content=(
    "---\nname: demo-skill\n"
    "description: Use when demonstrating the create_dir lookup gap.\n"
    "---\n\n# demo-skill\n\nBody.\n")))
print("skill_manage create :", created.get("success"), created.get("path"))
print("in prompt index     :", "demo-skill" in build_skills_system_prompt())
print("skills_list names   :", [s["name"] for s in json.loads(st.skills_list())["skills"]])
view = json.loads(st.skill_view("demo-skill"))
print("skill_view          :", "ok" if view.get("success") else view.get("error"))

Expected Behavior

Any skill the prompt index advertises can be loaded with skill_view, shows up in skills_list, and gets a slash command. In other words, every discovery surface scans the same directories.

Actual Behavior

On main @ 8c74118c4a:

skill_manage create : True /tmp/tmp2g9yr61c/brain-skills/demo-skill
in prompt index     : True
skills_list names   : []
skill_view          : Skill 'demo-skill' not found.

Affected Component

Tools (skill_view, skills_list), slash-command registration, gateway skill menus (Telegram / Discord).

Debug Report

N/A. Reproduced with the standalone script above on a fresh synthetic HERMES_HOME, with no gateway, provider or session involved.

Operating System

Linux (Ubuntu, kernel 6.8)

Python Version

3.12.3

Hermes Version

main @ 8c74118c4a. Also reproduced on the v0.21.1 docker image.

Root Cause Analysis

agent/skill_utils.py::get_all_skills_dirs() returns local → create_dir → external_dirs. Some callers use it; others build the list by hand as local + get_external_skills_dirs(), which leaves create_dir out:

Call site Directory list Sees create_dir?
agent/prompt_builder.py::build_skills_system_prompt get_all_skills_dirs()[1:] ✅
tools/skill_manager_tool.py::_find_skill (patch/edit) get_all_skills_dirs() ✅
tools/skill_manager_tool.py::_resolve_skill_dir (create) get_skill_create_dir() ✅
tools/skills_tool.py::_skill_search_dirs (skill_view, skills_list) local + get_external_skills_dirs() ❌
tools/skills_tool.py::_get_category_from_path local + get_external_skills_dirs() ❌
agent/skill_commands.py::scan_skill_commands local + get_external_skills_dirs() ❌
hermes_cli/commands_platforms.py::_iter_gateway_skills local + get_external_skills_dirs() ❌

The tests added in #100377 check get_all_skills_dirs() and _find_skill but no read path, which is how the gap got past review.

The obvious workaround has a trap. Adding the create_dir path to skills.external_dirs as well makes skill_view find the skills, but is_external_skill_path() then treats that directory as externally owned:

So the fix belongs in the read paths, not in config.

Proposed Fix

Switch the four ❌ sites to get_all_skills_dirs()[1:], the same form prompt_builder and skill_usage already use. get_all_skills_dirs() already removes duplicates between create_dir and external_dirs, and _collect_skill_candidates removes duplicates by resolved path, so a directory listed under both keys stays unambiguous. A PR with regression tests follows.

Out of scope, noted for follow-up:

  • tools/credential_files.py::_skill_dir_roots (the remote-sandbox skill sync) also enumerates local + external + project dirs without create_dir. So a create_dir skill's bundled files look like they are not synced to remote terminal backends. It uses a different mount layout, so I left it out; not verified end to end.
  • hermes_cli/commands.py still holds legacy copies of _collect_gateway_skill_entries / discord_skill_commands with the same pattern. No live caller uses them (the compat map points at commands_platforms), and they are scheduled for removal on 2026-09-14.

Are you willing to submit a PR for this?

  • I'd like to fix this myself and submit a PR

Activity

  1. added
    type/bugSomething isn't working
    P2Medium — degraded but workaround exists
    tool/skillsSkills system (list, view, manage)
    comp/agentCore agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint
    area/configConfig system, migrations, profiles
    on Sep 11, 2026
  2. Enough1122 commented on Sep 27, 2026

    @Enough1122

    Ran your script on main (b4410b4) verbatim; it reproduces unchanged - create reports True, the
    prompt index contains the skill, skills_list returns [], skill_view returns "not found". The
    cause is a one-line divergence between two dir resolvers: the prompt builder goes through
    agent/skill_utils.py:418-426 (get_all_skills_dirs), which appends create_dir, while the tool
    layer does not - tools/skills_tool.py:173-181 (_skill_search_dirs) composes project_dirs +
    [active_skills_dir] + get_external_skills_dirs, and agent/skill_utils.py:357-382
    (get_external_skills_dirs) reads only skills.external_dirs, never calling
    get_skill_create_dir. With create_dir set the two disagree - the first returns both dirs, the
    second [] - and since skills_list (:234-238) and skill_view (:593-596) both route through
    _skill_search_dirs, the slash commands and gateway skill menus inherit the gap. The fix wants
    get_external_skills_dirs to include get_skill_create_dir() on the read side, so every discovery
    surface scans what the prompt index already advertises.

  3. Or-well commented on Oct 1, 2026

    @Or-well

    Independent reproduction on a live instance, plus a workaround that restores every read surface

    Environment: release v0.21.5+5014.gaf92ea8 (install af92ea8e5b). Re-checked on main (e8c97320ac, 2026-10-01): tools/skills_tool.py::_skill_search_dirs still composes project + local + get_external_skills_dirs(), and agent/skill_utils.py::get_external_skills_dirs still reads only skills.external_dirs (no get_skill_create_dir) — so the divergence is unchanged on main, while the docs still promise the integrated behaviour (website/docs/user-guide/features/skills.md L474: "The directory is fully integrated. Skills under create_dir … appear in the skill index, skills_list, skill_view, slash commands").

    Reproduction on a real profile, not a synthetic HERMES_HOME: 90 user-authored skills live under skills.create_dir: ~/.hermes/skills-local, and skills.external_dirs did not list that directory.

    surface result with create_dir only
    system-prompt skill index (agent/prompt_builder.py) ✅ advertised
    agent skills_list(category="autonomous-ai-agents") (tools/skills_tool.py:234) ❌ only the 2 builtin skills of that category remain
    agent skill_view("<moved-skill>") (tools/skills_tool.py:593) ❌ Skill '<name>' not found.
    hermes skills list CLI (hermes_cli/skills_hub.py::do_list) ❌ 157 skills → 67 (table rows 158 → 68)
    skill_manage create / patch / delete (tools/skill_manager_tool.py) ✅ still writes into create_dir (verified with a throwaway skill)

    That is exactly the "created → advertised → unloadable" state reported here: the agent sees the skill in its prompt index and then cannot load it.

    Workaround until the fix lands — keep create_dir for writes and additionally list the same path in skills.external_dirs:

    skills:
      create_dir: ~/.hermes/skills-local      # new skills are written here
      external_dirs:
        - ~/.hermes/skills-local              # discovery/read path

    With both keys pointing at the same directory every read surface recovers: hermes skills list becomes byte-identical to the pre-move state (157 = 30 builtin + 24 official + 90 user-authored + 13 shared), skills_list and skill_view resolve, and skill_manage still creates into create_dir. The duplicated entry is harmless — get_all_skills_dirs() already dedupes, and #108160 keeps that dedupe covered by a regression test.

    Re #108160: that PR addresses precisely this divergence (moving the read call sites to get_all_skills_dirs()[1:]). It has been open since 2026-09-11 with no review or checks; I'm happy to verify a rebase against current main on a live instance (90 skills under create_dir, all surfaces re-checked) if that helps move it forward.

  4. neo-wanderer commented on Oct 4, 2026

    @neo-wanderer
    Author

    Fixed on main by #132464 — f525ecd (skill_view / skills_list) and 340be37 (slash commands). The repro above passes from 340be37 onward. Closing; #108160 is closed as superseded.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existsarea/configConfig system, migrations, profilescomp/agentCore agent runtime: loop, agent_init, prompt builder, context-compression, responses endpointtool/skillsSkills system (list, view, manage)type/bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions