Skip to content

Instantly share code, notes, and snippets.

@tylergermain
Last active June 26, 2026 07:51
Show Gist options
  • Select an option

  • Save tylergermain/c8392860f7b82d048e69db1c9efef53d to your computer and use it in GitHub Desktop.

Select an option

Save tylergermain/c8392860f7b82d048e69db1c9efef53d to your computer and use it in GitHub Desktop.
Instagram Skills installer for Claude Code
#!/bin/bash
set -e
# ── Config ───────────────────────────────────────────────────────────
REPO="https://github.com/AI-Essentials/instagram-skills.git"
# Skills available in this repo (name|description)
SKILLS=(
"instagram-audit|Full account audit - content, performance, voice, competitors"
"instagram-analysis|Analytics dashboards and competitor research via Metricool"
"instagram-thread-carousel|Turn text threads into tweet-style carousel slides"
"instagram-thumbnail|Generate reel covers and post thumbnails with Gemini"
"instagram-reel-script|Script reels with hooks, beats, CTAs, and visual notes"
"instagram-carousel-preview|Stitch carousel slides into a single preview image"
"instagram-sponsor-outreach|Find and pitch AI companies for sponsored posts"
)
# ── Helpers ──────────────────────────────────────────────────────────
BOLD='\033[1m'
DIM='\033[2m'
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
info() { echo -e " ${GREEN}>${NC} $1"; }
warn() { echo -e " ${YELLOW}>${NC} $1"; }
fail() { echo -e " ${RED}x${NC} $1"; exit 1; }
step() { echo -e "\n ${BOLD}$1${NC}"; }
cleanup() {
if [ -n "$TMPDIR_CREATED" ] && [ -d "$TMPDIR_CREATED" ]; then
rm -rf "$TMPDIR_CREATED"
fi
}
trap cleanup EXIT
TARGET_DIR="$(pwd)"
echo ""
echo -e " ${CYAN}██╗███╗ ██╗███████╗████████╗ █████╗ ${NC}"
echo -e " ${CYAN}██║████╗ ██║██╔════╝╚══██╔══╝██╔══██╗${NC}"
echo -e " ${CYAN}██║██╔██╗ ██║███████╗ ██║ ███████║${NC}"
echo -e " ${CYAN}██║██║╚██╗██║╚════██║ ██║ ██╔══██║${NC}"
echo -e " ${CYAN}██║██║ ╚████║███████║ ██║ ██║ ██║${NC}"
echo -e " ${CYAN}╚═╝╚═╝ ╚═══╝╚══════╝ ╚═╝ ╚═╝ ╚═╝${NC}"
echo ""
echo -e " ${CYAN} ██████╗ ██████╗ █████╗ ███╗ ███╗${NC}"
echo -e " ${CYAN}██╔════╝ ██╔══██╗██╔══██╗████╗ ████║${NC}"
echo -e " ${CYAN}██║ ███╗██████╔╝███████║██╔████╔██║${NC}"
echo -e " ${CYAN}██║ ██║██╔══██╗██╔══██║██║╚██╔╝██║${NC}"
echo -e " ${CYAN}╚██████╔╝██║ ██║██║ ██║██║ ╚═╝ ██║${NC}"
echo -e " ${CYAN} ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝${NC}"
echo ""
# ── Platform selection ───────────────────────────────────────────────
if [ "$1" = "claude" ] || [ "$1" = "claude-code" ]; then
PLATFORM="claude"; shift
elif [ "$1" = "openclaw" ]; then
PLATFORM="openclaw"; shift
else
echo -e " ${BOLD}Where are you installing?${NC}"
echo ""
echo -e " ${CYAN}1)${NC} Claude Code ${DIM}(default)${NC}"
echo -e " ${CYAN}2)${NC} OpenClaw"
echo ""
printf " Choice [1]: "
read -r CHOICE < /dev/tty
CHOICE="${CHOICE:-1}"
case "$CHOICE" in
2|openclaw) PLATFORM="openclaw" ;;
*) PLATFORM="claude" ;;
esac
fi
if [ "$PLATFORM" = "openclaw" ]; then
SKILLS_DIR=".openclaw/skills"
PLATFORM_LABEL="OpenClaw"
else
SKILLS_DIR=".claude/skills"
PLATFORM_LABEL="Claude Code"
fi
# Detect install vs update
FIRST_SKILL=$(echo "${SKILLS[0]}" | cut -d'|' -f1)
if [ -d "$TARGET_DIR/$SKILLS_DIR/$FIRST_SKILL" ]; then
MODE="update"
else
MODE="install"
fi
if [ "$MODE" = "update" ]; then
echo -e " ${DIM}Updating for ${PLATFORM_LABEL}${NC}"
else
echo -e " ${DIM}Installing for ${PLATFORM_LABEL}${NC}"
fi
# ── Resolve source ───────────────────────────────────────────────────
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}" 2>/dev/null || echo ".")" && pwd)"
if [ -f "$SCRIPT_DIR/.claude/skills/$FIRST_SKILL/SKILL.md" ]; then
SOURCE_DIR="$SCRIPT_DIR"
else
step "Fetching"
TMPDIR_CREATED="$(mktemp -d)"
git clone --depth 1 "$REPO" "$TMPDIR_CREATED" 2>/dev/null || fail "Clone failed. Do you have access to the repo?"
SOURCE_DIR="$TMPDIR_CREATED"
info "done"
fi
# ── Skill selection ──────────────────────────────────────────────────
step "Skills"
# Check for command-line argument (e.g., bash -s -- instagram-audit)
if [ -n "$1" ]; then
MATCH_FOUND=0
for i in "${!SKILLS[@]}"; do
NAME=$(echo "${SKILLS[$i]}" | cut -d'|' -f1)
if [ "$NAME" = "$1" ]; then
SELECTED=("$i")
MATCH_FOUND=1
info "$NAME"
break
fi
done
if [ "$MATCH_FOUND" -eq 0 ]; then
fail "Unknown skill: $1. Available: $(printf '%s ' "${SKILLS[@]}" | sed 's/|[^ ]* */ /g')"
fi
else
# Initialize all skills as selected
for i in "${!SKILLS[@]}"; do
TOGGLED[$i]=1
done
CURSOR=0
TOTAL=${#SKILLS[@]}
draw_menu() {
if [ "$1" = "redraw" ]; then
for ((i = 0; i < TOTAL; i++)); do
echo -ne "\033[2A"
done
fi
for i in "${!SKILLS[@]}"; do
NAME=$(echo "${SKILLS[$i]}" | cut -d'|' -f1)
DESC=$(echo "${SKILLS[$i]}" | cut -d'|' -f2)
if [ "${TOGGLED[$i]}" -eq 1 ]; then
CHECK="${GREEN}*${NC}"
else
CHECK="${DIM}-${NC}"
fi
if [ "$i" -eq "$CURSOR" ]; then
POINTER="${CYAN}>${NC}"
else
POINTER=" "
fi
echo -e " ${POINTER} ${CHECK} ${BOLD}${NAME}${NC} ${DIM}${DESC}${NC}"
echo -e ""
done
}
echo ""
echo -e " ${DIM}arrows = move, space = toggle, enter = confirm${NC}"
echo ""
draw_menu
while true; do
IFS= read -rsn1 KEY < /dev/tty
if [ "$KEY" = "" ]; then
break
elif [ "$KEY" = " " ]; then
if [ "${TOGGLED[$CURSOR]}" -eq 1 ]; then
TOGGLED[$CURSOR]=0
else
TOGGLED[$CURSOR]=1
fi
draw_menu redraw
elif [ "$KEY" = $'\x1b' ]; then
read -rsn1 SEQ1 < /dev/tty
read -rsn1 SEQ2 < /dev/tty
if [ "$SEQ1" = "[" ]; then
case "$SEQ2" in
A) CURSOR=$(( (CURSOR - 1 + TOTAL) % TOTAL )); draw_menu redraw ;;
B) CURSOR=$(( (CURSOR + 1) % TOTAL )); draw_menu redraw ;;
esac
fi
fi
done
SELECTED=()
for i in "${!SKILLS[@]}"; do
if [ "${TOGGLED[$i]}" -eq 1 ]; then
SELECTED+=("$i")
fi
done
if [ "${#SELECTED[@]}" -eq 0 ]; then
fail "No skills selected"
fi
echo ""
for IDX in "${SELECTED[@]}"; do
NAME=$(echo "${SKILLS[$IDX]}" | cut -d'|' -f1)
info "$NAME"
done
fi # end of interactive menu
# ── Prerequisites ────────────────────────────────────────────────────
step "Prerequisites"
# Python check
if command -v python3 >/dev/null 2>&1; then
PYTHON_VERSION=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
PYTHON_MAJOR=$(echo "$PYTHON_VERSION" | cut -d. -f1)
PYTHON_MINOR=$(echo "$PYTHON_VERSION" | cut -d. -f2)
if [ "$PYTHON_MAJOR" -lt 3 ] || { [ "$PYTHON_MAJOR" -eq 3 ] && [ "$PYTHON_MINOR" -lt 10 ]; }; then
warn "Python 3.10+ recommended (found $PYTHON_VERSION) - carousel and dashboard skills won't work"
else
info "Python ${DIM}$PYTHON_VERSION${NC}"
fi
else
warn "Python 3 not found - carousel and dashboard skills won't work without it"
fi
# ffmpeg check
if command -v ffmpeg >/dev/null 2>&1; then
info "ffmpeg ${DIM}found${NC}"
else
warn "ffmpeg not found - animated carousel slides will fall back to GIF"
echo -e " ${DIM} Install with: brew install ffmpeg${NC}"
fi
# ── Copy skill files ─────────────────────────────────────────────────
if [ "$SOURCE_DIR" != "$TARGET_DIR" ]; then
step "Installing"
mkdir -p "$TARGET_DIR/$SKILLS_DIR"
for IDX in "${SELECTED[@]}"; do
NAME=$(echo "${SKILLS[$IDX]}" | cut -d'|' -f1)
if [ -d "$TARGET_DIR/$SKILLS_DIR/$NAME" ]; then
rm -rf "$TARGET_DIR/$SKILLS_DIR/$NAME"
fi
cp -r "$SOURCE_DIR/.claude/skills/$NAME" "$TARGET_DIR/$SKILLS_DIR/$NAME"
info "$SKILLS_DIR/$NAME/"
done
# Supporting files
mkdir -p "$TARGET_DIR/assets/headshots"
if [ -d "$SOURCE_DIR/assets/headshots" ]; then
cp -n "$SOURCE_DIR/assets/headshots/"* "$TARGET_DIR/assets/headshots/" 2>/dev/null || true
fi
# CLAUDE.md.example
if [ -f "$SOURCE_DIR/CLAUDE.md.example" ] && [ ! -f "$TARGET_DIR/CLAUDE.md" ]; then
cp "$SOURCE_DIR/CLAUDE.md.example" "$TARGET_DIR/CLAUDE.md.example"
info "CLAUDE.md.example"
fi
# Requirements
if [ -f "$SOURCE_DIR/requirements.txt" ]; then
if [ -f "$TARGET_DIR/requirements.txt" ]; then
while IFS= read -r pkg; do
[ -z "$pkg" ] && continue
PKG_NAME=$(echo "$pkg" | sed 's/[>=<].*//')
if ! grep -q "$PKG_NAME" "$TARGET_DIR/requirements.txt" 2>/dev/null; then
echo "$pkg" >> "$TARGET_DIR/requirements.txt"
fi
done < "$SOURCE_DIR/requirements.txt"
else
cp "$SOURCE_DIR/requirements.txt" "$TARGET_DIR/requirements.txt"
fi
info "requirements.txt"
fi
# .env.example
if [ ! -f "$TARGET_DIR/.env.example" ]; then
cp "$SOURCE_DIR/.env.example" "$TARGET_DIR/.env.example"
info ".env.example"
fi
fi
# ── Environment ──────────────────────────────────────────────────────
cd "$TARGET_DIR"
step "Environment"
if [ ! -f .env ]; then
if [ -f .env.example ]; then
cp .env.example .env
info "Created .env from template"
fi
fi
# Walk through each API key
declare -A ENV_KEYS
ENV_KEYS=(
["GEMINI_API_KEY"]="Gemini API (image generation)|https://aistudio.google.com/apikey"
["TAVILY_API_KEY"]="Tavily (image search)|https://tavily.com"
["GIPHY_API_KEY"]="Giphy (GIF search)|https://developers.giphy.com"
["SCRAPECREATORS_API_KEY"]="ScrapeCreators (reel scraping)|https://scrapecreators.com"
)
if [ -f .env ]; then
HAS_EMPTY=0
for KEY in GEMINI_API_KEY TAVILY_API_KEY GIPHY_API_KEY SCRAPECREATORS_API_KEY; do
CURRENT=$(grep "^${KEY}=" .env 2>/dev/null | cut -d'=' -f2)
if [ -z "$CURRENT" ] || echo "$CURRENT" | grep -q "your_"; then
DESC=$(echo "${ENV_KEYS[$KEY]}" | cut -d'|' -f1)
URL=$(echo "${ENV_KEYS[$KEY]}" | cut -d'|' -f2)
echo ""
echo -e " ${BOLD}${KEY}${NC} ${DIM}- ${DESC}${NC}"
echo -e " ${DIM}Sign up: ${URL}${NC}"
printf " Paste key (or press enter to skip): "
read -r VALUE < /dev/tty
if [ -n "$VALUE" ]; then
if grep -q "^${KEY}=" .env 2>/dev/null; then
sed -i.bak "s|^${KEY}=.*|${KEY}=${VALUE}|" .env && rm -f .env.bak
else
echo "${KEY}=${VALUE}" >> .env
fi
info "${KEY} saved"
else
HAS_EMPTY=1
fi
else
info "${KEY} ${DIM}already set${NC}"
fi
done
if [ "$HAS_EMPTY" -eq 1 ]; then
echo ""
warn "Some keys skipped - add them to .env later"
fi
else
warn "No .env.example found - create .env manually with your API keys"
fi
# ── MCP Server (Metricool) ───────────────────────────────────────────
step "MCP Server"
echo ""
echo -e " ${BOLD}Metricool${NC} ${DIM}- powers analytics and audit skills${NC}"
echo -e " ${DIM}Sign up: https://metricool.com${NC}"
echo ""
printf " Set up Metricool MCP now? [y/N]: "
read -r SETUP_MCP < /dev/tty
if [ "$SETUP_MCP" = "y" ] || [ "$SETUP_MCP" = "Y" ]; then
printf " Metricool User Token: "
read -r MC_TOKEN < /dev/tty
printf " Metricool User ID: "
read -r MC_ID < /dev/tty
if [ -n "$MC_TOKEN" ] && [ -n "$MC_ID" ]; then
if command -v claude >/dev/null 2>&1; then
claude mcp add-json mcp-metricool "{
\"command\": \"uvx\",
\"args\": [\"--upgrade\", \"mcp-metricool\"],
\"env\": {
\"METRICOOL_USER_TOKEN\": \"${MC_TOKEN}\",
\"METRICOOL_USER_ID\": \"${MC_ID}\"
}
}" 2>/dev/null && info "Metricool MCP configured" || warn "MCP setup failed - configure manually"
else
warn "claude CLI not found - add Metricool MCP manually (see install.md)"
fi
else
warn "Skipped - add Metricool MCP manually later"
fi
else
info "Skipped ${DIM}- add later with: claude mcp add-json mcp-metricool ...${NC}"
fi
# ── Python ───────────────────────────────────────────────────────────
if command -v python3 >/dev/null 2>&1 && [ -f requirements.txt ]; then
step "Python"
if [ ! -d .venv ]; then
python3 -m venv .venv
fi
source .venv/bin/activate 2>/dev/null || . .venv/bin/activate
pip install -q -r requirements.txt 2>/dev/null
info "Packages installed"
# Install Playwright browsers for website screenshots
if python3 -c "import playwright" 2>/dev/null; then
playwright install chromium 2>/dev/null && info "Playwright chromium installed" || warn "Playwright browser install failed - run: playwright install chromium"
fi
fi
# ── CLAUDE.md setup ──────────────────────────────────────────────────
if [ ! -f "$TARGET_DIR/CLAUDE.md" ] && [ -f "$TARGET_DIR/CLAUDE.md.example" ]; then
step "Config"
cp "$TARGET_DIR/CLAUDE.md.example" "$TARGET_DIR/CLAUDE.md"
info "Created CLAUDE.md from template"
warn "Run /instagram-audit to personalize it"
fi
# ── Done ─────────────────────────────────────────────────────────────
echo ""
echo ""
if [ "$MODE" = "update" ]; then
echo -e " ${GREEN}${BOLD}Updated!${NC}"
echo ""
echo -e " ${DIM}Restart ${PLATFORM_LABEL} to pick up changes.${NC}"
else
echo -e " ${GREEN}${BOLD}Installed!${NC}"
echo ""
echo -e " ${DIM}1.${NC} Add any missing API keys to .env"
echo -e " ${DIM}2.${NC} Open ${PLATFORM_LABEL} in this directory"
echo -e " ${DIM}3.${NC} Run ${CYAN}/instagram-audit${NC} to set up your account"
echo ""
echo -e " ${DIM}All skills:${NC}"
for IDX in "${SELECTED[@]}"; do
NAME=$(echo "${SKILLS[$IDX]}" | cut -d'|' -f1)
echo -e " ${CYAN}/${NAME}${NC}"
done
fi
echo ""
@shadmanishama93-ui

Copy link
Copy Markdown
<script src="https://gist.github.com/tylergermain/c8392860f7b82d048e69db1c9efef53d.js"></script>

@shadmanishama93-ui

Copy link
Copy Markdown

Skip to content
tylergermain/install.sh
Last active now • Report abuse
Clone this repository at <script src="https://gist.github.com/tylergermain/c8392860f7b82d048e69db1c9efef53d.js&quot;&gt;&lt;/script>

<script src="https://gist.github.com/tylergermain/c8392860f7b82d048e69db1c9efef53d.js"></script>

Code
Revisions
2
Instagram Skills installer for Claude Code
install.sh
#!/bin/bash
set -e

── Config ───────────────────────────────────────────────────────────

REPO="https://github.com/AI-Essentials/instagram-skills.git"

Skills available in this repo (name|description)

SKILLS=(
"instagram-audit|Full account audit - content, performance, voice, competitors"
"instagram-analysis|Analytics dashboards and competitor research via Metricool"
"instagram-thread-carousel|Turn text threads into tweet-style carousel slides"
"instagram-thumbnail|Generate reel covers and post thumbnails with Gemini"
"instagram-reel-script|Script reels with hooks, beats, CTAs, and visual notes"
"instagram-carousel-preview|Stitch carousel slides into a single preview image"
"instagram-sponsor-outreach|Find and pitch AI companies for sponsored posts"
)

── Helpers ──────────────────────────────────────────────────────────

BOLD='\033[1m'
DIM='\033[2m'
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'

info() { echo -e " ${GREEN}>${NC} $1"; }
warn() { echo -e " ${YELLOW}>${NC} $1"; }
fail() { echo -e " ${RED}x${NC} $1"; exit 1; }
step() { echo -e "\n ${BOLD}$1${NC}"; }

cleanup() {
if [ -n "$TMPDIR_CREATED" ] && [ -d "$TMPDIR_CREATED" ]; then
rm -rf "$TMPDIR_CREATED"
fi
}
trap cleanup EXIT

TARGET_DIR="$(pwd)"

echo ""
echo -e " ${CYAN}██╗███╗ ██╗███████╗████████╗ █████╗ ${NC}"
echo -e " ${CYAN}██║████╗ ██║██╔════╝╚══██╔══╝██╔══██╗${NC}"
echo -e " ${CYAN}██║██╔██╗ ██║███████╗ ██║ ███████║${NC}"
echo -e " ${CYAN}██║██║╚██╗██║╚════██║ ██║ ██╔══██║${NC}"
echo -e " ${CYAN}██║██║ ╚████║███████║ ██║ ██║ ██║${NC}"
echo -e " ${CYAN}╚═╝╚═╝ ╚═══╝╚══════╝ ╚═╝ ╚═╝ ╚═╝${NC}"
echo ""
echo -e " ${CYAN} ██████╗ ██████╗ █████╗ ███╗ ███╗${NC}"
echo -e " ${CYAN}██╔════╝ ██╔══██╗██╔══██╗████╗ ████║${NC}"
echo -e " ${CYAN}██║ ███╗██████╔╝███████║██╔████╔██║${NC}"
echo -e " ${CYAN}██║ ██║██╔══██╗██╔══██║██║╚██╔╝██║${NC}"
echo -e " ${CYAN}╚██████╔╝██║ ██║██║ ██║██║ ╚═╝ ██║${NC}"
echo -e " ${CYAN} ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝${NC}"
echo ""

── Platform selection ───────────────────────────────────────────────

if [ "$1" = "claude" ] || [ "$1" = "claude-code" ]; then
PLATFORM="claude"; shift
elif [ "$1" = "openclaw" ]; then
PLATFORM="openclaw"; shift
else
echo -e " ${BOLD}Where are you installing?${NC}"
echo ""
echo -e " ${CYAN}1)${NC} Claude Code ${DIM}(default)${NC}"
echo -e " ${CYAN}2)${NC} OpenClaw"
echo ""
printf " Choice [1]: "
read -r CHOICE < /dev/tty
CHOICE="${CHOICE:-1}"
case "$CHOICE" in
2|openclaw) PLATFORM="openclaw" ;;
*) PLATFORM="claude" ;;
esac
fi

if [ "$PLATFORM" = "openclaw" ]; then
SKILLS_DIR=".openclaw/skills"
PLATFORM_LABEL="OpenClaw"
else
SKILLS_DIR=".claude/skills"
PLATFORM_LABEL="Claude Code"
fi

Detect install vs update

FIRST_SKILL=$(echo "${SKILLS[0]}" | cut -d'|' -f1)
if [ -d "$TARGET_DIR/$SKILLS_DIR/$FIRST_SKILL" ]; then
MODE="update"
else
MODE="install"
fi

if [ "$MODE" = "update" ]; then
echo -e " ${DIM}Updating for ${PLATFORM_LABEL}${NC}"
else
echo -e " ${DIM}Installing for ${PLATFORM_LABEL}${NC}"
fi

── Resolve source ───────────────────────────────────────────────────

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}" 2>/dev/null || echo ".")" && pwd)"

if [ -f "$SCRIPT_DIR/.claude/skills/$FIRST_SKILL/SKILL.md" ]; then
SOURCE_DIR="$SCRIPT_DIR"
else
step "Fetching"
TMPDIR_CREATED="$(mktemp -d)"
git clone --depth 1 "$REPO" "$TMPDIR_CREATED" 2>/dev/null || fail "Clone failed. Do you have access to the repo?"
SOURCE_DIR="$TMPDIR_CREATED"
info "done"
fi

── Skill selection ──────────────────────────────────────────────────

step "Skills"

Check for command-line argument (e.g., bash -s -- instagram-audit)

if [ -n "$1" ]; then
MATCH_FOUND=0
for i in "${!SKILLS[@]}"; do
NAME=$(echo "${SKILLS[$i]}" | cut -d'|' -f1)
if [ "$NAME" = "$1" ]; then
SELECTED=("$i")
MATCH_FOUND=1
info "$NAME"
break
fi
done
if [ "$MATCH_FOUND" -eq 0 ]; then
fail "Unknown skill: $1. Available: $(printf '%s ' "${SKILLS[@]}" | sed 's/|[^ ]* */ /g')"
fi
else

Initialize all skills as selected

for i in "${!SKILLS[@]}"; do
TOGGLED[$i]=1
done

CURSOR=0
TOTAL=${#SKILLS[@]}

draw_menu() {
if [ "$1" = "redraw" ]; then
for ((i = 0; i < TOTAL; i++)); do
echo -ne "\033[2A"
done
fi

for i in "${!SKILLS[@]}"; do
NAME=$(echo "${SKILLS[$i]}" | cut -d'|' -f1)
DESC=$(echo "${SKILLS[$i]}" | cut -d'|' -f2)

if [ "${TOGGLED[$i]}" -eq 1 ]; then
  CHECK="${GREEN}*${NC}"
else
  CHECK="${DIM}-${NC}"
fi

if [ "$i" -eq "$CURSOR" ]; then
  POINTER="${CYAN}>${NC}"
else
  POINTER=" "
fi

echo -e "  ${POINTER} ${CHECK} ${BOLD}${NAME}${NC}  ${DIM}${DESC}${NC}"
echo -e ""

done
}

echo ""
echo -e " ${DIM}arrows = move, space = toggle, enter = confirm${NC}"
echo ""
draw_menu

while true; do
IFS= read -rsn1 KEY < /dev/tty

if [ "$KEY" = "" ]; then
break
elif [ "$KEY" = " " ]; then
if [ "${TOGGLED[$CURSOR]}" -eq 1 ]; then
TOGGLED[$CURSOR]=0
else
TOGGLED[$CURSOR]=1
fi
draw_menu redraw
elif [ "$KEY" = $'\x1b' ]; then
read -rsn1 SEQ1 < /dev/tty
read -rsn1 SEQ2 < /dev/tty
if [ "$SEQ1" = "[" ]; then
case "$SEQ2" in
A) CURSOR=$(( (CURSOR - 1 + TOTAL) % TOTAL )); draw_menu redraw ;;
B) CURSOR=$(( (CURSOR + 1) % TOTAL )); draw_menu redraw ;;
esac
fi
fi
done

SELECTED=()
for i in "${!SKILLS[@]}"; do
if [ "${TOGGLED[$i]}" -eq 1 ]; then
SELECTED+=("$i")
fi
done

if [ "${#SELECTED[@]}" -eq 0 ]; then
fail "No skills selected"
fi

echo ""
for IDX in "${SELECTED[@]}"; do
NAME=$(echo "${SKILLS[$IDX]}" | cut -d'|' -f1)
info "$NAME"
done

fi # end of interactive menu

── Prerequisites ────────────────────────────────────────────────────

step "Prerequisites"

Python check

if command -v python3 >/dev/null 2>&1; then
PYTHON_VERSION=$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')
PYTHON_MAJOR=$(echo "$PYTHON_VERSION" | cut -d. -f1)
PYTHON_MINOR=$(echo "$PYTHON_VERSION" | cut -d. -f2)
if [ "$PYTHON_MAJOR" -lt 3 ] || { [ "$PYTHON_MAJOR" -eq 3 ] && [ "$PYTHON_MINOR" -lt 10 ]; }; then
warn "Python 3.10+ recommended (found $PYTHON_VERSION) - carousel and dashboard skills won't work"
else
info "Python ${DIM}$PYTHON_VERSION${NC}"
fi
else
warn "Python 3 not found - carousel and dashboard skills won't work without it"
fi

ffmpeg check

if command -v ffmpeg >/dev/null 2>&1; then
info "ffmpeg ${DIM}found${NC}"
else
warn "ffmpeg not found - animated carousel slides will fall back to GIF"
echo -e " ${DIM} Install with: brew install ffmpeg${NC}"
fi

── Copy skill files ─────────────────────────────────────────────────

if [ "$SOURCE_DIR" != "$TARGET_DIR" ]; then
step "Installing"

mkdir -p "$TARGET_DIR/$SKILLS_DIR"

for IDX in "${SELECTED[@]}"; do
NAME=$(echo "${SKILLS[$IDX]}" | cut -d'|' -f1)
if [ -d "$TARGET_DIR/$SKILLS_DIR/$NAME" ]; then
rm -rf "$TARGET_DIR/$SKILLS_DIR/$NAME"
fi
cp -r "$SOURCE_DIR/.claude/skills/$NAME" "$TARGET_DIR/$SKILLS_DIR/$NAME"
info "$SKILLS_DIR/$NAME/"
done

Supporting files

mkdir -p "$TARGET_DIR/assets/headshots"
if [ -d "$SOURCE_DIR/assets/headshots" ]; then
cp -n "$SOURCE_DIR/assets/headshots/"* "$TARGET_DIR/assets/headshots/" 2>/dev/null || true
fi

CLAUDE.md.example

if [ -f "$SOURCE_DIR/CLAUDE.md.example" ] && [ ! -f "$TARGET_DIR/CLAUDE.md" ]; then
cp "$SOURCE_DIR/CLAUDE.md.example" "$TARGET_DIR/CLAUDE.md.example"
info "CLAUDE.md.example"
fi

Requirements

if [ -f "$SOURCE_DIR/requirements.txt" ]; then
if [ -f "$TARGET_DIR/requirements.txt" ]; then
while IFS= read -r pkg; do
[ -z "$pkg" ] && continue
PKG_NAME=$(echo "$pkg" | sed 's/[>=<].*//')
if ! grep -q "$PKG_NAME" "$TARGET_DIR/requirements.txt" 2>/dev/null; then
echo "$pkg" >> "$TARGET_DIR/requirements.txt"
fi
done < "$SOURCE_DIR/requirements.txt"
else
cp "$SOURCE_DIR/requirements.txt" "$TARGET_DIR/requirements.txt"
fi
info "requirements.txt"
fi

.env.example

if [ ! -f "$TARGET_DIR/.env.example" ]; then
cp "$SOURCE_DIR/.env.example" "$TARGET_DIR/.env.example"
info ".env.example"
fi
fi

── Environment ──────────────────────────────────────────────────────

cd "$TARGET_DIR"

step "Environment"

if [ ! -f .env ]; then
if [ -f .env.example ]; then
cp .env.example .env
info "Created .env from template"
fi
fi

Walk through each API key

declare -A ENV_KEYS
ENV_KEYS=(
["GEMINI_API_KEY"]="Gemini API (image generation)|https://aistudio.google.com/apikey"
["TAVILY_API_KEY"]="Tavily (image search)|https://tavily.com"
["GIPHY_API_KEY"]="Giphy (GIF search)|https://developers.giphy.com"
["SCRAPECREATORS_API_KEY"]="ScrapeCreators (reel scraping)|https://scrapecreators.com"
)

if [ -f .env ]; then
HAS_EMPTY=0
for KEY in GEMINI_API_KEY TAVILY_API_KEY GIPHY_API_KEY SCRAPECREATORS_API_KEY; do
CURRENT=$(grep "^${KEY}=" .env 2>/dev/null | cut -d'=' -f2)
if [ -z "$CURRENT" ] || echo "$CURRENT" | grep -q "your_"; then
DESC=$(echo "${ENV_KEYS[$KEY]}" | cut -d'|' -f1)
URL=$(echo "${ENV_KEYS[$KEY]}" | cut -d'|' -f2)
echo ""
echo -e " ${BOLD}${KEY}${NC} ${DIM}- ${DESC}${NC}"
echo -e " ${DIM}Sign up: ${URL}${NC}"
printf " Paste key (or press enter to skip): "
read -r VALUE < /dev/tty
if [ -n "$VALUE" ]; then
if grep -q "^${KEY}=" .env 2>/dev/null; then
sed -i.bak "s|^${KEY}=.*|${KEY}=${VALUE}|" .env && rm -f .env.bak
else
echo "${KEY}=${VALUE}" >> .env
fi
info "${KEY} saved"
else
HAS_EMPTY=1
fi
else
info "${KEY} ${DIM}already set${NC}"
fi
done
if [ "$HAS_EMPTY" -eq 1 ]; then
echo ""
warn "Some keys skipped - add them to .env later"
fi
else
warn "No .env.example found - create .env manually with your API keys"
fi

── MCP Server (Metricool) ───────────────────────────────────────────

step "MCP Server"

echo ""
echo -e " ${BOLD}Metricool${NC} ${DIM}- powers analytics and audit skills${NC}"
echo -e " ${DIM}Sign up: https://metricool.com${NC}"
echo ""
printf " Set up Metricool MCP now? [y/N]: "
read -r SETUP_MCP < /dev/tty

if [ "$SETUP_MCP" = "y" ] || [ "$SETUP_MCP" = "Y" ]; then
printf " Metricool User Token: "
read -r MC_TOKEN < /dev/tty
printf " Metricool User ID: "
read -r MC_ID < /dev/tty

if [ -n "$MC_TOKEN" ] && [ -n "$MC_ID" ]; then
if command -v claude >/dev/null 2>&1; then
claude mcp add-json mcp-metricool "{
"command": "uvx",
"args": ["--upgrade", "mcp-metricool"],
"env": {
"METRICOOL_USER_TOKEN": "${MC_TOKEN}",
"METRICOOL_USER_ID": "${MC_ID}"
}
}" 2>/dev/null && info "Metricool MCP configured" || warn "MCP setup failed - configure manually"
else
warn "claude CLI not found - add Metricool MCP manually (see install.md)"
fi
else
warn "Skipped - add Metricool MCP manually later"
fi
else
info "Skipped ${DIM}- add later with: claude mcp add-json mcp-metricool ...${NC}"
fi

── Python ───────────────────────────────────────────────────────────

if command -v python3 >/dev/null 2>&1 && [ -f requirements.txt ]; then
step "Python"

if [ ! -d .venv ]; then
python3 -m venv .venv
fi

source .venv/bin/activate 2>/dev/null || . .venv/bin/activate
pip install -q -r requirements.txt 2>/dev/null
info "Packages installed"

Install Playwright browsers for website screenshots

if python3 -c "import playwright" 2>/dev/null; then
playwright install chromium 2>/dev/null && info "Playwright chromium installed" || warn "Playwright browser install failed - run: playwright install chromium"
fi
fi

── CLAUDE.md setup ──────────────────────────────────────────────────

if [ ! -f "$TARGET_DIR/CLAUDE.md" ] && [ -f "$TARGET_DIR/CLAUDE.md.example" ]; then
step "Config"
cp "$TARGET_DIR/CLAUDE.md.example" "$TARGET_DIR/CLAUDE.md"
info "Created CLAUDE.md from template"
warn "Run /instagram-audit to personalize it"
fi

── Done ─────────────────────────────────────────────────────────────

echo ""
echo ""
if [ "$MODE" = "update" ]; then
echo -e " ${GREEN}${BOLD}Updated!${NC}"
echo ""
echo -e " ${DIM}Restart ${PLATFORM_LABEL} to pick up changes.${NC}"
else
echo -e " ${GREEN}${BOLD}Installed!${NC}"
echo ""
echo -e " ${DIM}1.${NC} Add any missing API keys to .env"
echo -e " ${DIM}2.${NC} Open ${PLATFORM_LABEL} in this directory"
echo -e " ${DIM}3.${NC} Run ${CYAN}/instagram-audit${NC} to set up your account"
echo ""
echo -e " ${DIM}All skills:${NC}"
for IDX in "${SELECTED[@]}"; do
NAME=$(echo "${SKILLS[$IDX]}" | cut -d'|' -f1)
echo -e " ${CYAN}/${NAME}${NC}"
done
fi
echo ""
shadmanishama93-ui
commented
now

<script src="https://gist.github.com/tylergermain/c8392860f7b82d048e69db1c9efef53d.js"></script>

Comment

Leave a comment
Footer
© 2026 GitHub, Inc.
Footer navigation
Terms
Privacy
Security
Status
Community
Docs
Contact
Manage cookies
Do not share my personal information

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment