Interactive CLI for Server Maintenance

For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.

Goal: Create a pure Bash interactive CLI in bin/cli.sh that guides users through project installation and all management commands with their flags and options.

Architecture: Single Bash script using select menus with hierarchical structure. Main menu leads to category submenus, each showing available commands with configurable options.

Tech Stack: Pure Bash (no dependencies), ANSI colors, select menus


Example Output

╔══════════════════════════════════════════════════════════════╗
║              🔧 Server Maintenance CLI                       ║
╚══════════════════════════════════════════════════════════════╝

Select an option:
1) Install / Setup Project
2) Health & Monitoring
3) Alerts & Incidents
4) Intelligence & Recommendations
5) Pipeline Orchestration
6) Notifications
7) Exit

> 4

═══ Intelligence & Recommendations ═══

Select a command:
1) get_recommendations - Get AI recommendations
2) Back to main menu

> 1

═══ get_recommendations ═══

Available options:
  --memory     Analyze memory usage
  --disk       Analyze disk usage
  --all        Analyze everything
  --path=PATH  Path for disk analysis (default: /)
  --json       Output as JSON
  --provider=  Provider to use (default: local)

Select analysis type:
1) Memory analysis (--memory)
2) Disk analysis (--disk)
3) Full analysis (--all)
4) Custom options
5) Back

> 2

Enter path to analyze [/var/log]: /tmp

Command to run:
  uv run python manage.py get_recommendations --disk --path=/tmp

Run this command? (y/n): y

⠋ Running command...
[command output here]

Task 1: Create base script with banner and main menu

Files:

  • Create: bin/cli.sh

Step 1: Write the base script

#!/usr/bin/env bash
#
# Interactive CLI for Server Maintenance
# Usage: ./bin/cli.sh
#

set -e

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
BOLD='\033[1m'

# Get script directory
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"

# Change to project root
cd "$PROJECT_ROOT"

show_banner() {
    clear
    echo -e "${CYAN}"
    echo "╔══════════════════════════════════════════════════════════════╗"
    echo "║              🔧 Server Maintenance CLI                       ║"
    echo "╚══════════════════════════════════════════════════════════════╝"
    echo -e "${NC}"
}

show_main_menu() {
    echo -e "${BOLD}Select an option:${NC}"
    echo ""

    local options=(
        "Install / Setup Project"
        "Health & Monitoring"
        "Alerts & Incidents"
        "Intelligence & Recommendations"
        "Pipeline Orchestration"
        "Notifications"
        "Exit"
    )

    select opt in "${options[@]}"; do
        case $REPLY in
            1) install_project ;;
            2) health_menu ;;
            3) alerts_menu ;;
            4) intelligence_menu ;;
            5) pipeline_menu ;;
            6) notify_menu ;;
            7) echo -e "${GREEN}Goodbye!${NC}"; exit 0 ;;
            *) echo -e "${RED}Invalid option${NC}" ;;
        esac
        break
    done
}

# Placeholder functions (will be implemented in subsequent tasks)
install_project() { echo "Not implemented yet"; }
health_menu() { echo "Not implemented yet"; }
alerts_menu() { echo "Not implemented yet"; }
intelligence_menu() { echo "Not implemented yet"; }
pipeline_menu() { echo "Not implemented yet"; }
notify_menu() { echo "Not implemented yet"; }

# Main loop
main() {
    while true; do
        show_banner
        show_main_menu
        echo ""
        read -p "Press Enter to continue..."
    done
}

main "$@"

Step 2: Make executable and test

chmod +x bin/cli.sh
./bin/cli.sh

Step 3: Commit

git add bin/cli.sh
git commit -m "feat(cli): add interactive CLI base with main menu"

Task 2: Add install/setup function

Files:

  • Modify: bin/cli.sh

Step 1: Implement install_project function

install_project() {
    show_banner
    echo -e "${BOLD}═══ Install / Setup Project ═══${NC}"
    echo ""

    local options=(
        "Full installation (uv sync + pre-commit)"
        "Install dependencies only (uv sync)"
        "Install pre-commit hooks"
        "Check installation status"
        "Back to main menu"
    )

    select opt in "${options[@]}"; do
        case $REPLY in
            1)
                echo -e "${YELLOW}Running full installation...${NC}"
                run_command "uv sync" "Installing dependencies"
                run_command "uv run pre-commit install" "Installing pre-commit hooks"
                ;;
            2)
                run_command "uv sync" "Installing dependencies"
                ;;
            3)
                run_command "uv run pre-commit install" "Installing pre-commit hooks"
                ;;
            4)
                check_installation
                ;;
            5)
                return
                ;;
            *)
                echo -e "${RED}Invalid option${NC}"
                ;;
        esac
        break
    done
}

check_installation() {
    echo -e "${BOLD}Checking installation status...${NC}"
    echo ""

    # Check uv
    if command -v uv &> /dev/null; then
        echo -e "${GREEN}${NC} uv is installed ($(uv --version))"
    else
        echo -e "${RED}${NC} uv is not installed"
    fi

    # Check .venv
    if [ -d ".venv" ]; then
        echo -e "${GREEN}${NC} Virtual environment exists"
    else
        echo -e "${RED}${NC} Virtual environment not found"
    fi

    # Check pre-commit
    if [ -f ".git/hooks/pre-commit" ]; then
        echo -e "${GREEN}${NC} Pre-commit hooks installed"
    else
        echo -e "${YELLOW}!${NC} Pre-commit hooks not installed"
    fi

    # Check Django
    if uv run python manage.py check &> /dev/null; then
        echo -e "${GREEN}${NC} Django is configured correctly"
    else
        echo -e "${RED}${NC} Django check failed"
    fi
}

run_command() {
    local cmd="$1"
    local description="${2:-Running command}"

    echo ""
    echo -e "${CYAN}Command: ${cmd}${NC}"
    echo ""

    if eval "$cmd"; then
        echo ""
        echo -e "${GREEN}${description} completed successfully${NC}"
    else
        echo ""
        echo -e "${RED}${description} failed${NC}"
    fi
}

Step 2: Test

./bin/cli.sh
# Select option 1, then option 4 to check status

Step 3: Commit

git add bin/cli.sh
git commit -m "feat(cli): add install/setup menu with status check"

Task 3: Add health monitoring menu

Files:

  • Modify: bin/cli.sh

Step 1: Implement health_menu function

health_menu() {
    show_banner
    echo -e "${BOLD}═══ Health & Monitoring ═══${NC}"
    echo ""
    echo -e "${CYAN}Command: check_health${NC}"
    echo "Check system health metrics (CPU, memory, disk)"
    echo ""
    echo -e "${BOLD}Available options:${NC}"
    echo "  --environment=ENV  Environment name (default: development)"
    echo "  --json             Output as JSON"
    echo ""

    local options=(
        "Run health check (default)"
        "Run with JSON output"
        "Specify environment"
        "Back to main menu"
    )

    select opt in "${options[@]}"; do
        case $REPLY in
            1)
                confirm_and_run "uv run python manage.py check_health"
                ;;
            2)
                confirm_and_run "uv run python manage.py check_health --json"
                ;;
            3)
                read -p "Enter environment name [development]: " env_name
                env_name="${env_name:-development}"
                confirm_and_run "uv run python manage.py check_health --environment=$env_name"
                ;;
            4)
                return
                ;;
            *)
                echo -e "${RED}Invalid option${NC}"
                ;;
        esac
        break
    done
}

confirm_and_run() {
    local cmd="$1"
    echo ""
    echo -e "${BOLD}Command to run:${NC}"
    echo -e "  ${CYAN}${cmd}${NC}"
    echo ""
    read -p "Run this command? (y/n): " confirm

    if [[ "$confirm" =~ ^[Yy]$ ]]; then
        echo ""
        eval "$cmd"
    else
        echo -e "${YELLOW}Command cancelled${NC}"
    fi
}

Step 2: Test

./bin/cli.sh
# Select option 2 (Health & Monitoring)

Step 3: Commit

git add bin/cli.sh
git commit -m "feat(cli): add health monitoring menu"

Task 4: Add alerts menu

Files:

  • Modify: bin/cli.sh

Step 1: Implement alerts_menu function

alerts_menu() {
    show_banner
    echo -e "${BOLD}═══ Alerts & Incidents ═══${NC}"
    echo ""

    local options=(
        "run_check - Run a specific checker"
        "check_and_alert - Run checker and create alert"
        "Back to main menu"
    )

    select opt in "${options[@]}"; do
        case $REPLY in
            1) run_check_menu ;;
            2) check_and_alert_menu ;;
            3) return ;;
            *) echo -e "${RED}Invalid option${NC}" ;;
        esac
        break
    done
}

run_check_menu() {
    show_banner
    echo -e "${BOLD}═══ run_check ═══${NC}"
    echo ""
    echo "Run a health checker and display results"
    echo ""
    echo -e "${BOLD}Available options:${NC}"
    echo "  CHECKER_NAME       Name of checker to run (required)"
    echo "  --list             List available checkers"
    echo "  --json             Output as JSON"
    echo ""

    local options=(
        "List available checkers"
        "Run a checker"
        "Run with JSON output"
        "Back"
    )

    select opt in "${options[@]}"; do
        case $REPLY in
            1)
                confirm_and_run "uv run python manage.py run_check --list"
                ;;
            2)
                read -p "Enter checker name: " checker_name
                if [ -n "$checker_name" ]; then
                    confirm_and_run "uv run python manage.py run_check $checker_name"
                else
                    echo -e "${RED}Checker name required${NC}"
                fi
                ;;
            3)
                read -p "Enter checker name: " checker_name
                if [ -n "$checker_name" ]; then
                    confirm_and_run "uv run python manage.py run_check $checker_name --json"
                else
                    echo -e "${RED}Checker name required${NC}"
                fi
                ;;
            4)
                return
                ;;
            *)
                echo -e "${RED}Invalid option${NC}"
                ;;
        esac
        break
    done
}

check_and_alert_menu() {
    show_banner
    echo -e "${BOLD}═══ check_and_alert ═══${NC}"
    echo ""
    echo "Run checker and create incident if threshold exceeded"
    echo ""
    echo -e "${BOLD}Available options:${NC}"
    echo "  CHECKER_NAME           Name of checker (required)"
    echo "  --threshold=VALUE      Alert threshold (required)"
    echo "  --severity=LEVEL       Severity: info|warning|error|critical"
    echo "  --title=TITLE          Custom incident title"
    echo ""

    read -p "Enter checker name: " checker_name
    if [ -z "$checker_name" ]; then
        echo -e "${RED}Checker name required${NC}"
        return
    fi

    read -p "Enter threshold value: " threshold
    if [ -z "$threshold" ]; then
        echo -e "${RED}Threshold required${NC}"
        return
    fi

    read -p "Enter severity [warning]: " severity
    severity="${severity:-warning}"

    read -p "Enter custom title (optional): " title

    local cmd="uv run python manage.py check_and_alert $checker_name --threshold=$threshold --severity=$severity"
    if [ -n "$title" ]; then
        cmd="$cmd --title=\"$title\""
    fi

    confirm_and_run "$cmd"
}

Step 2: Test

./bin/cli.sh
# Select option 3 (Alerts & Incidents)

Step 3: Commit

git add bin/cli.sh
git commit -m "feat(cli): add alerts menu with run_check and check_and_alert"

Task 5: Add intelligence menu

Files:

  • Modify: bin/cli.sh

Step 1: Implement intelligence_menu function

intelligence_menu() {
    show_banner
    echo -e "${BOLD}═══ Intelligence & Recommendations ═══${NC}"
    echo ""
    echo -e "${CYAN}Command: get_recommendations${NC}"
    echo "Get AI-powered recommendations for system optimization"
    echo ""
    echo -e "${BOLD}Available options:${NC}"
    echo "  --memory           Analyze memory usage"
    echo "  --disk             Analyze disk usage"
    echo "  --all              Analyze everything"
    echo "  --path=PATH        Path for disk analysis (default: /)"
    echo "  --top-n=N          Number of top processes (default: 10)"
    echo "  --threshold-mb=MB  Large file threshold (default: 100)"
    echo "  --old-days=DAYS    Old file age in days (default: 30)"
    echo "  --json             Output as JSON"
    echo "  --provider=NAME    Provider to use (default: local)"
    echo "  --list-providers   List available providers"
    echo ""

    local options=(
        "Memory analysis"
        "Disk analysis"
        "Full analysis (memory + disk)"
        "Custom options"
        "List providers"
        "Back to main menu"
    )

    select opt in "${options[@]}"; do
        case $REPLY in
            1)
                confirm_and_run "uv run python manage.py get_recommendations --memory"
                ;;
            2)
                read -p "Enter path to analyze [/var/log]: " disk_path
                disk_path="${disk_path:-/var/log}"
                confirm_and_run "uv run python manage.py get_recommendations --disk --path=$disk_path"
                ;;
            3)
                confirm_and_run "uv run python manage.py get_recommendations --all"
                ;;
            4)
                custom_recommendations
                ;;
            5)
                confirm_and_run "uv run python manage.py get_recommendations --list-providers"
                ;;
            6)
                return
                ;;
            *)
                echo -e "${RED}Invalid option${NC}"
                ;;
        esac
        break
    done
}

custom_recommendations() {
    echo ""
    echo -e "${BOLD}Configure custom analysis:${NC}"

    local cmd="uv run python manage.py get_recommendations"

    read -p "Include memory analysis? (y/n) [y]: " inc_memory
    if [[ "${inc_memory:-y}" =~ ^[Yy]$ ]]; then
        cmd="$cmd --memory"
    fi

    read -p "Include disk analysis? (y/n) [y]: " inc_disk
    if [[ "${inc_disk:-y}" =~ ^[Yy]$ ]]; then
        cmd="$cmd --disk"
        read -p "  Path to analyze [/]: " disk_path
        if [ -n "$disk_path" ]; then
            cmd="$cmd --path=$disk_path"
        fi
    fi

    read -p "Top N processes [10]: " top_n
    if [ -n "$top_n" ]; then
        cmd="$cmd --top-n=$top_n"
    fi

    read -p "Large file threshold MB [100]: " threshold_mb
    if [ -n "$threshold_mb" ]; then
        cmd="$cmd --threshold-mb=$threshold_mb"
    fi

    read -p "Output as JSON? (y/n) [n]: " use_json
    if [[ "$use_json" =~ ^[Yy]$ ]]; then
        cmd="$cmd --json"
    fi

    confirm_and_run "$cmd"
}

Step 2: Test

./bin/cli.sh
# Select option 4 (Intelligence & Recommendations)

Step 3: Commit

git add bin/cli.sh
git commit -m "feat(cli): add intelligence menu with get_recommendations"

Task 6: Add pipeline menu

Files:

  • Modify: bin/cli.sh

Step 1: Implement pipeline_menu function

pipeline_menu() {
    show_banner
    echo -e "${BOLD}═══ Pipeline Orchestration ═══${NC}"
    echo ""

    local options=(
        "run_pipeline - Execute a pipeline"
        "monitor_pipeline - Monitor pipeline execution"
        "Back to main menu"
    )

    select opt in "${options[@]}"; do
        case $REPLY in
            1) run_pipeline_menu ;;
            2) monitor_pipeline_menu ;;
            3) return ;;
            *) echo -e "${RED}Invalid option${NC}" ;;
        esac
        break
    done
}

run_pipeline_menu() {
    show_banner
    echo -e "${BOLD}═══ run_pipeline ═══${NC}"
    echo ""
    echo "Execute a pipeline definition"
    echo ""
    echo -e "${BOLD}Available options:${NC}"
    echo "  PIPELINE_NAME      Name of pipeline (or path to definition)"
    echo "  --list             List available pipelines"
    echo "  --dry-run          Show what would be executed"
    echo "  --json             Output as JSON"
    echo ""

    local options=(
        "List available pipelines"
        "Run a pipeline"
        "Dry run (preview)"
        "Back"
    )

    select opt in "${options[@]}"; do
        case $REPLY in
            1)
                confirm_and_run "uv run python manage.py run_pipeline --list"
                ;;
            2)
                read -p "Enter pipeline name: " pipeline_name
                if [ -n "$pipeline_name" ]; then
                    confirm_and_run "uv run python manage.py run_pipeline $pipeline_name"
                else
                    echo -e "${RED}Pipeline name required${NC}"
                fi
                ;;
            3)
                read -p "Enter pipeline name: " pipeline_name
                if [ -n "$pipeline_name" ]; then
                    confirm_and_run "uv run python manage.py run_pipeline $pipeline_name --dry-run"
                else
                    echo -e "${RED}Pipeline name required${NC}"
                fi
                ;;
            4)
                return
                ;;
            *)
                echo -e "${RED}Invalid option${NC}"
                ;;
        esac
        break
    done
}

monitor_pipeline_menu() {
    show_banner
    echo -e "${BOLD}═══ monitor_pipeline ═══${NC}"
    echo ""
    echo "Monitor pipeline execution status"
    echo ""
    echo -e "${BOLD}Available options:${NC}"
    echo "  PIPELINE_ID        ID of pipeline execution to monitor"
    echo "  --list             List recent pipeline executions"
    echo "  --follow           Follow execution in real-time"
    echo ""

    local options=(
        "List recent executions"
        "Monitor a pipeline"
        "Follow pipeline (real-time)"
        "Back"
    )

    select opt in "${options[@]}"; do
        case $REPLY in
            1)
                confirm_and_run "uv run python manage.py monitor_pipeline --list"
                ;;
            2)
                read -p "Enter pipeline execution ID: " pipeline_id
                if [ -n "$pipeline_id" ]; then
                    confirm_and_run "uv run python manage.py monitor_pipeline $pipeline_id"
                else
                    echo -e "${RED}Pipeline ID required${NC}"
                fi
                ;;
            3)
                read -p "Enter pipeline execution ID: " pipeline_id
                if [ -n "$pipeline_id" ]; then
                    confirm_and_run "uv run python manage.py monitor_pipeline $pipeline_id --follow"
                else
                    echo -e "${RED}Pipeline ID required${NC}"
                fi
                ;;
            4)
                return
                ;;
            *)
                echo -e "${RED}Invalid option${NC}"
                ;;
        esac
        break
    done
}

Step 2: Test

./bin/cli.sh
# Select option 5 (Pipeline Orchestration)

Step 3: Commit

git add bin/cli.sh
git commit -m "feat(cli): add pipeline menu with run_pipeline and monitor_pipeline"

Task 7: Add notifications menu

Files:

  • Modify: bin/cli.sh

Step 1: Implement notify_menu function

notify_menu() {
    show_banner
    echo -e "${BOLD}═══ Notifications ═══${NC}"
    echo ""

    local options=(
        "list_notify_drivers - List available notification drivers"
        "test_notify - Send a test notification"
        "Back to main menu"
    )

    select opt in "${options[@]}"; do
        case $REPLY in
            1)
                confirm_and_run "uv run python manage.py list_notify_drivers"
                ;;
            2)
                test_notify_menu
                ;;
            3)
                return
                ;;
            *)
                echo -e "${RED}Invalid option${NC}"
                ;;
        esac
        break
    done
}

test_notify_menu() {
    show_banner
    echo -e "${BOLD}═══ test_notify ═══${NC}"
    echo ""
    echo "Send a test notification to verify driver configuration"
    echo ""
    echo -e "${BOLD}Available options:${NC}"
    echo "  DRIVER_NAME        Name of notification driver (required)"
    echo "  --channel=NAME     Specific channel/recipient"
    echo "  --message=TEXT     Custom test message"
    echo ""

    read -p "Enter driver name: " driver_name
    if [ -z "$driver_name" ]; then
        echo -e "${RED}Driver name required${NC}"
        return
    fi

    read -p "Enter channel (optional): " channel
    read -p "Enter custom message (optional): " message

    local cmd="uv run python manage.py test_notify $driver_name"
    if [ -n "$channel" ]; then
        cmd="$cmd --channel=$channel"
    fi
    if [ -n "$message" ]; then
        cmd="$cmd --message=\"$message\""
    fi

    confirm_and_run "$cmd"
}

Step 2: Test

./bin/cli.sh
# Select option 6 (Notifications)

Step 3: Commit

git add bin/cli.sh
git commit -m "feat(cli): add notifications menu with list_notify_drivers and test_notify"

Task 8: Final polish and testing

Files:

  • Modify: bin/cli.sh

Step 1: Add help option and improve UX

# Add at top after colors
show_help() {
    echo "Usage: ./bin/cli.sh [command]"
    echo ""
    echo "Interactive CLI for Server Maintenance"
    echo ""
    echo "Commands:"
    echo "  (no args)    Start interactive mode"
    echo "  help         Show this help message"
    echo "  install      Jump to installation menu"
    echo "  health       Jump to health monitoring"
    echo "  alerts       Jump to alerts menu"
    echo "  intel        Jump to intelligence menu"
    echo "  pipeline     Jump to pipeline menu"
    echo "  notify       Jump to notifications menu"
    echo ""
}

# Update main() to handle arguments
main() {
    case "${1:-}" in
        help|--help|-h)
            show_help
            exit 0
            ;;
        install)
            show_banner
            install_project
            ;;
        health)
            show_banner
            health_menu
            ;;
        alerts)
            show_banner
            alerts_menu
            ;;
        intel|intelligence)
            show_banner
            intelligence_menu
            ;;
        pipeline)
            show_banner
            pipeline_menu
            ;;
        notify)
            show_banner
            notify_menu
            ;;
        "")
            while true; do
                show_banner
                show_main_menu
                echo ""
                read -p "Press Enter to continue..."
            done
            ;;
        *)
            echo "Unknown command: $1"
            show_help
            exit 1
            ;;
    esac
}

Step 2: Test all menus

# Test interactive mode
./bin/cli.sh

# Test direct commands
./bin/cli.sh help
./bin/cli.sh health
./bin/cli.sh intel

Step 3: Commit

git add bin/cli.sh
git commit -m "feat(cli): add help and direct command shortcuts"

Summary

Task Description
1 Create base script with banner and main menu
2 Add install/setup function
3 Add health monitoring menu
4 Add alerts menu
5 Add intelligence menu
6 Add pipeline menu
7 Add notifications menu
8 Final polish and testing

This site uses Just the Docs, a documentation theme for Jekyll.