diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 5a60de02e673c2c45089c0e116a55ded51eae115..857202f9df3b7732f9e5dfc712f3342de96cabe5 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -11,45 +11,140 @@ image: $DOCKER_IMAGE
 stages:
   - image
 
-######
-# Permissions fixup
-#
-# GitLab uses a too-lax umask when checking out the repositories, which leads
-# to root-owned  world-writable files being put in the images.
-#
-# The image-builder container defaults to umask 022 which would only affects
-# the w bit, so reset it for group and other users.
-#
-# See https://gitlab.com/gitlab-org/gitlab-runner/issues/1736
-before_script: &gitlab_permissions_fixup
-  - chmod -R og-w .
-  - chmod -R a-w overlays/sudo-fqdn
-
-build image rk3399:
-  stage: image
+stages:
+  - build
+  - generate
+  - lava
+
+.rootfs:
+  stage: build
+  before_script: &gitlab_permissions_fixup
+    - chmod -R og-w .
+    - chmod -R a-w overlays/sudo-fqdn
   script:
-    - export VERSION="$(date '+%Y%m%d.%H%M%S')"
     - mkdir out
+    - pushd out && debos -t architecture:${ARCHITECTURE} ../ospack.yaml && popd
+    - 'echo IMAGE_JOB_ID: \"${CI_JOB_ID}\" | tee -a out/image-build-job.yaml'
+    - 'echo ARCHITECTURE: \"${ARCHITECTURE}\" | tee -a out/image-build-job.yaml'
+  artifacts:
+    paths:
+      - out/*
+
+.kernel:
+  tags:
+    - lightweight
+  variables: &kernel_variables
+    DEBIAN_FRONTEND: noninteractive
+    GIT_STRATEGY: none
+  stage: build
+  script:
+    - mkdir dist
+    - "chdist -d dist create apertis https://repositories.apertis.org/apertis/ v2023pre target"
+    - cp /etc/apt/trusted.gpg.d/apertis-archive-keyring.gpg dist/apertis/etc/apt/trusted.gpg.d/
+    - "chdist -d dist -a ${ARCHITECTURE} apt apertis update"
+    - 'chdist -d dist -a ${ARCHITECTURE} apt apertis download "linux-image-*-${ARCHITECTURE}"'
+    - dpkg -x *.deb .
+    - mkdir -p out
+    - cp -v boot/vmlinuz* out
+    - if [ -d boot/dtbs ]  ; then cp -v boot/dtbs/*/*/*.dtb out ; fi
+    - depmod -b $(pwd)  $(basename $(echo lib/modules/*))
+    - tar cvzf out/modules.tar.gz lib/modules
+    - 'echo VMLINUZ: out/vmlinuz* | tee -a out/kernel-build-job.yaml'
+    - 'echo KERNEL_JOB_ID: \"${CI_JOB_ID}\" | tee -a out/kernel-build-job.yaml'
+  artifacts:
+    paths:
+      - out/*
+
+kernel arm64:
+  extends: .kernel
+  variables:
+    ARCHITECTURE: arm64
+    <<: *kernel_variables
+
+rootfs arm64:
+  extends: .rootfs
+  variables:
+    ARCHITECTURE: arm64
+
+kernel amd64:
+  extends: .kernel
+  variables:
+    ARCHITECTURE: amd64
+    <<: *kernel_variables
+
+rootfs amd64:
+  extends: .rootfs
+  variables:
+    ARCHITECTURE: amd64
+
+generate arm64 tests:
+  stage: generate
+  tags:
+    - lightweight
+  script:
+    - ./generate_lava_job.py
+        -e DEVICE_TYPE=bcm2711-rpi-4-b
+        -e DTB=bcm2711-rpi-4-b.dtb
+        -e BOOT_METHOD=u-boot
+        --env-file out/kernel-build-job.yaml
+        --env-file out/image-build-job.yaml > rpi.yaml
+    - ./generate_lava_job.py
+        -e DEVICE_TYPE=rk3399-roc-pc
+        -e DTB=rk3399-roc-pc.dtb
+        -e BOOT_METHOD=u-boot
+        --env-file out/kernel-build-job.yaml
+        --env-file out/image-build-job.yaml > renegade-elite.yaml
+  artifacts:
+    paths:
+      - "rpi.yaml"
+      - "renegade-elite.yaml"
+  needs:
+    - "rootfs arm64"
+    - "kernel arm64"
 
-    # build ospack
-    - debos
-        -t architecture:arm64
-        -t type:lava
-        -t suite:$APERTIS_SUITE
-        -t timestamp:$VERSION
-        --artifactdir=out
-        ${CI_PROJECT_DIR}/ospack.yaml
-
-    # build image
-    - debos
-        -t architecture:arm64
-        -t type:lava
-        -t suite:$APERTIS_SUITE
-        -t sbc:roc-pc-rk3399
-        -t image:lava
-        --artifactdir=out
-        ${CI_PROJECT_DIR}/image-rk3399.yaml
+generate amd64 test:
+  stage: generate
+  tags:
+    - lightweight
+  script:
+    - ./generate_lava_job.py
+        -e DEVICE_TYPE=aaeon-UPN-EHLX4RE-A10-0864
+        -e BOOT_METHOD=grub
+        --env-file out/kernel-build-job.yaml
+        --env-file out/image-build-job.yaml > up-squared.yaml
   artifacts:
-    expire_in: 7d
     paths:
-      - out
+      - "up-squared.yaml"
+  needs:
+    - "rootfs amd64"
+    - "kernel amd64"
+
+.lavatest:
+  stage: lava
+  tags:
+    - lava-runner
+  artifacts:
+    when: always
+    paths:
+      - log.yaml
+
+lava test rpi :
+  extends: .lavatest
+  script:
+    - submit rpi.yaml
+  needs:
+    - "generate arm64 tests"
+
+lava test renegade elite:
+  extends: .lavatest
+  script:
+    - submit renegade-elite.yaml
+  needs:
+    - "generate arm64 tests"
+
+lava test up squared:
+  extends: .lavatest
+  script:
+    - submit up-squared.yaml
+  needs:
+    - "generate amd64 test"
diff --git a/generate_lava_job.py b/generate_lava_job.py
new file mode 100755
index 0000000000000000000000000000000000000000..91a015fe4704dce7a030efa6b563435bf6d0a2e6
--- /dev/null
+++ b/generate_lava_job.py
@@ -0,0 +1,30 @@
+#!/usr/bin/env python3
+
+from jinja2 import Environment, FileSystemLoader
+import yaml
+import os
+import argparse
+
+class ParseKwargs(argparse.Action):
+    def __call__(self, parser, namespace, values, option_string=None):
+        key, value = values.split('=')
+        if getattr(namespace, self.dest) == None:
+            setattr(namespace, self.dest, dict())
+        getattr(namespace, self.dest)[key] = value
+
+parser = argparse.ArgumentParser(
+                    prog = 'generate_lava_job',
+                    description = 'GEeerate lava jobs')
+parser.add_argument('-e', '--env', action=ParseKwargs)
+parser.add_argument('--env-file', action='append')
+args = parser.parse_args()
+
+env = args.env
+for file in args.env_file:
+    s = open(file, 'r')
+    env = env | list(yaml.load_all(s, Loader=yaml.FullLoader))[0]
+
+jinja = Environment(loader=FileSystemLoader('.'))
+template = jinja.get_template('testjob.jinja2')
+data = template.render(env=env);
+print(data)
diff --git a/ospack.yaml b/ospack.yaml
index 9a313efe1795053a094fbae8147de147743e2baf..75e086a57da315ad359c1d7d5f791e2761db71c5 100644
--- a/ospack.yaml
+++ b/ospack.yaml
@@ -1,10 +1,10 @@
 {{- $architecture := or .architecture "amd64" }}
-{{- $type := or .type "ml-video-compression" -}}
+{{- $type := or .type "lava" -}}
 {{- $mirror := or .mirror "https://repositories.apertis.org/apertis/" -}}
 {{- $suite := or .suite "v2023pre" -}}
 {{- $timestamp := or .timestamp "" -}}
 {{- $snapshot := or .snapshot "" -}}
-{{- $ospack := or .ospack (printf "ospack_%s-%s-%s" $suite $architecture $type) -}}
+{{- $ospack := or .ospack (printf "rootfs-%s" $architecture) -}}
 {{- $pack := or .pack "true" -}}
 {{- $stable := or .stable "" -}}
 {{- $osname := or .osname "apertis" -}}
@@ -70,16 +70,6 @@ actions:
     packages:
       - busybox
       - dbus-user-session
-#      - udisks2 # for offline updates in apertis-update-manager
-#      - libblockdev-crypto2 # for offline updates in apertis-update-manager
-
-#  - action: apt
-#    description: "Firmware packages"
-#    packages:
-#      - firmware-realtek
-#      - firmware-atheros
-#      - firmware-iwlwifi
-#      - firmware-sof-signed
 
   - action: apt
     description: "Networking packages"
@@ -147,21 +137,6 @@ actions:
   - action: overlay
     source: overlays/fsck
 
-  - action: overlay
-    source: overlays/launch-user-session/
-
-  - action: run
-    chroot: true
-    description: Disable getty on tty1 as compositor will launch there
-    command: systemctl disable getty@tty1.service
-
-#  - action: overlay
-#    source: overlays/fixedfunction-static-site
-
-#  - action: overlay
-#    description: "Install ed25519 public keys for Flatpak"
-#    source: overlays/ed25519-flatpak
-
   - action: run
     chroot: true
     description: "Enable /tmp mount"
@@ -262,6 +237,16 @@ actions:
     chroot: false
     script: scripts/list-files "$ROOTDIR" | gzip > "${ARTIFACTDIR}/{{ $ospack }}.filelist.gz"
 
+  - action: run
+    description: Create a base kernel-less initramfs
+    chroot: true
+    command: mkinitramfs -o /boot/initramfs
+
+  - action: run
+    chroot: false
+    command: mv ${ROOTDIR}/boot/initramfs ${ARTIFACTDIR}/{{ $architecture }}-initramfs.gz
+
+
   - action: pack
     compression: gz
     file: {{ $ospack }}.tar.gz
diff --git a/testjob.jinja2 b/testjob.jinja2
new file mode 100644
index 0000000000000000000000000000000000000000..3a08403652229de3b6088f9ad219958e4393826d
--- /dev/null
+++ b/testjob.jinja2
@@ -0,0 +1,87 @@
+device_type: {{ env["DEVICE_TYPE"] }}
+
+job_name: electronica 2022
+timeouts:
+  job:
+    minutes: 15
+  action:
+   minutes: 5
+priority: high
+visibility: public
+
+{%- set gitlab_artifacts = '{{job.CI_API_V4_URL}}/projects/{{job.CI_PROJECT_ID}}/jobs/' -%}
+{%- set kernel_artifacts = gitlab_artifacts ~ env["KERNEL_JOB_ID"] ~ '/artifacts' -%}
+{%- set image_artifacts = gitlab_artifacts ~ env["IMAGE_JOB_ID"] ~ '/artifacts' %}
+
+actions:
+  - deploy:
+      timeout:
+        minutes: 2
+      to: tftp
+      kernel:
+        url: "{{kernel_artifacts}}/{{env['VMLINUZ']}}"
+        type: image
+        headers:
+           JOB-TOKEN: {{ '{{job.CI_JOB_TOKEN}}' }}
+      modules:
+        url: "{{kernel_artifacts}}/out/modules.tar.gz"
+        compression: gz
+        headers:
+           JOB-TOKEN: {{ '{{job.CI_JOB_TOKEN}}' }}
+{%- if env['DTB'] is defined %}
+      dtb:
+        url: "{{kernel_artifacts}}/out/{{env['DTB']}}"
+        headers:
+           JOB-TOKEN: {{ '{{job.CI_JOB_TOKEN}}' }}
+{%- endif %}
+      ramdisk:
+        url: "{{image_artifacts}}/out/{{env['ARCHITECTURE']}}-initramfs.gz"
+        compression: gz
+        headers:
+           JOB-TOKEN: {{ '{{job.CI_JOB_TOKEN}}' }}
+      nfsrootfs:
+        url: "{{image_artifacts}}/out/rootfs-{{env['ARCHITECTURE']}}.tar.gz"
+        compression: gz
+        headers:
+           JOB-TOKEN: {{ '{{job.CI_JOB_TOKEN}}' }}
+      os: oe
+
+  - boot:
+      method: {{ env['BOOT_METHOD'] }}
+      commands: nfs
+      timeout:
+        minutes: 10
+      auto_login:
+        login_prompt: 'login:'
+        username: user
+        password_prompt: 'Password:'
+        password: user
+        login_commands:
+          - sudo su
+          - env
+          - systemctl --failed
+      prompts:
+        - 'user@'
+        - 'root@'
+
+  - test:
+      timeout:
+        minutes: 1
+      definitions:
+      - repository:
+          metadata:
+            format: Lava-Test Test Definition 1.0
+            name: health
+            description: "health check"
+            os:
+              - apertis
+            scope:
+              - functional
+            environment:
+              - lava-test-shell
+          run:
+            steps:
+              - ps axf
+        from: inline
+        name: dmesg
+        path: inline/health.yaml