Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 09:01:22 +08:00
commit 4cbc82fbd4
9 changed files with 2670 additions and 0 deletions

View File

@@ -0,0 +1,359 @@
# Ranking Algorithm for Claude Skills
Comprehensive scoring system to rank skills by popularity, freshness, and quality.
## Core Ranking Formula
```
final_score = (base_stars * freshness_multiplier * quality_bonus)
```
## Component 1: Base Stars
Direct indicator of community validation and popularity.
```bash
base_stars = repository.stargazers_count
# Minimum threshold: 10 stars (filter out experiments)
if [ $base_stars -lt 10 ]; then
skip_result=true
fi
```
## Component 2: Freshness Multiplier
Recent updates indicate active maintenance and modern practices.
### Calculate Days Since Last Update
```bash
# Get pushed_at timestamp from repository
pushed_at="2025-10-28T12:00:00Z"
# Calculate days old (macOS)
days_old=$(( ($(date +%s) - $(date -j -f "%Y-%m-%dT%H:%M:%SZ" "$pushed_at" +%s)) / 86400 ))
# Calculate days old (Linux)
days_old=$(( ($(date +%s) - $(date -d "$pushed_at" +%s)) / 86400 ))
```
### Apply Freshness Multiplier
```bash
if [ $days_old -lt 30 ]; then
freshness_multiplier=1.5
freshness_badge="🔥"
freshness_label="Hot"
elif [ $days_old -lt 90 ]; then
freshness_multiplier=1.2
freshness_badge="📅"
freshness_label="Recent"
elif [ $days_old -lt 180 ]; then
freshness_multiplier=1.0
freshness_badge="📆"
freshness_label="Active"
else
freshness_multiplier=0.5
freshness_badge="⏰"
freshness_label="Older"
fi
```
### Freshness Tiers
| Age Range | Multiplier | Badge | Label | Reasoning |
|-----------|------------|-------|-------|-----------|
| < 30 days | 1.5x | 🔥 | Hot | Very active, likely works with latest Claude |
| 30-90 days | 1.2x | 📅 | Recent | Active maintenance |
| 90-180 days | 1.0x | 📆 | Active | Stable, still maintained |
| > 180 days | 0.5x | ⏰ | Older | May be outdated or abandoned |
## Component 3: Quality Bonus (Optional)
Additional signals of skill quality beyond stars and freshness.
### Quality Signals
```bash
quality_bonus=1.0 # Start at neutral
# Has comprehensive description
if [ ${#description} -gt 100 ]; then
quality_bonus=$(echo "$quality_bonus + 0.1" | bc)
fi
# Has reference files
reference_count=$(gh api "repos/$repo/contents" | jq '[.[] | select(.name | test("references|docs|examples"))] | length')
if [ $reference_count -gt 0 ]; then
quality_bonus=$(echo "$quality_bonus + 0.1" | bc)
fi
# Has dependencies documentation
if gh api "repos/$repo/contents" | jq -e '.[] | select(.name == "package.json")' > /dev/null; then
quality_bonus=$(echo "$quality_bonus + 0.05" | bc)
fi
# Active issues/PRs indicate engagement
open_issues=$(gh api "repos/$repo" | jq '.open_issues_count')
if [ $open_issues -gt 0 ] && [ $open_issues -lt 20 ]; then
quality_bonus=$(echo "$quality_bonus + 0.05" | bc)
fi
# Has recent commits (beyond just pushed_at)
recent_commits=$(gh api "repos/$repo/commits?per_page=10" | jq 'length')
if [ $recent_commits -ge 5 ]; then
quality_bonus=$(echo "$quality_bonus + 0.1" | bc)
fi
# Cap quality bonus at 1.5x
if (( $(echo "$quality_bonus > 1.5" | bc -l) )); then
quality_bonus=1.5
fi
```
### Quality Tier Examples
| Quality Bonus | Characteristics |
|---------------|-----------------|
| 1.0x (baseline) | Basic SKILL.md only |
| 1.1x | + Good description |
| 1.2x | + Reference files |
| 1.3x | + Dependencies documented |
| 1.4x | + Active community (issues/PRs) |
| 1.5x (max) | All of the above |
## Complete Scoring Implementation
### Bash Implementation
```bash
#!/bin/bash
calculate_score() {
local repo=$1
local stars=$2
local pushed_at=$3
# Calculate days since last update
days_old=$(( ($(date +%s) - $(date -j -f "%Y-%m-%dT%H:%M:%SZ" "$pushed_at" +%s)) / 86400 ))
# Freshness multiplier
if [ $days_old -lt 30 ]; then
freshness=1.5
badge="🔥"
elif [ $days_old -lt 90 ]; then
freshness=1.2
badge="📅"
elif [ $days_old -lt 180 ]; then
freshness=1.0
badge="📆"
else
freshness=0.5
badge="⏰"
fi
# Calculate final score
score=$(echo "$stars * $freshness" | bc)
echo "$score|$badge|$days_old"
}
# Example usage
result=$(calculate_score "lackeyjb/playwright-skill" 612 "2025-10-28T12:00:00Z")
score=$(echo "$result" | cut -d'|' -f1)
badge=$(echo "$result" | cut -d'|' -f2)
days=$(echo "$result" | cut -d'|' -f3)
echo "Score: $score, Badge: $badge, Days: $days"
# Output: Score: 918.0, Badge: 🔥, Days: 2
```
### JQ Implementation (More Portable)
```bash
gh search repos "claude skills" --json name,stargazersCount,pushedAt --limit 20 | \
jq -r --arg now "$(date -u +%s)" '.[] |
. as $repo |
($repo.pushedAt | fromdateiso8601) as $pushed |
(($now | tonumber) - $pushed) / 86400 | floor as $days |
(if $days < 30 then 1.5 elif $days < 90 then 1.2 elif $days < 180 then 1.0 else 0.5 end) as $multiplier |
(if $days < 30 then "🔥" elif $days < 90 then "📅" elif $days < 180 then "📆" else "⏰" end) as $badge |
($repo.stargazersCount * $multiplier) as $score |
"\($score)|\($repo.name)|\($repo.stargazersCount)|\($badge)|\($days)"
' | sort -t'|' -k1 -nr | head -10
```
## Ranking Examples
### Real-World Scores
| Skill | Stars | Days Old | Freshness | Multiplier | Final Score | Rank |
|-------|-------|----------|-----------|------------|-------------|------|
| playwright-skill | 612 | 2 | 🔥 | 1.5x | **918** | #1 |
| agent-skill-creator | 96 | 5 | 🔥 | 1.5x | **144** | #2 |
| skill-codex | 153 | 9 | 🔥 | 1.5x | **229.5** | Would be #2, but bumped by age |
| ios-simulator-skill | 77 | 2 | 🔥 | 1.5x | **115.5** | #3 |
| claude-skills-mcp | 85 | 2 | 🔥 | 1.5x | **127.5** | #4 |
*With hot multiplier, even 77 stars beats 96 stars from 30+ days ago*
### Score Comparison Scenarios
**Scenario 1: Fresh skill vs. Popular old skill**
- Skill A: 50 stars, 10 days old → 50 × 1.5 = **75 points** 🔥
- Skill B: 100 stars, 200 days old → 100 × 0.5 = **50 points**
- **Winner: Skill A** (freshness wins)
**Scenario 2: Very popular but older skill**
- Skill A: 1000 stars, 365 days old → 1000 × 0.5 = **500 points**
- Skill B: 200 stars, 15 days old → 200 × 1.5 = **300 points** 🔥
- **Winner: Skill A** (massive popularity overcomes age)
**Scenario 3: Moderate skill, regularly updated**
- Skill A: 50 stars, 85 days old → 50 × 1.2 = **60 points** 📅
- Skill B: 60 stars, 95 days old → 60 × 1.0 = **60 points** 📆
- **Tie** (freshness threshold matters)
## Handling Edge Cases
### Newly Created Skills (< 7 days old)
```bash
# New skills may have inflated scores, add small penalty
if [ $days_old -lt 7 ]; then
new_skill_penalty=0.9
score=$(echo "$score * $new_skill_penalty" | bc)
note="⚠️ Very new skill - limited validation"
fi
```
### Archived or Deprecated Skills
```bash
# Check if repository is archived
is_archived=$(gh api "repos/$repo" | jq -r '.archived')
if [ "$is_archived" = "true" ]; then
score=0 # Exclude from results
note="🔒 Archived - no longer maintained"
fi
```
### Fork vs. Original
```bash
# Check if repository is a fork
is_fork=$(gh api "repos/$repo" | jq -r '.fork')
if [ "$is_fork" = "true" ]; then
# Check if fork has more stars than parent
parent_stars=$(gh api "repos/$repo" | jq -r '.parent.stargazers_count')
if [ $stars -gt $parent_stars ]; then
# Fork is more popular, keep it
note="🍴 Popular fork"
else
# Prefer original
score=$(echo "$score * 0.8" | bc)
note="🍴 Fork - see original"
fi
fi
```
## Sorting and Display
### Final Sort Order
```bash
# Sort by score (descending), then by stars (descending)
results | sort -t'|' -k1,1nr -k3,3nr | head -10
```
### Ties
When scores are identical:
1. Sort by stars (higher first)
2. If still tied, sort by freshness (newer first)
3. If still tied, sort alphabetically
```bash
# Multi-level sort
jq -r '.[] | "\(.score)|\(.stars)|\(.days_old)|\(.name)"' | \
sort -t'|' -k1,1nr -k2,2nr -k3,3n -k4,4
```
## Performance Optimization
### Bulk Scoring
```bash
# Score all repos in one pass
gh search repos "claude skills" --json name,stargazersCount,pushedAt,fullName --limit 50 | \
jq -r --arg now "$(date -u +%s)" '
.[] |
. as $repo |
($repo.pushedAt | fromdateiso8601) as $pushed |
(($now | tonumber) - $pushed) / 86400 | floor as $days |
(if $days < 30 then 1.5 elif $days < 90 then 1.2 elif $days < 180 then 1.0 else 0.5 end) as $mult |
($repo.stargazersCount * $mult) as $score |
{
name: $repo.name,
full_name: $repo.fullName,
stars: $repo.stargazersCount,
days_old: $days,
score: $score
}
' | jq -s 'sort_by(-.score) | .[0:10]'
```
### Caching Scores
```bash
# Cache scores to avoid recalculation
score_cache=".skill-scores.json"
# Generate or load cache
if [ ! -f "$score_cache" ] || [ $(($(date +%s) - $(stat -f %m "$score_cache"))) -gt 3600 ]; then
# Regenerate cache (older than 1 hour)
calculate_all_scores > "$score_cache"
fi
# Use cached scores
cat "$score_cache" | jq '.[] | select(.score > 50)'
```
## Customization
### User-Defined Weights
Allow users to adjust ranking preferences:
```bash
# Default weights
STAR_WEIGHT=1.0
FRESHNESS_WEIGHT=1.0
QUALITY_WEIGHT=0.5
# Calculate weighted score
weighted_score=$(echo "$stars * $STAR_WEIGHT + $freshness_score * $FRESHNESS_WEIGHT + $quality_score * $QUALITY_WEIGHT" | bc)
```
### Category-Specific Ranking
Different categories may value different factors:
```bash
# For automation skills: prioritize quality (working code)
if [ "$category" = "automation" ]; then
QUALITY_WEIGHT=1.5
fi
# For research skills: prioritize freshness (up-to-date sources)
if [ "$category" = "research" ]; then
FRESHNESS_WEIGHT=1.5
fi
```
---
**Summary:** The ranking algorithm balances popularity (stars) with recency (freshness), ensuring users see both well-established skills and cutting-edge new capabilities. Quality signals provide additional nuance for edge cases.