diff --git a/skills/autonomous-ai-agents/hermes-agent/SKILL.md b/skills/autonomous-ai-agents/hermes-agent/SKILL.md index 42edf68cc4..7b4565825f 100644 --- a/skills/autonomous-ai-agents/hermes-agent/SKILL.md +++ b/skills/autonomous-ai-agents/hermes-agent/SKILL.md @@ -1,13 +1,13 @@ --- name: hermes-agent description: "Use, configure, theme, extend, and orchestrate Hermes Agent." -version: 3.1.0 +version: 3.2.0 author: Hermes Agent + Teknium license: MIT platforms: [linux, macos, windows] metadata: hermes: - tags: [hermes, setup, configuration, multi-agent, spawning, cli, gateway, themes, skins, desktop-plugins, tui-widgets, petdex, development] + tags: [hermes, setup, configuration, multi-agent, spawning, cli, gateway, bots, bot-mode, features, themes, skins, desktop-plugins, tui-widgets, petdex, development] homepage: https://github.com/NousResearch/hermes-agent related_skills: [claude-code, codex, opencode] --- @@ -34,12 +34,14 @@ What makes Hermes different: This skill is a concise operating guide, not the complete source of truth for every Hermes feature. If a Hermes feature, command, or setting is not mentioned here or in a reference, do not treat that absence as evidence that it does not exist. Check the live repository and official docs before giving a negative answer. -Good verification targets: +Good verification targets, cheapest first: +- **Every shipped feature, one line each: https://hermes-agent.nousresearch.com/docs/llms.txt.** Start here for any "can Hermes do X?" or "how do I do X?" — it indexes the entire documentation set with a link to the page that answers. It is generated from the docs tree on every build, so it is never behind the product. Fetch it with `web_extract`, or `curl -s https://hermes-agent.nousresearch.com/docs/llms.txt` when web tools are off. The whole documentation set in one file is at `/docs/llms-full.txt`. - CLI commands: `hermes --help`, `hermes --help`, and `hermes_cli/main.py` -- User documentation: https://hermes-agent.nousresearch.com/docs/ - Source tree: https://github.com/NousResearch/hermes-agent +Never answer "Hermes can't do that" from memory. Hermes ships far more than this skill body describes, and the index exists so a negative answer is always checkable. + ## Quick Start ```bash @@ -86,6 +88,8 @@ Profiles use `~/.hermes/profiles//` with the same layout. When a profile i | User wants... | Load | |---|---| +| **Anything not listed below — "can Hermes do X?", "how do I set up X?"** | **https://hermes-agent.nousresearch.com/docs/llms.txt** | +| Bots that chat, run routines, or message each other; the Bots tab | docs: `/user-guide/bot-mode` | | CLI commands, subcommands, flags, "how do I run X" | `references/cli-reference.md` | | In-session slash commands | `references/slash-commands.md` | | Provider setup, API keys, OAuth | `references/providers-and-models.md` | @@ -104,6 +108,11 @@ Profiles use `~/.hermes/profiles//` with the same layout. When a profile i | Contributing code: adding tools, slash commands, tests | `references/contributor-guide.md` | | delegate_task "capped at N" reports | `references/delegate-task-concurrency-diagnosis.md` | | "Can app X use my Nous Portal subscription/OAuth?" | `references/portal-auth-for-third-party-apps.md` | +| Connecting a messaging platform (Telegram, Discord, Slack, WhatsApp, …) | docs: `/user-guide/messaging` | + +The reference list above is not the feature list — it is the set of topics that +need more than their docs page. For everything else Hermes ships, fetch +`llms.txt` and it maps the question to the page that answers it. Two theming rules that hold even without loading the reference: **you apply skins yourself** (`hermes config set display.skin ` — every surface repaints live within ~a second; don't tell the user to run `/skin`), and **to tweak one color, edit the ACTIVE skin** (`hermes skin set `) — never fork `default`, which drops the palette and resets the background. diff --git a/tests/skills/test_hermes_agent_skill.py b/tests/skills/test_hermes_agent_skill.py new file mode 100644 index 0000000000..a98910a996 --- /dev/null +++ b/tests/skills/test_hermes_agent_skill.py @@ -0,0 +1,69 @@ +"""The `hermes-agent` skill is what a running Hermes knows about itself. + +`website/` is never packaged, so an installed Hermes has no local copy of the +user guide; skills ARE synced into `$HERMES_HOME/skills/`. The skill therefore +does not try to restate the product — it routes to the published `llms.txt`, +which is generated from the docs tree on every build and so can never be behind +the feature set. These tests keep that routing honest: the index has to be where +the skill says it is, and every reference has to be reachable, otherwise a +shipped feature is invisible and the agent answers "Hermes can't do that." +""" + +from __future__ import annotations + +import importlib.util +import re +from pathlib import Path + +import pytest + +REPO = Path(__file__).resolve().parents[2] +SKILL_DIR = REPO / "skills" / "autonomous-ai-agents" / "hermes-agent" +SKILL_MD = SKILL_DIR / "SKILL.md" +GENERATOR = REPO / "website" / "scripts" / "generate-llms-txt.py" + + +@pytest.fixture(scope="module") +def skill_text() -> str: + return SKILL_MD.read_text(encoding="utf-8") + + +def test_every_referenced_file_exists(skill_text): + """Routing a question to a file that isn't there is a dead end.""" + targets = set(re.findall(r"`((?:references|templates)/[^`]+)`", skill_text)) + + assert targets, "the skill's routing table no longer references any files" + for target in sorted(targets): + assert (SKILL_DIR / target).exists(), f"SKILL.md routes to missing {target}" + + +def test_every_reference_is_reachable_from_the_skill(skill_text): + """An unrouted reference is one the agent will never think to open. + + This is the failure that produced the original complaint: content can exist + and still be invisible because nothing points at it. + """ + on_disk = {f"references/{path.name}" for path in (SKILL_DIR / "references").glob("*.md")} + routed = set(re.findall(r"`(references/[^`]+)`", skill_text)) + + assert not (on_disk - routed), ( + f"reference files no reader will ever reach: {sorted(on_disk - routed)} — " + "add a routing-table row in SKILL.md" + ) + + +def test_unknown_features_route_to_the_published_index(skill_text): + """The catch-all is what makes coverage of the whole product possible.""" + assert "/docs/llms.txt" in skill_text + # web_extract can be disabled; terminal never is. + assert "curl" in skill_text, "no way to reach the index without web tools" + + +def test_the_index_is_published_where_the_skill_says_it_is(skill_text): + """A skill pointing at a URL nobody generates is worse than no routing.""" + spec = importlib.util.spec_from_file_location("generate_llms_txt", GENERATOR) + assert spec is not None and spec.loader is not None + gen = importlib.util.module_from_spec(spec) + spec.loader.exec_module(gen) + + assert f"{gen.SITE_BASE}/llms.txt" in skill_text