Awesome-omni-skill start-local

Start local development environment with auto-detected services in a persistent tmux session

install
source · Clone the upstream repo
git clone https://github.com/diegosouzapw/awesome-omni-skill
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/diegosouzapw/awesome-omni-skill "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/development/start-local" ~/.claude/skills/diegosouzapw-awesome-omni-skill-start-local && rm -rf "$T"
manifest: skills/development/start-local/SKILL.md
source content

/start-local - Start Local Development Environment in tmux

Start local development environment with auto-detected services in a persistent tmux session.

Usage

/start-local                 # Uses .env or .env.development
/start-local staging         # Uses .env.staging
/start-local production      # Uses .env.production

Process

Step 1: Determine Environment

ENVIRONMENT=${1:-development}
ENV_FILE=".env.${ENVIRONMENT}"

# Fallback to .env if specific file doesn't exist
if [ ! -f "$ENV_FILE" ] && [ "$ENVIRONMENT" = "development" ]; then
    ENV_FILE=".env"
fi

if [ ! -f "$ENV_FILE" ]; then
    echo "❌ Environment file not found: $ENV_FILE"
    ls -1 .env* 2>/dev/null
    exit 1
fi

Step 2: Detect Project Type

detect_project_type() {
    if [ -f "package.json" ]; then
        grep -q "\"next\":" package.json && echo "nextjs" && return
        grep -q "\"vite\":" package.json && echo "vite" && return
        grep -q "\"react-scripts\":" package.json && echo "cra" && return
        grep -q "\"@vue/cli\":" package.json && echo "vue" && return
        echo "node"
    elif [ -f "requirements.txt" ] || [ -f "pyproject.toml" ]; then
        grep -q "django" requirements.txt pyproject.toml 2>/dev/null && echo "django" && return
        grep -q "flask" requirements.txt pyproject.toml 2>/dev/null && echo "flask" && return
        echo "python"
    elif [ -f "Cargo.toml" ]; then
        echo "rust"
    elif [ -f "go.mod" ]; then
        echo "go"
    else
        echo "unknown"
    fi
}

PROJECT_TYPE=$(detect_project_type)

Step 3: Detect Required Services

NEEDS_SUPABASE=false
NEEDS_POSTGRES=false
NEEDS_REDIS=false

[ -f "supabase/config.toml" ] && NEEDS_SUPABASE=true
grep -q "postgres" "$ENV_FILE" 2>/dev/null && NEEDS_POSTGRES=true
grep -q "redis" "$ENV_FILE" 2>/dev/null && NEEDS_REDIS=true

Step 4: Generate Random Port

DEV_PORT=$(shuf -i 3000-9999 -n 1)

while lsof -i :$DEV_PORT >/dev/null 2>&1; do
    DEV_PORT=$(shuf -i 3000-9999 -n 1)
done

Step 5: Create tmux Session

PROJECT_NAME=$(basename "$(pwd)")
BRANCH=$(git branch --show-current 2>/dev/null || echo "main")
TIMESTAMP=$(date +%s)
SESSION="dev-${PROJECT_NAME}-${TIMESTAMP}"

tmux new-session -d -s "$SESSION" -n servers

Step 6: Start Services

PANE_COUNT=0

# Main dev server
case $PROJECT_TYPE in
    nextjs|vite|cra|vue)
        tmux send-keys -t "$SESSION:servers.${PANE_COUNT}" "PORT=$DEV_PORT npm run dev 2>&1 | tee dev-server-${DEV_PORT}.log" C-m
        ;;
    django)
        tmux send-keys -t "$SESSION:servers.${PANE_COUNT}" "python manage.py runserver $DEV_PORT 2>&1 | tee dev-server-${DEV_PORT}.log" C-m
        ;;
    flask)
        tmux send-keys -t "$SESSION:servers.${PANE_COUNT}" "FLASK_RUN_PORT=$DEV_PORT flask run 2>&1 | tee dev-server-${DEV_PORT}.log" C-m
        ;;
    *)
        tmux send-keys -t "$SESSION:servers.${PANE_COUNT}" "PORT=$DEV_PORT npm run dev 2>&1 | tee dev-server-${DEV_PORT}.log" C-m
        ;;
esac

# Additional services (if needed)
if [ "$NEEDS_SUPABASE" = true ]; then
    PANE_COUNT=$((PANE_COUNT + 1))
    tmux split-window -v -t "$SESSION:servers"
    tmux send-keys -t "$SESSION:servers.${PANE_COUNT}" "supabase start" C-m
fi

if [ "$NEEDS_POSTGRES" = true ] && [ "$NEEDS_SUPABASE" = false ]; then
    PANE_COUNT=$((PANE_COUNT + 1))
    tmux split-window -v -t "$SESSION:servers"
    tmux send-keys -t "$SESSION:servers.${PANE_COUNT}" "docker-compose up postgres" C-m
fi

if [ "$NEEDS_REDIS" = true ]; then
    PANE_COUNT=$((PANE_COUNT + 1))
    tmux split-window -v -t "$SESSION:servers"
    tmux send-keys -t "$SESSION:servers.${PANE_COUNT}" "redis-server" C-m
fi

tmux select-layout -t "$SESSION:servers" tiled

Step 7: Create Additional Windows

# Logs window
tmux new-window -t "$SESSION" -n logs
tmux send-keys -t "$SESSION:logs" "tail -f dev-server-${DEV_PORT}.log 2>/dev/null || sleep infinity" C-m

# Work window
tmux new-window -t "$SESSION" -n work

# Git window
tmux new-window -t "$SESSION" -n git
tmux send-keys -t "$SESSION:git" "git status" C-m

Step 8: Save Metadata

cat > .tmux-dev-session.json <<EOF
{
  "session": "$SESSION",
  "project_name": "$PROJECT_NAME",
  "branch": "$BRANCH",
  "type": "$PROJECT_TYPE",
  "environment": "$ENVIRONMENT",
  "env_file": "$ENV_FILE",
  "dev_port": $DEV_PORT,
  "created": "$(date -Iseconds)"
}
EOF

Step 9: Display Summary

echo ""
echo "✨ Dev Environment Started: $SESSION"
echo ""
echo "Environment: $ENVIRONMENT ($ENV_FILE)"
echo "Dev Server: http://localhost:$DEV_PORT"
[ "$NEEDS_SUPABASE" = true ] && echo "Supabase: http://localhost:54321"
echo ""
echo "Attach: tmux attach -t $SESSION"
echo "Detach: Ctrl+a d"
echo "Status: /tmux-status"
echo ""

Notes

  • Auto-detects framework/stack from project files
  • Auto-detects services from .env and config files
  • Random ports prevent conflicts
  • Session persists across disconnects
  • Metadata saved to
    .tmux-dev-session.json