Skip to content

Add spec for .well-known URI - #254

Open
jonathanhefner wants to merge 2 commits into
agentskills:mainfrom
jonathanhefner:well-known-uri
Open

Add spec for .well-known URI#254
jonathanhefner wants to merge 2 commits into
agentskills:mainfrom
jonathanhefner:well-known-uri

Conversation

@jonathanhefner

@jonathanhefner jonathanhefner commented Mar 16, 2026

Copy link
Copy Markdown
Collaborator

See accompanying proposal issue here: #255

Skill distribution is one of the most-discussed gaps in the spec (#27, #81, #210, #243). Today, distributing skills means sharing files ad hoc — cloning repos, copying directories, or bundling them in platform-specific packages.

This PR adds a standardized distribution mechanism: a publisher hosts an index.json at a well-known URL (RFC 8615) that enumerates available skills. Clients fetch the index, download skill artifacts, and verify their integrity.

How it works

Publishers serve a discovery index at /.well-known/agent-skills/index.json:

{
  "$schema": "https://schemas.agentskills.io/discovery/0.2.0/schema.json",
  "skills": [
    {
      "name": "code-review",
      "type": "skill-md",
      "description": "Review code for bugs, security issues, and best practices.",
      "url": "/.well-known/agent-skills/code-review/SKILL.md",
      "digest": "sha256:c4d5e6f7..."
    },
    {
      "name": "wrangler",
      "type": "archive",
      "description": "Deploy and manage Cloudflare Workers projects.",
      "url": "/.well-known/agent-skills/wrangler.tar.gz",
      "digest": "sha256:a1b2c3d4..."
    }
  ]
}

Skills are distributed as either a single SKILL.md file (type: "skill-md") or a bundled archive (type: "archive") for skills with scripts, references, and assets. Each entry includes a SHA-256 digest for integrity verification and caching. URLs can be relative, path-absolute, or fully qualified, so skills can be hosted anywhere (e.g., on a CDN).

The spec also covers archive safety (path traversal, symlink, decompression bomb protections), HTTP requirements, client implementation steps, and security considerations for script execution.

Provenance

Based on Cloudflare's Agent Skills Discovery RFC, incorporating changes from a proposed revision that the RFC authors have tentatively approved.


Preview: https://agent-skills-jh-well-known-uri.mintlify.app/well-known-uri

Distilled from Cloudflare's Agent Skills Discovery RFC. Covers the
`index.json` format, `$schema` versioning, URL resolution, SHA-256
digest verification, archive distribution (`.tar.gz`/`.zip`), HTTP
requirements, and client implementation steps.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add guidance for clients to warn the user when encountering an
unrecognized `type` value in skill entries, both in the format
description and client implementation steps.

Add a "Prompt injection" bullet to security considerations, noting that
skill content is loaded into agent context and can alter agent behavior.

Reword the "Trust" bullet to focus on why trusted origins matter (skills
run in agent context with access to the user's environment) and reorder
security considerations: Trust, Prompt injection, Script execution,
Digest verification, Archive safety.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@pja-ant

pja-ant commented Mar 24, 2026

Copy link
Copy Markdown

Is the digest adding much here? In terms of integrity, it's likely from the same trust domain as the skills themselves so someone tampering the skill can likely tamper the index as well. For caching, would it not be better to just rely on standard HTTP caching?

The presence of the digest adds friction to using this: you can't just put a bunch of static files in the .well-known any more -- you need some process to keep the digests in sync with the skills, and if they get out of sync then things can stop working for clients. Feels like a bit of a footgun with not much value add IMO.

@jonathanhefner

Copy link
Copy Markdown
Collaborator Author

In terms of integrity, it's likely from the same trust domain as the skills themselves so someone tampering the skill can likely tamper the index as well.

It's possible to host the index on one domain and the skill artifacts on a CDN. In that case, the integrity hashes add an extra layer of security. See also cloudflare/agent-skills-discovery-rfc#2.

For caching, would it not be better to just rely on standard HTTP caching?

I do think people should leverage standard HTTP caching, particularly for the index! Being able to completely avoid additional GETs for each (cached) skill artifact is a minor benefit. A larger benefit is being able to check if any skills have been updated with a single GET (and to have that baked into the format rather than hope people implement HTTP caching correctly).

But I think an even bigger motivator is consistency of skill bundles — if there are multiple skills that should be updated in lockstep, then you have a race condition where:

  1. Client downloads the index
  2. Client downloads v1 of the first skill
  3. Server deploys new version of the bundle
  4. Client downloads v2 of the second skill

The integrity hashes allow the client to detect this scenario and retry. See also cloudflare/agent-skills-discovery-rfc#3.

@jonathanhefner

Copy link
Copy Markdown
Collaborator Author

The presence of the digest adds friction to using this: you can't just put a bunch of static files in the .well-known any more -- you need some process to keep the digests in sync with the skills, and if they get out of sync then things can stop working for clients.

By the way, I created a GitHub Action for this: https://github.com/jonathanhefner/agentskills-build-for-well-known

If this PR is merged, I intend to transfer the repo to the agentskills org and publish the action to the GitHub Marketplace.

@pja-ant

pja-ant commented Mar 24, 2026

Copy link
Copy Markdown

Fair points! I wonder if immutable/versioned skills would be a better solve for the consistency issue (less work for clients, avoid potentially many retries for a rolling deployment trying to find an index consistent with skills). Not sure if it's much of an issue.

rareba added a commit to rareba/zeroclaw that referenced this pull request Mar 29, 2026
…stall (zeroclaw-labs#4853)

Add support for installing skills via the Agent Skills `.well-known`
discovery standard (agentskills/agentskills#254). When a user runs
`zeroclaw skills install https://example.com`, the installer detects
bare domain URLs and fetches `/.well-known/agent-skills/index.json`
to discover and install available skills.

- Add `--from-well-known` flag to `skills install` for explicit opt-in
- Auto-detect bare domain URLs (https://host with no path) as candidates
- Parse index.json with `{"skills": [{name, description, url}, ...]}`
- Install each listed skill via git clone or zip download
- Apply the same security audit as all other install paths
- Add unit tests for URL detection, URL construction, and JSON parsing
seburbina added a commit to seburbina/skillhub that referenced this pull request Apr 9, 2026
Add /.well-known/agent-skills/index.json and per-skill download
endpoints, implementing the Cloudflare Agent Skills Discovery RFC
(being adopted into the spec via agentskills/agentskills#254).

Any spec-compliant agent can now discover and install skills from
AgentSkillDepot by fetching the well-known index — zero custom
integration needed.

- GET /.well-known/agent-skills/index.json — lists all public skills
  with name, type, description, url, and sha256 digest
- GET /.well-known/agent-skills/:slug.tar.gz — direct skill download
  with R2 streaming and download count tracking
- Add sha256_digest column to skill_versions for spec compliance
- Wire route into main Hono app

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
seburbina added a commit to seburbina/skillhub that referenced this pull request Apr 9, 2026
* docs: reposition from Claude-only to open Agent Skills standard

Update all user-facing copy and docs to reflect that AgentSkillDepot
is a publisher platform for the open Agent Skills standard
(agentskills.io), not a Claude-only registry. The standard is now
implemented by 30+ agents including Claude Code, Cursor, GitHub
Copilot, OpenAI Codex, Gemini CLI, and more.

Changes across 8 files:
- README.md: hero, description, requirements section
- package.json: description field
- base-skill/skillhub/SKILL.md: description + body + skill-creator ref
- landing.tsx: title, meta, h1, lead, value props
- install.tsx: requirements, lead, install comment
- email.ts: "Claude agent" → "agent" in claim emails
- package.py: error message for missing skill-creator
- plan-archive.md: context paragraph + skill description

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(well-known): implement Agent Skills Discovery spec endpoint

Add /.well-known/agent-skills/index.json and per-skill download
endpoints, implementing the Cloudflare Agent Skills Discovery RFC
(being adopted into the spec via agentskills/agentskills#254).

Any spec-compliant agent can now discover and install skills from
AgentSkillDepot by fetching the well-known index — zero custom
integration needed.

- GET /.well-known/agent-skills/index.json — lists all public skills
  with name, type, description, url, and sha256 digest
- GET /.well-known/agent-skills/:slug.tar.gz — direct skill download
  with R2 streaming and download count tracking
- Add sha256_digest column to skill_versions for spec compliance
- Wire route into main Hono app

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(well-known): spec compliance — SHA-256 digest, ZIP format, CORS

Three fixes to align the .well-known endpoint with PR #254:

1. Digest: publish.ts now stores `sha256:${hex}` in sha256_digest
   column at publish time. The content_hash was already SHA-256 —
   this just adds the spec-required prefix format.

2. Archive format: serve as .zip (not .tar.gz) since our .skill
   files are ZIP archives. Content-Type set to application/zip.
   Spec says clients determine format from Content-Type header.

3. CORS: add cors({ origin: "*" }) middleware to all .well-known
   routes per spec recommendation for browser-based clients.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ci): correct R2 binding name + add api-changelog entry

- Fix SKILL_BUCKET → SKILLS_BUCKET typo in well-known.ts
- Add .well-known + cross-vendor changelog entry for CI gate

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
seburbina added a commit to seburbina/skillhub that referenced this pull request Apr 9, 2026
* docs: reposition from Claude-only to open Agent Skills standard

Update all user-facing copy and docs to reflect that AgentSkillDepot
is a publisher platform for the open Agent Skills standard
(agentskills.io), not a Claude-only registry. The standard is now
implemented by 30+ agents including Claude Code, Cursor, GitHub
Copilot, OpenAI Codex, Gemini CLI, and more.

Changes across 8 files:
- README.md: hero, description, requirements section
- package.json: description field
- base-skill/skillhub/SKILL.md: description + body + skill-creator ref
- landing.tsx: title, meta, h1, lead, value props
- install.tsx: requirements, lead, install comment
- email.ts: "Claude agent" → "agent" in claim emails
- package.py: error message for missing skill-creator
- plan-archive.md: context paragraph + skill description

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(well-known): implement Agent Skills Discovery spec endpoint

Add /.well-known/agent-skills/index.json and per-skill download
endpoints, implementing the Cloudflare Agent Skills Discovery RFC
(being adopted into the spec via agentskills/agentskills#254).

Any spec-compliant agent can now discover and install skills from
AgentSkillDepot by fetching the well-known index — zero custom
integration needed.

- GET /.well-known/agent-skills/index.json — lists all public skills
  with name, type, description, url, and sha256 digest
- GET /.well-known/agent-skills/:slug.tar.gz — direct skill download
  with R2 streaming and download count tracking
- Add sha256_digest column to skill_versions for spec compliance
- Wire route into main Hono app

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(well-known): spec compliance — SHA-256 digest, ZIP format, CORS

Three fixes to align the .well-known endpoint with PR #254:

1. Digest: publish.ts now stores `sha256:${hex}` in sha256_digest
   column at publish time. The content_hash was already SHA-256 —
   this just adds the spec-required prefix format.

2. Archive format: serve as .zip (not .tar.gz) since our .skill
   files are ZIP archives. Content-Type set to application/zip.
   Spec says clients determine format from Content-Type header.

3. CORS: add cors({ origin: "*" }) middleware to all .well-known
   routes per spec recommendation for browser-based clients.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ci): correct R2 binding name + add api-changelog entry

- Fix SKILL_BUCKET → SKILLS_BUCKET typo in well-known.ts
- Add .well-known + cross-vendor changelog entry for CI gate

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove remaining Claude-only references from all pages

Update _layout.tsx OG description, claim.tsx, skill.tsx, dashboard.tsx,
install.tsx, and landing.tsx — replace "Claude session", "inside Claude",
"your Claude agent" with agent-agnostic language. Claude Code is still
mentioned where appropriate as one of many supported agents in a list.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
seburbina added a commit to seburbina/skillhub that referenced this pull request Apr 9, 2026
* docs: reposition from Claude-only to open Agent Skills standard

Update all user-facing copy and docs to reflect that AgentSkillDepot
is a publisher platform for the open Agent Skills standard
(agentskills.io), not a Claude-only registry. The standard is now
implemented by 30+ agents including Claude Code, Cursor, GitHub
Copilot, OpenAI Codex, Gemini CLI, and more.

Changes across 8 files:
- README.md: hero, description, requirements section
- package.json: description field
- base-skill/skillhub/SKILL.md: description + body + skill-creator ref
- landing.tsx: title, meta, h1, lead, value props
- install.tsx: requirements, lead, install comment
- email.ts: "Claude agent" → "agent" in claim emails
- package.py: error message for missing skill-creator
- plan-archive.md: context paragraph + skill description

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(well-known): implement Agent Skills Discovery spec endpoint

Add /.well-known/agent-skills/index.json and per-skill download
endpoints, implementing the Cloudflare Agent Skills Discovery RFC
(being adopted into the spec via agentskills/agentskills#254).

Any spec-compliant agent can now discover and install skills from
AgentSkillDepot by fetching the well-known index — zero custom
integration needed.

- GET /.well-known/agent-skills/index.json — lists all public skills
  with name, type, description, url, and sha256 digest
- GET /.well-known/agent-skills/:slug.tar.gz — direct skill download
  with R2 streaming and download count tracking
- Add sha256_digest column to skill_versions for spec compliance
- Wire route into main Hono app

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(well-known): spec compliance — SHA-256 digest, ZIP format, CORS

Three fixes to align the .well-known endpoint with PR #254:

1. Digest: publish.ts now stores `sha256:${hex}` in sha256_digest
   column at publish time. The content_hash was already SHA-256 —
   this just adds the spec-required prefix format.

2. Archive format: serve as .zip (not .tar.gz) since our .skill
   files are ZIP archives. Content-Type set to application/zip.
   Spec says clients determine format from Content-Type header.

3. CORS: add cors({ origin: "*" }) middleware to all .well-known
   routes per spec recommendation for browser-based clients.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ci): correct R2 binding name + add api-changelog entry

- Fix SKILL_BUCKET → SKILLS_BUCKET typo in well-known.ts
- Add .well-known + cross-vendor changelog entry for CI gate

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: remove remaining Claude-only references from all pages

Update _layout.tsx OG description, claim.tsx, skill.tsx, dashboard.tsx,
install.tsx, and landing.tsx — replace "Claude session", "inside Claude",
"your Claude agent" with agent-agnostic language. Claude Code is still
mentioned where appropriate as one of many supported agents in a list.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* docs: add ClawHavoc security hardening implementation plan

Based on deep analysis of the ClawHavoc supply-chain attack against
ClawHub (1,184 malicious skills, 335 distributing AMOS malware).

Five enhancements planned for a follow-up PR:
1. Typosquat detection (Levenshtein distance check on slugs)
2. New exfiltration rules (password-archives, memory manipulation,
   fake prerequisites)
3. Version-diff-aware scanning (catch "clean v1, malware v1.0.1")
4. New-publisher rate limiting (5 skills/week for first 7 days)
5. GitHub account linking for publishers (schema + verification)

See docs/clawhavoc-hardening-plan.md for full spec with integration
points, verification steps, and file paths.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@petemounce

Copy link
Copy Markdown

Most skills are instructions only. For those, there's no real versioning need: you always want the latest, and the skill can be treated as a live document. If the description improves or a workflow step changes, you just update it — there's no "breaking change" concept the way there is with a code package.

Those seems to have made some assumptions:

  • all changes to a skill are positive to its performance, and tested in every use-scenario
  • no external consumer will ever need to a/b test version x vs y to provide a reproduction for a regression
  • no changes to a skill will be malicious

To my mind, I agree skills are instructions - in the same way that all released software packages are instructions. These are just prose vs code.

Rodriguespn added a commit to supabase/supabase that referenced this pull request May 15, 2026
…45641)

## Summary

This PR makes `fetchAgentSkills.mjs` a spec-compliant client of the
[agent-skills `.well-known` URI
spec](agentskills/agentskills#254), and updates
the script to match the current release structure in
[`supabase/agent-skills`](https://github.com/supabase/agent-skills).

---

## 1. Spec-compliant URL resolution and digest verification

`fetchAgentSkills.mjs` acts as a client consuming the `.well-known`
discovery index. The [agent-skills `.well-known`
spec](agentskills/agentskills#254) is explicit
on two points:

**URL resolution** — skill artifact URLs in `index.json` must be
resolved per [RFC 3986
§5.2.2](https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.2)
using the index URL as the base URI:

> "The `url` field specifies where to fetch the skill artifact. URLs are
resolved per RFC 3986 Section 5 using the index URL as the base URI."

This means `skill.url` can be relative (`supabase.tar.gz`),
path-absolute (`/.well-known/agent-skills/supabase.tar.gz`), or fully
absolute (e.g. a CDN URL like
`https://cdn.example.com/supabase.tar.gz`). The previous implementation
extracted a filename with `.split('/').pop()` which happened to work for
bare relative URLs but was not doing RFC 3986 resolution.

**Digest verification** — clients must verify artifact integrity before
use:

> "Clients **must** verify downloaded content against the `digest` in
the index. A mismatch indicates the content is corrupted or tampered
with — clients **must not** use unverified content."

The updated script uses `new URL(skill.url, githubReleaseIndexUrl)` for
compliant resolution, verifies each artifact's SHA-256 digest from the
in-memory buffer before any disk writes, and only writes to
`public/.well-known/agent-skills/` once all digests pass.

**Acknowledged overhead**: since Supabase owns both the publisher
([`scripts/build-release.ts`](https://github.com/supabase/agent-skills/blob/main/scripts/build-release.ts)
in `supabase/agent-skills`) and this consumer, the practical risk of
non-compliant URL handling is currently low — the publisher always emits
bare relative filenames. However, being spec-compliant here gives us
full flexibility to change how skills are packaged or hosted in
`supabase/agent-skills` in the future (e.g. moving artifacts to a CDN)
without needing to update this script.

---

## 2. Semver release tags

#44878 referenced `supabase/agent-skills#66` (date+SHA tags).
[supabase/agent-skills#77](supabase/agent-skills#77)
has since merged, moving releases to semver tags managed by Release
Please. `/releases/latest` works for both formats — no code change
needed, just a rebase.

---------

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Rodriguespn added a commit to supabase/supabase that referenced this pull request May 19, 2026
…45641)

## Summary

This PR makes `fetchAgentSkills.mjs` a spec-compliant client of the
[agent-skills `.well-known` URI
spec](agentskills/agentskills#254), and updates
the script to match the current release structure in
[`supabase/agent-skills`](https://github.com/supabase/agent-skills).

---

## 1. Spec-compliant URL resolution and digest verification

`fetchAgentSkills.mjs` acts as a client consuming the `.well-known`
discovery index. The [agent-skills `.well-known`
spec](agentskills/agentskills#254) is explicit
on two points:

**URL resolution** — skill artifact URLs in `index.json` must be
resolved per [RFC 3986
§5.2.2](https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.2)
using the index URL as the base URI:

> "The `url` field specifies where to fetch the skill artifact. URLs are
resolved per RFC 3986 Section 5 using the index URL as the base URI."

This means `skill.url` can be relative (`supabase.tar.gz`),
path-absolute (`/.well-known/agent-skills/supabase.tar.gz`), or fully
absolute (e.g. a CDN URL like
`https://cdn.example.com/supabase.tar.gz`). The previous implementation
extracted a filename with `.split('/').pop()` which happened to work for
bare relative URLs but was not doing RFC 3986 resolution.

**Digest verification** — clients must verify artifact integrity before
use:

> "Clients **must** verify downloaded content against the `digest` in
the index. A mismatch indicates the content is corrupted or tampered
with — clients **must not** use unverified content."

The updated script uses `new URL(skill.url, githubReleaseIndexUrl)` for
compliant resolution, verifies each artifact's SHA-256 digest from the
in-memory buffer before any disk writes, and only writes to
`public/.well-known/agent-skills/` once all digests pass.

**Acknowledged overhead**: since Supabase owns both the publisher
([`scripts/build-release.ts`](https://github.com/supabase/agent-skills/blob/main/scripts/build-release.ts)
in `supabase/agent-skills`) and this consumer, the practical risk of
non-compliant URL handling is currently low — the publisher always emits
bare relative filenames. However, being spec-compliant here gives us
full flexibility to change how skills are packaged or hosted in
`supabase/agent-skills` in the future (e.g. moving artifacts to a CDN)
without needing to update this script.

---

## 2. Semver release tags

#44878 referenced `supabase/agent-skills#66` (date+SHA tags).
[supabase/agent-skills#77](supabase/agent-skills#77)
has since merged, moving releases to semver tags managed by Release
Please. `/releases/latest` works for both formats — no code change
needed, just a rebase.

---------

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@jonathanhefner

Copy link
Copy Markdown
Collaborator Author

@petemounce @xtfer @Rodriguespn

How would one go about version-pinning skills via this? For my org it's pretty important to trace the inputs to agents to debug the output, so knowing for sure which versions of particular skills were in play is key for that.

Version pinning is done by digest + artifact URL. Entries in index.json can specify arbitrary URLs (e.g., https://cdn.example.com/my-cool-skill/v2.0.0/my-cool-skill.zip). A lock file would record the digest as the "version" and the artifact URL for future resolution (if needed).

Note, however, that servers are not required to host older versions of skills. The spec simply allows for it.

@schneidergithub

Copy link
Copy Markdown

Curious if there is any movement on this proposal. You have my vote!

As far as pinning, this is git, can't you just pin to the commit? I'm not sure I understand the concern.

@Rodriguespn

Copy link
Copy Markdown

Apologies for the late reply @jonathanhefner.

Version pinning is done by digest + artifact URL. [...] Note, however, that servers are not required to host older versions of skills. The spec simply allows for it.

Agreed that servers shouldn't be required to host older versions — but I think there's a gap in the discovery layer, and as @petemounce noted, rollback and regression reproduction are real use cases worth supporting.

Artifact URLs can be anything (a CDN, a GitHub release asset, etc.), so I have no objection there. The missing piece is: to install or rollback to a specific version, a client needs the index.json snapshot for that version — that's what contains both the artifact URL and the digest for that release. Without a standard way to find it, the mechanism breaks down.

Concrete example: I have Supabase agent skills v0.1.6 installed. I upgrade to v0.1.7. A day later I notice my agent is behaving unexpectedly due to a new instruction Supabase introduced. I want to rollback to v0.1.6. The artifact may still be hosted somewhere, but with only the latest index.json defined there's no standard way to discover the snapshot that describes v0.1.6 — its artifact URL and expected digest.

My proposal doesn't enforce publishers to host older index.json versions, but for those that want to, it defines a standard: serve a versioned index.json per release, each with the artifact URL and digest for that version, alongside a versions.json for discovery.

/.well-known/agent-skills/index.json          ← latest (v0.2.0)
/.well-known/agent-skills/versions.json       ← version list
/.well-known/agent-skills/v0.1.0/index.json    ← snapshot
/.well-known/agent-skills/v0.1.1/index.json    ← snapshot
/.well-known/agent-skills/v0.2.0/index.json   ← snapshot
// versions.json

{
  "latest": "0.2.0",
  "versions": ["0.1.0", "0.1.1", "0.2.0"]
}

This gives clients a standard way to rollback, A/B test, or reproduce regressions as Pete mentioned. Would love to hear your thoughts.

@olijboyd

Copy link
Copy Markdown

@schneidergithub commit pinning works when the artifact is git-addressed, and as a publisher that's what we do ourselves, our index URLs point at immutable commit hashes rather than main. But the spec deliberately allows artifact URLs that aren't git at all (CDNs, release assets), and even where they are, the thing a rollback actually needs isn't the artifact, it's the pair of artifact URL plus expected digest for the version you're going back to, and that pair only exists in an index snapshot. Which I think is @Rodriguespn's point, and from the consumer side I can confirm the gap is real: the consumer we run at TomeVault re-fetches indexes and digest-compares on every pass, so we know the moment a skill's content changes, but when it does there's no standard way to ask the publisher what it changed from. We work around it by keeping our own history of (URL, digest) pairs per skill, which works because we were already watching, but it does nothing for a fresh client that wants v0.1.6 of something it has never seen.

One suggestion on the shape proposed in #380: versioned snapshots only carry trust weight if a client can rely on them not changing. A /v0.1.6/index.json path is just another mutable URL unless the spec says snapshots MUST be immutable once published, and a publisher who can rewrite history under a version label defeats the regression-reproduction case @petemounce raised. The cheap fix is for versions.json to carry the digest of each snapshot index alongside the version string, then the version list is the only thing the client has to take on trust, and a rewritten snapshot is detectable rather than silent. That also keeps @jonathanhefner's line intact: servers still aren't required to host old versions, the ones that choose to just can't quietly edit them.

@petemounce

Copy link
Copy Markdown

@olijboyd in practical terms, I think one cannot mandate a server comply with a must in a spec with only the spec. The server owner can silently mutate what they serve even if the spec says not to.

I'd hazard that's contributory to how come ecosystems centralise their package management. The owner organisation starts to gain reputation for being a trustworthy spec-compliant host. In a decentralised scenario, that trust is easy to assert, (much) harder to verify.

@Rodriguespn

Copy link
Copy Markdown

In a decentralised scenario, that trust is easy to assert, (much) harder to verify.

Totally agree with @petemounce on this. The spec can state that "snapshots MUST be immutable once published," but then there is no mechanism to enforce this in the decentralized scenario described in this spec.

For that reason, my proposal deliberately states that the versioning model is built on trust that the publisher won't change a snapshot.

@olijboyd

Copy link
Copy Markdown

@petemounce @Rodriguespn fair, you've changed my mind. You can't make a server honour a MUST, and the external record I floated earlier doesn't get round that, it just moves the trust from the publisher onto whoever keeps the record. From where we sit that's us, we already re-fetch indexes and digest-compare every pass, so we'd see a snapshot change under a version label. That only works because we were watching though, and a client showing up cold has no reason to take our word for it over the publisher's.

What I'd want is a record the client can check for itself instead of taking it on trust from us, and that's the part that isn't ours to assert. We're not there, what we run today is the weaker private version. I don't think it belongs in this PR anyway, which is about discovery and the snapshot shape, and per-snapshot digests in versions.json are still worth doing for whoever was there from the start. Mostly I wanted to walk back my earlier comment, a side database doesn't solve this for anyone but the person who already owns the database.

@jonathanhefner

Copy link
Copy Markdown
Collaborator Author

@Rodriguespn

The missing piece is: to install or rollback to a specific version, a client needs the index.json snapshot for that version — that's what contains both the artifact URL and the digest for that release. Without a standard way to find it, the mechanism breaks down.

I think this would be done via client-side lock files and version control, similar to how it's done with, e.g., package.json and package-lock.json (especially when you specify semantic version ranges instead of exact versions).

As mentioned, the lock file would record the old URL (and digest), and could be checked into version control. Rolling back could be done the same as reverting a change to package-lock.json. That said, there are also other approaches -- e.g., checking the skills themselves into version control, or retaining a backup of the lock file instead of using version control.

Essentially, the lock file contains the snapshot of index.json that you are referring to.

@Rodriguespn

Copy link
Copy Markdown

@jonathanhefner

the lock file would record the old URL (and digest), and could be checked into version control. Rolling back could be done the same as reverting a change to package-lock.json.

This only covers the cases where the client already knows where the skills are hosted (they were installed before in that project or when the client needs to rollback to a version that has been installed in that project), but it ignores case where the client has never seen a specific agent skills version (A/B testing, evals pipeline, etc...).
Also, if I accidentally delete my lockfile, how can I discover old skill versions? If I delete my package-lock.json and run ' npm install, the pinned versions of the dependencies listed in package.jsonwill be listed in the newly generatedpackage-lock.json`.

Again, my point is not to enforce the agent skill providers to list their versions, but to include in the spec as a recommended practice so clients can easily discover skills the same way we currently discover npm or cargo packages.

PS: This discussion is about versioning and this PR is to write a spec for agent skills discoverability under a /.well-known path. Happy to open a new issue and move this discussion there if this is blocking this PR from being merged

@mm-aiva

mm-aiva commented Jul 16, 2026

Copy link
Copy Markdown

The digest field + "clients must not use unverified content" requirement here composes cleanly with content-provenance attestations, and it might be worth a sentence in the spec text saying so: the .well-known index digest covers the shipped artifact (transport integrity, rooted in domain ownership + TLS), while a signature/attestation file inside the skill directory can cover the individual files after extraction (publisher provenance, rooted in a pinned key or CI identity). The two verify independently and neither weakens the other.

We ship the second layer today as a DSSE sidecar (contextlock.dsse.json, per-file sha256+length, monotonic version, expiry - https://github.com/mindmodelai/contextlock, details in discussion #393), and it required zero changes to work alongside this proposal - the sidecar simply rides inside whatever artifact the index digests. If the companion-document route ever makes sense for attestation conventions, the precedent this PR sets for optional spec surface is exactly the right shape.

Disclosure: written with AI assistance, human-reviewed.

@olijboyd

Copy link
Copy Markdown

Coming back to this, because I think the gap this thread landed on is now closeable. You all agreed the hard part: in a decentralised setup you can't make a publisher honour a "MUST", so a versioned snapshot is only as good as the publisher's word, and as @petemounce said, that trust is easy to assert and much harder to verify. I agreed at the time that the fix wasn't ours to assert and that we weren't there yet.

We're there now. If an independent party re-fetches the index, digest-compares every pass, and signs what it actually saw at each version, then a client showing up cold has a record it can check for itself against a published key, without taking the publisher's word or mine. A rewritten snapshot stops being silent and becomes detectable by anyone, which is the property the "MUST" was reaching for. It doesn't ask publishers to host old versions or change anything in this PR, it just sits alongside as an independent witness.

I've been running this at 180k+ skills, signed and served so a cold client can pull one and verify it. It composes cleanly with the digest already in the proposal (transport integrity, rooted in the publisher's domain) and with a publisher-signed sidecar like @mm-aiva's contextlock (publisher provenance). Three independent layers, none weakening the others.

I'd like to help make the independent-witness piece real without adding anything to this PR, so I'd value your read on whether that's the right way to close the gap you've been circling here.

@snapsynapse

Copy link
Copy Markdown

The last few comments have converged on a three-layer shape: transport integrity rooted in domain + TLS (this PR's digest), publisher provenance in a signed sidecar (@mm-aiva), independent verification (@olijboyd). That layering matches what we've been running in production, so rather than propose anything new I'd like to offer two shipped implementations as prior art for whatever informative text this PR ends up carrying.

GuideCheck (guidecheck.org) is a .well-known trust artifact already in the wild: a constrained plain-text profile served at /.well-known/assistant-guide.txt, same bytes for human and agent, with a canonical URL, a sidecar manifest, and an applies-to version field. Most relevant to the last two comments: it has an independent-verifier ecosystem with a published 0–5 conformance ladder, and its explicit doctrine is "conformance is not safety." The witness role @olijboyd describes slots naturally into that frame. Verification levels are claims made by verifiers about artifacts, rooted in the verifier's key. They aren't properties of the artifact itself, and keeping that distinction in the spec text is what stops the three layers collapsing into each other.

skill-provenance is the bundle-side integrity half: MANIFEST.yaml with per-resource sha256 traveling inside the bundle, and as of 5.1.0 an optional validated_against block binding harness/model validation records to the exact bundle version (informational by design; it never gates the integrity check). It composes with this PR the same way @mm-aiva describes contextlock composing: the index digest covers the shipped artifact, the in-bundle manifest covers the files after extraction, and neither weakens the other. The in-bundle half matters for the failure mode registry-side verification can't reach. The moment a skill is pasted into a chat window, the .well-known chain is gone, and the only provenance left is what traveled inside the bundle.

The two compose today, not hypothetically: skillprovenance.dev publishes its own GuideCheck guide at /.well-known/assistant-guide.txt, so the same project is verified domain-side and pinned bundle-side through two independent mechanisms. Genuinely glad to see this conversation land here. I've been chipping away at this problem on my own for months, so thanks to everyone pushing it forward!

If it would help, I'm happy to draft a short informative paragraph naming the independently-verifying layers and where each roots its trust (domain, publisher key, verifier key). A couple of sentences of non-normative text, no new spec surface.

Disclosure: drafted with AI assistance, human-reviewed, per the contributing guidelines.

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.