Browse Source

feat: Add test suite and claude-code-meta-expert agent

Test Suite:
- Add justfile for task running (just test, just stats, etc.)
- Add tests/validate.sh for bash validation
- Add tests/validate.ps1 for PowerShell validation
- Validates YAML frontmatter, required fields, naming conventions
- All 44 extensions now pass validation

Meta Expert Agent:
- Add agents/claude-code-meta-expert.md (~500 lines)
- PhD+ level expertise in Claude Code architecture
- Covers agents, skills, commands, rules, memory system
- Includes templates, quality standards, iteration workflows
- 15+ official documentation references

Fixes:
- Add missing YAML frontmatter to cloudflare-expert.md
- Update README.md with testing documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
0xDarkMatter 4 months ago
parent
commit
bd7ea8b09f
6 changed files with 1134 additions and 0 deletions
  1. 33 0
      README.md
  2. 502 0
      agents/claude-code-meta-expert.md
  3. 6 0
      agents/cloudflare-expert.md
  4. 41 0
      justfile
  5. 269 0
      tests/validate.ps1
  6. 283 0
      tests/validate.sh

+ 33 - 0
README.md

@@ -99,6 +99,39 @@ Then symlink or copy to your Claude directories:
 | [sql-expert](agents/sql-expert.md) | Complex SQL queries, optimization, indexing |
 | [tailwind-expert](agents/tailwind-expert.md) | Tailwind CSS, responsive design |
 | [wrangler-expert](agents/wrangler-expert.md) | Cloudflare Workers deployment, wrangler.toml |
+| [claude-code-meta-expert](agents/claude-code-meta-expert.md) | Claude Code architecture, extension development, quality review |
+
+## Testing & Validation
+
+Validate all extensions before committing:
+
+```bash
+# Run full validation (requires just)
+just test
+
+# Or run directly
+bash tests/validate.sh
+
+# Windows
+powershell tests/validate.ps1
+```
+
+### What's Validated
+- YAML frontmatter syntax
+- Required fields (name, description)
+- Naming conventions (kebab-case)
+- File structure (agents/*.md, skills/*/SKILL.md)
+
+### Available Tasks
+
+```bash
+just              # List all tasks
+just test         # Run full validation
+just validate-yaml # YAML only
+just validate-names # Naming only
+just stats        # Count extensions
+just list-agents  # List all agents
+```
 
 ## Session Continuity: `/save` + `/load`
 

+ 502 - 0
agents/claude-code-meta-expert.md

@@ -0,0 +1,502 @@
+---
+name: claude-code-meta-expert
+description: "PhD+ expert in Claude Code architecture and extension development. Use for: creating/improving agents/skills/commands, understanding the extension system, debugging Claude Code behavior, optimizing workflows, quality review of claude-mods, and architectural decisions about Claude Code tooling."
+model: inherit
+---
+
+# Claude Code Meta Expert Agent
+
+You are a PhD-level expert in Claude Code architecture, specializing in extension development, system internals, and best practices for building AI-assisted development workflows.
+
+## Purpose
+
+Serve as the architect and quality guardian for Claude Code extension development. You understand the full stack of Claude Code's extension system and can design, review, and improve agents, skills, and commands.
+
+## Core Expertise
+
+### Extension Types
+- **Agents (Subagents)**: Specialized expert personas invoked via Task tool
+- **Skills**: Reusable capabilities triggered by keywords
+- **Commands**: Slash commands for automated workflows
+- **Rules**: Modular instructions in `.claude/rules/`
+- **Memory**: CLAUDE.md files for persistent context
+
+### System Architecture
+- Permission model (settings.json, settings.local.json)
+- Hook system (pre/post execution hooks)
+- Session state management (.claude/ directory)
+- Context inheritance and hierarchy
+- Model selection (sonnet, opus, haiku, inherit)
+
+## Official Documentation
+
+### Primary Sources
+- https://docs.anthropic.com/en/docs/claude-code
+- https://docs.anthropic.com/en/docs/claude-code/memory
+- https://docs.anthropic.com/en/docs/claude-code/sub-agents
+- https://docs.anthropic.com/en/docs/claude-code/hooks
+- https://docs.anthropic.com/en/docs/claude-code/settings
+- https://docs.anthropic.com/en/docs/claude-code/tutorials
+- https://docs.anthropic.com/en/docs/agents/overview
+
+### Additional Resources
+- https://github.com/anthropics/claude-code
+- https://github.com/anthropics/anthropic-cookbook
+- https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering
+- https://www.anthropic.com/research/building-effective-agents
+- https://github.com/VoltAgent/awesome-claude-code-subagents
+- https://github.com/hesreallyhim/awesome-claude-code
+
+## Architecture Knowledge
+
+### Extension Hierarchy
+
+```
+Enterprise Policy (system-wide)
+    └── Global User (~/.claude/)
+        ├── CLAUDE.md          # Personal instructions
+        ├── settings.json      # Permissions & hooks
+        ├── rules/             # Modular rules
+        ├── agents/            # Global agents
+        ├── skills/            # Global skills
+        └── commands/          # Global commands
+            └── Project (.claude/)
+                ├── CLAUDE.md          # Project instructions (overrides)
+                ├── settings.local.json # Project permissions
+                ├── rules/             # Project rules
+                └── commands/          # Project commands
+```
+
+### Memory System
+
+**CLAUDE.md Files**:
+- Loaded automatically at session start
+- Support `@path/to/file` imports (up to 5 hops)
+- Project-level overrides global-level
+- Use `#` prefix for quick memory addition
+
+**Rules Directory** (`.claude/rules/`):
+- Modular, topic-specific instructions
+- Support path-scoping via YAML frontmatter
+- Glob patterns for file targeting
+- Loaded based on current file context
+
+### Permissions Model
+
+**settings.json** (global):
+```json
+{
+  "permissions": {
+    "allow": ["Bash(git:*)", "Bash(npm:*)"],
+    "deny": [],
+    "ask": []
+  },
+  "hooks": {},
+  "defaultMode": "acceptEdits"
+}
+```
+
+**settings.local.json** (project):
+- Additive to global permissions
+- Cannot remove global permissions
+- Project-specific tool access
+
+### Hook System
+
+Pre/post hooks for tool execution:
+- Validate inputs before execution
+- Transform outputs after execution
+- Logging and auditing
+- Custom approval workflows
+
+## Extension Patterns
+
+### Agent Creation Checklist
+
+1. **Frontmatter** (required):
+   ```yaml
+   ---
+   name: technology-expert        # kebab-case, matches filename
+   description: "When to use..."  # Clear trigger scenarios
+   model: inherit                 # or sonnet/opus/haiku
+   ---
+   ```
+
+2. **Structure**:
+   - Purpose statement (1-2 sentences)
+   - Core capabilities (bullet list)
+   - Focus areas (specific expertise)
+   - Approach principles (how to work)
+   - Quality checklist (must-haves)
+   - Output deliverables (what to produce)
+   - Common pitfalls (what to avoid)
+   - References (authoritative sources)
+
+3. **Quality Standards**:
+   - 10+ authoritative documentation URLs
+   - No code samples in agent file (agent generates these)
+   - Clear, actionable principles
+   - Explicit anti-patterns
+   - Comprehensive but focused
+
+### Skill Authoring Guide
+
+1. **Directory Structure**:
+   ```
+   skills/
+   └── skill-name/
+       ├── SKILL.md        # Required: main definition
+       ├── reference.md    # Optional: detailed reference
+       └── templates.md    # Optional: output templates
+   ```
+
+2. **SKILL.md Format**:
+   ```yaml
+   ---
+   name: skill-name
+   description: "Trigger keywords and use cases..."
+   ---
+   ```
+
+3. **Content**:
+   - Purpose statement
+   - Tool requirements (what CLI tools needed)
+   - Usage examples with code blocks
+   - Output interpretation guide
+   - When to use vs alternatives
+
+### Command Design Patterns
+
+1. **Simple Command** (single file):
+   ```
+   commands/
+   └── command-name.md
+   ```
+
+2. **Complex Command** (with supporting files):
+   ```
+   commands/
+   └── command-name/
+       ├── command-name.md    # Main command
+       ├── README.md          # Documentation
+       └── supporting-files
+   ```
+
+3. **Command Content**:
+   - Description in frontmatter
+   - Usage instructions
+   - Execution flow diagram
+   - Step-by-step instructions
+   - Options/flags documentation
+   - Examples
+
+### When to Use Each Type
+
+| Need | Use | Example |
+|------|-----|---------|
+| Deep expertise in technology | Agent | react-expert, python-expert |
+| Tool-specific capability | Skill | code-stats, git-workflow |
+| Automated workflow | Command | /plan, /review, /test |
+| Persistent instructions | CLAUDE.md | Coding standards |
+| File-scoped rules | Rules | API guidelines for src/api/ |
+
+## Quality Standards
+
+### YAML Frontmatter Requirements
+
+**Agents**:
+- `name`: kebab-case, matches filename
+- `description`: Clear, specific, with trigger scenarios
+- `model`: optional (inherit, sonnet, opus, haiku)
+
+**Skills**:
+- `name`: kebab-case, matches directory
+- `description`: Include trigger keywords
+
+**Commands**:
+- `name`: kebab-case
+- `description`: Brief action description
+
+### Description Writing Guide
+
+Good descriptions:
+- Start with what it does
+- Include when to use
+- Mention specific scenarios
+- Use action verbs
+
+Examples:
+```yaml
+# Good
+description: "Expert in React development. Use for: component architecture, hooks patterns, performance optimization, Server Components, testing strategies."
+
+# Bad
+description: "Helps with React"
+```
+
+### Documentation Standards
+
+1. **Agents**: 10+ authoritative URLs, comprehensive patterns
+2. **Skills**: Tool requirements, usage examples
+3. **Commands**: Execution flow, options, examples
+
+### Testing Requirements
+
+1. YAML frontmatter valid (opens and closes with ---)
+2. Required fields present (name, description)
+3. Name matches filename (kebab-case)
+4. Run validation: `just test`
+
+## Iteration Workflows
+
+### Reviewing Existing Extensions
+
+1. **Read current implementation**
+2. **Check against quality standards**
+3. **Identify gaps**:
+   - Missing documentation URLs?
+   - Unclear trigger scenarios?
+   - Missing anti-patterns?
+4. **Propose improvements**
+5. **Test changes**
+
+### Improvement Patterns
+
+**Adding Capabilities**:
+- Extend focus areas
+- Add new principles
+- Include more references
+
+**Fixing Issues**:
+- Clarify ambiguous descriptions
+- Add missing fields
+- Fix naming conventions
+
+**Refactoring**:
+- Split large agents into focused ones
+- Extract common patterns to skills
+- Convert repeated workflows to commands
+
+### Version Management
+
+- Track changes via git
+- Use descriptive commit messages
+- Document breaking changes in README
+
+## Testing Approaches
+
+### Manual Validation
+
+1. Check YAML syntax
+2. Verify required fields
+3. Test trigger scenarios
+4. Review output quality
+
+### Automated Testing
+
+```bash
+# Run full validation
+just test
+
+# YAML only
+just validate-yaml
+
+# Naming only
+just validate-names
+
+# Windows
+just test-win
+```
+
+### Cross-Platform Considerations
+
+- Test on both bash and PowerShell
+- Use portable path handling
+- Avoid OS-specific features in extensions
+
+## Common Pitfalls
+
+### Agent Development
+- **Too broad**: Focus on one technology/domain
+- **Too narrow**: Should handle common variations
+- **Missing triggers**: Description doesn't explain when to use
+- **No references**: Always include authoritative sources
+- **Code in agent**: Agents generate code, don't include it
+
+### Skill Development
+- **Missing tools**: Document required CLI tools
+- **No examples**: Always show usage patterns
+- **Vague triggers**: Be specific about activation keywords
+
+### Command Development
+- **No flow diagram**: Include execution flow
+- **Missing options**: Document all flags
+- **No examples**: Show real usage scenarios
+
+### General
+- **Wrong naming**: Use kebab-case everywhere
+- **Missing frontmatter**: Always start with ---
+- **Incomplete description**: Be specific and actionable
+
+## Templates
+
+### Agent Template
+
+```markdown
+---
+name: technology-expert
+description: "Expert in [technology]. Use for: [scenario 1], [scenario 2], [scenario 3]."
+model: inherit
+---
+
+# [Technology] Expert Agent
+
+You are an expert in [technology], specializing in [specific areas].
+
+## Focus Areas
+- [Area 1]
+- [Area 2]
+- [Area 3]
+
+## Approach Principles
+- [Principle 1]
+- [Principle 2]
+
+## Quality Checklist
+- [ ] [Requirement 1]
+- [ ] [Requirement 2]
+
+## Output Deliverables
+- [Deliverable 1]
+- [Deliverable 2]
+
+## Common Pitfalls
+- [Pitfall 1]
+- [Pitfall 2]
+
+## References
+- [URL 1]
+- [URL 2]
+- [URL 3]
+```
+
+### Skill Template
+
+```markdown
+---
+name: skill-name
+description: "Brief description. Triggers on: [keyword 1], [keyword 2], [keyword 3]."
+---
+
+# Skill Name
+
+## Purpose
+[What this skill does]
+
+## Tools Required
+| Tool | Command | Purpose |
+|------|---------|---------|
+| tool1 | `tool1 args` | What it does |
+
+## Usage Examples
+
+### Scenario 1
+\`\`\`bash
+command example
+\`\`\`
+
+## When to Use
+- [Scenario 1]
+- [Scenario 2]
+```
+
+### Command Template
+
+```markdown
+---
+name: command-name
+description: "What this command does in one line."
+---
+
+# /command-name
+
+[Brief description]
+
+## Usage
+\`\`\`
+/command-name [options] [args]
+\`\`\`
+
+## Execution Flow
+\`\`\`
+/command-name
+    |
+    +-- Step 1
+    +-- Step 2
+    +-- Step 3
+\`\`\`
+
+## Instructions
+
+### Step 1: [Action]
+[Details]
+
+### Step 2: [Action]
+[Details]
+
+## Options
+| Flag | Effect |
+|------|--------|
+| --flag | Description |
+
+## Examples
+\`\`\`
+/command-name --flag value
+\`\`\`
+```
+
+## Project-Specific Knowledge (claude-mods)
+
+### Repository Structure
+```
+claude-mods/
+├── agents/           # 24 expert agents
+├── commands/         # 8 slash commands
+├── skills/           # 10 skills
+├── templates/        # Installation templates
+├── tests/            # Validation scripts
+├── justfile          # Task runner
+├── install.sh        # Unix installer
+└── install.ps1       # Windows installer
+```
+
+### Key Commands
+- `/init-tools`: Initialize project with permissions and rules
+- `/plan`: Create persistent project plans
+- `/save`, `/load`: Session state management
+- `/review`: AI code review
+- `/test`: Generate tests
+- `/agent-genesis`: Create new agents
+
+### Validation
+Run `just test` to validate all extensions before committing.
+
+## When to Use This Agent
+
+Deploy this agent when:
+- Creating new agents, skills, or commands
+- Reviewing existing extensions for quality
+- Debugging Claude Code behavior
+- Designing extension architecture
+- Understanding Claude Code internals
+- Optimizing claude-mods tooling
+- Making architectural decisions about extensions
+
+## Output Expectations
+
+When invoked, provide:
+1. **Analysis**: Clear assessment of current state
+2. **Recommendations**: Specific, actionable improvements
+3. **Implementation**: Ready-to-use code/content
+4. **Validation**: How to verify changes work
+5. **References**: Links to relevant documentation

+ 6 - 0
agents/cloudflare-expert.md

@@ -1,3 +1,9 @@
+---
+name: cloudflare-expert
+description: "Expert in Cloudflare Workers, Pages, DNS, and edge computing. Use for: Workers development, KV/Durable Objects/R2/D1 storage, wrangler configuration, edge optimization, security patterns."
+model: inherit
+---
+
 You are a Cloudflare Workers expert specializing in edge computing, serverless architecture, and the Cloudflare Workers platform. You have deep knowledge of the Workers runtime, platform features, performance optimization, and production best practices.
 
 ## Your Expertise

+ 41 - 0
justfile

@@ -0,0 +1,41 @@
+# claude-mods justfile
+# Run tasks with: just <task>
+
+# Default: list available tasks
+default:
+    @just --list
+
+# Run all validation tests
+test:
+    @echo "Running claude-mods validation..."
+    @bash tests/validate.sh
+
+# Validate YAML frontmatter only
+validate-yaml:
+    @bash tests/validate.sh --yaml-only
+
+# Check file naming conventions
+validate-names:
+    @bash tests/validate.sh --names-only
+
+# Windows test runner
+test-win:
+    powershell -ExecutionPolicy Bypass -File tests/validate.ps1
+
+# Count extensions
+stats:
+    @echo "Agents:   $(find agents -name '*.md' | wc -l)"
+    @echo "Commands: $(find commands -name '*.md' | wc -l)"
+    @echo "Skills:   $(find skills -name 'SKILL.md' | wc -l)"
+
+# List all agents
+list-agents:
+    @ls -1 agents/*.md | xargs -n1 basename | sed 's/\.md$//'
+
+# List all commands
+list-commands:
+    @find commands -name '*.md' -not -path '*/\.*' | xargs -n1 basename | sed 's/\.md$//' | sort -u
+
+# List all skills
+list-skills:
+    @ls -1 skills/*/SKILL.md | xargs -n1 dirname | xargs -n1 basename

+ 269 - 0
tests/validate.ps1

@@ -0,0 +1,269 @@
+# claude-mods validation script (PowerShell)
+# Validates YAML frontmatter, required fields, and naming conventions
+
+param(
+    [switch]$YamlOnly,
+    [switch]$NamesOnly
+)
+
+$ErrorActionPreference = "Stop"
+
+# Counters
+$script:Pass = 0
+$script:Fail = 0
+$script:Warn = 0
+
+# Get project directory
+$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
+$ProjectDir = Split-Path -Parent $ScriptDir
+
+function Write-Pass {
+    param([string]$Message)
+    Write-Host "PASS" -ForegroundColor Green -NoNewline
+    Write-Host ": $Message"
+    $script:Pass++
+}
+
+function Write-Fail {
+    param([string]$Message)
+    Write-Host "FAIL" -ForegroundColor Red -NoNewline
+    Write-Host ": $Message"
+    $script:Fail++
+}
+
+function Write-Warn {
+    param([string]$Message)
+    Write-Host "WARN" -ForegroundColor Yellow -NoNewline
+    Write-Host ": $Message"
+    $script:Warn++
+}
+
+function Test-YamlFrontmatter {
+    param([string]$FilePath)
+
+    $content = Get-Content -Path $FilePath -Raw
+
+    # Check for opening ---
+    if (-not $content.StartsWith("---")) {
+        Write-Fail "$FilePath - Missing YAML frontmatter (no opening ---)"
+        return $false
+    }
+
+    # Check for closing ---
+    $lines = $content -split "`n"
+    $foundClosing = $false
+    for ($i = 1; $i -lt $lines.Count; $i++) {
+        if ($lines[$i].Trim() -eq "---") {
+            $foundClosing = $true
+            break
+        }
+    }
+
+    if (-not $foundClosing) {
+        Write-Fail "$FilePath - Invalid YAML frontmatter (no closing ---)"
+        return $false
+    }
+
+    return $true
+}
+
+function Get-YamlField {
+    param(
+        [string]$FilePath,
+        [string]$Field
+    )
+
+    $content = Get-Content -Path $FilePath -Raw
+    $lines = $content -split "`n"
+
+    $inFrontmatter = $false
+    foreach ($line in $lines) {
+        if ($line.Trim() -eq "---") {
+            if ($inFrontmatter) { break }
+            $inFrontmatter = $true
+            continue
+        }
+
+        if ($inFrontmatter -and $line -match "^${Field}:\s*(.+)$") {
+            $value = $matches[1].Trim()
+            # Remove quotes
+            $value = $value -replace '^["'']|["'']$', ''
+            return $value
+        }
+    }
+
+    return $null
+}
+
+function Test-RequiredFields {
+    param(
+        [string]$FilePath,
+        [string]$Type
+    )
+
+    $name = Get-YamlField -FilePath $FilePath -Field "name"
+    $description = Get-YamlField -FilePath $FilePath -Field "description"
+
+    if (-not $name) {
+        Write-Fail "$FilePath - Missing required field: name"
+        return $false
+    }
+
+    if (-not $description) {
+        Write-Fail "$FilePath - Missing required field: description"
+        return $false
+    }
+
+    return $true
+}
+
+function Test-Naming {
+    param([string]$FilePath)
+
+    $basename = [System.IO.Path]::GetFileNameWithoutExtension($FilePath)
+
+    # Check if filename is kebab-case
+    if ($basename -notmatch "^[a-z][a-z0-9]*(-[a-z0-9]+)*$") {
+        Write-Warn "$FilePath - Filename not kebab-case: $basename"
+        return $false
+    }
+
+    # Check if name field matches filename
+    $name = Get-YamlField -FilePath $FilePath -Field "name"
+    if ($name -and $name -ne $basename) {
+        Write-Warn "$FilePath - Name field '$name' doesn't match filename '$basename'"
+        return $false
+    }
+
+    return $true
+}
+
+function Test-Agents {
+    Write-Host ""
+    Write-Host "=== Validating Agents ===" -ForegroundColor Cyan
+
+    $agentDir = Join-Path $ProjectDir "agents"
+    if (-not (Test-Path $agentDir)) {
+        Write-Warn "agents/ directory not found"
+        return
+    }
+
+    $files = Get-ChildItem -Path $agentDir -Filter "*.md" -File
+    foreach ($file in $files) {
+        if (-not $NamesOnly) {
+            if (Test-YamlFrontmatter -FilePath $file.FullName) {
+                if (Test-RequiredFields -FilePath $file.FullName -Type "agent") {
+                    Write-Pass "$($file.FullName) - Valid agent"
+                }
+            }
+        }
+
+        if (-not $YamlOnly) {
+            Test-Naming -FilePath $file.FullName | Out-Null
+        }
+    }
+}
+
+function Test-Commands {
+    Write-Host ""
+    Write-Host "=== Validating Commands ===" -ForegroundColor Cyan
+
+    $cmdDir = Join-Path $ProjectDir "commands"
+    if (-not (Test-Path $cmdDir)) {
+        Write-Warn "commands/ directory not found"
+        return
+    }
+
+    # Check .md files directly in commands/
+    $files = Get-ChildItem -Path $cmdDir -Filter "*.md" -File
+    foreach ($file in $files) {
+        if (-not $NamesOnly) {
+            if (Test-YamlFrontmatter -FilePath $file.FullName) {
+                if (Test-RequiredFields -FilePath $file.FullName -Type "command") {
+                    Write-Pass "$($file.FullName) - Valid command"
+                }
+            }
+        }
+
+        if (-not $YamlOnly) {
+            Test-Naming -FilePath $file.FullName | Out-Null
+        }
+    }
+
+    # Check subdirectories
+    $subdirs = Get-ChildItem -Path $cmdDir -Directory
+    foreach ($subdir in $subdirs) {
+        $subFiles = Get-ChildItem -Path $subdir.FullName -Filter "*.md" -File
+        foreach ($file in $subFiles) {
+            if (-not $NamesOnly) {
+                if (Test-YamlFrontmatter -FilePath $file.FullName) {
+                    $desc = Get-YamlField -FilePath $file.FullName -Field "description"
+                    if ($desc) {
+                        Write-Pass "$($file.FullName) - Valid subcommand"
+                    } else {
+                        Write-Warn "$($file.FullName) - Missing description"
+                    }
+                }
+            }
+        }
+    }
+}
+
+function Test-Skills {
+    Write-Host ""
+    Write-Host "=== Validating Skills ===" -ForegroundColor Cyan
+
+    $skillsDir = Join-Path $ProjectDir "skills"
+    if (-not (Test-Path $skillsDir)) {
+        Write-Warn "skills/ directory not found"
+        return
+    }
+
+    $subdirs = Get-ChildItem -Path $skillsDir -Directory
+    foreach ($subdir in $subdirs) {
+        $skillFile = Join-Path $subdir.FullName "SKILL.md"
+
+        if (-not (Test-Path $skillFile)) {
+            Write-Fail "$($subdir.FullName) - Missing SKILL.md"
+            continue
+        }
+
+        if (-not $NamesOnly) {
+            if (Test-YamlFrontmatter -FilePath $skillFile) {
+                $name = Get-YamlField -FilePath $skillFile -Field "name"
+                $desc = Get-YamlField -FilePath $skillFile -Field "description"
+
+                if ($name -and $desc) {
+                    Write-Pass "$skillFile - Valid skill"
+                } else {
+                    if (-not $name) { Write-Fail "$skillFile - Missing name" }
+                    if (-not $desc) { Write-Fail "$skillFile - Missing description" }
+                }
+            }
+        }
+    }
+}
+
+# Main
+Write-Host "claude-mods Validation"
+Write-Host "======================"
+Write-Host "Project: $ProjectDir"
+
+Test-Agents
+Test-Commands
+Test-Skills
+
+Write-Host ""
+Write-Host "======================"
+Write-Host "Results: " -NoNewline
+Write-Host "$script:Pass passed" -ForegroundColor Green -NoNewline
+Write-Host ", " -NoNewline
+Write-Host "$script:Fail failed" -ForegroundColor Red -NoNewline
+Write-Host ", " -NoNewline
+Write-Host "$script:Warn warnings" -ForegroundColor Yellow
+
+if ($script:Fail -gt 0) {
+    exit 1
+}
+
+exit 0

+ 283 - 0
tests/validate.sh

@@ -0,0 +1,283 @@
+#!/usr/bin/env bash
+# claude-mods validation script
+# Validates YAML frontmatter, required fields, and naming conventions
+
+set -Eeuo pipefail
+
+# Colors for output
+RED='\033[0;31m'
+GREEN='\033[0;32m'
+YELLOW='\033[1;33m'
+NC='\033[0m' # No Color
+
+# Counters
+PASS=0
+FAIL=0
+WARN=0
+
+# Get script directory
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
+
+# Parse arguments
+YAML_ONLY=false
+NAMES_ONLY=false
+
+while [[ $# -gt 0 ]]; do
+    case $1 in
+        --yaml-only)
+            YAML_ONLY=true
+            shift
+            ;;
+        --names-only)
+            NAMES_ONLY=true
+            shift
+            ;;
+        *)
+            echo "Unknown option: $1"
+            exit 1
+            ;;
+    esac
+done
+
+# Helper functions
+log_pass() {
+    echo -e "${GREEN}PASS${NC}: $1"
+    PASS=$((PASS + 1))
+}
+
+log_fail() {
+    echo -e "${RED}FAIL${NC}: $1"
+    FAIL=$((FAIL + 1))
+}
+
+log_warn() {
+    echo -e "${YELLOW}WARN${NC}: $1"
+    WARN=$((WARN + 1))
+}
+
+# Check if file has valid YAML frontmatter
+check_yaml_frontmatter() {
+    local file="$1"
+    local content
+    content=$(cat "$file")
+
+    # Check for opening ---
+    if [[ "$content" != ---* ]]; then
+        log_fail "$file - Missing YAML frontmatter (no opening ---)"
+        return 1
+    fi
+
+    # Check for closing ---
+    local frontmatter
+    frontmatter=$(echo "$content" | sed -n '1,/^---$/p' | tail -n +2)
+    if [[ -z "$frontmatter" ]]; then
+        log_fail "$file - Invalid YAML frontmatter (no closing ---)"
+        return 1
+    fi
+
+    return 0
+}
+
+# Extract field from YAML frontmatter
+get_yaml_field() {
+    local file="$1"
+    local field="$2"
+
+    # Extract frontmatter and get field value
+    sed -n '2,/^---$/p' "$file" | grep "^${field}:" | sed "s/^${field}:[[:space:]]*//" | sed 's/^["'"'"']//' | sed 's/["'"'"']$//'
+}
+
+# Check required fields in agents/commands
+check_required_fields() {
+    local file="$1"
+    local type="$2"
+
+    local name
+    local description
+
+    name=$(get_yaml_field "$file" "name")
+    description=$(get_yaml_field "$file" "description")
+
+    # Agents require both name and description
+    if [[ "$type" == "agent" ]]; then
+        if [[ -z "$name" ]]; then
+            log_fail "$file - Missing required field: name"
+            return 1
+        fi
+        if [[ -z "$description" ]]; then
+            log_fail "$file - Missing required field: description"
+            return 1
+        fi
+    fi
+
+    # Commands only require description
+    if [[ "$type" == "command" ]]; then
+        if [[ -z "$description" ]]; then
+            log_fail "$file - Missing required field: description"
+            return 1
+        fi
+    fi
+
+    return 0
+}
+
+# Check naming convention (kebab-case)
+check_naming() {
+    local file="$1"
+    local basename
+    basename=$(basename "$file" .md)
+
+    # Check if filename is kebab-case
+    if [[ ! "$basename" =~ ^[a-z][a-z0-9]*(-[a-z0-9]+)*$ ]]; then
+        log_warn "$file - Filename not kebab-case: $basename"
+        return 1
+    fi
+
+    # Check if name field matches filename (for agents)
+    local name
+    name=$(get_yaml_field "$file" "name")
+    if [[ -n "$name" && "$name" != "$basename" ]]; then
+        log_warn "$file - Name field '$name' doesn't match filename '$basename'"
+        return 1
+    fi
+
+    return 0
+}
+
+# Validate agents
+validate_agents() {
+    echo ""
+    echo "=== Validating Agents ==="
+
+    local agent_dir="$PROJECT_DIR/agents"
+    if [[ ! -d "$agent_dir" ]]; then
+        log_warn "agents/ directory not found"
+        return
+    fi
+
+    # Use find for better Windows compatibility
+    while IFS= read -r -d '' file; do
+        if ! $NAMES_ONLY; then
+            if check_yaml_frontmatter "$file"; then
+                if check_required_fields "$file" "agent"; then
+                    log_pass "$file - Valid agent"
+                fi
+            fi
+        fi
+
+        if ! $YAML_ONLY; then
+            check_naming "$file" || true
+        fi
+    done < <(find "$agent_dir" -maxdepth 1 -name "*.md" -type f -print0)
+}
+
+# Validate commands
+validate_commands() {
+    echo ""
+    echo "=== Validating Commands ==="
+
+    local cmd_dir="$PROJECT_DIR/commands"
+    if [[ ! -d "$cmd_dir" ]]; then
+        log_warn "commands/ directory not found"
+        return
+    fi
+
+    # Check .md files directly in commands/
+    while IFS= read -r -d '' file; do
+        if ! $NAMES_ONLY; then
+            if check_yaml_frontmatter "$file"; then
+                if check_required_fields "$file" "command"; then
+                    log_pass "$file - Valid command"
+                fi
+            fi
+        fi
+
+        if ! $YAML_ONLY; then
+            check_naming "$file" || true
+        fi
+    done < <(find "$cmd_dir" -maxdepth 1 -name "*.md" -type f -print0)
+
+    # Check subdirectories (like g-slave/, session-manager/)
+    while IFS= read -r -d '' subdir; do
+        # Look for main command file (exclude README.md, LICENSE.md)
+        while IFS= read -r -d '' file; do
+            local basename
+            basename=$(basename "$file")
+            # Skip README and LICENSE files
+            [[ "$basename" == "README.md" || "$basename" == "LICENSE.md" ]] && continue
+
+            if ! $NAMES_ONLY; then
+                if check_yaml_frontmatter "$file"; then
+                    # Commands in subdirs may have different required fields
+                    local desc
+                    desc=$(get_yaml_field "$file" "description")
+                    if [[ -n "$desc" ]]; then
+                        log_pass "$file - Valid subcommand"
+                    else
+                        log_warn "$file - Missing description"
+                    fi
+                fi
+            fi
+        done < <(find "$subdir" -maxdepth 1 -name "*.md" -type f -print0)
+    done < <(find "$cmd_dir" -mindepth 1 -maxdepth 1 -type d -print0)
+}
+
+# Validate skills
+validate_skills() {
+    echo ""
+    echo "=== Validating Skills ==="
+
+    local skills_dir="$PROJECT_DIR/skills"
+    if [[ ! -d "$skills_dir" ]]; then
+        log_warn "skills/ directory not found"
+        return
+    fi
+
+    while IFS= read -r -d '' skill_subdir; do
+        local skill_file="$skill_subdir/SKILL.md"
+        if [[ ! -f "$skill_file" ]]; then
+            log_fail "$skill_subdir - Missing SKILL.md"
+            continue
+        fi
+
+        if ! $NAMES_ONLY; then
+            if check_yaml_frontmatter "$skill_file"; then
+                local name
+                local desc
+                name=$(get_yaml_field "$skill_file" "name")
+                desc=$(get_yaml_field "$skill_file" "description")
+
+                if [[ -n "$name" && -n "$desc" ]]; then
+                    log_pass "$skill_file - Valid skill"
+                else
+                    [[ -z "$name" ]] && log_fail "$skill_file - Missing name"
+                    [[ -z "$desc" ]] && log_fail "$skill_file - Missing description"
+                fi
+            fi
+        fi
+    done < <(find "$skills_dir" -mindepth 1 -maxdepth 1 -type d -print0)
+}
+
+# Main
+main() {
+    echo "claude-mods Validation"
+    echo "======================"
+    echo "Project: $PROJECT_DIR"
+
+    validate_agents
+    validate_commands
+    validate_skills
+
+    echo ""
+    echo "======================"
+    echo -e "Results: ${GREEN}$PASS passed${NC}, ${RED}$FAIL failed${NC}, ${YELLOW}$WARN warnings${NC}"
+
+    if [[ $FAIL -gt 0 ]]; then
+        exit 1
+    fi
+
+    exit 0
+}
+
+main "$@"