Problem
Skills are unconditionally advertised in the system prompt regardless of whether their runtime dependencies are actually available. This causes the agent to claim capabilities it cannot deliver — it sees the skill in its prompt, promises the user it can help, then fails at execution time with cryptic errors.
This was first surfaced via #630 (GIF search), but the problem is systemic: any skill that depends on a CLI binary (e.g., himalaya, openhue, ddgs) or an API key (e.g., TENOR_API_KEY, NOTION_API_KEY) will exhibit the same behavior if those dependencies aren't installed.
Root Cause
build_skills_system_prompt() in agent/prompt_builder.py lists all skills in ~/.hermes/skills/ (filtered only by OS platform). There is no mechanism for a skill to declare runtime prerequisites.
skill_view() returns skill content with zero prerequisite validation — the agent gets instructions to run commands that may not exist.
- Several bundled skills depend on non-universal CLI tools or API keys but don't declare this anywhere.
Proposed Solution
Add a prerequisites field to the SKILL.md frontmatter spec:
---
name: gif-search
description: Search GIFs from Tenor
prerequisites:
env_vars: [TENOR_API_KEY] # checked via os.getenv()
commands: [curl, jq] # checked via shutil.which()
---
Three layers of defense:
| Layer |
Where |
Behavior |
| System prompt |
prompt_builder.py |
Skills with unmet prereqs excluded — LLM never sees them |
skills_list() |
skills_tool.py |
Returns prerequisites_met: false + what's missing |
skill_view() |
skills_tool.py |
Returns prerequisites_warning telling agent to inform user |
Skills that need prerequisites declared:
| Skill |
Type |
Prereq |
gifs/gif-search |
env_var |
TENOR_API_KEY |
productivity/notion |
env_var |
NOTION_API_KEY |
email/himalaya |
command |
himalaya |
apple/imessage |
command |
imsg |
apple/apple-notes |
command |
memo |
apple/apple-reminders |
command |
remindctl |
smart-home/openhue |
command |
openhue |
research/duckduckgo-search |
command |
ddgs |
github/codebase-inspection |
command |
pygount |
feeds/blogwatcher |
command |
blogwatcher |
music-creation/songsee |
command |
songsee |
mcp/mcporter |
command |
npx |
Design principles:
- Backward compatible — skills without
prerequisites behave exactly as before
- Mirrors existing patterns — tools already use
check_fn + requires_env for the same purpose; this brings skills to parity
- Generalizable — any future skill author just adds the frontmatter field
Related
Environment
- Hermes Agent v1.0.0
- All platforms
Problem
Skills are unconditionally advertised in the system prompt regardless of whether their runtime dependencies are actually available. This causes the agent to claim capabilities it cannot deliver — it sees the skill in its prompt, promises the user it can help, then fails at execution time with cryptic errors.
This was first surfaced via #630 (GIF search), but the problem is systemic: any skill that depends on a CLI binary (e.g.,
himalaya,openhue,ddgs) or an API key (e.g.,TENOR_API_KEY,NOTION_API_KEY) will exhibit the same behavior if those dependencies aren't installed.Root Cause
build_skills_system_prompt()inagent/prompt_builder.pylists all skills in~/.hermes/skills/(filtered only by OS platform). There is no mechanism for a skill to declare runtime prerequisites.skill_view()returns skill content with zero prerequisite validation — the agent gets instructions to run commands that may not exist.Proposed Solution
Add a
prerequisitesfield to the SKILL.md frontmatter spec:Three layers of defense:
prompt_builder.pyskills_list()skills_tool.pyprerequisites_met: false+ what's missingskill_view()skills_tool.pyprerequisites_warningtelling agent to inform userSkills that need prerequisites declared:
gifs/gif-searchTENOR_API_KEYproductivity/notionNOTION_API_KEYemail/himalayahimalayaapple/imessageimsgapple/apple-notesmemoapple/apple-remindersremindctlsmart-home/openhueopenhueresearch/duckduckgo-searchddgsgithub/codebase-inspectionpygountfeeds/blogwatcherblogwatchermusic-creation/songseesongseemcp/mcporternpxDesign principles:
prerequisitesbehave exactly as beforecheck_fn+requires_envfor the same purpose; this brings skills to parityRelated
Environment