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
374 lines
12 KiB
Bash
Executable File
374 lines
12 KiB
Bash
Executable File
#!/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
|