#!/usr/bin/env bash set -euo pipefail # Lobster AI Skill Installer # Usage: curl -fsSL https://skills.lobsterbio.com | bash # # Interactive 3-step install: # A) Which coding agent # B) Global or local # C) Which skills (lobster-use, lobster-dev, or both) # # Downloads skill folders via GitHub tarball — no MANIFEST needed. REPO="the-omics-os/lobster" BRANCH="main" TARBALL_URL="https://github.com/${REPO}/archive/${BRANCH}.tar.gz" TARBALL_PREFIX="${REPO##*/}-${BRANCH}" # lobster-main # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' CYAN='\033[0;36m' DIM='\033[2m' BOLD='\033[1m' RESET='\033[0m' info() { echo -e "${DIM}$1${RESET}"; } ok() { echo -e "${GREEN}✓${RESET} $1"; } warn() { echo -e "${YELLOW}!${RESET} $1"; } err() { echo -e "${RED}✗${RESET} $1"; } prompt() { if [ -e /dev/tty ]; then read -r "$@" /dev/null || true fi } echo "" echo -e "${BOLD}🦞 Lobster AI Skill Installer${RESET}" echo "" # ── Step A: Which coding agent? ───────────────────────────────────── AGENT_IDS=() AGENT_LABELS=() if [ -d "$HOME/.claude" ] || command -v claude &>/dev/null; then AGENT_IDS+=("claude"); AGENT_LABELS+=("Claude Code") fi if command -v codex &>/dev/null; then AGENT_IDS+=("codex"); AGENT_LABELS+=("Codex") fi if [ -d "$HOME/.gemini" ] || command -v gemini &>/dev/null; then AGENT_IDS+=("gemini"); AGENT_LABELS+=("Gemini CLI") fi if [ -d "$HOME/.openclaw" ] || command -v openclaw &>/dev/null; then AGENT_IDS+=("openclaw"); AGENT_LABELS+=("OpenClaw") fi if [ -d "$HOME/.cursor" ] || command -v cursor &>/dev/null; then AGENT_IDS+=("cursor"); AGENT_LABELS+=("Cursor") fi if [ ${#AGENT_IDS[@]} -eq 0 ]; then info "No coding agent detected. Defaulting to Claude Code." AGENT_IDS=("claude"); AGENT_LABELS=("Claude Code") fi AGENT="" if [ ${#AGENT_IDS[@]} -eq 1 ]; then AGENT="${AGENT_IDS[0]}" echo -e "Detected agent: ${BOLD}${AGENT_LABELS[0]}${RESET}" else echo -e "Detected coding agents:" echo "" for i in "${!AGENT_IDS[@]}"; do echo -e " ${CYAN}$((i+1)))${RESET} ${BOLD}${AGENT_LABELS[$i]}${RESET}" done echo "" printf "Install for which agent? [1]: " prompt choice choice="${choice:-1}" idx=$((choice - 1)) if [ "$idx" -ge 0 ] 2>/dev/null && [ "$idx" -lt ${#AGENT_IDS[@]} ]; then AGENT="${AGENT_IDS[$idx]}" else AGENT="${AGENT_IDS[0]}" fi echo -e "Selected: ${BOLD}${AGENT_LABELS[$idx]:-${AGENT_LABELS[0]}}${RESET}" fi echo "" # Agent → directory mapping global_dir() { case "$1" in claude) echo "$HOME/.claude/skills" ;; codex) echo "$HOME/.codex/skills" ;; gemini) echo "$HOME/.gemini/skills" ;; openclaw) echo "$HOME/.openclaw/skills" ;; cursor) echo "$HOME/.cursor/skills" ;; esac } local_dir() { case "$1" in claude) echo "$(pwd)/.claude/skills" ;; codex) echo "$(pwd)/.codex/skills" ;; gemini) echo "$(pwd)/.gemini/skills" ;; openclaw) echo "$(pwd)/.openclaw/skills" ;; cursor) echo "$(pwd)/.cursor/skills" ;; esac } GLOBAL_DIR="$(global_dir "$AGENT")" LOCAL_DIR="$(local_dir "$AGENT")" # ── Step B: Global or local? ──────────────────────────────────────── echo -e "Where should skills be installed?" echo "" echo -e " ${CYAN}1)${RESET} ${BOLD}Local${RESET} — this project only ${DIM}(${LOCAL_DIR}/)${RESET}" echo -e " ${CYAN}2)${RESET} ${BOLD}Global${RESET} — all projects ${DIM}(${GLOBAL_DIR}/)${RESET}" echo "" printf "Choose [1/2] (default: 2 global): " prompt choice case "${choice:-2}" in 1|local|l) INSTALL_MODE="local"; SKILLS_DIR="$LOCAL_DIR" ;; *) INSTALL_MODE="global"; SKILLS_DIR="$GLOBAL_DIR" ;; esac # Check for existing skills EXISTING="" for s in lobster-use lobster-dev; do [ -d "${SKILLS_DIR}/${s}" ] && EXISTING="${EXISTING:+${EXISTING}, }${s}" done if [ -n "$EXISTING" ]; then warn "Already installed: ${EXISTING} (will overwrite)" fi echo "" echo -e "Install mode: ${BOLD}${INSTALL_MODE}${RESET}" echo -e "Install path: ${BOLD}${SKILLS_DIR}/${RESET}" echo "" # ── Step C: Which skills? ─────────────────────────────────────────── echo -e "Which skills to install?" echo "" echo -e " ${CYAN}1)${RESET} ${BOLD}lobster-use${RESET} — CLI, workflows, analysis patterns" echo -e " ${CYAN}2)${RESET} ${BOLD}lobster-dev${RESET} — Architecture, agents, services, testing" echo -e " ${CYAN}3)${RESET} ${BOLD}Both${RESET} — recommended" echo "" printf "Choose [1/2/3] (default: 3 both): " prompt choice SELECTED=() case "${choice:-3}" in 1) SELECTED=("lobster-use") ;; 2) SELECTED=("lobster-dev") ;; *) SELECTED=("lobster-use" "lobster-dev") ;; esac echo "" # ── Download & extract via tarball ────────────────────────────────── info "Downloading skills..." TMPDIR="$(mktemp -d)" trap 'rm -rf "$TMPDIR"' EXIT if ! curl -fsSL "$TARBALL_URL" -o "${TMPDIR}/repo.tar.gz"; then err "Failed to download from GitHub." info "Check your connection or try again later." exit 1 fi mkdir -p "$SKILLS_DIR" ANY_FAILED=0 for skill in "${SELECTED[@]}"; do TAR_PATH="${TARBALL_PREFIX}/skills/${skill}/" if tar xzf "${TMPDIR}/repo.tar.gz" -C "$SKILLS_DIR" --strip-components=2 "$TAR_PATH" 2>/dev/null; then file_count=$(find "${SKILLS_DIR}/${skill}" -type f | wc -l | tr -d ' ') ok "${skill} (${file_count} files)" else err "${skill} — not found in archive" ANY_FAILED=1 fi done echo "" if [ $ANY_FAILED -eq 0 ]; then ok "Done!" echo "" for skill in "${SELECTED[@]}"; do case "$skill" in lobster-use) info " lobster-use — CLI, workflows, analysis patterns" ;; lobster-dev) info " lobster-dev — Architecture, agents, services, testing" ;; esac done echo "" if [ "$INSTALL_MODE" = "local" ]; then info "Skills will load when your agent opens this folder." else info "Open any project and ask:" echo -e " ${BOLD}\"Analyze the RNA-seq data in ./data/\"${RESET}" fi else err "Some skills failed to extract." info "Try again: curl -fsSL https://skills.lobsterbio.com | bash" fi echo "" info "Follows the AgentSkills open standard (https://agentskills.io)" echo ""