Skip to content

feat(skills): /reload-skills slash command + skills_reload agent tool#17670

Closed
shannonsands wants to merge 1 commit into
NousResearch:mainfrom
shannonsands:feat/reload-skills
Closed

feat(skills): /reload-skills slash command + skills_reload agent tool#17670
shannonsands wants to merge 1 commit into
NousResearch:mainfrom
shannonsands:feat/reload-skills

Conversation

@shannonsands

Copy link
Copy Markdown
Contributor

What does this PR do?

Note: Split out from #17255. That PR's branch had an unrelated WIP commit
(Add OpenShell sandbox provider) tangled in from a prior session, so the
actual diff (31 files, +3860/-24) didn't match the body (10 files, +682/-4).
This PR is the surgical version: just the reload-skills commit cherry-picked
onto fresh main. Verified byte-identical via git range-diff (=).
The OpenShell sandbox provider work continues to live on
shannonsands:feat/reload-skills-command for the local-testing branch and
will get its own PR later.

Adds a public reload path for the in-process skill caches so newly installed
(or removed) skills become visible mid-session without a gateway restart.
The existing internal API
agent.prompt_builder.clear_skills_system_prompt_cache(clear_snapshot=True)
is now exposed across three surfaces:

  1. /reload-skills slash command — works in the CLI (cli.py) and the
    gateway (gateway/run.py), mirroring the shape of /reload-mcp. Includes
    /reload_skills alias for Telegram autocomplete and an explicit Discord
    registration.
  2. skills_reload agent tool — exposed in the skills toolset alongside
    skills_list / skill_view / skill_manage so an agent/subagent can
    rescan after dropping a new skill via the shell or skills_hub.
  3. agent.skill_commands.reload_skills() — shared helper used by all
    three callers.

The helper clears every in-process skill cache:

  • agent.skill_commands._skill_commands (slash-command map)
  • agent.prompt_builder._SKILLS_PROMPT_CACHE (in-process LRU)
  • ~/.hermes/.skills_prompt_snapshot.json (cross-process snapshot)

…and returns a structured diff:

{
    "added":      ["new-skill"],   # bare names, no leading slash
    "removed":    [],
    "unchanged":  ["..."],
    "total":      37,              # post-rescan skill count
    "commands":   37,              # /slash-skill count
}

When the diff is non-empty, both the CLI and gateway append a short
[IMPORTANT: Skills have been reloaded …] note to the end of the
conversation history so the model sees the change on its next turn (same
pattern /reload-mcp uses).

Related Issue

Aligns with #15626 (plugin reload — same shape, different subsystem) and
addresses the runtime cache-staleness called out in #14535 / #14536. No
specific skill-reload issue exists yet; happy to file one and link, or fold
it under one of the above if a maintainer prefers.

Type of Change

  • ✨ New feature (non-breaking change that adds functionality)

Changes Made

File Change
agent/skill_commands.py New reload_skills() helper
tools/skills_tool.py New skills_reload agent tool + SKILLS_RELOAD_SCHEMA
cli.py New _reload_skills method + /reload-skills dispatch
gateway/run.py New _handle_reload_skills_command + dispatcher entry
gateway/platforms/discord.py Discord slash command registration
hermes_cli/commands.py CommandDef("reload-skills", …)
toolsets.py Added skills_reload to the skills toolset (4 enumerations)
tests/agent/test_skill_commands_reload.py 9 cases — helper + tool registration
tests/cli/test_cli_reload_skills.py 3 cases — CLI handler
tests/gateway/test_reload_skills_command.py 4 cases — gateway handler + dispatcher

Total: +682 / -4 across 10 files.

How to Test

Manual

# 1. Start a hermes chat session
hermes chat

# 2. In another terminal, drop a new skill into ~/.hermes/skills/
mkdir -p ~/.hermes/skills/mid-session-demo
cat > ~/.hermes/skills/mid-session-demo/SKILL.md <<'SKILL'
---
name: mid-session-demo
description: a skill installed during a session
---
body
SKILL

# 3. Back in the chat, run:
/reload-skills

# Expected output:
#   🔄 Reloading skills...
#     ➕ Added: mid-session-demo
#     📚 N skill(s) available
#     ✅ Skill cache cleared

The same flow works inside the gateway (Telegram, Discord, Slack, etc.). For
agentic flows, the model can call the new skills_reload tool directly after
installing a skill.

Automated

pytest tests/agent/test_skill_commands_reload.py \
       tests/cli/test_cli_reload_skills.py \
       tests/gateway/test_reload_skills_command.py -q
# 16 passed

Surrounding regressions (skills tooling, prompt builder, command registry,
gateway slash dispatch) all green:

pytest tests/agent/test_skill_commands_reload.py \
       tests/agent/test_skill_commands.py \
       tests/agent/test_prompt_builder.py \
       tests/cli/test_cli_reload_skills.py \
       tests/gateway/test_reload_skills_command.py \
       tests/tools/test_skills_tool.py \
       tests/skills/ \
       tests/hermes_cli/test_commands.py \
       tests/gateway/test_unknown_command.py -q
# 527 passed, 1 skipped

Checklist

Code

  • I've read the Contributing Guide
  • Commit follows Conventional Commits
  • No duplicate PRs (feat(skills): /reload-skills slash command + skills_reload agent tool #17255 will be closed in favour of this one)
  • PR contains only related changes
  • I've run pytest tests/ -q for the touched areas — green (527 passed across surrounding files)
  • I've added tests for my changes (16 new cases)
  • Tested on my platform: macOS 15 Apple Silicon, Python 3.13.3

Documentation & Housekeeping

  • Updated relevant documentation — N/A (slash command is auto-listed in /help via the existing CommandDef registry)
  • Updated cli-config.yaml.example if config keys changed — N/A
  • Updated CONTRIBUTING.md or AGENTS.md if architecture changed — N/A
  • Considered cross-platform impact — works the same on Linux/macOS/Windows; Telegram alias and Discord registration covered
  • Updated tool descriptions/schemas if tool behavior changed — skills_reload schema added; existing tools unchanged

Background — why this matters

We're integrating Hermes into a sandboxed orchestrator (NemoClaw-style). When
the orchestrator drops a freshly-installed skill into ~/.hermes/skills/
mid-session, Hermes can't see it until restart. The internal
clear_skills_system_prompt_cache(clear_snapshot=True) already does the
right thing — this PR just wires it to a slash command (so users can invoke
it) and an agent tool (so agents that just installed a skill via shell can
pick it up themselves, closing the agentic-install catch-22 also raised in
#15626).

Adds a public reload path for the in-process skill caches so newly
installed (or removed) skills become visible mid-session without a
gateway restart. Mirrors the shape of /reload-mcp.

Three surfaces:
* /reload-skills slash command — CLI (cli.py) and gateway (gateway/run.py),
  with /reload_skills alias for Telegram autocomplete and an explicit
  Discord registration.
* skills_reload agent tool (tools/skills_tool.py) — lets agents/subagents
  pick up freshly-installed skills via tool call.
* agent.skill_commands.reload_skills() — shared helper that clears
  _skill_commands, _SKILLS_PROMPT_CACHE (in-process LRU), and the
  on-disk .skills_prompt_snapshot.json, then returns an added/removed
  diff plus the new total count.

Tested:
* tests/agent/test_skill_commands_reload.py (9 cases)
* tests/cli/test_cli_reload_skills.py       (3 cases)
* tests/gateway/test_reload_skills_command.py (4 cases)

Use case: NemoClaw / OpenShell-style sandboxed orchestrators that drop
skills into ~/.hermes/skills mid-session, plus agentic flows where the
agent itself installs a skill via the shell tool and needs it bound
without a gateway restart. The Python helper
clear_skills_system_prompt_cache(clear_snapshot=True) already exists
internally — this PR just exposes it via slash command and tool.
@alt-glitch alt-glitch added type/feature New feature or request comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery tool/skills Skills system (list, view, manage) platform/discord Discord bot adapter P3 Low — cosmetic, nice to have labels Apr 30, 2026
@teknium1

Copy link
Copy Markdown
Contributor

Merged via #17744#17744

Your commit was cherry-picked onto current main with your authorship preserved (commit 7966560, still authored by @shannonsands). A follow-up commit (dd2d1ba) refactored the feature to match the design Teknium wanted:

  • No prompt-cache invalidation — skills don't need to live in the system prompt for the model to use them (they're invoked at runtime via /skill-name, skills_list, or skill_view). Keeping the cache intact preserves prefix caching across the reload. (MCP has to break the cache because tool schemas must be known at conversation start; skills do not.)
  • Dropped the skills_reload agent tool, schema, and four toolset enumerations — the model doesn't need a new schema entry to see a just-installed skill.
  • Replaced the phantom role: user transcript write with a one-shot queued note (CLI: _pending_skills_reload_note, gateway: _pending_skills_reload_notes[session_key]) that's prepended to the NEXT real user message and then cleared. Message alternation stays intact and nothing out-of-band persists to the session transcript.
  • Diff now carries full frontmatter descriptions formatted - name: description (same shape the system prompt uses for pre-existing skills) so the model reads added/removed skills in the familiar catalog format.

Thanks for the clean split-out PR and the detailed implementation — made the salvage straightforward.

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

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have platform/discord Discord bot adapter tool/skills Skills system (list, view, manage) type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants