diff --git a/.dockerignore b/.dockerignore
index af0e68c90f433657dc3a69909e2fee7d497ee62e..44111dfd4d533deb6c98267225fe32f69a5d5f12 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -1,2 +1,7 @@
 .build/
 .build.*/
+.dockerignore
+
+target/
+appimage/
+Dockerfile
diff --git a/.gitignore b/.gitignore
index 83990fd22bbb1a3c742c5d7258a95492387b18e6..9e8fef6c896e26021f1eeb4b109b6bc0e7ae9e2d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,8 +2,6 @@
 target/
 .build/
 .cache/
-build/
-build.*/
 .build.*/
 bin/
 pkg/
@@ -14,7 +12,6 @@ fake/
 config.log
 *\~
 *.AppImage
-appimage/
 *.pro.user
 !*.inc
 !Cargo.lock
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index d81782e228f8e444166054bd384b95f903196cfa..a4f5ac0360103909b4b6cce85f4ec2965d84cbbd 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,4 +1,3 @@
-
 .common_build:
     only:
         - master
@@ -18,13 +17,12 @@
     resource_group: rust_build
     before_script:
         - lsb_release -a
-        - echo -e "[profile.release]\nopt-level = 0" >> "$CARGO_HOME/config.toml"
-        - apt update && apt -y install make libmpv-dev cmake clang clang-format gcc g++ xxd mkvtoolnix
-            libcurl4-openssl-dev libsqlite3-dev manpages man-db libfontconfig-dev
-            qt6-base-dev qt6-declarative-dev qt6-multimedia-dev
+        - apt update && apt -y install make libmpv-dev cmake clang clang-format g++
+            manpages man-db qt6-base-dev qt6-declarative-dev qt6-multimedia-dev
         - cargo --version
     script:
-        - CXX=${cxx_compiler} CC=${c_compiler} cargo build --release
+        - CXX=${cxx_compiler} cargo test  --release
+        - CXX=${cxx_compiler} cargo build --release
 
 variables:
     GIT_DEPTH: 1 # No need to clone all the history
@@ -34,15 +32,13 @@ variables:
 #################################################
 
 build-clang:
-    stage: build
+    stage:    build
     extends: .common_build
     variables:
-        c_compiler: clang
         cxx_compiler: clang++
 
 build-gcc:
-    stage: build
+    stage:    build
     extends: .common_build
     variables:
-        c_compiler: gcc
         cxx_compiler: g++
diff --git a/BUILD.md b/BUILD.md
deleted file mode 100644
index dbd14f8bb3c8c4c30876cddafdaaa625dac2ca9a..0000000000000000000000000000000000000000
--- a/BUILD.md
+++ /dev/null
@@ -1,106 +0,0 @@
-# Build options for Lektor
-
-## Building a lektor distribution for windows (Cross Compilation)
-
-Windows 64 bit binaries are built from a linux system. Here we will assume you are using an arch
-linux system because it's what I'm using. Install the packages `mingw-w64-gcc`, `mingw-w64-cmake`
-(aur), `mingw-w64-make` (aur). You may also install the `mingw-w64-qt6-*` (aur) packages. For the
-mpv library, install the packages in [utils/arch-pkgs]. Make sure that you have the windows
-toolchain for 64 bit installed. Run the followinf commands:
-
-    (cd utils/arch-pkgs/mingw-w64-shaderc && makepkg -si)
-    yay -Sy mingw-w64-gcc mingw-w64-cmake mingw-w64-make mingw-w64-dlfcn x86_64-w64-mingw32-ldd
-    yay -Sy mingw-w64-mpv                   # Be sure to install it after building shaderc from source
-    yay -Sy mingw-w64-qt6-*                 # You may specify the packages, you may doo the bootstrap thingy here
-    rustup target add x86_64-pc-windows-gnu # Add the windows target, here we build 64bit applications
-    MAKE=x86_64-w64-mingw32-make CMAKE=x86_64-w64-mingw32-cmake CXX=x86_64-w64-mingw32-g++ cargo build --target x86_64-pc-windows-gnu
-
-To produce the zip file for windows users, from the target folder run the following commands:
-
-    mkdir -p lektor/platforms && cd lektor  # Prepare folders
-    cp ../{lkt,amadeus,lektord}.exe .       # Copy the produced executables
-    cp ../lektor_c.dll .                    # Copy the dll for lektord
-
-    for F in $(WINEPATH=/usr/x86_64-w64-mingw32/bin x86_64-w64-mingw32-ldd lektor_c.dll | grep -v "not found" | awk '{print $3}')
-    do
-        cp "$F" . # Copy DLL files
-    done
-    chmod +x *.dll *.dll.*                                                              # Set DLL executable for linux, just in case
-    cp /usr/x86_64-w64-mingw32/lib/qt6/plugins/platforms/qwindows.dll        platforms/ # Copy the windows platform dll for Qt
-    cp /usr/x86_64-w64-mingw32/lib/qt6/plugins/styles/qwindowsvistastyle.dll styles/    # Copy the style dll
-    (cd .. && zip lektor.zip lektor/* lektor/platforms/*)                               # Create the zip file
-
-    # Now you can run lektord and distribute the zip file!
-    ./lektord.exe
-
-> Be sure to have the multilib repos and install the bootstrap `minwg-w64-*-bootstrap` packages
-> first, to avoid the circular dependencies... And be sure to have a lot of time to waste.
-
-## Building a lektor distribution for linux (AppImage)
-
-Note that it is preferable to build AppImages from the older system that you want to support, see
-the [official website](https://appimage.org/). Note that you can run AppImage from anywhere at the
-condition that the target system has fuse2 installed and is newer that the system the AppImage was
-build with.
-
-### Build on host system (ArchLinux)
-
-First you need the LinuxDeploy and AppImageTool binaries. You will need to have fuse2 installed on
-your system. We will assume you are using an *x86_64* system. You can download it their repositories:
-- https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous
-- https://github.com/AppImage/AppImageKit/releases/tag/continuous
-
-As an alternative you can use the following commands and add the `$HOME/.local/bin` folder to you path.
-
-    wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
-    wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-static-x86_64.AppImage
-    mv appimagetool-x86_64.AppImage       ~/.local/bin/appimagetool
-    mv linuxdeploy-static-x86_64.AppImage ~/.local/bin/linuxdeploy
-    chmod +x ~/.local/bin/appimagetool
-    chmod +x ~/.local/bin/linuxdeploy
-
-For the packages needed to build the lektor project, on arch you may install the following packages:
-`qt6-multimedia-ffmpeg`, `qt6-translations`, `qt6-declarative`, `qt6-multimedia`, `qt6-wayland`,
-`qt6-tools`, `qt6-base`, `qt6-svg`, `mpv`, `cmake`, `cmake-extra-modules`. The usual way of
-installing rust is by executing their script:
-
-    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
-
-After building the lektord executable and .so files, you can use the following commands from the
-target folder (where the executable where generated). We will reference the root folder of the
-lektord repository as `$ROOT`.
-
-    mkdir Amadeus Lektord Lkt # Create one folder for each AppImage
-
-    # Do the thing for Lkt
-    linuxdeploy --appdir Lkt --executable lkt --icon-file $ROOT/utils/desktop/lektor.png --desktop-file $ROOT/utils/desktop/lkt.desktop
-    appimagetool --comp xz --sign --sign-key $YOUR_SIGN_KEY Lkt
-
-    # Do the thing for Lektord
-    linuxdeploy --appdir Lektord --executable lektord --icon-file $ROOT/utils/desktop/lektor.png --desktop-file $ROOT/utils/desktop/lektord.desktop
-    appimagetool --comp xz --sign --sign-key $YOUR_SIGN_KEY Lektord
-
-    # Do the thing for Amadeus
-    linuxdeploy --appdir Amadeus --executable lektord --icon-file $ROOT/utils/desktop/amadeus.png --desktop-file $ROOT/utils/desktop/amadeus.desktop
-    appimagetool --comp xz --sign --sign-key $YOUR_SIGN_KEY Amadeus
-
-### Build in a container (Docker/Podman)
-
-As an alternative you can run the docker which will use debian 12 (bookworm) to try to build an
-AppImage which is compatible with as many systems as possible, note that with Qt6 we won't be able
-to support systems that are too old.
-
-You can use docker (must be configured) or podman, with podman you don't need a root daemon and
-privileges, it will run as your current user. In the latter case your container registry config file
-`/etc/containers/registries.conf` must contains the following content:
-
-    [registries.search]
-    registries = ['docker.io']
-
-When everything is configured you can run the following commands, using either docker or podman.
-Note that you still need fuse2 on the host system.
-
-    mkdir -p appimage
-    podman build --rm -v "$PWD/appimage":/usr/src/lektor/appimage --cap-add SYS_ADMIN --device /dev/fuse .
-    podman image prune -f
-
diff --git a/Dockerfile b/Dockerfile
deleted file mode 100644
index 075be434c363643050273636180d81778fb8c13c..0000000000000000000000000000000000000000
--- a/Dockerfile
+++ /dev/null
@@ -1,48 +0,0 @@
-ARG VERSION=1.73
-FROM rust:${VERSION}-bookworm
-WORKDIR /usr/src/lektor
-COPY . .
-
-RUN apt update && apt -y install \
-        make libmpv-dev cmake clang clang-format manpages man-db \
-        qt6-base-dev qt6-declarative-dev qt6-multimedia-dev fuse
-
-RUN mkdir appimagetool \
-    && wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage \
-        -O appimagetool/appimage                  \
-    && chmod +x appimagetool/appimage             \
-    && ./appimagetool/appimage --appimage-extract \
-    && mv squashfs-root appimagetool/
-
-RUN mkdir linuxdeploy \
-    && wget https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage \
-        -O linuxdeploy/appimage                  \
-    && chmod +x linuxdeploy/appimage             \
-    && ./linuxdeploy/appimage --appimage-extract \
-    && mv squashfs-root linuxdeploy/
-
-RUN CXX=clang++ cargo build --release
-
-RUN ./linuxdeploy/squashfs-root/AppRun           \
-        -v1 --appdir appimage/Lkt                \
-        --executable target/release/lkt          \
-        --icon-file utils/desktop/lektor.png     \
-        --desktop-file utils/desktop/lkt.desktop \
-    && ./appimagetool/squashfs-root/AppRun -v --comp xz appimage/Lkt \
-    && mv Lkt-*.AppImage appimage/ && rm -rf appimage/Lkt/
-
-RUN ./linuxdeploy/squashfs-root/AppRun               \
-        -v1 --appdir appimage/Lektord                \
-        --executable target/release/lektord          \
-        --icon-file utils/desktop/lektor.png         \
-        --desktop-file utils/desktop/lektord.desktop \
-    && ./appimagetool/squashfs-root/AppRun -v --comp xz appimage/Lektord \
-    && mv Lektord-*.AppImage appimage/ && rm -rf appimage/Lektord/
-
-RUN ./linuxdeploy/squashfs-root/AppRun               \
-        -v1 --appdir appimage/Amadeus                \
-        --executable target/release/amadeus          \
-        --icon-file utils/desktop/amadeus.png        \
-        --desktop-file utils/desktop/amadeus.desktop \
-    && ./appimagetool/squashfs-root/AppRun -v --comp xz appimage/Amadeus \
-    && mv Amadeus-*.AppImage appimage/ && rm -rf appimage/Amadeus/
diff --git a/Dockerfile.appimage b/Dockerfile.appimage
new file mode 100644
index 0000000000000000000000000000000000000000..d768628fd85b287ef635afc7fabbf28c64535a83
--- /dev/null
+++ b/Dockerfile.appimage
@@ -0,0 +1,29 @@
+FROM    rust:1.73-bullseye AS linux-base
+WORKDIR /usr/src
+COPY    --chmod=0755 utils/scripts/docker/setup_base.bash setup
+RUN     ./setup
+
+FROM    linux-base AS linux-cache
+WORKDIR /usr/src
+COPY    --chmod=0755 utils/scripts/docker/prepare_workspace.bash prepare
+RUN     STAGE=1 ./prepare
+COPY    lektor_procmacros/Cargo.toml    lektor_procmacros
+COPY    lektor_lib/Cargo.toml           lektor_lib
+COPY    lektor_nkdb/Cargo.toml          lektor_nkdb
+COPY    lektor_repo/Cargo.toml          lektor_repo
+COPY    lektor_mpris/Cargo.toml         lektor_mpris
+COPY    kurisu_api/Cargo.toml           kurisu_api
+COPY    lektor_payloads/Cargo.toml      lektor_payloads
+COPY    lektor_utils/Cargo.toml         lektor_utils
+COPY    lkt/Cargo.toml                  lkt
+COPY    lektord/Cargo.toml              lektord
+COPY    amadeus/Cargo.toml              amadeus
+COPY    Cargo.toml Cargo.lock           ./
+RUN     STAGE=2 ./prepare
+
+FROM        linux-cache
+WORKDIR     /usr/src
+COPY        --chmod=0755 utils/scripts/docker/package_appimages.bash package
+COPY        --chmod=0755 utils/scripts/docker/touch_files.bash       touch
+ENTRYPOINT  ./touch && CXX=clang++ cargo test --release && CXX=clang++ cargo build --release && ./package
+
diff --git a/Dockerfile.windows b/Dockerfile.windows
new file mode 100644
index 0000000000000000000000000000000000000000..e3d2f5881b336336585c68baf702371c2bbbfb7f
--- /dev/null
+++ b/Dockerfile.windows
@@ -0,0 +1,40 @@
+FROM    archlinux:latest AS mingw64-base
+WORKDIR /usr/src
+COPY    --chmod=0755 utils/scripts/docker/setup_cross.bash setup
+COPY    --chmod=0644 --chown=1000:1000 utils/arch-pkgs/mingw-w64-shaderc /home/devel/mingw-w64-shaderc
+RUN     ./setup
+
+FROM    mingw64-base as mingw64-cache
+USER    devel
+ENV     HOME=/home/devel
+ENV     MAKE=x86_64-w64-mingw32-make
+ENV     CMAKE=x86_64-w64-mingw32-cmake
+ENV     CXX=x86_64-w64-mingw32-g++
+WORKDIR /home/devel
+COPY    --chmod=0755 utils/scripts/docker/prepare_workspace.bash prepare
+RUN     STAGE=1 ./prepare
+COPY    lektor_procmacros/Cargo.toml    lektor_procmacros
+COPY    lektor_lib/Cargo.toml           lektor_lib
+COPY    lektor_nkdb/Cargo.toml          lektor_nkdb
+COPY    lektor_repo/Cargo.toml          lektor_repo
+COPY    lektor_mpris/Cargo.toml         lektor_mpris
+COPY    kurisu_api/Cargo.toml           kurisu_api
+COPY    lektor_payloads/Cargo.toml      lektor_payloads
+COPY    lektor_utils/Cargo.toml         lektor_utils
+COPY    lkt/Cargo.toml                  lkt
+COPY    lektord/Cargo.toml              lektord
+COPY    amadeus/Cargo.toml              amadeus
+COPY    Cargo.toml Cargo.lock           ./
+RUN     STAGE=2 ./prepare --target x86_64-pc-windows-gnu
+
+FROM        mingw64-cache
+USER        devel
+ENV         HOME=/home/devel
+ENV         MAKE=x86_64-w64-mingw32-make
+ENV         CMAKE=x86_64-w64-mingw32-cmake
+ENV         CXX=x86_64-w64-mingw32-g++
+WORKDIR     /home/devel
+COPY        --chmod=0755 utils/scripts/docker/touch_files.bash touch
+COPY        --chmod=0755 utils/scripts/docker/package_zip.bash package
+ENTRYPOINT  ./touch && cargo test --release --target x86_64-pc-windows-gnu && cargo build --release --target x86_64-pc-windows-gnu && ./package
+
diff --git a/README.md b/README.md
index 51e9613b39aa128f22140235bd57cb66f43c4640..326de5f5033f0beff1de63f9de81be6805e590e1 100644
--- a/README.md
+++ b/README.md
@@ -23,9 +23,9 @@ A Karaoke player made to replace the old bash scripts on Sakura.
 
 ### Prerequisites
 
-- [rust](https://www.rust-lang.org) compiler with version >= 1.72
-- [cmake](https://cmake.org/) at least the version 3.17
-- C++ compiler with [C++20 support](https://en.cppreference.com/w/cpp/20)
+- [rust](https://www.rust-lang.org) compiler with version >= 1.70
+- [cmake](https://cmake.org/) at least the version 3.18
+- C++ compiler with [C++17 support](https://en.cppreference.com/w/cpp/17)
 - [mpv](https://mpv.io/) development library
 - [Qt6](https://www.qt.io/) development library: QtCore, QtWidgets, QtOpenGL, QtOpenGLWidgets.
 
@@ -36,7 +36,7 @@ from the `graphviz` package to be installed for that script to work.
 ### Building instructions
 
 The manual way of installing and setting up lektor. We will suppose that cargo will place all the
-binaries inside the `target` folder:
+binaries inside the `target` folder and that you have all the libraries installed correctly.
 
     cargo build --release
     install -CD -m 0755 utils/scripts/kagary.py $HOME/.local/bin/kagary
@@ -49,7 +49,30 @@ compiler: `CXX=clang++ cargo build --release`. By default the build artifacts fo
 placed in the `.build` folder at the root of the project. If you specify another compiler they will
 be placed in the `.build.$(basename "$CXX")` folder.
 
-For more informations about builds options, see the [BUILD.md] file.
+You can use podman (must be configured) or docker, with podman you don't need a root daemon and
+privileges, it will run as your current user. In the former case your container registry config file
+`/etc/containers/registries.conf` must contains the following content:
+
+    [registries.search]
+    registries = ['docker.io']
+
+When everything is configured you can run the following commands, using either docker or podman:
+
+    # AppImage build
+    podman build -t lektor_appimage -f Dockerfile.appimage
+    podman run -v $PWD/build:/build -v $PWD:/src lektor_appimage
+
+    # Windows build
+    podman build -t lektor_windows -f Dockerfile.windows
+    podman run -v $PWD/build:/build -v $PWD:/src lektor_windows
+
+> Note that the generated AppImages won't be signed, you can signed them by extracting them, and
+> repacking them with you gpg key, here with Amadeus as an example. You will need to have downloaded
+> the appimage utility.
+>
+>     ./Amadeus-x86_64.AppImage --appimage-extract
+>     mv squashfs-root Amadeus
+>     appimagetool --comp xz --sign --sign-key $YOUR_SIGN_KEY Amadeus
 
 ## How to use lektor
 
diff --git a/amadeus/amadeus.appdata.xml b/amadeus/amadeus.appdata.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9e5705ba6a9ac2be760dbf47fadbe2382b08ea80
--- /dev/null
+++ b/amadeus/amadeus.appdata.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<component type="desktop-application">
+	<id>amadeus</id>
+	<metadata_license>MIT</metadata_license>
+	<project_license>MIT</project_license>
+	<name>Amadeus</name>
+	<summary>Amadeus client for lektord</summary>
+	<description>
+		<p>Amadeus is a GUI client written in Rust for the lektord daemon.</p>
+	</description>
+	<launchable type="desktop-id">amadeus.desktop</launchable>
+	<url type="homepage">https://kurisu.iiens.net</url>
+	<screenshots>
+		<screenshot type="default">
+			<image></image>
+		</screenshot>
+	</screenshots>
+	<provides>
+		<id>amadeus.desktop</id>
+	</provides>
+</component>
diff --git a/utils/desktop/amadeus.desktop b/amadeus/amadeus.desktop
similarity index 100%
rename from utils/desktop/amadeus.desktop
rename to amadeus/amadeus.desktop
diff --git a/utils/desktop/amadeus.png b/amadeus/amadeus.png
similarity index 100%
rename from utils/desktop/amadeus.png
rename to amadeus/amadeus.png
diff --git a/amadeus/src/main.rs b/amadeus/src/main.rs
index 9f97cd8dd0676363fe84da90c8bd32d5fbc52c9b..ffb31bf782e5561e8fb88324b31de78eb455e513 100644
--- a/amadeus/src/main.rs
+++ b/amadeus/src/main.rs
@@ -49,7 +49,7 @@ fn main() -> Result<()> {
         id: Some("Amadeus".to_string()),
         window: iced::window::Settings {
             icon: Some(iced::window::icon::from_file_data(
-                include_bytes!("../../utils/desktop/amadeus.png"),
+                include_bytes!("../amadeus.png"),
                 Some(image::ImageFormat::Png),
             )?),
             resizable: true,
diff --git a/build/.gitignore b/build/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..d6b7ef32c8478a48c3994dcadc86837f4371184d
--- /dev/null
+++ b/build/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/lektor_utils/src/open/mod.rs b/lektor_utils/src/open/mod.rs
index 20b9bdc0e44a92bf68de1018e77588428562be77..e20e99a3831f9a26daeb61a7d834307634105b6b 100644
--- a/lektor_utils/src/open/mod.rs
+++ b/lektor_utils/src/open/mod.rs
@@ -68,7 +68,7 @@
 
 #[cfg(windows)]
 #[path = "windows.rs"]
-mod windows;
+mod os;
 
 #[cfg(target_os = "macos")]
 #[path = "macos.rs"]
diff --git a/lektord/c/icon.xpm b/lektord/c/icon.xpm
index dbebed39f7e3b0eb74d4a036b90954dc27a1d090..442f00ecf997b0206ef118ab4c765c9cbcacf23d 100644
--- a/lektord/c/icon.xpm
+++ b/lektord/c/icon.xpm
@@ -1,5 +1,5 @@
 /* XPM */
-static char *icon[] = {
+static const char *const icon[] = {
 /* columns rows colors chars-per-pixel */
 "32 32 9 1 ",
 "  c #0E001D",
diff --git a/lektord/c/module_qt_window.cc b/lektord/c/module_qt_window.cc
index 18697e14ac5ea7dc58b4eec097063ede15fcccbe..90012ebab3db6d7c8dbd31f50bdeeac77c61eca8 100644
--- a/lektord/c/module_qt_window.cc
+++ b/lektord/c/module_qt_window.cc
@@ -17,7 +17,12 @@ ___create_mpv_widget(void *arg)
     setlocale(LC_NUMERIC, "C");
     qt_window->main_window = new MainWindow(qt_window);
     qt_window->main_window->show();
-    return std::bit_cast<void *>((static_cast<size_t>(app.exec())));
+
+    // Becaust of debian bullseye we don't have bit_cast and must use a memcpy...
+    const size_t ret = static_cast<size_t>(app.exec());
+    void *ret_ptr    = nullptr;
+    std::memcpy(&ret_ptr, &ret, sizeof(void *));
+    return ret_ptr;
 }
 
 #if defined(LKT_OS_MINGW) && (LKT_OS_MINGW == 1)
diff --git a/lektord/lektord.appdata.xml b/lektord/lektord.appdata.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c0d6c25c84537248529f5ccd92f0aba18ae3b2a2
--- /dev/null
+++ b/lektord/lektord.appdata.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<component type="desktop-application">
+	<id>lektord</id>
+	<metadata_license>MIT</metadata_license>
+	<project_license>MIT</project_license>
+	<name>Lektord</name>
+	<summary>The lektord daemon</summary>
+	<description>
+		<p>The lektord daemon.</p>
+	</description>
+	<launchable type="desktop-id">lektord.desktop</launchable>
+	<url type="homepage">https://kurisu.iiens.net</url>
+	<screenshots>
+		<screenshot type="default">
+			<image></image>
+		</screenshot>
+	</screenshots>
+	<provides>
+		<id>lektord.desktop</id>
+	</provides>
+</component>
diff --git a/utils/desktop/lektord.desktop b/lektord/lektord.desktop
similarity index 93%
rename from utils/desktop/lektord.desktop
rename to lektord/lektord.desktop
index 5edb11e125f8e9834c3fe53bc3dd931f9310aac9..025c33b3754f46b4e11cb76fe85708a9b3040b04 100644
--- a/utils/desktop/lektord.desktop
+++ b/lektord/lektord.desktop
@@ -2,7 +2,7 @@
 Version=1.0
 Type=Application
 Name=Lektord
-Icon=lektor
+Icon=lektord
 GenericName=Lektor deamon
 Comment=The lektor deamon
 Keywords=video;audio
diff --git a/utils/desktop/lektor.png b/lektord/lektord.png
similarity index 100%
rename from utils/desktop/lektor.png
rename to lektord/lektord.png
diff --git a/lkt/lkt.appdata.xml b/lkt/lkt.appdata.xml
new file mode 100644
index 0000000000000000000000000000000000000000..97c49143f55f5c001b1521e5ce031e99aff9a73a
--- /dev/null
+++ b/lkt/lkt.appdata.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<component type="desktop-application">
+	<id>lkt</id>
+	<metadata_license>MIT</metadata_license>
+	<project_license>MIT</project_license>
+	<name>Lkt</name>
+	<summary>Lkt client for lektord</summary>
+	<description>
+		<p>Lkt is a GUI client written in Rust for the lektord daemon.</p>
+	</description>
+	<launchable type="desktop-id">lkt.desktop</launchable>
+	<url type="homepage">https://kurisu.iiens.net</url>
+	<screenshots>
+		<screenshot type="default">
+			<image></image>
+		</screenshot>
+	</screenshots>
+	<provides>
+		<id>lkt.desktop</id>
+	</provides>
+</component>
diff --git a/utils/desktop/lkt.desktop b/lkt/lkt.desktop
similarity index 94%
rename from utils/desktop/lkt.desktop
rename to lkt/lkt.desktop
index 43a0db42797281c3c4ae361a1ca59c6e9e4ee290..ea63948751725c3fccbc32cb7015b0a199320d8a 100644
--- a/utils/desktop/lkt.desktop
+++ b/lkt/lkt.desktop
@@ -2,7 +2,7 @@
 Version=1.0
 Type=Application
 Name=Lkt
-Icon=lektor
+Icon=lkt
 GenericName=lkt commnand line client
 Comment=lkt command line client
 Keywords=video;audio
diff --git a/lkt/lkt.png b/lkt/lkt.png
new file mode 100644
index 0000000000000000000000000000000000000000..e33521da3f8b9cdab4488e9f0c2f3d0f53d47da6
Binary files /dev/null and b/lkt/lkt.png differ
diff --git a/utils/scripts/docker/package_appimages.bash b/utils/scripts/docker/package_appimages.bash
new file mode 100755
index 0000000000000000000000000000000000000000..e4989c3a0001f93dea77efa1d1feb714933053c5
--- /dev/null
+++ b/utils/scripts/docker/package_appimages.bash
@@ -0,0 +1,104 @@
+#!/usr/bin/env bash
+set -xe
+[ ! -f /build/.gitignore ] && {
+    echo "The appimage folder is not mounted in the docker"
+    exit 1
+}
+[ ! -d squashfs-root ] && {
+    echo "The appimage utilities where not deployed..."
+    exit 1
+}
+
+export ARCH=$(arch)
+export PATH="$PWD/squashfs-root/usr/bin:$PATH"
+export LD_LIBRARY_PATH="$PWD/squashfs-root/usr/lib:$LD_LIBRARY_PATH"
+export QMAKE=/usr/lib/qt6/bin/qmake6
+
+function join_by() {
+    local d=${1-} f=${2-}
+    if shift 2; then
+        printf %s "$f" "${@/#/$d}"
+    fi
+}
+
+function get_additional_libs() {
+    case $* in
+        *qt*) for LIB in /usr/lib/x86_64-linux-gnu/libQt6WaylandEglCompositorHwIntegration.so   \
+                         /usr/lib/x86_64-linux-gnu/libQt6WaylandEglClientHwIntegration.so       \
+                         /usr/lib/x86_64-linux-gnu/libQt6WaylandCompositor.so                   \
+                         /usr/lib/x86_64-linux-gnu/libQt6OpenGLWidgets.so                       \
+                         /usr/lib/x86_64-linux-gnu/libQt6OpenGL.so                              \
+                         /usr/lib/x86_64-linux-gnu/libQt6MultimediaWidgets.so                   \
+                         /usr/lib/x86_64-linux-gnu/libQt6Multimedia.so                          \
+                         /usr/lib/x86_64-linux-gnu/libQt6Concurrent.so                          \
+                         /usr/lib/x86_64-linux-gnu/libQt6WaylandClient.so                       \
+                         /usr/lib/x86_64-linux-gnu/libQt6XcbQpa.so                              \
+                         /usr/lib/x86_64-linux-gnu/libQt6EglFSDeviceIntegration.so              \
+                         /usr/lib/x86_64-linux-gnu/libQt6EglFsKmsGbmSupport.so                  \
+                         /usr/lib/x86_64-linux-gnu/libQt6EglFsKmsSupport.so                     ;
+        do
+            for FILE in ${LIB}*; do
+                echo -n " -l${FILE} "
+            done
+        done;;
+        *);;
+    esac
+}
+
+function deploy() {
+    local EXEC=${1,,}
+
+    local  EXTRA_QT_PLUGINS="concurrent;core;dbus;eglfsdeviceintegration;eglfskmssupport;gui;multimedia;multimediawidgets;"
+    local  EXTRA_QT_PLUGINS+="opengl;openglwidgets;waylandclient;waylandcompositor;widgets;xcbqpa;"
+    export EXTRA_QT_PLUGINS
+
+    local  EXTRA_PLATFORM_PLUGINS="libqxcb.so;libqeglfs.so;libqwayland-egl.so;libqwayland-generic.so;"
+    export EXTRA_PLATFORM_PLUGINS
+
+    local EXCLUDE_LIBS="libgdk_pixbuf libpango libcairo libgio libglib libgmodule libgobject libgthread"
+    local EXCLUDE_LIBS="-name *$(join_by "* -or -name *" $EXCLUDE_LIBS)*"
+
+    local QT_SRC=/usr/lib/x86_64-linux-gnu/qt6/plugins
+    local QT_DST=${EXEC^}/usr/plugins
+
+    # Will do most of the work
+    linuxdeploy -v1 --appdir ${EXEC^} -e target/release/${EXEC} \
+        -i ${EXEC}/${EXEC}.png -d ${EXEC}/${EXEC}.desktop       \
+        ${*:2} $(get_additional_libs $*)
+
+    # Handle aftermath things here, we force copy the qt plugins for wayland and remove unwanted
+    # libs... NOTE: For now we force the xcb platform because of troubles with wayland...
+    mkdir -p ${EXEC^}/apprun-hooks/
+    case ${*:2} in
+        *qt*)
+        echo "export QT_QPA_PLATFORM=xcb" > ${EXEC^}/apprun-hooks/force-xcb.sh
+        for PLUGIN in ${QT_SRC}/*; do
+            local PLUGIN=$(basename ${PLUGIN})
+            if [ ! -d ${QT_DST}/${PLUGIN} ]; then
+                cp -rf ${QT_SRC}/${PLUGIN} ${QT_DST}/${PLUGIN}
+            fi
+        done;;
+        *);;
+    esac
+    find ${EXEC^}/usr/lib/ -type f -and \( ${EXCLUDE_LIBS} \) -delete
+    cp LICENSE CHANGELOG.md CONTRIBUTING.md ${EXEC^}/
+    install -Dm644 ${EXEC}/${EXEC}.appdata.xml ${EXEC^}/usr/share/metainfo/${EXEC}.appdata.xml
+cat > ${EXEC^}/AppRun <<EOF
+#!/usr/bin/env bash
+set -e
+this_dir="\$(readlink -f "\$(dirname "\$0")")"
+for HOOK in "\$this_dir"/apprun-hooks/*; do
+    source "\$HOOK"
+done
+exec "\$this_dir"/AppRun.wrapped "$@"
+EOF
+
+    # Pack the AppImage
+    appimagetool -v --comp xz ${EXEC^}
+    mv ${EXEC^}-$(arch).AppImage /build/
+}
+
+deploy lkt
+deploy amadeus
+deploy lektord --plugin qt
+
diff --git a/utils/scripts/docker/package_zip.bash b/utils/scripts/docker/package_zip.bash
new file mode 100755
index 0000000000000000000000000000000000000000..92553393227590565a57a938fce40e170f28d1c7
--- /dev/null
+++ b/utils/scripts/docker/package_zip.bash
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+set -xe
+[ ! -f /build/.gitignore ] && {
+    echo "The output folder is not mounted in the docker"
+    exit 1
+}
+
+cd $(readlink -f target/x86_64-pc-windows-gnu/release)
+
+mkdir -p lektor/platforms && cd lektor  # Prepare folders
+cp ../{lkt,amadeus,lektord}.exe .       # Copy the produced executables
+cp ../lektor_c.dll .                    # Copy the dll for lektord
+
+# Copy all the needed dll files
+for F in $(WINEPATH=/usr/x86_64-w64-mingw32/bin x86_64-w64-mingw32-ldd lektor_c.dll | grep -v "not found" | awk '{print $3}')
+do
+    cp "$F" .
+done
+chmod +x *.dll *.dll.*                                                           # Set DLL executable for linux, just in case
+cp /usr/x86_64-w64-mingw32/lib/qt6/plugins/platforms/qwindows.dll platforms/     # Copy the windows platform dll for Qt
+cp /usr/x86_64-w64-mingw32/lib/qt6/plugins/styles/qwindowsvistastyle.dll styles/ # Copy the style dll
+
+# Create the zip file
+cd ..
+zip lektor.zip lektor/* lektor/platforms/*
+mv lektor.zip /build/
diff --git a/utils/scripts/docker/prepare_workspace.bash b/utils/scripts/docker/prepare_workspace.bash
new file mode 100755
index 0000000000000000000000000000000000000000..c504e7aacf0b6cc606b1459e8f165fe9ac7aaeb4
--- /dev/null
+++ b/utils/scripts/docker/prepare_workspace.bash
@@ -0,0 +1,24 @@
+#!/usr/bin/env bash
+set -e
+
+if [ "x$STAGE" = "x1" ]; then
+    cargo new --lib lektor_procmacros
+    cargo new --lib lektor_lib
+    cargo new --lib lektor_nkdb
+    cargo new --lib lektor_repo
+    cargo new --lib lektor_mpris
+    cargo new --lib kurisu_api
+    cargo new --lib lektor_payloads
+    cargo new --lib lektor_utils
+    cargo new lkt
+    cargo new lektord
+    cargo new amadeus
+    echo "" > lektor_procmacros/src/lib.rs
+    if [ -f $HOME/.cargo/env ]; then
+        echo "source $HOME.cargo/env" >> $HOME/.bashrc
+    fi
+else
+    find . -type f -exec touch -d "1990-01-01 00:00:00" {} \;
+    cargo build --release $*
+    rm -rf kurisu_api lektor_* lkt amadeus lektord
+fi
diff --git a/utils/scripts/docker/setup_base.bash b/utils/scripts/docker/setup_base.bash
new file mode 100755
index 0000000000000000000000000000000000000000..bbdf53c6e3df23f828eef3cacea75a617d030335
--- /dev/null
+++ b/utils/scripts/docker/setup_base.bash
@@ -0,0 +1,45 @@
+#!/usr/bin/env bash
+set -xe
+
+ARCH=$(arch)
+PKG_BASE="make libmpv-dev cmake clang clang-format manpages man-db"
+PKG_BACKPORT=""
+
+PKG_BACKPORT+=" qt6-base-dev qt6-declarative-dev qt6-multimedia-dev qt6-tools-private-dev"
+PKG_BACKPORT+=" qt6-tools-dev-tools qt6-tools-dev qt6-5compat-dev"
+PKG_BACKPORT+=" qt6-image-formats-plugins qt6-gtk-platformtheme qt6-base-abi libqt6xml6"
+PKG_BACKPORT+=" libqt6multimedia6 libqt6concurrent6 libqt6multimediawidgets6 "
+PKG_BACKPORT+=" libqt6opengl6 libqt6openglwidgets6 libqt6widgets6"
+PKG_BACKPORT+=" qt6-translations-l10n qt6-l10n-tools"
+
+PKG_BACKPORT+=" qt6-wayland-dev qt6-wayland qt6-wayland-dev-tools"
+PKG_BACKPORT+=" libqt6waylandclient6 libqt6waylandcompositor6 libqt6waylandeglclienthwintegration6"
+PKG_BACKPORT+=" libqt6waylandeglcompositorhwintegration6 libqt6wlshellintegration6"
+
+PKG_BACKPORT+=" qt6-qpa-plugins"
+
+function appimage_setup() {
+    local APPIMAGE=$(basename "$1")
+    wget "$1"
+    chmod +x ${APPIMAGE}
+    ./${APPIMAGE} --appimage-extract
+    rm -rf ${APPIMAGE}
+}
+
+echo "deb     http://deb.debian.org/debian bullseye-backports main contrib non-free" >> /etc/apt/sources.list
+echo "deb-src http://deb.debian.org/debian bullseye-backports main contrib non-free" >> /etc/apt/sources.list
+
+apt update
+apt upgrade -y
+apt -y install $PKG_BASE
+apt -y install -t bullseye-backports $PKG_BACKPORT
+rm -rf /var/cache/
+
+appimage_setup \
+    https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-$ARCH.AppImage
+
+appimage_setup \
+    https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-$ARCH.AppImage
+
+appimage_setup \
+    https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-$ARCH.AppImage
diff --git a/utils/scripts/docker/setup_cross.bash b/utils/scripts/docker/setup_cross.bash
new file mode 100755
index 0000000000000000000000000000000000000000..a56aeffcb0bed8a424c4231cebd8ad649919decd
--- /dev/null
+++ b/utils/scripts/docker/setup_cross.bash
@@ -0,0 +1,63 @@
+#!/usr/bin/env bash
+set -xe
+
+PKG_BASE="imagemagick make ninja git binutils patch base-devel unzip protobuf"
+PKG_MINGW="mingw-w64-binutils mingw-w64-crt mingw-w64-gcc mingw-w64-headers mingw-w64-winpthreads"
+
+AUR_BOOTSTRAP_MINGW="mingw-w64-x264-bootstrap mingw-w64-headers-bootstrap mingw-w64-freetype2-bootstrap mingw-w64-cairo-bootstrap "
+AUR_BOOTSTRAP_MINGW+="mingw-w64-cmake mingw-w64-extra-cmake-modules mingw-w64-make mingw-w64-configure mingw-w64-meson mingw-w64-pkg-config "
+
+AUR_MINGW="mingw-w64-mpv mingw-w64-bzip2 mingw-w64-expat mingw-w64-fontconfig mingw-w64-freeglut mingw-w64-freetype2 "
+AUR_MINGW+="mingw-w64-libdbus mingw-w64-libiconv mingw-w64-libjpeg-turbo mingw-w64-libpng mingw-w64-libtiff mingw-w64-libxml2 "
+AUR_MINGW+="mingw-w64-openssl mingw-w64-openjpeg mingw-w64-openjpeg2 mingw-w64-pcre mingw-w64-pdcurses mingw-w64-protobuf "
+AUR_MINGW+="mingw-w64-readline mingw-w64-sdl2 mingw-w64-termcap mingw-w64-tools mingw-w64-zlib mingw-w64-gettext "
+
+AUR_QT_MINGW="clang qt6-tools mingw-w64-qt6-base mingw-w64-qt6-base-static mingw-w64-qt6-5compat "
+AUR_QT_MINGW+="mingw-w64-qt6-imageformats mingw-w64-qt6-multimedia mingw-w64-qt6-shadertools "
+AUR_QT_MINGW+="mingw-w64-qt6-svg mingw-w64-qt6-tools mingw-w64-qt6-translations "
+
+# Base system
+pacman-key --init
+pacman-key --populate
+
+pacman -Syu --noconfirm --noprogressbar archlinux-keyring pacman
+pacman-db-upgrade
+
+pacman -Syu --noconfirm --noprogressbar ca-certificates
+trust  extract-compat
+pacman -Syu --noconfirm --noprogressbar --needed ${PKG_BASE}
+
+cat >> /etc/pacman.conf << EOF
+[multilib]
+Include = /etc/pacman.d/mirrorlist
+EOF
+
+pacman -Syu --noconfirm --noprogressbar --needed ${PKG_MINGW}
+useradd -m -d /home/devel -u 1000 -U -G users,tty -s /bin/bash devel
+echo "devel ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
+
+# AUR + Rust
+su -c bash - devel << EOF
+    set -xe
+    cd /home/devel
+
+    curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o rustup.sh
+    chmod +x rustup.sh
+    ./rustup.sh -y
+    source ~/.cargo/env
+    rustup target add x86_64-pc-windows-gnu
+
+    git clone https://aur.archlinux.org/yay.git --depth 1
+    (cd yay && makepkg -si --noconfirm --noprogressbar)
+    yay -Syu --answerdiff=None --verbose --noconfirm $AUR_BOOTSTRAP_MINGW
+    (cd mingw-w64-shaderc && makepkg -si --noconfirm --noprogressbar)
+    yay -Syu --answerdiff=None --verbose --noconfirm mingw-w64-glslang
+    yay -Syu --answerdiff=None --verbose --noconfirm $AUR_MINGW_2
+    yay -Syu --answerdiff=None --noconfirm $AUR_MISC $AUR_MINGW $AUR_QT_MINGW
+    go clean -cache
+EOF
+
+# Clear cache to reduce image size
+rm -rf /var/cache/pacman/pkg/ /var/lib/pacman/ /etc/pacman.d/gnupg/
+rm -rf /home/devel/yay /home/devel/.cache/yay
+rm /home/devel/rustup.sh
diff --git a/utils/scripts/docker/touch_files.bash b/utils/scripts/docker/touch_files.bash
new file mode 100755
index 0000000000000000000000000000000000000000..ecf319a7c7b47c5ec469fa96378dc21346a01dc0
--- /dev/null
+++ b/utils/scripts/docker/touch_files.bash
@@ -0,0 +1,16 @@
+#!/usr/bin/env bash
+set -e
+shopt -s globstar
+
+[ ! -f /src/.gitignore ] && {
+    echo "The source folder is not mounted in the docker"
+    exit 1
+}
+
+# Remove the thing we used to setup the build cache...
+rm -rf kurisu_api lektor_* lkt amadeus lektord
+
+# Get the sources...
+for THING in /src/*; do
+    cp -rf ${THING} .
+done