Get the FREE Ultimate OpenClaw Setup Guide →

manifest-validation

Scanned
npx machina-cli add skill LiorCohen/sdd/manifest-validation --openclaw
Files (1)
SKILL.md
7.8 KB

Manifest Validation

Validates .claude-plugin/marketplace.json and plugin/.claude-plugin/plugin.json against the official Claude Code plugin specification.

Documentation Reference: Claude Code Plugins Reference Claude Code Version: 2.1.27 Schema Fetched: 2026-01-31


When to Use

  • Before committing changes to manifest files
  • After version bumps
  • When debugging plugin loading issues
  • After modifying hooks, MCP, or LSP configurations

Validation Checklist

Run through all checks in order. Stop at the first failure.

1. JSON Syntax Valid

# Both must parse without errors
jq . plugin/.claude-plugin/plugin.json > /dev/null
jq . .claude-plugin/marketplace.json > /dev/null

2. Required Fields Present

plugin.json - Must have:

FieldTypeDescription
namestringUnique identifier (kebab-case, no spaces)

marketplace.json - Must have:

FieldTypeDescription
namestringMarketplace identifier (kebab-case)
owner.namestringMaintainer name
pluginsarrayList of plugins (non-empty)

Each plugin entry - Must have:

FieldTypeDescription
namestringPlugin identifier
sourcestring|objectWhere to fetch plugin
# Check required fields
jq -e '.name' plugin/.claude-plugin/plugin.json
jq -e '.name, .owner.name, .plugins[0].name, .plugins[0].source' .claude-plugin/marketplace.json

3. Versions Match

If both files specify version, they must be identical:

PLUGIN_VER=$(jq -r '.version // empty' plugin/.claude-plugin/plugin.json)
MARKET_VER=$(jq -r '.plugins[0].version // empty' .claude-plugin/marketplace.json)
[ "$PLUGIN_VER" = "$MARKET_VER" ] && echo "OK: $PLUGIN_VER" || echo "MISMATCH: plugin=$PLUGIN_VER marketplace=$MARKET_VER"

4. Paths Start with ./

All component paths must be relative to plugin root and start with ./:

FieldExample
commands["./core/commands/sdd.md"]
skills["./core/skills/"]
mcpServers"./.mcp.json"
lspServers"./.lsp.json"
outputStyles"./styles/"
# Check all command paths start with ./
jq -r '.commands[]? // empty' plugin/.claude-plugin/plugin.json | while read -r p; do echo "$p" | grep -qE '^\./' || echo "ERROR: command path must start with ./: $p"; done

5. Referenced Files Exist

Verify files referenced by paths actually exist:

# Check command files exist
jq -r '.commands[]? // empty' plugin/.claude-plugin/plugin.json | while read -r p; do
  [ -f "plugin/${p#./}" ] || [ -d "plugin/${p#./}" ] && echo "OK: $p" || echo "ERROR: not found: plugin/${p#./}"
done

# Check skill directories exist
jq -r '.skills[]? // empty' plugin/.claude-plugin/plugin.json | while read -r p; do
  [ -d "plugin/${p#./}" ] && echo "OK: $p" || echo "ERROR: not found: plugin/${p#./}"
done

6. Source Directory Exists

Marketplace plugin source paths must point to valid directories:

SOURCE=$(jq -r '.plugins[0].source' .claude-plugin/marketplace.json)
[ -d "$SOURCE" ] && echo "OK: $SOURCE" || echo "ERROR: source directory not found: $SOURCE"

7. Name Format Valid

Names must be kebab-case (lowercase letters, numbers, hyphens):

jq -r '.name' plugin/.claude-plugin/plugin.json | grep -E '^[a-z0-9]+(-[a-z0-9]+)*$' || echo "ERROR: invalid name format"

8. No Path Traversal

Paths must not contain ../ (security restriction):

jq -r '.. | strings | select(contains("../"))' plugin/.claude-plugin/plugin.json && echo "ERROR: path traversal detected" || echo "OK: no path traversal"

Quick Full Validation

Run all checks at once:

echo "=== Manifest Validation ==="

# 1. JSON syntax
echo -n "1. JSON syntax: "
jq . plugin/.claude-plugin/plugin.json > /dev/null 2>&1 && \
jq . .claude-plugin/marketplace.json > /dev/null 2>&1 && \
echo "OK" || echo "FAIL"

# 2. Required fields
echo -n "2. Required fields: "
jq -e '.name' plugin/.claude-plugin/plugin.json > /dev/null 2>&1 && \
jq -e '.name and .owner.name and (.plugins | length > 0)' .claude-plugin/marketplace.json > /dev/null 2>&1 && \
echo "OK" || echo "FAIL"

# 3. Version match
echo -n "3. Version match: "
P=$(jq -r '.version // "none"' plugin/.claude-plugin/plugin.json)
M=$(jq -r '.plugins[0].version // "none"' .claude-plugin/marketplace.json)
[ "$P" = "$M" ] && echo "OK ($P)" || echo "FAIL (plugin=$P, marketplace=$M)"

# 4. Paths start with ./
echo -n "4. Path format: "
FAIL=0
for p in $(jq -r '.commands[]?, .skills[]?' plugin/.claude-plugin/plugin.json 2>/dev/null); do
  [[ "$p" == ./* ]] || { echo "FAIL ($p)"; FAIL=1; break; }
done
[ $FAIL -eq 0 ] && echo "OK"

# 5. Referenced files exist
echo -n "5. Files exist: "
FAIL=0
for p in $(jq -r '.commands[]?, .skills[]?' plugin/.claude-plugin/plugin.json 2>/dev/null); do
  [ -f "plugin/${p#./}" ] || [ -d "plugin/${p#./}" ] || { echo "FAIL (missing: plugin/${p#./})"; FAIL=1; break; }
done
[ $FAIL -eq 0 ] && echo "OK"

# 6. Source directory exists
echo -n "6. Source exists: "
S=$(jq -r '.plugins[0].source' .claude-plugin/marketplace.json)
[ -d "$S" ] && echo "OK ($S)" || echo "FAIL ($S not found)"

# 7. Name format
echo -n "7. Name format: "
jq -r '.name' plugin/.claude-plugin/plugin.json | grep -qE '^[a-z0-9]+(-[a-z0-9]+)*$' && \
echo "OK" || echo "FAIL"

# 8. No path traversal
echo -n "8. No traversal: "
jq -r '.. | strings' plugin/.claude-plugin/plugin.json 2>/dev/null | grep -q '\.\.' && \
echo "FAIL" || echo "OK"

echo "=== Done ==="

Schema Reference

plugin.json

{
  "name": "plugin-name",           // REQUIRED: kebab-case
  "version": "1.0.0",              // Optional: semver
  "description": "Brief desc",     // Optional
  "author": {                      // Optional
    "name": "Author Name",
    "email": "author@example.com",
    "url": "https://github.com/author"
  },
  "homepage": "https://docs.example.com",
  "repository": "https://github.com/user/plugin",
  "license": "MIT",
  "keywords": ["keyword1"],
  "commands": [                    // Array of command paths
    "./core/commands/sdd.md",
    "./core/commands/sdd-run.md"
  ],
  "skills": [                      // Array of skill directory paths
    "./core/skills/"
  ],
  "mcpServers": "./.mcp.json",
  "lspServers": "./.lsp.json",
  "outputStyles": "./styles/"
}

marketplace.json

{
  "name": "marketplace-name",      // REQUIRED: kebab-case
  "owner": {                       // REQUIRED
    "name": "Owner Name",          // REQUIRED
    "email": "contact@example.com"
  },
  "plugins": [                     // REQUIRED: non-empty array
    {
      "name": "plugin-name",       // REQUIRED
      "source": "./plugin",        // REQUIRED: path or object
      "description": "Plugin desc",
      "version": "1.0.0"
    }
  ]
}

Common Issues

IssueCauseFix
command path must start with ./Path relative to wrong directoryEnsure all paths in commands array start with ./
version mismatchForgot to update both filesRun version bump script or update both
source directory not foundWrong source pathVerify ./plugin exists
invalid name formatSpaces or uppercase in nameUse kebab-case: my-plugin
path traversal detectedUsing ../ in pathsKeep all paths within plugin root
referenced file not foundTypo or missing fileVerify path exists under plugin/

See Also

Source

git clone https://github.com/LiorCohen/sdd/blob/main/.claude/skills/manifest-validation/SKILL.mdView on GitHub

Overview

Validates plugin and marketplace manifest files against the official Claude Code plugin specification to ensure correctness before use. This helps prevent loading or integration issues by catching syntax, field, and path problems early.

How This Skill Works

The skill runs a structured checklist against plugin.json and marketplace.json. It validates JSON syntax, required fields, version alignment when present, path conventions (start with ./), referenced file and directory existence, name format, and path traversal, stopping at the first failure to surface the most actionable issue.

When to Use It

  • Before committing changes to manifest files
  • After version bumps
  • When debugging plugin loading issues
  • After modifying hooks, MCP, or LSP configurations
  • During CI pipelines or PR checks

Quick Start

  1. Step 1: Run the validation suite against plugin.json and marketplace.json
  2. Step 2: Check JSON syntax with jq for both files
  3. Step 3: Review and fix any field, path, or reference issues before commit

Best Practices

  • Run checks in the defined order and stop at the first failure
  • Use jq to validate JSON syntax for both files
  • Verify required fields and correct types (name, owner.name, plugins, etc.)
  • Ensure all paths start with ./ and reference existing files/directories
  • Check for path traversal and kebab-case name formats

Example Use Cases

  • After updating plugin.json and marketplace.json versions, run the validator to confirm alignment and references
  • A failure flag due to an invalid plugin name that doesn't follow kebab-case
  • A path in plugin.json that does not start with ./ causing a path format error
  • Detection of path traversal ../ in a path requiring security-safe references
  • Missing or non-existent referenced files or directories are flagged and must be created or corrected

Frequently Asked Questions

Add this skill to your agents
Sponsor this space

Reach thousands of developers