~kris/dots

sdeploy

9cef5645c384935405b1f9a09731e8995eb59987 — Kris Yotam 6 months ago
Initial commit: deployment scripts split from lazykris

Arch Linux deploy fully implemented with updated URLs pointing to
srice/sdeploy repos. Skeleton structure for Gentoo, Kali, Ubuntu,
macOS, and Windows 11.
A  => .gitignore +7 -0
@@ 1,7 @@
*.aux
*.log
*.out
*.toc
*.fls
*.fdb_latexmk
*.synctex.gz

A  => README.md +30 -0
@@ 1,30 @@
# sdeploy

Kris's Simple Deploy — OS-specific deployment scripts that install packages and configure a system using [srice](https://github.com/krisyotam/srice) dotfiles.

## Structure

```
ksd-arch/      → Arch Linux (primary, fully implemented)
ksd-gentoo/    → Gentoo (planned)
ksd-kali/      → Kali Linux (planned)
ksd-ubuntu/    → Ubuntu/Debian (planned)
ksd-macos/     → macOS (planned)
ksd-win11/     → Windows 11 + WSL (planned)
```

## Usage (Arch)

```bash
curl -LO https://raw.githubusercontent.com/krisyotam/sdeploy/main/ksd-arch/deploy.sh
bash deploy.sh
```

The deploy script will:
1. Install packages from `progs.csv`
2. Clone and stow [srice](https://github.com/krisyotam/srice) dotfiles
3. Run post-install configuration

## Related

- [srice](https://github.com/krisyotam/srice) — The dotfiles this deploys

A  => compile-all-pdfs.sh +9 -0
@@ 1,9 @@
#!/bin/bash
# Compile all manual.tex files across KSD variants
for dir in ksd-*/; do
    if [ -f "$dir/manual.tex" ]; then
        echo "Compiling $dir/manual.tex..."
        (cd "$dir" && latexmk -pdf manual.tex)
    fi
done
echo "Done."

A  => ksd-arch/deploy.sh +1072 -0
@@ 1,1072 @@
#!/bin/sh

# ============================================================================
#
#       ██╗      █████╗ ███████╗██╗   ██╗██╗  ██╗██████╗ ██╗███████╗        Z
#       ██║     ██╔══██╗╚══███╔╝╚██╗ ██╔╝██║ ██╔╝██╔══██╗██║██╔════╝      Z
#       ██║     ███████║  ███╔╝  ╚████╔╝ █████╔╝ ██████╔╝██║███████╗    z
#       ██║     ██╔══██║ ███╔╝    ╚██╔╝  ██╔═██╗ ██╔══██╗██║╚════██║  z
#       ███████╗██║  ██║███████╗   ██║   ██║  ██╗██║  ██║██║███████║
#       ╚══════╝╚═╝  ╚═╝╚══════╝   ╚═╝   ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝╚══════╝
#
# LazyKris - Kris's Auto Rice Bootstrapping Scripts
# "The only way to do great work is to automate the boring parts."
#                                              - Every Linux User Ever
#
# Author: Kris Yotam (aka. khr1st)
# Contact: krisyotam@protonmail.com
# Date: 2026.01.23
# License: GNU GPLv3
# Repository: https://github.com/krisyotam/lazykris
# ============================================================================

# ============================================================================
# CONFIGURATION VARIABLES
# ============================================================================

# Repository URLs and branches
DOTFILES_REPO="https://github.com/krisyotam/srice.git"
DOTFILES_BRANCH="main"
PROGS_FILE="https://raw.githubusercontent.com/krisyotam/sdeploy/main/ksd-arch/progs.csv"
NOTES_FILE="https://raw.githubusercontent.com/krisyotam/sdeploy/main/ksd-arch/notes.csv"
DEV_FILE="https://raw.githubusercontent.com/krisyotam/sdeploy/main/ksd-arch/dev.csv"

# Doom Emacs repository
DOOM_REPO="https://github.com/doomemacs/doomemacs"

# Dev directory top-level directories
DEV_TLDS="sites systems formal foss labs parsing"

# AUR helper of choice (yay is recommended)
AUR_HELPER="yay"

# BlackArch repository setup script
BLACKARCH_STRAP="https://blackarch.org/strap.sh"

# AppImages directory (relative to user home)
APPIMAGES_DIR=".local/bin/appimages"

# Source directory for git builds (suckless, etc)
SRC_DIR=".local/src"

# Flatpak remote
FLATPAK_REMOTE="flathub"
FLATPAK_REMOTE_URL="https://dl.flathub.org/repo/flathub.flatpakrepo"

# Terminal settings
export TERM=ansi

# Device type (set during installation)
# Options: "desktop" or "macbook-2015"
DEVICE_TYPE=""

# Optional installations (set during installation)
INSTALL_NOTES="no"
INSTALL_DEV="no"

# ============================================================================
# UTILITY FUNCTIONS
# ============================================================================

# Display error message and exit
error() {
    printf "\033[1;31mError:\033[0m %s\n" "$1" >&2
    exit 1
}

# Display info message
info() {
    printf "\033[1;34m==>\033[0m %s\n" "$1"
}

# Display success message
success() {
    printf "\033[1;32m==>\033[0m %s\n" "$1"
}

# Display warning message
warn() {
    printf "\033[1;33m==>\033[0m %s\n" "$1"
}

# Install a package from official repos (pacman)
installpkg() {
    pacman --noconfirm --needed -S "$1" >/dev/null 2>&1
}

# ============================================================================
# DEVICE SELECTION
# ============================================================================

# Ask user which device they're installing on
selectdevice() {
    DEVICE_TYPE=$(whiptail --title "Device Selection" \
        --menu "Which device are you installing on?\n\nThis determines HiDPI settings, bar sizes, etc." 14 60 2 \
        "desktop" "Custom PC / Standard Display" \
        "macbook-2015" "MacBook Pro 2015 Retina (13\")" \
        3>&1 1>&2 2>&3 3>&1) || exit 1
}

# Run device-specific post-installation scripts
run_device_setup() {
    case "$DEVICE_TYPE" in
        "macbook-2015")
            whiptail --infobox "Applying MacBook Pro 2015 Retina settings..." 7 55
            # Run the laptop HiDPI script
            if [ -x "/home/$name/.local/bin/laptop" ]; then
                sudo -u "$name" /home/$name/.local/bin/laptop
            else
                warn "Laptop script not found or not executable"
            fi
            ;;
        "desktop")
            whiptail --infobox "Desktop setup - no additional configuration needed." 7 55
            sleep 1
            ;;
        *)
            # Unknown device, skip
            ;;
    esac
}

# ============================================================================
# GITHUB AUTHENTICATION
# ============================================================================

# Authenticate with GitHub for private repo access
setup_github_auth() {
    # Check if gh is installed
    if ! command -v gh >/dev/null 2>&1; then
        warn "GitHub CLI not installed, skipping authentication"
        return 1
    fi

    # Check if already authenticated
    if sudo -u "$name" gh auth status >/dev/null 2>&1; then
        whiptail --infobox "Already authenticated with GitHub." 7 50
        sleep 1
        return 0
    fi

    # Explain the process to user
    whiptail --title "GitHub Authentication" --msgbox "To clone private repositories, you need to authenticate with GitHub.

The next screen will show a one-time code.

1. Visit: github.com/login/device
2. Enter the code shown
3. Approve access

Press OK to continue." 14 55

    # Run gh auth login with device flow
    # Using --git-protocol https so git operations use the gh credential helper
    clear
    echo ""
    echo "=========================================="
    echo "  GitHub Device Authentication"
    echo "=========================================="
    echo ""
    sudo -u "$name" gh auth login --hostname github.com --git-protocol https --scopes repo,read:org

    # Verify authentication succeeded
    if sudo -u "$name" gh auth status >/dev/null 2>&1; then
        whiptail --infobox "GitHub authentication successful!" 7 45
        sleep 1
        return 0
    else
        warn "GitHub authentication failed or was cancelled"
        return 1
    fi
}

# ============================================================================
# OPTIONAL INSTALLATIONS
# ============================================================================

# Ask user about optional repo installations (notes, dev)
selectoptional() {
    # Notes repositories (slipbox, etc.)
    if whiptail --title "Notes Repositories" \
        --yesno "Install notes repositories (slipbox, etc.)?

This clones Kris's personal notes repos into ~/notes/.
These are private repos and require GitHub authentication.

Skip this if you're not Kris or don't have access." 14 60; then
        INSTALL_NOTES="yes"
    else
        INSTALL_NOTES="no"
    fi

    # Dev repositories
    if whiptail --title "Dev Repositories" \
        --yesno "Install development repositories?

This creates ~/dev/ structure with TLDs:
  sites, systems, formal, foss, labs, parsing

And clones repos from dev.csv (many are private).

Skip this if you're not Kris or don't have access." 16 60; then
        INSTALL_DEV="yes"
    else
        INSTALL_DEV="no"
    fi
}

# ============================================================================
# WELCOME AND USER INPUT
# ============================================================================

# Display welcome message with ASCII art
welcomemsg() {
    whiptail --title "Welcome!" --msgbox "
   ██╗      █████╗ ███████╗██╗   ██╗██╗  ██╗██████╗ ██╗███████╗        Z
   ██║     ██╔══██╗╚══███╔╝╚██╗ ██╔╝██║ ██╔╝██╔══██╗██║██╔════╝      Z
   ██║     ███████║  ███╔╝  ╚████╔╝ █████╔╝ ██████╔╝██║███████╗    z
   ██║     ██╔══██║ ███╔╝    ╚██╔╝  ██╔═██╗ ██╔══██╗██║╚════██║  z
   ███████╗██║  ██║███████╗   ██║   ██║  ██╗██║  ██║██║███████║
   ╚══════╝╚═╝  ╚═╝╚══════╝   ╚═╝   ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝╚══════╝

Welcome to LazyKris!

This script will automatically install a fully-featured
Arch Linux desktop with my custom builds of dwm, dmenu,
dwmblocks, st, and surf. In addition several extreme privacy
configs for the rotation of browsers ran.

Sit back, grab a coffee, and let the automation begin.

-Kris" 24 80

    whiptail --title "Important Note!" \
        --yes-button "All ready!" \
        --no-button "Return..." \
        --yesno "Before we begin, please ensure:

1. You are running this as root
2. Pacman is updated (pacman -Sy)
3. Arch keyrings are current
4. You have a stable internet connection

If any of these are not met, the installation
may fail partway through." 14 60
}

# Get username and password from user
getuserandpass() {
    name=$(whiptail --inputbox "Enter a username for the new account.

This will be the user that owns the dotfiles
and runs the desktop environment." 12 60 3>&1 1>&2 2>&3 3>&1) || exit 1

    # Validate username format
    while ! echo "$name" | grep -q "^[a-z_][a-z0-9_-]*$"; do
        name=$(whiptail --nocancel --inputbox "Invalid username.

Username must:
- Start with a lowercase letter or underscore
- Contain only lowercase letters, numbers, - or _

Enter a valid username:" 14 60 3>&1 1>&2 2>&3 3>&1)
    done

    # Get password
    pass1=$(whiptail --nocancel --passwordbox "Enter a password for $name." 10 60 3>&1 1>&2 2>&3 3>&1)
    pass2=$(whiptail --nocancel --passwordbox "Confirm the password." 10 60 3>&1 1>&2 2>&3 3>&1)

    # Verify password match
    while [ "$pass1" != "$pass2" ]; do
        unset pass2
        pass1=$(whiptail --nocancel --passwordbox "Passwords did not match.

Enter password again:" 12 60 3>&1 1>&2 2>&3 3>&1)
        pass2=$(whiptail --nocancel --passwordbox "Confirm the password." 10 60 3>&1 1>&2 2>&3 3>&1)
    done
}

# Warn if user already exists
usercheck() {
    if id -u "$name" >/dev/null 2>&1; then
        whiptail --title "User Exists" \
            --yes-button "Continue" \
            --no-button "Cancel" \
            --yesno "The user '$name' already exists on this system.

LazyKris can install for an existing user, but it will
OVERWRITE any conflicting dotfiles and settings.

Your personal files (documents, videos, etc.) will NOT
be touched.

Note: The password will be changed to what you entered.

Continue with installation?" 16 65
    fi
}

# Final confirmation before install
preinstallmsg() {
    whiptail --title "Ready to Install" \
        --yes-button "Let's go!" \
        --no-button "Cancel" \
        --yesno "Everything is ready!

The installation will now proceed automatically.
This may take 30-60 minutes depending on your
internet speed and the number of packages.

You can watch the progress, but no input is needed.

Press 'Let's go!' to begin installation." 14 60 || {
        clear
        exit 1
    }
}

# ============================================================================
# USER MANAGEMENT
# ============================================================================

# Create user account and set password
adduserandpass() {
    whiptail --infobox "Creating user '$name'..." 7 50

    # Create user with fish shell, add to wheel group
    useradd -m -g wheel -s /usr/bin/fish "$name" >/dev/null 2>&1 ||
        usermod -a -G wheel "$name" && mkdir -p /home/"$name" && chown "$name":wheel /home/"$name"

    # Set up source directory for git builds
    export repodir="/home/$name/$SRC_DIR"
    mkdir -p "$repodir"
    chown -R "$name":wheel "$(dirname "$repodir")"

    # Set password
    echo "$name:$pass1" | chpasswd
    unset pass1 pass2
}

# ============================================================================
# SYSTEM PREPARATION
# ============================================================================

# Refresh Arch keyrings (handles both Arch and Artix)
refreshkeys() {
    case "$(readlink -f /sbin/init)" in
        *systemd*)
            whiptail --infobox "Refreshing Arch keyring..." 7 40
            pacman --noconfirm -S archlinux-keyring >/dev/null 2>&1
            ;;
        *)
            whiptail --infobox "Setting up Arch repos for Artix..." 7 50
            pacman --noconfirm --needed -S \
                artix-keyring artix-archlinux-support >/dev/null 2>&1

            # Add Arch extra repo if not present
            grep -q "^\[extra\]" /etc/pacman.conf || {
                echo "[extra]
Include = /etc/pacman.d/mirrorlist-arch" >>/etc/pacman.conf
            }

            pacman -Sy --noconfirm >/dev/null 2>&1
            pacman-key --populate archlinux >/dev/null 2>&1
            ;;
    esac
}

# Set up BlackArch repository for security tools
setup_blackarch() {
    whiptail --infobox "Setting up BlackArch repository..." 7 50

    # Check if BlackArch is already configured
    if grep -q "^\[blackarch\]" /etc/pacman.conf; then
        return 0
    fi

    # Download and run the strap script
    curl -sL "$BLACKARCH_STRAP" -o /tmp/blackarch-strap.sh
    chmod +x /tmp/blackarch-strap.sh
    /tmp/blackarch-strap.sh >/dev/null 2>&1

    # Sync repos
    pacman -Sy --noconfirm >/dev/null 2>&1
}

# Set up Flatpak
setup_flatpak() {
    whiptail --infobox "Setting up Flatpak..." 7 40

    # Install flatpak if not present
    installpkg flatpak

    # Add flathub remote
    flatpak remote-add --if-not-exists "$FLATPAK_REMOTE" "$FLATPAK_REMOTE_URL" >/dev/null 2>&1
}

# ============================================================================
# PACKAGE INSTALLATION FUNCTIONS
# ============================================================================

# Install AUR helper manually (yay)
manualinstall() {
    # Skip if already installed
    pacman -Qq "$1" >/dev/null 2>&1 && return 0

    whiptail --infobox "Installing $1 manually..." 7 50

    sudo -u "$name" mkdir -p "$repodir/$1"
    sudo -u "$name" git -C "$repodir" clone --depth 1 --single-branch \
        --no-tags -q "https://aur.archlinux.org/$1.git" "$repodir/$1" 2>/dev/null ||
        {
            cd "$repodir/$1" || return 1
            sudo -u "$name" git pull --force origin master
        }

    cd "$repodir/$1" || exit 1
    sudo -u "$name" makepkg --noconfirm -si >/dev/null 2>&1 || return 1
}

# Install from official repos (pacman)
maininstall() {
    whiptail --title "LazyKris Installation" \
        --infobox "[$n/$total] Installing: $1

$2" 8 70
    installpkg "$1"
}

# Install from AUR via helper
aurinstall() {
    whiptail --title "LazyKris Installation" \
        --infobox "[$n/$total] Installing from AUR: $1

$2" 8 70

    # Skip if already installed
    echo "$aurinstalled" | grep -q "^$1$" && return 0

    sudo -u "$name" $AUR_HELPER -S --noconfirm "$1" >/dev/null 2>&1
}

# Install via git clone and make
gitmakeinstall() {
    # Extract program name from URL
    progname="${1##*/}"
    progname="${progname%.git}"
    dir="$repodir/$progname"

    whiptail --title "LazyKris Installation" \
        --infobox "[$n/$total] Building from source: $progname

$2" 8 70

    # Clone or update repository
    sudo -u "$name" git -C "$repodir" clone --depth 1 --single-branch \
        --no-tags -q "$1" "$dir" 2>/dev/null ||
        {
            cd "$dir" || return 1
            sudo -u "$name" git pull --force origin master
        }

    # Build and install
    cd "$dir" || exit 1
    make >/dev/null 2>&1
    make install >/dev/null 2>&1
    cd /tmp || return 1
}

# Install from Flatpak
flatpakinstall() {
    whiptail --title "LazyKris Installation" \
        --infobox "[$n/$total] Installing Flatpak: $1

$2" 8 70

    flatpak install -y "$FLATPAK_REMOTE" "$1" >/dev/null 2>&1
}

# Install AppImage from URL
appimageinstall() {
    # Extract filename from URL
    filename="${1##*/}"
    # Clean up the filename (remove version numbers for cleaner name)
    cleanname=$(echo "$filename" | sed 's/-[0-9].*\.AppImage/.AppImage/')

    whiptail --title "LazyKris Installation" \
        --infobox "[$n/$total] Downloading AppImage: $cleanname

$2" 8 70

    # Create appimages directory
    appdir="/home/$name/$APPIMAGES_DIR"
    sudo -u "$name" mkdir -p "$appdir"

    # Download and make executable
    sudo -u "$name" curl -sL "$1" -o "$appdir/$cleanname"
    chmod +x "$appdir/$cleanname"
    chown "$name":wheel "$appdir/$cleanname"
}

# Install from BlackArch repository
blackarchinstall() {
    whiptail --title "LazyKris Installation" \
        --infobox "[$n/$total] Installing from BlackArch: $1

$2" 8 70

    # Ensure BlackArch is set up
    grep -q "^\[blackarch\]" /etc/pacman.conf || setup_blackarch

    installpkg "$1"
}

# ============================================================================
# MAIN INSTALLATION LOOP
# ============================================================================

installationloop() {
    # Download or copy progs.csv
    if [ -f "$PROGS_FILE" ]; then
        cp "$PROGS_FILE" /tmp/progs.csv
    else
        curl -Ls "$PROGS_FILE" >/tmp/progs.csv
    fi

    # Remove comments and empty lines for counting
    sed '/^#/d;/^$/d' /tmp/progs.csv >/tmp/progs-clean.csv
    total=$(wc -l </tmp/progs-clean.csv)
    aurinstalled=$(pacman -Qqm 2>/dev/null)

    # Track if we need special setup
    needs_blackarch=false
    needs_flatpak=false

    # First pass: check what we need
    while IFS=, read -r tag program comment; do
        case "$tag" in
            "B") needs_blackarch=true ;;
            "F") needs_flatpak=true ;;
        esac
    done </tmp/progs-clean.csv

    # Set up special repositories if needed
    [ "$needs_blackarch" = true ] && setup_blackarch
    [ "$needs_flatpak" = true ] && setup_flatpak

    # Second pass: install everything
    n=0
    while IFS=, read -r tag program comment; do
        n=$((n + 1))

        # Strip quotes from comment if present
        echo "$comment" | grep -q "^\".*\"$" &&
            comment="$(echo "$comment" | sed -E "s/(^\"|\"$)//g")"

        case "$tag" in
            "A") aurinstall "$program" "$comment" ;;
            "G") gitmakeinstall "$program" "$comment" ;;
            "F") flatpakinstall "$program" "$comment" ;;
            "I") appimageinstall "$program" "$comment" ;;
            "B") blackarchinstall "$program" "$comment" ;;
            *)   maininstall "$program" "$comment" ;;
        esac
    done </tmp/progs-clean.csv
}

# ============================================================================
# NOTES REPOSITORIES INSTALLATION
# ============================================================================

# Install notes repositories from notes.csv
notesinstallloop() {
    whiptail --infobox "Setting up notes repositories..." 7 50

    # Download or copy notes.csv
    if [ -f "$NOTES_FILE" ]; then
        cp "$NOTES_FILE" /tmp/notes.csv
    else
        curl -Ls "$NOTES_FILE" >/tmp/notes.csv
    fi

    # Remove comments and empty lines
    sed '/^#/d;/^$/d' /tmp/notes.csv >/tmp/notes-clean.csv

    notesdir="/home/$name/notes"
    sudo -u "$name" mkdir -p "$notesdir"

    # Clone each repository
    while IFS=, read -r repo_url target_dir description; do
        # Strip quotes if present
        repo_url=$(echo "$repo_url" | sed -E "s/(^\"|\"$)//g")
        target_dir=$(echo "$target_dir" | sed -E "s/(^\"|\"$)//g")
        description=$(echo "$description" | sed -E "s/(^\"|\"$)//g")

        whiptail --infobox "Cloning notes repo: $description" 7 60

        if [ "$target_dir" = "." ] || [ -z "$target_dir" ]; then
            # Clone directly into notes directory (merge contents)
            clone_dir="$notesdir"
        else
            # Clone into subdirectory
            clone_dir="$notesdir/$target_dir"
        fi

        # Clone or update the repository
        if [ -d "$clone_dir/.git" ]; then
            # Already exists, pull updates
            sudo -u "$name" git -C "$clone_dir" pull --ff-only >/dev/null 2>&1
        elif [ "$target_dir" = "." ] || [ -z "$target_dir" ]; then
            # Clone into existing notes dir (init if empty)
            sudo -u "$name" git clone --depth 1 "$repo_url" "$notesdir.tmp" >/dev/null 2>&1
            # Move contents (except .git initially, then move .git)
            sudo -u "$name" cp -rfT "$notesdir.tmp" "$notesdir"
            rm -rf "$notesdir.tmp"
        else
            sudo -u "$name" git clone --depth 1 "$repo_url" "$clone_dir" >/dev/null 2>&1
        fi

    done </tmp/notes-clean.csv

    chown -R "$name":wheel "$notesdir"
    rm -f /tmp/notes.csv /tmp/notes-clean.csv
}

# ============================================================================
# DEV REPOSITORIES INSTALLATION
# ============================================================================

# Install dev repositories from dev.csv
devinstallloop() {
    whiptail --infobox "Setting up development environment..." 7 50

    devdir="/home/$name/dev"

    # Create all TLD directories (even if empty)
    for tld in $DEV_TLDS; do
        sudo -u "$name" mkdir -p "$devdir/$tld"
    done

    # Download or copy dev.csv
    if [ -f "$DEV_FILE" ]; then
        cp "$DEV_FILE" /tmp/dev.csv
    else
        curl -Ls "$DEV_FILE" >/tmp/dev.csv
    fi

    # Remove comments and empty lines
    sed '/^#/d;/^$/d' /tmp/dev.csv >/tmp/dev-clean.csv

    # Count repos for progress
    total_repos=$(wc -l </tmp/dev-clean.csv)
    n=0

    # Clone each repository
    while IFS=, read -r repo_name repo_url description tld; do
        n=$((n + 1))

        # Strip quotes if present
        repo_name=$(echo "$repo_name" | sed -E "s/(^\"|\"$)//g")
        repo_url=$(echo "$repo_url" | sed -E "s/(^\"|\"$)//g")
        description=$(echo "$description" | sed -E "s/(^\"|\"$)//g")
        tld=$(echo "$tld" | sed -E "s/(^\"|\"$)//g")

        # Target directory
        clone_dir="$devdir/$tld/$repo_name"

        whiptail --infobox "[$n/$total_repos] Cloning: $repo_name
Into: ~/dev/$tld/

$description" 9 60

        # Clone or update the repository
        if [ -d "$clone_dir/.git" ]; then
            # Already exists, pull updates
            sudo -u "$name" git -C "$clone_dir" pull --ff-only >/dev/null 2>&1
        else
            # Ensure parent directory exists
            sudo -u "$name" mkdir -p "$(dirname "$clone_dir")"
            # Clone the repo
            sudo -u "$name" git clone --depth 1 "$repo_url" "$clone_dir" >/dev/null 2>&1
        fi

    done </tmp/dev-clean.csv

    chown -R "$name":wheel "$devdir"
    rm -f /tmp/dev.csv /tmp/dev-clean.csv

    success "Development environment setup complete!"
}

# ============================================================================
# DOTFILES INSTALLATION
# ============================================================================

# Clone and deploy dotfiles directly (LARBS method)
putgitrepo() {
    # Downloads a gitrepo $1 and places the files in $2 only overwriting conflicts
    whiptail --infobox "Downloading and installing config files..." 7 60

    dir=$(mktemp -d)
    [ ! -d "$2" ] && mkdir -p "$2"
    chown "$name":wheel "$dir" "$2"

    sudo -u "$name" git -C "$dir" clone --depth 1 \
        --single-branch --no-tags -q --recursive -b "$DOTFILES_BRANCH" \
        --recurse-submodules "$1" "$dir/repo"

    # Copy all dotfiles to target directory
    sudo -u "$name" cp -rfT "$dir/repo" "$2"

    # Clean up git metadata and repo files from home
    rm -rf "$2/.git" "$2/README.md" "$2/LICENSE" "$2/FUNDING.yml" "$2/.stowrc" "$2/.stow-local-ignore"

    # Keep a copy of the repo in .local/src for reference/updates
    dotfiles_dir="/home/$name/.local/src/lazykris"
    sudo -u "$name" mkdir -p "$(dirname "$dotfiles_dir")"
    sudo -u "$name" cp -rfT "$dir/repo" "$dotfiles_dir"

    rm -rf "$dir"
}

# Set wallpaper using setbg
setup_wallpaper() {
    whiptail --infobox "Setting wallpaper..." 7 50

    wallpaper="/home/$name/.local/share/lazykris/lazykris-wallpaper.png"
    if [ -f "$wallpaper" ] && [ -x "/home/$name/.local/bin/setbg" ]; then
        sudo -u "$name" /home/$name/.local/bin/setbg -s "$wallpaper"
    fi
}

# ============================================================================
# POST-INSTALLATION SETUP
# ============================================================================

# Set up Doom Emacs
setup_doom_emacs() {
    whiptail --infobox "Installing Doom Emacs..." 7 50

    emacsdir="/home/$name/.config/emacs"
    doomdir="/home/$name/.config/doom"

    # Clone Doom Emacs if not present
    if [ ! -d "$emacsdir" ]; then
        sudo -u "$name" git clone --depth 1 "$DOOM_REPO" "$emacsdir" >/dev/null 2>&1
    fi

    # Ensure doom config directory exists (should be from dotfiles)
    sudo -u "$name" mkdir -p "$doomdir"

    # Run doom install (non-interactive)
    whiptail --infobox "Running Doom Emacs install (this may take a while)..." 7 60
    sudo -u "$name" DOOMDIR="$doomdir" "$emacsdir/bin/doom" install --no-config --no-env --no-fonts >/dev/null 2>&1

    # Sync doom packages
    whiptail --infobox "Syncing Doom Emacs packages..." 7 50
    sudo -u "$name" DOOMDIR="$doomdir" "$emacsdir/bin/doom" sync >/dev/null 2>&1

    # Note: doom bin path is already in fish config
}

# Set up Neovim (LazyVim auto-bootstraps, just ensure first run works)
setup_neovim() {
    whiptail --infobox "Preparing Neovim (LazyVim)..." 7 50

    nvimdir="/home/$name/.config/nvim"
    nvimdata="/home/$name/.local/share/nvim"

    # Ensure directories exist
    sudo -u "$name" mkdir -p "$nvimdir"
    sudo -u "$name" mkdir -p "$nvimdata"

    # LazyVim bootstraps itself on first run via lazy.lua
    # Run nvim headless to trigger plugin installation
    whiptail --infobox "Installing Neovim plugins (LazyVim)..." 7 55
    sudo -u "$name" nvim --headless "+Lazy! sync" +qa >/dev/null 2>&1 || true

    chown -R "$name":wheel "$nvimdir" "$nvimdata"
}

# Create necessary directories
create_directories() {
    whiptail --infobox "Creating directory structure..." 7 50

    homedir="/home/$name"

    # Core directories
    sudo -u "$name" mkdir -p "$homedir/downloads"
    sudo -u "$name" mkdir -p "$homedir/dev"
    sudo -u "$name" mkdir -p "$homedir/notes"
    sudo -u "$name" mkdir -p "$homedir/mail"
    sudo -u "$name" mkdir -p "$homedir/tmp"
    sudo -u "$name" mkdir -p "$homedir/archive"

    # Media directories
    sudo -u "$name" mkdir -p "$homedir/media/music"
    sudo -u "$name" mkdir -p "$homedir/media/pics"
    sudo -u "$name" mkdir -p "$homedir/media/videos"
    sudo -u "$name" mkdir -p "$homedir/media/screenshots"
    sudo -u "$name" mkdir -p "$homedir/media/wallpapers"
    sudo -u "$name" mkdir -p "$homedir/media/recordings"
    sudo -u "$name" mkdir -p "$homedir/media/books"
    sudo -u "$name" mkdir -p "$homedir/media/docs"

    # XDG directories (.local)
    sudo -u "$name" mkdir -p "$homedir/.local/bin"
    sudo -u "$name" mkdir -p "$homedir/.local/bin/appimages"
    sudo -u "$name" mkdir -p "$homedir/.local/bin/statusbar"
    sudo -u "$name" mkdir -p "$homedir/.local/src"
    sudo -u "$name" mkdir -p "$homedir/.local/share"
    sudo -u "$name" mkdir -p "$homedir/.local/share/man"
    sudo -u "$name" mkdir -p "$homedir/.local/state"

    # XDG config and cache
    sudo -u "$name" mkdir -p "$homedir/.config"
    sudo -u "$name" mkdir -p "$homedir/.cache"
    sudo -u "$name" mkdir -p "$homedir/.cache/fish"

    # Flatpak data directory
    sudo -u "$name" mkdir -p "$homedir/.var/app"

    # Keys and security (empty, managed by tools)
    sudo -u "$name" mkdir -p "$homedir/.ssh"
    sudo -u "$name" mkdir -p "$homedir/.gnupg"
    chmod 700 "$homedir/.ssh" "$homedir/.gnupg"

    # Claude Code
    sudo -u "$name" mkdir -p "$homedir/.claude"

    # Application-specific config directories
    sudo -u "$name" mkdir -p "$homedir/.config/abook"
    sudo -u "$name" mkdir -p "$homedir/.config/mpd/playlists"
    sudo -u "$name" mkdir -p "$homedir/.config/newsboat"
    sudo -u "$name" mkdir -p "$homedir/.config/btop/themes"
    sudo -u "$name" mkdir -p "$homedir/.config/dunst"
    sudo -u "$name" mkdir -p "$homedir/.config/calcurse"
    sudo -u "$name" mkdir -p "$homedir/.config/rtorrent"
    sudo -u "$name" mkdir -p "$homedir/.config/zathura"
    sudo -u "$name" mkdir -p "$homedir/.config/wal/templates"

    # Set proper ownership
    chown -R "$name":wheel "$homedir"
}

# Set fish as default shell
setup_fish_shell() {
    whiptail --infobox "Setting fish as default shell..." 7 50
    chsh -s /usr/bin/fish "$name" >/dev/null 2>&1
}

# Make all user bin scripts executable
setup_bin_scripts() {
    whiptail --infobox "Setting up user scripts..." 7 50

    bindir="/home/$name/.local/bin"

    # Make all scripts in .local/bin executable
    if [ -d "$bindir" ]; then
        find "$bindir" -type f -exec chmod +x {} \;
        chown -R "$name":wheel "$bindir"
    fi

    # Also handle statusbar scripts
    if [ -d "$bindir/statusbar" ]; then
        find "$bindir/statusbar" -type f -exec chmod +x {} \;
    fi
}

# System configuration tweaks
system_tweaks() {
    whiptail --infobox "Applying system tweaks..." 7 50

    # Disable system beep
    rmmod pcspkr 2>/dev/null
    echo "blacklist pcspkr" >/etc/modprobe.d/nobeep.conf

    # Make dash the default /bin/sh (faster scripts)
    ln -sfT /bin/dash /bin/sh 2>/dev/null

    # Generate dbus UUID (needed for some systems)
    dbus-uuidgen >/var/lib/dbus/machine-id 2>/dev/null

    # Pacman tweaks: colors, parallel downloads, candy
    grep -q "ILoveCandy" /etc/pacman.conf || \
        sed -i "/#VerbosePkgLists/a ILoveCandy" /etc/pacman.conf
    sed -Ei "s/^#(ParallelDownloads).*/\1 = 5/;/^#Color$/s/#//" /etc/pacman.conf

    # Use all cores for compilation
    sed -i "s/-j2/-j$(nproc)/;/^#MAKEFLAGS/s/^#//" /etc/makepkg.conf
}

# Enable tap to click for touchpads
setup_touchpad() {
    [ ! -f /etc/X11/xorg.conf.d/40-libinput.conf ] && {
        mkdir -p /etc/X11/xorg.conf.d
        printf 'Section "InputClass"
    Identifier "libinput touchpad catchall"
    MatchIsTouchpad "on"
    MatchDevicePath "/dev/input/event*"
    Driver "libinput"
    Option "Tapping" "on"
EndSection' >/etc/X11/xorg.conf.d/40-libinput.conf
    }
}

# Set up sudoers for wheel group
setup_sudoers() {
    whiptail --infobox "Configuring sudo permissions..." 7 50

    # Allow wheel users to sudo with password
    echo "%wheel ALL=(ALL:ALL) ALL" >/etc/sudoers.d/00-wheel-can-sudo

    # Allow certain commands without password
    echo "%wheel ALL=(ALL:ALL) NOPASSWD: /usr/bin/shutdown,/usr/bin/reboot,/usr/bin/systemctl suspend,/usr/bin/mount,/usr/bin/umount,/usr/bin/pacman -Syu,/usr/bin/pacman -Syyu,/usr/bin/pacman -Syyu --noconfirm,/usr/bin/loadkeys,/usr/bin/pacman -Syyuw --noconfirm" >/etc/sudoers.d/01-cmds-without-password

    # Set neovim as default editor for visudo
    echo "Defaults editor=/usr/bin/nvim" >/etc/sudoers.d/02-visudo-editor

    # Allow dmesg for non-root
    mkdir -p /etc/sysctl.d
    echo "kernel.dmesg_restrict = 0" >/etc/sysctl.d/dmesg.conf

    # Disable pam_faillock (prevents account lockouts on failed logins)
    for pamfile in /etc/pam.d/system-login /etc/pam.d/system-auth /etc/pam.d/login /etc/pam.d/sudo; do
        [ -f "$pamfile" ] && sed -i 's/^\([^#].*pam_faillock.*\)$/# \1/' "$pamfile"
    done
}

# Clean up temporary files
cleanup() {
    rm -f /tmp/progs.csv /tmp/progs-clean.csv
    rm -f /etc/sudoers.d/lazykris-temp
}

# Display completion message
finalize() {
    whiptail --title "Installation Complete!" --msgbox "
   ██╗      █████╗ ███████╗██╗   ██╗██╗  ██╗██████╗ ██╗███████╗        Z
   ██║     ██╔══██╗╚══███╔╝╚██╗ ██╔╝██║ ██╔╝██╔══██╗██║██╔════╝      Z
   ██║     ███████║  ███╔╝  ╚████╔╝ █████╔╝ ██████╔╝██║███████╗    z
   ██║     ██╔══██║ ███╔╝    ╚██╔╝  ██╔═██╗ ██╔══██╗██║╚════██║  z
   ███████╗██║  ██║███████╗   ██║   ██║  ██╗██║  ██║██║███████║
   ╚══════╝╚═╝  ╚═╝╚══════╝   ╚═╝   ╚═╝  ╚═╝╚═╝  ╚═╝╚═╝╚══════╝

Congratulations! LazyKris installation is complete!

To start using your new system:

1. Log out of root
2. Log in as '$name'
3. Run 'startx' to start dwm

Your default shell is fish, and all your dotfiles
have been deployed.

Enjoy your new setup!

-Kris" 28 80
}

# ============================================================================
# MAIN SCRIPT EXECUTION
# ============================================================================

# Ensure we're running as root with necessary tools
pacman --noconfirm --needed -Sy libnewt ||
    error "This script must be run as root on an Arch-based system with internet."

# Welcome and get user info
welcomemsg || error "User cancelled."
selectdevice || error "User cancelled."
selectoptional
getuserandpass || error "User cancelled."
usercheck || error "User cancelled."
preinstallmsg || error "User cancelled."

### Automated installation begins ###

# Refresh keyrings for package verification
refreshkeys || error "Failed to refresh keyrings."

# Install essential bootstrap packages
for pkg in curl ca-certificates base-devel git ntp fish dash; do
    whiptail --infobox "Installing bootstrap package: $pkg" 7 60
    installpkg "$pkg"
done

# Sync system time for package verification
whiptail --infobox "Synchronizing system time..." 7 50
ntpd -q -g >/dev/null 2>&1

# Create user account
adduserandpass || error "Failed to create user account."

# Handle any pacnew sudoers file
[ -f /etc/sudoers.pacnew ] && cp /etc/sudoers.pacnew /etc/sudoers

# Temporarily allow passwordless sudo for builds
trap 'rm -f /etc/sudoers.d/lazykris-temp' HUP INT QUIT TERM PWR EXIT
echo "%wheel ALL=(ALL) NOPASSWD: ALL
Defaults:%wheel,root runcwd=*" >/etc/sudoers.d/lazykris-temp

# Apply system tweaks
system_tweaks

# Install AUR helper
manualinstall "$AUR_HELPER" || error "Failed to install AUR helper."

# Enable automatic updates for git AUR packages
$AUR_HELPER -Y --save --devel

# Main installation loop - install all packages from progs.csv
installationloop

# Deploy dotfiles to home directory
putgitrepo "$DOTFILES_REPO" "/home/$name"

# Create directory structure
create_directories

# Make all bin scripts executable
setup_bin_scripts

# Set wallpaper
setup_wallpaper

# Set up fish shell
setup_fish_shell

# GitHub authentication (only if user wants private repos)
if [ "$INSTALL_NOTES" = "yes" ] || [ "$INSTALL_DEV" = "yes" ]; then
    setup_github_auth
fi

# Clone notes repositories (slipbox, etc.) - optional
[ "$INSTALL_NOTES" = "yes" ] && notesinstallloop

# Clone dev repositories and create TLD structure - optional
[ "$INSTALL_DEV" = "yes" ] && devinstallloop

# Set up Doom Emacs (install + sync packages)
setup_doom_emacs

# Set up Neovim (LazyVim plugin installation)
setup_neovim

# Enable touchpad tap-to-click
setup_touchpad

# Configure sudoers
setup_sudoers

# Run device-specific setup (laptop HiDPI, etc.)
run_device_setup

# Clean up
cleanup

# All done!
finalize

# vim: ft=sh ts=4 sw=4 et

A  => ksd-arch/dev.csv +39 -0
@@ 1,39 @@
#NAME,URL,DESCRIPTION,TLD
#
# Development repositories to clone into ~/dev/
# FORMAT: repo_name,github_url,description,top_level_directory
#
# TLDs (Top Level Directories):
#   sites   - websites (regardless of framework)
#   systems - low-level, infra, machine facing code
#   formal  - proofs in lean4, coq, agda, etc.
#   foss    - open source software contributions
#   labs    - experiments, prototypes, half-baked ideas
#   parsing - random src downloaded for inspiration
#
# Sites
krisyotam.com,https://github.com/krisyotam/krisyotam.com,personal website,sites
notes.krisyotam.com,https://github.com/krisyotam/notes.krisyotam.com,notes website,sites
thevirtuousqueen.com,https://github.com/krisyotam/thevirtuousqueen.com,virtuous queen website,sites
donlamar.com,https://github.com/krisyotam/donlamar.com,don lamar website,sites
#
# Formal
proofs,https://github.com/krisyotam/proofs,formal proofs collection,formal
#
# Labs
malware,https://github.com/krisyotam/malware,malware research with org zettel analysis,labs
prompts,https://github.com/krisyotam/prompts,prompts for various AI models,labs
scripts,https://github.com/krisyotam/scripts,general scripts and bin testing,labs
offsec,https://github.com/krisyotam/offsec,pentesting scripts for offsec and defsec,labs
pentest,https://github.com/krisyotam/pentest,pentest directories with org notes and opvpn files,labs
compcode,https://github.com/krisyotam/compcode,competitive programming solutions and practice,labs
#
# Parsing (inspiration repos)
wifi-password,https://github.com/rauchg/wifi-password,wifi password retrieval script,parsing
next-ai-news,https://github.com/rauchg/next-ai-news,next.js AI news app,parsing
NextFaster,https://github.com/ethanniser/NextFaster,faster next.js template,parsing
blog,https://github.com/rauchg/blog,rauchg blog source,parsing
gwern.net,https://github.com/gwern/gwern.net,gwern website source,parsing
archiver-bot,https://github.com/gwern/archiver-bot,gwern archiver bot,parsing
archive-text-urls,https://github.com/gwern/archive-text-urls,gwern url archiving tools,parsing
misc-haskell,https://github.com/gwern/misc-haskell,gwern misc haskell code,parsing

A  => ksd-arch/manual.pdf +0 -0
A  => ksd-arch/manual.tex +631 -0
@@ 1,631 @@
\documentclass[11pt,a4paper]{article}
\usepackage[margin=1in]{geometry}
\usepackage{longtable}
\usepackage{booktabs}
\usepackage{hyperref}
\usepackage{xcolor}
\usepackage{titlesec}
\usepackage{fancyhdr}
\usepackage{enumitem}
\usepackage{graphicx}
\usepackage{parskip}

% Colors
\definecolor{accent}{HTML}{458588}
\definecolor{darkbg}{HTML}{282828}
\definecolor{lighttext}{HTML}{EBDBB2}

% Hyperlink styling
\hypersetup{
    colorlinks=true,
    linkcolor=accent,
    urlcolor=accent,
    pdftitle={LazyKris Documentation},
    pdfauthor={Kris Yotam}
}

% Section styling
\titleformat{\section}{\Large\bfseries}{\thesection}{1em}{}
\titleformat{\subsection}{\large\bfseries}{\thesubsection}{1em}{}

% Header/footer
\pagestyle{fancy}
\fancyhf{}
\fancyhead[L]{\textbf{LazyKris}}
\fancyhead[R]{Kris Yotam}
\fancyfoot[C]{\thepage}
\renewcommand{\headrulewidth}{0.4pt}

\begin{document}

% Title Page
\begin{titlepage}
\centering
\vspace*{2cm}
{\Huge\bfseries LazyKris\par}
\vspace{0.5cm}
{\Large Kris's Auto-Rice Bootstrapping Script\par}
\vspace{2cm}
{\large An Arch Linux installer that deploys a complete,\\keyboard-driven environment in minutes.\par}
\vspace{3cm}
{\large Kris Yotam\par}
\vspace{0.5cm}
{\large \url{https://krisyotam.com}\par}
\vfill
{\large Version 1.0\par}
{\large \today\par}
\end{titlepage}

\tableofcontents
\newpage

% ==============================================================================
\section{Introduction}
% ==============================================================================

LazyKris is an auto-rice bootstrapping script for Arch Linux. It installs and configures a complete keyboard-driven environment centered around the suckless philosophy: simple, efficient software that does one thing well.

The system includes:
\begin{itemize}[noitemsep]
    \item \textbf{dwm} --- Tiling window manager with 22 patches
    \item \textbf{st} --- Terminal emulator with scrollback and ligatures
    \item \textbf{dmenu} --- Application launcher with fuzzy matching
    \item \textbf{dwmblocks} --- Modular status bar
    \item \textbf{surf} --- Minimal webkit browser for focused work
    \item \textbf{fish} --- Shell with syntax highlighting
    \item \textbf{lf} --- Terminal file manager with previews
    \item \textbf{neovim} --- Modern text editor
\end{itemize}

\subsection{Installation}

On a fresh Arch Linux system:

\begin{verbatim}
curl -LO https://raw.githubusercontent.com/krisyotam/lazykris/main/lazykris.sh
sh lazykris.sh
\end{verbatim}

The script will prompt for a username, install all packages, compile suckless builds, deploy dotfiles, and set fish as the default shell.

% ==============================================================================
\section{Window Management (dwm)}
% ==============================================================================

dwm is a dynamic window manager. Windows are organized into tags (workspaces) and can be arranged in tiled, monocle, or floating layouts.

\subsection{Essential}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Mod+Return} & Spawn terminal (st) / promote to master \\
\texttt{Mod+Shift+Return} & Spawn additional terminal \\
\texttt{Mod+d} & App launcher (dlaunch) \\
\texttt{Mod+q} & Kill focused window \\
\texttt{Mod+j/k} & Focus next/previous window \\
\texttt{Mod+h/l} & Decrease/increase master area size \\
\texttt{Mod+Tab} & Switch to last viewed tag \\
\texttt{Mod+1-9} & View tag 1-9 \\
\texttt{Mod+Shift+1-9} & Move window to tag 1-9 \\
\texttt{Mod+0} & View all tags \\
\texttt{Mod+Shift+0} & Tag window to all tags \\
\bottomrule
\end{longtable}

\subsection{Window Management}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Mod+Shift+j/k} & Move window down/up in stack \\
\texttt{Mod+Shift+Space} & Toggle floating \\
\texttt{Mod+Shift+s} & Toggle sticky \\
\texttt{Mod+i} & Increase number of masters \\
\texttt{Mod+Shift+h/l} & Increase/decrease window size (cfact) \\
\texttt{Mod+Shift+o} & Reset cfact \\
\bottomrule
\end{longtable}

\subsection{Layouts}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Mod+t} & Tile layout \\
\texttt{Mod+f} & Floating layout \\
\texttt{Mod+Shift+r} & Reading mode (equal-width vertical columns) \\
\texttt{Mod+Space} & Toggle last layout \\
\texttt{Mod+Ctrl+,} & Cycle layouts prev \\
\texttt{Mod+Ctrl+.} & Cycle layouts next \\
\bottomrule
\end{longtable}

Available layouts via cycle: tile, floating, monocle, bstack, centeredmaster, centeredfloatingmaster, columns, deck, spiral, dwindle, nrowgrid.

\subsection{Tag Navigation}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Mod+Shift+Left/Right} & Move window to prev/next tag \\
\texttt{Mod+Shift+Tab} & Shift view to previous tag \\
\texttt{Mod+Shift+\textbackslash} & Shift view to next tag \\
\bottomrule
\end{longtable}

\subsection{Multi-Monitor}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Mod+,/.} & Focus prev/next monitor \\
\texttt{Mod+Shift+,/.} & Move window to prev/next monitor \\
\bottomrule
\end{longtable}

\subsection{Applications}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Mod+b} & Browser selector (dbrowse) \\
\texttt{Mod+w} & Content writer (dwrite) \\
\texttt{Mod+r} & Library browser (dread) \\
\texttt{Mod+n} & Notes browser (dnotes) \\
\texttt{Mod+e} & Metadata editor (dedit) \\
\texttt{Mod+c} & Content creator (dcreate) \\
\texttt{Mod+p} & Password manager (passmenu) \\
\texttt{Mod+y} & World clock (dtime) \\
\texttt{Mod+m} & Mode selector (dmode) \\
\texttt{Mod+a} & Questions (questions) \\
\texttt{Mod+Shift+c} & Clipboard manager (dclip) \\
\texttt{Mod+Shift+n} & RSS reader (newsboat) \\
\texttt{Mod+Shift+m} & Toggle mute \\
\bottomrule
\end{longtable}

\subsection{Screenshots}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{PrintScreen} & Full screenshot (screenshot) \\
\texttt{Shift+PrintScreen} & Selection screenshot (screenshot select) \\
\texttt{Mod+PrintScreen} & Screen recording (record) \\
\texttt{Mod+Shift+PrintScreen} & Stop recording \\
\bottomrule
\end{longtable}

\subsection{Media Keys}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{XF86 AudioRaise/Lower} & Volume up/down \\
\texttt{XF86 AudioMute} & Toggle mute \\
\texttt{XF86 BrightnessUp/Down} & Screen brightness \\
\bottomrule
\end{longtable}

\subsection{System}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Mod+BackSpace} & System actions menu (sysact) \\
\texttt{Mod+Shift+q} & System actions menu (sysact) \\
\texttt{Mod+Ctrl+Shift+q} & Restart dwm \\
\texttt{Mod+Shift+F5} & Reload Xresources \\
\bottomrule
\end{longtable}

\subsection{Scratchpad}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Mod+`} & Toggle scratchpad terminal \\
\texttt{Mod+Ctrl+`} & Set window as scratchpad \\
\texttt{Mod+Shift+`} & Remove scratchpad \\
\bottomrule
\end{longtable}

\subsection{Mouse Controls}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Action} & \textbf{Result} \\
\midrule
\endhead
\texttt{Mod+Left Click} & Move floating window \\
\texttt{Mod+Right Click} & Resize floating window \\
\texttt{Mod+Middle Click} & Toggle floating \\
Click on tag & Switch to that tag \\
Click on layout icon & Toggle last layout \\
Right click layout icon & Set monocle layout \\
\bottomrule
\end{longtable}

% ==============================================================================
\section{Terminal (st)}
% ==============================================================================

st is a simple terminal. This build includes scrollback, font ligatures, transparency, and URL handling.

\subsection{Clipboard}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Ctrl+Shift+c} & Copy selection \\
\texttt{Ctrl+Shift+v} & Paste \\
\texttt{Right Click} & Paste from clipboard \\
\bottomrule
\end{longtable}

\subsection{Scrollback}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Alt+k} & Scroll up \\
\texttt{Alt+j} & Scroll down \\
\bottomrule
\end{longtable}

\subsection{Font and Zoom}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Alt+,} & Zoom in \\
\texttt{Alt+.} & Zoom out \\
\texttt{Alt+g} & Reset to default size \\
\bottomrule
\end{longtable}

\subsection{Transparency}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Alt+s} & Increase transparency \\
\texttt{Alt+a} & Decrease transparency \\
\texttt{Alt+m} & Reset transparency \\
\bottomrule
\end{longtable}

\subsection{Other}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Mod+Shift+Enter} & Spawn new terminal in current directory \\
\bottomrule
\end{longtable}

% ==============================================================================
\section{Application Launcher (dmenu)}
% ==============================================================================

dmenu is a dynamic menu for X. It reads from stdin and presents matches in a bar at the top (or center) of the screen.

\subsection{Navigation}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Arrow Keys} & Navigate items \\
\texttt{Tab} & Copy selected item to input \\
\texttt{Ctrl+n} / \texttt{Ctrl+p} & Next/previous item \\
\texttt{PageUp} / \texttt{PageDown} & Move by page \\
\texttt{Home} / \texttt{End} & Jump to first/last item \\
\bottomrule
\end{longtable}

\subsection{Editing}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Ctrl+a} & Move cursor to beginning \\
\texttt{Ctrl+e} & Move cursor to end \\
\texttt{Ctrl+u} & Delete to beginning \\
\texttt{Ctrl+k} & Delete to end \\
\texttt{Ctrl+w} & Delete word backwards \\
\texttt{Ctrl+y} & Paste primary selection \\
\texttt{Ctrl+Shift+y} & Paste clipboard \\
\bottomrule
\end{longtable}

\subsection{Confirmation}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Enter} & Confirm selection (execute) \\
\texttt{Ctrl+Enter} & Confirm selection (output only, no exec) \\
\texttt{Shift+Enter} & Confirm input text (ignore selection) \\
\texttt{Escape} & Cancel \\
\bottomrule
\end{longtable}

% ==============================================================================
\section{Web Browser (surf)}
% ==============================================================================

surf is a minimal webkit-based browser. It's designed for focused reading and research, without the distractions of a full browser.

\subsection{Navigation}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Ctrl+g} & Open URL bar (dmenu) \\
\texttt{Ctrl+/} & Search in page \\
\texttt{Ctrl+n} & Find next \\
\texttt{Ctrl+Shift+n} & Find previous \\
\texttt{Ctrl+h} & Go back \\
\texttt{Ctrl+l} & Go forward \\
\texttt{Ctrl+r} & Reload page \\
\texttt{Ctrl+Shift+r} & Force reload (bypass cache) \\
\texttt{Escape} & Stop loading \\
\bottomrule
\end{longtable}

\subsection{Zooming}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{Ctrl++} or \texttt{Ctrl+=} & Zoom in \\
\texttt{Ctrl+-} & Zoom out \\
\texttt{Ctrl+0} & Reset zoom \\
\bottomrule
\end{longtable}

\subsection{Scrolling}

\begin{longtable}{@{}ll@{}}
\toprule
\textbf{Keybinding} & \textbf{Action} \\
\midrule
\endhead
\texttt{j} / \texttt{k} & Scroll down/up \\
\texttt{h} / \texttt{l} & Scroll left/right \\
\texttt{Space} / \texttt{Shift+Space} & Page down/up \\
\texttt{g} / \texttt{G} & Go to top/bottom \\
\bottomrule
\end{longtable}

% ==============================================================================
\section{Colorscheme (pywal)}
% ==============================================================================

LazyKris uses pywal to generate colorschemes from wallpapers. Colors are applied to dwm, st, dmenu, dunst, and zathura.

\subsection{Usage}

\begin{verbatim}
setbg /path/to/wallpaper.png
\end{verbatim}

The \texttt{setbg} script:
\begin{enumerate}[noitemsep]
    \item Sets the wallpaper using xwallpaper
    \item Generates a colorscheme using pywal
    \item Applies colors to Xresources
    \item Signals dwmblocks to update
\end{enumerate}

% ==============================================================================
\section{Git Configuration}
% ==============================================================================

The system supports multiple git identities that auto-switch based on directory.

\subsection{Profiles}

\begin{longtable}{@{}lll@{}}
\toprule
\textbf{Directory} & \textbf{Profile} & \textbf{Use Case} \\
\midrule
\endhead
\texttt{\textasciitilde/dev/personal/} & krisyotam & Personal projects \\
\texttt{\textasciitilde/dev/security/} & khr1st & Pentesting, CTF \\
\texttt{\textasciitilde/dev/work/} & laelyotam & Work projects \\
\bottomrule
\end{longtable}

\subsection{Useful Aliases}

\begin{longtable}{@{}lll@{}}
\toprule
\textbf{Alias} & \textbf{Command} & \textbf{Description} \\
\midrule
\endhead
\texttt{git st} & \texttt{status -sb} & Short status \\
\texttt{git lg} & \texttt{log --oneline --graph --all} & Pretty log \\
\texttt{git sync} & \texttt{pull --rebase \&\& push} & Quick sync \\
\texttt{git undo} & \texttt{reset --soft HEAD\textasciitilde1} & Undo last commit \\
\bottomrule
\end{longtable}

% ==============================================================================
\section{Patches Reference}
% ==============================================================================

\subsection{dwm Patches}

\begin{itemize}[noitemsep]
    \item \textbf{vanitygaps} --- Gaps allowed across all layouts
    \item \textbf{swallow} --- Terminals swallow windows spawned by child processes
    \item \textbf{scratchpad} --- Dropdown terminal accessible via keybind
    \item \textbf{sticky} --- Make windows visible on all tags
    \item \textbf{hide\_vacant\_tags} --- Hide tags with no windows in the bar
    \item \textbf{xresources} --- Read colors and config from Xresources at startup
    \item \textbf{stacker} --- Move windows up/down in the stack
    \item \textbf{shiftview} --- Cycle through tags
    \item \textbf{statuscmd} --- Clickable status bar for dwmblocks
    \item \textbf{pertag} --- Each tag remembers its own layout settings
    \item \textbf{cyclelayout} --- Cycle through layouts with keybind
    \item \textbf{restartsig} --- Restart dwm in place without losing windows
    \item \textbf{true fullscreen} --- Prevents focus shifting in fullscreen mode
\end{itemize}

Multiple layouts included: tile, floating, monocle, bstack, centeredmaster, centeredfloatingmaster, columns (reading mode), deck, spiral, dwindle, nrowgrid.

\subsection{st Patches}

\begin{itemize}[noitemsep]
    \item \textbf{ligatures} --- HarfBuzz ligature support
    \item \textbf{sixel} --- Sixel graphics support (check sixel branch)
    \item \textbf{scrollback} --- Scroll history
    \item \textbf{clipboard} --- Clipboard integration
    \item \textbf{alpha} --- Transparency support with configurable opacity
    \item \textbf{boxdraw} --- Render box-drawing characters without font glyphs
    \item \textbf{patch\_column} --- Doesn't cut text while resizing
    \item \textbf{font2} --- Secondary font support (emoji fallback)
    \item \textbf{right click paste} --- Paste with right click
    \item \textbf{newterm} --- Spawn new terminal in current directory
    \item \textbf{anygeometry} --- Dynamic geometry/borders
    \item \textbf{xresources} --- Live reload colors/settings from Xresources
    \item \textbf{sync} --- Better draw timing to reduce flicker/tearing
    \item \textbf{live reload} --- Change colors/fonts on the fly
    \item \textbf{swapmouse} --- Swap mouse buttons
\end{itemize}

\subsection{dmenu Patches}

\begin{itemize}[noitemsep]
    \item \textbf{xresources} --- Read colors and settings from Xresources (pywal compatible)
    \item \textbf{alpha} --- Transparency support, can be embedded in transparent st
    \item \textbf{password} --- Hide input for password entry (\texttt{-P} flag)
    \item \textbf{mouse support} --- Click to select options
\end{itemize}

Additional features:
\begin{itemize}[noitemsep]
    \item \textbf{Emoji support} --- Can view color characters like emoji
    \item \textbf{Reject non-matching} --- \texttt{-r} flag rejects input that doesn't match an option
\end{itemize}

% ==============================================================================
\section{FAQ}
% ==============================================================================

\textbf{Q: How do I change the default font?}

Edit \texttt{\textasciitilde/.config/x11/xresources} and set \texttt{st.font} or \texttt{dmenu.font}. Then run:
\begin{verbatim}
xrdb -merge ~/.config/x11/xresources
\end{verbatim}
Restart the application for changes to take effect.

\textbf{Q: How do I add a keybinding to dwm?}

Edit \texttt{\textasciitilde/.local/src/dwm/config.h}, add your binding to the \texttt{keys[]} array, then rebuild:
\begin{verbatim}
cd ~/.local/src/dwm
sudo make clean install
\end{verbatim}
Restart dwm with \texttt{Mod+Ctrl+Shift+q}.

\textbf{Q: How do I change the colorscheme?}

Run \texttt{setbg} with a new wallpaper. Colors are extracted from the image:
\begin{verbatim}
setbg /path/to/wallpaper.png
\end{verbatim}

\textbf{Q: Why fish instead of bash or zsh?}

Fish provides syntax highlighting, autosuggestions, and completions out of the box without configuration. It's faster to set up and more user-friendly.

\textbf{Q: How do I update the suckless builds?}

Pull changes from GitHub and rebuild:
\begin{verbatim}
cd ~/.local/src/dwm
git pull
sudo make clean install
\end{verbatim}

\textbf{Q: How do I add a new package to the system?}

For official packages: \texttt{sudo pacman -S package}

For AUR packages: \texttt{yay -S package}

To make it part of your LazyKris config, add it to \texttt{progs.csv}.

\textbf{Q: How do I configure email?}

Use mutt-wizard to set up neomutt:
\begin{verbatim}
mw -a your@email.com
\end{verbatim}
Follow the prompts to configure your email provider.

\textbf{Q: How do I mount external drives?}

Press \texttt{Mod+F9} to open the mount menu. Select the drive to mount. Use \texttt{Mod+F10} to unmount.

% ==============================================================================
\section{Credits}
% ==============================================================================

LazyKris is inspired by \href{https://larbs.xyz}{LARBS} (Luke's Auto-Rice Bootstrapping Scripts) by Luke Smith.

The suckless software (dwm, st, dmenu, surf) is developed by \href{https://suckless.org}{suckless.org}.

% ==============================================================================
\section{License}
% ==============================================================================

This project is licensed under the GPL-3.0 License.

Source code: \url{https://github.com/krisyotam/lazykris}

\end{document}

A  => ksd-arch/notes.csv +9 -0
@@ 1,9 @@
#REPO_URL,TARGET_DIR,DESCRIPTION
#
# Notes repositories to clone into ~/notes/
# FORMAT: github_url,subdirectory_name,description
#
# The repos will be cloned into ~/notes/<subdirectory_name>
# If subdirectory_name is empty or ".", it clones directly into ~/notes/
#
https://github.com/krisyotam/slipbox,.,main zettelkasten and org-roam notes

A  => ksd-arch/post-install.sh +191 -0
@@ 1,191 @@
#!/bin/sh

# ============================================================================
# LazyKris Post-Install Script
# ============================================================================
#
# This script installs optional large packages that take a long time.
# Run this AFTER the main lazykris.sh installation completes.
#
# Usage:
#   ./post-install.sh [option]
#
# Options:
#   all       - Install everything
#   texlive   - Install full LaTeX suite
#   davinci   - Install DaVinci Resolve
#   help      - Show this help
#
# ============================================================================

set -e

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

info() { printf "${BLUE}==>${NC} %s\n" "$1"; }
success() { printf "${GREEN}==>${NC} %s\n" "$1"; }
warn() { printf "${YELLOW}==>${NC} %s\n" "$1"; }
error() { printf "${RED}Error:${NC} %s\n" "$1" >&2; exit 1; }

# Check if running as regular user (not root)
check_user() {
    if [ "$(id -u)" = "0" ]; then
        error "Run this script as your regular user, not root."
    fi
}

# Check for yay
check_aur_helper() {
    if ! command -v yay >/dev/null 2>&1; then
        error "yay is not installed. Run lazykris.sh first."
    fi
}

# ============================================================================
# TEXLIVE - Full LaTeX Suite (~2-3GB)
# ============================================================================

install_texlive() {
    info "Installing TeX Live (full LaTeX suite)..."
    warn "This will download ~2-3GB of packages."
    echo ""
    read -p "Continue? [y/N] " response
    case "$response" in
        [yY][eE][sS]|[yY])
            ;;
        *)
            warn "Skipping TeX Live installation."
            return 0
            ;;
    esac

    info "Installing TeX Live packages..."

    # Core packages
    sudo pacman -S --noconfirm --needed \
        texlive-basic \
        texlive-latex \
        texlive-latexrecommended \
        texlive-latexextra \
        texlive-fontsrecommended \
        texlive-fontsextra \
        texlive-fontutils \
        texlive-bibtexextra \
        texlive-binextra \
        texlive-mathscience \
        texlive-pictures \
        texlive-xetex \
        texlive-luatex \
        texlive-plaingeneric

    # Optional packages (uncomment if needed)
    # sudo pacman -S --noconfirm --needed \
    #     texlive-context \
    #     texlive-formatsextra \
    #     texlive-games \
    #     texlive-humanities \
    #     texlive-metapost \
    #     texlive-music \
    #     texlive-pstricks \
    #     texlive-publishers

    success "TeX Live installation complete!"
    echo ""
    echo "Test with: pdflatex --version"
    echo "Compile a document: pdflatex document.tex"
}

# ============================================================================
# DAVINCI RESOLVE - Professional Video Editor (~3GB)
# ============================================================================

install_davinci() {
    info "Installing DaVinci Resolve..."
    warn "This will download ~3GB and may take 30+ minutes."
    echo ""
    echo "Note: DaVinci Resolve requires:"
    echo "  - NVIDIA GPU with proprietary drivers, OR"
    echo "  - AMD GPU with ROCm support"
    echo ""
    read -p "Continue? [y/N] " response
    case "$response" in
        [yY][eE][sS]|[yY])
            ;;
        *)
            warn "Skipping DaVinci Resolve installation."
            return 0
            ;;
    esac

    info "Installing DaVinci Resolve from AUR..."
    yay -S --noconfirm davinci-resolve

    success "DaVinci Resolve installation complete!"
    echo ""
    echo "Launch with: davinci-resolve"
    echo ""
    echo "If you have issues, you may need to install GPU drivers:"
    echo "  NVIDIA: sudo pacman -S nvidia nvidia-utils"
    echo "  AMD:    yay -S rocm-opencl-runtime"
}

# ============================================================================
# HELP
# ============================================================================

show_help() {
    echo "LazyKris Post-Install Script"
    echo ""
    echo "Usage: $0 [option]"
    echo ""
    echo "Options:"
    echo "  all       Install everything (texlive + davinci)"
    echo "  texlive   Install full TeX Live suite (~2-3GB)"
    echo "  davinci   Install DaVinci Resolve (~3GB)"
    echo "  help      Show this help message"
    echo ""
    echo "Examples:"
    echo "  $0 texlive    # Install just LaTeX"
    echo "  $0 all        # Install everything"
    echo ""
}

# ============================================================================
# MAIN
# ============================================================================

main() {
    check_user
    check_aur_helper

    case "${1:-help}" in
        all)
            install_texlive
            echo ""
            install_davinci
            echo ""
            success "All post-install packages complete!"
            ;;
        texlive|tex|latex)
            install_texlive
            ;;
        davinci|resolve)
            install_davinci
            ;;
        help|-h|--help)
            show_help
            ;;
        *)
            error "Unknown option: $1"
            show_help
            exit 1
            ;;
    esac
}

main "$@"

A  => ksd-arch/progs.csv +269 -0
@@ 1,269 @@
#TAG,PACKAGE,DESCRIPTION
#
# Legend:
# (empty) = pacman (official repos)
# A = AUR (via yay)
# G = Git clone + make install
# F = Flatpak
# I = AppImage (download URL)
# B = BlackArch (requires strap.sh first)
#
# Basic Programs
A,lf,"terminal file browser/manager"
,btop,"task manager and system monitor"
,neomutt,"terminal email client"
A,mutt-wizard-git,"email setup wizard for neomutt"
A,abook,"address book for neomutt"
,ncmpcpp,"ncurses music player for mpd"
,networkmanager,"provides nmtui for wifi management"
,bluez,"Bluetooth protocol stack"
,bluez-utils,"Bluetooth utilities (bluetoothctl)"
,blueman,"Bluetooth manager GUI (blueman-manager)"
,newsboat,"terminal RSS feed reader"
,pulsemixer,"terminal audio control"
A,mouseless-bin,"keyboard-driven mouse control"
,tmux,"terminal multiplexer"
,emacs,"extensible text editor"
,nsxiv,"minimalist image viewer"
,calcurse,"terminal calendar and organizer"
A,sc-im,"terminal spreadsheet (Excel-like)"
#
# System/X11
,xorg-server,"graphical server"
,xorg-xinit,"starts graphical server"
,xorg-xwininfo,"window info queries"
,xorg-xset,"X server config utility"
,xorg-xprop,"window properties tool"
,xorg-xbacklight,"screen brightness control"
,polkit,"user policy management"
,xcompmgr,"compositor for transparency"
,webkit2gtk,"web rendering engine for surf"
,gcr,"crypto UI library for surf"
,xwallpaper,"wallpaper setter"
,xclip,"clipboard from command line"
,xdotool,"window automation tool"
,xcape,"key remapping (capslock to escape)"
,unclutter,"hides inactive mouse cursor"
,slock,"simple screen locker"
,arandr,"monitor arrangement GUI"
#
# Suckless Builds
G,https://github.com/krisyotam/dwm,"tiling window manager"
G,https://github.com/krisyotam/dwmblocks,"modular status bar"
G,https://github.com/krisyotam/dmenu,"application launcher"
G,https://github.com/krisyotam/st,"terminal emulator"
G,https://github.com/krisyotam/scron,"simple cron daemon"
G,https://github.com/krisyotam/quark,"tiny HTTP server"
G,https://github.com/krisyotam/surf,"minimal webkit browser for deep work"
#
# Fonts - System
,noto-fonts,"comprehensive Unicode coverage"
,noto-fonts-cjk,"Chinese Japanese Korean support"
,noto-fonts-emoji,"emoji font"
,ttf-liberation,"metric-compatible Arial Times Courier"
,ttf-dejavu,"excellent Unicode coverage"
,ttf-roboto,"Google Roboto font"
A,ttf-opensans,"Open Sans font"
,ttf-ubuntu-font-family,"Ubuntu fonts"
,ttf-droid,"Droid fonts"
,inter-font,"modern UI font"
,adobe-source-sans-fonts,"Adobe Source Sans"
,adobe-source-serif-fonts,"Adobe Source Serif"
,adobe-source-code-pro-fonts,"Adobe Source Code Pro"
A,ttf-cascadia-code,"Microsoft Cascadia Code"
,otf-libertinus,"Libertinus serif and sans"
,ttf-font-awesome,"icons and glyphs"
#
# Fonts - Monospace/Coding
,ttf-fira-code,"coding font with ligatures"
,ttf-hack,"Hack monospace font"
,ttf-inconsolata,"Inconsolata font"
A,ttf-iosevka-bin,"Iosevka font (prebuilt)"
,ttf-jetbrains-mono,"JetBrains Mono font"
#
# Fonts - Nerd Fonts
,ttf-jetbrains-mono-nerd,"JetBrains Mono with Nerd icons"
,ttf-firacode-nerd,"Fira Code with Nerd icons"
,ttf-hack-nerd,"Hack with Nerd icons"
,ttf-meslo-nerd,"Meslo with Nerd icons"
,ttf-sourcecodepro-nerd,"Source Code Pro with Nerd icons"
A,ttf-iosevka-nerd-bin,"Iosevka with Nerd icons (prebuilt)"
,ttf-cascadia-code-nerd,"Cascadia Code with Nerd icons"
A,ttf-ubuntu-nerd,"Ubuntu Mono with Nerd icons"
A,ttf-roboto-mono-nerd,"Roboto Mono with Nerd icons"
,ttf-nerd-fonts-symbols,"standalone Nerd symbols"
#
# Font Management
,fontconfig,"font configuration"
A,fontpreview-ueberzug,"terminal font previewer"
#
# Theming
,gnome-keyring,"system keyring"
A,gtk-theme-arc-gruvbox-git,"dark GTK theme"
,python-qdarkstyle,"dark Qt theme"
,libnotify,"desktop notifications library"
,dunst,"notification daemon"
#
# Audio/Video
,mpd,"music player daemon"
,mpc,"mpd terminal interface"
,mpv,"video player"
,ffmpeg,"video and audio processing"
,ffmpegthumbnailer,"video thumbnails"
,pipewire,"audio server"
,wireplumber,"audio session manager"
,pipewire-pulse,"PulseAudio compatibility"
,alsa-utils,"ALSA utilities including amixer"
#
# Filesystem
,dosfstools,"DOS filesystem tools"
,exfatprogs,"exFAT filesystem tools"
,ntfs-3g,"NTFS partition access"
A,simple-mtpfs,"phone and MTP mounting"
#
# Utilities
,bc,"calculator language"
,man-db,"man pages database"
,maim,"screenshot tool"
,unzip,"archive extraction"
,atool,"archive management"
,poppler,"PDF utilities"
,mediainfo,"media file info"
A,task-spooler,"command queue"
,socat,"data transfer utility"
,moreutils,"unix utilities collection"
,tesseract,"OCR engine"
,tesseract-data-eng,"English OCR data"
,ueberzugpp,"terminal image previews"
,fzf,"fuzzy finder"
,fd,"fast find replacement"
,ripgrep,"fast grep replacement"
,jq,"JSON processor"
,wget,"file downloader"
,rsync,"file sync"
,rclone,"cloud storage sync"
,fastfetch,"system info display"
,lynx,"terminal browser"
,eza,"modern ls replacement"
,zoxide,"smarter cd command"
,dust,"disk usage analyzer"
A,dysk,"disk usage viewer for statusbar"
,lm_sensors,"hardware sensors for temperature"
,sysstat,"system stats including iostat"
,playerctl,"media player controller for statusbar"
,upower,"battery and power device info"
,acpi,"battery status utility"
#
# IDEs/Editors
,neovim,"modern vim"
,zed,"AI-powered IDE"
A,claude-code-bin,"Anthropic AI CLI"
#
# Terminals
A,warp-terminal,"AI terminal"
#
# Browsers
A,librewolf-bin,"privacy-focused browser"
A,librewolf-extension-localcdn-bin,"CDN emulation extension"
A,librewolf-extension-istilldontcareaboutcookies-bin,"cookie banner remover"
A,librewolf-extension-tridactyl-bin,"vim bindings extension"
A,librewolf-extension-ublock-origin-bin,"ad blocker extension"
A,arkenfox-user.js,"browser hardening config"
,torbrowser-launcher,"Tor browser"
A,mullvad-browser-bin,"Mullvad privacy browser"
#
# Writing Software (Flatpak)
I,https://github.com/vkbo/novelWriter/releases/download/v2.8.2/novelwriter-2.8.2-x86_64.AppImage,"novel writing software"
F,com.notesnook.Notesnook,"encrypted note-taking"
#
# LaTeX - use post-install.sh for full texlive suite
#
# Tools
,git,"version control"
,github-cli,"GitHub CLI"
,openssh,"SSH client and server"
,mosh,"mobile shell with auto-reconnect"
,sshfs,"mount remote filesystems via SSH"
,docker,"containerization"
,docker-compose,"multi-container Docker"
A,lazygit,"terminal UI for git"
A,lazydocker,"terminal UI for docker"
,git-delta,"better git diff viewer"
A,aws-cli-v2,"AWS command line"
A,flarectl,"Cloudflare CLI"
,curl,"data transfer tool"
,httpie,"user-friendly HTTP client"
,zathura,"PDF viewer with vim bindings"
,zathura-pdf-mupdf,"mupdf backend for zathura"
,yt-dlp,"YouTube downloader"
#
# Media/Anime
A,ani-cli,"anime streaming CLI"
A,manga-tui,"terminal manga reader with image support"
A,hakuneko-desktop,"manga and anime downloader"
I,https://api.hayase.watch/files/linux-hayase-6.4.50-linux.AppImage,"anime streaming app"
#
# Misc Programs
A,speedtest-cli,"internet speed test"
A,wikiman,"offline wiki and man pages"
A,gphoto2,"DSLR camera control"
A,v4l2loopback-dkms,"virtual webcam for DSLR"
,bat,"cat with syntax highlighting"
A,python-pywal,"colorscheme generator"
#
# VPNs
A,mullvad-vpn-bin,"Mullvad VPN client"
,openvpn,"OpenVPN client"
#
# Security
A,protonmail-bridge,"Proton Mail bridge for email clients"
A,proton-pass,"Proton Authenticator"
,proxychains-ng,"proxy chaining"
,gnupg,"GPG encryption"
,pass,"password manager using GPG"
,sqlcipher,"encrypted SQLite"
A,clipnotify,"clipboard change notifications"
#
# Video/Graphics
,obs-studio,"screen recording and streaming"
#A,davinci-resolve,"video editor - use post-install.sh"
,gimp,"image editor"
,inkscape,"vector graphics editor"
F,org.kde.SymbolEditor,"symbol and icon editor"
,imagemagick,"image manipulation CLI"
,perl-image-exiftool,"read/write EXIF metadata"
,flameshot,"screenshot with annotation"
#
# Social
F,com.discordapp.Discord,"Discord client"
,element-desktop,"Matrix client"
A,catgirl,"terminal IRC client"
#
# Torrent
,rtorrent,"terminal torrent client"
,transmission-cli,"transmission daemon and CLI tools"
#
# Shell
,fish,"friendly interactive shell"
,starship,"cross-shell prompt"
,direnv,"per-directory environment"
,gum,"fluid terminal UI toolkit"
#
# Compilers/Languages
,gcc,"C and C++ compiler"
,clang,"LLVM C and C++ compiler"
,dotnet-sdk,".NET SDK"
,rustup,"Rust toolchain installer"
,python,"Python interpreter"
,python-pip,"Python package manager"
,jdk-openjdk,"Java JDK"
,scala,"Scala language"
,sbt,"Scala build tool"
,ghc,"Haskell compiler"
,cabal-install,"Haskell package manager"
,nodejs,"JavaScript runtime"
,npm,"Node package manager"
,go,"Go language"
,inetutils,"network utilities including hostname command"
A,cmatrix-git,"matrix terminal animation with transparency"
,conky,"System monitor for X and Wayland with Lua scripting"

A  => ksd-gentoo/deploy.sh +4 -0
@@ 1,4 @@
#!/bin/bash
# KSD - Kris's Simple Deploy for Gentoo
echo "Not yet implemented"
exit 1

A  => ksd-gentoo/manual.tex +26 -0
@@ 1,26 @@
\documentclass[12pt]{article}
\usepackage[margin=1in]{geometry}
\usepackage{hyperref}

\title{KSD Gentoo Manual}
\author{Kris Yotam}
\date{\today}

\begin{document}
\maketitle
\tableofcontents

\section{Introduction}
This manual covers the KSD (Kris's Simple Deploy) script for Gentoo Linux.

\section{Prerequisites}
\begin{itemize}
    \item A fresh Gentoo installation
    \item Internet connection
    \item Root or sudo access
\end{itemize}

\section{Usage}
TBD.

\end{document}

A  => ksd-kali/deploy.sh +4 -0
@@ 1,4 @@
#!/bin/bash
# KSD - Kris's Simple Deploy for Kali Linux
echo "Not yet implemented"
exit 1

A  => ksd-kali/manual.tex +26 -0
@@ 1,26 @@
\documentclass[12pt]{article}
\usepackage[margin=1in]{geometry}
\usepackage{hyperref}

\title{KSD Kali Linux Manual}
\author{Kris Yotam}
\date{\today}

\begin{document}
\maketitle
\tableofcontents

\section{Introduction}
This manual covers the KSD (Kris's Simple Deploy) script for Kali Linux.

\section{Prerequisites}
\begin{itemize}
    \item A fresh Kali Linux installation
    \item Internet connection
    \item Root or sudo access
\end{itemize}

\section{Usage}
TBD.

\end{document}

A  => ksd-macos/deploy.sh +4 -0
@@ 1,4 @@
#!/bin/bash
# KSD - Kris's Simple Deploy for macOS
echo "Not yet implemented"
exit 1

A  => ksd-macos/manual.tex +26 -0
@@ 1,26 @@
\documentclass[12pt]{article}
\usepackage[margin=1in]{geometry}
\usepackage{hyperref}

\title{KSD macOS Manual}
\author{Kris Yotam}
\date{\today}

\begin{document}
\maketitle
\tableofcontents

\section{Introduction}
This manual covers the KSD (Kris's Simple Deploy) script for macOS.

\section{Prerequisites}
\begin{itemize}
    \item A fresh macOS installation
    \item Internet connection
    \item Administrator access
\end{itemize}

\section{Usage}
TBD.

\end{document}

A  => ksd-ubuntu/deploy.sh +4 -0
@@ 1,4 @@
#!/bin/bash
# KSD - Kris's Simple Deploy for Ubuntu
echo "Not yet implemented"
exit 1

A  => ksd-ubuntu/manual.tex +26 -0
@@ 1,26 @@
\documentclass[12pt]{article}
\usepackage[margin=1in]{geometry}
\usepackage{hyperref}

\title{KSD Ubuntu Manual}
\author{Kris Yotam}
\date{\today}

\begin{document}
\maketitle
\tableofcontents

\section{Introduction}
This manual covers the KSD (Kris's Simple Deploy) script for Ubuntu.

\section{Prerequisites}
\begin{itemize}
    \item A fresh Ubuntu installation
    \item Internet connection
    \item Root or sudo access
\end{itemize}

\section{Usage}
TBD.

\end{document}

A  => ksd-win11/deploy.sh +4 -0
@@ 1,4 @@
#!/bin/bash
# KSD - Kris's Simple Deploy for Windows 11
echo "Not yet implemented"
exit 1

A  => ksd-win11/manual.tex +27 -0
@@ 1,27 @@
\documentclass[12pt]{article}
\usepackage[margin=1in]{geometry}
\usepackage{hyperref}

\title{KSD Windows 11 Manual}
\author{Kris Yotam}
\date{\today}

\begin{document}
\maketitle
\tableofcontents

\section{Introduction}
This manual covers the KSD (Kris's Simple Deploy) script for Windows 11 with WSL.

\section{Prerequisites}
\begin{itemize}
    \item A fresh Windows 11 installation
    \item WSL enabled
    \item Internet connection
    \item Administrator access
\end{itemize}

\section{Usage}
TBD.

\end{document}