diff --git a/flake.nix b/flake.nix
index 2358ab1..7c17fff 100644
--- a/flake.nix
+++ b/flake.nix
@@ -18,11 +18,12 @@
         pkgs = import nixpkgs { inherit system; };
         patosPkgs = self.packages.${system};
         version = "0.0.1";
+        updateUrl = "http://10.0.2.2:8000";
       in
       {
         packages = {
           default = patosPkgs.image;
-          image = pkgs.callPackage ./pkgs/image { inherit patosPkgs version; };
+          image = pkgs.callPackage ./pkgs/image { inherit patosPkgs version updateUrl; };
           rootfs = pkgs.callPackage ./pkgs/rootfs/mkrootfs.nix { inherit patosPkgs version; };
           initrd = pkgs.callPackage ./pkgs/rootfs/mkinitrd.nix { inherit patosPkgs version; };
           kernel = pkgs.callPackage ./pkgs/kernel { };
diff --git a/pkgs/image/default.nix b/pkgs/image/default.nix
index 2084901..8f3acbf 100644
--- a/pkgs/image/default.nix
+++ b/pkgs/image/default.nix
@@ -3,13 +3,14 @@
   patosPkgs,
   version,
   runCommand,
-  ...
+  updateUrl
 }:
 let
   pname = "patos-image";
 in
 runCommand pname {
   inherit version;
+  inherit updateUrl;
 
   buildInputs = with pkgs; [
     erofs-utils
@@ -24,7 +25,7 @@ runCommand pname {
     SYSTEMD_REPART_MKFS_OPTIONS_EROFS = "--all-root"; # -zlz4hc,12 -C1048576 -Efragments,dedupe,ztailpacking";
   };
 
-  kernelCmdLine = "console=ttyS0";
+  kernelCmdLine = "console=ttyS0 patos.secureboot=true";
 }
 ''
 mkdir -p $out/init.repart.d $out/final.repart.d
@@ -70,6 +71,63 @@ ExecStartPost=rm -rf /boot/sbctl
 EOF
 ln -sf ../secure-boot-import-keys.service rootfs/usr/lib/systemd/system/sysinit.target.wants/secure-boot-import-keys.service
 
+# sysupdate
+mkdir -p rootfs/etc/sysupdate.d
+cat <<EOF > rootfs/etc/sysupdate.d/10-uki.transfer
+[Source]
+Path=${updateUrl}
+MatchPattern=patos_@v.efi
+Type=url-file
+
+[Target]
+InstancesMax=2
+MatchPattern=patos_@v+@l-@d.efi patos_@v+@l.efi patos_@v.efi
+Mode=0444
+Path=/EFI/Linux
+PathRelativeTo=esp
+TriesDone=0
+TriesLeft=3
+Type=regular-file
+
+[Transfer]
+Verify=no
+EOF
+
+cat <<EOF > rootfs/etc/sysupdate.d/20-root.transfer
+[Source]
+Type=url-file
+Path=${updateUrl}
+MatchPattern=patos_@v_@u.verity
+
+[Target]
+Type=partition
+Path=auto
+MatchPattern=verity-@v
+MatchPartitionType=root-verity
+ReadOnly=1
+
+[Transfer]
+Verify=no
+EOF
+
+cat <<EOF > rootfs/etc/sysupdate.d/22-root.transfer
+[Source]
+Type=url-file
+Path=${updateUrl}
+MatchPattern=patos_@v_@u.root
+
+[Target]
+Type=partition
+Path=auto
+MatchPattern=root-@v
+MatchPartitionType=root
+ReadOnly=1
+
+[Transfer]
+Verify=no
+EOF
+
+
 # Initial partitioning
 cat <<EOF > init.repart.d/10-root.conf
 [Partition]
@@ -146,8 +204,8 @@ cat <<EOF > final.repart.d/10-esp.conf
 [Partition]
 Type=esp
 Format=vfat
-SizeMinBytes=96M
-SizeMaxBytes=96M
+SizeMinBytes=128M
+SizeMaxBytes=128M
 CopyFiles=/rootfs/boot:/
 EOF
 
diff --git a/pkgs/rootfs/mkinitrd.nix b/pkgs/rootfs/mkinitrd.nix
index 5cc6411..10399a6 100644
--- a/pkgs/rootfs/mkinitrd.nix
+++ b/pkgs/rootfs/mkinitrd.nix
@@ -4,7 +4,12 @@
   runCommand,
   ...
 }:
+let
+  secureBootEnroll = ./secure-boot-enroll.sh;
+in
 runCommand "patos-initrd" {
+  inherit secureBootEnroll;
+
   buildInputs = with pkgs; [
     cpio
     xz
@@ -32,31 +37,7 @@ ln -sf /etc/os-release ./etc/initrd-release
 ln -sf initrd.target ./usr/lib/systemd/system/default.target
 
 # setup secure boot
-cat <<EOF > ./usr/bin/secure-boot-enroll
-#!/bin/sh
-set -ex -o pipefail
-
-SETUP_MODE=\$(sbctl status --json | xq -r '.setup_mode')
-
-[ "\$SETUP_MODE" = "false" ] && exit 0
-
-cat <<EOL> /run/sbctl.yml
----
-keydir: /sysroot/boot/sbctl/keys
-guid: /sysroot/boot/sbctl/GUID
-EOL
-
-ESP=\$(blkid --label ESP)
-
-mount \$ESP /sysroot/boot && \
-  sbctl --config /run/sbctl.yml create-keys && \
-  sbctl --config /run/sbctl.yml enroll-keys --yolo && \
-  # Sign EFIs
-  find /sysroot/boot -type f \( -iname "*.efi" -o -iname "*.EFI" \) -print0 | xargs -I {} sbctl --config /run/sbctl.yml sign {}
-
-umount /sysroot/boot && \
-  systemctl reboot -f
-EOF
+cat $secureBootEnroll > ./usr/bin/secure-boot-enroll
 chmod +x ./usr/bin/secure-boot-enroll
 
 cat <<EOF > ./usr/lib/systemd/system/secure-boot-enroll.service
diff --git a/pkgs/rootfs/mkrootfs.nix b/pkgs/rootfs/mkrootfs.nix
index f98a219..61e99d1 100644
--- a/pkgs/rootfs/mkrootfs.nix
+++ b/pkgs/rootfs/mkrootfs.nix
@@ -74,8 +74,8 @@ cat <<EOF > $out/etc/repart.d/10-esp.conf
 [Partition]
 Type=esp
 Format=vfat
-SizeMaxBytes=96M
-SizeMinBytes=96M
+SizeMaxBytes=128M
+SizeMinBytes=128M
 EOF
 
 cat <<EOF > $out/etc/repart.d/20-root-a.conf
@@ -178,7 +178,12 @@ cp -P ${pkgs.libbpf}/lib/libbpf*.so* $out/usr/lib/
 cp -P ${pkgs.sbctl}/bin/sbctl $out/usr/bin/
 rm -f $out/usr/bin/blkid
 cp -P ${pkgs.util-linuxMinimal}/bin/blkid $out/usr/bin/
+cp -P ${pkgs.util-linuxMinimal}/bin/lsblk $out/usr/bin/
+cp -P ${pkgs.bash}/bin/bash $out/usr/bin/
+
+### install xq (jq clone)
 cp -P ${pkgs.xq}/bin/xq $out/usr/bin/
+ln -sf /usr/bin/xq $out/usr/bin/jq
 
 ### install ca cert bundle
 chmod 755 $out/etc/ssl $out/etc/ssl/certs
diff --git a/pkgs/rootfs/secure-boot-enroll.sh b/pkgs/rootfs/secure-boot-enroll.sh
new file mode 100644
index 0000000..9546027
--- /dev/null
+++ b/pkgs/rootfs/secure-boot-enroll.sh
@@ -0,0 +1,37 @@
+#!/bin/bash
+set -ex -uo pipefail
+
+enroll=
+for o in $(< /proc/cmdline); do
+    case $o in
+        patos.secureboot=*)
+            enroll=${o#*=}
+            ;;
+    esac
+done
+
+if [ -z "$enroll" ]; then
+  echo 'No patos.secureboot= parameter on the kernel command line' >&2
+  exit 0
+fi
+
+SETUP_MODE=$(sbctl status --json | jq -r '.setup_mode')
+
+[ "$SETUP_MODE" = "false" -o "$enroll" != "true" ] && exit 0
+
+cat <<EOL> /run/sbctl.yml
+---
+keydir: /sysroot/boot/sbctl/keys
+guid: /sysroot/boot/sbctl/GUID
+EOL
+
+ESP=$(blkid --label ESP)
+
+mount $ESP /sysroot/boot && \
+  sbctl --config /run/sbctl.yml create-keys && \
+  sbctl --config /run/sbctl.yml enroll-keys --yolo && \
+  # Sign EFIs
+  find /sysroot/boot -type f \( -iname "*.efi" -o -iname "*.EFI" \) -print0 | xargs -I {} sbctl --config /run/sbctl.yml sign {}
+
+umount /sysroot/boot && \
+  systemctl reboot -f