diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 79f586e5636e5c9435ba33ab92b52470c30aee54..fd8d8e9f743aead48dfb49e590f42fe303e3fb9b 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -14,17 +14,22 @@ stages:
     STORAGE_DRIVER: vfs
     BUILDAH_FORMAT: docker
     BUILDAH_ISOLATION: chroot
-    FQ_IMAGE_NAME: "$CI_REGISTRY_IMAGE/front:$CI_COMMIT_SHORT_SHA"
+    IMAGE_NAME: front
+    IMAGE_TAG: "$CI_COMMIT_SHORT_SHA"
+    REGISTRY_IMAGE: "$CI_REGISTRY_IMAGE/$IMAGE_NAME"
+    FQ_IMAGE_NAME: "$REGISTRY_IMAGE:$IMAGE_TAG"
     BUILD_CONTEXT: "."
     CONTAINERFILE: "front/Containerfile"
   before_script:
     - export REGISTRY_AUTH_FILE="$HOME/auth.json"
     - echo "$CI_REGISTRY_PASSWORD" | buildah login -u "$CI_REGISTRY_USER" --password-stdin "$CI_REGISTRY"
   script:
-    - buildah build -t "$FQ_IMAGE_NAME" -f "$CONTAINERFILE" "$BUILD_CONTEXT"
+    - buildah build -t "$FQ_IMAGE_NAME" -f "$CONTAINERFILE" $BUILD_CONTEXT
     - buildah push "$FQ_IMAGE_NAME"
+    - buildah tag "$FQ_IMAGE_NAME" "$REGISTRY_IMAGE:latest"
+    - buildah push "$REGISTRY_IMAGE:latest"
 
-build on gitlab.pasteur.fr:
+build front:
   extends: .build-with-buildah
   variables:
     PUBLIC_URL: "nyx.pasteur.cloud"
@@ -32,7 +37,7 @@ build on gitlab.pasteur.fr:
     - if: ($CI_COMMIT_BRANCH == "main" &&
         $CI_PROJECT_ID == $GITLAB_PASTEUR_PROJECT_ID)      # gitlab.pasteur.fr only
 
-build dev on gitlab.pasteur.fr:
+build dev front:
   extends: .build-with-buildah
   variables:
     PUBLIC_URL: "nyx.dev.pasteur.cloud"
@@ -40,25 +45,6 @@ build dev on gitlab.pasteur.fr:
     - if: ($CI_COMMIT_BRANCH == "dev" &&
         $CI_PROJECT_ID == $GITLAB_PASTEUR_PROJECT_ID)      # gitlab.pasteur.fr only
 
-.deploy-with-manifests:
-  stage: deploy
-  image: docker.io/enix/ci-toolbox:1.21
-  variables:
-    APP_NAME: nyxui
-    FQ_IMAGE_NAME: "$CI_REGISTRY_IMAGE/front:$CI_COMMIT_SHORT_SHA"
-  script:
-    - kubectl create secret
-      docker-registry registry-gitlab
-      --docker-server=registry-gitlab.pasteur.fr
-      --docker-username="$DOCKER_USER"
-      --docker-password="$DOCKER_TOKEN"
-      --docker-email=kubernetes@pasteur.fr
-      -n "$KUBE_NAMESPACE"
-      --dry-run=client -o yaml | kubectl apply -f -
-    - envsubst < k8s/front-deployment.yaml | kubectl apply -n "$KUBE_NAMESPACE" -f -
-    - envsubst < k8s/front-service.yaml | kubectl apply -n "$KUBE_NAMESPACE" -f -
-    - envsubst < k8s/ingress.yaml | kubectl apply -n "$KUBE_NAMESPACE" -f -
-
 .deploy-with-helm:
   stage: deploy
   image: docker.io/enix/ci-toolbox:1.21
@@ -81,16 +67,17 @@ build dev on gitlab.pasteur.fr:
 deploy to pasteur.cloud:
   extends: .deploy-with-helm
   variables:
-    SERVICE_TARGET_PORT: "8080"
     IMAGE_SECRETS: "registry-gitlab"
     KUBE_NAMESPACE: "nyx-prod"
     PUBLIC_URL: "nyx.pasteur.cloud"
     INGRESS_CLASS: "external"
     INGRESS_URL: "nyx.pasteur.cloud"
-    SERVICE_PORT: "80"
     LIMITS_CPU: "2"
-    LIMITS_MEMORY: "4Gi"
-    LIMITS_STORAGE: "1Gi"
+    LIMITS_MEMORY: "5Gi"
+    LIMITS_STORAGE: "4Gi"
+    LT_LIMITS_CPU: "2"
+    LT_LIMITS_MEMORY: "5Gi"
+    LT_LIMITS_STORAGE: "2Gi"
   environment:
     name: k8sprod-02/nyx-prod
     url: https://nyx.pasteur.cloud
@@ -102,16 +89,17 @@ deploy to pasteur.cloud:
 deploy to dev.pasteur.cloud:
   extends: .deploy-with-helm
   variables:
-    SERVICE_TARGET_PORT: "8080"
     IMAGE_SECRETS: "registry-gitlab"
     KUBE_NAMESPACE: "nyx-dev"
     PUBLIC_URL: "nyx.dev.pasteur.cloud"
     INGRESS_CLASS: "internal"
     INGRESS_URL: "nyx.dev.pasteur.cloud"
-    SERVICE_PORT: "80"
     LIMITS_CPU: "2"
-    LIMITS_MEMORY: "4Gi"
-    LIMITS_STORAGE: "1Gi"
+    LIMITS_MEMORY: "5Gi"
+    LIMITS_STORAGE: "4Gi"
+    LT_LIMITS_CPU: "2"
+    LT_LIMITS_MEMORY: "5Gi"
+    LT_LIMITS_STORAGE: "2Gi"
   environment:
     name: k8sdev-01/nyx-dev
     url: https://nyx.dev.pasteur.cloud
@@ -120,3 +108,16 @@ deploy to dev.pasteur.cloud:
         $CI_PROJECT_ID == $GITLAB_PASTEUR_PROJECT_ID)      # gitlab.pasteur.fr only
       when: manual
 
+build larvatagger backend:
+  extends: .build-with-buildah
+  variables:
+    IMAGE_NAME: "larvatagger"
+    IMAGE_TAG: "0.20.1-bigfat"
+    BUILD_CONTEXT: --build-arg LARVATAGGER_IMAGE_TAG=0.20.1-bigfat back
+    CONTAINERFILE: "back/Containerfile.larvatagger"
+  rules:
+    - if: ($CI_COMMIT_BRANCH == "dev" &&
+        $CI_PROJECT_ID == $GITLAB_PASTEUR_PROJECT_ID)       # gitlab.pasteur.fr only
+      when: manual                                          # on IMAGE_TAG update only; alias latest is used and
+      allow_failure: true                                   # should be confirmed to work when moving to branch main
+
diff --git a/Project.toml b/Project.toml
index c0988dd6a547e0f579a517e251b1c385ea5b8d2f..d4e91c2a9b2074c33ffa2c1b18d2e0d50a339547 100644
--- a/Project.toml
+++ b/Project.toml
@@ -1,7 +1,7 @@
 name = "NyxUI"
 uuid = "2c32e805-e4ca-4d0f-96f6-9d2d6204339d"
 authors = ["François Laurent <francois.laurent@pasteur.fr>"]
-version = "0.2.0"
+version = "0.2.1"
 
 [deps]
 Bonito = "824d6782-a2ef-11e9-3a09-e5662e0c26f8"
diff --git a/README.md b/README.md
index 4b6613d49b827be7f5327db4ddfc1184f91a04a3..f97582dddea39d74bb78cd820274f18fc7640eee 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ Web interface meant to be served at [nyx.pasteur.cloud](https://nyx.pasteur.clou
 It features an app catalog, with the following apps:
 
 * an editor for muscular activity programs,
-* [LarvaTagger.jl](https://gitlab.pasteur.fr/nyx/larvatagger.jl) without any automating tagging backends.
+* [LarvaTagger.jl](https://gitlab.pasteur.fr/nyx/larvatagger.jl) with two automating tagging backends.
 
 
 ## Local installation
@@ -24,10 +24,11 @@ cp front/Manifest.toml .
 juliaup add lts
 juliaup default lts
 julia --project=. -e 'using Pkg; Pkg.instantiate()'
+. back/larvatagger-no-build.sh
 julia --project=. routes.jl
 ```
 
-You may be asked whether to authorize ports 9284 and 9285; please give the app permission.
+You may be asked whether to authorize ports 9284, 9285 and 9286; please give the app permission.
 
 From there, in a web browser, open http://localhost:9284/ to access the app.
 
@@ -35,4 +36,9 @@ Note that the generated files can be found somewhere in directory *storage/expor
 
 The download buttons in the LarvaTagger app will not work in the web browser.
 To make them work, the reverse proxy setup in the container image called *front* is required.
-If you have [Podman](https://podman.io/), as an alternative to the above installation procedure, you can simply run `front/build.sh --now` and, once the container is up and running, connect to http://localhost:8080/.
+If you have [Podman](https://podman.io/), as an alternative to the above installation procedure, you can simply run the backend and frontend as follows:
+```
+. back/larvatagger-no-build.sh
+front/build.sh --now
+```
+Once the frontend container is up and running, connect to http://localhost:8080/.
diff --git a/back/Containerfile.larvatagger b/back/Containerfile.larvatagger
new file mode 100644
index 0000000000000000000000000000000000000000..963f0428d1ff978e2996a9348ba71be7a44123ac
--- /dev/null
+++ b/back/Containerfile.larvatagger
@@ -0,0 +1,58 @@
+ARG LARVATAGGER_IMAGE_TAG=0.20.1-bigfat
+FROM docker.io/flaur/larvatagger:${LARVATAGGER_IMAGE_TAG} as src
+
+
+FROM debian:bullseye as base
+
+# Python and Curl for Poetry
+RUN apt-get update \
+ && apt-get install --no-install-recommends -y python3-dev python3-pip curl \
+ && rm -rf /var/lib/apt/lists/*
+
+# Unprivileged environment
+ARG UID=1001
+
+RUN useradd julia -u ${UID} --user-group --create-home
+
+COPY --chown=julia --from=src /app /app/
+
+USER ${UID}
+
+# Poetry
+ENV POETRY_VERSION=1.8.4
+
+ENV POETRY_HOME=/app/poetry
+ENV POETRY_VIRTUALENVS_IN_PROJECT=1
+ENV PIP_DISABLE_PIP_VERSION_CHECK=1
+ENV PIP_NO_CACHE_DIR=1
+
+RUN curl -sSL https://install.python-poetry.org | python3 -
+
+# Julia
+ARG JULIA_VERSION=1.10.9
+
+ENV JULIA_PROJECT=/app
+ENV JULIA_DEPOT_PATH=/app/julia
+ENV JULIAUP_DEPOT_PATH=/app/juliaup
+
+RUN export HOME="${JULIA_PROJECT}" \
+ && curl -fsSL https://install.julialang.org \
+  | sh -s -- --yes --default-channel "${JULIA_VERSION}" \
+ && ${JULIA_PROJECT}/.juliaup/bin/juliaup config versionsdbupdateinterval 0
+
+ENV PATH "${PATH}:${JULIA_PROJECT}/.juliaup/bin:${POETRY_HOME}/bin"
+
+# LarvaTagger.jl/MaggotUBA-adapter/PasteurJanelia-adapter
+RUN cd "${JULIA_PROJECT}" \
+ && julia -e 'using Pkg; Pkg.instantiate()' \
+ && cd MaggotUBA \
+ && poetry install --only main \
+ && cd ../PasteurJanelia \
+ && poetry install --only main
+
+# final stage
+
+COPY --chown=julia larvatagger-entrypoint.sh /app/
+
+ENTRYPOINT ["/app/larvatagger-entrypoint.sh"]
+CMD []
diff --git a/back/larvatagger-build.sh b/back/larvatagger-build.sh
new file mode 100755
index 0000000000000000000000000000000000000000..dcbdefd4efd44f8c70416a87a345be5e1be2c282
--- /dev/null
+++ b/back/larvatagger-build.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+
+CONTAINERFILE=back/Containerfile.larvatagger
+
+if ! [ -f "$CONTAINERFILE" -a -f routes.jl ]; then
+  echo "Run $0 from the project root directory"
+  exit 1
+fi
+
+IMAGE=larvatagger-backend
+
+podman rmi -f $IMAGE || true
+
+podman build --tag $IMAGE -f "$CONTAINERFILE" back
+
+if [ "$1" = "--now" ]; then
+  podman run -d -p 9286:9286 $IMAGE
+
+  CONTAINER=`podman ps | grep $IMAGE | cut -d' ' -f1`
+
+  if [ -n "$CONTAINER" ]; then
+    echo "podman logs -f $CONTAINER"
+    sleep 1
+    podman logs -f $CONTAINER
+  fi
+fi
+
+export LARVATAGGER_BACKEND=http://localhost:9286
diff --git a/back/larvatagger-entrypoint.sh b/back/larvatagger-entrypoint.sh
new file mode 100755
index 0000000000000000000000000000000000000000..aa3148262e7ecbd5645582d987dbc231d0ad3486
--- /dev/null
+++ b/back/larvatagger-entrypoint.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+if [ -z "$LARVATAGGER_PORT" ]; then
+  LARVATAGGER_PORT=9286
+else
+  echo "Using environment variable: LARVATAGGER_PORT= $LARVATAGGER_PORT"
+fi
+
+if [ -z "$LARVATAGGER_TOKEN_EXPIRY" ]; then
+  LARVATAGGER_TOKEN_EXPIRY=14400
+else
+  echo "Using environment variable: LARVATAGGER_TOKEN_EXPIRY= $LARVATAGGER_TOKEN_EXPIRY"
+fi
+
+julia -e "using LarvaTagger.REST.Server; run_backend(\"/app\", $LARVATAGGER_TOKEN_EXPIRY; host=\"0.0.0.0\", port=$LARVATAGGER_PORT)"
diff --git a/back/larvatagger-no-build.sh b/back/larvatagger-no-build.sh
new file mode 100755
index 0000000000000000000000000000000000000000..7101dd78a518d69cc5900982cd093c28b29184bc
--- /dev/null
+++ b/back/larvatagger-no-build.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+# for tests with lightweight deployment
+
+if [ -z "$LARVATAGGER_PORT" ]; then
+  LARVATAGGER_PORT=9286
+else
+  echo "Using environment variable: LARVATAGGER_PORT= $LARVATAGGER_PORT"
+fi
+if [ -z "$LARVATAGGER_IMAGE" ]; then
+  LARVATAGGER_IMAGE=docker.io/flaur/larvatagger:0.20-bigfat
+else
+  echo "Using environment variable: LARVATAGGER_IMAGE= $LARVATAGGER_IMAGE"
+fi
+if [ -z "$LARVATAGGER_TOKEN_EXPIRY" ]; then
+  LARVATAGGER_TOKEN_EXPIRY=3600
+else
+  echo "Using environment variable: LARVATAGGER_TOKEN_EXPIRY= $LARVATAGGER_TOKEN_EXPIRY"
+fi
+
+podman run -d -p $LARVATAGGER_PORT:9285 --entrypoint=julia $LARVATAGGER_IMAGE --project=/app \
+  -e "using LarvaTagger.REST.Server; run_backend(\"/app\", $LARVATAGGER_TOKEN_EXPIRY; host=\"0.0.0.0\")"
+
+CONTAINER=`podman ps | grep $LARVATAGGER_IMAGE | cut -d' ' -f1`
+if ! [ -z "$CONTAINER" ]; then
+  echo "To monitor the LarvaTagger backend:"
+  echo "podman logs -f $CONTAINER"
+fi
+
+export LARVATAGGER_BACKEND=http://localhost:$LARVATAGGER_PORT
diff --git a/front/Containerfile b/front/Containerfile
index ca3adb2ca753e1ccc03e122f5601699f51eaeb6d..c788eb393e2502007750241730379d6f33192c04 100644
--- a/front/Containerfile
+++ b/front/Containerfile
@@ -16,7 +16,7 @@ ENV JULIA_PROJECT /app
 ENV JULIA_DEPOT_PATH /app/julia
 ENV JULIAUP_DEPOT_PATH /app/juliaup
 
-ARG JULIA_VERSION=1.10.8
+ARG JULIA_VERSION=1.10.9
 
 # UID/GID should match with same arguments defined in:
 # https://github.com/nginxinc/docker-nginx-unprivileged/blob/main/mainline/debian/Dockerfile
diff --git a/front/Containerfile.local b/front/Containerfile.local
index 1449a18a07a320562569f5b34085d88edbb3e1ea..d25b8dc6c2da4c909e9ce01c4b12d912aed9a010 100644
--- a/front/Containerfile.local
+++ b/front/Containerfile.local
@@ -6,7 +6,7 @@ COPY ./NyxUI.jl/front/proxy.conf /etc/nginx/conf.d/default.conf
 
 ENV JULIAUP_DEPOT_PATH /juliaup
 ENV JULIA_DEPOT_PATH /julia
-ARG JULIA_VERSION=1.10.8
+ARG JULIA_VERSION=1.10.9
 
 RUN curl -fsSL https://install.julialang.org \
   | sh -s -- --yes --default-channel $JULIA_VERSION
diff --git a/front/Manifest.toml b/front/Manifest.toml
index 7b87bea4414da2f15a4abc08c99fb472c32226cf..c55bc77741b68794a3f25a3b962a0272af08f286 100644
--- a/front/Manifest.toml
+++ b/front/Manifest.toml
@@ -1,6 +1,6 @@
 # This file is machine-generated - editing it directly is not advised
 
-julia_version = "1.10.8"
+julia_version = "1.10.9"
 manifest_format = "2.0"
 project_hash = "f30a6bd140cd9f9b66d3656725e83b8d83e18ee6"
 
@@ -833,12 +833,12 @@ uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f"
 version = "1.4.0"
 
 [[deps.LarvaTagger]]
-deps = ["Bonito", "Colors", "Dates", "DocOpt", "Format", "LinearAlgebra", "Logging", "Makie", "Meshes", "NearestNeighbors", "NyxWidgets", "Observables", "ObservationPolicies", "OrderedCollections", "PlanarLarvae", "Random", "StaticArrays", "Statistics", "TidyObservables", "WGLMakie"]
-git-tree-sha1 = "c9c185beb0bf417ed98afe9b8b9da557a0b886b7"
+deps = ["Bonito", "Colors", "Dates", "DocOpt", "Format", "HTTP", "JSON3", "LinearAlgebra", "Logging", "Makie", "Meshes", "NearestNeighbors", "NyxWidgets", "Observables", "ObservationPolicies", "OrderedCollections", "Oxygen", "PlanarLarvae", "Random", "StaticArrays", "Statistics", "TidyObservables", "WGLMakie"]
+git-tree-sha1 = "0b405b69b603ef4df736142907a32ab81df20215"
 repo-rev = "main"
 repo-url = "https://gitlab.pasteur.fr/nyx/larvatagger.jl"
 uuid = "8b3b36f1-dfed-446e-8561-ea19fe966a4d"
-version = "0.19.1"
+version = "0.20.1"
 
 [[deps.LazyArtifacts]]
 deps = ["Artifacts", "Pkg"]
@@ -1182,7 +1182,7 @@ version = "3.2.4+0"
 [[deps.OpenLibm_jll]]
 deps = ["Artifacts", "Libdl"]
 uuid = "05823500-19ac-5b8b-9628-191a04bc5112"
-version = "0.8.1+2"
+version = "0.8.1+4"
 
 [[deps.OpenMPI_jll]]
 deps = ["Artifacts", "CompilerSupportLibraries_jll", "Hwloc_jll", "JLLWrappers", "LazyArtifacts", "Libdl", "MPIPreferences", "TOML", "Zlib_jll"]
@@ -1219,6 +1219,12 @@ git-tree-sha1 = "12f1439c4f986bb868acda6ea33ebc78e19b95ad"
 uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d"
 version = "1.7.0"
 
+[[deps.Oxygen]]
+deps = ["DataStructures", "Dates", "HTTP", "JSON3", "MIMEs", "Reexport", "RelocatableFolders", "Requires", "Sockets", "Statistics", "StructTypes"]
+git-tree-sha1 = "2ad010b0de6172faf1d09ed5e0837eb0b7355bd8"
+uuid = "df9a0d86-3283-4920-82dc-4555fc0d1d8b"
+version = "1.5.16"
+
 [[deps.PCRE2_jll]]
 deps = ["Artifacts", "Libdl"]
 uuid = "efcefdf7-47ab-520b-bdef-62a2eaa19f15"
diff --git a/front/build-run-local.sh b/front/build-run-local.sh
index 79c9f43c516b343ebe6ad3c278c5d3cd2efc4a21..3aeaf2cf5830e21d597b2c1020197a569d04638d 100755
--- a/front/build-run-local.sh
+++ b/front/build-run-local.sh
@@ -18,7 +18,7 @@ podman build --tag $IMAGE -f "$CONTAINERFILE" .. # --no-cache
 #mkdir -p public
 
 podman run -d -p 8081:80 -p 9484:9284 -p 9485:9285 \
-  $IMAGE
+  -e LARVATAGGER_BACKEND $IMAGE
 
 CONTAINER=`podman ps | grep $IMAGE | cut -d' ' -f1`
 
diff --git a/front/build.sh b/front/build.sh
index 02619d93707323be1424da296f75d23b03c4f9ee..1b9693e7604222abb0d8f84078505bb916cc64ba 100755
--- a/front/build.sh
+++ b/front/build.sh
@@ -14,7 +14,7 @@ podman rmi -f $IMAGE || true
 podman build --tag $IMAGE -f "$CONTAINERFILE" .
 
 if [ "$1" = "--now" ]; then
-  podman run -d -p 8080:8080 $IMAGE
+  podman run -d -p 8080:8080 -e LARVATAGGER_BACKEND $IMAGE
 
   CONTAINER=`podman ps | grep $IMAGE | cut -d' ' -f1`
 
diff --git a/front/entrypoint.sh b/front/entrypoint.sh
index ae9288c705d3be255e713840b01b6dda44475ac1..035824383afd539fbaf57417a5c0d6380ba9c982 100644
--- a/front/entrypoint.sh
+++ b/front/entrypoint.sh
@@ -2,6 +2,17 @@
 
 set -m
 
+cd /app
+
+if [ -f "front/.env" ]; then
+  echo "Found dotenv file:"
+  echo "------------------"
+  cat front/.env
+  echo "------------------"
+  export `cat front/.env | xargs`
+fi
+LARVATAGGER_BACKEND=`echo $LARVATAGGER_BACKEND | sed "s/localhost/host.containers.internal/"`
+
 
 /docker-entrypoint.sh nginx -g "daemon off;" &>/dev/null &
 NGINX_PID=$!
diff --git a/nyxui/Chart.yaml b/nyxui/Chart.yaml
index 567ea86302b3a01ca09c28aa9ff20c3b221acfe9..0126bd73d2b6b45bfc01440c03ffad743acd82c3 100644
--- a/nyxui/Chart.yaml
+++ b/nyxui/Chart.yaml
@@ -15,10 +15,10 @@ type: application
 # This is the chart version. This version number should be incremented each time you make changes
 # to the chart and its templates, including the app version.
 # Versions are expected to follow Semantic Versioning (https://semver.org/)
-version: 0.2.0
+version: 0.2.1
 
 # This is the version number of the application being deployed. This version number should be
 # incremented each time you make changes to the application. Versions are not expected to
 # follow Semantic Versioning. They should reflect the version the application is using.
 # It is recommended to use it with quotes.
-appVersion: "0.2.0"
+appVersion: "0.2.1"
diff --git a/nyxui/templates/configmap-front.yaml b/nyxui/templates/configmap-front.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..5505c88ba7f881e8cd9edbba2840e5e50e33ffdc
--- /dev/null
+++ b/nyxui/templates/configmap-front.yaml
@@ -0,0 +1,9 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ include "nyxui.name" . }}-front-config
+  labels:
+    {{- include "nyxui.labels" . | nindent 4 }}
+data:
+  .env: |
+    LARVATAGGER_BACKEND=http://{{ include "nyxui.name" . }}-larvatagger:{{ .Values.service.port }}
diff --git a/nyxui/templates/deployment-front.yaml b/nyxui/templates/deployment-front.yaml
index e4319b60f95077b28ca3c82ebbb063a4c36914a9..d54718c230320e9a2b843afca2e5c0ca43c6f36e 100644
--- a/nyxui/templates/deployment-front.yaml
+++ b/nyxui/templates/deployment-front.yaml
@@ -1,7 +1,7 @@
 apiVersion: apps/v1
 kind: Deployment
 metadata:
-  name: {{ include "nyxui.name" . }}
+  name: {{ include "nyxui.name" . }}-front
   labels:
     {{- include "nyxui.labels" . | nindent 4 }}
 spec:
@@ -19,6 +19,7 @@ spec:
       {{- end }}
       labels:
         {{- include "nyxui.labels" . | nindent 8 }}
+        app.kubernetes.io/component: front
         {{- with .Values.podLabels }}
         {{- toYaml . | nindent 8 }}
         {{- end }}
@@ -45,13 +46,19 @@ spec:
           readinessProbe:
             {{- toYaml .Values.readinessProbe | nindent 12 }}
           resources:
-            {{- toYaml .Values.resources | nindent 12 }}
-          {{- with .Values.volumeMounts }}
+            {{- toYaml .Values.front.resources | nindent 12 }}
           volumeMounts:
+            - name: front-config
+              mountPath: /app/front/.env
+              subPath: .env
+          {{- with .Values.volumeMounts }}
             {{- toYaml . | nindent 12 }}
           {{- end }}
-      {{- with .Values.volumes }}
       volumes:
+        - name: front-config
+          configMap:
+            name: nyxui-front-config
+      {{- with .Values.volumes }}
         {{- toYaml . | nindent 8 }}
       {{- end }}
       {{- with .Values.nodeSelector }}
diff --git a/nyxui/templates/deployment-larvatagger.yaml b/nyxui/templates/deployment-larvatagger.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e47504b514bb3111a860a6f4d322d3fd91fe7e7f
--- /dev/null
+++ b/nyxui/templates/deployment-larvatagger.yaml
@@ -0,0 +1,69 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: {{ include "nyxui.name" . }}-larvatagger
+  labels:
+    {{- include "nyxui.labels" . | nindent 4 }}
+spec:
+  {{- if not .Values.autoscaling.enabled }}
+  replicas: {{ .Values.replicaCount }}
+  {{- end }}
+  selector:
+    matchLabels:
+      {{- include "nyxui.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      {{- with .Values.podAnnotations }}
+      annotations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      labels:
+        {{- include "nyxui.labels" . | nindent 8 }}
+        app.kubernetes.io/component: larvatagger
+        {{- with .Values.podLabels }}
+        {{- toYaml . | nindent 8 }}
+        {{- end }}
+    spec:
+      {{- with .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      serviceAccountName: {{ include "nyxui.serviceAccountName" . }}
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+      containers:
+        - name: {{ .Chart.Name }}
+          securityContext:
+            {{- toYaml .Values.securityContext | nindent 12 }}
+          image: "{{ .Values.larvatagger.image.repository }}/{{ .Values.larvatagger.image.name }}:{{ .Values.larvatagger.image.tag }}"
+          imagePullPolicy: {{ .Values.larvatagger.image.pullPolicy }}
+          ports:
+            - name: http
+              containerPort: {{ .Values.larvatagger.service.targetPort }}
+              protocol: TCP
+          livenessProbe:
+            {{- toYaml .Values.livenessProbe | nindent 12 }}
+          readinessProbe:
+            {{- toYaml .Values.readinessProbe | nindent 12 }}
+          resources:
+            {{- toYaml .Values.larvatagger.resources | nindent 12 }}
+          {{- with .Values.volumeMounts }}
+          volumeMounts:
+            {{- toYaml . | nindent 12 }}
+          {{- end }}
+      {{- with .Values.volumes }}
+      volumes:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.nodeSelector }}
+      nodeSelector:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
diff --git a/nyxui/templates/ingress.yaml b/nyxui/templates/ingress.yaml
index 79522d81581951e662142e67a07a2f658f1dbbc0..03b430ca4f4babe57d49441578a6e7c74322f7f3 100644
--- a/nyxui/templates/ingress.yaml
+++ b/nyxui/templates/ingress.yaml
@@ -49,11 +49,11 @@ spec:
             backend:
               {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
               service:
-                name: {{ $fullName }}
+                name: {{ .serviceName }}
                 port:
                   number: {{ $svcPort }}
               {{- else }}
-              serviceName: {{ $fullName }}
+              serviceName: {{ .serviceName }}
               servicePort: {{ $svcPort }}
               {{- end }}
           {{- end }}
diff --git a/nyxui/templates/service.yaml b/nyxui/templates/service-front.yaml
similarity index 79%
rename from nyxui/templates/service.yaml
rename to nyxui/templates/service-front.yaml
index 60862517ccbf08121aa79a056685be0af95c2916..5bdec4b94120fe572c8423f0401cf2809d45c81a 100644
--- a/nyxui/templates/service.yaml
+++ b/nyxui/templates/service-front.yaml
@@ -1,7 +1,7 @@
 apiVersion: v1
 kind: Service
 metadata:
-  name: {{ include "nyxui.name" . }}
+  name: {{ include "nyxui.name" . }}-front
   labels:
     {{- include "nyxui.labels" . | nindent 4 }}
 spec:
@@ -13,3 +13,4 @@ spec:
       name: http
   selector:
     {{- include "nyxui.selectorLabels" . | nindent 4 }}
+    app.kubernetes.io/component: front
diff --git a/nyxui/templates/service-larvatagger.yaml b/nyxui/templates/service-larvatagger.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..32ac7f4c92105f2d576ecc102576c961e828c9dc
--- /dev/null
+++ b/nyxui/templates/service-larvatagger.yaml
@@ -0,0 +1,16 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "nyxui.name" . }}-larvatagger
+  labels:
+    {{- include "nyxui.labels" . | nindent 4 }}
+spec:
+  type: {{ .Values.service.type }}
+  ports:
+    - port: {{ .Values.service.port }}
+      targetPort: http
+      protocol: TCP
+      name: http
+  selector:
+    {{- include "nyxui.selectorLabels" . | nindent 4 }}
+    app.kubernetes.io/component: larvatagger
diff --git a/nyxui/values.yaml b/nyxui/values.yaml
index c7bde4b53aa898e7b498be9c48dd79fee0850467..4eacdc45d699d9c4fc5b3c2c480d2e3b1fa4df87 100644
--- a/nyxui/values.yaml
+++ b/nyxui/values.yaml
@@ -12,6 +12,33 @@ front:
     pullPolicy: Always
   service:
     targetPort: 8080
+  resources:
+    limits:
+      cpu: "2"
+      memory: 4Gi
+      ephemeral-storage: 1Gi
+    requests:
+      cpu: "2"
+      memory: 4Gi
+      ephemeral-storage: 1Gi
+
+larvatagger:
+  image:
+    repository: registry-gitlab.pasteur.fr/nyx/nyxui.jl
+    name: larvatagger
+    tag: latest
+    pullPolicy: Always
+  service:
+    targetPort: 9286
+  resources:
+    limits:
+      cpu: "2"
+      memory: 4Gi
+      ephemeral-storage: 4Gi
+    requests:
+      cpu: "2"
+      memory: 4Gi
+      ephemeral-storage: 4Gi
 
 imagePullSecrets:
   - name: registry-gitlab
@@ -60,21 +87,12 @@ ingress:
       paths:
         - path: /
           pathType: Prefix
+          serviceName: nyxui-front
   tls: []
   #  - secretName: chart-example-tls
   #    hosts:
   #      - chart-example.local
 
-resources: 
-  limits:
-    cpu: "2"
-    memory: 4Gi
-    ephemeral-storage: 1Gi
-  requests:
-    cpu: "2"
-    memory: 4Gi
-    ephemeral-storage: 1Gi
-
 autoscaling:
   enabled: false
   minReplicas: 1
@@ -82,18 +100,11 @@ autoscaling:
   targetCPUUtilizationPercentage: 80
   # targetMemoryUtilizationPercentage: 80
 
-# Additional volumes on the output Deployment definition.
+# Additional shared volumes on the output Deployment definitions.
 volumes: []
-# - name: foo
-#   secret:
-#     secretName: mysecret
-#     optional: false
 
-# Additional volumeMounts on the output Deployment definition.
+# Additional shared volumeMounts on the output Deployment definitions.
 volumeMounts: []
-# - name: foo
-#   mountPath: "/etc/foo"
-#   readOnly: true
 
 nodeSelector: {}
 
diff --git a/src/GenieExtras.jl b/src/GenieExtras.jl
index 40cf48a4fa308ea6ab9a3b9c735bfdc133852c19..ebe416c469fe35307a2cbe5faa8386b83008bf6e 100644
--- a/src/GenieExtras.jl
+++ b/src/GenieExtras.jl
@@ -1,8 +1,11 @@
 module GenieExtras
 
 import Genie.Renderer.Html
+import GenieSession: GenieSession, Session
+using NyxWidgets.Base: Cache
 
-export publish_css, appinfo, add_footer
+export publish_css, appinfo, add_footer, Session, SessionRegistry, getsessionid, getsession,
+       clearexpired
 
 const project_root = dirname(Base.current_project())
 
@@ -49,4 +52,129 @@ add_footer(ui::AbstractString, footer=footer) = "$ui$(footer())"
 
 add_footer(ui::Function, footer=footer) = () -> add_footer(ui(), footer)
 
+struct SessionRegistry
+    register
+    idlength
+    purgesession
+    purgesession_args
+end
+
+function SessionRegistry(f, args=(:session_id,); idlength=32)
+    SessionRegistry(Cache{String, Dict{Symbol, Any}}(), idlength, f, args)
+end
+
+Base.lock(f::Function, registry::SessionRegistry) = lock(f, registry.register)
+
+function check_session_id_length(registry, session_id)
+    if !isnothing(registry.idlength) && length(session_id) < registry.idlength
+        throw("wrong session_id length")
+    end
+end
+
+function Base.haskey(registry::SessionRegistry, session_id::AbstractString)
+    lock(registry) do
+        for session_long_id in keys(registry.register.cache)
+            if startswith(session_long_id, session_id)
+                return true
+            end
+        end
+        return false
+    end
+end
+
+function Base.getindex(registry::SessionRegistry, session_id::AbstractString)
+    check_session_id_length(registry, session_id)
+    lock(registry) do
+        for (session_long_id, records) in pairs(registry.register.cache)
+            if startswith(session_long_id, session_id)
+                records[:lastseen] = time()
+                return records
+            end
+        end
+        throw(KeyError(session_id))
+    end
+end
+
+Base.getindex(registry::SessionRegistry, session_id::AbstractString, record::Symbol
+             ) = registry[session_id][record]
+
+function getsessionid(session_long_id::String, idlength::Union{Nothing, <:Integer})
+    session_id = session_long_id
+    if !isnothing(idlength)
+        session_id = string(session_id[1:idlength])
+    end
+    return session_id
+end
+
+function getsessionid(registry::SessionRegistry)
+    session = GenieSession.session()
+    session_long_id = session.id
+    session_id = getsessionid(session_long_id, registry.idlength)
+    # create the entry in the register if missing
+    records = lock(registry) do
+        register = registry.register.cache
+        if session_id != session_long_id && session_id in keys(register)
+            # if the session has been registered with its short id (and `getsession`),
+            # update the short id with the long one
+            register[session_long_id] = pop!(register, session_id)
+        else
+            # registry.register is a NyxWidgets.Cache and `getindex` behaves like `get!`
+            registry.register[session_long_id]
+        end
+    end
+    # register minimum information
+    records[:session] = session
+    records[:lastseen] = time()
+    # run maintenance routine
+    clearexpired(registry)
+    return session_id
+end
+
+function getsession(registry::SessionRegistry, session_id::AbstractString)
+    if haskey(registry, session_id) # check for long id
+        registry[session_id]
+    else # call get! on short id (if session_id is short); not ideal
+        registry.register[session_id]
+    end
+end
+
+function clearexpired(registry, expiry::Real=604800)
+    lock(registry) do
+        register = registry.register.cache
+        for (session_long_id, records) in pairs(register)
+            if !haskey(records, :lastseen)
+                @warn "Missing key: lastseen"
+                continue
+            end
+            expiry <= time() - records[:lastseen] || continue
+            # prepare to clear the session; collect the arguments to purgesession
+            session_id = getsessionid(session_long_id, registry.idlength)
+            available_args = Dict(:session_id=>session_id,
+                                  :session_long_id=>session_long_id,
+                                  records...)
+            @info "Purging session" session_id
+            pop!(register, session_long_id)
+            if haskey(records, :session)
+                session = records[:session]
+                # see learn.genieframework.com/framework/genie.jl/recipes/session
+                empty!(session.data)
+            else
+                @warn "Missing key: session"
+            end
+            #
+            function get′(arg)
+                get(available_args, arg) do
+                    @warn "Missing argument for purgesession" arg
+                    nothing
+                end
+            end
+            try
+                registry.purgesession(get′.(registry.purgesession_args)...)
+            catch
+                @error "\`purgesession\` callback failed"
+            end
+        end
+    end
+end
+
 end
diff --git a/src/apps/catalog/app.jl b/src/apps/catalog/app.jl
index cc5c45f9791c9adea27df3892548c63051ec4e4e..4ae5596fcacbd34cff5b7b5d93fc792d66f50ef1 100644
--- a/src/apps/catalog/app.jl
+++ b/src/apps/catalog/app.jl
@@ -36,9 +36,7 @@ function app_catalog_view()
             ]))),
             item(item(class=app, Html.a(href=Router.link_to(:get_larvatagger), [
                 Html.h1("LarvaTagger", style=header2),
-                imageview(src="/images/LarvaTagger.png", style=img,
-                    Html.div(class=caption, "Partially available"),
-                ),
+                imageview(src="/images/LarvaTagger.png", style=img),
             ]))),
         ]),
     ])
diff --git a/src/apps/larvatagger/app.jl b/src/apps/larvatagger/app.jl
index dbdea6201e1c0fe84e2a892f9758f348ceaa7d84..7b3081623789d4afc10123143615d6dcce0ebebe 100644
--- a/src/apps/larvatagger/app.jl
+++ b/src/apps/larvatagger/app.jl
@@ -3,7 +3,7 @@ module LarvaTagger
 using NyxUI, NyxUI.Storage, NyxUI.GenieExtras
 using NyxWidgets.Base: Cache
 import LarvaTagger as LT
-using GenieSession, Stipple
+using Stipple
 import Stipple: @app, @init, @private, @in, @onchange, @onbutton, @click
 import StippleUI: tooltip
 
@@ -16,21 +16,33 @@ mutable struct Model
     sizefactor
     app # TODO: check whether explicitly closing apps helps
     appdata
+    kwargs
 end
 
-const bonito_models = Cache{String, Model}()
+function purgesession(model, session_id)
+    if isnothing(model)
+        @warn "Session data prematurely lost"
+    elseif !isnothing(model.app)
+        close(model.app)
+    end
+    purge_appdata(session_id, "larvatagger")
+    BonitoServer.addsession(bonito_app, session_id; restart=true)
+end
+
+const session_registry = SessionRegistry(purgesession, (:model, :session_id))
 
 const bonito_app = NamedApp("larvatagger",
     function (session)
         bucket = getbucket(session, "larvatagger", :read)
         mkpath(bucket)
-        model = lock(bonito_models) do
-            if haskey(bonito_models, session)
-                bonito_models.cache[session]
-            else
-                inputfile = Ref{Union{Nothing, String}}(nothing)
-                bonito_models.cache[session] = Model(1.0, nothing, inputfile)
+        model = get!(getsession(session_registry, session), :model) do
+            kwargs = Dict{Symbol, Any}()
+            if !isempty(get(ENV, "LARVATAGGER_BACKEND", ""))
+                kwargs[:backend_directory] = backend = ENV["LARVATAGGER_BACKEND"]
+                @info "Using environment variable" LARVATAGGER_BACKEND=backend
             end
+            inputfile = Ref{Union{Nothing, String}}(nothing)
+            Model(1.0, nothing, inputfile, kwargs)
         end
         exportdir = joinpath("public", session, "larvatagger")
         function prepare_download(srcfile)
@@ -54,18 +66,15 @@ const bonito_app = NamedApp("larvatagger",
                                          prepare_download=prepare_download,
                                          enable_new_directories=true,
                                          enable_delete=true,
-                                         viewfactor=model.sizefactor)
+                                         viewfactor=model.sizefactor,
+                                         model.kwargs...)
         return app
     end
 )
 
-function purgesession(session)
-    model = lock(bonito_models) do
-        pop!(bonito_models.cache, session)
-    end
-    isnothing(model.app) || close(model.app)
-    purge_appdata(session, "larvatagger")
-    BonitoServer.addsession(bonito_app, session; restart=true)
+function purgesession(session_id)
+    model = pop!(session_registry[session_id], :model, nothing)
+    purgesession(model, session_id)
 end
 
 
@@ -75,10 +84,10 @@ end
     @in reset_bonito_session = false
 
     @onchange isready begin
-        genie_session = GenieSession.session()
-        bonito_session_id = genie_session.id[1:32]
-        if haskey(bonito_models, bonito_session_id)
-            sizefactor = sizefactors_str[bonito_models[bonito_session_id].sizefactor]
+        bonito_session_id = getsessionid(session_registry)
+        if haskey(session_registry[bonito_session_id], :model)
+            model = session_registry[bonito_session_id, :model]
+            sizefactor = sizefactors_str[model.sizefactor]
         else
             BonitoServer.addsession(bonito_app, bonito_session_id)
         end
@@ -96,9 +105,10 @@ end
 
     @onchange sizefactor begin
         new_sizefactor = sizefactors[sizefactor]
-        if new_sizefactor != bonito_models[bonito_session_id].sizefactor
+        model = session_registry[bonito_session_id, :model]
+        if new_sizefactor != model.sizefactor
             @info "New size factor; refreshing the iframe"
-            bonito_models[bonito_session_id].sizefactor = new_sizefactor
+            model.sizefactor = new_sizefactor
             BonitoServer.addsession(bonito_app, bonito_session_id; restart=true) # restart
             width = appwidth[sizefactor]
             height = appheight[sizefactor]
@@ -112,7 +122,11 @@ end
     end
 
     @onbutton reset_bonito_session begin
-        purgesession(bonito_session_id)
+        try
+            purgesession(bonito_session_id)
+        catch
+            @error "Error while resetting session"
+        end
         # reset UI to defaults
         bonito_session_id[!] = ""
         sizefactor[!] = "1.0"
diff --git a/src/apps/muscles/Backbone.jl b/src/apps/muscles/Backbone.jl
index 5547f559f2007fab4c3a50d8d513536747340842..320d21489b037d1d5de6778dec93bed2a08ede2a 100644
--- a/src/apps/muscles/Backbone.jl
+++ b/src/apps/muscles/Backbone.jl
@@ -3,6 +3,7 @@ module Backbone
 using NyxWidgets.Base: Cache
 using NyxUI.MuscleActivities
 using NyxUI.Storage
+using NyxUI.GenieExtras
 using Bonito
 
 include("MuscleWidgets.jl")
@@ -11,58 +12,37 @@ using .MuscleWidgets
 export hasmodel, getmodel, setmodel, newsequence, getsequence, withsequences,
        exportsequence, loadsequence, deletesequence, purgesession
 
-# mutable struct Backbone{W}
-#     widget::Union{Nothing, W}
-#     channel::Observable{Bonito.JSCode}
-# end
-#
-# Backbone{W}() where {W} = Backbone{W}(nothing)
-#
-# Backbone{W}(widget::W) where {W} = Backbone{W}(widget, Observable(js""))
-#
-# Backbone(widget::W) where {W} = Backbone{W}(widget)
-#
-# function Bonito.jsrender(session::Session, widget::Backbone)
-#     isnothing(widget.widget) && error("backbone widget not initialized")
-#     on(session, widget.channel) do jscode
-#         evaljs(session, jscode)
-#     end
-#     Bonito.jsrender(session, widget.widget)
-# end
-
 ## models
 
-const __backbone_cache__ = Cache{String, MuscleWidget}()
-const __valid_sessions__ = Dict{String, Bool}()
+function purgesession end
+
+const session_registry = SessionRegistry(purgesession, (:session_id, ))
 
 function app(persistent=""; title="Nyx muscle activity")
     App(; title=title) do session
-        # # embedded apps are always renderded twice; save time # EDIT: except on Ctrl+R
-        # valid = get(__valid_sessions__, persistent, false)
-        # __valid_sessions__[persistent] = !valid
-        # valid || return
         @info "New session" session.id
         cache_id = isempty(persistent) ? session.id : persistent
-        model = __backbone_cache__[cache_id]
+        model = session_registry[cache_id, :model]
         Bonito.jsrender(session, model)
     end
 end
 
 ## muscle model
 
-getmodel(session_id) = __backbone_cache__[session_id]#.widget
+getmodel(session_id) = session_registry[session_id, :model]
 
-# for debugging
-getmodel() = first(values(__backbone_cache__))#.widget
-
-hasmodel(session_id) = haskey(__backbone_cache__, session_id)
+hasmodel(session_id) = haskey(session_registry[session_id], :model)
 
 function setmodel(session_id, sequence)
-    __backbone_cache__[session_id] = MuscleWidget(sequence)
+    records = getsession(session_registry, session_id)
+    records[:model] = model = MuscleWidget(sequence)
+    # init :sequences
+    get!(records, :sequences) do
+        Cache{Int, MuscleActivity}()
+    end
+    return model
 end
 
-# getchannel(session_id) = __backbone_cache__[session_id].channel
-
 ## sequence model
 
 function newsequencename(stem, existing)
@@ -97,14 +77,13 @@ function newsequence(session_id, sequence_name, sequence_names, start_time, time
     return sequence
 end
 
-const __sequences__ = Cache{String, Cache{Int, MuscleActivity}}()
-
 function getsequence(session_id, sequence_name)
     model = getmodel(session_id)
     sequence = nothing
     if model.sequence[].program_name != sequence_name
-        lock(__sequences__[session_id]) do
-            for outer sequence in values(__sequences__[session_id])
+        sequences = session_registry[session_id, :sequences]
+        lock(sequences) do
+            for outer sequence in values(sequences)
                 sequence.program_name == sequence_name && break
             end
         end
@@ -116,16 +95,16 @@ end
 getsequence(session_id) = getmodel(session_id).sequence[]
 
 function addsequence(session_id, sequence)
-    lock(__sequences__[session_id]) do
-        sequences = __sequences__[session_id]
+    sequences = session_registry[session_id, :sequences]
+    lock(sequences) do
         i = isempty(sequences) ? 0 : maximum(keys(sequences))
         sequences[i+1] = sequence
     end
 end
 
 function withsequences(f, session_id)
-    lock(__sequences__[session_id]) do
-        sequences = __sequences__[session_id]
+    sequences = session_registry[session_id, :sequences]
+    lock(sequences) do
         return f(sequences)
     end
 end
@@ -153,7 +132,7 @@ end
 function deletesequence(session_id)
     model = getmodel(session_id)
     current = model.sequence[].program_name
-    sequences = __sequences__[session_id]
+    sequences = session_registry[session_id, :sequences]
     lock(sequences) do
         for (ix, seq) in pairs(sequences)
             if seq.program_name == current
@@ -167,19 +146,7 @@ function deletesequence(session_id)
 end
 
 function purgesession(session_id; appname="muscles")
-   model = lock(__backbone_cache__) do
-        if session_id in keys(__backbone_cache__.cache)
-            #pop!(__valid_sessions__, session_id) # not sure what to do with it
-            pop!(__backbone_cache__.cache, session_id)
-        end
-    end
-    lock(__sequences__) do
-        if session_id in keys(__sequences__.cache)
-            pop!(__sequences__.cache, session_id)
-        end
-    end
-    purge_appdata(session_id, appname)
-    return model
+   purge_appdata(session_id, appname)
 end
 
 end
diff --git a/src/apps/muscles/app.jl b/src/apps/muscles/app.jl
index 6140bd2cb844c63fc6efdb74953b6a4ca7958b12..044e4cccdfc0cdf4fe2c0c067892be1daf998909 100644
--- a/src/apps/muscles/app.jl
+++ b/src/apps/muscles/app.jl
@@ -2,7 +2,7 @@ module MuscleApp
 
 using NyxUI, NyxUI.Storage, NyxUI.GenieExtras
 using Observables
-using Genie, GenieSession, Stipple, StippleUI
+using Genie, Stipple, StippleUI
 import Stipple: @app, @init, @private, @in, @out, @onchange, @onbutton, @notify
 
 include("Backbone.jl")
@@ -20,6 +20,8 @@ const maxlength = getconfig("muscle-activity", "maxlength")
 
 const bonito_app = NamedApp(:inherit, Backbone.app)
 
+Backbone.purgesession(session_id) = purgesession(session_id; appname=bonito_app.name)
+
 @app begin
     @private bonito_session_id = ""
 
@@ -95,7 +97,7 @@ const bonito_app = NamedApp(:inherit, Backbone.app)
     end
 
     @onbutton reset_bonito_session begin
-        model = purgesession(bonito_session_id; appname=bonito_app.name)
+        purgesession(bonito_session_id)
         # reset UI to defaults
         #bonito_session_id[!] = ""
         sequence[!] = MuscleActivity("")
@@ -445,8 +447,7 @@ function init_model(muscle_model=nothing)
         muscle_model = @init
         #@show muscle_model
     end
-    genie_session = GenieSession.session()
-    session_id = genie_session.id[1:32]
+    session_id = getsessionid(Backbone.session_registry)
     if hasmodel(session_id)
         withsequences(session_id) do sequences
             ids = sort!(collect(keys(sequences)))
diff --git a/values-yaml.gotmpl b/values-yaml.gotmpl
index d2b4df2f2498b992c4b4f9c3589308ffe201af6f..712200bbbec3e20b4f3fb06e2134726d7fd01cb4 100644
--- a/values-yaml.gotmpl
+++ b/values-yaml.gotmpl
@@ -7,11 +7,38 @@ replicaCount: 1
 front:
   image:
     repository: {{ requiredEnv "CI_REGISTRY_IMAGE" }}
-    name: {{ requiredEnv "IMAGE_NAME" }}
+    name: {{ env "IMAGE_NAME" | default "front" }}
     tag: {{ requiredEnv "CI_COMMIT_SHORT_SHA" }}
-    pullPolicy: {{ requiredEnv "IMAGE_POLICY" }}
+    pullPolicy: {{ env "IMAGE_POLICY" | default "Always" }}
   service:
-    targetPort: {{ requiredEnv "SERVICE_TARGET_PORT" }} 
+    targetPort: {{ env "SERVICE_TARGET_PORT" | default "8080" }}
+  resources:
+    limits:
+      cpu: {{ env "LIMITS_CPU" | default "2" }}
+      memory: {{ env "LIMITS_MEMORY" | default "4Gi" }}
+      ephemeral-storage: {{ env "LIMITS_STORAGE" | default "1Gi" }}
+    requests:
+      cpu: {{ env "LIMITS_CPU" | default "2" }}
+      memory: {{ env "LIMITS_MEMORY" | default "4Gi" }}
+      ephemeral-storage: {{ env "LIMITS_STORAGE" | default "1Gi" }}
+
+larvatagger:
+  image:
+    repository: {{ requiredEnv "CI_REGISTRY_IMAGE" }}
+    name: {{ env "LT_IMAGE_NAME" | default "larvatagger" }}
+    tag: {{ env "LT_IMAGE_TAG" | default "latest" }}
+    pullPolicy: {{ env "LT_IMAGE_POLICY" | default "Always" }}
+  service:
+    targetPort: {{ env "LARVATAGGER_PORT" | default "9286" }}
+  resources:
+    limits:
+      cpu: {{ env "LT_LIMITS_CPU" | default "2" }}
+      memory: {{ env "LT_LIMITS_MEMORY" | default "4Gi" }}
+      ephemeral-storage: {{ env "LT_LIMITS_STORAGE" | default "4Gi" }}
+    requests:
+      cpu: {{ env "LT_LIMITS_CPU" | default "2" }}
+      memory: {{ env "LT_LIMITS_MEMORY" | default "4Gi" }}
+      ephemeral-storage: {{ env "LT_LIMITS_STORAGE" | default "4Gi" }}
 
 imagePullSecrets:
   - name: {{ requiredEnv "IMAGE_SECRETS" }}
@@ -45,14 +72,14 @@ securityContext: {}
 
 service:
   type: ClusterIP
-  port: {{ requiredEnv "SERVICE_PORT" }}
+  port: {{ env "SERVICE_PORT" | default "80" }}
 
 ingress:
   enabled: true
   name: nyxui
-  className: {{ requiredEnv "INGRESS_CLASS" }}
+  className: {{ env "INGRESS_CLASS" | default "internal" }}
   annotations:
-    meta.helm.sh/release-name:  {{ requiredEnv "INGRESS_CLASS" }}
+    meta.helm.sh/release-name: nyxui
     meta.helm.sh/release-namespace: {{ requiredEnv "KUBE_NAMESPACE" }}
     nginx.ingress.kubernetes.io/proxy-body-size: "0"
   hosts:
@@ -60,21 +87,12 @@ ingress:
       paths:
         - path: /
           pathType: Prefix
+          serviceName: nyxui-front
   tls: []
   #  - secretName: chart-example-tls
   #    hosts:
   #      - chart-example.local
 
-resources: 
-  limits:
-    cpu: {{ requiredEnv "LIMITS_CPU" }}
-    memory: {{ requiredEnv "LIMITS_MEMORY" }}
-    ephemeral-storage: {{ requiredEnv "LIMITS_STORAGE" }}
-  requests:
-    cpu: {{ requiredEnv "LIMITS_CPU" }}
-    memory: {{ requiredEnv "LIMITS_MEMORY" }}
-    ephemeral-storage: {{ requiredEnv "LIMITS_STORAGE" }}
-
 autoscaling:
   enabled: false
   minReplicas: 1
@@ -82,18 +100,11 @@ autoscaling:
   targetCPUUtilizationPercentage: 80
   # targetMemoryUtilizationPercentage: 80
 
-# Additional volumes on the output Deployment definition.
+# Additional shared volumes on the output Deployment definitions.
 volumes: []
-# - name: foo
-#   secret:
-#     secretName: mysecret
-#     optional: false
 
-# Additional volumeMounts on the output Deployment definition.
+# Additional shared volumeMounts on the output Deployment definitions.
 volumeMounts: []
-# - name: foo
-#   mountPath: "/etc/foo"
-#   readOnly: true
 
 nodeSelector: {}