Skill: douglarek/clawhub-wrapper (version 1.0.1)

--- name: clawhub version: "1.0.1" description: "Download and install skills from ClawHub (https://clawhub.ai). Use when user wants to browse, search, or download skills from the ClawHub skill registry." --- # ClawHub Skill Download and install skills from ClawHub - a fast skill registry for AI agents. ## Commands ### Search Skills Search for skills by keyword: ```bash {baseDir}/clawhub-search.sh "<keyword>" ``` This searches the ClawHub registry and displays matching skills with their slug, name, summary, and download count. ### Download and Install Skill Download and install a skill by slug or ClawHub URL: ```bash # By slug {baseDir}/clawhub-download.sh <slug> # By ClawHub URL (e.g., https://clawhub.ai/steipete/github) {baseDir}/clawhub-download.sh https://clawhub.ai/owner/slug ``` This will: 1. Download the skill package from ClawHub 2. Extract it to `~/.agents/skills/clawhub-skills/<slug>/` 3. Display the installed skill information ### List Skills Browse available skills (sorted by downloads): ```bash {baseDir}/clawhub-search.sh ``` ## API Endpoints ClawHub uses the following API endpoints: - **List/Search Skills**: `https://wry-manatee-359.convex.site/api/v1/skills` - **Download Skill**: `https://wry-manatee-359.convex.site/api/v1/download?slug=<slug>` ## Examples User says: "I want to download the github skill from clawhub" → Use `clawhub-download.sh github` User says: "Search for weather related skills on clawhub" → Use `clawhub-search.sh "weather"` User says: "Install https://clawhub.ai/steipete/summarize" → Use `clawhub-download.sh https://clawhub.ai/steipete/summarize` User says: "What skills are popular on clawhub?" → Use `clawhub-search.sh` to list top skills by downloads

path: clawhub-search.sh
content: #!/bin/bash

# ClawHub Skill Search Tool
# Usage: clawhub-search.sh [keyword]
# If no keyword provided, lists top skills by downloads

set -e

API_URL="https://wry-manatee-359.convex.site/api/v1/skills"
SKILLS_DIR="$HOME/.agents/skills/clawhub-skills"

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

search_keyword="$1"

# Fetch skills from API
fetch_skills() {
    local cursor="$1"
    local url="$API_URL"
    if [ -n "$cursor" ]; then
        url="$API_URL?cursor=$cursor"
    fi
    curl -s "$url"
}

# Search in skill data
search_skills() {
    local keyword="$1"
    local all_skills="[]"
    local cursor=""
    local total=0
    
    # Fetch up to 100 skills (multiple pages if needed)
    while [ $total -lt 100 ]; do
        local response
        response=$(fetch_skills "$cursor")
        
        # Parse items
        local items
        items=$(echo "$response" | jq -r '.items // []')
        local count
        count=$(echo "$items" | jq 'length')
        
        if [ "$count" -eq 0 ]; then
            break
        fi
        
        all_skills=$(echo "$all_skills" "$items" | jq -s 'add')
        total=$(echo "$all_skills" | jq 'length')
        
        # Get next cursor
        cursor=$(echo "$response" | jq -r '.nextCursor // empty')
        if [ -z "$cursor" ]; then
            break
        fi
    done
    
    # Filter by keyword if provided
    if [ -n "$keyword" ]; then
        echo "$all_skills" | jq --arg kw "$keyword" '
            [.[] | select(
                (.slug // "" | ascii_downcase | contains($kw | ascii_downcase)) or
                (.displayName // "" | ascii_downcase | contains($kw | ascii_downcase)) or
                (.summary // "" | ascii_downcase | contains($kw | ascii_downcase))
            )] | sort_by(.stats.downloads) | reverse | .[0:20]
        '
    else
        # Sort by downloads, show top 20
        echo "$all_skills" | jq 'sort_by(.stats.downloads) | reverse | .[0:20]'
    fi
}

# Format and display results
display_results() {
    local skills_json="$1"
    local count
    count=$(echo "$skills_json" | jq 'length')
    
    if [ "$count" -eq 0 ]; then
        echo -e "${YELLOW}No skills found matching your search.${NC}"
        return
    fi
    
    echo ""
    echo -e "${CYAN}════════════════════════════════════════════════════════════════${NC}"
    echo -e "${CYAN}  ClawHub Skills (${count} results)${NC}"
    echo -e "${CYAN}════════════════════════════════════════════════════════════════${NC}"
    echo ""
    
    echo "$skills_json" | jq -r '.[] | @base64' | while read -r encoded; do
        local skill
        skill=$(echo "$encoded" | base64 -d)
        
        local slug displayName summary downloads stars installed
        slug=$(echo "$skill" | jq -r '.slug // "N/A"')
        displayName=$(echo "$skill" | jq -r '.displayName // "N/A"')
        summary=$(echo "$skill" | jq -r '.summary // "No description"')
        downloads=$(echo "$skill" | jq -r '.stats.downloads // 0')
        stars=$(echo "$skill" | jq -r '.stats.stars // 0')
        
        # Check if already installed
        if [ -d "$SKILLS_DIR/$slug" ]; then
            installed="${GREEN}[installed]${NC}"
        else
            installed=""
        fi
        
        # Truncate summary if too long
        if [ ${#summary} -gt 80 ]; then
            summary="${summary:0:77}..."
        fi
        
        echo -e "${GREEN}$slug${NC} $installed"
        echo -e "  ${BLUE}Name:${NC} $displayName"
        echo -e "  ${BLUE}Summary:${NC} $summary"
        echo -e "  ${BLUE}Downloads:${NC} $downloads  ${BLUE}Stars:${NC} $stars"
        echo ""
    done
    
    echo -e "${CYAN}────────────────────────────────────────────────────────────────${NC}"
    echo -e "To install a skill, use: ${YELLOW}clawhub-download.sh <slug>${NC}"
    echo -e "Or visit: ${YELLOW}https://clawhub.ai/<slug>${NC}"
    echo -e "${CYAN}────────────────────────────────────────────────────────────────${NC}"
}

# Main
if ! command -v jq &> /dev/null; then
    echo "Error: jq is required but not installed."
    echo "Install it with: sudo apt-get install jq"
    exit 1
fi

if [ -n "$search_keyword" ]; then
    echo -e "${BLUE}Searching for: ${YELLOW}$search_keyword${NC}..."
else
    echo -e "${BLUE}Fetching top skills from ClawHub...${NC}"
fi

skills_json=$(search_skills "$search_keyword")
display_results "$skills_json"

path: clawhub-download.sh
content: #!/bin/bash

# ClawHub Skill Download Tool
# Usage: clawhub-download.sh <slug|url>
# Downloads and installs a skill from ClawHub

set -e

API_URL="https://wry-manatee-359.convex.site/api/v1"
SKILLS_DIR="$HOME/.agents/skills/clawhub-skills"
TEMP_DIR="/tmp/clawhub-download-$$"

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

# Parse input - can be slug or full URL
input="$1"

if [ -z "$input" ]; then
    echo -e "${RED}Error: No skill specified.${NC}"
    echo "Usage: clawhub-download.sh <slug|url>"
    echo ""
    echo "Examples:"
    echo "  clawhub-download.sh github"
    echo "  clawhub-download.sh https://clawhub.ai/steipete/github"
    exit 1
fi

# Extract slug from URL or use as-is
if [[ "$input" == https://clawhub.ai/* ]]; then
    # Extract slug from URL (format: https://clawhub.ai/owner/slug)
    slug=$(echo "$input" | sed 's|https://clawhub.ai/[^/]*/||')
else
    slug="$input"
fi

echo -e "${CYAN}════════════════════════════════════════════════════════════════${NC}"
echo -e "${CYAN}  ClawHub Skill Downloader${NC}"
echo -e "${CYAN}════════════════════════════════════════════════════════════════${NC}"
echo ""
echo -e "${BLUE}Skill:${NC} $slug"
echo -e "${BLUE}Source:${NC} https://clawhub.ai/$slug"
echo ""

# Check dependencies
if ! command -v curl &> /dev/null; then
    echo -e "${RED}Error: curl is required but not installed.${NC}"
    exit 1
fi

if ! command -v unzip &> /dev/null; then
    echo -e "${RED}Error: unzip is required but not installed.${NC}"
    exit 1
fi

# Create temp directory
mkdir -p "$TEMP_DIR"

# Cleanup on exit
cleanup() {
    rm -rf "$TEMP_DIR"
}
trap cleanup EXIT

# Download skill package
echo -e "${YELLOW}Downloading skill package...${NC}"
download_url="$API_URL/download?slug=$slug"

http_code=$(curl -s -w "%{http_code}" -o "$TEMP_DIR/skill.zip" "$download_url")

if [ "$http_code" != "200" ]; then
    echo -e "${RED}Error: Failed to download skill (HTTP $http_code)${NC}"
    echo -e "${RED}URL: $download_url${NC}"
    exit 1
fi

# Check if it's a valid zip file
if ! unzip -t "$TEMP_DIR/skill.zip" &> /dev/null; then
    echo -e "${RED}Error: Downloaded file is not a valid zip archive.${NC}"
    exit 1
fi

# Extract skill package
echo -e "${YELLOW}Extracting skill package...${NC}"
unzip -o "$TEMP_DIR/skill.zip" -d "$TEMP_DIR/extracted" &> /dev/null

# Check for SKILL.md
if [ ! -f "$TEMP_DIR/extracted/SKILL.md" ]; then
    echo -e "${RED}Error: Downloaded package does not contain SKILL.md${NC}"
    exit 1
fi

# Create skill directory
skill_dir="$SKILLS_DIR/$slug"
mkdir -p "$skill_dir"

# Copy files to skill directory
echo -e "${YELLOW}Installing skill to $skill_dir...${NC}"
cp -r "$TEMP_DIR/extracted/"* "$skill_dir/"

# Display skill info
echo ""
echo -e "${GREEN}✓ Skill installed successfully!${NC}"
echo ""
echo -e "${CYAN}────────────────────────────────────────────────────────────────${NC}"

# Show skill details
if [ -f "$skill_dir/SKILL.md" ]; then
    echo -e "${BLUE}Skill Description:${NC}"
    echo ""
    # Extract name and description from SKILL.md
    skill_name=$(grep -m1 "^name:" "$skill_dir/SKILL.md" | sed 's/name: *//' | tr -d '"')
    skill_desc=$(grep -m1 "^description:" "$skill_dir/SKILL.md" | sed 's/description: *//' | tr -d '"')
    
    if [ -n "$skill_name" ]; then
        echo -e "  ${GREEN}Name:${NC} $skill_name"
    fi
    if [ -n "$skill_desc" ]; then
        echo -e "  ${GREEN}Description:${NC} $skill_desc"
    fi
    echo ""
fi

# Show _meta.json info if exists
if [ -f "$skill_dir/_meta.json" ]; then
    version=$(jq -r '.version // "N/A"' "$skill_dir/_meta.json")
    published=$(jq -r '.publishedAt // "N/A"' "$skill_dir/_meta.json")
    
    echo -e "  ${GREEN}Version:${NC} $version"
    if [ "$published" != "null" ] && [ "$published" != "N/A" ]; then
        # Convert timestamp to readable date
        if [[ "$published" =~ ^[0-9]+$ ]]; then
            pub_date=$(date -d "@$((published/1000))" "+%Y-%m-%d" 2>/dev/null || echo "N/A")
            echo -e "  ${GREEN}Published:${NC} $pub_date"
        fi
    fi
fi

echo -e "${CYAN}────────────────────────────────────────────────────────────────${NC}"
echo ""
echo -e "${YELLOW}Skill files:${NC}"
ls -la "$skill_dir"
echo ""
echo -e "${GREEN}The skill is now available for use!${NC}"
echo -e "Restart your agent to load the new skill, or it will be loaded on next session."

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