{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://tuvren.github.io/skillprism/schema/v1/skill.json",
  "title": "Skill YAML",
  "description": "Per-skill configuration file (skill.yaml) — defines a single skill's metadata and template variables. Note: this is a build-time config file, NOT the output SKILL.md frontmatter. Fields are processed internally; only the rendered template becomes SKILL.md. Whenever skill.yaml is present, including a group file that only contributes variables, the loader requires `skillprism` with value 1 (string or integer) and rejects the legacy `harnesses` key. `name` and `description` are not required: a group skill.yaml may omit them. A leaf skill that omits `name` uses its directory name; a leaf skill that omits `description` gets an empty description.",
  "type": "object",
  "properties": {
    "skillprism": {
      "description": "Manifest format version. Required. The loader accepts only the string \"1\" or the integer 1. Known limitation: integral floats such as 1.0 pass the schema but the YAML loader rejects them; use '1' or 1 without a decimal point.",
      "oneOf": [
        { "type": "string", "const": "1" },
        { "type": "integer", "const": 1 }
      ]
    },
    "name": {
      "type": ["string", "null"],
      "description": "Skill name. Optional. A group skill.yaml may omit it. A leaf skill that omits it uses the directory name. The loader does not restrict the character set or length."
    },
    "description": {
      "type": ["string", "null"],
      "description": "Brief description of what the skill does and when to use it. Optional. A group skill.yaml may omit it. A leaf skill that omits it gets an empty description."
    },
    "version": {
      "type": ["string", "null"],
      "description": "Skill version string, used internally. The loader accepts any string."
    },
    "license": {
      "type": ["string", "null"],
      "description": "License name or reference to a bundled license file (maps to SKILL.md frontmatter)"
    },
    "compatibility": {
      "type": ["string", "null"],
      "description": "Environment requirements. Indicates intended product, system packages, network access, etc. (maps to SKILL.md frontmatter). The loader accepts any string."
    },
    "required-capabilities": {
      "type": ["array", "null"],
      "items": { "type": "string" },
      "description": "Harness capabilities this skill requires (e.g., subagent, sidecar, manifest, allowed-tools). The Harness Resolver checks these against the selected harness definition and reports MissingCapability errors for any that aren't satisfied."
    },
    "metadata": {
      "type": ["object", "null"],
      "description": "Arbitrary key-value mapping for additional metadata (maps to SKILL.md frontmatter). Keys are strings, values are strings.",
      "additionalProperties": { "type": "string" }
    },
    "allowed-tools": {
      "type": ["string", "null"],
      "description": "Pre-approved tools the skill may use. The loader accepts a string only, not a YAML list. Maps to SKILL.md frontmatter."
    },
    "variables": {
      "type": ["object", "null"],
      "description": "Template variables available to SKILL.md (or SKILL.md.j2) during rendering. Structure is user-defined.",
      "additionalProperties": true
    },
    "when_to_use": {
      "type": ["string", "null"],
      "description": "Additional trigger phrases or example requests (Claude Code). Appended to description in skill listing."
    },
    "argument-hint": {
      "type": ["string", "null"],
      "description": "Autocomplete hint shown after skill name (e.g., [issue-number]) (Claude Code)"
    },
    "arguments": {
      "type": ["array", "null"],
      "items": { "type": "string" },
      "description": "Named positional arguments for $name substitution in skill content (Claude Code). The loader accepts a YAML list of strings only, not a single string."
    },
    "disable-model-invocation": {
      "type": ["boolean", "null"],
      "description": "When true, prevents agent from automatically loading this skill (Claude Code, Factory, Pi). Use for manual-only workflows. Omission leaves the field unset; the loader does not fill a default."
    },
    "user-invocable": {
      "type": ["boolean", "null"],
      "description": "When false, hides from / command menu (Claude Code, Factory). Omission leaves the field unset; the loader does not fill a default."
    },
    "disallowed-tools": {
      "type": ["array", "null"],
      "items": { "type": "string" },
      "description": "Tools removed from agent's available pool while this skill is active (Claude Code). The loader accepts a YAML list of strings only, not a single string."
    },
    "model": {
      "type": ["string", "null"],
      "description": "Model override for skill execution (Claude Code). E.g., claude-sonnet-4-20250514."
    },
    "effort": {
      "type": ["string", "null"],
      "description": "Effort level hint for skill execution (Claude Code). The loader accepts any string."
    },
    "context": {
      "type": ["string", "null"],
      "description": "Context mode string. The loader sets context forking only when the value is \"fork\"; any other string is accepted and does not enable forking."
    },
    "agent": {
      "type": ["string", "null"],
      "description": "Subagent type to use when context is set to fork (Claude Code)"
    },
    "hooks": {
      "type": ["object", "null"],
      "description": "Lifecycle hooks scoped to this skill (Claude Code). Values may be any YAML value.",
      "additionalProperties": true
    },
    "paths": {
      "type": ["array", "null"],
      "items": { "type": "string" },
      "description": "Glob patterns limiting automatic activation (Claude Code). The loader accepts a YAML list of strings only, not a single string."
    },
    "shell": {
      "type": ["string", "null"],
      "description": "Shell for command injection in this skill (Claude Code). The loader accepts any string."
    },
    "overrides": {
      "type": ["object", "null"],
      "description": "Per-harness overrides (build-time config, stripped from rendered output). Keys are harness IDs (e.g., claude, codex). The loader rejects a `harnesses` key here.",
      "additionalProperties": {
        "type": "object",
        "description": "Override variables and macros for this harness. Unknown keys are rejected.",
        "properties": {
          "variables": {
            "type": "object",
            "description": "Harness-specific variable overrides (merged with top-level variables, harness wins)",
            "additionalProperties": true
          },
          "macros": {
            "type": "object",
            "description": "Harness-specific macro overrides for this skill only. Values are strings.",
            "additionalProperties": { "type": "string" }
          }
        },
        "additionalProperties": false
      }
    }
  },
  "required": ["skillprism"],
  "additionalProperties": false
}
