Skill Definition Format v1
A skill is a single JSON document — the manifest. It declares the skill's identity, its input/output contract, the capabilities it needs, and how to run it. Hosts (marketplaces, agent runtimes, the CLI) read this document and nothing else to decide whether a skill is installable, runnable, and safe.
#Top-level fields
| Field | Type | Req. | Description |
|---|---|---|---|
| name | string | REQUIRED | Lowercase slug identifying the skill. ^[a-z0-9]([a-z0-9-]{0,62}[a-z0-9])?$, max 64 chars. |
| version | string | REQUIRED | Semver 2.0.0, no leading v. Example: "1.2.0". |
| description | string | REQUIRED | Human-readable summary. Recommended 20–280 characters. |
| inputs | object | REQUIRED | Schema object describing accepted input. See schemas. |
| outputs | object | REQUIRED | Schema object describing produced output. See schemas. |
| permissions | string[] | OPTIONAL | Capability tokens the skill needs. Omitted = [] (fully sandboxed). |
| runtime | object | OPTIONAL | Engine version, timeouts, memory, env vars. See runtime. |
| examples | object[] | OPTIONAL | Input/output pairs. Recommended — doubles as test fixtures. |
| author | string | OPTIONAL | Author or org name. Recommended for listings. |
| license | string | OPTIONAL | SPDX identifier, e.g. "MIT". Defaults to UNLICENSED on publish. |
| tags | string[] | OPTIONAL | Search keywords, lowercase. Max 10. |
#Identity: name, version, description
##name
The skill's slug. Lowercase ASCII letters, digits, and single hyphens; must start and end with an alphanumeric; max 64 characters. Names are namespaced per publisher on marketplaces, so acme/web-search and you/web-search can coexist — the bare name here is the unqualified slug.
// valid
"web-search" // ✓
"pdf2md" // ✓ digits fine
"a" // ✓ single char ok
// invalid — validator rejects these
"Web-Search" // ✗ uppercase
"web_search" // ✗ underscore
"-web-search" // ✗ leading hyphen
"web--search" // ✗ double hyphen
##version
Strict semver 2.0.0: MAJOR.MINOR.PATCH with optional pre-release and build metadata. No leading v — that's a display convention, not part of the version. Pre-release versions (e.g. 2.0.0-beta.1) install only with an explicit --pre flag. Versions below 0.1.0 are treated as drafts and hidden from marketplace search.
##description
One or two sentences a human would read in a listing. Must be non-blank. Under 20 characters or over 280 triggers a warning: short descriptions rank poorly, long ones get truncated in cards.
#Schemas: inputs & outputs
Both fields are schema objects in a JSON-Schema-like dialect. The shape is always:
{
"type": "object", // conventional; enforced by convention, not by type error
"required": ["query"], // every entry MUST exist in properties — else error
"properties": {
"query": {
"type": "string", // required per property (warning if missing)
"description": "The search query.",
"minLength": 1
},
"limit": {
"type": "integer",
"default": 5, // applied by hosts when the caller omits the field
"minimum": 1, "maximum": 50
},
"format": {
"type": "string",
"enum": ["json", "markdown"] // must be a non-empty array
},
"filters": {
"type": "array",
"items": { "type": "string" } // warning if omitted on arrays
}
}
}
##Allowed property types
| Type | JSON value | Notes |
|---|---|---|
| string | "text" | Supports minLength, maxLength, pattern (ECMA regex), format. |
| number | 3.14 | Any JSON number. minimum / maximum supported. |
| integer | 42 | Must have no fractional part at runtime. |
| boolean | true | — |
| array | […] | Declare items; minItems / maxItems supported. |
| object | {…} | May nest properties recursively. |
| null | null | Explicit nullability marker. |
Unknown type strings are errors (there is no guessing). A required entry that names a property not declared in properties is an error. Missing type on a property is a warning.
#Permissions
Capabilities are deny-by-default. A skill that doesn't declare permissions runs fully sandboxed: no network, no filesystem, no subprocesses. Declare only what you need — least privilege isn't just good hygiene, it determines your review lane on publish.
| Permission | Grants | Review |
|---|---|---|
| net.http | Outbound HTTPS requests | automatic |
| net.websocket | Outbound WebSocket connections | automatic |
| fs.read | Read files under the skill workspace | automatic |
| fs.write | Write files under the skill workspace | manual |
| exec | Spawn subprocesses | manual |
| env.read | Read environment variables declared in runtime.env | automatic |
| env.write | Modify the process environment | manual |
| clock | Wall-clock time | automatic |
| random | CSPRNG randomness | automatic |
| kv.read / kv.write | Skill-scoped key/value store | automatic |
"net.htp" grants nothing, so the linter flags anything outside the known list.#Runtime requirements
Optional hints to the host about how to execute the skill. All fields optional; hosts apply their own caps (marketplace defaults: 5 min timeout, 2048 MB memory).
| Field | Type | Description |
|---|---|---|
| engine | string | Version range, e.g. "skill-engine>=0.4". Hosts refuse to run on incompatible engines. |
| timeout_ms | number | Max wall-clock run time. Positive; warn above 300000. |
| memory_mb | number | Memory request. Positive; warn above 2048. |
| env | string[] | Environment variable names the skill may read (with env.read). Use UPPER_SNAKE_CASE. |
#Examples
An array of { name, input, output } objects. input and output must be objects. Examples are user documentation and machine fixtures: skill test runs each example's input and diffs the output. Give every example a descriptive name — unnamed examples draw a warning.
"examples": [
{
"name": "basic query",
"input": { "query": "agentskills spec", "limit": 3 },
"output": { "results": [ … ], "took_ms": 812 }
}
]
#Metadata: author, license, tags
Optional but recommended. author is a display string shown on listings. license should be an SPDX identifier (MIT, Apache-2.0); publishing without one marks the skill UNLICENSED (private). tags are lowercase search keywords, max 10.
#Full annotated example
{
"name": "web-search", // slug — lowercase, hyphenated
"version": "1.2.0", // semver, no leading v
"description": "Searches the public web and returns ranked results with titles, URLs, and snippets.",
"author": "Acme Labs",
"license": "MIT",
"tags": ["web", "search", "research"],
"inputs": { // what the caller provides
"type": "object",
"required": ["query"],
"properties": {
"query": { "type": "string", "minLength": 1 },
"limit": { "type": "integer", "default": 5, "minimum": 1, "maximum": 50 }
}
},
"outputs": { // what the skill returns
"type": "object",
"required": ["results"],
"properties": {
"results": {
"type": "array",
"items": { "type": "object" }
}
}
},
"permissions": ["net.http"], // least privilege: only outbound HTTPS
"runtime": {
"engine": "skill-engine>=0.4",
"timeout_ms": 15000,
"memory_mb": 256
},
"examples": [
{
"name": "basic query",
"input": { "query": "agentskills spec", "limit": 3 },
"output": { "results": [], "took_ms": 812 }
}
]
}
Paste this into the validator → — it passes with zero errors and zero warnings.
#Validation rules summary
| Severity | Rule |
|---|---|
| ERROR | Top level is not a JSON object |
| ERROR | Missing name, version, description, inputs, or outputs |
| ERROR | name fails the slug pattern or exceeds 64 chars |
| ERROR | version is not semver 2.0.0 (or has a leading v) |
| ERROR | description blank or not a string |
| ERROR | inputs/outputs not objects; required names a missing property; unknown property type |
| ERROR | permissions/tags not arrays of strings; runtime not an object; bad timeout_ms/memory_mb |
| ERROR | examples entries missing input/output objects |
| WARNING | Missing author, license, examples, or property types |
| WARNING | description shorter than 20 or longer than 280 chars; version is 0.0.x; unknown permission tokens |
| WARNING | runtime exceeds host caps; duplicate permissions; non-UPPER_SNAKE env names |
Exit codes follow the same split: the CLI's skill validate exits 0 on pass (even with warnings) and 1 on any error. See the CLI reference.