diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c0400078d..9679d79d1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -328,11 +328,6 @@ license: MIT platforms: [macos, linux] # Optional — restrict to specific OS platforms # Valid: macos, linux, windows # Omit to load on all platforms (default) -prerequisites: # Optional — runtime requirements - env_vars: [MY_API_KEY] # Env vars that must be set - commands: [curl, jq] # CLI binaries that must be on PATH - # Skills with unmet prerequisites are hidden - # from the system prompt and flagged in skill_view. metadata: hermes: tags: [Category, Subcategory, Keywords] @@ -371,25 +366,6 @@ platforms: [windows] # Windows only If the field is omitted or empty, the skill loads on all platforms (backward compatible). See `skills/apple/` for examples of macOS-only skills. -### Skill prerequisites - -Skills can declare runtime prerequisites via the `prerequisites` frontmatter field. Skills with unmet prerequisites are automatically hidden from the system prompt (the agent won't claim it can use them) and show a clear warning in `skill_view()` telling the agent what's missing. - -```yaml -prerequisites: - env_vars: [TENOR_API_KEY] # Env vars checked via os.getenv() - commands: [curl, jq] # CLI binaries checked via shutil.which() -``` - -Both sub-fields are optional — declare only what applies. If the field is omitted entirely, the skill is always available (backward compatible). - -**When to declare prerequisites:** -- The skill uses a CLI tool that isn't universally installed (e.g., `himalaya`, `openhue`, `ddgs`) -- The skill requires an API key in the environment (e.g., `NOTION_API_KEY`, `TENOR_API_KEY`) -- Without these, the skill's commands will fail — not just degrade gracefully - -See `skills/gifs/gif-search/` and `skills/email/himalaya/` for examples. - ### Skill guidelines - **No external dependencies unless absolutely necessary.** Prefer stdlib Python, curl, and existing Hermes tools (`web_extract`, `terminal`, `read_file`). diff --git a/agent/prompt_builder.py b/agent/prompt_builder.py index 09dc6dd43..c933ffe67 100644 --- a/agent/prompt_builder.py +++ b/agent/prompt_builder.py @@ -170,22 +170,6 @@ def _skill_is_platform_compatible(skill_file: Path) -> bool: return True # Err on the side of showing the skill -def _skill_prerequisites_met(skill_file: Path) -> bool: - """Check if a SKILL.md's declared prerequisites are satisfied. - - Returns True (show the skill) when prerequisites are met or not declared. - Returns False when the skill explicitly declares prerequisites that are missing. - """ - try: - from tools.skills_tool import _parse_frontmatter, check_skill_prerequisites - raw = skill_file.read_text(encoding="utf-8")[:2000] - frontmatter, _ = _parse_frontmatter(raw) - met, _ = check_skill_prerequisites(frontmatter) - return met - except Exception: - return True - - def build_skills_system_prompt() -> str: """Build a compact skill index for the system prompt. @@ -207,9 +191,6 @@ def build_skills_system_prompt() -> str: # Skip skills incompatible with the current OS platform if not _skill_is_platform_compatible(skill_file): continue - # Skip skills whose prerequisites (env vars, commands) are unmet - if not _skill_prerequisites_met(skill_file): - continue rel_path = skill_file.relative_to(skills_dir) parts = rel_path.parts if len(parts) >= 2: diff --git a/skills/apple/apple-notes/SKILL.md b/skills/apple/apple-notes/SKILL.md index 33fb3ef76..d68c183b5 100644 --- a/skills/apple/apple-notes/SKILL.md +++ b/skills/apple/apple-notes/SKILL.md @@ -9,8 +9,6 @@ metadata: hermes: tags: [Notes, Apple, macOS, note-taking] related_skills: [obsidian] -prerequisites: - commands: [memo] --- # Apple Notes diff --git a/skills/apple/apple-reminders/SKILL.md b/skills/apple/apple-reminders/SKILL.md index 7af393370..872cc3f59 100644 --- a/skills/apple/apple-reminders/SKILL.md +++ b/skills/apple/apple-reminders/SKILL.md @@ -8,8 +8,6 @@ platforms: [macos] metadata: hermes: tags: [Reminders, tasks, todo, macOS, Apple] -prerequisites: - commands: [remindctl] --- # Apple Reminders diff --git a/skills/apple/imessage/SKILL.md b/skills/apple/imessage/SKILL.md index 82df6a6ec..777461d37 100644 --- a/skills/apple/imessage/SKILL.md +++ b/skills/apple/imessage/SKILL.md @@ -8,8 +8,6 @@ platforms: [macos] metadata: hermes: tags: [iMessage, SMS, messaging, macOS, Apple] -prerequisites: - commands: [imsg] --- # iMessage diff --git a/skills/email/himalaya/SKILL.md b/skills/email/himalaya/SKILL.md index ddbf51aae..08517ebc1 100644 --- a/skills/email/himalaya/SKILL.md +++ b/skills/email/himalaya/SKILL.md @@ -8,8 +8,6 @@ metadata: hermes: tags: [Email, IMAP, SMTP, CLI, Communication] homepage: https://github.com/pimalaya/himalaya -prerequisites: - commands: [himalaya] --- # Himalaya Email CLI diff --git a/skills/feeds/blogwatcher/SKILL.md b/skills/feeds/blogwatcher/SKILL.md index c1ea4ac24..4aadfe943 100644 --- a/skills/feeds/blogwatcher/SKILL.md +++ b/skills/feeds/blogwatcher/SKILL.md @@ -8,8 +8,6 @@ metadata: hermes: tags: [RSS, Blogs, Feed-Reader, Monitoring] homepage: https://github.com/Hyaxia/blogwatcher -prerequisites: - commands: [blogwatcher] --- # Blogwatcher diff --git a/skills/gifs/gif-search/SKILL.md b/skills/gifs/gif-search/SKILL.md index ee55cac88..a255b934d 100644 --- a/skills/gifs/gif-search/SKILL.md +++ b/skills/gifs/gif-search/SKILL.md @@ -1,12 +1,9 @@ --- name: gif-search description: Search and download GIFs from Tenor using curl. No dependencies beyond curl and jq. Useful for finding reaction GIFs, creating visual content, and sending GIFs in chat. -version: 1.1.0 +version: 1.0.0 author: Hermes Agent license: MIT -prerequisites: - env_vars: [TENOR_API_KEY] - commands: [curl, jq] metadata: hermes: tags: [GIF, Media, Search, Tenor, API] @@ -16,43 +13,32 @@ metadata: Search and download GIFs directly via the Tenor API using curl. No extra tools needed. -## Setup - -Set your Tenor API key in your environment (add to `~/.hermes/.env`): - -```bash -TENOR_API_KEY=your_key_here -``` - -Get a free API key at https://developers.google.com/tenor/guides/quickstart — the Google Cloud Console Tenor API key is free and has generous rate limits. - ## Prerequisites -- `curl` and `jq` (both standard on macOS/Linux) -- `TENOR_API_KEY` environment variable +- `curl` and `jq` (both standard on Linux) ## Search for GIFs ```bash # Search and get GIF URLs -curl -s "https://tenor.googleapis.com/v2/search?q=thumbs+up&limit=5&key=${TENOR_API_KEY}" | jq -r '.results[].media_formats.gif.url' +curl -s "https://tenor.googleapis.com/v2/search?q=thumbs+up&limit=5&key=AIzaSyAyimkuYQYF_FXVALexPuGQctUWRURdCYQ" | jq -r '.results[].media_formats.gif.url' # Get smaller/preview versions -curl -s "https://tenor.googleapis.com/v2/search?q=nice+work&limit=3&key=${TENOR_API_KEY}" | jq -r '.results[].media_formats.tinygif.url' +curl -s "https://tenor.googleapis.com/v2/search?q=nice+work&limit=3&key=AIzaSyAyimkuYQYF_FXVALexPuGQctUWRURdCYQ" | jq -r '.results[].media_formats.tinygif.url' ``` ## Download a GIF ```bash # Search and download the top result -URL=$(curl -s "https://tenor.googleapis.com/v2/search?q=celebration&limit=1&key=${TENOR_API_KEY}" | jq -r '.results[0].media_formats.gif.url') +URL=$(curl -s "https://tenor.googleapis.com/v2/search?q=celebration&limit=1&key=AIzaSyAyimkuYQYF_FXVALexPuGQctUWRURdCYQ" | jq -r '.results[0].media_formats.gif.url') curl -sL "$URL" -o celebration.gif ``` ## Get Full Metadata ```bash -curl -s "https://tenor.googleapis.com/v2/search?q=cat&limit=3&key=${TENOR_API_KEY}" | jq '.results[] | {title: .title, url: .media_formats.gif.url, preview: .media_formats.tinygif.url, dimensions: .media_formats.gif.dims}' +curl -s "https://tenor.googleapis.com/v2/search?q=cat&limit=3&key=AIzaSyAyimkuYQYF_FXVALexPuGQctUWRURdCYQ" | jq '.results[] | {title: .title, url: .media_formats.gif.url, preview: .media_formats.tinygif.url, dimensions: .media_formats.gif.dims}' ``` ## API Parameters @@ -61,7 +47,7 @@ curl -s "https://tenor.googleapis.com/v2/search?q=cat&limit=3&key=${TENOR_API_KE |-----------|-------------| | `q` | Search query (URL-encode spaces as `+`) | | `limit` | Max results (1-50, default 20) | -| `key` | API key (from `$TENOR_API_KEY` env var) | +| `key` | API key (the one above is Tenor's public demo key) | | `media_filter` | Filter formats: `gif`, `tinygif`, `mp4`, `tinymp4`, `webm` | | `contentfilter` | Safety: `off`, `low`, `medium`, `high` | | `locale` | Language: `en_US`, `es`, `fr`, etc. | @@ -81,6 +67,7 @@ Each result has multiple formats under `.media_formats`: ## Notes +- The API key above is Tenor's public demo key — it works but has rate limits - URL-encode the query: spaces as `+`, special chars as `%XX` - For sending in chat, `tinygif` URLs are lighter weight - GIF URLs can be used directly in markdown: `![alt](url)` diff --git a/skills/github/codebase-inspection/SKILL.md b/skills/github/codebase-inspection/SKILL.md index 6954ad841..ca71ffdf9 100644 --- a/skills/github/codebase-inspection/SKILL.md +++ b/skills/github/codebase-inspection/SKILL.md @@ -8,8 +8,6 @@ metadata: hermes: tags: [LOC, Code Analysis, pygount, Codebase, Metrics, Repository] related_skills: [github-repo-management] -prerequisites: - commands: [pygount] --- # Codebase Inspection with pygount diff --git a/skills/mcp/mcporter/SKILL.md b/skills/mcp/mcporter/SKILL.md index acb6fcfb0..0bb08441c 100644 --- a/skills/mcp/mcporter/SKILL.md +++ b/skills/mcp/mcporter/SKILL.md @@ -8,8 +8,6 @@ metadata: hermes: tags: [MCP, Tools, API, Integrations, Interop] homepage: https://mcporter.dev -prerequisites: - commands: [npx] --- # mcporter diff --git a/skills/music-creation/songsee/SKILL.md b/skills/music-creation/songsee/SKILL.md index 11bcca0c7..4ad4752e3 100644 --- a/skills/music-creation/songsee/SKILL.md +++ b/skills/music-creation/songsee/SKILL.md @@ -8,8 +8,6 @@ metadata: hermes: tags: [Audio, Visualization, Spectrogram, Music, Analysis] homepage: https://github.com/steipete/songsee -prerequisites: - commands: [songsee] --- # songsee diff --git a/skills/productivity/notion/SKILL.md b/skills/productivity/notion/SKILL.md index c74d0df61..eb6cf1c2b 100644 --- a/skills/productivity/notion/SKILL.md +++ b/skills/productivity/notion/SKILL.md @@ -8,8 +8,6 @@ metadata: hermes: tags: [Notion, Productivity, Notes, Database, API] homepage: https://developers.notion.com -prerequisites: - env_vars: [NOTION_API_KEY] --- # Notion API diff --git a/skills/research/duckduckgo-search/SKILL.md b/skills/research/duckduckgo-search/SKILL.md index 8066b09cc..33742ff18 100644 --- a/skills/research/duckduckgo-search/SKILL.md +++ b/skills/research/duckduckgo-search/SKILL.md @@ -8,8 +8,6 @@ metadata: hermes: tags: [search, duckduckgo, web-search, free, fallback] related_skills: [arxiv] -prerequisites: - commands: [ddgs] --- # DuckDuckGo Search (Firecrawl Fallback) diff --git a/skills/smart-home/openhue/SKILL.md b/skills/smart-home/openhue/SKILL.md index b3efd1700..9b2252856 100644 --- a/skills/smart-home/openhue/SKILL.md +++ b/skills/smart-home/openhue/SKILL.md @@ -8,8 +8,6 @@ metadata: hermes: tags: [Smart-Home, Hue, Lights, IoT, Automation] homepage: https://www.openhue.io/cli -prerequisites: - commands: [openhue] --- # OpenHue CLI diff --git a/tests/agent/test_prompt_builder.py b/tests/agent/test_prompt_builder.py index dbedf184d..a35983b5f 100644 --- a/tests/agent/test_prompt_builder.py +++ b/tests/agent/test_prompt_builder.py @@ -8,7 +8,6 @@ from agent.prompt_builder import ( _scan_context_content, _truncate_content, _read_skill_description, - _skill_prerequisites_met, build_skills_system_prompt, build_context_files_prompt, CONTEXT_FILE_MAX_CHARS, @@ -212,69 +211,6 @@ class TestBuildSkillsSystemPrompt: assert "imessage" in result assert "Send iMessages" in result - def test_excludes_skills_with_unmet_prerequisites(self, monkeypatch, tmp_path): - """Skills with missing env var prerequisites should not appear.""" - monkeypatch.setenv("HERMES_HOME", str(tmp_path)) - monkeypatch.delenv("MISSING_API_KEY_XYZ", raising=False) - skills_dir = tmp_path / "skills" / "media" - - gated = skills_dir / "gated-skill" - gated.mkdir(parents=True) - (gated / "SKILL.md").write_text( - "---\nname: gated-skill\ndescription: Needs a key\n" - "prerequisites:\n env_vars: [MISSING_API_KEY_XYZ]\n---\n" - ) - - available = skills_dir / "free-skill" - available.mkdir(parents=True) - (available / "SKILL.md").write_text( - "---\nname: free-skill\ndescription: No prereqs\n---\n" - ) - - result = build_skills_system_prompt() - assert "free-skill" in result - assert "gated-skill" not in result - - def test_includes_skills_with_met_prerequisites(self, monkeypatch, tmp_path): - """Skills with satisfied prerequisites should appear normally.""" - monkeypatch.setenv("HERMES_HOME", str(tmp_path)) - monkeypatch.setenv("MY_API_KEY", "test_value") - skills_dir = tmp_path / "skills" / "media" - - skill = skills_dir / "ready-skill" - skill.mkdir(parents=True) - (skill / "SKILL.md").write_text( - "---\nname: ready-skill\ndescription: Has key\n" - "prerequisites:\n env_vars: [MY_API_KEY]\n---\n" - ) - - result = build_skills_system_prompt() - assert "ready-skill" in result - - -# ========================================================================= -# _skill_prerequisites_met -# ========================================================================= - - -class TestSkillPrerequisitesMet: - def test_met_or_absent(self, tmp_path, monkeypatch): - """No prereqs, met prereqs, and missing file all return True.""" - monkeypatch.setenv("PRESENT_KEY_123", "val") - basic = tmp_path / "basic.md" - basic.write_text("---\nname: basic\ndescription: basic\n---\n") - ready = tmp_path / "ready.md" - ready.write_text("---\nname: ready\ndescription: ready\nprerequisites:\n env_vars: [PRESENT_KEY_123]\n---\n") - assert _skill_prerequisites_met(basic) is True - assert _skill_prerequisites_met(ready) is True - assert _skill_prerequisites_met(tmp_path / "nope.md") is True - - def test_unmet_returns_false(self, tmp_path, monkeypatch): - monkeypatch.delenv("NONEXISTENT_KEY_ABC", raising=False) - skill = tmp_path / "SKILL.md" - skill.write_text("---\nname: gated\ndescription: gated\nprerequisites:\n env_vars: [NONEXISTENT_KEY_ABC]\n---\n") - assert _skill_prerequisites_met(skill) is False - # ========================================================================= # Context files prompt builder diff --git a/tests/tools/test_skills_tool.py b/tests/tools/test_skills_tool.py index aab9ed10a..629d3b478 100644 --- a/tests/tools/test_skills_tool.py +++ b/tests/tools/test_skills_tool.py @@ -11,7 +11,6 @@ from tools.skills_tool import ( _estimate_tokens, _find_all_skills, _load_category_description, - check_skill_prerequisites, skill_matches_platform, skills_list, skills_categories, @@ -465,124 +464,3 @@ class TestFindAllSkillsPlatformFiltering: assert len(skills_darwin) == 1 assert len(skills_linux) == 1 assert len(skills_win) == 0 - - -# --------------------------------------------------------------------------- -# check_skill_prerequisites -# --------------------------------------------------------------------------- - - -class TestCheckSkillPrerequisites: - def test_no_or_empty_prerequisites(self): - """No field, empty dict, or non-dict all pass.""" - assert check_skill_prerequisites({})[0] is True - assert check_skill_prerequisites({"prerequisites": {}})[0] is True - assert check_skill_prerequisites({"prerequisites": "curl"})[0] is True - - def test_env_var_present_and_missing(self, monkeypatch): - monkeypatch.setenv("MY_TEST_KEY", "val") - monkeypatch.delenv("NONEXISTENT_TEST_VAR_XYZ", raising=False) - assert check_skill_prerequisites({"prerequisites": {"env_vars": ["MY_TEST_KEY"]}})[0] is True - met, missing = check_skill_prerequisites({"prerequisites": {"env_vars": ["NONEXISTENT_TEST_VAR_XYZ"]}}) - assert met is False - assert "env $NONEXISTENT_TEST_VAR_XYZ" in missing - - def test_command_present_and_missing(self): - assert check_skill_prerequisites({"prerequisites": {"commands": ["python3"]}})[0] is True - met, missing = check_skill_prerequisites({"prerequisites": {"commands": ["nonexistent_binary_xyz_123"]}}) - assert met is False - assert "command `nonexistent_binary_xyz_123`" in missing - - def test_mixed_env_and_commands(self, monkeypatch): - monkeypatch.delenv("MISSING_A", raising=False) - met, missing = check_skill_prerequisites({ - "prerequisites": { - "env_vars": ["MISSING_A"], - "commands": ["python3", "nonexistent_cmd_xyz"], - } - }) - assert met is False - assert len(missing) == 2 - - def test_string_instead_of_list(self, monkeypatch): - """YAML scalar (string) should be coerced to a single-element list.""" - monkeypatch.delenv("SOLO_VAR", raising=False) - assert check_skill_prerequisites({"prerequisites": {"env_vars": "SOLO_VAR"}})[0] is False - assert check_skill_prerequisites({"prerequisites": {"commands": "nonexistent_cmd_xyz_solo"}})[0] is False - - -# --------------------------------------------------------------------------- -# _find_all_skills — prerequisites integration -# --------------------------------------------------------------------------- - - -class TestFindAllSkillsPrerequisites: - def test_skills_with_unmet_prereqs_flagged(self, tmp_path, monkeypatch): - monkeypatch.delenv("NONEXISTENT_API_KEY_XYZ", raising=False) - with patch("tools.skills_tool.SKILLS_DIR", tmp_path): - _make_skill( - tmp_path, "needs-key", - frontmatter_extra="prerequisites:\n env_vars: [NONEXISTENT_API_KEY_XYZ]\n", - ) - skills = _find_all_skills() - assert len(skills) == 1 - assert skills[0]["prerequisites_met"] is False - assert any("NONEXISTENT_API_KEY_XYZ" in m for m in skills[0]["prerequisites_missing"]) - - def test_skills_with_met_prereqs_no_flag(self, tmp_path, monkeypatch): - monkeypatch.setenv("MY_PRESENT_KEY", "val") - with patch("tools.skills_tool.SKILLS_DIR", tmp_path): - _make_skill( - tmp_path, "has-key", - frontmatter_extra="prerequisites:\n env_vars: [MY_PRESENT_KEY]\n", - ) - skills = _find_all_skills() - assert len(skills) == 1 - assert "prerequisites_met" not in skills[0] - - def test_skills_without_prereqs_no_flag(self, tmp_path): - with patch("tools.skills_tool.SKILLS_DIR", tmp_path): - _make_skill(tmp_path, "simple-skill") - skills = _find_all_skills() - assert len(skills) == 1 - assert "prerequisites_met" not in skills[0] - - -# --------------------------------------------------------------------------- -# skill_view — prerequisites warnings -# --------------------------------------------------------------------------- - - -class TestSkillViewPrerequisites: - def test_warns_on_unmet_prerequisites(self, tmp_path, monkeypatch): - monkeypatch.delenv("MISSING_KEY_XYZ", raising=False) - with patch("tools.skills_tool.SKILLS_DIR", tmp_path): - _make_skill( - tmp_path, "gated-skill", - frontmatter_extra="prerequisites:\n env_vars: [MISSING_KEY_XYZ]\n", - ) - raw = skill_view("gated-skill") - result = json.loads(raw) - assert result["success"] is True - assert result["prerequisites_met"] is False - assert "MISSING_KEY_XYZ" in result["prerequisites_warning"] - - def test_no_warning_when_prereqs_met(self, tmp_path, monkeypatch): - monkeypatch.setenv("PRESENT_KEY", "value") - with patch("tools.skills_tool.SKILLS_DIR", tmp_path): - _make_skill( - tmp_path, "ready-skill", - frontmatter_extra="prerequisites:\n env_vars: [PRESENT_KEY]\n", - ) - raw = skill_view("ready-skill") - result = json.loads(raw) - assert result["success"] is True - assert "prerequisites_warning" not in result - - def test_no_warning_when_no_prereqs(self, tmp_path): - with patch("tools.skills_tool.SKILLS_DIR", tmp_path): - _make_skill(tmp_path, "plain-skill") - raw = skill_view("plain-skill") - result = json.loads(raw) - assert result["success"] is True - assert "prerequisites_warning" not in result diff --git a/tools/skills_tool.py b/tools/skills_tool.py index dce15c449..e8baa0f59 100644 --- a/tools/skills_tool.py +++ b/tools/skills_tool.py @@ -34,11 +34,6 @@ SKILL.md Format (YAML Frontmatter, agentskills.io compatible): platforms: [macos] # Optional — restrict to specific OS platforms # Valid: macos, linux, windows # Omit to load on all platforms (default) - prerequisites: # Optional — runtime requirements - env_vars: [API_KEY] # Env vars that must be set (checked via os.getenv) - commands: [curl, jq] # CLI binaries that must be on PATH (checked via shutil.which) - # Skills with unmet prerequisites are hidden from the - # system prompt and flagged with a warning in skill_view. compatibility: Requires X # Optional (agentskills.io) metadata: # Optional, arbitrary key-value (agentskills.io) hermes: @@ -70,7 +65,6 @@ Usage: import json import os import re -import shutil import sys from pathlib import Path from typing import Dict, Any, List, Optional, Tuple @@ -124,43 +118,6 @@ def skill_matches_platform(frontmatter: Dict[str, Any]) -> bool: return False -def check_skill_prerequisites(frontmatter: Dict[str, Any]) -> Tuple[bool, List[str]]: - """Check if a skill's declared prerequisites are satisfied. - - Skills declare prerequisites via a top-level ``prerequisites`` dict - in their YAML frontmatter:: - - prerequisites: - env_vars: [TENOR_API_KEY] - commands: [curl, jq] - - Returns: - (all_met, missing) — True + empty list if all met, else False + list - of human-readable descriptions of what's missing. - """ - prereqs = frontmatter.get("prerequisites") - if not prereqs or not isinstance(prereqs, dict): - return True, [] - - missing: List[str] = [] - - env_vars = prereqs.get("env_vars") or [] - if isinstance(env_vars, str): - env_vars = [env_vars] - for var in env_vars: - if not os.getenv(str(var)): - missing.append(f"env ${var}") - - commands = prereqs.get("commands") or [] - if isinstance(commands, str): - commands = [commands] - for cmd in commands: - if not shutil.which(str(cmd)): - missing.append(f"command `{cmd}`") - - return (len(missing) == 0), missing - - def check_skills_requirements() -> bool: """Skills are always available -- the directory is created on first use if needed.""" return True @@ -305,19 +262,12 @@ def _find_all_skills() -> List[Dict[str, Any]]: description = description[:MAX_DESCRIPTION_LENGTH - 3] + "..." category = _get_category_from_path(skill_md) - - prereqs_met, prereqs_missing = check_skill_prerequisites(frontmatter) - - entry = { + + skills.append({ "name": name, "description": description, "category": category, - } - if not prereqs_met: - entry["prerequisites_met"] = False - entry["prerequisites_missing"] = prereqs_missing - - skills.append(entry) + }) except Exception: continue @@ -685,17 +635,6 @@ def skill_view(name: str, file_path: str = None, task_id: str = None) -> str: "usage_hint": "To view linked files, call skill_view(name, file_path) where file_path is e.g. 'references/api.md' or 'assets/config.yaml'" if linked_files else None } - # Prerequisite check — warn the agent if requirements are unmet - prereqs_met, prereqs_missing = check_skill_prerequisites(frontmatter) - if not prereqs_met: - result["prerequisites_met"] = False - result["prerequisites_missing"] = prereqs_missing - result["prerequisites_warning"] = ( - f"This skill requires {', '.join(prereqs_missing)} which " - f"{'is' if len(prereqs_missing) == 1 else 'are'} not available. " - f"Tell the user what's needed before attempting to use this skill." - ) - # Surface agentskills.io optional fields when present if frontmatter.get('compatibility'): result["compatibility"] = frontmatter['compatibility']