Skip to content

feat: install skill sets from AI Catalog + agentskills discovery indexes - #81875

Draft
teknium1 wants to merge 2 commits into
mainfrom
hermes/hermes-6527fdb8
Draft

teknium1 wants to merge 2 commits into
mainfrom
hermes/hermes-6527fdb8

Conversation

@teknium1

@teknium1 teknium1 commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

hermes skills install-set <url> installs a published group of skills in one command and creates the /<name> bundle alias that loads them together — a working prototype of the skill-set layering discussed with agentskills.io (agentskills PR #254 + AI Catalog).

The layering:

  1. AI Catalog (/.well-known/ai-catalog.json) — an entry typed application/agent-skills+json points at a skill discovery index and represents an installable set.
  2. agentskills feat(agent): use main model for context compression when no override is set #254 discovery index{"$schema", "skills": [{name, description, type: skill-md|archive, url, digest}]}. $schema gating, required sha256 digests, and archive-safety rules implemented per the spec draft.
  3. io.hermes.skill-set extension (namespaced AI Catalog entry metadata) — carries set-level usage intent: a suggested load-alias command and a shared instruction preamble. Clients that don't recognize the extension still install the correct set; they only miss the alias/preamble sugar.
"entries": [{
  "displayName": "Backend Dev",
  "type": "application/agent-skills+json",
  "url": "/.well-known/agent-skills/index.json",
  "extensions": {
    "io.hermes.skill-set": {
      "command": "backend-dev",
      "instruction": "Prefer TDD. Lint before opening a PR."
    }
  }
}]

Changes

  • tools/skill_set_catalog.py (new): catalog/index client — $schema allow-list (warn + stop on unknown, per feat(agent): use main model for context compression when no override is set #254), required sha256: digest verification, skill-md + archive artifacts (.tar.gz/.zip), archive safety (traversal/absolute-path/symlink/hardlink rejection, decompression-bomb caps, SKILL.md-at-root check), one-level sub-catalog nesting. All HTTP through the existing SSRF-guarded fetcher.
  • hermes_cli/skills_hub.py: do_install_set() — resolves origin → catalog → set → members, installs each member through the existing quarantine → security-scan → install pipeline (lock-file provenance included), then creates the skill-bundle alias from the extension.
  • hermes_cli/subcommands/skills.py: hermes skills install-set <url> [--set NAME] [--no-alias] [--force] [-y].
  • scripts/publish_skill_set.py (new): publisher-side counterpart — builds the static .well-known/ tree (catalog + index + artifacts, byte-stable tar.gz for digest-friendly caching) from local skill directories.
  • tests/tools/test_skill_set_catalog.py (new): 31 tests.

Validation

Result
Unit: digest gating (mismatch/missing/malformed/uppercase-hex) ✅ rejected
Unit: $schema unknown/absent ✅ refused per spec
Unit: archive traversal, absolute path, symlink, bomb, no-root-SKILL.md ✅ all rejected
Unit: catalog discovery, extension parsing, sub-catalog nesting, unrecognized-type skip
E2E (in tests): publisher script → real local HTTP server → discover → resolve → fetch → digest-verify
E2E (live): full do_install_set() against a served catalog — 2 skills installed via quarantine+scan, lock entries with digests, /backend-dev alias created and build_bundle_invocation_message() loads both skills with the shared instruction
scripts/run_tests.sh targeted (new + sibling skills-hub/bundles/subparser files) 35 + 24 pass

Infographic

Skill sets infographic

Prototype of the skill-set layering discussed with agentskills.io:

- AI Catalog (/.well-known/ai-catalog.json) entries typed
  application/agent-skills+json point at an agentskills PR #254
  discovery index and represent an installable skill set.
- The optional io.hermes.skill-set extension carries set-level usage
  intent: a suggested load-alias command and a shared instruction
  preamble. Clients that ignore the extension still install the
  correct set.
- tools/skill_set_catalog.py implements the client: $schema gating,
  required sha256 digest verification, skill-md + archive (.tar.gz/.zip)
  artifacts, and #254 archive-safety rules (traversal/absolute-path/
  link rejection, decompression caps).
- hermes skills install-set <url> installs every member through the
  existing quarantine -> scan -> install pipeline, then creates the
  /<name> skill bundle so the whole set loads in one turn.
- scripts/publish_skill_set.py is the publisher-side counterpart:
  builds the static .well-known tree (catalog + index + artifacts)
  from local skill directories with byte-stable archives.
@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

૮ >ﻌ< ა ci review

ran on 665129c

⚠️ Warnings

OSV vulnerability scan · View job

21 known vulnerabilities found in pinned dependencies.

How to fix:

Review the findings in the Security tab. Update the affected dependencies if a patched version is available.


debug info

CI timings

CI timings · View report · View job

Wall time 4m32s vs 6m54s (-34.3%). 14 job(s) slower, 7 faster, 2 unchanged.

  • Python tests / Run tests slice 4/12: +54.0s
  • Python tests / Run tests slice 3/12: -37.0s
  • Python tests / Run tests slice 12/12: +26.0s
  • Python tests / Run tests slice 6/12: +16.0s
  • Python tests / Run tests slice 7/12: -10.0s

@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/cli CLI entry point, hermes_cli/, setup wizard tool/skills Skills system (list, view, manage) labels Aug 8, 2026

@jonathanhefner jonathanhefner left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Amazing! ❤️

(For any onlookers, #254 refers to agentskills/agentskills#254 rather than #254.)

Codex found a few minor issues that I wanted to bubble up:

  • There is a redirect + URL resolution issue for skill set manifest files. For example:

    1. An AI Catalog entry points to https://example.com/.well-known/agent-skills/index.json.
    2. That URL redirects to https://cdn.example.com/releases/v2/index.json.
    3. The retrieved skill set manifest contains "url": "review/SKILL.md".
    4. RFC 3986 resolution produces https://cdn.example.com/releases/v2/review/SKILL.md.
    5. Hermes instead produces https://example.com/.well-known/agent-skills/review/SKILL.md.
  • Archive type is currently being determined by URL file extension (inside the skill set manifest file). Per agentskills/agentskills#254, it should check the Content-Type header before falling back to the URL file extension.

  • This implementation supports url in AI catalog entries but not data. Per https://github.com/Agent-Card/ai-catalog/blob/11ff6bb7541f10c3f06f740fc9ebb74bb95dca99/specification/ai-catalog.md#L239-L247, AI Catalog entries can have either url or inline data. (Not a blocker, but you may want to consider supporting data as well.)

…ion, inline data

Follow-ups from jonathanhefner's review on the skill-set prototype:

- Relative member URLs now resolve per RFC 3986 against the URL the
  index/catalog was ACTUALLY retrieved from (post-redirect), so an
  index that redirects to a CDN resolves its members against the CDN
  location, not the original well-known path.
- Archive format detection checks the Content-Type header first
  (application/gzip, application/zip, + common aliases) and only falls
  back to the URL file extension when the header is absent or generic,
  per agentskills #254.
- AI Catalog entries carrying inline 'data' instead of 'url' are now
  supported for both skill-set entries and nested sub-catalogs; inline
  indexes get the same $schema gating, and their relative member URLs
  resolve against the catalog's retrieved location.
@teknium1

teknium1 commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator Author

Thanks for the careful review — all three are addressed in 665129c:

  • Redirect + URL resolution: the fetcher now returns the final post-redirect URL, and relative member URLs resolve per RFC 3986 against the location the index (or catalog) was actually retrieved from. Your exact scenario — well-known index redirecting to a CDN path — is now a regression test (TestRedirectBaseResolution).
  • Content-Type-first archive detection: _archive_format() checks the Content-Type header first (application/gzip, application/zip, plus common aliases) and only falls back to the URL extension when the header is absent or generic (application/octet-stream etc.). Tests cover header-wins-over-wrong-extension and the no-header/no-extension rejection case.
  • Inline data entries: supported now for both skill-set entries and nested sub-catalogs. Inline indexes go through the same $schema gating, and their relative member URLs resolve against the catalog's retrieved location (since the data was transported inside that document).

41 tests green. Happy to keep iterating as #254 / the extension shape settle.

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 P3 Low — cosmetic, nice to have 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