Add .well-known/agent-skills/ discovery as a new skill source#63
Merged
Conversation
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>
Security fixes for the well-known source's fetch path: - B1 (SSRF / allowlist bypass): validate every fetched URL — index, each entry's artifact url, and redirect targets — against the origin allowlist and scheme rules via new assertUrlAllowed(). Previously only the configured index origin was gated, so an allowlisted-but-malicious publisher could point an artifact url at an internal host or off-allowlist CDN. Artifact origins (incl. CDNs) must now be on WELL_KNOWN_ALLOWED_ORIGINS. - B2 (silent off-origin redirects): fetch now uses redirect:"manual" and follows hops itself, re-validating each Location (max 5) so a 3xx can't escape the allowlist after the initial check. - N1: the polling update-check now reads the index body through the same size-capped reader instead of an unbounded arrayBuffer(). - N5: WELL_KNOWN_MAX_*_MB=0 (a 0-byte cap) now falls back to the default instead of failing every fetch. - N2/N3: clarifying comments on the tar header-size trust and the zip symlink-attribute fallback (documented as non-escape). Tests: assertUrlAllowed unit cases (off-origin, scheme, http-gate) plus sync integration tests for cross-origin artifact rejection, off-allowlist redirect rejection, and a followed same-origin redirect. Full suite 225 green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
olaservo
force-pushed
the
feature/well-known-discovery
branch
from
July 4, 2026 20:26
acaff4e to
d6b5a97
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
/.well-known/agent-skills/index.json, alongside existing local + GitHub sources.skill-md(single SKILL.md) andarchive(.tar.gz/.zip) entry types are supported, with safety checks for path traversal, symlinks, decompression bombs, and an enforced size cap.WELL_KNOWN_ALLOWED_ORIGINS), 5-min polling with ETag-driven conditional refetch, per-publisher cache directory, prune-on-removal.What's new
src/well-known-config.tsisWellKnownUrl), normalization (auto-appends/.well-known/agent-skills), allowlist (isOriginAllowed), cache-path helpers, env-var configsrc/well-known-sync.tssyncWellKnownorchestrates fetch → validate → digest-verify → write/extract; safetar/yauzl-promiseextraction; index pruning; conditional refresh via ETagsrc/well-known-polling.tsgithub-polling.tssrc/index.tsclassifyPaths, well-known sync at startup + on UI refresh, second polling managersrc/skill-config.ts/src/skill-discovery.ts/src/skill-display-tool.tsSourceTypeandSkillSource.typeextended with\"well-known\"src/ui/skill-display.{ts,css}src/ui/mcp-app.{ts,html}package.jsontar+yauzl-promise(with a small ambient.d.tssince the latter ships no types). Bumped to0.12.0.README.md/CLAUDE.mdConfiguration
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.tsuse a localhttp.createServerfixture (no network). They cover:$schemaversioning, malformed digests, invalid skill names, unknowntypevalues)skill-mdhappy path + digest mismatch rejection + size-cap rejectiontar.gzarchive happy path (multi-file)tar.gzarchive missingSKILL.mdrejectiontar.gzarchive with../escapepath-traversal entry rejectionindex.jsoncannot be fetchedonUpdatefires only when the index actually changes; timer doesn't start when interval ≤ 0 or no specsFull 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_ORIGINSor~/.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.WELL_KNOWN_ALLOWED_ORIGINS=… npm run inspector https://…/.well-known/agent-skills/.tools/list,prompts/list, andskill://…/SKILL.mdresources.SKILL.md+ bump its digest inindex.json; confirmnotifications/tools/list_changedfires within 5 minutes...is rejected.🤖 Generated with Claude Code