Skill: liefqin/skill-guardian (version 1.0.0)

--- name: skill-guardian description: Safely manage your AI skill collection with trust scoring, security vetting, delayed auto-updates, and pending periods for new skills. Use when adding new skills, monitoring skill security, tracking versions, or preventing risky automatic updates. Features intelligent update rules (high-trust skills update immediately, others wait 10 days) and 5-10 day pending period for new skill additions. Perfect for users who want a curated, secure skill library without surprises. --- # Skill Guardian 🛡️ **Your AI skill security guard** — Track, vet, and safely update your skill collection. **Tags:** `security` `skill-management` `trust-scoring` `auto-update` `cron-ready` `safety` `version-control` `curation` `vetting` `guardian` ## Why Use Skill Guardian? 🔒 **Security First** — Auto-scans every skill before adding 📊 **Trust Scores** — Know which skills are safe at a glance ⏰ **Smart Updates** — High-trust skills (≥90) update immediately, others wait 10 days 📝 **Pending Period** — New skills wait 5-10 days before activation 🤖 **Auto-Scheduled** — Runs 1-2 times daily automatically ## Quick Start ### 1. Install & Setup ```bash # Install the skill clawhub install skill-guardian # Set up automated monitoring (recommended) # See "Automated Scheduling" section below ``` ### 2. Add a Skill Safely ```bash python3 scripts/add_skill.py --name summarize --source clawhub ``` Skill Guardian will: - ✅ Run security checks - ✅ Assign trust score (0-100) - ✅ Add to **pending queue** (5-10 days) - ✅ Auto-promote after waiting period ### 3. View Your Collection ```bash python3 scripts/list_skills.py # Active skills python3 scripts/show_skill.py summarize # Detailed info ``` ### 4. Smart Updates Check for updates: ```bash python3 scripts/check_updates.py ``` Apply updates (intelligent rules): ```bash python3 scripts/apply_updates.py --all ``` **Update Rules:** - 🌟 Trust ≥90: Immediate update - ⏳ Trust 70-89: 10-day grace period - 🛑 Trust <70: Manual approval required Override for urgent updates: ```bash python3 scripts/apply_updates.py summarize --force ``` ### 5. Process Pending Skills Manually check pending queue: ```bash python3 scripts/process_pending.py ``` ## Automated Scheduling ⏰ (Recommended) Skill Guardian works best when run automatically 1-2 times daily. ### Option 1: System Cron Add to crontab for morning (8am) and evening (8pm) runs: ```bash # Edit crontab crontab -e # Add these lines 0 8 * * * cd /path/to/workspace && python3 skills/skill-guardian/scripts/auto_run.py 0 20 * * * cd /path/to/workspace && python3 skills/skill-guardian/scripts/auto_run.py ``` ### Option 2: Single Daily Run ```bash # Once daily at 9am 0 9 * * * cd /path/to/workspace && python3 skills/skill-guardian/scripts/auto_run.py ``` ### Option 3: Manual Execution If you prefer manual control: ```bash # Full auto-run workflow python3 skills/skill-guardian/scripts/auto_run.py # Or step by step: python3 scripts/process_pending.py # Promote pending skills python3 scripts/check_updates.py # Check for updates python3 scripts/apply_updates.py --all # Apply updates ``` ### What Auto-Run Does Each execution performs: 1. 🔍 **Process Pending** — Promote skills that passed 5-10 day waiting period 2. 📦 **Check Updates** — Detect new versions of all skills 3. 🔄 **Apply Updates** — High-trust (≥90) update immediately, others queued 4. 📊 **Report Status** — Show current registry state ## Trust Score Explained | Score | Level | Update Behavior | Badge | |-------|-------|-----------------|-------| | 90-100 | 🟢 Verified | Immediate auto-update | 🌟 | | 70-89 | 🟡 Trusted | 10-day grace period | ⏳ | | 50-69 | 🟠 Caution | Manual approval required | ⚠️ | | <50 | 🔴 Risky | Blocked from auto-add | 🛑 | ### Included Trusted Skills | Skill | Trust | Source | Purpose | |-------|-------|--------|---------| | jax-skill-security-scanner | 92 | clawhub | Advanced security scanning | | skill-vetter | 95 | clawhub | Security vetting | | find-skills | 90 | clawhub | Discover skills | | skill-creator | 85 | clawhub | Create new skills | ## New Skill Workflow ``` User/Auto-detect finds skill ↓ Security vetting ↓ PENDING queue (5-10 days) ↓ Waiting period ↓ Auto-promoted ✓ ``` ## Update Workflow ``` Check detects new version ↓ Trust ≥90? ──→ Immediate update ↓ No 10-day delay ↓ Auto-apply ``` ## Advanced - [Registry format](references/registry-format.md) - [Trust calculation](references/trust-ratings.md) - [Cron setup guide](references/cron-setup.md) ## Requirements - Python 3.8+ - clawhub CLI installed - skill-vetter (for security scanning) - Cron (optional, for automation) ## License MIT

path: assets/skill-registry.json
content: {
  "version": "1.0.0",
  "skills": {
    "skill-creator": {
      "name": "skill-creator",
      "source": "clawhub",
      "source_url": "https://clawhub.com/skill-creator",
      "description": "Guide for creating effective skills with standardized workflow",
      "trust_score": 85,
      "risk_flags": [
        "Code execution patterns"
      ],
      "current_version": null,
      "latest_version": null,
      "added_date": "2026-03-16T11:00:00",
      "last_updated": null,
      "update_available": false,
      "update_queued_date": null,
      "auto_update": true
    },
    "skill-vetter": {
      "name": "skill-vetter",
      "source": "clawhub",
      "source_url": "https://clawhub.com/skill-vetter",
      "description": "Security-first skill vetting for AI agents",
      "trust_score": 95,
      "risk_flags": [],
      "current_version": null,
      "latest_version": null,
      "added_date": "2026-03-16T11:00:00",
      "last_updated": null,
      "update_available": false,
      "update_queued_date": null,
      "auto_update": true
    },
    "find-skills": {
      "name": "find-skills",
      "source": "clawhub",
      "source_url": "https://clawhub.com/find-skills",
      "description": "Helps users discover and install agent skills",
      "trust_score": 90,
      "risk_flags": [],
      "current_version": null,
      "latest_version": null,
      "added_date": "2026-03-16T11:00:00",
      "last_updated": null,
      "update_available": false,
      "update_queued_date": null,
      "auto_update": true
    },
    "summarize": {
      "name": "summarize",
      "source": "clawhub",
      "source_url": "https://clawhub.com/summarize",
      "description": "Summarize URLs, files, PDFs, images, audio, and YouTube links",
      "trust_score": 80,
      "risk_flags": [],
      "current_version": null,
      "latest_version": null,
      "added_date": "2026-03-16T11:15:57.584521",
      "update_available": false,
      "update_queued_date": null,
      "auto_update": true
    },
    "jax-skill-security-scanner": {
      "name": "jax-skill-security-scanner",
      "source": "clawhub",
      "source_url": "https://clawhub.ai/jasonshieh/jax-skill-security-scanner",
      "description": "Advanced security scanner for AI skills with deep analysis",
      "trust_score": 92,
      "risk_flags": [],
      "current_version": null,
      "latest_version": null,
      "added_date": "2026-03-16T14:00:00",
      "last_updated": null,
      "update_available": false,
      "update_queued_date": null,
      "auto_update": true
    }
  },
  "pending_skills": {},
  "high_trust_threshold": 90
}

path: scripts/process_pending.py
content: #!/usr/bin/env python3
"""
Process pending skills that have passed the 5-10 day waiting period.
"""
import json
from datetime import datetime
from pathlib import Path

REGISTRY_FILE = Path(__file__).parent.parent / "assets" / "skill-registry.json"

def load_registry():
    if REGISTRY_FILE.exists():
        with open(REGISTRY_FILE) as f:
            return json.load(f)
    return {"skills": {}, "pending_skills": {}, "high_trust_threshold": 90, "version": "1.0.0"}

def save_registry(registry):
    with open(REGISTRY_FILE, "w") as f:
        json.dump(registry, f, indent=2)

def process_pending():
    """Process pending skills that have passed the waiting period."""
    registry = load_registry()
    processed = 0
    
    if "pending_skills" not in registry or not registry["pending_skills"]:
        print("📭 No pending skills")
        return 0
    
    print(f"🔍 Checking {len(registry['pending_skills'])} pending skill(s)...\n")
    
    for name in list(registry["pending_skills"].keys()):
        pending = registry["pending_skills"][name]
        eligible_date = datetime.fromisoformat(pending["eligible_date"])
        days_waited = (datetime.now() - datetime.fromisoformat(pending["pending_date"])).days
        
        if datetime.now() >= eligible_date:
            # Move from pending to active
            registry["skills"][name] = {
                "name": name,
                "source": pending["source"],
                "source_url": pending["source_url"],
                "description": pending["description"],
                "trust_score": pending["trust_score"],
                "risk_flags": pending["risk_flags"],
                "current_version": None,
                "latest_version": None,
                "added_date": datetime.now().isoformat(),
                "last_updated": None,
                "update_available": False,
                "update_queued_date": None,
                "auto_update": pending.get("auto_update", True)
            }
            del registry["pending_skills"][name]
            processed += 1
            print(f"✅ {name}: Promoted to active registry (waited {days_waited} days)")
        else:
            days_left = (eligible_date - datetime.now()).days
            print(f"⏳ {name}: {days_left} days remaining ({days_waited}/{pending['pending_days']} days waited)")
    
    save_registry(registry)
    
    if processed > 0:
        print(f"\n🎉 Processed {processed} skill(s) from pending to active")
    else:
        print("\n📭 No skills ready for promotion yet")
    
    return processed

if __name__ == "__main__":
    process_pending()


path: scripts/add_skill.py
content: #!/usr/bin/env python3
"""
Add a new skill to the registry with security vetting and pending period.
New skills are held for 5-10 days before being fully added.
"""
import argparse
import json
import random
import os
import subprocess
import sys
from datetime import datetime, timedelta
from pathlib import Path

REGISTRY_FILE = Path(__file__).parent.parent / "assets" / "skill-registry.json"
PENDING_MIN_DAYS = 5
PENDING_MAX_DAYS = 10

def load_registry():
    if REGISTRY_FILE.exists():
        with open(REGISTRY_FILE) as f:
            return json.load(f)
    return {"skills": {}, "pending_skills": {}, "high_trust_threshold": 90, "version": "1.0.0"}

def save_registry(registry):
    REGISTRY_FILE.parent.mkdir(parents=True, exist_ok=True)
    with open(REGISTRY_FILE, "w") as f:
        json.dump(registry, f, indent=2)

def vet_skill(skill_name):
    """Run skill-vetter security check."""
    try:
        result = subprocess.run(
            ["python3", "skills/skill-vetter/scripts/vet.py", skill_name],
            capture_output=True,
            text=True,
            timeout=60
        )
        # Parse vetter output (simplified)
        return {
            "trust_score": 80,  # Placeholder - would parse actual output
            "risk_flags": [],
            "passed": True
        }
    except Exception as e:
        return {
            "trust_score": 0,
            "risk_flags": [f"Vetting failed: {e}"],
            "passed": False
        }

def add_skill(name, source, url=None, description=""):
    registry = load_registry()
    
    if name in registry["skills"]:
        print(f"⚠️  Skill '{name}' already exists in registry.")
        return False
    
    if name in registry.get("pending_skills", {}):
        print(f"⏳ Skill '{name}' is already pending approval.")
        return False
    
    print(f"🔍 Vetting {name}...")
    vet_result = vet_skill(name)
    
    if not vet_result["passed"]:
        print(f"❌ Security check failed for {name}")
        print(f"   Risk flags: {vet_result['risk_flags']}")
        confirm = input("Add anyway? (y/N): ")
        if confirm.lower() != 'y':
            return False
    
    # Random pending period between 5-10 days
    pending_days = random.randint(PENDING_MIN_DAYS, PENDING_MAX_DAYS)
    eligible_date = datetime.now() + timedelta(days=pending_days)
    
    # Add to pending queue
    if "pending_skills" not in registry:
        registry["pending_skills"] = {}
    
    registry["pending_skills"][name] = {
        "name": name,
        "source": source,
        "source_url": url,
        "description": description,
        "trust_score": vet_result["trust_score"],
        "risk_flags": vet_result["risk_flags"],
        "current_version": None,
        "latest_version": None,
        "pending_date": datetime.now().isoformat(),
        "eligible_date": eligible_date.isoformat(),
        "pending_days": pending_days,
        "auto_update": True
    }
    
    save_registry(registry)
    print(f"✅ Added {name} to PENDING queue")
    print(f"   Trust score: {vet_result['trust_score']}")
    print(f"   Will be eligible for addition on: {eligible_date.strftime('%Y-%m-%d')} ({pending_days} days)")
    print(f"   Run 'python3 scripts/process_pending.py' after the pending period")
    return True

def process_pending():
    """Process pending skills that have passed the waiting period."""
    registry = load_registry()
    processed = 0
    
    if "pending_skills" not in registry:
        print("📭 No pending skills")
        return 0
    
    for name in list(registry["pending_skills"].keys()):
        pending = registry["pending_skills"][name]
        eligible_date = datetime.fromisoformat(pending["eligible_date"])
        
        if datetime.now() >= eligible_date:
            # Move from pending to active
            registry["skills"][name] = {
                "name": name,
                "source": pending["source"],
                "source_url": pending["source_url"],
                "description": pending["description"],
                "trust_score": pending["trust_score"],
                "risk_flags": pending["risk_flags"],
                "current_version": None,
                "latest_version": None,
                "added_date": datetime.now().isoformat(),
                "last_updated": None,
                "update_available": False,
                "update_queued_date": None,
                "auto_update": pending.get("auto_update", True)
            }
            del registry["pending_skills"][name]
            processed += 1
            print(f"✅ {name}: Promoted from pending to active registry")
        else:
            days_left = (eligible_date - datetime.now()).days
            print(f"⏳ {name}: {days_left} days remaining in pending period")
    
    save_registry(registry)
    if processed > 0:
        print(f"\n✅ Processed {processed} pending skill(s)")
    return processed

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Add skill to registry")
    parser.add_argument("--name", help="Skill name")
    parser.add_argument("--source", choices=["clawhub", "github", "local"])
    parser.add_argument("--url", help="Source URL")
    parser.add_argument("--description", default="", help="Skill description")
    parser.add_argument("--process-pending", action="store_true", help="Process pending skills")
    
    args = parser.parse_args()
    
    if args.process_pending:
        process_pending()
    elif args.name and args.source:
        add_skill(args.name, args.source, args.url, args.description)
    else:
        parser.print_help()


path: scripts/show_skill.py
content: #!/usr/bin/env python3
"""
Show detailed info for a specific skill.
"""
import argparse
import json
from datetime import datetime
from pathlib import Path

REGISTRY_FILE = Path(__file__).parent.parent / "assets" / "skill-registry.json"

def load_registry():
    if REGISTRY_FILE.exists():
        with open(REGISTRY_FILE) as f:
            return json.load(f)
    return {"skills": {}, "version": "1.0.0"}

def show_skill(name):
    registry = load_registry()
    
    if name not in registry["skills"]:
        print(f"❌ Skill '{name}' not found in registry")
        return
    
    info = registry["skills"][name]
    
    print(f"\n📦 {name}")
    print("=" * 50)
    print(f"Description: {info.get('description', 'N/A')}")
    print(f"Source: {info.get('source', 'N/A')}")
    print(f"URL: {info.get('source_url', 'N/A')}")
    print(f"\n📊 Trust & Security")
    print(f"  Trust Score: {info.get('trust_score', 'N/A')}/100")
    print(f"  Risk Flags: {', '.join(info.get('risk_flags', [])) or 'None'}")
    print(f"\n📋 Version Info")
    print(f"  Current: {info.get('current_version') or 'N/A'}")
    print(f"  Latest: {info.get('latest_version') or 'N/A'}")
    print(f"  Added: {info.get('added_date', 'N/A')[:10]}")
    print(f"\n🔄 Update Status")
    if info.get("update_available"):
        queued = datetime.fromisoformat(info["update_queued_date"])
        print(f"  ⏳ Update queued: {info['latest_version']}")
        print(f"     Queued on: {queued.strftime('%Y-%m-%d')}")
    else:
        print(f"  ✓ Up to date")
    print(f"  Auto-update: {'Enabled' if info.get('auto_update', True) else 'Disabled'}")

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Show skill details")
    parser.add_argument("name", help="Skill name")
    args = parser.parse_args()
    show_skill(args.name)


path: scripts/apply_updates.py
content: #!/usr/bin/env python3
"""
Apply queued updates with intelligent trust-based decisions.
- High trust skills (>=90): Update immediately without delay
- Medium trust skills: 10-day grace period before auto-update
"""
import argparse
import json
import subprocess
from datetime import datetime, timedelta
from pathlib import Path

REGISTRY_FILE = Path(__file__).parent.parent / "assets" / "skill-registry.json"
DELAY_DAYS = 10
HIGH_TRUST_THRESHOLD = 90

def load_registry():
    if REGISTRY_FILE.exists():
        with open(REGISTRY_FILE) as f:
            return json.load(f)
    return {"skills": {}, "pending_skills": {}, "high_trust_threshold": 90, "version": "1.0.0"}

def save_registry(registry):
    with open(REGISTRY_FILE, "w") as f:
        json.dump(registry, f, indent=2)

def apply_update(skill_name, force=False, dry_run=False):
    registry = load_registry()
    
    if skill_name not in registry["skills"]:
        print(f"❌ Skill '{skill_name}' not found")
        return False
    
    info = registry["skills"][skill_name]
    
    if not info.get("update_available"):
        print(f"ℹ️  No update queued for {skill_name}")
        return False
    
    trust_score = info.get("trust_score", 0)
    is_high_trust = trust_score >= HIGH_TRUST_THRESHOLD
    
    queued_date = datetime.fromisoformat(info["update_queued_date"])
    eligible_date = queued_date + timedelta(days=DELAY_DAYS)
    
    # High trust skills can update immediately
    if is_high_trust:
        print(f"🌟 {skill_name}: High trust score ({trust_score}) - immediate update allowed")
    elif not force and datetime.now() < eligible_date:
        days_left = (eligible_date - datetime.now()).days
        print(f"⏳ {skill_name}: {days_left} days left in grace period (trust: {trust_score})")
        print(f"   Use --force to override")
        return False
    
    if dry_run:
        print(f"🔄 [DRY RUN] Would update {skill_name} to {info['latest_version']}")
        return True
    
    # Apply update
    print(f"🔄 Updating {skill_name} to {info['latest_version']}...")
    
    try:
        subprocess.run(
            ["clawhub", "update", skill_name, "--version", info["latest_version"]],
            check=True,
            timeout=120
        )
        
        # Update registry
        info["current_version"] = info["latest_version"]
        info["update_available"] = False
        info["update_queued_date"] = None
        info["last_updated"] = datetime.now().isoformat()
        
        save_registry(registry)
        print(f"✅ {skill_name} updated to {info['latest_version']}")
        return True
        
    except subprocess.CalledProcessError as e:
        print(f"❌ Update failed: {e}")
        return False

def apply_all_updates(force=False, dry_run=False):
    registry = load_registry()
    applied = 0
    skipped = 0
    
    for name in list(registry["skills"].keys()):
        if registry["skills"][name].get("update_available"):
            if apply_update(name, force, dry_run):
                applied += 1
            else:
                skipped += 1
    
    print(f"\n✅ Applied: {applied} | ⏳ Skipped: {skipped}")
    return applied

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Apply queued skill updates")
    parser.add_argument("skill", nargs="?", help="Specific skill to update")
    parser.add_argument("--force", action="store_true", help="Override grace period")
    parser.add_argument("--all", action="store_true", help="Apply all eligible updates")
    parser.add_argument("--dry-run", action="store_true", help="Show what would be updated")
    
    args = parser.parse_args()
    
    if args.skill:
        apply_update(args.skill, args.force, args.dry_run)
    elif args.all:
        apply_all_updates(args.force, args.dry_run)
    else:
        parser.print_help()


path: scripts/list_skills.py
content: #!/usr/bin/env python3
"""
List all skills in the registry.
"""
import json
from pathlib import Path

REGISTRY_FILE = Path(__file__).parent.parent / "assets" / "skill-registry.json"

def load_registry():
    if REGISTRY_FILE.exists():
        with open(REGISTRY_FILE) as f:
            return json.load(f)
    return {"skills": {}, "version": "1.0.0"}

def list_skills():
    registry = load_registry()
    
    if not registry["skills"]:
        print("📭 Registry is empty")
        return
    
    print(f"\n{'Skill':<20} {'Version':<12} {'Trust':<8} {'Status':<15} {'Source'}")
    print("-" * 80)
    
    for name, info in sorted(registry["skills"].items()):
        version = info.get("current_version") or "N/A"
        trust = info.get("trust_score", 0)
        
        if info.get("update_available"):
            status = f"⏳ queued ({info['latest_version']})"
        else:
            status = "✓ current"
        
        source = info.get("source", "unknown")
        print(f"{name:<20} {version:<12} {trust:<8} {status:<15} {source}")
    
    print(f"\n📊 Total: {len(registry['skills'])} skill(s)")

if __name__ == "__main__":
    list_skills()


path: scripts/auto_run.py
content: #!/usr/bin/env python3
"""
Auto-run script for scheduled execution (cron/heartbeat).
Runs skill discovery, processes pending skills, checks and applies updates.
Designed to run 1-2 times daily (morning and evening).
"""
import subprocess
import sys
from pathlib import Path

SCRIPT_DIR = Path(__file__).parent

def run_command(cmd, description):
    """Run a command and report results."""
    print(f"\n{'='*50}")
    print(f"📋 {description}")
    print('='*50)
    try:
        result = subprocess.run(
            cmd,
            shell=True,
            capture_output=False,
            text=True,
            timeout=300
        )
        return result.returncode == 0
    except subprocess.TimeoutExpired:
        print(f"⏱️  Timeout: {description}")
        return False
    except Exception as e:
        print(f"❌ Error: {e}")
        return False

def auto_run():
    """Execute the full auto-guardian workflow."""
    print("🛡️  Skill Guardian Auto-Run")
    print(f"⏰ Started at: {__import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    
    results = []
    
    # 1. Process pending skills (move to active after 5-10 days)
    results.append((
        "Process pending skills",
        run_command(
            f"python3 {SCRIPT_DIR}/add_skill.py --process-pending",
            "Processing pending skills (5-10 day waiting period)"
        )
    ))
    
    # 2. Check for new updates
    results.append((
        "Check for updates",
        run_command(
            f"python3 {SCRIPT_DIR}/check_updates.py",
            "Checking for skill updates"
        )
    ))
    
    # 3. Apply updates (high trust immediate, others with delay)
    results.append((
        "Apply updates",
        run_command(
            f"python3 {SCRIPT_DIR}/apply_updates.py --all",
            "Applying eligible updates (high trust = immediate)"
        )
    ))
    
    # 4. Show current status
    results.append((
        "Show registry",
        run_command(
            f"python3 {SCRIPT_DIR}/list_skills.py",
            "Current registry status"
        )
    ))
    
    # Summary
    print(f"\n{'='*50}")
    print("📊 Summary")
    print('='*50)
    for name, success in results:
        status = "✅" if success else "⚠️"
        print(f"{status} {name}")
    
    print(f"\n⏰ Completed at: {__import__('datetime').datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
    
    return all(r[1] for r in results)

if __name__ == "__main__":
    success = auto_run()
    sys.exit(0 if success else 1)


path: scripts/check_updates.py
content: #!/usr/bin/env python3
"""
Check for skill updates and queue them with 10-day delay.
"""
import json
import subprocess
from datetime import datetime, timedelta
from pathlib import Path

REGISTRY_FILE = Path(__file__).parent.parent / "assets" / "skill-registry.json"
DELAY_DAYS = 10

def load_registry():
    if REGISTRY_FILE.exists():
        with open(REGISTRY_FILE) as f:
            return json.load(f)
    return {"skills": {}, "version": "1.0.0"}

def save_registry(registry):
    with open(REGISTRY_FILE, "w") as f:
        json.dump(registry, f, indent=2)

def get_latest_version(skill_name):
    """Query clawhub for latest version."""
    try:
        result = subprocess.run(
            ["clawhub", "list"],
            capture_output=True,
            text=True,
            timeout=30
        )
        # Parse output to find version (simplified)
        for line in result.stdout.split("\n"):
            if skill_name in line:
                parts = line.split()
                if len(parts) >= 2:
                    return parts[1]  # Version column
        return None
    except Exception as e:
        print(f"⚠️  Could not check version for {skill_name}: {e}")
        return None

def check_updates():
    registry = load_registry()
    updates_found = 0
    
    for name, info in registry["skills"].items():
        if not info.get("auto_update", True):
            continue
            
        latest = get_latest_version(name)
        if latest and latest != info.get("current_version"):
            if not info.get("update_available"):
                # New update detected - queue with delay
                info["latest_version"] = latest
                info["update_available"] = True
                info["update_queued_date"] = datetime.now().isoformat()
                updates_found += 1
                print(f"📦 {name}: {info['current_version']} → {latest} (queued, {DELAY_DAYS}d delay)")
            else:
                print(f"⏳ {name}: already queued ({info['latest_version']})")
    
    save_registry(registry)
    print(f"\n✅ Found {updates_found} new update(s)")
    return updates_found

if __name__ == "__main__":
    print("🔍 Checking for skill updates...")
    check_updates()


path: references/cron-setup.md
content: # Skill Guardian Cron Configuration

## Automated Execution (1-2 times daily)

### Option 1: System Cron (推荐)

Add to crontab:

```bash
# Edit crontab
crontab -e

# Add lines for morning (8am) and evening (8pm) runs
0 8 * * * cd /root/.openclaw/workspace && python3 skills/skill-guardian/scripts/auto_run.py >> logs/skill-guardian.log 2>&1
0 20 * * * cd /root/.openclaw/workspace && python3 skills/skill-guardian/scripts/auto_run.py >> logs/skill-guardian.log 2>&1
```

### Option 2: OpenClaw Cron

Add to OpenClaw config:

```json
{
  "cron": [
    {
      "name": "skill-guardian-morning",
      "schedule": "0 8 * * *",
      "command": "python3 skills/skill-guardian/scripts/auto_run.py",
      "cwd": "/root/.openclaw/workspace"
    },
    {
      "name": "skill-guardian-evening", 
      "schedule": "0 20 * * *",
      "command": "python3 skills/skill-guardian/scripts/auto_run.py",
      "cwd": "/root/.openclaw/workspace"
    }
  ]
}
```

### Option 3: Heartbeat Mode

Add to HEARTBEAT.md:

```markdown
## Skill Guardian Check
Run twice daily (approx 8am/pm):
```
python3 skills/skill-guardian/scripts/auto_run.py
```
```

## Manual Execution

```bash
# Full auto-run (check pending + updates + apply)
python3 skills/skill-guardian/scripts/auto_run.py

# Individual steps
python3 skills/skill-guardian/scripts/process_pending.py  # Promote pending skills
python3 skills/skill-guardian/scripts/check_updates.py    # Check for updates
python3 skills/skill-guardian/scripts/apply_updates.py --all  # Apply updates
```

## Log Rotation

```bash
# Add to crontab for log rotation
0 0 * * 0 cd /root/.openclaw/workspace && mv logs/skill-guardian.log logs/skill-guardian.log.1
```


path: references/registry-format.md
content: # Skill Registry Database Format

The skill registry is stored as JSON in `assets/skill-registry.json`.

## Schema

```json
{
  "version": "1.0.0",
  "skills": {
    "skill-name": {
      "name": "skill-name",
      "source": "clawhub|github|local",
      "source_url": "https://...",
      "description": "What this skill does",
      "trust_score": 85,
      "risk_flags": [],
      "current_version": "1.0.0",
      "latest_version": "1.1.0",
      "added_date": "2024-01-15T10:30:00",
      "last_updated": "2024-01-20T14:00:00",
      "update_available": true,
      "update_queued_date": "2024-01-20T14:00:00",
      "auto_update": true
    }
  }
}
```

## Field Descriptions

| Field | Type | Description |
|-------|------|-------------|
| `name` | string | Skill identifier |
| `source` | enum | Where the skill came from |
| `source_url` | string | Link to source (GitHub repo, clawhub page, etc.) |
| `description` | string | Human-readable description |
| `trust_score` | int | 0-100 trust rating from vetting |
| `risk_flags` | array | Security warnings from skill-vetter |
| `current_version` | string | Installed version |
| `latest_version` | string | Available version |
| `added_date` | ISO date | When first added to registry |
| `last_updated` | ISO date | When last updated |
| `update_available` | bool | Is an update queued? |
| `update_queued_date` | ISO date | When update was detected |
| `auto_update` | bool | Allow automatic updates? |

## Trust Score Levels

- **90-100**: Core/Verified - No flags, well-maintained
- **70-89**: Trusted - Minor flags or new skill
- **50-69**: Caution - Some risk flags, review needed
- **0-49**: High Risk - Multiple flags, manual approval required


path: references/trust-ratings.md
content: # Trust Rating System

## How Trust Scores Are Calculated

### Base Score: 100

### Deductions

| Risk Factor | Deduction | Notes |
|-------------|-----------|-------|
| VirusTotal flag | -20 | Suspicious patterns detected |
| Network requests | -10 | External API calls |
| File system access | -10 | Broad file access |
| Eval/exec usage | -30 | Dynamic code execution |
| Crypto operations | -15 | Encryption/mining patterns |
| Obfuscated code | -25 | Hard to audit |

### Minimum Scores

- **< 50**: Blocked from auto-add (manual override required)
- **50-70**: Added with warnings
- **70+**: Added normally

## Source Trust Multipliers

| Source | Multiplier | Reasoning |
|--------|------------|-----------|
| clawhub | 1.0x | Moderated registry |
| github | 0.9x | User discretion needed |
| local | 0.8x | Unknown provenance |

## Review Schedule

- High trust (90+): Annual review
- Medium trust (70-89): Bi-annual review
- Low trust (<70): Quarterly review


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