Skip to content

Add .well-known/agent-skills/ discovery as a new skill source#63

Open
olaservo wants to merge 2 commits into
mainfrom
feature/well-known-discovery
Open

Add .well-known/agent-skills/ discovery as a new skill source#63
olaservo wants to merge 2 commits into
mainfrom
feature/well-known-discovery

Conversation

@olaservo
Copy link
Copy Markdown
Owner

Summary

  • Adds consumer-side support for the agent-skills discovery RFC (v0.2.0). Skilljack can now pull skills from any HTTPS publisher serving /.well-known/agent-skills/index.json, alongside existing local + GitHub sources.
  • Every artifact is SHA-256 verified against the publisher's index entry; mismatches are rejected before anything is written to disk.
  • Both skill-md (single SKILL.md) and archive (.tar.gz / .zip) entry types are supported, with safety checks for path traversal, symlinks, decompression bombs, and an enforced size cap.
  • Mirrors the existing GitHub source: default-deny allowlist (WELL_KNOWN_ALLOWED_ORIGINS), 5-min polling with ETag-driven conditional refetch, per-publisher cache directory, prune-on-removal.

What's new

Area What changed
src/well-known-config.ts URL detection (isWellKnownUrl), normalization (auto-appends /.well-known/agent-skills), allowlist (isOriginAllowed), cache-path helpers, env-var config
src/well-known-sync.ts syncWellKnown orchestrates fetch → validate → digest-verify → write/extract; safe tar/yauzl-promise extraction; index pruning; conditional refresh via ETag
src/well-known-polling.ts Polling manager with the same shape as github-polling.ts
src/index.ts Third bucket in classifyPaths, well-known sync at startup + on UI refresh, second polling manager
src/skill-config.ts / src/skill-discovery.ts / src/skill-display-tool.ts SourceType and SkillSource.type extended with \"well-known\"
src/ui/skill-display.{ts,css} New source badge for well-known publishers
src/ui/mcp-app.{ts,html} Directory type union widened; blocked-state check now covers well-known too; add-directory placeholder/help text mention the URL form
package.json tar + yauzl-promise (with a small ambient .d.ts since the latter ships no types). Bumped to 0.12.0.
README.md / CLAUDE.md Usage example + new env vars + architecture notes

Configuration

WELL_KNOWN_ALLOWED_ORIGINS=https://example.com \
  skilljack-mcp https://example.com/.well-known/agent-skills/

Other env vars: WELL_KNOWN_POLL_INTERVAL_MS (default 300000), WELL_KNOWN_MAX_ARTIFACT_MB (10), WELL_KNOWN_MAX_UNPACKED_MB (50), WELL_KNOWN_ALLOW_HTTP (dev only).

Tests

28 new tests across well-known-{config,sync,polling}.test.ts use a local http.createServer fixture (no network). They cover:

  • URL parsing / normalization / allowlist gating
  • Index shape validation ($schema versioning, malformed digests, invalid skill names, unknown type values)
  • skill-md happy path + digest mismatch rejection + size-cap rejection
  • tar.gz archive happy path (multi-file)
  • tar.gz archive missing SKILL.md rejection
  • tar.gz archive with ../escape path-traversal entry rejection
  • Pruning per-skill cache dirs when a skill is removed from the index
  • Idempotent re-sync (no work when digests unchanged)
  • Top-level error when index.json cannot be fetched
  • Polling: onUpdate fires only when the index actually changes; timer doesn't start when interval ≤ 0 or no specs

Full suite: 217 / 217 passing, build clean.

Out of scope (intentional)

A full UI for managing the well-known origin allowlist (parallel to the existing "Allowed Orgs" panel) is deferred to a follow-up PR — it would add new server tools, a new HTML panel, and ~300 LOC of UI code best reviewed on its own. For now, configure via WELL_KNOWN_ALLOWED_ORIGINS or ~/.skilljack/config.json.

Publisher-mode (this server exposing its skills at .well-known/agent-skills/) is also out of scope; buildSkillIndex() already produces the right document shape, but no HTTP transport is added.

Test plan

  • npm install, npm run build, npm test — all green locally.
  • Spin up a local HTTPS publisher (or use the test fixtures) and add it via WELL_KNOWN_ALLOWED_ORIGINS=… npm run inspector https://…/.well-known/agent-skills/.
  • Verify skills appear in tools/list, prompts/list, and skill://…/SKILL.md resources.
  • Modify the publisher's SKILL.md + bump its digest in index.json; confirm notifications/tools/list_changed fires within 5 minutes.
  • Confirm a digest-tampered artifact is rejected (logs an error, skill is not written).
  • Confirm an origin not on the allowlist is reported as blocked at startup.
  • Confirm an archive entry with .. is rejected.

🤖 Generated with Claude Code

olaservo and others added 2 commits May 9, 2026 21:03
Implements consumer-side support for the agent-skills discovery RFC
(https://schemas.agentskills.io/discovery/0.2.0/schema.json), letting
the server pull skills from any HTTPS publisher serving an index.json
at /.well-known/agent-skills/.

New modules mirror the existing GitHub source pattern:
- well-known-config.ts: URL detection, parsing, default-deny allowlist
- well-known-sync.ts: index.json fetch + per-entry SHA-256 verification
  + safe extraction of tar.gz / zip artifacts (rejects path traversal,
  symlinks, decompression bombs, oversized payloads)
- well-known-polling.ts: ETag/If-None-Match-driven refresh

Wired into index.ts alongside GitHub: classifyPaths, source map,
startup sync, UI refresh callback, and a separate polling manager.

UI updates so well-known skills render correctly:
- skill-display.ts/.css: new source badge for well-known publishers
- mcp-app.ts/.html: directory type union, blocked-state check, and
  add-directory placeholder include the URL form

Adds tar + yauzl-promise dependencies. 28 new tests covering URL
parsing, allowlist gating, index validation, digest mismatch,
oversize cap, archive extraction (success + missing-SKILL.md +
path-traversal), pruning, idempotent re-sync, and polling change
detection. Full suite: 217 passing.

A full UI for managing the well-known origin allowlist (parallel to
the existing allowed-orgs panel) is intentionally deferred to a
follow-up. For now, configure via WELL_KNOWN_ALLOWED_ORIGINS or
~/.skilljack/config.json.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a panel parallel to "Allowed Orgs" so users can configure the
well-known origin allowlist from the skill-config UI, matching how
GitHub orgs are managed today.

Server tools (skill-config-tool.ts):
- skill-config-add-allowed-origin: accepts an origin or full URL,
  normalizes via new URL(input).origin, rejects http:// unless
  WELL_KNOWN_ALLOW_HTTP=1, persists via addWellKnownAllowedOrigin,
  and triggers onDirectoriesChanged() to re-sync any previously
  blocked publishers.
- skill-config-remove-allowed-origin: exact-match removal.
- All state-returning tools now include allowedOrigins alongside
  allowedOrgs / allowedUsers.
- Skill-count computation in getDirectoriesWithCounts() now matches
  well-known directories by source.origin so the per-directory count
  is correct.

UI (mcp-app.ts/.html/.css):
- New "Well-Known Allowed Origins" section with add/remove buttons.
- Add Origin modal + Confirm Remove Origin modal mirror the org ones.
- ConfigState gains allowedOrigins; render(), updateState() handle it.
- .remove-origin-btn shares CSS with .remove-org-btn.

Without this, users had to edit ~/.skilljack/config.json or set
WELL_KNOWN_ALLOWED_ORIGINS by hand. With it, the well-known consumer
flow is fully manageable from the Claude Desktop UI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant