Files
blackroad/scripts/claude-skill-matcher.sh
Alexa Amundson 78fbe80f2a Initial monorepo — everything BlackRoad in one place
bin/       230 CLI tools (ask-*, br-*, agent-*, roadid, carpool)
scripts/   99 automation scripts
fleet/     Node configs and deployment
workers/   Cloudflare Worker sources (roadpay, road-search, squad webhooks)
roadc/     RoadC programming language
roadnet/   Mesh network (5 APs, WireGuard)
operator/  Memory system scripts
config/    System configs
dotfiles/  Shell configs
docs/      Documentation

BlackRoad OS — Pave Tomorrow.

RoadChain-SHA2048: d1a24f55318d338b
RoadChain-Identity: alexa@sovereign
RoadChain-Full: d1a24f55318d338b24b60bad7be39286379c76ae5470817482100cb0ddbbcb97e147d07ac7243da0a9f0363e4e5c833d612b9c0df3a3cd20802465420278ef74875a5b77f55af6fe42a931b8b635b3d0d0b6bde9abf33dc42eea52bc03c951406d8cbe49f1a3d29b26a94dade05e9477f34a7d4d4c6ec4005c3c2ac54e73a68440c512c8e83fd9b1fe234750b898ef8f4032c23db173961fe225e67a0432b5293a9714f76c5c57ed5fdf35b9fb40fd73c03ebf88b7253c6a0575f5afb6a6b49b3bda310602fb1ef676859962dad2aebbb2875814b30eee0a8ba195e482d4cbc91d8819e7f38f6db53e8063401649c77bb994371473cabfb917fb53e8cbe73d60
2026-03-14 17:08:41 -05:00

374 lines
12 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# Claude Skill Matcher - ML-powered Claude-to-task matching algorithm!
# Analyzes past work patterns and intelligently matches Claudes to tasks
MEMORY_DIR="$HOME/.blackroad/memory"
MATCHER_DIR="$MEMORY_DIR/skill-matcher"
# Colors
GREEN='\033[0;32m'
CYAN='\033[0;36m'
YELLOW='\033[1;33m'
PURPLE='\033[0;35m'
BLUE='\033[0;34m'
BOLD='\033[1m'
NC='\033[0m'
# Initialize skill matcher
init_matcher() {
mkdir -p "$MATCHER_DIR"/{profiles,matches,training-data}
cat > "$MATCHER_DIR/skill-taxonomy.json" << 'EOF'
{
"skills": {
"backend": {
"keywords": ["api", "server", "backend", "fastapi", "express", "django"],
"weight": 1.0
},
"frontend": {
"keywords": ["react", "vue", "ui", "frontend", "component", "css"],
"weight": 1.0
},
"database": {
"keywords": ["postgres", "mysql", "database", "sql", "redis", "mongodb"],
"weight": 1.0
},
"devops": {
"keywords": ["docker", "k8s", "kubernetes", "deploy", "ci/cd", "terraform"],
"weight": 1.0
},
"ml": {
"keywords": ["machine learning", "neural", "tensorflow", "pytorch", "model"],
"weight": 1.0
},
"security": {
"keywords": ["security", "auth", "oauth", "encryption", "vulnerability"],
"weight": 1.0
},
"testing": {
"keywords": ["test", "pytest", "jest", "unit test", "integration"],
"weight": 0.8
},
"documentation": {
"keywords": ["docs", "documentation", "readme", "guide", "tutorial"],
"weight": 0.7
},
"integration": {
"keywords": ["integration", "api integration", "webhook", "connector"],
"weight": 0.9
},
"performance": {
"keywords": ["performance", "optimization", "cache", "benchmark"],
"weight": 0.9
}
}
}
EOF
echo -e "${GREEN}✅ Skill Matcher initialized${NC}"
}
# Build Claude profile from past work
build_profile() {
local claude_id="$1"
if [[ -z "$claude_id" ]]; then
echo -e "${YELLOW}Usage: build-profile <claude-id>${NC}"
return 1
fi
echo -e "${CYAN}🧠 Building skill profile for: ${BOLD}$claude_id${NC}"
# Analyze completed tasks and memory entries
local work_history=$(grep "$claude_id" "$MEMORY_DIR/journals/master-journal.jsonl" 2>/dev/null | \
jq -r 'select(.action == "completed" or .action == "announce") | .details' | \
tr '[:upper:]' '[:lower:]')
# Score each skill
declare -A skill_scores
while IFS= read -r skill; do
local score=0
local keywords=$(jq -r --arg skill "$skill" '.skills[$skill].keywords[]' "$MATCHER_DIR/skill-taxonomy.json")
while IFS= read -r keyword; do
local count=$(echo "$work_history" | grep -o "$keyword" | wc -l | tr -d ' ')
((score += count))
done <<< "$keywords"
skill_scores[$skill]=$score
done < <(jq -r '.skills | keys[]' "$MATCHER_DIR/skill-taxonomy.json")
# Create profile
local profile_file="$MATCHER_DIR/profiles/${claude_id}.json"
local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ")
echo "{" > "$profile_file"
echo " \"claude_id\": \"$claude_id\"," >> "$profile_file"
echo " \"updated_at\": \"$timestamp\"," >> "$profile_file"
echo " \"skills\": {" >> "$profile_file"
local first=true
for skill in "${!skill_scores[@]}"; do
[[ "$first" == "false" ]] && echo "," >> "$profile_file"
echo -n " \"$skill\": ${skill_scores[$skill]}" >> "$profile_file"
first=false
done
echo "" >> "$profile_file"
echo " }," >> "$profile_file"
echo " \"total_work\": $(echo "$work_history" | wc -l | tr -d ' ')" >> "$profile_file"
echo "}" >> "$profile_file"
# Display profile
echo ""
echo -e "${BOLD}${PURPLE}📊 Skill Profile:${NC}"
for skill in "${!skill_scores[@]}"; do
local score=${skill_scores[$skill]}
if [[ $score -gt 0 ]]; then
local bars=$(printf '█%.0s' $(seq 1 $((score > 10 ? 10 : score))))
echo -e " ${CYAN}$skill:${NC} $bars ${GREEN}($score)${NC}"
fi
done
echo ""
echo -e "${GREEN}✅ Profile saved to: $profile_file${NC}"
}
# Match Claude to task
match_to_task() {
local task_description="$1"
local top_n="${2:-5}"
if [[ -z "$task_description" ]]; then
echo -e "${YELLOW}Usage: match <task-description> [top-n]${NC}"
return 1
fi
echo -e "${CYAN}🎯 Finding best Claudes for task...${NC}"
echo -e "${BLUE}Task: ${task_description:0:80}...${NC}"
echo ""
# Analyze task to extract required skills
local task_lower=$(echo "$task_description" | tr '[:upper:]' '[:lower:]')
declare -A task_skills
while IFS= read -r skill; do
local score=0
local keywords=$(jq -r --arg skill "$skill" '.skills[$skill].keywords[]' "$MATCHER_DIR/skill-taxonomy.json")
while IFS= read -r keyword; do
if echo "$task_lower" | grep -q "$keyword"; then
((score++))
fi
done <<< "$keywords"
task_skills[$skill]=$score
done < <(jq -r '.skills | keys[]' "$MATCHER_DIR/skill-taxonomy.json")
echo -e "${BOLD}Required Skills:${NC}"
for skill in "${!task_skills[@]}"; do
[[ ${task_skills[$skill]} -gt 0 ]] && echo -e "${CYAN}$skill${NC} (${task_skills[$skill]} matches)"
done
echo ""
# Match against Claude profiles
declare -A match_scores
for profile_file in "$MATCHER_DIR/profiles"/*.json; do
[[ ! -f "$profile_file" ]] && continue
local claude=$(jq -r '.claude_id' "$profile_file")
local total_score=0
for skill in "${!task_skills[@]}"; do
local task_need=${task_skills[$skill]}
local claude_skill=$(jq -r --arg skill "$skill" '.skills[$skill] // 0' "$profile_file")
# Score = task need × Claude skill level
local score=$((task_need * claude_skill))
((total_score += score))
done
match_scores[$claude]=$total_score
done
# Sort and display top matches
echo -e "${BOLD}${GREEN}🏆 Top Matches:${NC}"
echo ""
local rank=1
for claude in $(for c in "${!match_scores[@]}"; do echo "${match_scores[$c]} $c"; done | sort -rn | head -n "$top_n" | awk '{print $2}'); do
local score=${match_scores[$claude]}
# Medal/badge
local badge=""
case $rank in
1) badge="${YELLOW}🥇 " ;;
2) badge="${BLUE}🥈 " ;;
3) badge="${PURPLE}🥉 " ;;
*) badge=" " ;;
esac
echo -e "${badge}${BOLD}#$rank${NC} ${CYAN}$claude${NC} - ${GREEN}Score: $score${NC}"
# Show matching skills
local profile_file="$MATCHER_DIR/profiles/${claude}.json"
echo -n " Skills: "
for skill in "${!task_skills[@]}"; do
if [[ ${task_skills[$skill]} -gt 0 ]]; then
local claude_skill=$(jq -r --arg skill "$skill" '.skills[$skill] // 0' "$profile_file")
[[ $claude_skill -gt 0 ]] && echo -n "${skill}(${claude_skill}) "
fi
done
echo ""
((rank++))
done
echo ""
echo -e "${GREEN}✅ Top $top_n matches found${NC}"
}
# Build profiles for all active Claudes
build_all_profiles() {
echo -e "${CYAN}🧠 Building profiles for all active Claudes...${NC}"
echo ""
local active_claudes=$(tail -200 "$MEMORY_DIR/journals/master-journal.jsonl" 2>/dev/null | \
jq -r '.entity' | grep "claude-" | sort -u)
local count=0
while IFS= read -r claude; do
[[ -z "$claude" ]] && continue
echo -e "${BLUE}Building: $claude${NC}"
build_profile "$claude" > /dev/null 2>&1
((count++))
done <<< "$active_claudes"
echo ""
echo -e "${GREEN}✅ Built $count Claude profiles${NC}"
}
# Show all profiles
list_profiles() {
echo -e "${BOLD}${PURPLE}╔════════════════════════════════════════════════════════════╗${NC}"
echo -e "${BOLD}${PURPLE}║ 👥 CLAUDE SKILL PROFILES 👥 ║${NC}"
echo -e "${BOLD}${PURPLE}╚════════════════════════════════════════════════════════════╝${NC}"
echo ""
for profile_file in "$MATCHER_DIR/profiles"/*.json; do
[[ ! -f "$profile_file" ]] && continue
local claude=$(jq -r '.claude_id' "$profile_file")
local total=$(jq -r '.total_work' "$profile_file")
echo -e "${CYAN}$claude${NC} (${total} work items)"
# Top 3 skills
local top_skills=$(jq -r '.skills | to_entries | sort_by(-.value) | .[0:3] | .[] | "\(.key): \(.value)"' "$profile_file")
while IFS=: read -r skill score; do
echo -e "${skill}: ${GREEN}${score}${NC}"
done <<< "$top_skills"
echo ""
done
}
# Show help
show_help() {
cat << EOF
${CYAN}╔════════════════════════════════════════════════════════════╗${NC}
${CYAN}║ 🧬 Claude Skill Matcher - Help 🧬 ║${NC}
${CYAN}╚════════════════════════════════════════════════════════════╝${NC}
${GREEN}USAGE:${NC}
$0 <command> [options]
${GREEN}COMMANDS:${NC}
${BLUE}init${NC}
Initialize skill matcher system
${BLUE}build-profile${NC} <claude-id>
Build skill profile for a Claude based on past work
Example: $0 build-profile claude-backend-specialist
${BLUE}build-all${NC}
Build profiles for all active Claudes
${BLUE}match${NC} <task-description> [top-n]
Find best Claude matches for a task (default: top 5)
Example: $0 match "Build FastAPI backend with PostgreSQL" 3
${BLUE}list${NC}
List all Claude profiles
${GREEN}HOW IT WORKS:${NC}
1. Analyzes Claude's past work from memory entries
2. Scores skills based on keyword matching
3. Builds comprehensive skill profile
4. Matches tasks to Claudes using similarity scoring
5. Returns ranked list of best matches
${GREEN}SKILLS TRACKED:${NC}
• Backend (API, servers, FastAPI)
• Frontend (React, Vue, UI)
• Database (PostgreSQL, Redis, SQL)
• DevOps (Docker, K8s, deployment)
• ML (TensorFlow, models)
• Security (Auth, encryption)
• Testing (pytest, unit tests)
• Documentation (guides, tutorials)
• Integration (APIs, webhooks)
• Performance (optimization, caching)
${GREEN}EXAMPLES:${NC}
# Build profile for a Claude
$0 build-profile claude-backend-specialist
# Build all profiles
$0 build-all
# Match task to best Claudes
$0 match "Deploy React frontend with authentication"
# Get top 3 matches
$0 match "Optimize database queries" 3
EOF
}
# Main command router
case "$1" in
init)
init_matcher
;;
build-profile)
build_profile "$2"
;;
build-all)
build_all_profiles
;;
match)
match_to_task "$2" "$3"
;;
list)
list_profiles
;;
help|--help|-h)
show_help
;;
*)
echo -e "${YELLOW}Unknown command: $1${NC}"
show_help
exit 1
;;
esac