home / skills / terrylica / cc-skills / plugin-validator

This skill validates Claude Code plugins structure, detects silent failures in hooks, and ensures plugin.json correctness to prevent release risks.

npx playbooks add skill terrylica/cc-skills --skill plugin-validator

Review the files below or copy the command above to add this skill to your agents.

Files (3)
SKILL.md
4.9 KB
---
name: plugin-validator
description: Validate plugin structure and silent failures. TRIGGERS - plugin validation, check plugin, hook audit.
allowed-tools: Read, Bash, Glob, Grep, TodoWrite
---

# Plugin Validator

Comprehensive validation for Claude Code marketplace plugins.

## When to Use This Skill

Use this skill when:

- Validating plugin structure before release
- Auditing hooks for silent failures
- Checking plugin.json syntax and required fields
- Verifying skill file formatting and frontmatter

## Quick Start

```bash
# Validate a specific plugin
uv run plugins/plugin-dev/skills/plugin-validator/scripts/audit_silent_failures.py plugins/my-plugin/

# Validate with fix suggestions
uv run plugins/plugin-dev/skills/plugin-validator/scripts/audit_silent_failures.py plugins/my-plugin/ --fix
```

## Validation Phases

### Phase 1: Structure Validation

Check plugin directory structure:

```bash
/usr/bin/env bash << 'VALIDATE_EOF'
PLUGIN_PATH="${1:-.}"

# Check plugin.json exists
if [[ ! -f "$PLUGIN_PATH/plugin.json" ]]; then
    echo "ERROR: Missing plugin.json" >&2
    exit 1
fi

# Validate JSON syntax
if ! jq empty "$PLUGIN_PATH/plugin.json" 2>/dev/null; then
    echo "ERROR: Invalid JSON in plugin.json" >&2
    exit 1
fi

# Check required fields
REQUIRED_FIELDS=("name" "version" "description")
for field in "${REQUIRED_FIELDS[@]}"; do
    if ! jq -e ".$field" "$PLUGIN_PATH/plugin.json" >/dev/null 2>&1; then
        echo "ERROR: Missing required field: $field" >&2
        exit 1
    fi
done

echo "Structure validation passed"
VALIDATE_EOF
```

### Phase 2: Silent Failure Audit

**Critical Rule**: All hook entry points MUST emit to stderr on failure.

Run the audit script:

```bash
uv run plugins/plugin-dev/skills/plugin-validator/scripts/audit_silent_failures.py plugins/my-plugin/
```

#### What Gets Checked

| Check         | Target Files | Pattern                                |
| ------------- | ------------ | -------------------------------------- |
| Shellcheck    | `hooks/*.sh` | SC2155, SC2086, etc.                   |
| Silent bash   | `hooks/*.sh` | `mkdir\|cp\|mv\|rm\|jq` without `if !` |
| Silent Python | `hooks/*.py` | `except.*: pass` without stderr        |

#### Hook Entry Points vs Utility Scripts

| Location                 | Type        | Requirement          |
| ------------------------ | ----------- | -------------------- |
| `plugins/*/hooks/*.sh`   | Entry point | MUST emit to stderr  |
| `plugins/*/hooks/*.py`   | Entry point | MUST emit to stderr  |
| `plugins/*/scripts/*.sh` | Utility     | Fallback behavior OK |
| `plugins/*/scripts/*.py` | Utility     | Fallback behavior OK |

### Phase 3: Fix Patterns

#### Bash: Silent mkdir

```bash
# BAD - silent failure
mkdir -p "$DIR"

# GOOD - emits to stderr
if ! mkdir -p "$DIR" 2>&1; then
    echo "[plugin] Failed to create directory: $DIR" >&2
fi
```

#### Python: Silent except pass

```python
# BAD - silent failure
except (json.JSONDecodeError, OSError):
    pass

# GOOD - emits to stderr
except (json.JSONDecodeError, OSError) as e:
    print(f"[plugin] Warning: {e}", file=sys.stderr)
```

## Integration with /plugin-dev:create

This skill is invoked in Phase 3 of the plugin-add workflow:

```markdown
### 3.4 Plugin Validation

**MANDATORY**: Run plugin-validator before registration.

Task with subagent_type="plugin-dev:plugin-validator"
prompt: "Validate the plugin at plugins/$PLUGIN_NAME/"
```

## Exit Codes

| Code | Meaning                             |
| ---- | ----------------------------------- |
| 0    | All validations passed              |
| 1    | Violations found (see output)       |
| 2    | Error (invalid path, missing files) |

## References

- [Silent Failure Patterns](./references/silent-failure-patterns.md)

---

## Troubleshooting

| Issue                        | Cause                         | Solution                                            |
| ---------------------------- | ----------------------------- | --------------------------------------------------- |
| plugin.json not found        | Missing manifest file         | Create plugin.json with required fields             |
| Invalid JSON syntax          | Malformed plugin.json         | Run `jq empty plugin.json` to find syntax errors    |
| Missing required field       | Incomplete manifest           | Add name, version, description to plugin.json       |
| Shellcheck errors            | Bash script issues            | Run `shellcheck hooks/*.sh` to see details          |
| Silent failure in bash       | Missing error handling        | Add `if !` check around mkdir/cp/mv/rm commands     |
| Silent except:pass in Python | Missing stderr output         | Add `print(..., file=sys.stderr)` before pass       |
| Exit code 2                  | Invalid path or missing files | Verify plugin path exists and has correct structure |
| Violations after --fix       | Fix suggestions not applied   | Manually apply suggested fixes from output          |

Overview

This skill validates plugin structure and detects silent failure patterns in hook entry points for Claude Code marketplace plugins. It enforces manifest correctness, required fields, and that hooks emit errors to stderr on failure. Use it as a gated check before registering or releasing a plugin.

How this skill works

The validator runs three phases: structure validation, silent-failure audit, and fix-pattern suggestions. It checks plugin.json exists and parses as JSON, verifies required fields, scans hooks for silent shell operations and bare except/pass patterns in Python, and flags entry-point scripts that do not emit to stderr. Optionally it can output suggested fixes but does not auto-apply destructive changes.

When to use it

  • Before releasing or registering a plugin to the marketplace
  • When auditing plugin hooks to prevent silent failures at runtime
  • During CI to catch manifest or syntax errors early
  • Before merging plugin changes that add or modify hooks
  • When preparing a plugin for semantic version bump or deployment

Best practices

  • Ensure plugin.json includes name, version, and description and passes JSON linting
  • Treat hooks/* as entry points: always emit errors to stderr on failure
  • Use explicit error checks for shell commands (if ! cmd ...; then echo >&2 ...) instead of relying on silent defaults
  • Avoid bare except: pass in Python; log or print exceptions to stderr with context
  • Run the validator in CI with exit-on-failure to prevent silent regressions

Example use cases

  • CI pipeline step that validates plugins/NEW_PLUGIN before merge
  • Pre-release checklist to ensure hooks report failures and manifest is valid
  • Developer running a local audit to find silent mkdir/cp/mv invocations in hooks
  • Audit that differentiates entry-point hooks (must emit stderr) from utility scripts (fallback behavior allowed)
  • Inspecting a plugin after refactor to ensure exception handling still reports errors

FAQ

What exit codes should I expect?

0 means all validations passed, 1 means violations were found, and 2 indicates an error such as an invalid path or missing files.

Can the validator automatically fix issues?

It provides fix suggestions for common patterns (e.g., wrapping mkdir in if ! ... and printing exceptions to stderr) but does not apply destructive fixes automatically; review suggested changes before committing.