diff --git a/.envrc b/.envrc
index 1d953f4..4857c1e 100644
--- a/.envrc
+++ b/.envrc
@@ -1 +1,3 @@
 use nix
+
+export BASHLY_SOURCE_DIR=$(cat .target)
diff --git a/.forgejo/workflows/release.yaml b/.forgejo/workflows/release.yaml
index a5297ea..a574329 100644
--- a/.forgejo/workflows/release.yaml
+++ b/.forgejo/workflows/release.yaml
@@ -3,30 +3,45 @@ on:
     tags:
       - v**
 jobs:
-  release:
+  build-artifacts:
     runs-on: docker
+    strategy:
+      matrix:
+        tool:
+          - autoinstall
+          - autostart-manage
     steps:
       - uses: https://code.forgejo.org/actions/checkout@v3
       - id: install-dependencies
         run: |
           apt update
-          # TODO add pandoc for docs
           apt install -y make ruby
           gem install bashly
         shell: bash
       - id: run-bashly
         run: |
+          echo "${{ matrix.tool }}" > .target
           make generate
-          #make docs
         shell: bash
-      - id: prepare-release
+      - uses: https://code.forgejo.org/actions/upload-artifact@v3
+        with:
+          name: ${{ matrix.tool }}
+          path: ${{ github.workspace }}/output/${{ matrix.tool }}
+  upload-release:
+    runs-on: docker
+    steps:
+      - uses: https://code.forgejo.org/actions/checkout@v3
+      - uses: https://code.forgejo.org/actions/download-artifact@v3
+        with:
+          path: /tmp/artifacts-in
+          merge-multiple: true # broken "collect-artifacts" used as workaround
+      - id: collect-artifacts
         run: |
-          mkdir /tmp/release
-          cp ./autostart-manage /tmp/release
-          #cp -r ./man1 /tmp/release
+          mkdir /tmp/artifacts-out
+          mv $(find /tmp/artifacts-in -type f) /tmp/artifacts-out
         shell: bash
       - uses: https://code.forgejo.org/actions/forgejo-release@v1
         with:
           direction: upload
-          release-dir: /tmp/release
+          release-dir: /tmp/artifacts-out
           token: ${{ github.token }}
diff --git a/.gitignore b/.gitignore
index d0fb366..d45b622 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
-src/lib/send_completions.sh
+.target
+output/
 
-autostart-manage
-man1
+autoinstall/lib/send_completions.sh
+autostart-manage/lib/send_completions.sh
diff --git a/Makefile b/Makefile
index 1fc809f..b2a84de 100644
--- a/Makefile
+++ b/Makefile
@@ -1,12 +1,22 @@
-completions:
-	bashly add completions
+target:
+	@echo "Select target directory"
+	@echo $$(find . -name bashly.yml | sed -e 's/.\///' -e 's/\/.*//' | $$DMENU) > .target
 
-generate: completions
-	bashly generate --upgrade
+get-target:
+	$(eval TARGET := $(shell cat .target))
+
+output-dir:
+	mkdir -p ./output
+
+completions: get-target
+	BASHLY_SOURCE_DIR=$(TARGET) bashly add completions
+
+generate: get-target output-dir completions
+	BASHLY_SOURCE_DIR=$(TARGET) bashly generate --upgrade
 
 docs: generate
-	bashly render :mandoc ./man1
+	BASHLY_SOURCE_DIR=$(TARGET) bashly render :mandoc ./output/man1
 
-install: generate docs
-	cp -f ./autostart-manage ~/.local/bin/
-	cp -f ./man1/autostart-manage*.1 ~/.local/share/man/man1/
+deploy: generate docs
+	cp -f ./output/$(TARGET) ~/.local/bin/
+	cp -f ./output/man1/$(TARGET)*.1 ~/.local/share/man/man1/
diff --git a/autoinstall/archive_command.sh b/autoinstall/archive_command.sh
new file mode 100644
index 0000000..6019708
--- /dev/null
+++ b/autoinstall/archive_command.sh
@@ -0,0 +1,18 @@
+#!/usr/bin/env bash
+
+target=${args[target]:?}
+url=${args[url]:?}
+
+if [ ! -f "$target" ]
+then
+	echo "Installing archive $url to $target"
+
+	target_dir=$(dirname "$target")
+	mkdir -p "$target_dir"
+	cd "$target_dir" || exit 1
+
+	_http_client "$url" > "$target"
+	tar xaf "$target"
+
+	_run_hook
+fi
diff --git a/autoinstall/bashly.yml b/autoinstall/bashly.yml
new file mode 100644
index 0000000..3a382ae
--- /dev/null
+++ b/autoinstall/bashly.yml
@@ -0,0 +1,111 @@
+name: autoinstall
+help: Install files, repository and else
+version: 0.1.1
+
+flags:
+  - long: --clean
+    short: -c
+    help: Clean exisiting targets
+  - long: --hook
+    short: -h
+    help: Hook to run if something changed
+    arg: hook
+
+environment_variables:
+  - name: AUTOINSTALL_CLEAN
+    help: Clean exisiting targets
+
+dependencies:
+  http_client:
+    command: [curl, wget]
+    help: Please install either curl or wget
+
+commands:
+  - name: completions
+    help: Generate bash completions
+
+  - name: run
+    help: Autoinstall from file
+    args:
+      - name: group
+        required: true
+        help: The group to install
+
+  - name: git
+    help: Install a git repository
+    args:
+      - name: repo
+        required: true
+        help: The url of the git repository
+      - name: target
+        required: true
+        help: The path to clone the repository into
+
+  - name: file
+    help: Install a file
+    args:
+      - name: url
+        required: true
+        help: The url of the file
+      - name: target
+        required: true
+        help: The file-path to download the file into
+    flags:
+      - long: --pipe
+        short: -p
+        help: Pipe file through command (e.g. "tar xzO")
+        arg: pipe
+        default: cat
+
+  - name: exe
+    help: Install an executable
+    args:
+      - name: url
+        required: true
+        help: The url of the file
+      - name: target
+        required: true
+        help: The file-path to download the file into
+    filename: file_command.sh
+    flags:
+      - long: --pipe
+        short: -f
+        help: Pipe file through command (e.g. "tar xzO")
+        arg: pipe
+        default: cat
+      - long: --completions
+        short: -c
+        help: Run a command on the new exe to install completions
+        arg: completions
+
+  - name: archive
+    help: Install an archive
+    args:
+      - name: url
+        required: true
+        help: The url of the arhive
+      - name: target
+        required: true
+        help: The path to clone the repository into
+
+  - name: env
+    help: Create a file with envsubst
+    args:
+      - name: template
+        required: true
+        help: The path to the template
+      - name: target
+        required: true
+        help: The path to write the result to
+    dependencies:
+      envsubst: This tool is usually part of the gettext package
+
+  - name: text
+    help: Create a file from text
+    args:
+      - name: text
+        required: true
+        help: The text to write to the file
+      - name: target
+        required: true
+        help: The path to write the result to
diff --git a/autoinstall/before.sh b/autoinstall/before.sh
new file mode 100644
index 0000000..f88899b
--- /dev/null
+++ b/autoinstall/before.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+
+action=${action:?}
+
+# if action is run or completions, do nothing
+if [ "$action" = "run" ] || [ "$action" = "completions" ]
+then
+	return
+fi
+
+clean=${args[--clean]:-}
+target=${args[target]:?}
+
+if [ "$action" = "exe" ]
+then
+	target="$HOME/.local/bin/$target"
+fi
+
+if [ -n "$clean" ] || [ -n "${AUTOINSTALL_CLEAN:-}" ]
+then
+	echo "Cleaning $target"
+	rm -rf "$target"
+fi
diff --git a/src/completions_command.sh b/autoinstall/completions_command.sh
similarity index 100%
rename from src/completions_command.sh
rename to autoinstall/completions_command.sh
diff --git a/autoinstall/env_command.sh b/autoinstall/env_command.sh
new file mode 100644
index 0000000..74d65d7
--- /dev/null
+++ b/autoinstall/env_command.sh
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+target=${args[target]:?}
+template=${args[template]:?}
+
+if [ ! -f "$target" ]
+then
+	echo "Installing env-template $template to $target"
+
+	target_dir=$(dirname "$target")
+	mkdir -p "$target_dir"
+	cd "$target_dir" || exit 1
+
+	envsubst < "$template" > "$target"
+
+	_run_hook
+fi
diff --git a/autoinstall/file_command.sh b/autoinstall/file_command.sh
new file mode 100644
index 0000000..09ff198
--- /dev/null
+++ b/autoinstall/file_command.sh
@@ -0,0 +1,42 @@
+#!/usr/bin/env bash
+
+pipe=${args[--pipe]:?}
+completions=${args[--completions]:-}
+target=${args[target]:?}
+url=${args[url]:?}
+
+if [ "${action:-file}" = "exe" ]
+then
+	if [ -x "$(command -v "$target")" ]
+	then
+		return
+	fi
+	exe=$target
+	target="$HOME/.local/bin/$target"
+fi
+
+
+if [ ! -f "$target" ]
+then
+	echo "Installing file $url to $target"
+
+	target_dir=$(dirname "$target")
+	mkdir -p "$target_dir"
+	cd "$target_dir" || exit 1
+
+	_http_client "$url" | eval "$pipe" > "$target"
+
+	if [ "${action:-file}" = "exe" ]
+	then
+		chmod +x "$target"
+
+		if [ -n "$completions" ]
+		then
+			echo "Installing completions for $exe"
+			# shellcheck disable=SC2086
+			"$target" $completions > "$XDG_CONFIG_HOME/completionsrc.d/_$(basename "$exe")"
+		fi
+	fi
+
+	_run_hook
+fi
diff --git a/autoinstall/git_command.sh b/autoinstall/git_command.sh
new file mode 100644
index 0000000..33faf65
--- /dev/null
+++ b/autoinstall/git_command.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+
+target=${args[target]:?}
+repo=${args[repo]:?}
+
+if [ ! -d "$target" ]
+then
+	echo "Installing repo $repo to $target"
+
+	mkdir -p "$target"
+
+	git clone --depth=1 "$repo" "$target" >/dev/null 2>&1
+
+	_run_hook
+fi
diff --git a/src/lib/colors.sh b/autoinstall/lib/colors.sh
similarity index 83%
rename from src/lib/colors.sh
rename to autoinstall/lib/colors.sh
index 7458e2d..cbdc015 100644
--- a/src/lib/colors.sh
+++ b/autoinstall/lib/colors.sh
@@ -26,26 +26,17 @@ yellow() { print_in_color "\e[33m" "$*"; }
 blue() { print_in_color "\e[34m" "$*"; }
 magenta() { print_in_color "\e[35m" "$*"; }
 cyan() { print_in_color "\e[36m" "$*"; }
-black() { print_in_color "\e[30m" "$*"; }
-white() { print_in_color "\e[37m" "$*"; }
-
 bold() { print_in_color "\e[1m" "$*"; }
 underlined() { print_in_color "\e[4m" "$*"; }
-
 red_bold() { print_in_color "\e[1;31m" "$*"; }
 green_bold() { print_in_color "\e[1;32m" "$*"; }
 yellow_bold() { print_in_color "\e[1;33m" "$*"; }
 blue_bold() { print_in_color "\e[1;34m" "$*"; }
 magenta_bold() { print_in_color "\e[1;35m" "$*"; }
 cyan_bold() { print_in_color "\e[1;36m" "$*"; }
-black_bold() { print_in_color "\e[1;30m" "$*"; }
-white_bold() { print_in_color "\e[1;37m" "$*"; }
-
 red_underlined() { print_in_color "\e[4;31m" "$*"; }
 green_underlined() { print_in_color "\e[4;32m" "$*"; }
 yellow_underlined() { print_in_color "\e[4;33m" "$*"; }
 blue_underlined() { print_in_color "\e[4;34m" "$*"; }
 magenta_underlined() { print_in_color "\e[4;35m" "$*"; }
 cyan_underlined() { print_in_color "\e[4;36m" "$*"; }
-black_underlined() { print_in_color "\e[4;30m" "$*"; }
-white_underlined() { print_in_color "\e[4;37m" "$*"; }
diff --git a/autoinstall/lib/common.sh b/autoinstall/lib/common.sh
new file mode 100644
index 0000000..584603a
--- /dev/null
+++ b/autoinstall/lib/common.sh
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+_http_client() {
+	if [ -x "$(command -v curl)" ]
+	then
+		curl -fsSL "$1"
+	elif [ -x "$(command -v wget)" ]
+	then
+		wget -qO - "$1"
+	fi
+}
+
+_run_hook() {
+	hook=${args[--hook]:-}
+	if [ -n "$hook" ]
+	then
+		yellow "Running hook: $hook"
+		bash -c "$hook"
+	fi
+}
diff --git a/autoinstall/run_command.sh b/autoinstall/run_command.sh
new file mode 100644
index 0000000..7703daf
--- /dev/null
+++ b/autoinstall/run_command.sh
@@ -0,0 +1,48 @@
+#!/usr/bin/env bash
+
+group=${args[group]:?}
+clean=${args[--clean]:-}
+
+_config_query() {
+	tomlq -c --arg group "$group" \
+		'.autoinstall | map(select(.group == $group)) | '"$1" \
+		"$XDG_CONFIG_HOME/autoinstall.toml"
+}
+
+#length=$(_config_query "length")
+_config_query ".[]" | while read -r entry; do
+	install_args=()
+
+	type=$(echo "$entry" | jq -r '.type')
+	source=$(echo "$entry" | jq -r '.source')
+	target=$(echo "$entry" | jq -r '.target')
+	hook=$(echo "$entry" | jq -r '.hook // ""')
+	pipe=$(echo "$entry" | jq -r '.pipe // ""')
+	completions=$(echo "$entry" | jq -r '.completions // ""')
+
+	if [[ -n "$hook" ]]; then
+		install_args+=("--hook=$hook")
+	fi
+	if [[ -n "$clean" ]]; then
+		install_args+=("--clean")
+	fi
+
+	install_args+=("$type")
+
+	if [[ -n "$pipe" ]]; then
+		install_args+=("--pipe=$pipe")
+	fi
+	if [[ -n "$completions" ]]; then
+		install_args+=("--completions=$completions")
+	fi
+
+	if [[ $source = \$* ]]
+	then
+		source=$(eval "echo $source")
+	fi
+	install_args+=("$source")
+
+	install_args+=("$(eval "echo $target")")
+
+	autoinstall "${install_args[@]}"
+done
diff --git a/autoinstall/text_command.sh b/autoinstall/text_command.sh
new file mode 100644
index 0000000..4fcd486
--- /dev/null
+++ b/autoinstall/text_command.sh
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+
+target=${args[target]:?}
+text=${args[text]:?}
+
+if [ ! -f "$target" ]
+then
+	echo "Installing text '$text' to $target"
+
+	target_dir=$(dirname "$target")
+	mkdir -p "$target_dir"
+
+	echo "$text" > "$target"
+
+	_run_hook
+fi
diff --git a/src/bashly.yml b/autostart-manage/bashly.yml
similarity index 88%
rename from src/bashly.yml
rename to autostart-manage/bashly.yml
index a578c1b..4c292bd 100644
--- a/src/bashly.yml
+++ b/autostart-manage/bashly.yml
@@ -1,6 +1,6 @@
 name: autostart-manage
 help: Manage autostart
-version: 0.1.4
+version: 0.1.1
 
 dependencies:
   tomlq: please install yq (https://github.com/kislyuk/yq)
@@ -19,10 +19,6 @@ commands:
     help: Get the current status of all programs
   - name: sync
     help: Remove all programs from autostart and the re-enable all
-    args:
-      - name: groups
-        required: false
-        help: Extra groups to sync
   - name: enable
     help: Add a single program to autostart
     args:
@@ -77,15 +73,6 @@ commands:
     completions:
       - $(autostart-manage list)
     filename: systemctl.sh
-  - name: kill
-    help: Kill the program from autostart
-    args:
-      - name: program
-        required: true
-        help: Program to kill
-    completions:
-      - $(autostart-manage list)
-    filename: systemctl.sh
   - name: log
     alias: logs
     help: Show the log for a single program from autostart
diff --git a/autostart-manage/completions_command.sh b/autostart-manage/completions_command.sh
new file mode 100644
index 0000000..0d10993
--- /dev/null
+++ b/autostart-manage/completions_command.sh
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+
+send_completions
diff --git a/src/exec_command.sh b/autostart-manage/exec_command.sh
similarity index 63%
rename from src/exec_command.sh
rename to autostart-manage/exec_command.sh
index 2e2c816..2842069 100644
--- a/src/exec_command.sh
+++ b/autostart-manage/exec_command.sh
@@ -2,5 +2,6 @@
 
 program=${args[program]:?}
 
+cmd=$(_get_autostart_cmd "$program")
 sleep "$(_get_autostart_delay "$program")"
-bash -c "$(_get_autostart_cmd "$program")"
+bash -c "$cmd"
diff --git a/src/info_command.sh b/autostart-manage/info_command.sh
similarity index 90%
rename from src/info_command.sh
rename to autostart-manage/info_command.sh
index 566cdce..1f895e3 100644
--- a/src/info_command.sh
+++ b/autostart-manage/info_command.sh
@@ -4,6 +4,6 @@ autostart_units=()
 while IFS='' read -r line
 do
 	autostart_units+=("$line")
-done < <(_list "*")
+done < <(_list)
 
 _echo_table "${autostart_units[@]}" | column -t -s$'\t' --table-columns 'Unit,Enabled?,Active?,Command'
diff --git a/autostart-manage/lib/colors.sh b/autostart-manage/lib/colors.sh
new file mode 100644
index 0000000..cbdc015
--- /dev/null
+++ b/autostart-manage/lib/colors.sh
@@ -0,0 +1,42 @@
+## Color functions [@bashly-upgrade colors]
+## This file is a part of Bashly standard library
+##
+## Usage:
+## Use any of the functions below to color or format a portion of a string.
+##
+##   echo "before $(red this is red) after"
+##   echo "before $(green_bold this is green_bold) after"
+##
+## Color output will be disabled if `NO_COLOR` environment variable is set
+## in compliance with https://no-color.org/
+##
+print_in_color() {
+  local color="$1"
+  shift
+  if [[ -z ${NO_COLOR+x} ]]; then
+    printf "$color%b\e[0m\n" "$*"
+  else
+    printf "%b\n" "$*"
+  fi
+}
+
+red() { print_in_color "\e[31m" "$*"; }
+green() { print_in_color "\e[32m" "$*"; }
+yellow() { print_in_color "\e[33m" "$*"; }
+blue() { print_in_color "\e[34m" "$*"; }
+magenta() { print_in_color "\e[35m" "$*"; }
+cyan() { print_in_color "\e[36m" "$*"; }
+bold() { print_in_color "\e[1m" "$*"; }
+underlined() { print_in_color "\e[4m" "$*"; }
+red_bold() { print_in_color "\e[1;31m" "$*"; }
+green_bold() { print_in_color "\e[1;32m" "$*"; }
+yellow_bold() { print_in_color "\e[1;33m" "$*"; }
+blue_bold() { print_in_color "\e[1;34m" "$*"; }
+magenta_bold() { print_in_color "\e[1;35m" "$*"; }
+cyan_bold() { print_in_color "\e[1;36m" "$*"; }
+red_underlined() { print_in_color "\e[4;31m" "$*"; }
+green_underlined() { print_in_color "\e[4;32m" "$*"; }
+yellow_underlined() { print_in_color "\e[4;33m" "$*"; }
+blue_underlined() { print_in_color "\e[4;34m" "$*"; }
+magenta_underlined() { print_in_color "\e[4;35m" "$*"; }
+cyan_underlined() { print_in_color "\e[4;36m" "$*"; }
diff --git a/autostart-manage/lib/common.sh b/autostart-manage/lib/common.sh
new file mode 100644
index 0000000..dfbbb1c
--- /dev/null
+++ b/autostart-manage/lib/common.sh
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+
+_systemctl () {
+	systemctl --user "${@:2}" "autostart@$1.service"
+}
+
+_query_autostart_toml() {
+	tomlq -r --arg host "$HOSTNAME" \
+    '.hosts[$host].groups as $groups | .apps | to_entries[] | select(
+        (.value.hosts | contains([$host])) or
+        ([.value.group] | inside($groups))
+    ) | '"$1" \
+    "$XDG_CONFIG_HOME/autostart.toml"
+}
+
+_list () {
+	_query_autostart_toml '.value.alias // .key'
+}
+
+_autostart_run_graphical () {
+	set +e
+	pass x # Try to unlock yubikey asap
+
+	start-audio pipewire
+	wait-for-service "network-online.target"
+
+	# Execute only if not already running
+	# Don't match keepassxc-proxy
+	if ! (pgrep -l keepassxc | grep -v prox) >/dev/null
+	then
+		if pass x
+		then
+			(pass keepass | head -n 1 | keepassxc --pw-stdin ~/sync/passwords.kdbx) &
+		fi
+	fi
+
+	autoinstall run graphical
+	autostart-manage run
+}
+
+_echo_table () {
+	for unit in "$@"
+	do
+		printf "%s\t%s\t%s\t%s\n" \
+			"$unit" \
+			"$(_systemctl "$unit" is-enabled)" \
+			"$(_systemctl "$unit" is-active)" \
+			"$(_get_autostart_cmd "$unit")"
+	done
+}
+
+_get_autostart_cmd () {
+	_query_autostart_toml 'select((.key == "'"$1"'") or (.value.alias == "'"$1"'")) | .value.command'
+}
+
+_get_autostart_delay () {
+	_query_autostart_toml 'select((.key == "'"$1"'") or (.value.alias == "'"$1"'")) | .value.delay // 0'
+}
diff --git a/src/list_command.sh b/autostart-manage/list_command.sh
similarity index 67%
rename from src/list_command.sh
rename to autostart-manage/list_command.sh
index c732452..0986740 100644
--- a/src/list_command.sh
+++ b/autostart-manage/list_command.sh
@@ -1,3 +1,3 @@
 #!/usr/bin/env bash
 
-_list "*"
+_list
diff --git a/autostart-manage/log_command.sh b/autostart-manage/log_command.sh
new file mode 100644
index 0000000..7d9657c
--- /dev/null
+++ b/autostart-manage/log_command.sh
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+
+journalctl --user -fu "autostart@${args[program]:?}.service"
diff --git a/src/run_command.sh b/autostart-manage/run_command.sh
similarity index 100%
rename from src/run_command.sh
rename to autostart-manage/run_command.sh
diff --git a/src/run_wayland_command.sh b/autostart-manage/run_wayland_command.sh
similarity index 100%
rename from src/run_wayland_command.sh
rename to autostart-manage/run_wayland_command.sh
diff --git a/src/run_xorg_command.sh b/autostart-manage/run_xorg_command.sh
similarity index 100%
rename from src/run_xorg_command.sh
rename to autostart-manage/run_xorg_command.sh
diff --git a/autostart-manage/sync_command.sh b/autostart-manage/sync_command.sh
new file mode 100644
index 0000000..d08ac71
--- /dev/null
+++ b/autostart-manage/sync_command.sh
@@ -0,0 +1,14 @@
+#!/usr/bin/env bash
+
+rm "$HOME/.config/systemd/user/autostart.target.wants/"*
+
+autostart_units=()
+while IFS='' read -r line
+do
+	autostart_units+=("$line")
+done < <(_list)
+
+for unit in "${autostart_units[@]}"
+do
+	_systemctl "$unit" add-wants autostart.target
+done
diff --git a/src/systemctl.sh b/autostart-manage/systemctl.sh
similarity index 100%
rename from src/systemctl.sh
rename to autostart-manage/systemctl.sh
diff --git a/run.sh b/run.sh
index 8125377..67177b3 100755
--- a/run.sh
+++ b/run.sh
@@ -1,7 +1,9 @@
 #!/usr/bin/env sh
 
+target=$(cat .target)
+
+[ -n "$target" ] || exit 1
+
 make generate
 
-printf "\nBuild complete. Running...\n==========================\n\n"
-
-time ./autostart-manage "$@"
+"./output/$target" "$@"
diff --git a/settings.yml b/settings.yml
new file mode 100644
index 0000000..63e7150
--- /dev/null
+++ b/settings.yml
@@ -0,0 +1,49 @@
+# The path to bashly.yml
+config_path: "%{source_dir}/bashly.yml"
+
+# The path to use for creating the bash script
+target_dir: output
+
+# The path to use for common library files, relative to source_dir
+lib_dir: lib
+
+# The path to use for command files, relative to source_dir
+# When set to nil (~), command files will be placed directly under source_dir
+# When set to any other string, command files will be placed under this
+# directory, and each command will get its own subdirectory
+commands_dir: ~
+
+# Configure the bash options that will be added to the initialize function:
+# strict: true       Bash strict mode (set -euo pipefail)
+# strict: false      Only exit on errors (set -e)
+# strict: ''         Do not add any 'set' directive
+# strict: <string>   Add any other custom 'set' directive
+strict: true
+
+# When true, the generated script will use tab indentation instead of spaces
+# (every 2 leading spaces will be converted to a tab character)
+tab_indent: true
+
+# When true, the generated script will consider any argument in the form of
+# `-abc` as if it is `-a -b -c`.
+compact_short_flags: true
+
+# Set to 'production' or 'development':
+# env: production    Generate a smaller script, without file markers
+# env: development   Generate with file markers
+env: development
+
+# The extension to use when reading/writing partial script snippets
+partials_extension: sh
+
+# Display various usage elements in color by providing the name of the color
+# function. The value for each property is a name of a function that is
+# available in your script, for example: `green` or `bold`.
+# You can run `bashly add colors` to add a standard colors library.
+# This option cannot be set via environment variables.
+usage_colors:
+  caption: blue
+  command: green
+  arg: red
+  flag: yellow
+  environment_variable: cyan
diff --git a/src/before.sh b/src/before.sh
deleted file mode 100644
index b2e3c84..0000000
--- a/src/before.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env bash
-
-service_file="$HOME/.config/systemd/user/autostart@.service"
-if [ ! -f "$service_file" ]; then
-  _deploy_service_file "$service_file"
-fi
-
-target_file="$HOME/.config/systemd/user/autostart.target"
-if [ ! -f "$target_file" ]; then
-  _deploy_target_file "$target_file"
-fi
diff --git a/src/lib/common.sh b/src/lib/common.sh
deleted file mode 100644
index 2f99562..0000000
--- a/src/lib/common.sh
+++ /dev/null
@@ -1,81 +0,0 @@
-#!/usr/bin/env bash
-
-_systemctl () {
-	systemctl --user "${@:2}" "autostart@$1.service"
-}
-
-_query_autostart_toml() {
-	groups_json=$(echo -n "$2" | tr "," "\n" | jq -R . | jq -s .)
-	tomlq -r \
-		--arg host "$HOSTNAME" \
-		--argjson extra_groups "$groups_json" \
-		'.hosts[$host].groups as $groups | .apps | to_entries[] | select(
-			(.value.hosts | contains([$host])) or
-			(
-				(
-					([.value.group] | inside($groups)) or
-					([.value.group] | inside($extra_groups)) or
-					$extra_groups == ["*"]
-				) and (.value.group != "")
-			)
-		) | '"$1" \
-		"$XDG_CONFIG_HOME/autostart.toml"
-}
-
-_list () {
-	_query_autostart_toml '.value.alias // .key' "$1"
-}
-
-_autostart_run_graphical () {
-	set +e
-	pass x # Try to unlock yubikey asap
-
-	start-audio pipewire
-	wait-for-service "network-online.target"
-
-	# Execute only if not already running
-	# Don't match keepassxc-proxy
-	if ! (pgrep -l keepassxc | grep -v prox) >/dev/null
-	then
-		if pass x
-		then
-			(pass keepass | head -n 1 | keepassxc --pw-stdin ~/sync/passwords.kdbx) &
-		fi
-	fi
-
-	autoinstall run graphical
-	autostart-manage run
-}
-
-_echo_table () {
-	for unit in "$@"
-	do
-		if [ "$(_systemctl "$unit" is-enabled)" = "enabled" ]
-		then
-			_enabled=$(green "enabled")
-		else
-			_enabled=$(red "disabled")
-		fi
-
-		if _systemctl "$unit" is-active --quiet
-		then
-			_active=$(green "active")
-		else
-			_active=$(red "inactive")
-		fi
-
-		printf "%s\t%s\t%s\t%s\n" \
-			"$unit" \
-			"$_enabled" \
-			"$_active" \
-			"$(_get_autostart_cmd "$unit")"
-	done
-}
-
-_get_autostart_cmd () {
-	_query_autostart_toml 'select((.key == "'"$1"'") or (.value.alias == "'"$1"'")) | .value.command' "*"
-}
-
-_get_autostart_delay () {
-	_query_autostart_toml 'select((.key == "'"$1"'") or (.value.alias == "'"$1"'")) | .value.delay // 0' "*"
-}
diff --git a/src/lib/systemd_files.sh b/src/lib/systemd_files.sh
deleted file mode 100644
index d5eb682..0000000
--- a/src/lib/systemd_files.sh
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/env bash
-
-_deploy_service_file() {
-  cat <<EOF > "$1"
-[Unit]
-Description=Autostart several tools and services
-StartLimitIntervalSec=120
-StartLimitBurst=10
-
-[Service]
-KillMode=process
-ExecStart=/bin/sh -c ". \$HOME/.profile && autostart-manage exec '%i'"
-Restart=on-failure
-RestartSec=5s
-EOF
-}
-
-_deploy_target_file() {
-  cat <<EOF > "$1"
-[Unit]
-Description=Current graphical user session
-Documentation=man:systemd.special(7)
-RefuseManualStart=no
-StopWhenUnneeded=no
-EOF
-}
diff --git a/src/log_command.sh b/src/log_command.sh
deleted file mode 100644
index 8f8f075..0000000
--- a/src/log_command.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/usr/bin/env bash
-
-journalctl --user -b0 -fu "autostart@${args[program]:?}.service"
diff --git a/src/sync_command.sh b/src/sync_command.sh
deleted file mode 100644
index 49dfd4e..0000000
--- a/src/sync_command.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/usr/bin/env bash
-
-rm -f "$HOME/.config/systemd/user/autostart.target.wants/"*
-
-autostart_units=()
-while IFS='' read -r line
-do
-	autostart_units+=("autostart@$line.service")
-done < <(_list "${args[groups]:-}")
-
-systemctl --user add-wants autostart.target "${autostart_units[@]}"