Add personal superpowers overlay system

Enables users to write and manage their own skills alongside core skills.

## Key Features:
- Auto-setup on first session: Creates ~/.config/superpowers/ git repo
- Two-tier skills: Personal skills shadow core skills when paths match
- Environment variable support: PERSONAL_SUPERPOWERS_DIR, XDG_CONFIG_HOME
- GitHub integration: Optional public repo creation for sharing skills
- CLI-agnostic: Works across Claude Code, Codex CLI, Gemini CLI (future)

## Changes:
- Added hooks/setup-personal-superpowers.sh - Auto-initializes personal repo
- Updated hooks/session-start.sh - Runs setup, offers GitHub repo creation
- Updated list-skills, skills-search - Search both personal and core skills
- Renamed skills/meta/creating-skills → writing-skills
- Added skills/meta/setting-up-personal-superpowers - Setup documentation
- Added skills/meta/sharing-skills - Contribution workflow
- Removed skills/meta/installing-skills - Old ~/.clank system
- Removed all INDEX.md files - Replaced by list-skills tool
- Updated README.md, getting-started - Document personal skills workflow

## Architecture:
~/.config/superpowers/skills/  # Personal (user-created, git-tracked)
${CLAUDE_PLUGIN_ROOT}/skills/  # Core (read-only, from plugin)

Search order: Personal first, core second (first match wins)
This commit is contained in:
Jesse Vincent
2025-10-10 14:01:45 -07:00
parent dee324d417
commit 6c0ab4cfec
19 changed files with 668 additions and 590 deletions

View File

@@ -1,13 +1,17 @@
---
name: Getting Started with Skills
description: Skills wiki intro - mandatory workflows, search tool, brainstorming triggers
description: Skills wiki intro - mandatory workflows, search tool, brainstorming triggers, personal skills
when_to_use: Read this FIRST at start of each conversation when skills are active
version: 2.0.0
version: 3.0.0
---
# Getting Started with Skills
Your personal wiki of proven techniques, patterns, and tools at `${CLAUDE_PLUGIN_ROOT}/skills/`.
Two skill libraries work together:
- **Core skills** at `${CLAUDE_PLUGIN_ROOT}/skills/` (from plugin)
- **Personal skills** at `~/.config/superpowers/skills/` (yours to create and share)
Personal skills shadow core skills when names match.
## Just Read This Guide?
@@ -28,7 +32,8 @@ ${CLAUDE_PLUGIN_ROOT}/skills/getting-started/list-skills
- Load with Read tool only when needed
**When you see skill references in documentation:**
- `skills/path/name`Use Read tool on `${CLAUDE_PLUGIN_ROOT}/skills/path/name/SKILL.md`
- `skills/path/name`Check personal first (`~/.config/superpowers/skills/path/name/SKILL.md`)
- If not found, check core (`${CLAUDE_PLUGIN_ROOT}/skills/path/name/SKILL.md`)
- Load supporting files only when implementing
## Mandatory Workflow 1: Brainstorming Before Coding
@@ -115,14 +120,7 @@ You: Searching past conversations...
**Why:** Checklists without TodoWrite tracking = steps get skipped. Every time.
**Examples:** TDD (write test, watch fail, implement, verify), Systematic Debugging (4 phases), Creating Skills (RED-GREEN-REFACTOR)
## Navigation
Really, try skills-search first.
**Categories:** skills/INDEX.md → testing, debugging, coding, architecture, collaboration, meta
**Individual skill:** Load from category INDEX
**Examples:** TDD (write test, watch fail, implement, verify), Systematic Debugging (4 phases), Writing Skills (RED-GREEN-REFACTOR)
## How to Read a Skill
@@ -159,13 +157,15 @@ Your human partner's specific instructions describe WHAT to do, not HOW.
**Red flags:** "Instruction was specific" • "Seems simple" • "Workflow is overkill"
## Creating and Updating Skills
## Writing and Sharing Skills
**Before creating OR editing ANY skill:**
**All personal skills are written to `~/.config/superpowers/skills/`**
**Before writing ANY skill:**
1. **STOP** - Even if your human partner gave specific instructions
2. **Read skills/meta/creating-skills**
3. **Check in** - "You asked me to edit [skill]. Should I follow creating-skills process or make the change?"
2. **Read skills/meta/writing-skills**
3. **Follow the TDD process** - No skill without failing test first
**Your human partner's specific instruction is NOT implicit permission to skip the process.**
@@ -173,11 +173,14 @@ Your human partner's specific instructions describe WHAT to do, not HOW.
- "Just a small addition"
- "Instruction was specific, so I can proceed"
**All of these mean: STOP and check in first.**
**All of these mean: STOP and follow writing-skills process.**
Found something valuable? See skills/meta/creating-skills
**Want to share a skill with everyone?**
- See skills/meta/sharing-skills for how to contribute to core superpowers
Want a skill that doesn't exist? Edit skills/REQUESTS.md (at ${CLAUDE_PLUGIN_ROOT}/skills/REQUESTS.md)
**Want a skill that doesn't exist?**
- Write it yourself (see skills/meta/writing-skills) and share it!
- Or open an issue at https://github.com/obra/superpowers/issues
## Summary

View File

@@ -1,22 +1,50 @@
#!/usr/bin/env bash
# list-skills - Show all available skill names without descriptions
# For Claude to quickly see what exists before searching
# Searches personal skills first, then core skills (personal shadows core)
set -euo pipefail
# Detect if running from repo or installed location
# Detect core skills directory (repo or installed location)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [[ "$SCRIPT_DIR" == *"/.claude/plugins/cache/"* ]]; then
# Installed as plugin
SKILLS_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
CORE_SKILLS_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
else
# Running from repo
SKILLS_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
CORE_SKILLS_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
fi
# Find all SKILL.md files and extract their paths
find "$SKILLS_DIR" -name "SKILL.md" -type f | \
sed "s|$SKILLS_DIR/||; s|/SKILL.md||" | \
sort
# Use PERSONAL_SUPERPOWERS_DIR if set, otherwise XDG_CONFIG_HOME/superpowers, otherwise ~/.config/superpowers
PERSONAL_SUPERPOWERS_DIR="${PERSONAL_SUPERPOWERS_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/superpowers}"
PERSONAL_SKILLS_DIR="${PERSONAL_SUPERPOWERS_DIR}/skills"
# Collect all skill paths with deduplication
declare -A seen_skills
all_skills=()
# Personal skills first (take precedence)
if [[ -d "$PERSONAL_SKILLS_DIR" ]]; then
while IFS= read -r file; do
skill_path="${file#$PERSONAL_SKILLS_DIR/}"
skill_path="${skill_path%/SKILL.md}"
if [[ -n "$skill_path" ]]; then
seen_skills["$skill_path"]=1
all_skills+=("$skill_path")
fi
done < <(find "$PERSONAL_SKILLS_DIR" -name "SKILL.md" -type f 2>/dev/null || true)
fi
# Core skills (only if not shadowed by personal)
while IFS= read -r file; do
skill_path="${file#$CORE_SKILLS_DIR/}"
skill_path="${skill_path%/SKILL.md}"
if [[ -n "$skill_path" ]] && [[ -z "${seen_skills[$skill_path]:-}" ]]; then
all_skills+=("$skill_path")
fi
done < <(find "$CORE_SKILLS_DIR" -name "SKILL.md" -type f 2>/dev/null || true)
# Sort and output
printf "%s\n" "${all_skills[@]}" | sort
exit 0

View File

@@ -1,20 +1,24 @@
#!/usr/bin/env bash
# skills-search - Find relevant skills using grep patterns
# Logs all searches for gap analysis (gardening skill processes the log)
# Searches personal skills first, then core skills (personal shadows core)
set -euo pipefail
# Detect if running from repo or installed location
# Detect core skills directory (repo or installed location)
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
if [[ "$SCRIPT_DIR" == *"/.claude/skills/getting-started" ]]; then
# Installed location
SKILLS_DIR="${HOME}/.claude/skills"
if [[ "$SCRIPT_DIR" == *"/.claude/plugins/cache/"* ]]; then
# Installed as plugin
CORE_SKILLS_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
else
# Running from repo
SKILLS_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
CORE_SKILLS_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
fi
LOG_FILE="${HOME}/.superpowers/search-log.jsonl"
# Use PERSONAL_SUPERPOWERS_DIR if set, otherwise XDG_CONFIG_HOME/superpowers, otherwise ~/.config/superpowers
PERSONAL_SUPERPOWERS_DIR="${PERSONAL_SUPERPOWERS_DIR:-${XDG_CONFIG_HOME:-$HOME/.config}/superpowers}"
PERSONAL_SKILLS_DIR="${PERSONAL_SUPERPOWERS_DIR}/skills"
LOG_FILE="${PERSONAL_SUPERPOWERS_DIR}/search-log.jsonl"
# Show usage if no arguments
if [[ $# -eq 0 ]]; then
@@ -40,16 +44,51 @@ timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
query="$*"
echo "{\"timestamp\":\"$timestamp\",\"query\":\"$query\"}" >> "$LOG_FILE" 2>/dev/null || true
# Search all SKILL.md files - both content AND path names
# Content search: grep file contents
content_matches=$(grep -E -r "$@" "$SKILLS_DIR/" --include="SKILL.md" -l 2>/dev/null || true)
# Search both personal and core skills directories
# Personal skills take precedence (searched first)
# Content search: grep file contents from both locations
content_matches_personal=""
content_matches_core=""
if [[ -d "$PERSONAL_SKILLS_DIR" ]]; then
content_matches_personal=$(grep -E -r "$@" "$PERSONAL_SKILLS_DIR/" --include="SKILL.md" -l 2>/dev/null || true)
fi
content_matches_core=$(grep -E -r "$@" "$CORE_SKILLS_DIR/" --include="SKILL.md" -l 2>/dev/null || true)
# Filename search: find all SKILL.md paths, then grep the paths themselves
all_skills=$(find "$SKILLS_DIR/" -name "SKILL.md" -type f 2>/dev/null || true)
path_matches=$(echo "$all_skills" | grep -E "$@" 2>/dev/null || true)
all_skills_personal=""
all_skills_core=""
if [[ -d "$PERSONAL_SKILLS_DIR" ]]; then
all_skills_personal=$(find "$PERSONAL_SKILLS_DIR/" -name "SKILL.md" -type f 2>/dev/null || true)
fi
all_skills_core=$(find "$CORE_SKILLS_DIR/" -name "SKILL.md" -type f 2>/dev/null || true)
# Combine and deduplicate
results=$(printf "%s\n%s" "$content_matches" "$path_matches" | sort -u | grep -v '^$' || true)
path_matches_personal=$(echo "$all_skills_personal" | grep -E "$@" 2>/dev/null || true)
path_matches_core=$(echo "$all_skills_core" | grep -E "$@" 2>/dev/null || true)
# Combine all matches
all_matches=$(printf "%s\n%s\n%s\n%s" "$content_matches_personal" "$content_matches_core" "$path_matches_personal" "$path_matches_core" | grep -v '^$' || true)
# Deduplicate by skill path (personal shadows core)
declare -A seen_skills
results=""
while IFS= read -r file; do
# Extract skill path relative to its base directory
if [[ "$file" == "$PERSONAL_SKILLS_DIR"* ]]; then
skill_path="${file#$PERSONAL_SKILLS_DIR/}"
else
skill_path="${file#$CORE_SKILLS_DIR/}"
fi
skill_path="${skill_path%/SKILL.md}"
# Only include if we haven't seen this skill path yet
if [[ -z "${seen_skills[$skill_path]:-}" ]]; then
seen_skills["$skill_path"]=1
results="${results}${file}"$'\n'
fi
done <<< "$all_matches"
results=$(echo "$results" | grep -v '^$' | sort -u || true)
if [[ -z "$results" ]]; then
echo "❌ No skills found matching: $*"
@@ -68,7 +107,12 @@ echo "$results" | while read -r file; do
description=$(grep "^description:" "$file" 2>/dev/null | sed 's/description: *//' || echo "")
# Get relative path without @ prefix or /SKILL.md suffix
rel_path="${file#$SKILLS_DIR/}"
# Handle both personal and core skills
if [[ "$file" == "$PERSONAL_SKILLS_DIR"* ]]; then
rel_path="${file#$PERSONAL_SKILLS_DIR/}"
else
rel_path="${file#$CORE_SKILLS_DIR/}"
fi
rel_path="skills/${rel_path%/SKILL.md}"
if [[ -n "$description" ]]; then