> ## Documentation Index
> Fetch the complete documentation index at: https://docs.danubeai.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Validate Skill

> Check a SKILL.md and its files against the Agent Skills specification before creating or submitting

## Overview

Runs the same validation that Create Skill and Submit Skill apply, without saving anything. Use it to get structured errors and suggestions while authoring. The response is always `200`; a failing skill comes back with `valid: false` and a list of errors.

When the `skills-ref` reference validator is installed on the server it runs first. Otherwise the built-in checks apply:

* SKILL.md must start with `---` delimited YAML frontmatter.
* `name` is required, must use lowercase letters, digits and single hyphens (no leading, trailing or consecutive hyphens), must be at most 64 characters, and must equal `skill_name`.
* `description` is required, at least 20 and at most 1024 characters.
* `compatibility`, when present, at most 500 characters.
* Every file in `scripts`, `reference_files` and `assets` needs a `name`, and the name must not contain `/`, `\` or `..`.

Warnings (non-blocking) are raised when the SKILL.md body is under 10 characters or a script has empty content.

**Auth:** Accepts either JWT or API key (`danube-api-key` header).

The Python and TypeScript SDKs do not wrap this endpoint yet, and there is no MCP tool for it. Call it directly.

## Body Parameters

<ParamField body="skill_name" type="string" required>
  The expected skill name (max 64 characters). Must match `name` in the frontmatter.
</ParamField>

<ParamField body="skill_md_content" type="string" required>
  The full SKILL.md content including YAML frontmatter (max 500,000 characters)
</ParamField>

<ParamField body="scripts" type="array" default={[]}>
  Script files (max 20)

  <Expandable title="File object">
    <ParamField body="name" type="string" required>
      File name (max 255 characters, no directories)
    </ParamField>

    <ParamField body="content" type="string" default="">
      File content (max 500,000 characters)
    </ParamField>

    <ParamField body="content_type" type="string">
      MIME type, used for assets
    </ParamField>
  </Expandable>
</ParamField>

<ParamField body="reference_files" type="array" default={[]}>
  Reference files (max 20). Same file object as `scripts`.
</ParamField>

<ParamField body="assets" type="array" default={[]}>
  Asset files (max 20). Same file object as `scripts`.
</ParamField>

## Response

<ResponseField name="valid" type="boolean">
  `true` when no errors were found
</ResponseField>

<ResponseField name="errors" type="array">
  Blocking problems. Empty when `valid` is `true`.

  <Expandable title="Error object">
    <ResponseField name="field" type="string">
      Where the problem is: `skill_md_content`, `name`, `description`, `compatibility`, `scripts`, `reference_files` or `assets`
    </ResponseField>

    <ResponseField name="message" type="string">
      What is wrong
    </ResponseField>

    <ResponseField name="suggestion" type="string">
      How to fix it. May be `null`.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="warnings" type="array">
  Non-blocking notes, as strings
</ResponseField>

<ResponseField name="parsed_name" type="string">
  The `name` read from the frontmatter, or `null` if it could not be parsed
</ResponseField>

<ResponseField name="parsed_description" type="string">
  The `description` read from the frontmatter, or `null` if it could not be parsed
</ResponseField>

## Example

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST "https://api.danubeai.com/v1/skills/validate" \
    -H "danube-api-key: YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "skill_name": "pdf-processing",
      "skill_md_content": "---\nname: pdf-processing\ndescription: Extract text and tables from PDF files. Use when working with PDF documents.\n---\n\n# PDF Processing\n\n1. Parse the PDF file\n2. Extract text content\n3. Return structured data",
      "scripts": [
        {"name": "extract.py", "content": "import fitz\n\ndef extract(path):\n    doc = fitz.open(path)\n    return [p.get_text() for p in doc]"}
      ]
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json Valid theme={null}
  {
    "valid": true,
    "errors": [],
    "warnings": [],
    "parsed_name": "pdf-processing",
    "parsed_description": "Extract text and tables from PDF files. Use when working with PDF documents."
  }
  ```

  ```json Invalid theme={null}
  {
    "valid": false,
    "errors": [
      {
        "field": "name",
        "message": "Name in frontmatter 'pdf_processing' does not match provided name 'pdf-processing'.",
        "suggestion": "Change the name in frontmatter to 'pdf-processing' or update the skill name."
      },
      {
        "field": "description",
        "message": "Description is too short.",
        "suggestion": "Provide a more detailed description that explains what the skill does AND when to use it."
      }
    ],
    "warnings": [
      "Script 'extract.py' has no content."
    ],
    "parsed_name": "pdf_processing",
    "parsed_description": "Process PDFs"
  }
  ```
</ResponseExample>
