You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Proposal: keep the top level for the spec, put extensions in metadata with Kubernetes-style prefixed keys
#618
The spec today says only "We recommend making your key names reasonably unique to avoid accidental conflicts." That leaves every client to invent its own convention, and in practice several have skipped metadata entirely. Goose uses top-level author, version, and tags. Claude Code defines its own top-level fields.
This proposal tries to settle all of the above with one rule.
Proposal
The top level of the frontmatter is reserved for fields defined by the Agent Skills spec. Clients and authors must not add new top-level fields.
Every extension goes in metadata, under a prefixed key, using the same syntax as Kubernetes labels and annotations:
prefix/name, where prefix is a DNS subdomain the author or client controls (for example io.modelcontextprotocol/ or example.com/).
name is at most 63 characters, starts and ends with an alphanumeric character, and may contain -, _, and . in between.
Keys without a prefix are reserved for the skill author's private use, and clients should not depend on them.
A field moves to the top level only after it has proven itself as a prefixed key, ideally across more than one client. Promotion must say which form wins when both are present, and how long the prefixed form stays supported.
Values stay strings. Structured values are encoded (for example as JSON) inside the string.
Example:
---
name: pdf-processingdescription: Extract text and tables from PDF files.metadata:
author: example-orgexample.com/hooks: '["pre-tool-use"]'io.modelcontextprotocol/test-marker: "true"example.com/source: "https://github.com/example/skills"
---
Why Kubernetes is the right model
Kubernetes has run this exact pattern for about a decade, across a very large ecosystem of independent vendors, without coordination.
A fixed envelope with an open extension map. Every Kubernetes object has the same top-level shape (apiVersion, kind, metadata, spec, status). Vendors do not add top-level fields; they add prefixed keys to metadata.annotations. The core schema stayed stable while the ecosystem grew around it.
Domain prefixes prevent collisions without a registry. Owning a domain is owning a namespace, so nobody has to coordinate names. kubernetes.io/ and k8s.io/ are reserved for the core project, which is what point 3 above does for agentskills.io/.
Annotation first, field later. Kubernetes incubates features as annotations and promotes them to real fields only after they prove themselves:
kubernetes.io/ingress.class became spec.ingressClassName.
The seccomp.security.alpha.kubernetes.io/* annotations became securityContext.seccompProfile.
The container.apparmor.security.beta.kubernetes.io/* annotations became securityContext.appArmorProfile.
Each promotion came with a rule for which form wins and a deprecation window. That is the process point 4 asks for.
String values are deliberate. Annotations are map[string]string. Structured data is encoded, for example kubectl.kubernetes.io/last-applied-configuration holds a JSON document. Every parser stays trivial, and no client has to agree on a type system for someone else's data.
Why an open top level hurts the spec
It spends names the spec may need later. If clients use top-level version, author, or tags with different meanings, the spec can never standardize those names cleanly. It inherits every conflicting meaning already in use. Prefixed keys leave the plain names free for the spec to define.
Readers and validators cannot tell spec fields from vendor fields. With a closed top level, anything unprefixed at the top is standard by construction.
It is hard to undo. CONTRIBUTING notes that it is much easier to add to a specification than to remove from it. A top-level field that clients ship can effectively never be removed. A prefixed key in metadata can be ignored, deprecated, or promoted.
It costs almost nothing.metadata already exists and is already the documented place for extensions. This proposal adds a key syntax and a promotion rule; it adds no new fields.
Addressing the main objections
"Nesting under metadata is less pleasant to write" (the main argument in Open frontmatter schema (with namespacing guidance) #211): one level of nesting is the price of a stable core. Kubernetes users make the same trade on every object.
"Existing top-level extensions would become non-conforming": they can be grandfathered with a deprecation window, and clients can read both forms during the transition, the same way Kubernetes handled each annotation-to-field promotion.
Spec change if accepted
A small edit to the metadata field section of docs/specification.mdx: replace "We recommend making your key names reasonably unique" with the key syntax above, reserve agentskills.io/, state that new top-level fields are reserved for the spec, and describe the promotion rule. #546 could be folded into the same change.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Problem
Several threads are each solving the same question: where do fields that the spec does not define go, and how are they named?
x-prefix (closed in favor of Open frontmatter schema (with namespacing guidance) #211).{AGENT_NAME}-or nested under{AGENT_NAME}:.io.modelcontextprotocol/prefix insidemetadata.metadatavalues are strings only, because shipping runtimes already store nested maps, booleans, and lists there.metadata.activation) and [Proposal]: Add an optional source field under metadata for update tracking of manually installed skills #564 (metadata.source) each pick their own unprefixed key insidemetadata.The spec today says only "We recommend making your key names reasonably unique to avoid accidental conflicts." That leaves every client to invent its own convention, and in practice several have skipped
metadataentirely. Goose uses top-levelauthor,version, andtags. Claude Code defines its own top-level fields.This proposal tries to settle all of the above with one rule.
Proposal
metadata, under a prefixed key, using the same syntax as Kubernetes labels and annotations:prefix/name, whereprefixis a DNS subdomain the author or client controls (for exampleio.modelcontextprotocol/orexample.com/).nameis at most 63 characters, starts and ends with an alphanumeric character, and may contain-,_, and.in between.agentskills.io/is reserved for the spec itself. The MCP reservation in docs: reserve the io.modelcontextprotocol/ key prefix in the metadata map #546 becomes one instance of the general rule instead of a special case.Example:
Why Kubernetes is the right model
Kubernetes has run this exact pattern for about a decade, across a very large ecosystem of independent vendors, without coordination.
A fixed envelope with an open extension map. Every Kubernetes object has the same top-level shape (
apiVersion,kind,metadata,spec,status). Vendors do not add top-level fields; they add prefixed keys tometadata.annotations. The core schema stayed stable while the ecosystem grew around it.Domain prefixes prevent collisions without a registry. Owning a domain is owning a namespace, so nobody has to coordinate names.
kubernetes.io/andk8s.io/are reserved for the core project, which is what point 3 above does foragentskills.io/.Annotation first, field later. Kubernetes incubates features as annotations and promotes them to real fields only after they prove themselves:
kubernetes.io/ingress.classbecamespec.ingressClassName.seccomp.security.alpha.kubernetes.io/*annotations becamesecurityContext.seccompProfile.container.apparmor.security.beta.kubernetes.io/*annotations becamesecurityContext.appArmorProfile.Each promotion came with a rule for which form wins and a deprecation window. That is the process point 4 asks for.
String values are deliberate. Annotations are
map[string]string. Structured data is encoded, for examplekubectl.kubernetes.io/last-applied-configurationholds a JSON document. Every parser stays trivial, and no client has to agree on a type system for someone else's data.Why an open top level hurts the spec
version,author, ortagswith different meanings, the spec can never standardize those names cleanly. It inherits every conflicting meaning already in use. Prefixed keys leave the plain names free for the spec to define.metadatacan be ignored, deprecated, or promoted.metadataalready exists and is already the documented place for extensions. This proposal adds a key syntax and a promotion rule; it adds no new fields.Addressing the main objections
metadatais less pleasant to write" (the main argument in Open frontmatter schema (with namespacing guidance) #211): one level of nesting is the price of a stable core. Kubernetes users make the same trade on every object.Spec change if accepted
A small edit to the
metadatafield section ofdocs/specification.mdx: replace "We recommend making your key names reasonably unique" with the key syntax above, reserveagentskills.io/, state that new top-level fields are reserved for the spec, and describe the promotion rule. #546 could be folded into the same change.cc @jonathanhefner (#211, #192) and @tobi-oye (#546), since this would overlap with both.
All reactions