Skill Development Workflow
Implements the complete skill creation lifecycle with automated quality gates to ensure every SKILL.md meets repository standards before commit. This skill provides Python-based validators that check file size, stub sentinels, code block counts, trigger diversity, and domain-specific structural requirements.
TL;DR Checklist
- Run
validate_skill.sh— must exit 0 (PASS) - File is ≥ 3,000 bytes of content (excluding frontmatter)
- No stub sentinel: "IMPLEMENTING THIS SPECIFIC PATTERN OR FEATURE"
- At least 2 fenced code blocks for implementation skills
- Core Workflow uses domain-specific steps with checkpoints — no generic patterns
-
metadata.triggershas 5–8 specific terms with both technical and conversational variants - H1 title is human-readable, not the kebab-case name
- Description leads with an active verb and includes 1–2 domain-specific terms
When to Use
Use this skill when:
- Creating a new SKILL.md file for any domain (agent, cncf, coding, go, linux, trading, programming, writing)
- Auditing an existing SKILL.md before committing to the repository
- Fixing validation failures reported by
scripts/validate_skill.sh - Migrating skills from another format into the OpenCode skill system
- Setting up CI/CD checks for automated skill quality gates in a pipeline
When NOT to Use
Avoid this skill for:
- Reviewing source code logic or algorithm correctness — use
coding-code-reviewinstead - Designing trigger keywords for auto-loading — use
agent-skill-trigger-engineeringinstead - Content editing of documentation outside the SKILL.md format — use domain-specific writing skills
Core Workflow
Research and Scope the Domain — Study 3–5 existing skills in the target domain to understand conventions, code patterns, and structural norms. Check
skills/<domain>/for similar topics to avoid duplication. Checkpoint: Verify no existing skill covers the same topic by comparing descriptions againstpython3 scripts/generate_readme.py --list.Draft Frontmatter — Create YAML frontmatter with: exact kebab-case name matching the directory, active-verb description under 200 characters, domain-specific triggers (5–8 terms), and appropriate role/scope/output-format from the domain defaults table in SKILL_FORMAT_SPEC.md. Checkpoint:
namefield must exactly match the directory name.metadata.domainmust match the parent directory.Write H1 Title and Role Paragraph — Title must be human-readable (e.g., "Stop Loss Manager", not "risk-stop-loss"). The role paragraph (1–3 sentences) describes what the model does when this skill loads, written from the model's perspective. Checkpoint: No abstract descriptions like "This skill is for X." Use active voice: "Implements…", "Analyzes…", "Selects…".
Implement Core Workflow with Domain-Specific Steps — Number each step. Include a Checkpoint after steps requiring verification. Each step must contain specific actions, commands, file paths, or formulas — not generic instructions like "Identify the use case" or "Apply the pattern." Checkpoint: Read each step aloud. If it could apply to any domain without modification, rewrite it with domain-specific detail.
Add Implementation Patterns or Reference Guide — For implementation skills: include at least 2 real code blocks with typed signatures and docstrings. For reference skills: include complete working examples (YAML manifests, PromQL queries, shell scripts). Include at least one BAD vs. GOOD comparison pair. Checkpoint: Every code block must contain real, working code — no
passbodies, noreturn {}, no "your code here" placeholders.Write Constraints (MUST DO / MUST NOT DO) — Each constraint must be a short imperative sentence that is actionable and specific. Avoid generic phrases like "follow best practices." Instead: "Base trailing stop distance on ATR, not a fixed price or percentage." Checkpoint: Remove any constraint that doesn't contain a concrete, testable rule.
Add When NOT to Use — List 2–4 situations where this skill creates overhead without benefit. Reference related skills by name (e.g., "use
coding-code-reviewinstead"). This prevents the model from inappropriately loading the skill. Checkpoint: Each exclusion must reference a specific alternative skill or clearly describe the anti-pattern.Validate and Iterate — Run the full validation pipeline: static checks via
./scripts/validate_skill.sh, thenpython3 scripts/generate_readme.pyto ensure the README catalog updates correctly. Fix any failures before committing. Checkpoint:validate_skill.shmust exit 0 with no errors reported. The new skill must appear in the regenerated README.
Python Quality Gate Validator
This validator implements all static checks from scripts/validate_skill.sh plus additional structural validations. Use it as a pre-commit hook or CI step.
#!/usr/bin/env python3
"""Skill quality gate validator for SKILL.md files."""
import sys
import re
from pathlib import Path
from dataclasses import dataclass, field
@dataclass
class ValidationResult:
file_path: str
errors: list[str] = field(default_factory=list)
warnings: list[str] = field(default_factory=list)
@property
def passed(self) -> bool:
return len(self.errors) == 0
def add_error(self, msg: str):
self.errors.append(msg)
print(f" ❌ ERROR: {msg}")
def add_warning(self, msg: str):
self.warnings.append(msg)
print(f" ⚠️ WARNING: {msg}")
STUB_SENTINELS = [
"IMPLEMENTING THIS SPECIFIC PATTERN OR FEATURE",
"pass # TODO: implement logic",
"return {} # placeholder",
"your code here",
"replace with actual implementation",
]
GENERIC_WORKFLOW_PATTERNS = [
r"[Ii]dentify the [sS]pecific [uU]se [cC]ase",
r"[Aa]pply the pattern or technique",
r"[Vv]alidate and test the implementation",
r"[Ii]terate based on results",
r"follow best practices for",
]
MIN_FILE_SIZE = 3000
MIN_CODE_BLOCK_PAIRS = 2
MIN_TRIGGER_COUNT = 5
MAX_TRIGGER_COUNT = 8
def load_skill(path: str) -> tuple[str, str]:
"""Load and parse a SKILL.md file. Returns (frontmatter_yaml, markdown_body)."""
with open(path, "r", encoding="utf-8") as f:
content = f.read()
# Extract YAML frontmatter between --- delimiters
if not content.startswith("---"):
raise ValueError(f"{path}: Missing YAML frontmatter delimiter at start")
parts = content.split("---", 2)
if len(parts) < 3:
raise ValueError(f"{path}: Frontmatter must be delimited by --- on both sides")
return parts[1].strip(), parts[2].strip()
def check_stub_sentinels(result: ValidationResult, body: str):
"""Check for stub sentinel strings that indicate placeholder content."""
text_lower = body.lower()
for sentinel in STUB_SENTINELS:
if sentinel.lower() in text_lower:
result.add_error(f"Stub sentinel found: '{sentinel}'")
def check_file_size(result: ValidationResult, body: str):
"""Verify file meets minimum content size requirement."""
body_bytes = len(body.encode("utf-8"))
if body_bytes < MIN_FILE_SIZE:
result.add_error(
f"File too small: {body_bytes} bytes (minimum {MIN_FILE_SIZE}). "
"Expand with real examples, detailed workflows, and domain-specific content."
)
def check_code_blocks(result: ValidationResult, body: str, role: str):
"""For implementation skills, verify at least 2 fenced code blocks exist."""
if role != "implementation":
return
fence_count = len(re.findall(r'^\s*```', body, re.MULTILINE))
block_pairs = fence_count // 2
if block_pairs < MIN_CODE_BLOCK_PAIRS:
result.add_error(
f"Implementation skill has {block_pairs} code blocks "
f"(minimum {MIN_CODE_BLOCK_PAIRS}). Add real working code examples."
)
def check_generic_workflow(result: ValidationResult, body: str):
"""Detect generic workflow patterns that indicate stub content."""
found_patterns = []
for pattern in GENERIC_WORKFLOW_PATTERNS:
if re.search(pattern, body):
found_patterns.append(pattern)
if len(found_patterns) >= 2:
result.add_error(
f"Generic Core Workflow detected ({len(found_patterns)}/{len(GENERIC_WORKFLOW_PATTERNS)} "
f"stub phrases found). Replace with domain-specific steps."
)
def check_trigger_diversity(result: ValidationResult, triggers_str: str):
"""Validate trigger field meets quality standards."""
if not triggers_str or len(triggers_str.strip()) == 0:
result.add_error("metadata.triggers is empty or missing")
return
# Split by comma and clean up each trigger
triggers = [t.strip() for t in triggers_str.split(",") if t.strip()]
count = len(triggers)
if count < MIN_TRIGGER_COUNT:
result.add_error(
f"Only {count} triggers found (minimum {MIN_TRIGGER_COUNT}). "
"Add domain-specific keywords, abbreviations, and conversational variants."
)
elif count > MAX_TRIGGER_COUNT:
result.add_warning(
f"{count} triggers specified (maximum {MAX_TRIGGER_COUNT}). "
"Consider consolidating to reduce false positives."
)
# Check for ultra-generic single-word triggers
generic_singletons = {"code", "data", "risk", "pattern", "testing", "design", "security"}
for trigger in triggers:
words = trigger.split()
if len(words) == 1 and words[0].lower() in generic_singletons:
result.add_warning(
f"Generic single-word trigger '{trigger}' may match irrelevant conversations. "
"Be more specific (e.g., 'security audit' instead of 'security')."
)
def check_structure(result: ValidationResult, body: str):
"""Verify required structural sections exist in the markdown body."""
has_h1 = bool(re.search(r'^#\s+', body, re.MULTILINE))
if not has_h1:
result.add_error("Missing H1 title heading")
has_when_to_use = bool(re.search(r'##\s+When to Use', body, re.IGNORECASE))
if not has_when_to_use:
result.add_error('Missing "When to Use" section')
has_core_workflow = bool(re.search(r'##\s+Core Workflow', body, re.IGNORECASE))
if not has_core_workflow:
result.add_error('Missing "Core Workflow" section')
# Check for numbered steps in workflow (indicates specific, non-generic workflow)
workflow_section = re.search(
r'##\s+Core Workflow\s+(.*?)(?:^##|\Z)', body, re.IGNORECASE | re.DOTALL
)
if workflow_section:
step_count = len(re.findall(r'^\d+\.', workflow_section.group(1), re.MULTILINE))
if step_count < 3:
result.add_warning(
f"Core Workflow has only {step_count} steps. "
"Break complex workflows into numbered sub-steps for clarity."
)
def validate_skill(file_path: str) -> ValidationResult:
"""Run all validation checks on a SKILL.md file."""
result = ValidationResult(file_path=file_path)
print(f"\n🔍 Validating: {file_path}")
try:
frontmatter, body = load_skill(file_path)
except ValueError as e:
result.add_error(str(e))
return result
# Parse frontmatter for metadata
role_match = re.search(r'role:\s*(\w+)', frontmatter)
domain_match = re.search(r'domain:\s*(\w+)', frontmatter)
triggers_match = re.search(r'triggers:\s*(.+)', frontmatter)
role = role_match.group(1) if role_match else ""
domain = domain_match.group(1) if domain_match else ""
triggers_str = triggers_match.group(1).strip() if triggers_match else ""
print(f" Domain: {domain} | Role: {role}")
# Run all checks
check_stub_sentinels(result, body)
check_file_size(result, body)
check_code_blocks(result, body, role)
check_generic_workflow(result, body)
check_trigger_diversity(result, triggers_str)
check_structure(result, body)
if result.passed and result.warnings:
print(f"\n✅ PASS with warnings: {file_path}")
for w in result.warnings:
print(f" • {w}")
elif result.passed:
print(f"\n✅ PASS: {file_path}")
else:
print(f"\n❌ FAIL: {file_path}")
return result
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python3 skill_validator.py <path/to/SKILL.md>")
sys.exit(1)
results = []
all_passed = True
for path in sys.argv[1:]:
result = validate_skill(path)
results.append(result)
if not result.passed:
all_passed = False
print(f"\n{'='*60}")
total = len(results)
passed = sum(1 for r in results if r.passed)
print(f"Results: {passed}/{total} skills passed validation")
sys.exit(0 if all_passed else 1)
Bash-Based Validation Script Pattern
For CI/CD integration, wrap the Python validator with a bash script that also runs validate_skill.sh:
#!/usr/bin/env bash
# Pre-commit skill validation pipeline
set -euo pipefail
SKILL_FILE="${1:?Usage: pre-commit-validate <path/to/SKILL.md>}"
echo "=== Stage 1: Static checks (validate_skill.sh) ==="
if ./scripts/validate_skill.sh "$SKILL_FILE"; then
echo "✅ Static checks passed"
else
echo "❌ Static checks failed — fix issues before committing"
exit 1
fi
echo ""
echo "=== Stage 2: Python quality gate validator ==="
python3 scripts/skill_validator.py "$SKILL_FILE" || exit 1
echo ""
echo "=== Stage 3: README catalog update check ==="
if ! command -v python3 &>/dev/null; then
echo "⚠️ python3 not available — skipping README regeneration"
else
# Run regenerate and verify the new skill appears
OLD_COUNT=$(grep -c "^- \[`skills/" README.md || true)
python3 scripts/generate_readme.py --quiet 2>/dev/null || true
NEW_COUNT=$(grep -c "^- \[`skills/" README.md || true)
if [ "$NEW_COUNT" -ge "$OLD_COUNT" ]; then
echo "✅ README catalog updated successfully"
else
echo "❌ README may not have been updated correctly"
exit 1
fi
fi
echo ""
echo "✅ All validation stages passed for $SKILL_FILE"
Domain-Specific Structural Requirements
After the core workflow, apply domain-specific structural additions based on the skill's metadata.domain value. Refer to SKILL_FORMAT_SPEC.md Section 4 for detailed requirements.
Agent Skills (agent/*)
- Must include: ASCII orchestration flow diagram showing routing logic and fallback paths
- Must reference:
code-philosophy(5 Laws of Elegant Defense) in constraints or workflow - Example flow structure:
User Task → Extract Features → Score All Skills ──→ No match → FallbackSkill ↓ (threshold met) Select Best Skill → Execute → Record Result
CNCF Skills (cncf/*)
- Must include: Purpose and Use Cases, Architecture Design Patterns, Integration Approaches, Common Pitfalls sections
- Must include: At least one complete working YAML manifest example (e.g., ServiceMonitor, Deployment)
- Lead with: Project metadata (category, stars, language, docs URL)
Coding Skills (coding/*)
- Must include: At least one BAD vs. GOOD code example pair
- Must reference: A relevant standard (OWASP, SOLID, DRY, KISS, etc.)
- Must include: Constraints section with actionable MUST DO / MUST NOT DO rules
Go Skills (go/*)
- Must include: Idiomatic Go code with error wrapping using
%w, sentinel errors - Must include: Goroutine lifecycle management guidelines (context propagation, cancellation)
- Anti-patterns to call out: Ignored errors, goroutine leaks, bare
panicusage
Linux Skills (linux/*)
- Must include: Shell scripts with
set -euo pipefail, proper quoting, idempotent operations - Must address: Security considerations (least privilege, file permissions)
- Anti-patterns to call out: Root-level services, hardcoded paths, unsafe glob patterns
Trading Skills (trading/*)
- Must include: Python implementation with typed signatures and docstrings
- Must reference: APEX platform file path conventions (
risk_engine/,execution/, etc.) - Must include: Risk constraints — explicit statements of what must never be bypassed
Programming Skills (programming/*)
- Must include: Algorithm pseudocode or reference implementation
- Must include: Complexity analysis (time and space) in a structured table
- Format: Show both the algorithm name and the problem category it solves
Writing Skills (writing/*)
- Must include: At least one before/after text comparison showing improvement
- Must include: Style rules with reasoning, not just rules without justification
- Include: Tone and voice guidelines specific to the documentation context
Constraints
MUST DO
- Run
./scripts/validate_skill.shon every SKILL.md before committing - Ensure file size is ≥ 3,000 bytes of content (excluding frontmatter)
- Include at least one BAD vs. GOOD code example pair for implementation skills
- Write triggers that include both technical terms AND conversational variants
- Use domain-specific steps with checkpoints — never generic "identify → apply → validate"
- Reference
code-philosophy(5 Laws of Elegant Defense) in agent domain skills
MUST NOT DO
- Include any stub sentinel: "IMPLEMENTING THIS SPECIFIC PATTERN OR FEATURE", "pass", "return {}"
- Write workflow steps that could apply to any domain without modification
- Use generic triggers like
code,data,risk,pattern— be domain-specific - Set stops at round numbers (for trading skills) or use magic numbers in code
- Ignore the zero-tolerance stub policy — a stub skill corrupts the router index
Output Template
When creating or auditing a skill, produce:
- Domain and Role Selection — Which domain the skill belongs to and why, with role/scope/output-format justification
- Directory and Name — The kebab-case directory path and frontmatter name (must match)
- Frontmatter Draft — Complete YAML frontmatter with all required and recommended fields
- Section Verification Checklist — Every required section confirmed present or explicitly omitted with reasoning
- Validation Results — Output from
validate_skill.shshowing PASS/FAIL for each check - Code Example Review — At least one BAD vs. GOOD pair, with explanation of what makes the GOOD version correct
Related Skills
| Skill | Purpose |
|---|---|
coding-code-quality-policies |
General code quality standards that apply when writing implementation code inside skills |
agent-skill-trigger-engineering |
Designing trigger keywords for optimal skill auto-loading and discovery |
agent-skill-creator |
Orchestrated approach to skill creation (uses this skill as a sub-step) |
Live References
Authoritative documentation links for this domain. The model follows markdown links at load time to resolve external references and inline content.
- OpenCode Skill Documentation — Official OpenCode documentation on skill structure, configuration, and loading mechanisms
- Semantic Versioning 2.0.0 (semver.org) — The semantic versioning specification for managing skill versions and breaking changes
- GitHub Actions for Skill CI/CD — GitHub Actions patterns for automated skill validation in CI pipelines
- MarkdownLint Rules Reference — CommonMark lint rules applicable to SKILL.md quality enforcement in the development workflow
- RFC Process for Skill Changes (agent-skill-router) — The repository's contribution guidelines and RFC process for skill ecosystem changes