# Static Agent Marketplace

- **Version:** 0.1.0-draft
- **Date:** 2026-11-04
- **Status:** Editor's Draft, the first maturity stage of [GOVERNANCE.md](https://github.com/static-agent-marketplace/static-agent-marketplace-spec/blob/main/GOVERNANCE.md#maturity). Not stable; anything can change before 1.0.0.
- **Editors:** Choi Won ([@myso-kr](https://github.com/myso-kr))
- **This version:** [static-agent-marketplace.org/spec/draft/](https://static-agent-marketplace.org/spec/draft/)
- **Latest release:** none yet
- **Previous version:** none
- **Schemas:** [static-agent-marketplace.org/schemas/](https://static-agent-marketplace.org/schemas/)
- **Repository:** [static-agent-marketplace/static-agent-marketplace-spec](https://github.com/static-agent-marketplace/static-agent-marketplace-spec)
- **Feedback:** [GitHub issues](https://github.com/static-agent-marketplace/static-agent-marketplace-spec/issues)
- **License:** Copyright 2026 Static Agent Marketplace contributors. Licensed under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).

## Abstract

This document is a profile. It says how a static website, such as one served by GitHub Pages, publishes a set of agent plugins and skills so that people can browse them and agent hosts can install them. It invents no new file format and no new well-known URI. It composes four existing documents, AI Catalog, Agent Skills discovery, the Claude Code plugin marketplace and llms.txt, and adds what they leave open: a fixed place for the remaining files, one normalized catalog, a canonical archive encoding, immutable versioned paths, discovery links in HTML, and install prompts.

## Status of this document

This is an Editor's Draft of version 0.1.0, dated in the header and changed in place. It is published so that the reference implementation and other implementers can test against it; cite a release candidate or a release instead once one exists. Sections marked informative are not requirements. Where an upstream specification and this profile disagree, the upstream specification wins (section 3).

## 1. Introduction

Agent plugins and skills are usually distributed from a git repository. Many publishers instead want a plain website: the source can stay private, the site is cheap to host, and people need a page to read before they install anything. No standard covers publishing a plugin marketplace at a web URL. Several conventions cover parts of it, and each host reads a different part.

This profile gives one answer for a static site. A generator reads the publisher's existing plugin or skill tree, writes one normalized catalog, and derives every published file from that catalog. The result can be served by any static host that preserves paths and bytes.

### 1.1. Goals

- Publish one source tree so that Claude Code and Agent Skills clients install from the site URL, and other hosts install from downloaded archives.
- Let people, agents and tools find every machine-readable file from any page of the site.
- Make every archive reproducible and every published version immutable.
- Keep the source repository and its history private; the published site is the only public surface.

### 1.2. Non-goals

- A new plugin or skill format. Inputs are the formats publishers already use (section 4).
- A search service or server API. Everything here is a static file.
- Trust in the publisher. Digests detect changed bytes; they do not say who wrote them (section 13).

## 2. Conventions and terminology

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 \[[RFC2119](https://www.rfc-editor.org/rfc/rfc2119)\] \[[RFC8174](https://www.rfc-editor.org/rfc/rfc8174)\] when, and only when, they appear in all capitals, as shown here.

The Abstract, the Status of this document, the Introduction, examples and every section or annex marked "(informative)" are informative. Everything else, tables included, is normative. The text blocks of sections 5.2, 12.2 and 12.3 and the elements of section 9 are templates and are normative; the host names under `example.com` in them are examples.

The terms below are defined in the project [glossary](../../glossary/), which is the only place a term is defined; this list is generated from it. A term in italics, such as *catalog*, refers to the glossary entry.

<!-- glossary:begin (generated by tools/glossary.py from glossary/terms.json; do not edit) -->

- **Archive**: A ZIP archive in the canonical encoding of section 10.2. Its digest identifies one version of one plugin or skill.
- **Base namespace**: The configurable path, by default `/.agent-marketplace/`, that holds every published file other than the entry points. Written `<base>` in paths; it starts and ends with a slash.
- **Canonical JSON**: The single JSON serialization every generated JSON file uses: sorted keys, two-space indentation and a final newline (section 7.1).
- **Catalog**: The document `<base>catalog.json`, from which every other published file is derived (section 7.2).
- **Client**: Software that reads the published files of a site to list, download or install packages, such as a host or a skills command-line tool. A conforming client meets section 16.1.
- **Component** (from Claude Code plugin reference): One of skills, agents, commands, hooks or Model Context Protocol (MCP) servers inside a plugin.
- **Conformance case**: A directory of the conformance suite holding `case.json`, `input/`, `expected/` and `SHA256SUMS` (section 16.2).
- **Digest** (from Agent Skills discovery 0.2.0): The lowercase hexadecimal SHA-256 of an archive's bytes, written `sha256:<hex>` where an upstream format requires that form.
- **Entry document**: The file `<base>entries/<p>.json` or `<base>entries/skills/<s>.json`: one catalog item with `$schema`, `kind` and `specVersion` added (section 7.6).
- **Entry point**: A published file that a client finds by a fixed path rather than by a link (section 5).
- **External entry**: An input B marketplace entry whose source is remote. It is listed in the catalog but never fetched or packaged (section 7.7).
- **Generator**: Software that reads an input tree and parameters and writes the published files. A conforming generator meets section 16.1.
- **Host**: An application that installs plugins or skills. This profile covers Claude Code, Codex, Grok Build, Antigravity and Gemini CLI, plus clients of Agent Skills discovery.
- **Host package**: An archive or tree in a host-specific layout, produced only when requested (Annex A).
- **Install prompt**: Generated text a user can paste into their own agent to install one plugin or skill with the host's own commands (section 12).
- **Lock**: The record, kept in the source repository and never published, of every archive published under a versioned path and its digest (section 11.2).
- **Plugin** (from Claude Code plugin reference): A directory in the Claude Code plugin layout: an optional `.claude-plugin/plugin.json` plus component folders such as `skills/`, `agents/`, `commands/` and `hooks/`.
- **Plugin archive**: The archive of a whole plugin, with the plugin root at the top, used as a Claude Code archive source (section 10.1).
- **Site**: The static website the files are published on. Its origin is the scheme, host and port of `siteUrl`.
- **Skill** (from Agent Skills): A directory holding a `SKILL.md` file and any supporting files.
- **Skill archive** (from Agent Skills discovery 0.2.0): The archive of one skill with `SKILL.md` at the top, as Agent Skills discovery 0.2.0 requires (section 10.1).
- **Support level**: One of native, partial or none, saying how much of a plugin works on a host (section 7.5).
- **Well-known URI** (from RFC 8615): A URI whose path starts with `/.well-known/`, reserved for names registered with IANA.
- **Yank**: To withdraw one published version: it leaves every published document and its archives stop being served, and the lock keeps the reason (section 11.4).

<!-- glossary:end -->

In paths, `<base>` is the base namespace, `<p>` a plugin name, `<s>` a skill name and `<v>` a version. URLs written as `https://plugins.example.com/...` are examples.

## 3. Relationship to upstream specifications

This profile composes the following documents. Each is cited at the version shown.

| Document | Version used | What this profile takes from it |
|---|---|---|
| [AI Catalog](https://ai-catalog.io/spec) | draft, `specVersion` 1.0 | `/.well-known/ai-catalog.json`, entry fields, media types, `urn:air` identifiers |
| [Agent Skills discovery](https://github.com/cloudflare/agent-skills-discovery-rfc) | 0.2.0 | `/.well-known/agent-skills/index.json`, archive entries, `sha256:` digests |
| [Agent Skills](https://agentskills.io/specification) | as published | `SKILL.md` front matter, name and description limits |
| [Claude Code plugin marketplace](https://code.claude.com/docs/en/plugins/marketplace-reference) | Claude Code 2.1.224 or later | `marketplace.json`, `archive` plugin sources, plugin layout |
| [llms.txt](https://llmstxt.org/) | proposal | `/llms.txt` structure |
| [RFC 8615](https://www.rfc-editor.org/rfc/rfc8615) | | rules for `/.well-known/` names |

Rules for this relationship:

1. Upstream wins. If an upstream document and this profile conflict, the upstream document is authoritative for the files it defines, and the conflict is a defect in this profile that a later version corrects.
2. No restatement. This profile restates upstream rules only where it narrows them (for example, absolute URLs where upstream also allows relative ones). Narrowing never produces a file that upstream forbids; a rule of this profile that would is a defect in this profile.
3. Shrinking scope. When an upstream document adopts something this profile defines, a later version of this profile replaces its own text with a reference to the upstream text.
4. Extension points only. Where this profile adds data to an upstream document, it uses that document's extension mechanism (for AI Catalog, the `extensions` member; section 8.1).

## 4. Inputs

A generator reads exactly one of two input layouts, selected by the `source` parameter. Both are layouts publishers already use; this profile defines no new manifest.

### 4.1. Input A: a skills directory

The input root holds `skills/<s>/SKILL.md` for one or more skills, in the Agent Skills layout. Each skill becomes one plugin with the same name and the single skill `<s>`.

- The plugin version is the `version` parameter (section 4.3). A generator MAY read it from a package manifest instead, but the value MUST be the same for every skill of the input.
- The plugin description is the skill's `description`.
- The plugin license is the skill's `license` front matter field, or else the `license` parameter.
- The generator synthesizes a plugin manifest `.claude-plugin/plugin.json` whose content is the canonical JSON (section 7.1) of an object with exactly the members `description`, `license`, `name` and `version`.
- The plugin directory is the synthesized manifest plus every file of `skills/<s>/` at `skills/<s>/` inside the plugin.

Input A has no agents, commands, hooks or MCP servers. A publisher who needs them uses input B.

### 4.2. Input B: a Claude Code marketplace

The input root holds `.claude-plugin/marketplace.json` in the Claude Code format, with plugins in subdirectories.

- The marketplace `name`, `owner` and `metadata.description` become the catalog's `marketplace.name`, `marketplace.owner` and `marketplace.description`.
- An entry whose `source` is a relative path (`./...`) is a local plugin. The generator reads and packages it.
- An entry whose `source` is an object of type `github`, `url`, `git-subdir` or `npm` is an external plugin. The generator lists it under `external` in the catalog (section 7.7) and MUST NOT fetch or package it.
- Entries of any other source type MUST be rejected (`source-type`).
- For a local plugin, `version` is taken from `.claude-plugin/plugin.json`, else from the entry. If both are present and differ, the input MUST be rejected (`version-mismatch`). If neither is present, the input MUST be rejected (`version-missing`).
- The display fields `description`, `license`, `displayName`, `author`, `homepage`, `repository` and `keywords` are taken from the entry when present, else from `plugin.json`. `category` and `tags` are taken from the entry.
- Entry component fields (`commands`, `agents`, `skills`, `hooks`, `outputStyles`, `themes`) and `strict` are copied unchanged into the URL-mode marketplace entry (section 8.3). They do not change the plugin directory.

Components of a local plugin are found by the standard layout, relative to the plugin directory:

| Component | Found at | Recorded as |
|---|---|---|
| skills | `skills/<s>/SKILL.md` | skill names, sorted |
| agents | `agents/*.md` | paths, sorted |
| commands | `commands/**/*.md` | paths, sorted |
| hooks | `hooks/hooks.json` | one item per handler (section 7.3) |
| MCP servers | `.mcp.json` | one item per server, sorted by name |

### 4.3. Generator parameters

| Parameter | Required | Meaning |
|---|---|---|
| `source` | yes | `skills` (input A) or `marketplace` (input B) |
| `siteUrl` | yes | The site origin: `https://` plus host and optional port, no path, no trailing slash |
| `base` | yes | The base namespace path, starting and ending with `/`. Default `/.agent-marketplace/` |
| `pages` | yes | The path of human-readable pages, starting and ending with `/`. Default `/plugins/` |
| `marketplace` | input A | Object with `name`, `owner` (`{"name": ...}`) and optional `description` |
| `version` | input A | The version of every plugin (section 4.1) |
| `license` | no | Input A license when a skill has none |
| `lock` | no | The path of the lock (section 11.2) relative to the input root, when the generator is told where it is |
| `hostPackages` | yes | Annex A packages to produce: any of `codex`, `antigravity`, `gemini`, `bundle`. Can be empty |

How an implementation receives these parameters (a configuration file, command-line flags) is out of scope. The conformance suite passes them in `case.json` (section 16.2).

The entry points of section 5 are defined at the origin root. A site whose content is served under a path prefix, such as a GitHub project site at `https://owner.github.io/repo/`, cannot publish them and does not conform. Generators SHOULD warn about this and SHOULD recommend a custom domain.

### 4.4. Input validation

A generator MUST check the input before writing any file, and MUST NOT publish anything when a check fails. Each check has a rule identifier. A generator SHOULD report the identifiers of every failed check; the conformance suite compares them (section 16.2).

| Rule | Requirement |
|---|---|
| `name-format` | Every plugin, skill and marketplace name matches `^[a-z0-9]+(-[a-z0-9]+)*$` and is at most 64 characters. This is the intersection of what the supported hosts accept. |
| `name-directory` | A skill's `name` equals its directory name. A local plugin's entry `name` equals the `name` in its `plugin.json` when that file exists. |
| `name-duplicate` | No two plugins share a name, and no two skills share a name across the whole input. |
| `name-reserved` | The marketplace name, and the URL-mode name derived from it (section 8.3), is not reserved by Claude Code (for example, names starting with `claudeai`). |
| `description-length` | Every plugin and skill description is 1 to 1,024 characters. |
| `license-missing` | Every plugin has a license, as an [SPDX license expression](https://spdx.github.io/spdx-spec/v3.0.1/annexes/spdx-license-expressions/). |
| `version-format` | Every version is a [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html) version without build metadata, at most 64 characters. |
| `version-missing` | Every local plugin has a version (section 4.2). |
| `version-mismatch` | Entry and `plugin.json` versions agree (section 4.2). |
| `source-type` | Every input B entry has a supported source type (section 4.2). |
| `path-escape` | Every component path and every relative source stays inside its plugin directory and contains no `..` segment. |
| `symlink` | The input contains no symbolic links inside a plugin or skill directory. |
| `reference-closure` | Every relative link or image target in a Markdown file resolves to an existing file inside the same skill directory, for files in a skill, or inside the same plugin directory, for other files (section 13.2). |
| `portable-path` | Every file path inside a plugin meets section 10.3. |
| `case-collision` | No two paths in one plugin differ only in letter case. |
| `file-size` | No file exceeds 25 MiB, and no archive exceeds 100 MiB. |
| `lock-violation` | No published version changes content (section 11.2). |
| `frontmatter` | Every `SKILL.md` starts with YAML front matter holding `name` and `description`. |

`SKILL.md` files longer than 500 lines SHOULD produce a warning, not a failure.

## 5. Entry points

### 5.1. Fixed paths

A conforming site publishes these files at these paths, relative to the origin. They are the only files a client is expected to find without a link.

| Path | Defined by | Content | Required |
|---|---|---|---|
| `/.well-known/ai-catalog.json` | AI Catalog | section 8.1 | yes |
| `/.well-known/agent-skills/index.json` | Agent Skills discovery 0.2.0 | section 8.2 | when the catalog has at least one skill |
| `/.claude-plugin/marketplace.json` | Claude Code convention | section 8.3 | yes |
| `/llms.txt` | llms.txt | section 5.2 | yes |

Under `/.well-known/agent-skills/`, the generator MUST write only the index and the skill archives of section 10.1, at `/.well-known/agent-skills/<s>/<v>/<s>.zip`. Any other file there could collide with a skill name.

A generator MUST NOT create any other name under `/.well-known/`. RFC 8615 requires new well-known names to be registered, and this profile registers none (section 15).

### 5.2. The llms.txt section

The generator adds one section to `/llms.txt`. If the site already has an `/llms.txt`, the section is appended to it and the rest of the file is kept unchanged. If the site has none, the generator writes `# ` and the marketplace name as the first line, a blank line, and then the section.

The section is the following lines, each ended by a line feed (LF), with values substituted. The `agentSkillsIndex` line is present only when that entry point exists. One plugin line follows per plugin, sorted by name.

```text
## Agent marketplace

- [AI catalog](<aiCatalog>): every package on this site, in AI Catalog format
- [Agent skills index](<agentSkillsIndex>): skills for Agent Skills discovery clients
- [Claude Code marketplace](<claudeMarketplace>): add with /plugin marketplace add
- [Catalog](<catalog>): versions, files, digests and install prompts
- [Checksums](<sha256sums>): SHA-256 of every archive
- [<p> <v>](<entryUrl>): <description>
```

The values in angle brackets are the members of the same name in the catalog's `entryPoints` and plugin items.

## 6. The base namespace

### 6.1. Layout

Every published file other than the entry points lives under `<base>`, by default `/.agent-marketplace/`. Clients reach these files only through links from the entry points, so the path carries no meaning of its own.

| Path | Content | Section |
|---|---|---|
| `<base>catalog.json` | the catalog | 7.2 |
| `<base>SHA256SUMS` | digests of every archive | 10.4 |
| `<base>entries/<p>.json` | one plugin entry | 7.6 |
| `<base>entries/skills/<s>.json` | one skill entry | 7.6 |
| `<base>dist/plugins/<p>/<v>/<p>.zip` | plugin archive | 10.1 |
| `<base>dist/skills/<s>/<v>/<s>.claude-ai.zip` | Claude app upload archive | 10.1 |
| `<base>tree/` | host tree (only with `hostPackages`) | Annex A |
| `<base>dist/<v>/market.zip` and `<base>dist/plugins/<p>/<v>/<p>.<host>.zip` | host packages (only with `hostPackages`) | Annex A |

The default name starts with a dot so that it cannot collide with paths of human-written pages, in the same way as `/.claude-plugin/`. It is not a well-known URI and is not registered.

### 6.2. Configuration

A publisher can choose another `base`. The generator MUST refuse a `base` that is, or is inside, `/.well-known/` or `/.claude-plugin/`, and MUST refuse to overwrite a file of the site that it did not generate. A client MUST NOT assume the default; it follows the links in the entry points.

## 7. Catalog and entry documents

### 7.1. Canonical JSON

Every JSON file this profile defines or generates, including the upstream documents of section 8 and the manifest of section 4.1, MUST be serialized as canonical JSON, a subset of [JSON](https://www.rfc-editor.org/rfc/rfc8259):

- [UTF-8](https://www.rfc-editor.org/rfc/rfc3629) without a byte order mark.
- Object members sorted by key, comparing keys as sequences of Unicode code points.
- Two spaces of indentation per level; one member or array item per line; `": "` between key and value; empty arrays as `[]` and empty objects as `{}`.
- Strings escape only `"`, `\`, and control characters; `\b`, `\f`, `\n`, `\r` and `\t` use their short forms, other control characters use `\u00XX` with lowercase hex. Non-ASCII characters and `/` are written as is.
- Numbers are integers without exponent or leading zeros.
- The file ends with a single LF.

This is the output of Python's `json.dumps(value, indent=2, sort_keys=True, ensure_ascii=False)` followed by a newline. Canonical JSON makes the files of two conforming generators byte-identical for the same input, which the conformance suite relies on.

All URLs inside generated JSON MUST be absolute `https` [URLs](https://www.rfc-editor.org/rfc/rfc3986) built from `siteUrl`. Some hosts do not resolve relative URLs.

### 7.2. The catalog

`<base>catalog.json` is the single source of every other output. Its schema is [`catalog.schema.json`](../../schemas/draft/catalog.schema.json), a [JSON Schema 2020-12](https://json-schema.org/draft/2020-12) document like every schema of this profile.

| Member | Content |
|---|---|
| `$schema` | `https://static-agent-marketplace.org/schemas/draft/catalog.schema.json` |
| `specVersion` | `0.1.0-draft` |
| `generator` | OPTIONAL. `name`, `version` and optional `url` of the implementation. Omitted in conformance runs |
| `marketplace` | `name`, `owner`, optional `description`, and `url`: `siteUrl` plus `/` |
| `entryPoints` | absolute URLs: `aiCatalog`, `agentSkillsIndex` (when there are skills), `claudeMarketplace`, `llmsTxt`, `catalog`, `sha256sums` |
| `plugins` | plugin items (section 7.3), sorted by name |
| `skills` | skill items (section 7.4), sorted by name |
| `external` | external entries (section 7.7), sorted by name |
| `bundle` | the Annex A bundle package, present only when produced |

A client MUST compare `$schema` as an opaque string. It need not fetch it.

### 7.3. Plugin items

| Member | Content |
|---|---|
| `name`, `version`, `description`, `license` | from the input (section 4) |
| `displayName`, `author`, `homepage`, `repository`, `keywords`, `category`, `tags` | present only when the input has them |
| `lifecycle` | present only for deprecated plugins (section 11.4) |
| `components` | `skills`, `agents`, `commands`, `hooks` and `mcpServers`, each an array, empty when absent |
| `hosts` | support level per host (section 7.5) |
| `files` | every member of the plugin archive: `path`, `bytes`, `sha256`, `mode` (`0644` or `0755`), sorted by path |
| `packages` | `claudeArchive` (section 10.1), plus Annex A packages when produced. Each package has `url`, `sha256` and `bytes` |
| `install` | `prompts`, with at least `claude` (section 12) |
| `pageUrl` | `siteUrl` + `pages` + `<p>/` |
| `entryUrl` | the URL of the plugin's entry document |

Each hook item is one handler of `hooks/hooks.json`, visiting events in sorted order, then matcher groups and handlers in file order. It has `event`, `type`, and when present in the input `matcher`, `command`, `url` and `timeout`.

Each MCP server item has `name`, `env` (the sorted names of its environment variables) and, when present, `command` or `url`. A generator MUST NOT copy environment variable values, headers or arguments that could hold credentials.

### 7.4. Skill items

| Member | Content |
|---|---|
| `name`, `description` | from the skill's `SKILL.md` |
| `version`, `license` | from the plugin that holds the skill |
| `plugin` | the name of that plugin |
| `files` | every member of the skill archive, as in section 7.3 |
| `packages` | `skillArchive` and `claudeAiUpload` (section 10.1) |
| `install` | `prompts`, with at least `agent-skills` (section 12) |
| `pageUrl` | `siteUrl` + `pages` + `<p>/skills/<s>/` |
| `entryUrl` | the URL of the skill's entry document |

### 7.5. Host support levels

`hosts` gives each host one of `native` (every component works), `partial` (some components do not work on that host) or `none` (no component works). A component is unsupported on a host when it appears in that host's row below. The level is `native` if the plugin has no unsupported component, `none` if it has components and all of them are unsupported, and `partial` otherwise.

| Host | Unsupported components |
|---|---|
| Claude Code | none |
| Grok Build | none (it reads Claude Code plugins) |
| Codex | agents, commands, hooks |
| Antigravity | commands, hooks |
| Gemini CLI | agents; hooks whose event is not one of `PreToolUse`, `PostToolUse`, `SessionStart`, `SessionEnd`, `UserPromptSubmit`, `Stop`, `PreCompact`, `Notification` |

These rows summarize the host formats as of this draft and change with them; Annex A gives the detail.

### 7.6. Entry documents

For every plugin item, the generator writes `<base>entries/<p>.json`; for every skill item, `<base>entries/skills/<s>.json`. An entry document is the item with three members added: `$schema` (`https://static-agent-marketplace.org/schemas/draft/entry.schema.json`), `kind` (`plugin` or `skill`) and `specVersion`. Nothing else is added or removed. Its schema is [`entry.schema.json`](../../schemas/draft/entry.schema.json).

An entry document is the machine-readable form of the page that describes the same package, and the page links it (section 9).

### 7.7. External entries

An external entry has `name`, `source` copied from the input, and `description` and `version` when the input has them. The generator lists it so that the catalog is complete, but it produces no archive, file list, entry document or install prompt for it, and does not list it in the upstream documents of section 8.

## 8. Upstream documents

### 8.1. AI Catalog

`/.well-known/ai-catalog.json` is an AI Catalog document with `specVersion` `1.0`, a `host` with `displayName` set to the owner name, and these entries:

| Entry | `identifier` | `type` | `url` | Other members |
|---|---|---|---|---|
| each skill | `urn:air:<host>:skill:<s>` | `application/agent-skills+zip` | the skill archive | `description`, `digest`, `version` |
| each plugin | `urn:air:<host>:plugin:<p>` | `application/zip` | the plugin archive | `description`, `digest`, `version`, profile extension with role `claude-plugin-archive` |
| the catalog | `urn:air:<host>:catalog:<marketplace>` | `application/json` | `<base>catalog.json` | `description`, profile extension with role `catalog` and `specVersion` |
| the Claude marketplace | `urn:air:<host>:claude-marketplace:<name>` | `application/json` | `/.claude-plugin/marketplace.json` | `description`, profile extension with role `claude-marketplace` |

`<host>` is the host name of `siteUrl`. `digest` is `sha256:` followed by the lowercase hex digest of the archive. Entries are sorted by `identifier`, then `version`.

The profile extension is the `extensions` member `https://static-agent-marketplace.org/extensions/profile`, an object whose `role` says what the entry points at. The descriptions of the catalog and Claude marketplace entries are `Static Agent Marketplace catalog with versions, files and digests.` and `Claude Code plugin marketplace with archive sources.`

A Claude Code plugin archive is not an Agent Plugins bundle, so it is not typed `application/agent-plugins+zip`. When Annex A packages are produced, a generator MAY add Agent Plugins entries for them.

### 8.2. Agent Skills discovery index

`/.well-known/agent-skills/index.json` follows Agent Skills discovery 0.2.0: `$schema` is `https://schemas.agentskills.io/discovery/0.2.0/schema.json`, and `skills` has one item per skill, sorted by name, with `name`, `description`, `type` `archive`, `url` (the absolute URL of the skill archive) and `digest`.

### 8.3. Claude Code marketplace

`/.claude-plugin/marketplace.json` is a Claude Code marketplace for URL mode, in which Claude Code downloads only this file. Every plugin therefore uses an `archive` source.

- `name` is the marketplace name followed by `-pages`, so that it never collides with the git-mode marketplace of the same publisher in a user's settings.
- `owner` is the catalog owner; `metadata.description` is the marketplace description when there is one.
- `plugins` has one item per plugin, sorted by name, with `name`, `version`, `source` `{"source": "archive", "url": ..., "sha256": ...}`, the display fields of section 7.3 that the plugin has, and the entry fields copied under section 4.2.

Claude Code 2.1.224 or later is needed for archive sources. Claude Code checks `sha256` before installing.

## 9. Head discovery links

Every [HTML](https://html.spec.whatwg.org/multipage/) page of the site SHOULD carry these elements in its `head`, in this order, with absolute `href` values. A link whose target was not generated is omitted.

```html
<link rel="alternate" type="text/plain" title="llms.txt" href="https://plugins.example.com/llms.txt">
<link rel="alternate" type="application/ai-catalog+json" title="AI catalog" href="https://plugins.example.com/.well-known/ai-catalog.json">
<link rel="alternate" type="application/json" title="Agent skills" href="https://plugins.example.com/.well-known/agent-skills/index.json">
<link rel="alternate" type="application/json" title="Claude plugin marketplace" href="https://plugins.example.com/.claude-plugin/marketplace.json">
```

A page that describes one plugin or one skill SHOULD also carry a link to its entry document, with title `<p> entry` or `<s> skill entry`:

```html
<link rel="alternate" type="application/json" title="safe-shell entry" href="https://plugins.example.com/.agent-marketplace/entries/safe-shell.json">
```

These links use `rel="alternate"`, the relation llms.txt uses for a page's Markdown version (`type="text/markdown"`). They sit next to that link as siblings that differ only in `type` and `title`. Attribute values are HTML-escaped. Every page is a valid place to start discovery, which matters because a static host such as GitHub Pages cannot add HTTP `Link` headers.

AI Catalog also defines a `rel="ai-catalog"` link relation. A page MAY carry it in addition.

A page about a package SHOULD also describe it with a [schema.org `SoftwareApplication`](https://schema.org/SoftwareApplication) object in [JSON-LD](https://www.w3.org/TR/json-ld11/) whose `softwareVersion` and `downloadUrl` match the entry. `rel="alternate"` is not used for archives, which are not another representation of the page.

## 10. Archives and digests

### 10.1. Three archive shapes

Hosts expect different layouts, so each package is published in the shape its reader expects.

| Archive | Path | Top level of the archive | Read by |
|---|---|---|---|
| Plugin archive | `<base>dist/plugins/<p>/<v>/<p>.zip` | the plugin root (`.claude-plugin/`, `skills/`, ...) | Claude Code `archive` source |
| Skill archive | `/.well-known/agent-skills/<s>/<v>/<s>.zip` | the skill root (`SKILL.md`, ...) | Agent Skills discovery clients |
| Claude app upload | `<base>dist/skills/<s>/<v>/<s>.claude-ai.zip` | one folder `<s>/` holding the skill | manual upload to the Claude apps |

The members of a plugin archive are the files of the plugin directory (section 4). The members of a skill archive are the files of `skills/<s>/` with that prefix removed. The members of a Claude app upload archive are the skill archive members with the prefix `<s>/` added.

### 10.2. Canonical encoding

Every archive MUST be encoded exactly as follows, so that any two implementations produce the same bytes from the same members.

1. ZIP format as described by the [PKWARE APPNOTE](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT), without ZIP64, encryption, data descriptors, extra fields, comments or directory entries.
2. Members ordered by path, comparing UTF-8 bytes.
3. Every member stored without compression (method 0).
4. Every local header: version needed 20, flags 0, method 0, modification time 0x0000 and date 0x0021 (1980-01-01 00:00:00), CRC-32, compressed and uncompressed size equal, name length, extra length 0.
5. Every central directory header: version made by 0x0314 (Unix, 2.0), version needed 20, flags 0, method 0, the same time, date, CRC-32 and sizes, extra, comment and disk number 0, internal attributes 0, external attributes equal to the Unix mode `0100644` or `0100755` shifted left by 16 bits, and the offset of the local header.
6. One end of central directory record with disk numbers 0, both entry counts equal, the central directory size and offset, and no comment.

Stored entries cost size but remove every dependence on a compression library, which would otherwise make archives differ between implementations (see [Reproducible builds: archives](https://reproducible-builds.org/docs/archives/)). Text-heavy plugins are usually small; section 4.4 caps archives at 100 MiB.

### 10.3. Members, paths and modes

- Paths use `/` and are relative to the archive root. Each segment matches `^[A-Za-z0-9._-]+$` and is not `.` or `..`; the whole path is at most 240 characters. Segments MUST NOT be Windows device names (`CON`, `PRN`, `AUX`, `NUL`, `COM1` to `COM9`, `LPT1` to `LPT9`, with or without an extension).
- Only regular files are members. Empty directories are not represented.
- The mode is `0755` when the input file is executable (git mode `100755`) and `0644` otherwise.
- Member bytes are the input bytes unchanged, with the single exception of the manifest synthesized for input A.

### 10.4. SHA256SUMS

`<base>SHA256SUMS` lists every archive the site publishes, including retained earlier versions (section 11.3), one per line: the lowercase hex [SHA-256](https://doi.org/10.6028/NIST.FIPS.180-4), two spaces, and the path relative to the origin root without a leading slash. Lines are sorted by path, comparing UTF-8 bytes, and each ends with LF. This is the format [GNU `sha256sum`](https://www.gnu.org/software/coreutils/manual/html_node/sha2-utilities.html) reads, so a user who mirrors the site can check it with `sha256sum -c SHA256SUMS` from the mirror root.

The same digest appears in the catalog (`sha256`), in the AI Catalog and Agent Skills index (`digest`), and in the Claude Code marketplace (`sha256`). A generator MUST write the same value in every place.

## 11. Versioning, the lock and yank

### 11.1. Immutable versioned paths

Every archive path contains the package version. Once an archive has been published at a path, the bytes at that path MUST NOT change. A content change needs a new version. The *catalog* and the other JSON documents can change on every publication; archives cannot.

Static hosts cache responses (GitHub Pages sends `max-age=600`). A client can therefore see an older catalog for a few minutes; because archive paths are immutable, every URL that older catalog names still serves the bytes it describes.

### 11.2. The lock

The generator keeps a lock: a record of every archive it has published, with its digest. The lock lives in the source repository, is updated by the generator and is never published. Its format is [`lock.schema.json`](../../schemas/draft/lock.schema.json). The file name is implementation-defined; `agent-marketplace.lock.json` is RECOMMENDED. When the `lock` parameter is given, the generator reads the lock from that path.

Before publishing, the generator compares every archive it is about to publish with the lock. If an archive path is already in the lock with a different digest, the generator MUST stop (`lock-violation`). After a successful publication it records new archives in the lock. Canonical archives (section 10.2) make this check meaningful: the same input always gives the same digest.

### 11.3. Retained versions

Some static hosts replace the whole site on each deployment. To keep earlier versions available, a generator SHOULD rebuild the archives of the last few versions of each package (RECOMMENDED: 3) from the source revision of that version, and MUST check each rebuilt archive against the lock. Retained archives are listed in `SHA256SUMS`; the catalog and the upstream documents list only the current version.

### 11.4. Removal, yank and deprecation

- Removal. A package that leaves the input disappears from every published document. The lock keeps its releases with `removed: true`.
- Yank. A publisher withdraws one version, for example after a security problem, by adding `yanked` with a reason to its lock release. A yanked version is removed from every published document and its archives are no longer served. If the yanked version is the newest, the newest non-yanked version becomes current. A page about the package SHOULD show the reason.
- Deprecation. A plugin whose `plugin.json` sets `metadata.lifecycle` to `deprecated` stays published with `lifecycle` `{"status": "deprecated"}` in its item, plus `replacedBy` and `note` when `metadata.replacedBy` and `metadata.lifecycleNote` are present. Install prompts for a deprecated plugin SHOULD say so.

Removing a version is always allowed; changing one is not. Rolling back to an earlier source revision therefore works.

## 12. Install prompts

### 12.1. Purpose and rules

An install prompt is text a user can paste into their own agent so that the agent installs one package. It is an alternative to typing commands. Install prompts are stored in `install.prompts` of each item ([`install-prompt.schema.json`](../../schemas/draft/install-prompt.schema.json)).

- The generator writes prompts from the catalog by the templates below; they are never written by hand, so their commands, URLs, versions and digests always match the catalog.
- Prompts use only the host's own install commands. They MUST NOT ask the agent to download and run a script, to pipe a download into a shell, or to run any command other than those listed.
- When a package can run code (hooks, MCP servers, or skill files under `scripts/`), the prompt MUST ask the agent to show what will run and wait for the user's approval, and `requiresApproval` is `true`.
- Prompts are in English whatever the page language; a page MAY add a one-line explanation in its own language.

The prompt object has `host`, `text` (lines joined by LF, no trailing LF), `commands` (the commands in `text`, in order), `sha256` (of the archive installed) and `requiresApproval`.

### 12.2. Claude Code prompt

For each plugin, `install.prompts.claude` has `commands` `/plugin marketplace add <claudeMarketplace>` and `/plugin install <p>@<name>`, where `<name>` is the marketplace name of section 8.3, and this `text`:

```text
Install the "<p>" plugin, version <v>, for Claude Code.
1. Run: /plugin marketplace add <claudeMarketplace>
2. Run: /plugin install <p>@<name>
3. Before enabling it, show me its hooks (<events>) and MCP servers (<servers>) and wait for my approval.
The plugin archive sha256 is <sha256>. Stop if Claude Code reports a different digest.
Do not run any other download or shell command.
```

Line 4 is present only when the plugin has hooks or MCP servers. `<events>` is the sorted, distinct hook event names and `<servers>` the sorted server names, each joined by `, `, or `none` when empty.

### 12.3. Agent Skills prompt

For each skill, `install.prompts.agent-skills` has the single command `npx skills add <siteUrl>` and this `text`:

```text
Install the "<s>" skill, version <v>, with the skills CLI.
1. Run: npx skills add <siteUrl>
2. When it lists the skills on that site, select only "<s>".
3. Before using it, show me the files in its scripts folder and wait for my approval.
The skill archive sha256 is <sha256>. Stop if the CLI reports a digest mismatch.
Do not run any other download or shell command.
```

Line 4 is present only when the skill has files under `scripts/`.

Prompts for hosts that install from a downloaded archive are defined in Annex A.5, and exist only when the matching host packages are produced.

## 13. Security considerations

### 13.1. Everything published is public

A static site is public even when its source repository is private. Every file in every archive, including scripts and hook commands, is readable by anyone. Generators SHOULD take an explicit allow list of what to publish rather than publish the whole repository, and SHOULD scan generated files for secrets and for names the publisher has marked as internal before publishing.

### 13.2. Reference closure

A skill or plugin can link to files outside its directory, for example internal documents. Publishing those files automatically would leak them; publishing the link alone would break it. The `reference-closure` rule (section 4.4) therefore makes such a link an error. The generator MUST NOT resolve it by copying the target.

### 13.3. Code that runs on install or use

Hooks, MCP servers and skill scripts run on the user's machine. A page about a package MUST NOT execute any of them. It SHOULD show, for each hook, the event, matcher, command, timeout and whether the host can block on it, and SHOULD let the user read the script files it calls. Hosts differ: Antigravity ignores a failing hook, Grok Build blocks only on `PreToolUse` with a 5 second default timeout, and Codex runs plugin hooks only for manually installed desktop plugins. Pages SHOULD state such differences. Install prompts require explicit approval for these packages (section 12.1).

### 13.4. Integrity

Every archive is pinned by SHA-256 in several documents (section 10.4). Claude Code and Agent Skills clients verify the digest before installing. For hosts that install from a downloaded archive, the user or the agent has to compare the digest with the catalog or `SHA256SUMS`; install prompts say so.

A digest proves that bytes are unchanged, not who produced them. A site that is compromised can change archives and digests together. Publishers who need provenance can add build attestations for archives; they are outside this profile.

### 13.5. Archive extraction

A client that extracts an archive MUST reject members with absolute paths, `..` segments or links. It SHOULD cap the extracted size. Canonical archives never contain them, so a member that does is a sign of tampering.

### 13.6. Install prompts

An install prompt is input to an agent, and a hostile page could try to inject instructions through it. Users are advised to take prompts only from the site that publishes the package. An agent that receives a prompt is expected to treat its text as a request from the user, not as authority, and to refuse commands outside the host's install commands; this profile does not define agents, so this is advice, not a requirement. The fixed templates of section 12 keep legitimate prompts short and checkable.

### 13.7. Well-known URIs

Whoever can write to `/.well-known/` of an origin can speak for it. On shared hosts, publishers are advised to make sure no other party can write files to the site.

### 13.8. Threats considered and residual risk

This section adds no requirement. It records which attacks the profile addresses and which it leaves open, as [RFC 3552](https://www.rfc-editor.org/rfc/rfc3552) asks of a security considerations section.

- Eavesdropping and modification in transit. Every URL in generated JSON is an absolute `https` URL (section 7.1), so the profile relies on TLS between the site and the client. It signs nothing itself.
- A compromised site or source repository. Out of scope: whoever controls the site can change archives and every digest together (section 13.4).
- Replay of older documents. A cache, a mirror or an attacker that serves an older catalog or marketplace file can lead a client to an older version. Its archive digest still matches, so the client installs genuine but older bytes, which can include a yanked version when its archive is still served from elsewhere. The profile has no freshness or rollback protection beyond the short cache lifetime of section 11.1.
- Malicious content. A package can contain hooks, MCP servers and scripts that act against the user. The profile does not judge content; it makes that code visible on pages and in prompts and asks for approval (sections 12.1 and 13.3).
- Prompt injection. Install prompts are text for an agent (section 13.6); a hostile page can imitate them. The fixed templates make a legitimate prompt recognizable but do not authenticate it.
- Denial of service. Input validation caps file and archive sizes (section 4.4), and clients cap extraction (section 13.5). The size of the catalog and the number of packages are not bounded.

## 14. Privacy considerations

Published files contain only what the input contains plus digests and URLs. Generators MUST NOT add download counters, tracking parameters or analytics to generated files or URLs.

The rest of this section adds no requirement; it follows the questions of [RFC 6973](https://www.rfc-editor.org/rfc/rfc6973).

- Data published. Catalogs, entry documents and marketplace files copy the input's names, descriptions and display fields, including `author`, `homepage` and `repository`. An `author` object can hold a person's name and email address, which every visitor and crawler can then read. Publishers are advised to review these fields before publishing.
- Observers. The static host and any content delivery network in front of it see every request for the entry points and archives, with the client's IP address and user agent. The profile cannot hide that a client fetched a given package; it only keeps the published files free of identifiers of their own.
- Identifiers. Generated files carry no per-user or per-download identifier. The optional `generator` member names the implementation and its version.
- Retention. The lock, which records every published version and the reason for each yank, stays in the source repository and is never published (section 11.2).

## 15. IANA considerations

This document has no IANA actions. The section is kept, as [RFC 8126](https://www.rfc-editor.org/rfc/rfc8126) recommends, so that readers see that nothing is requested.

It uses `/.well-known/ai-catalog.json` and `/.well-known/agent-skills/`, which are defined, and proposed for registration, by their own specifications. It defines no media type and no link relation; the media types in sections 8.1 and 9 are those of the upstream documents.

## 16. Conformance

### 16.1. Conformance classes

- A conforming generator, given an input and parameters, either writes exactly the files of sections 5 to 10 with the content those sections define, byte for byte, or rejects the input under section 4.4 and writes nothing.
- A conforming site serves the files a conforming generator wrote, at their paths and with their bytes. It SHOULD serve `.json` as `application/json` and `.zip` as `application/zip`, and SHOULD allow cross-origin reads. The requirements on pages in sections 9, 11.4, 12.1 and 13.3 apply to the HTML pages of a conforming site.
- A conforming *client* meets the requirements on clients in sections 6.2, 7.2 and 13.5. This profile places no other requirement on how a client lists or installs packages; the hosts' own documents govern that.

Annex A outputs are OPTIONAL. A generator that produces them still conforms when `hostPackages` is empty and it produces none.

### 16.2. Conformance suite

The suite lives in `conformance/<version>/` of the specification repository. Each case is a directory:

- `case.json`: identifier, description, the sections it exercises, `level` (`required` or `optional`), `expect` (`accept` or `reject`), `rules` for reject cases, and the generator `parameters` ([`case.schema.json`](../../schemas/draft/case.schema.json)).
- `input/`: the input tree.
- `expected/`: for accept cases, every file the generator writes, at its path relative to the origin root, plus `_fragments/` with the llms.txt section (`llms-section.md`) and the head links (`head-site.html`, `head-plugin-<p>.html`, `head-skill-<s>.html`). For reject cases, only `rejection.json` with the expected rule identifiers.
- `SHA256SUMS`: the digest of every file under `expected/`.

An implementation passes an accept case when it writes exactly the files under `expected/`, outside `_fragments/`, with identical bytes, and produces the fragments when asked. It passes a reject case when it writes nothing and reports at least the listed rules. A conformance claim names the suite version and passes every `required` case.

The suite tests generators only. A case whose `parameters` name a `lock` holds that lock in `input/`; a case without it has no lock, whatever file name an implementation uses by default (section 11.2).

### 16.3. Schemas and prose

The JSON Schemas of a version describe the structure of the documents that version defines. Where a schema and the prose differ, the prose governs. A schema is never stricter than the prose: a document that meets the prose validates against its schema, and a schema that rejects such a document is a defect in the schema. A schema can be looser, because some rules, such as sort order, digests and canonical form, are not expressed in JSON Schema.

## 17. Implementation notes (informative)

- Both build paths give the same site. On GitHub Pages a site can be built by the classic branch build (the `github-pages` gem, Jekyll 3.10, safe mode) or by a GitHub Actions workflow. A generator that runs before Jekyll, and writes its output into the site source, works with both: the classic path commits the output, the Actions path writes it just before the build. An implementation is expected to give byte-identical sites through both paths, and to check this in its own CI. This is a condition on implementations, not on the format.
- Jekyll skips paths that start with a dot. Sites need `include: [.well-known, .claude-plugin, .agent-marketplace]` (and `.agents`, `.antigravity-plugin` for Annex A trees). Actions deployments with `actions/upload-pages-artifact` also need `include-hidden-files: true`, or the dot directories are dropped silently. Do not add `.nojekyll`, which turns off the classic build.
- Files with YAML front matter, such as `SKILL.md`, are rendered by Jekyll. A generator has to make sure the published bytes are the input bytes, for example by serving them from a path Jekyll copies unchanged, and is advised to check the built site.
- GitHub Pages limits a site to 1 GB and a deployment to 10 minutes. A generator can warn well before the size limit and keep the number of retained versions small.
- The reference implementation is [jekyll-theme-modootoday](https://github.com/modootoday/jekyll-theme-modootoday).

## Annex A. Per-host packaging (informative)

This annex describes the optional *host packages* for hosts that cannot install from a URL. Host formats change often; the host documentation is authoritative: [Agent Plugins 1.0](https://agent-plugins.org/), [Codex plugins](https://developers.openai.com/codex/plugins/build), [Antigravity plugins](https://antigravity.google/docs/plugins), [Gemini CLI extensions](https://geminicli.com/docs/extensions/reference/) and [Grok Build plugins](https://docs.x.ai/build/features/skills-plugins-marketplaces).

### A.1. Host tree

With any `hostPackages`, the generator writes `<base>tree/`, a marketplace tree in which each plugin carries every host's manifest side by side:

```text
.claude-plugin/marketplace.json      relative sources (Claude Code, Grok Build, Codex fallback)
.agents/plugins/marketplace.json     Codex; local sources only
plugins/<p>/
  .claude-plugin/plugin.json         input
  plugin.json                        Agent Plugins 1.0 (Codex)
  .antigravity-plugin/plugin.json    Antigravity; takes precedence over plugin.json
  gemini-extension.json              Gemini CLI
  skills/  agents/                   input, shared
  commands/*.md                      input (Claude Code)
  commands/*.toml                    Gemini CLI
  hooks/hooks.json                   input (Claude Code event names)
  hooks.json                         Antigravity
  .mcp.json                          input (Claude Code)
  mcp.json                           Agent Plugins
  mcp_config.json                    Antigravity
```

Codex skips `github` and `archive` sources, so the tree's marketplace files use relative sources only. The URL-mode marketplace of section 8.3 is a different file with a different name.

### A.2. Field mapping

| Input (`.claude-plugin/plugin.json`) | Agent Plugins / Codex | Antigravity | Gemini CLI |
|---|---|---|---|
| `name` | `name` | `name` | `name` |
| `displayName` | `extensions["com.openai"].interface.displayName` | `displayName` | not carried |
| `version`, `description` | same | same | same |
| `author`, `homepage`, `repository`, `license`, `keywords` | same | same | not carried |
| `skills/` | `skills/` | `skills/` | `skills/` |
| `agents/*.md` | not carried | `agents/` | `agents/*.md` (preview) |
| `commands/*.md` | not carried | not carried | converted to `commands/*.toml` |
| `hooks/hooks.json` | `extensions["com.openai"].hooks` | root `hooks.json` | `hooks/hooks.json`, renamed events, timeouts in ms |
| `.mcp.json` | `mcp.json` | `mcp_config.json`, servers named `<p>_<server>` | `mcpServers` in the manifest |

### A.3. Hook events

| Claude Code | Codex | Antigravity | Gemini CLI | Grok Build |
|---|---|---|---|---|
| `PreToolUse` | `PreToolUse` | `PreToolUse` | `BeforeTool` | `PreToolUse` |
| `PostToolUse` | `PostToolUse` | `PostToolUse` | `AfterTool` | `PostToolUse` |
| `SessionStart` | `SessionStart` | `SessionStart` | `SessionStart` | `SessionStart` |
| `SessionEnd` | `SessionEnd` | not carried | `SessionEnd` | `SessionEnd` |
| `UserPromptSubmit` | `UserPromptSubmit` | not verified | `BeforeAgent` | `UserPromptSubmit` |
| `Stop` | `Stop` | `Stop` | `AfterAgent` | `Stop` |
| `PreCompact` | `PreCompact` | not carried | `PreCompress` | `PreCompact` |
| `Notification` | not carried | not carried | `Notification` | `Notification` |

Events without a counterpart are left out of that host's package, and the page says the hook does not run there.

### A.4. Host archives

| Archive | Path | Content |
|---|---|---|
| Antigravity | `<base>dist/plugins/<p>/<v>/<p>.antigravity.zip` | the plugin root with the Antigravity files |
| Gemini CLI | `<base>dist/plugins/<p>/<v>/<p>.gemini.zip` | the plugin root with the Gemini CLI files |
| Bundle | `<base>dist/<v>/market.zip` | all of `<base>tree/`, where `<v>` is the catalog publication version |

They use the encoding of section 10.2 and are listed in `SHA256SUMS`, in `packages` (`antigravityArchive`, `geminiArchive`) and in the catalog `bundle`.

### A.5. Local install prompts

For a host that installs from a local path, the prompt asks the agent to download the archive, compare its SHA-256 with the catalog value and stop on a mismatch, extract it, and run the host's own install command: `codex plugin marketplace add ./market` for Codex, `agy plugin install ./<p>` for Antigravity, `gemini extensions install ./<p>` for Gemini CLI, and `--plugin-dir ./market/plugins/<p>` for Grok Build. Exact templates will be defined once each path has been tested against the host.

## Annex B. Example (informative)

A minimal catalog for one skill-only plugin; the conformance suite has complete, byte-exact examples.

```json
{
  "$schema": "https://static-agent-marketplace.org/schemas/draft/catalog.schema.json",
  "entryPoints": {
    "aiCatalog": "https://plugins.example.com/.well-known/ai-catalog.json",
    "catalog": "https://plugins.example.com/.agent-marketplace/catalog.json",
    "claudeMarketplace": "https://plugins.example.com/.claude-plugin/marketplace.json",
    "llmsTxt": "https://plugins.example.com/llms.txt",
    "sha256sums": "https://plugins.example.com/.agent-marketplace/SHA256SUMS"
  },
  "external": [],
  "marketplace": {
    "name": "example-market",
    "owner": {
      "name": "Example Publisher"
    },
    "url": "https://plugins.example.com/"
  },
  "plugins": [],
  "skills": [],
  "specVersion": "0.1.0-draft"
}
```

## Annex C. References

Normative:

- \[AGENT-SKILLS\] [Agent Skills specification](https://agentskills.io/specification), as published.
- \[AGENT-SKILLS-DISCOVERY\] [Agent Skills discovery via well-known URIs](https://github.com/cloudflare/agent-skills-discovery-rfc), version 0.2.0.
- \[AI-CATALOG\] [AI Catalog](https://ai-catalog.io/spec), draft, `specVersion` 1.0.
- \[APPNOTE\] [PKWARE APPNOTE](https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT), the ZIP format.
- \[CLAUDE-CODE-MARKETPLACE\] [Claude Code plugin marketplace reference](https://code.claude.com/docs/en/plugins/marketplace-reference), Claude Code 2.1.224 or later.
- \[FIPS180-4\] NIST, [Secure Hash Standard (SHS)](https://doi.org/10.6028/NIST.FIPS.180-4), FIPS PUB 180-4, August 2015.
- \[HTML\] WHATWG, [HTML Living Standard](https://html.spec.whatwg.org/multipage/).
- \[JSON-LD\] W3C, [JSON-LD 1.1](https://www.w3.org/TR/json-ld11/), Recommendation, July 2020.
- \[JSON-SCHEMA\] [JSON Schema 2020-12](https://json-schema.org/draft/2020-12), core and validation vocabularies.
- \[LLMS-TXT\] [llms.txt](https://llmstxt.org/), proposal.
- \[RFC2119\] S. Bradner, [Key words for use in RFCs to Indicate Requirement Levels](https://www.rfc-editor.org/rfc/rfc2119), BCP 14, RFC 2119, March 1997.
- \[RFC3629\] F. Yergeau, [UTF-8, a transformation format of ISO 10646](https://www.rfc-editor.org/rfc/rfc3629), STD 63, RFC 3629, November 2003.
- \[RFC3986\] T. Berners-Lee, R. Fielding and L. Masinter, [Uniform Resource Identifier (URI): Generic Syntax](https://www.rfc-editor.org/rfc/rfc3986), STD 66, RFC 3986, January 2005.
- \[RFC8174\] B. Leiba, [Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words](https://www.rfc-editor.org/rfc/rfc8174), BCP 14, RFC 8174, May 2017.
- \[RFC8259\] T. Bray, [The JavaScript Object Notation (JSON) Data Interchange Format](https://www.rfc-editor.org/rfc/rfc8259), STD 90, RFC 8259, December 2017.
- \[RFC8615\] M. Nottingham, [Well-Known Uniform Resource Identifiers (URIs)](https://www.rfc-editor.org/rfc/rfc8615), RFC 8615, May 2019.
- \[SCHEMA-ORG\] [schema.org `SoftwareApplication`](https://schema.org/SoftwareApplication).
- \[SEMVER\] [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0.html).
- \[SPDX\] [SPDX license expressions](https://spdx.github.io/spdx-spec/v3.0.1/annexes/spdx-license-expressions/), SPDX Specification 3.0.1, Annex B.

Informative:

- \[AGENT-PLUGINS\] [Agent Plugins 1.0](https://agent-plugins.org/).
- \[ANTIGRAVITY\] [Antigravity plugins](https://antigravity.google/docs/plugins).
- \[CODEX\] [Codex plugins](https://developers.openai.com/codex/plugins/build).
- \[GEMINI-CLI\] [Gemini CLI extensions](https://geminicli.com/docs/extensions/reference/).
- \[GH-PAGES\] [GitHub Pages limits](https://docs.github.com/en/pages/getting-started-with-github-pages/github-pages-limits).
- \[GNU-SHA256SUM\] [GNU `sha256sum`](https://www.gnu.org/software/coreutils/manual/html_node/sha2-utilities.html), GNU Coreutils manual.
- \[GROK-BUILD\] [Grok Build plugins](https://docs.x.ai/build/features/skills-plugins-marketplaces).
- \[REFERENCE-IMPLEMENTATION\] [jekyll-theme-modootoday](https://github.com/modootoday/jekyll-theme-modootoday), the reference implementation.
- \[REPRO-ARCHIVES\] [Reproducible builds: archives](https://reproducible-builds.org/docs/archives/).
- \[RFC3552\] E. Rescorla and B. Korver, [Guidelines for Writing RFC Text on Security Considerations](https://www.rfc-editor.org/rfc/rfc3552), BCP 72, RFC 3552, July 2003.
- \[RFC6973\] A. Cooper et al., [Privacy Considerations for Internet Protocols](https://www.rfc-editor.org/rfc/rfc6973), RFC 6973, July 2013.
- \[RFC8126\] M. Cotton, B. Leiba and T. Narten, [Guidelines for Writing an IANA Considerations Section in RFCs](https://www.rfc-editor.org/rfc/rfc8126), BCP 26, RFC 8126, June 2017.

## Annex D. Changes

- 0.1.0-draft: first editor's draft.
