Skill: zerozlw/skill-release-pipeline (version 1.0.0)

--- name: skill-publisher description: Package, publish, and distribute OpenClaw skills to GitHub and ClawHub. Activate when user wants to: (1) package a skill folder for distribution, (2) push a skill to a GitHub repo, (3) publish a skill to ClawHub registry, (4) sync a skill across GitHub and ClawHub. NOT for: creating skill content, writing SKILL.md, or installing skills. --- # Skill Publisher Automate the full lifecycle of publishing OpenClaw skills: package → GitHub → ClawHub. ## Prerequisites - `gh` CLI authenticated (`gh auth status`) - `npx clawhub` CLI authenticated (`npx clawhub whoami`) - A skill folder with a valid `SKILL.md` ## Quick Start ### Full Pipeline (package + GitHub + ClawHub) ```bash # From the skill directory scripts/publish.sh /path/to/skill-folder --repo owner/repo-name --version 1.0.0 ``` ### Individual Steps ```bash # 1. Validate & package only scripts/validate.sh /path/to/skill-folder # 2. Push to GitHub scripts/push-github.sh /path/to/skill-folder --repo owner/repo-name # 3. Publish to ClawHub npx clawhub publish /path/to/skill-folder --version 1.0.0 --slug skill-name ``` ## Workflow ### Step 1: Prepare the Skill Folder Ensure the skill folder contains: ``` skill-name/ ├── SKILL.md (required — YAML frontmatter + markdown body) ├── LICENSE (recommended — MIT) ├── examples/ (optional — usage examples) ├── scripts/ (optional — helper scripts) ├── references/ (optional — reference docs) └── assets/ (optional — templates, images, fonts) ``` **SKILL.md frontmatter must include:** ```yaml --- name: skill-name description: Clear description of what the skill does and when to activate it --- ``` ### Step 2: Push to GitHub ```bash cd /path/to/skill-folder # Init if needed git init git add -A git commit -m "feat: initial release of skill-name" # Create repo and push gh repo create owner/repo-name --public --source=. --push ``` If the repo already exists: ```bash git remote add origin https://github.com/owner/repo-name.git 2>/dev/null || true git push -u origin main ``` ### Step 3: Publish to ClawHub ```bash # Login if needed (opens browser) npx clawhub login # Publish with version npx clawhub publish /path/to/skill-folder \ --version 1.0.0 \ --slug skill-name \ --name "Display Name" \ --tags "tag1,tag2" # Verify npx clawhub inspect skill-name ``` **Note:** ClawHub runs a security scan after publishing. The skill becomes searchable once the scan passes (usually within a few minutes). ## Common Tasks ### Update an Existing Skill ```bash # 1. Make changes to the skill folder # 2. Push to GitHub cd /path/to/skill-folder git add -A && git commit -m "fix: description of changes" git push # 3. Publish new version to ClawHub npx clawhub publish /path/to/skill-folder --version 1.1.0 ``` ### Fork an Existing Skill ```bash npx clawhub publish /path/to/skill-folder \ --version 1.0.0 \ --slug my-fork-name \ --fork-of original-skill@1.0.0 ``` ### Check Publish Status ```bash npx clawhub inspect skill-name npx clawhub search skill-name ``` ## Troubleshooting | Error | Fix | |-------|-----| | `--version must be valid semver` | Add `--version x.y.z` flag | | `Skill is hidden while security scan is pending` | Wait a few minutes, then retry `inspect` | | `Not logged in` | Run `npx clawhub login` | | `gh: not authenticated` | Run `gh auth login` | | `fatal: remote origin already exists` | Safe to ignore, or use `git remote set-url` | ## Naming Conventions - **Slug:** lowercase, hyphens only (e.g., `figma-plugin-writer`) - **Repo:** match the slug (e.g., `openclaw-figma-plugin-writer`) - **Version:** semver (e.g., `1.0.0`, `1.2.3`)

path: scripts/publish.sh
content: #!/usr/bin/env bash
# publish.sh — Full pipeline: validate → GitHub → ClawHub
# Usage: publish.sh <skill-folder> --repo owner/repo --version x.y.z [--slug name] [--tags t1,t2]

set -euo pipefail

FOLDER=""
REPO=""
VERSION=""
SLUG=""
TAGS="latest"
COMMIT_MSG=""

usage() {
  echo "Usage: $0 <skill-folder> --repo owner/repo --version x.y.z [--slug name] [--tags t1,t2] [--message msg]"
  exit 1
}

while [[ $# -gt 0 ]]; do
  case $1 in
    --repo)      REPO="$2"; shift 2 ;;
    --version)   VERSION="$2"; shift 2 ;;
    --slug)      SLUG="$2"; shift 2 ;;
    --tags)      TAGS="$2"; shift 2 ;;
    --message|-m) COMMIT_MSG="$2"; shift 2 ;;
    -h|--help)   usage ;;
    *)           if [[ -z "$FOLDER" ]]; then FOLDER="$1"; shift else usage; fi ;;
  esac
done

[[ -z "$FOLDER" || -z "$REPO" || -z "$VERSION" ]] && usage
FOLDER="$(cd "$FOLDER" && pwd)"

# Derive slug from folder name if not provided
if [[ -z "$SLUG" ]]; then
  SLUG="$(basename "$FOLDER")"
fi

if [[ -z "$COMMIT_MSG" ]]; then
  COMMIT_MSG="release: $SLUG v$VERSION"
fi

echo "=== Skill Publisher ==="
echo "Folder:  $FOLDER"
echo "Repo:    $REPO"
echo "Version: $VERSION"
echo "Slug:    $SLUG"
echo ""

# Step 1: Validate SKILL.md
echo "--- Step 1: Validating ---"
if [[ ! -f "$FOLDER/SKILL.md" ]]; then
  echo "ERROR: SKILL.md not found in $FOLDER"
  exit 1
fi

# Check frontmatter
if ! head -1 "$FOLDER/SKILL.md" | grep -q "^---"; then
  echo "ERROR: SKILL.md missing YAML frontmatter (must start with ---)"
  exit 1
fi

if ! grep -q "^name:" "$FOLDER/SKILL.md"; then
  echo "ERROR: SKILL.md frontmatter missing 'name' field"
  exit 1
fi

if ! grep -q "^description:" "$FOLDER/SKILL.md"; then
  echo "ERROR: SKILL.md frontmatter missing 'description' field"
  exit 1
fi

echo "  ✓ SKILL.md valid"

# Step 2: Push to GitHub
echo ""
echo "--- Step 2: Pushing to GitHub ---"
cd "$FOLDER"

if [[ ! -d .git ]]; then
  git init
  echo "  ✓ git init"
fi

git add -A
git commit -m "$COMMIT_MSG" --allow-empty 2>/dev/null || true
echo "  ✓ committed"

# Add remote if not exists
if ! git remote get-url origin &>/dev/null; then
  git remote add origin "https://github.com/$REPO.git"
  echo "  ✓ added remote origin"
fi

git push -u origin main 2>&1 || git push -u origin master 2>&1
echo "  ✓ pushed to GitHub"

# Step 3: Publish to ClawHub
echo ""
echo "--- Step 3: Publishing to ClawHub ---"

# Check auth
if ! npx clawhub whoami &>/dev/null; then
  echo "ERROR: Not logged in to ClawHub. Run: npx clawhub login"
  exit 1
fi

npx clawhub publish "$FOLDER" \
  --version "$VERSION" \
  --slug "$SLUG" \
  --tags "$TAGS"

echo ""
echo "=== Done! ==="
echo "GitHub:  https://github.com/$REPO"
echo "ClawHub: https://clawhub.ai/skills/$SLUG"
echo ""
echo "Install: npx clawhub@latest install $SLUG"


path: scripts/push-github.sh
content: #!/usr/bin/env bash
# push-github.sh — Initialize git and push skill to GitHub
# Usage: push-github.sh <skill-folder> --repo owner/repo [--message "commit message"]

set -euo pipefail

FOLDER=""
REPO=""
COMMIT_MSG=""

while [[ $# -gt 0 ]]; do
  case $1 in
    --repo)    REPO="$2"; shift 2 ;;
    --message|-m) COMMIT_MSG="$2"; shift 2 ;;
    -h|--help) echo "Usage: $0 <skill-folder> --repo owner/repo [--message msg]"; exit 0 ;;
    *)         if [[ -z "$FOLDER" ]]; then FOLDER="$1"; shift else echo "Unknown: $1"; exit 1; fi ;;
  esac
done

[[ -z "$FOLDER" || -z "$REPO" ]] && { echo "Usage: $0 <skill-folder> --repo owner/repo"; exit 1; }

FOLDER="$(cd "$FOLDER" && pwd)"
SLUG="$(basename "$FOLDER")"

if [[ -z "$COMMIT_MSG" ]]; then
  COMMIT_MSG="feat: $SLUG skill for OpenClaw"
fi

cd "$FOLDER"

# Init git if needed
if [[ ! -d .git ]]; then
  git init
  echo "Initialized git repo"
fi

# Stage and commit
git add -A
git commit -m "$COMMIT_MSG" --allow-empty
echo "Committed: $COMMIT_MSG"

# Set remote
if git remote get-url origin &>/dev/null; then
  git remote set-url origin "https://github.com/$REPO.git"
else
  git remote add origin "https://github.com/$REPO.git"
fi

# Push
git push -u origin main 2>&1 || git push -u origin master 2>&1

echo ""
echo "✅ Pushed to https://github.com/$REPO"


path: scripts/validate.sh
content: #!/usr/bin/env bash
# validate.sh — Validate a skill folder structure
# Usage: validate.sh <skill-folder>

set -euo pipefail

FOLDER="${1:-}"
if [[ -z "$FOLDER" ]]; then
  echo "Usage: $0 <skill-folder>"
  exit 1
fi

FOLDER="$(cd "$FOLDER" && pwd)"
ERRORS=0

echo "Validating: $FOLDER"
echo ""

# Check SKILL.md exists
if [[ ! -f "$FOLDER/SKILL.md" ]]; then
  echo "  ✗ SKILL.md not found"
  ERRORS=$((ERRORS + 1))
else
  echo "  ✓ SKILL.md exists"

  # Check frontmatter
  if head -1 "$FOLDER/SKILL.md" | grep -q "^---"; then
    echo "  ✓ YAML frontmatter present"
  else
    echo "  ✗ Missing YAML frontmatter (must start with ---)"
    ERRORS=$((ERRORS + 1))
  fi

  # Check required fields
  if grep -q "^name:" "$FOLDER/SKILL.md"; then
    NAME=$(grep "^name:" "$FOLDER/SKILL.md" | head -1 | sed 's/^name: *//')
    echo "  ✓ name: $NAME"
  else
    echo "  ✗ Missing 'name' in frontmatter"
    ERRORS=$((ERRORS + 1))
  fi

  if grep -q "^description:" "$FOLDER/SKILL.md"; then
    echo "  ✓ description present"
  else
    echo "  ✗ Missing 'description' in frontmatter"
    ERRORS=$((ERRORS + 1))
  fi

  # Check size
  LINES=$(wc -l < "$FOLDER/SKILL.md")
  if [[ $LINES -gt 500 ]]; then
    echo "  ⚠ SKILL.md is $LINES lines (recommended: <500)"
  else
    echo "  ✓ SKILL.md size OK ($LINES lines)"
  fi
fi

# Check LICENSE
if [[ -f "$FOLDER/LICENSE" ]]; then
  echo "  ✓ LICENSE present"
else
  echo "  ⚠ No LICENSE file (recommended: MIT)"
fi

# Check for symlinks
if find "$FOLDER" -type l | grep -q .; then
  echo "  ✗ Symlinks detected (not allowed by ClawHub)"
  ERRORS=$((ERRORS + 1))
else
  echo "  ✓ No symlinks"
fi

# List contents
echo ""
echo "Contents:"
ls -la "$FOLDER" | grep -v "^total" | grep -v "^\."

echo ""
if [[ $ERRORS -eq 0 ]]; then
  echo "✅ Validation passed"
else
  echo "❌ $ERRORS error(s) found"
  exit 1
fi


Security scan verdicts — ClawScan: clean | static analysis: clean | VirusTotal: clean | SkillSpector: clean (LOW)