diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..8bb80d5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+bootstrapper.log
diff --git a/TODO.md b/TODO.md
index 6a7b911..bb22372 100644
--- a/TODO.md
+++ b/TODO.md
@@ -7,3 +7,5 @@
 ## Alternatives
 
 - [ ] `xbps-alternatives pinentry -s pinentry-gnome`
+- [ ] `xdg-mime default firefox.desktop x-scheme-handler/http x-scheme-handler/https text/html`
+- [ ] `env -u BROWSER xdg-settings set default-web-browser firefox.desktop`
diff --git a/bootstrap.sh b/bootstrap.sh
index c21a8c8..545d7d2 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -7,6 +7,7 @@ DOTS_BRANCH="main"
 STOW_DIR=".local/share/stow"
 DOTS_PACKAGE="dots"
 CONFIG_FILE="./config.yml"
+LOG_FILE="bootstrap.log"
 
 USER_GROUPS="wheel,floppy,audio,video,cdrom,optical,kvm,xbuilder,users,docker" # Comma separated list
 SCRIPT_DIR="$(dirname "$(readlink -f "$0")")"
@@ -20,6 +21,7 @@ RESET="$(tput sgr0)"
 
 error() {
     printf "%b\n" "${RED}${BOLD}${1}${RESET}" >&2
+    echo "$1" >>"$LOG_FILE"
     exit 1
 }
 
@@ -33,30 +35,36 @@ prompt() {
 }
 
 emphasize() {
-    printf "%b\n" "${GREEN}${BOLD}${1}${RESET}"
+    message=$1
+    printf "%-$(tput cols)b\n" "${GREEN}${BOLD}${message}${RESET}"
+    echo "$1" >>"$LOG_FILE"
 }
 
 info() {
-    printf "%b\n" "${1}"
+    message=$1
+    printf "%-$(tput cols)b\n" "${message}"
+    echo "$1" >>"$LOG_FILE"
 }
 
 warn() {
-    printf "%b\n" "${YELLOW}${BOLD}${1}${RESET}"
+    message=$1
+    printf "%-$(tput cols)b\n" "${YELLOW}${BOLD}${message}${RESET}"
+    echo "$1" >>"$LOG_FILE"
 }
 
 print_buffer() {
     buffer_size=$1
-    line_length=$2
+    trim=${2:-y} # 'y' | 'n'
+    line_length=$(tput cols)
+
     for i in $(seq 1 "$((buffer_size))"); do
-        # shellcheck disable=SC2016
         if [ "$trim" = "y" ]; then
-            template='%-${line_length}s\n'
+            template="%-${line_length}s\n"
         else
-            template='%-${line_length}.${line_length}s\n'
+            template="%-${line_length}.${line_length}s\n"
         fi
-        # shellcheck disable=SC2086
         eval '[ -z "${buffer'"$i"':-}" ] || {
-            printf "'"$template"'" "${buffer'$i'}"
+            printf "'"$template"'" "${buffer'"$i"'}"
         }'
     done
 }
@@ -74,24 +82,25 @@ push_buffer() {
 scroll() {
     buffer_size=$1 # int
     trim=${2:-y}   # 'y' | 'n'
-    line_length=$(tput cols)
-    trap 'line_length=$(tput cols)' WINCH
 
     tput civis
     while read -r line; do
         push_buffer "$line" "$buffer_size"
+        echo "$line" >>"$LOG_FILE"
 
         tput sc
-        print_buffer "$buffer_size" "$line_length"
+        print_buffer "$buffer_size" "$trim"
         tput rc
     done
     tput cnorm
 
+    tput sc
     for i in $(seq 1 $((buffer_size))); do
+        printf "%-$(tput cols)s" ""
         eval "unset buffer$i"
     done
-    print_buffer "$buffer_size" "$line_length"
-    trap - WINCH
+    tput rc
+    print_buffer "$buffer_size" "$trim"
 }
 
 check_root() {
@@ -121,15 +130,24 @@ setup() {
 install_packages() {
     IFS='
 '
+    set +e
     for p in $(yq -c '.packages.[]' <config.yml); do
         flags=$(echo "$p" | yq -r '.command[1:].[]')
         packages=$(echo "$p" | yq -r '.list[]')
-        # shellcheck disable=SC2086
-        [ -n "${packages}" ] && echo $flags $packages |
-            xargs "$(echo "$p" | yq -r '.command[0]')"
-    done | scroll 7
+        # shellcheck disable=SC2086,2015
+        case $(echo "$p" | yq -r '.local') in
+            true) [ -n "${packages}" ] && echo "$flags" "$packages" | sudo -i -u "$username" xargs "$(echo "$p" | yq -r '.command[0]')" || touch /tmp/bootstrapper-failed ;;
+            false) [ -n "${packages}" ] && echo "$flags" "$packages" | xargs "$(echo "$p" | yq -r '.command[0]')" || touch /tmp/bootstrapper-failed ;;
+        esac
+    done 2>&1 | scroll 7
+    set -e
 
-    info "Done!"
+    if [ -f /tmp/bootstrapper-failed ]; then
+        warn "Failures during package installation, check logs."
+        rm /tmp/bootstrapper-failed
+    else
+        info "Done!"
+    fi
 }
 
 install_files() {
@@ -176,7 +194,7 @@ create_user() {
 
 create_directories() {
     #shellcheck disable=SC2016
-    directories=$(yq -c '[].directories' <${CONFIG_FILE})
+    directories=$(yq -c '.directories.[]' <${CONFIG_FILE})
     counter=1
     num_dirs=$(echo "$directories" | wc -l)
 
@@ -189,7 +207,7 @@ create_directories() {
         [ -d "${user_home}/${path}" ] || sudo -u "$username" mkdir -m "${mode}" -p "${user_home}/${path}"
 
         counter=$((counter + 1))
-    done
+    done 2>&1 | scroll 7
 
     info "Done!"
 }
@@ -231,7 +249,7 @@ enable_services() {
     for service in $services; do
         info "Enabling service ${counter} of ${num_services}: ${service}"
         [ ! -L "/var/service/${service}" ] && ln -s "/etc/sv/${service}" "/var/service/"
-    done
+    done 2>&1 | scroll 7
 
     info "Done!"
 }
@@ -240,7 +258,7 @@ finalize() {
     gid=$(getent passwd "$username" | cut -d ':' -f 4)
     groupname=$(getent group "$gid" | cut -d ':' -f 1)
     info "Setting ownership of home directories..."
-    chown -v "$username:$groupname" -R "$user_home" 2>&1 | scroll 7
+    chown "$username:$groupname" -R "$user_home"
     info "Done!"
 }
 
@@ -248,6 +266,8 @@ finalize() {
 
 trap 'tput cnorm; tput sgr0; exit' INT TERM EXIT
 
+echo >"$LOG_FILE"
+
 check_root
 
 emphasize "-- Copying Files --"
@@ -259,9 +279,6 @@ install_files
 emphasize "-- Preparing Installation --"
 setup
 
-emphasize "-- Installing Packages --"
-install_packages
-
 username="$SUDO_USER"
 if [ -z "$username" ]; then
     emphasize "-- Creating User Account --"
@@ -270,13 +287,16 @@ else
     user_home=$(getent passwd "$username" | cut -d ':' -f 6)
 fi
 
-emphasize "-- Creating Standard Home Directories --"
-create_directories
-
 emphasize "-- Installing Dotfiles --"
 install_dotfiles
 select_keymap
 
+emphasize "-- Creating Standard Home Directories --"
+create_directories
+
+emphasize "-- Installing Packages --"
+install_packages
+
 emphasize "-- Enabling Services --"
 enable_services
 
diff --git a/config.yml b/config.yml
index b9a8ca7..f4b2541 100644
--- a/config.yml
+++ b/config.yml
@@ -35,11 +35,9 @@ directories:
 
 packages:
   - command: ["xbps-install", "-y"]
+    local: False
     list:
       - 7zip
-      - ImageMagick
-      - NetworkManager
-      - Signal-Desktop
       - ansible
       - apache-htpasswd
       - arandr
@@ -50,8 +48,6 @@ packages:
       - bat
       - bind-utils
       - binutils
-      - blueman
-      - bluez
       - bottom
       - breeze-icons
       - cargo
@@ -93,6 +89,7 @@ packages:
       - gnupg2-scdaemon
       - gpgme
       - htop
+      - ImageMagick
       - jq
       - just
       - k9s
@@ -115,6 +112,8 @@ packages:
       - ncpamixer
       - neofetch
       - neovim
+      - NetworkManager
+      - ngetty
       - nmap
       - noto-fonts-cjk
       - noto-fonts-emoji
@@ -147,7 +146,8 @@ packages:
       - ripgrep
       - rlwrap
       - rsync
-      - ruby-asciidoctor
+      - ruby
+      - ruby-devel
       - rust
       - rust-analyzer
       - rust-src
@@ -155,6 +155,7 @@ packages:
       - seahorse
       - shellcheck
       - shfmt
+      - Signal-Desktop
       - simple-mtpfs
       - smbclient
       - socat
@@ -209,25 +210,31 @@ packages:
       - zsh-autosuggestions
       - zsh-completions
       - zsh-syntax-highlighting
-  - command: ["pnpm", "install", "-g"]
+  - command: ["pnpm", "add", "-g"]
+    pre: ["pnpm setup"]
+    local: True
     list:
       - "neovim"
   - command: ["cargo", "install", "-j", "-2"]
+    local: True
     list:
       - "oatmeal"
       - "gpg-tui"
   - command: ["composer", "global", "require"]
+    local: True
     list: []
   - command: ["gem", "install"]
+    local: False
     list:
       - asciidoctor
       - asciidoctor-pdf
-      - asciidoctor
       - asciidoctor-diagram
       - pygments.rb
       - neovim
   - command: ["cpanm"]
+    local: False
     list:
       - Neovim::Ext
   - command: ["pipx", "--global", "install"]
+    local: False
     list: []