diff --git a/krebs/0tests/data/secrets/shack/telegram_bot.env b/krebs/0tests/data/secrets/shack/telegram_bot.env
new file mode 100644
index 000000000..e69de29bb
diff --git a/krebs/1systems/puyak/config.nix b/krebs/1systems/puyak/config.nix
index c84887eaa..08a3392bd 100644
--- a/krebs/1systems/puyak/config.nix
+++ b/krebs/1systems/puyak/config.nix
@@ -18,6 +18,7 @@
     <stockholm/krebs/2configs/shack/prometheus/server.nix>
     <stockholm/krebs/2configs/shack/prometheus/blackbox.nix>
     <stockholm/krebs/2configs/shack/prometheus/unifi.nix>
+    <stockholm/krebs/2configs/shack/prometheus/alertmanager-telegram.nix>
     <stockholm/krebs/2configs/shack/gitlab-runner.nix>
 
     ## Collect local statistics via collectd and send to collectd
diff --git a/krebs/1systems/wolf/config.nix b/krebs/1systems/wolf/config.nix
index 029644ca6..0160f9ebb 100644
--- a/krebs/1systems/wolf/config.nix
+++ b/krebs/1systems/wolf/config.nix
@@ -27,6 +27,8 @@ in
     <stockholm/krebs/2configs/shack/muellshack.nix>
     # provide light control api
     <stockholm/krebs/2configs/shack/node-light.nix>
+    # light.shack web-ui
+    <stockholm/krebs/2configs/shack/light.shack.nix>
     # send mail if muell was not handled
     <stockholm/krebs/2configs/shack/muell_mail.nix>
     # send mail if muell was not handled
@@ -34,6 +36,22 @@ in
     # powerraw usb serial to mqtt and raw socket
     <stockholm/krebs/2configs/shack/powerraw.nix>
 
+    { # do not log to /var/spool/log
+      services.nginx.appendHttpConfig = ''
+          map $request_method $loggable {
+            default 1;
+            GET 0;
+          }
+          log_format vhost '$host $remote_addr - $remote_user '
+                     '[$time_local] "$request" $status '
+                     '$body_bytes_sent "$http_referer" '
+                     '"$http_user_agent"';
+          error_log stderr;
+          access_log syslog:server=unix:/dev/log vhost;
+      '';
+      services.journald.rateLimitBurst = 10000;
+    }
+
     # create samba share for anonymous usage with the laser and 3d printer pc
     <stockholm/krebs/2configs/shack/share.nix>
 
diff --git a/krebs/2configs/go.nix b/krebs/2configs/go.nix
index f4c1290c2..c39b08a8e 100644
--- a/krebs/2configs/go.nix
+++ b/krebs/2configs/go.nix
@@ -13,7 +13,7 @@ with import <stockholm/lib>;
     enable = true;
     virtualHosts.go = {
       locations."/".extraConfig = ''
-        proxy_set_header Host go;
+        proxy_set_header Host go.r;
         proxy_pass http://localhost:1337;
       '';
       serverAliases = [
diff --git a/krebs/2configs/reaktor2.nix b/krebs/2configs/reaktor2.nix
index 72eff176b..061dc9ab9 100644
--- a/krebs/2configs/reaktor2.nix
+++ b/krebs/2configs/reaktor2.nix
@@ -76,7 +76,7 @@ let
           };
         }
         {
-          pattern = ''^([\w-]*):?\s+([+-][1-9][0-9]*)\s+(\S+)$'';
+          pattern = ''^([\H-]*):?\s+([+-][1-9][0-9]*)\s+(\S+)$'';
           activate = "match";
           arguments = [1 2 3];
           command = {
diff --git a/krebs/2configs/shack/glados/default.nix b/krebs/2configs/shack/glados/default.nix
index 9bf90bca4..f47bca2db 100644
--- a/krebs/2configs/shack/glados/default.nix
+++ b/krebs/2configs/shack/glados/default.nix
@@ -3,6 +3,7 @@ let
   shackopen = import ./multi/shackopen.nix;
   wasser = import ./multi/wasser.nix;
   badair = import ./multi/schlechte_luft.nix;
+  rollos = import ./multi/rollos.nix;
 in {
   services.nginx.virtualHosts."hass.shack" = {
     serverAliases = [ "glados.shack" ];
@@ -62,13 +63,18 @@ in {
         ];
       };
       # https://www.home-assistant.io/components/influxdb/
-      #influxdb = {
-      #  database = "hass";
-      #  tags = {
-      #    instance = "wolf";
-      #    source = "hass";
-      #  };
-      #};
+      influxdb = {
+        database = "glados";
+        host = "influx.shack";
+        component_config_glob = {
+          "sensor.*particulate_matter_2_5um_concentration".override_measurement = "2_5um particles";
+          "sensor.*particulate_matter_10_0um_concentration".override_measurement ="10um particles";
+        };
+        tags = {
+          instance = "wolf";
+          source = "glados";
+        };
+      };
       esphome = {};
       api = {};
       mqtt = {
@@ -93,8 +99,7 @@ in {
         };
       };
       switch =
-        wasser.switch
-        ++ (import ./switch/power.nix)
+        (import ./switch/power.nix)
         ;
       light =  [];
       media_player = [
@@ -113,6 +118,7 @@ in {
         ++ (import ./sensors/mate.nix)
         ++ (import ./sensors/darksky.nix { inherit lib;})
         ++ shackopen.sensor
+        ++ wasser.sensor
         ;
       air_quality = (import ./sensors/sensemap.nix );
 
@@ -147,6 +153,7 @@ in {
 
       automation = wasser.automation
         ++ badair.automation
+        ++ rollos.automation
         ++ (import ./automation/shack-startup.nix)
         ++ (import ./automation/party-time.nix)
         ++ (import ./automation/hass-restart.nix);
diff --git a/krebs/2configs/shack/glados/multi/rollos.nix b/krebs/2configs/shack/glados/multi/rollos.nix
index 1febad525..4e6494936 100644
--- a/krebs/2configs/shack/glados/multi/rollos.nix
+++ b/krebs/2configs/shack/glados/multi/rollos.nix
@@ -1,13 +1,56 @@
+# 
+
 let
   glados = import ../lib;
+  tempsensor = "sensor.dark_sky_temperature";
+  all_covers = [
+    "cover.crafting_rollo"
+    "cover.elab_rollo"
+    "cover.or2_rollo"
+    "cover.retroraum_rollo"
+  ];
 in
 {
-  # LED
-  light = [
-  ];
-  sensor = [
-  ];
   automation =
   [
+    { alias = "Rollos fahren Runter";
+      trigger = [
+        {
+          platform = "numeric_state";
+          entity_id = tempsensor;
+          above = 25;
+          for = "00:30:00";
+        }
+      ];
+      condition =
+        [
+          {
+            condition = "state";
+            entity_id = "sun.sun";
+            state = "above_horizon";
+          }
+      ];
+      action =
+        [
+          { service = "cover.close_cover";
+            entity_id = all_covers;
+          }
+        ];
+    }
+    { alias = "Rollos fahren Hoch";
+      trigger = [
+        {
+          platform = "sun";
+          event = "sunset";
+        }
+      ];
+      condition = [ ];
+      action =
+        [
+          { service = "cover.open_cover";
+            entity_id = all_covers;
+          }
+        ];
+    }
   ];
 }
diff --git a/krebs/2configs/shack/glados/multi/wasser.nix b/krebs/2configs/shack/glados/multi/wasser.nix
index 6f3dc98ad..74ce736a6 100644
--- a/krebs/2configs/shack/glados/multi/wasser.nix
+++ b/krebs/2configs/shack/glados/multi/wasser.nix
@@ -2,13 +2,17 @@
 #  switch.crafting_giesskanne_relay
 let
   glados = import ../lib;
-  seconds = 10;
+  seconds = 20;
   wasser = "switch.crafting_giesskanne_relay";
 in
 {
-  switch = [
-    (glados.tasmota.plug { host = "Wasser"; topic = "plug";} )
-  ];
+  sensor = map ( entity_id: {
+      platform = "statistics";
+      name = "Statistics for ${entity_id}";
+      inherit entity_id;
+      max_age.minutes = "60";
+    }) ["sensor.crafting_brotbox_soil_moisture"];
+
 
   automation =
   [
diff --git a/krebs/2configs/shack/influx.nix b/krebs/2configs/shack/influx.nix
index 92cb24bf3..93d83a59b 100644
--- a/krebs/2configs/shack/influx.nix
+++ b/krebs/2configs/shack/influx.nix
@@ -8,6 +8,11 @@ in
   networking.firewall.allowedTCPPorts = [ port ]; # for legacy applications
   networking.firewall.allowedUDPPorts = [ collectd-port ];
   services.nginx.virtualHosts."influx.shack" = {
+    # Disable constant GET request logging.
+    # $loggable map is defined in 1/wolf
+    extraConfig = ''
+      access_log syslog:server=unix:/dev/log combined if=$loggable;
+    '';
     locations."/" = {
       proxyPass = "http://localhost:${toString port}/";
     };
diff --git a/krebs/2configs/shack/light.shack.nix b/krebs/2configs/shack/light.shack.nix
new file mode 100644
index 000000000..8e01cb1bf
--- /dev/null
+++ b/krebs/2configs/shack/light.shack.nix
@@ -0,0 +1,12 @@
+{ config, pkgs, ... }:
+let
+  light-shack-src = pkgs.fetchgit {
+      url = "https://git.shackspace.de/rz/standby.shack";
+      rev = "e1b90a0a";
+      sha256 = "07fmz63arc5rxa0a3778srwz0jflp4ad6xnwkkc56hwybby0bclh";
+    };
+  web-dir = "${light-shack-src}/client/www/";
+in
+{
+  services.nginx.virtualHosts."light.shack".locations."/".root = web-dir;
+}
diff --git a/krebs/2configs/shack/muell_mail.nix b/krebs/2configs/shack/muell_mail.nix
index 409278954..481564719 100644
--- a/krebs/2configs/shack/muell_mail.nix
+++ b/krebs/2configs/shack/muell_mail.nix
@@ -4,8 +4,8 @@ let
   pkg = pkgs.callPackage (
     pkgs.fetchgit {
       url = "https://git.shackspace.de/rz/muell_mail";
-      rev = "57b67c95052d90044137b2c89007a371dc389afd";
-      sha256 = "1grkzs6fxjnc2bv4kskj63d5sb4qxz6yyr85nj0da9hn7qkk4jkj";
+      rev = "c3e43687879f95e01a82ef176fa15678543b2eb8";
+      sha256 = "0hgchwam5ma96s2v6mx2jfkh833psadmisjbm3k3153rlxp46frx";
     }) { mkYarnPackage = pkgs.yarn2nix-moretea.mkYarnPackage; };
     home = "/var/lib/muell_mail";
     cfg = toString <secrets/shack/muell_mail.js>;
diff --git a/krebs/2configs/shack/node-light.nix b/krebs/2configs/shack/node-light.nix
index b471f2af5..4a981ea87 100644
--- a/krebs/2configs/shack/node-light.nix
+++ b/krebs/2configs/shack/node-light.nix
@@ -28,6 +28,9 @@ in {
   };
 
   services.nginx.virtualHosts."openhab.shack" = {
+    extraConfig = ''
+      access_log syslog:server=unix:/dev/log combined if=$loggable;
+    '';
     serverAliases = [ "lightapi.shack" ];
     locations."/power/".proxyPass = "http://localhost:${port}/power/";
     locations."/lounge/".proxyPass = "http://localhost:${port}/lounge/";
diff --git a/krebs/2configs/shack/prometheus/alert-rules.nix b/krebs/2configs/shack/prometheus/alert-rules.nix
index 096c551ba..1c2d0b1ad 100644
--- a/krebs/2configs/shack/prometheus/alert-rules.nix
+++ b/krebs/2configs/shack/prometheus/alert-rules.nix
@@ -1,102 +1,42 @@
-{ lib }:
-with lib;
-
+{ lib,... }:
 let
-  deviceFilter = ''device!="ramfs",device!="rpc_pipefs",device!="lxcfs",device!="nsfs",device!="borgfs"'';
-in mapAttrsToList (name: opts: {
-  alert = name;
-  expr = opts.condition;
-  for = opts.time or "2m";
-  labels = if (opts.page or true) then { severity = "page"; } else {};
-  annotations = {
-    summary = opts.summary;
-    description = opts.description;
-  };
-}) {
-  node_down = {
-    condition = ''up{job="node"} == 0'';
-    summary = "{{$labels.alias}}: Node is down.";
-    description = "{{$labels.alias}} has been down for more than 2 minutes.";
-  };
-  node_systemd_service_failed = {
-    condition = ''node_systemd_unit_state{state="failed"} == 1'';
-    summary = "{{$labels.alias}}: Service {{$labels.name}} failed to start.";
-    description = "{{$labels.alias}} failed to (re)start service {{$labels.name}}.";
-  };
-  node_filesystem_full_80percent = {
-    condition = ''sort(node_filesystem_free_bytes{${deviceFilter}} < node_filesystem_size_bytes{${deviceFilter}} * 0.2) / 1024^3'';
-    time = "10m";
-    summary = "{{$labels.alias}}: Filesystem is running out of space soon.";
-    description = "{{$labels.alias}} device {{$labels.device}} on {{$labels.mountpoint}} got less than 20% space left on its filesystem.";
-  };
-  node_filesystem_full_in_7d = {
-    condition = ''predict_linear(node_filesystem_free_bytes{${deviceFilter}}[2d], 7*24*3600) <= 0'';
-    time = "1h";
-    summary = "{{$labels.alias}}: Filesystem is running out of space in 7 days.";
-    description = "{{$labels.alias}} device {{$labels.device}} on {{$labels.mountpoint}} is running out of space of in approx. 7 days";
-  };
-  node_filesystem_full_in_30d = {
-    condition = ''predict_linear(node_filesystem_free_bytes{${deviceFilter}}[30d], 30*24*3600) <= 0'';
-    time = "1h";
-    summary = "{{$labels.alias}}: Filesystem is running out of space in 30 days.";
-    description = "{{$labels.alias}} device {{$labels.device}} on {{$labels.mountpoint}} is running out of space of in approx. 30 days";
-  };
-  node_filedescriptors_full_in_3h = {
-    condition = ''predict_linear(node_filefd_allocated[3h], 3*3600) >= node_filefd_maximum'';
-    time = "20m";
-    summary = "{{$labels.alias}} is running out of available file descriptors in 3 hours.";
-    description = "{{$labels.alias}} is running out of available file descriptors in approx. 3 hours";
-  };
-  node_filedescriptors_full_in_7d = {
-    condition = ''predict_linear(node_filefd_allocated[7d], 7*24*3600) >= node_filefd_maximum'';
-    time = "1h";
-    summary = "{{$labels.alias}} is running out of available file descriptors in 7 days.";
-    description = "{{$labels.alias}} is running out of available file descriptors in approx. 7 days";
-  };
-  node_load15 = {
-    condition = ''node_load15 / on(alias) count(node_cpu_seconds_total{mode="system"}) by (alias) >= 1.0'';
-    time = "10m";
-    summary = "{{$labels.alias}}: Running on high load: {{$value}}";
-    description = "{{$labels.alias}} is running with load15 > 1 for at least 5 minutes: {{$value}}";
-  };
-  node_ram_using_90percent = {
-    condition =  "node_memory_MemFree_bytes + node_memory_Buffers_bytes + node_memory_Cached_bytes < node_memory_MemTotal_bytes * 0.1";
-    time = "1h";
-    summary = "{{$labels.alias}}: Using lots of RAM.";
-    description = "{{$labels.alias}} is using at least 90% of its RAM for at least 1 hour.";
-  };
-  node_swap_using_30percent = {
-    condition = "node_memory_SwapTotal_bytes - (node_memory_SwapFree_bytes + node_memory_SwapCached_bytes) > node_memory_SwapTotal_bytes * 0.3";
-    time = "30m";
-    summary = "{{$labels.alias}}: Using more than 30% of its swap.";
-    description = "{{$labels.alias}} is using 30% of its swap space for at least 30 minutes.";
-  };
-  node_visible_confluence_space = {
-    condition = "node_visible_confluence_space != 0";
-    summary = "crowd prometheus cann see the {{$labels.space_name}} confluence space!";
-    description = "crowd user `prometheus` can see the `{{$labels.space_name}}` confluence space.";
-  };
-  node_hwmon_temp = {
-    condition = "node_hwmon_temp_celsius > node_hwmon_temp_crit_celsius*0.9 OR node_hwmon_temp_celsius > node_hwmon_temp_max_celsius*0.95";
-    time = "5m";
-    summary = "{{$labels.alias}}: Sensor {{$labels.sensor}}/{{$labels.chip}} temp is high: {{$value}} ";
-    description = "{{$labels.alias}} reports hwmon sensor {{$labels.sensor}}/{{$labels.chip}} temperature value is nearly critical: {{$value}}";
-  };
-  node_conntrack_limit = {
-    condition  = "node_nf_conntrack_entries_limit - node_nf_conntrack_entries < 1000";
-    time = "5m";
-    summary = "{{$labels.alias}}: Number of tracked connections high";
-    description = "{{$labels.alias}} has only {{$value}} free slots for connection tracking available.";
-  };
-  node_reboot = {
-    condition = "time() - node_boot_time_seconds < 300";
-    summary = "{{$labels.alias}}: Reboot";
-    description = "{{$labels.alias}} just rebooted.";
-  };
-  node_uptime = {
-    condition = "time() - node_boot_time_seconds > 2592000";
-    page = false;
-    summary = "{{$labels.alias}}: Uptime monster";
-    description = "{{$labels.alias}} has been up for more than 30 days.";
-  };
+  disk_free_threshold = "10"; # at least this much free disk percentage
+in {
+  services.prometheus.rules = [(builtins.toJSON
+    {
+      groups = [
+        { name = "shack-env";
+          rules = [
+            {
+              alert = "RootPartitionFull";
+              for = "30m";
+              expr = ''(node_filesystem_avail_bytes{alias="wolf.shack",mountpoint="/"} * 100) / node_filesystem_size_bytes{alias="wolf.shack",mountpoint="/"} < ${disk_free_threshold}'';
+              labels.severity = "warning";
+              annotations.summary = "{{ $labels.alias }} root disk full";
+              annotations.url = "http://grafana.shack/d/hb7fSE0Zz/shack-system-dashboard?orgId=1&var-job=node&var-hostname=All&var-node=wolf.shack:9100&var-device=All&var-maxmount=%2F&var-show_hostname=wolf";
+              annotations.description = ''The root disk of {{ $labels.alias }} has {{ $value | printf "%.2f" }}% free disk space (Threshold at ${disk_free_threshold}%).A vast number of shackspace services will stop working. CI for deploying new configuration will also seize working. Log in to the system and run `nix-collect-garbage -d` and clean up the shack share folder in `/home/share` .If this does not help you can check `du -hs /var/ | sort -h`, run `docker system prune` or if you are really desperate run `du -hs / | sort -h` and go through the folders recursively until you've found something to delete'';
+            }
+            {
+              alert = "RootPartitionFull";
+              for = "30m";
+              expr = ''(node_filesystem_avail_bytes{alias="puyak.shack",mountpoint="/"} * 100) / node_filesystem_size_bytes{alias="puyak.shack",mountpoint="/"} < ${disk_free_threshold}'';
+              labels.severity = "warning";
+              annotations.summary = "{{ $labels.alias }} root disk full";
+              annotations.url = "http://grafana.shack/d/hb7fSE0Zz/shack-system-dashboard?orgId=1&var-job=node&var-hostname=All&var-node=wolf.shack:9100&var-device=All&var-maxmount=%2F&var-show_hostname=puyak";
+              annotations.description = ''The root disk of {{ $labels.alias }} has {{ $value | printf "%.2f" }}% free disk space (Threshold at ${disk_free_threshold}%).Prometheus will not be able to create new alerts and CI for deploying new configuration will also seize working. Log in to the system and run `nix-collect-garbage -d` and if this does not help you can check `du -hs /var/ | sort -h`, run `docker system prune` or if you are really desperate run `du -hs / | sort -h` and go through the folders recursively until you've found something to delete'';
+            }
+            {
+              alert = "HostDown";
+              expr = ''up{alias="wolf.shack"} == 0'';
+              for = "5m";
+              labels.severity = "page";
+              annotations.summary = "Instance {{ $labels.alias }} down for 5 minutes";
+              annotations.url = "http://grafana.shack/d/hb7fSE0Zz/shack-system-dashboard?orgId=1&var-job=node&var-hostname=All&var-node=wolf.shack:9100&var-device=All&var-maxmount=%2F&var-show_hostname=wolf";
+              annotations.description = ''Host {{ $labels.alias }} went down and has not been reconnected after 5 minutes. This is probably bad news, try to restart the host via naproxen ( http://naproxen.shack:8006 ). Wolf being down means that CI,glados automation, light management and a couple of other services will not work anymore.'';
+            }
+          ];
+        }
+      ];
+    }
+  )];
 }
diff --git a/krebs/2configs/shack/prometheus/alertmanager-telegram.nix b/krebs/2configs/shack/prometheus/alertmanager-telegram.nix
new file mode 100644
index 000000000..8527001cb
--- /dev/null
+++ b/krebs/2configs/shack/prometheus/alertmanager-telegram.nix
@@ -0,0 +1,17 @@
+{ pkgs, ...}:
+{
+  systemd.services.alertmanager-bot-telegram = {
+    wantedBy = [ "multi-user.target" ];
+    after = [ "ip-up.target" ];
+    serviceConfig = {
+      EnvironmentFile = toString <secrets/shack/telegram_bot.env>;
+      DynamicUser = true;
+      StateDirectory = "alertbot";
+      ExecStart = ''${pkgs.alertmanager-bot-telegram}/bin/alertmanager-bot \
+        --alertmanager.url=http://alert.prometheus.shack --log.level=info \
+        --store=bolt --bolt.path=/var/lib/alertbot/bot.db \
+        --listen.addr="0.0.0.0:16320" \
+        --template.paths=${./templates}/shack.tmpl'';
+    };
+  };
+}
diff --git a/krebs/2configs/shack/prometheus/server.nix b/krebs/2configs/shack/prometheus/server.nix
index c088a3b08..9e4b4d1a7 100644
--- a/krebs/2configs/shack/prometheus/server.nix
+++ b/krebs/2configs/shack/prometheus/server.nix
@@ -1,6 +1,9 @@
 { pkgs, lib, config, ... }:
 # from https://gist.github.com/globin/02496fd10a96a36f092a8e7ea0e6c7dd
 {
+  imports = [
+    ./alert-rules.nix
+  ];
   networking = {
     firewall.allowedTCPPorts = [
       9090  # prometheus
@@ -18,12 +21,6 @@
     };
     prometheus = {
       enable = true;
-      ruleFiles = lib.singleton (pkgs.writeText "prometheus-rules.yml" (builtins.toJSON {
-            groups = lib.singleton {
-              name = "mf-alerting-rules";
-              rules = import ./alert-rules.nix { inherit lib; };
-            };
-          }));
       scrapeConfigs = [
         {
           job_name = "node";
@@ -118,7 +115,10 @@
       ];
       alertmanager = {
         enable = true;
-        listenAddress = "0.0.0.0";
+        listenAddress = "127.0.0.1";
+        webExternalUrl = "http://alert.prometheus.shack";
+        logLevel = "debug";
+
         configuration = {
           "global" = {
             "smtp_smarthost" = "smtp.example.com:587";
@@ -134,15 +134,10 @@
           "receivers" = [
             {
               "name" = "team-admins";
-              "email_configs" = [
-                {
-                  "to" = "devnull@example.com";
-                  "send_resolved" = true;
-                }
-              ];
+              "email_configs" = [ ];
               "webhook_configs" = [
                 {
-                  "url" = "https://example.com/prometheus-alerts";
+                  "url" = "http://localhost:16320";
                   "send_resolved" = true;
                 }
               ];
diff --git a/krebs/2configs/shack/prometheus/templates/shack.tmpl b/krebs/2configs/shack/prometheus/templates/shack.tmpl
new file mode 100644
index 000000000..9295f019f
--- /dev/null
+++ b/krebs/2configs/shack/prometheus/templates/shack.tmpl
@@ -0,0 +1,25 @@
+{{ define "telegram.default" }}
+{{range .Alerts -}}
+{{ $severity := index .Labels "severity" }}
+{{ $desc := "No Description" }}
+{{ if eq .Status "firing" }}
+  {{ $desc = index .Annotations "description" }}
+  {{- if eq $severity "critical" -}}
+    <i><u><b>[CRITICAL]</b></u></i>
+  {{- else if eq $severity "warning" -}}
+    <u><b>[WARNING]</b></u>
+  {{- else -}}
+    <b>[{{ $severity }}]</b>
+  {{- end -}}
+{{ else -}}
+  {{ $desc = "The issue has been resolved" }}
+  <del>[RESOLVED]</del>
+{{- end }} {{ index .Labels "alertname"}}: {{ index .Annotations "summary"}}
+
+{{ $desc }}
+
+Alert Links:
+* <a href="{{ index .Annotations "url"}}">Grafana</a>
+* <a href="{{ .GeneratorURL }}">Source</a>
+{{end -}}
+{{end}}
diff --git a/krebs/3modules/external/mic92.nix b/krebs/3modules/external/mic92.nix
index 782f8ac04..5a766664f 100644
--- a/krebs/3modules/external/mic92.nix
+++ b/krebs/3modules/external/mic92.nix
@@ -349,19 +349,20 @@ in {
           ip4.addr = "10.243.29.171";
           aliases = [ "rock.r" ];
           tinc.pubkey = ''
-            -----BEGIN RSA PUBLIC KEY-----
-            MIICCgKCAgEAsMJbXDhkaLZcEzCIe8G+rHyLulWIqrUAmDT4Vbtv4r0QhPBsqwjM
-            DuvRtX5SNHdjfZWnUZoOlmXrmIo07exPFQvyrnppm6DNx+IZ5mNMNVIFUoojRhF7
-            HS2jubcjTEib56XEYWKly0olrVMbsJk5THJqRQyOQuTPCFToxXVRcT5t/UK6Dzgh
-            mp+suJ7IcmmO80IwfZrQrQslkQ6TdOy1Vs908GacSQJyRxdRxLraU/98iMhFbAQf
-            Ap+qVSUU88iCi+tcoSYzKhqU2N0AhRGcsE073B3Px8CAgPK/juwTrFElKEc17X9M
-            Rh41DvUjrtG4ERPmbwKPtsLagmnZUlU8A5YC8wtV08RI5QBsbbOsKInareV1aLeD
-            91ZVCBPFTz8IM6Mc6H435eMCMC2ynFCDyRGdcue3tBQoaTGe1dbduIZkPGn+7cg4
-            fef1db6SQD4HCwDLv8CTFLACR/jmAapwZEgvJ3u3bpgMGzt+QNvL1cxUr3TBUWRv
-            3f0R+Dj8DCUWTJUE7K5LO7bL4p9Ht0yIsVH+/DucyoMQqRwCwWSr7+H2MAsWviav
-            ZRRfH0RqZPEzCxyLDBtkVrx+GRAUZxy1xlqmN16O/sRHiqq3bv8Jk3dwuRZlFu6q
-            cOFu4g9XsamHkmCuVkvTGjnC2h21MjUUr3PGHzOMtiM/18LcfX730f8CAwEAAQ==
-            -----END RSA PUBLIC KEY-----
+            -----BEGIN PUBLIC KEY-----
+            MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA0uhNk3XXVxQcIVhD1Ime
+            9PY3QBIcXvwDlOrd3oUwyWTvZpUeO7yzIXdouAe4s0ohPIVq7Cmruj4ZrOGUCKyB
+            oJpOziYSbL/IiCpXyOzWMLEwu0AoeFfbxig+5oZfwQ9epM2j902CgsUipJBLIg48
+            BC9oOD+/iYEwsFPqQ/S0kETyQK5Ad+qv0lbU6/Kmify8Qplvpv/8DRdjsdLki1fU
+            a6MAEw12OtHe6IWtlitPjFMBykTP6kkSp/eg0G2KZFVuEulwHGf9QT/eT4fZTMCC
+            2V5Vp4rIr/hawmj+h4NIxniBSQcPAAIGNwZVC4uYYV1nd4iaI/T04rDJwte5WKHf
+            EVxtlYt9RU1I/XdNRSj9gYyneVcVlDVos8Z93oUv1hIGZYFtNmGVna6lggOBPf/t
+            BZ1MT6FKA4QX9JI8bQoNs18s8ffzyb07psNbH6YhpCygnhf9C7NR/CeI8BtpzJza
+            1Qk731Z6bk6xRFKMuY2tRKlNCqPHULj44oTHB3Ki2B/bMlkguqSChfFzKIRASYO1
+            SASSgddexjkjKLslxcLWhIqYrZhuhYlFyoeoMI3qQsey/4X5PUmQDxxhTT80+qvE
+            thBNPg46joyLTq9E9ddf7t/0C6oD2DXY88N9bkztuK5dtYHmjajUbePuaTJtrKhI
+            7MnLboZCEiSyvkVTTx0Yjf0CAwEAAQ==
+            -----END PUBLIC KEY-----
           '';
         };
       };
@@ -463,6 +464,7 @@ in {
           ip4.addr = "10.243.29.185";
           aliases = [
             "eva.r"
+            "prometheus.r"
           ];
           tinc.pubkey = ''
             -----BEGIN PUBLIC KEY-----
diff --git a/krebs/3modules/hosts.nix b/krebs/3modules/hosts.nix
index 159b54e34..ae0136303 100644
--- a/krebs/3modules/hosts.nix
+++ b/krebs/3modules/hosts.nix
@@ -48,7 +48,9 @@ in {
       hostNetAliases = host:
         mapAttrs (_: net: filter (x: x.name != null && x.value != []) [
           { name = net.ip4.addr or null; value = net.aliases; }
+          { name = net.ip4.addr or null; value = (map (alias: "4.${alias}") net.aliases); }
           { name = net.ip6.addr or null; value = net.aliases; }
+          { name = net.ip6.addr or null; value = (map (alias: "6.${alias}") net.aliases); }
         ]) host.nets;
 
       # netAliases : { ${netname} : [addrAliases] }
diff --git a/krebs/3modules/lass/default.nix b/krebs/3modules/lass/default.nix
index 2a75cc1bb..d2a945284 100644
--- a/krebs/3modules/lass/default.nix
+++ b/krebs/3modules/lass/default.nix
@@ -95,6 +95,7 @@ in {
         };
         wiregrill = {
           via = internet;
+          ip4.addr = "10.244.1.103";
           ip6.addr = w6 "1";
           aliases = [
             "prism.w"
@@ -104,6 +105,7 @@ in {
             subnets = [
               (krebs.genipv6 "wiregrill" "external" 0).subnetCIDR
               (krebs.genipv6 "wiregrill" "lass" 0).subnetCIDR
+              "10.244.1.0/24"
             ];
           };
         };
@@ -196,6 +198,7 @@ in {
         };
         wiregrill = {
           ip6.addr = w6 "50da";
+          ip4.addr = "10.244.1.4";
           aliases = [
             "shodan.w"
           ];
@@ -554,6 +557,7 @@ in {
     phone = {
       nets = {
         wiregrill = {
+          ip4.addr = "10.244.1.13";
           ip6.addr = w6 "a";
           aliases = [
             "phone.w"
diff --git a/krebs/3modules/newsbot-js.nix b/krebs/3modules/newsbot-js.nix
index 00e346f8e..a3640caa5 100644
--- a/krebs/3modules/newsbot-js.nix
+++ b/krebs/3modules/newsbot-js.nix
@@ -48,7 +48,7 @@ let
         };
         urlShortenerHost = mkOption {
           type = types.str;
-          default = "go";
+          default = "go.r";
           description = "what server to use for url shortening, host";
         };
         urlShortenerPort = mkOption {
diff --git a/krebs/5pkgs/simple/alertmanager-bot-telegram/default.nix b/krebs/5pkgs/simple/alertmanager-bot-telegram/default.nix
new file mode 100644
index 000000000..f0e221406
--- /dev/null
+++ b/krebs/5pkgs/simple/alertmanager-bot-telegram/default.nix
@@ -0,0 +1,26 @@
+{ lib, fetchFromGitHub, buildGoModule }:
+
+buildGoModule rec {
+  pname = "alertmanager-bot";
+  version = "2020-07-13";
+
+  src = fetchFromGitHub {
+    owner = "metalmatze";
+    repo = "alertmanager-bot";
+    rev = "5efc0bbbf8023d4324e9da98562f064a714a7206";
+    sha256 = "09cciml1j8x76jpm2v5v6h2q6j1fkhsz1kswslmx8wl4wk40xgp4";
+  };
+
+  modSha256 = "0nlnxkpcna7g7qslyz5i1619paw4jkb1ma4fgpsgvgx1spwrjm8h";
+  postInstall = ''
+    install -D ./default.tmpl $out/templates/default.tmpl
+  '';
+
+  meta = with lib; {
+    description = "Simple command-line snippet manager, written in Go";
+    homepage = https://github.com/knqyf263/pet;
+    license = licenses.mit;
+    maintainers = with maintainers; [ kalbasit ];
+    platforms = platforms.linux ++ platforms.darwin;
+  };
+}
diff --git a/krebs/5pkgs/simple/flameshot-once/profile.nix b/krebs/5pkgs/simple/flameshot-once/profile.nix
index 4427e5b23..5aed99597 100644
--- a/krebs/5pkgs/simple/flameshot-once/profile.nix
+++ b/krebs/5pkgs/simple/flameshot-once/profile.nix
@@ -118,7 +118,7 @@ let
           type = types.bool;
         };
         timeout = mkOption {
-          default = 100;
+          default = 200;
           description = ''
             Maximum time in milliseconds allowed for the flameshot daemon to
             react.
diff --git a/krebs/5pkgs/simple/realwallpaper/default.nix b/krebs/5pkgs/simple/realwallpaper/default.nix
index 057983fec..72a314ba9 100644
--- a/krebs/5pkgs/simple/realwallpaper/default.nix
+++ b/krebs/5pkgs/simple/realwallpaper/default.nix
@@ -104,7 +104,7 @@ pkgs.writers.writeDashBin "generate-wallpaper" ''
       'https://neo.sci.gsfc.nasa.gov/view.php?datasetId=MOD10C1_E_SNOW') &
     fetch_older_days 7 chlora-raw.jpg $(get_neo_url \
       'https://neo.sci.gsfc.nasa.gov/view.php?datasetId=MY1DMM_CHLORA') &
-    fetch_older_days 3 fire-raw.jpg $(get_neo_url \
+    fetch_older_days 7 fire-raw.jpg $(get_neo_url \
       'https://neo.sci.gsfc.nasa.gov/view.php?datasetId=MOD14A1_E_FIRE') &
 
     # regular fetches
diff --git a/lass/1systems/blue/config.nix b/lass/1systems/blue/config.nix
index c46bb351e..f6dc23d20 100644
--- a/lass/1systems/blue/config.nix
+++ b/lass/1systems/blue/config.nix
@@ -17,27 +17,6 @@ with import <stockholm/lib>;
 
   networking.nameservers = [ "1.1.1.1" ];
 
-  services.restic.backups = genAttrs [
-    "daedalus"
-    "icarus"
-    "littleT"
-    "prism"
-    "shodan"
-    "skynet"
-  ] (dest: {
-    initialize = true;
-    extraOptions = [
-      "sftp.command='ssh backup@${dest}.r -i ${config.krebs.build.host.ssh.privkey.path} -s sftp'"
-    ];
-    repository = "sftp:backup@${dest}.r:/backups/blue";
-    passwordFile = (toString <secrets>) + "/restic/${dest}";
-    timerConfig = { OnCalendar = "00:05"; RandomizedDelaySec = "5h"; };
-    paths = [
-      "/home/"
-      "/var/lib"
-    ];
-  });
-
   time.timeZone = "Europe/Berlin";
   users.users.mainUser.openssh.authorizedKeys.keys = [ config.krebs.users.lass-android.pubkey ];
 }
diff --git a/lass/1systems/morpheus/config.nix b/lass/1systems/morpheus/config.nix
index c3a8ea6c8..79fbe4c97 100644
--- a/lass/1systems/morpheus/config.nix
+++ b/lass/1systems/morpheus/config.nix
@@ -18,6 +18,7 @@ with import <stockholm/lib>;
     gitAndTools.hub
     nix-review
     firefox
+    ag
   ];
 
   services.openssh.forwardX11 = true;
diff --git a/lass/1systems/mors/config.nix b/lass/1systems/mors/config.nix
index c1ceb0633..b03d95c49 100644
--- a/lass/1systems/mors/config.nix
+++ b/lass/1systems/mors/config.nix
@@ -126,8 +126,6 @@ with import <stockholm/lib>;
     remmina
     transmission
 
-    iodine
-
     macchanger
     dpass
 
diff --git a/lass/1systems/mors/physical.nix b/lass/1systems/mors/physical.nix
index 2f3a68442..a9108104b 100644
--- a/lass/1systems/mors/physical.nix
+++ b/lass/1systems/mors/physical.nix
@@ -23,7 +23,7 @@
 
   services.udev.extraRules = ''
     SUBSYSTEM=="net", DEVPATH=="/devices/pci*/*1c.1/*/net/*", NAME="wl0"
-    SUBSYSTEM=="net", ATTR{address}=="3c:97:0e:4f:42:35", NAME="et0"
+    SUBSYSTEM=="net", ATTR{address}=="3c:97:0e:37:15:d9", NAME="et0"
   '';
 
   #TODO activationScripts seem broken, fix them!
diff --git a/lass/1systems/prism/config.nix b/lass/1systems/prism/config.nix
index 33ec21e72..b335353be 100644
--- a/lass/1systems/prism/config.nix
+++ b/lass/1systems/prism/config.nix
@@ -272,9 +272,9 @@ with import <stockholm/lib>;
         resolveLocalQueries = false;
 
         extraConfig= ''
-          listen-address=42:1:ce16::1
+          listen-address=42:1:ce16::1,10.244.1.103
           except-interface=lo
-          interface=wg0
+          interface=wiregrill
         '';
       };
     }
@@ -284,7 +284,10 @@ with import <stockholm/lib>;
       ];
     }
     {
-      services.murmur.enable = true;
+      services.murmur = {
+        enable = true;
+        bandwidth = 10000000;
+      };
       services.murmur.registerName = "lassul.us";
       krebs.iptables.tables.filter.INPUT.rules = [
         { predicate = "-p tcp --dport 64738"; target = "ACCEPT";}
diff --git a/lass/1systems/prism/physical.nix b/lass/1systems/prism/physical.nix
index 7458f5ffd..1a3bee850 100644
--- a/lass/1systems/prism/physical.nix
+++ b/lass/1systems/prism/physical.nix
@@ -55,6 +55,16 @@
     fsType = "zfs";
   };
 
+  fileSystems."/var/realwallpaper/archive" = {
+    device = "tank/wallpaper";
+    fsType = "zfs";
+  };
+
+  fileSystems."/home/xanf" = {
+    device = "/dev/disk/by-id/wwn-0x500a07511becb076";
+    fsType = "ext4";
+  };
+
   nix.maxJobs = lib.mkDefault 8;
   powerManagement.cpuFreqGovernor = lib.mkDefault "powersave";
 
diff --git a/lass/1systems/shodan/physical.nix b/lass/1systems/shodan/physical.nix
index 39a4d9661..55e91b0e4 100644
--- a/lass/1systems/shodan/physical.nix
+++ b/lass/1systems/shodan/physical.nix
@@ -10,7 +10,7 @@
     loader.grub.version = 2;
     loader.grub.device = "/dev/sda";
 
-    initrd.luks.devices = [ { name = "luksroot"; device = "/dev/sda2"; } ];
+    initrd.luks.devices.lusksroot.device = "/dev/sda2";
     initrd.luks.cryptoModules = [ "aes" "sha512" "sha1" "xts" ];
     initrd.availableKernelModules = [ "xhci_hcd" "ehci_pci" "ahci" "usb_storage" ];
   };
diff --git a/lass/1systems/wizard/run-vm.sh b/lass/1systems/wizard/run-vm.sh
new file mode 100755
index 000000000..13914ad5f
--- /dev/null
+++ b/lass/1systems/wizard/run-vm.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env nix-shell
+#! nix-shell -i bash -p nixos-generators
+
+set -efu
+
+WD=$(dirname "$0")
+nixos-generate -I stockholm="$WD"/../../.. -c "$WD"/config.nix -f vm-nogui --run
diff --git a/lass/1systems/wizard/test.nix b/lass/1systems/wizard/test.nix
index c7a27102a..165b9f14d 100644
--- a/lass/1systems/wizard/test.nix
+++ b/lass/1systems/wizard/test.nix
@@ -1,7 +1,7 @@
 { config, lib, pkgs, ... }:
 {
   imports = [
-    ./default.nix
+    ./config.nix
   ];
   virtualisation.emptyDiskImages = [
     8000
diff --git a/lass/1systems/xerxes/config.nix b/lass/1systems/xerxes/config.nix
index e4a4fb505..8c4362865 100644
--- a/lass/1systems/xerxes/config.nix
+++ b/lass/1systems/xerxes/config.nix
@@ -41,22 +41,6 @@
     displayManager.lightdm.autoLogin.user = "lass";
   };
 
-  services.syncthing.declarative = {
-    folders = {
-      the_playlist = {
-        path = "/home/lass/tmp/the_playlist";
-        devices = [ "mors" "phone" "prism" "xerxes" ];
-      };
-    };
-  };
-  krebs.permown = {
-    "/home/lass/tmp/the_playlist" = {
-      owner = "lass";
-      group = "syncthing";
-      umask = "0007";
-    };
-  };
-
   boot.blacklistedKernelModules = [ "xpad" ];
   systemd.services.xboxdrv = {
     wantedBy = [ "multi-user.target" ];
@@ -93,7 +77,15 @@
     };
   };
 
-  hardware.bluetooth.enable = true;
+  hardware.bluetooth = {
+    enable = true;
+    powerOnBoot = true;
+    # config.General.Disable = "Headset";
+    extraConfig = ''
+      [General]
+      Disable = Headset
+    '';
+  };
   hardware.pulseaudio.package = pkgs.pulseaudioFull;
   # hardware.pulseaudio.configFile = pkgs.writeText "default.pa" ''
   #   load-module module-bluetooth-policy
diff --git a/lass/1systems/yellow/config.nix b/lass/1systems/yellow/config.nix
index 82fe3fac5..d400697d7 100644
--- a/lass/1systems/yellow/config.nix
+++ b/lass/1systems/yellow/config.nix
@@ -172,7 +172,7 @@ with import <stockholm/lib>;
     client
     dev tun
     proto udp
-    remote 89.249.65.83 1194
+    remote 185.230.127.27 1194
     resolv-retry infinite
     remote-random
     nobind
@@ -195,7 +195,6 @@ with import <stockholm/lib>;
     fast-io
     cipher AES-256-CBC
     auth SHA512
-
     <ca>
     -----BEGIN CERTIFICATE-----
     MIIFCjCCAvKgAwIBAgIBATANBgkqhkiG9w0BAQ0FADA5MQswCQYDVQQGEwJQQTEQ
@@ -251,6 +250,27 @@ with import <stockholm/lib>;
     3f8a56ddb2e64eb67adfc9b337157ff4
     -----END OpenVPN Static key V1-----
     </tls-auth>
-
   '';
+
+  systemd.services.flix-index = {
+    wantedBy = [ "multi-user.target" ];
+    path = [
+      pkgs.coreutils
+      pkgs.findutils
+      pkgs.inotifyTools
+    ];
+    serviceConfig = {
+      Restart = "always";
+      ExecStart = pkgs.writers.writeDash "flix-index" ''
+        set -efu
+
+        DIR=/var/download/finished
+        cd "$DIR"
+        while inotifywait -rq -e create -e move -e delete "$DIR"; do
+          find . -type f > "$DIR"/index.tmp
+          mv "$DIR"/index.tmp "$DIR"/index
+        done
+      '';
+    };
+  };
 }
diff --git a/lass/2configs/baseX.nix b/lass/2configs/baseX.nix
index baf93ffe5..e92ddbcca 100644
--- a/lass/2configs/baseX.nix
+++ b/lass/2configs/baseX.nix
@@ -72,10 +72,11 @@ in {
     git-preview
     gnome3.dconf
     iodine
+    libarchive
     lm_sensors
     ncdu
     nix-index
-    nix-review
+    nixpkgs-review
     nmap
     pavucontrol
     ponymix
@@ -92,6 +93,8 @@ in {
     xsel
     zathura
     (pkgs.writeDashBin "screenshot" ''
+      set -efu
+
       ${pkgs.flameshot-once}/bin/flameshot-once
       ${pkgs.klem}/bin/klem
     '')
diff --git a/lass/2configs/blue-host.nix b/lass/2configs/blue-host.nix
index 718a92e9c..7aabf0931 100644
--- a/lass/2configs/blue-host.nix
+++ b/lass/2configs/blue-host.nix
@@ -49,54 +49,54 @@ in {
   };
 
 
-  systemd.services = builtins.listToAttrs (map (host:
-    let
-    in nameValuePair "sync-blue-${host}" {
-    bindsTo = [ "container@blue.service" ];
-    wantedBy = [ "container@blue.service" ];
-    # ssh needed for rsync
-    path = [ pkgs.openssh ];
-    serviceConfig = {
-      Restart = "always";
-      RestartSec = 10;
-      ExecStart = pkgs.writeDash "sync-blue-${host}" ''
-        set -efu
-        #make sure blue is running
-        /run/wrappers/bin/ping -c1 blue.r > /dev/null
+  #systemd.services = builtins.listToAttrs (map (host:
+  #  let
+  #  in nameValuePair "sync-blue-${host}" {
+  #  bindsTo = [ "container@blue.service" ];
+  #  wantedBy = [ "container@blue.service" ];
+  #  # ssh needed for rsync
+  #  path = [ pkgs.openssh ];
+  #  serviceConfig = {
+  #    Restart = "always";
+  #    RestartSec = 10;
+  #    ExecStart = pkgs.writeDash "sync-blue-${host}" ''
+  #      set -efu
+  #      #make sure blue is running
+  #      /run/wrappers/bin/ping -c1 blue.r > /dev/null
 
-        #make sure the container is unlocked
-        ${pkgs.mount}/bin/mount | ${pkgs.gnugrep}/bin/grep -q '^encfs on /var/lib/containers/blue'
+  #      #make sure the container is unlocked
+  #      ${pkgs.mount}/bin/mount | ${pkgs.gnugrep}/bin/grep -q '^encfs on /var/lib/containers/blue'
 
-        #make sure our target is reachable
-        ${pkgs.untilport}/bin/untilport ${host}.r 22 2>/dev/null
+  #      #make sure our target is reachable
+  #      ${pkgs.untilport}/bin/untilport ${host}.r 22 2>/dev/null
 
-        #start sync
-        ${pkgs.lsyncd}/bin/lsyncd -log scarce ${pkgs.writeText "lsyncd-config.lua" ''
-          settings {
-            nodaemon = true,
-            inotifyMode = "CloseWrite or Modify",
-          }
-          sync {
-            default.rsyncssh,
-            source = "/var/lib/containers/.blue",
-            host = "${host}.r",
-            targetdir = "/var/lib/containers/.blue",
-            rsync = {
-              archive = true,
-              owner = true,
-              group = true,
-            };
-            ssh = {
-              binary = "${pkgs.openssh}/bin/ssh";
-              identityFile = "/var/lib/containers/blue/home/lass/.ssh/id_rsa",
-            },
-          }
-        ''}
-      '';
-    };
-    unitConfig.ConditionPathExists = "!/var/run/ppp0.pid";
-    }
-  ) remote_hosts);
+  #      #start sync
+  #      ${pkgs.lsyncd}/bin/lsyncd -log scarce ${pkgs.writeText "lsyncd-config.lua" ''
+  #        settings {
+  #          nodaemon = true,
+  #          inotifyMode = "CloseWrite or Modify",
+  #        }
+  #        sync {
+  #          default.rsyncssh,
+  #          source = "/var/lib/containers/.blue",
+  #          host = "${host}.r",
+  #          targetdir = "/var/lib/containers/.blue",
+  #          rsync = {
+  #            archive = true,
+  #            owner = true,
+  #            group = true,
+  #          };
+  #          ssh = {
+  #            binary = "${pkgs.openssh}/bin/ssh";
+  #            identityFile = "/var/lib/containers/blue/home/lass/.ssh/id_rsa",
+  #          },
+  #        }
+  #      ''}
+  #    '';
+  #  };
+  #  unitConfig.ConditionPathExists = "!/var/run/ppp0.pid";
+  #  }
+  #) remote_hosts);
 
   environment.systemPackages = [
     (pkgs.writeDashBin "start-blue" ''
diff --git a/lass/2configs/blue.nix b/lass/2configs/blue.nix
index a4000cada..15408a200 100644
--- a/lass/2configs/blue.nix
+++ b/lass/2configs/blue.nix
@@ -26,6 +26,8 @@ with (import <stockholm/lib>);
     { predicate = "-i wiregrill -p udp --dport 60000:61000"; target = "ACCEPT";}
     { predicate = "-i retiolum -p tcp --dport 9998:9999"; target = "ACCEPT";}
     { predicate = "-i wiregrill -p tcp --dport 9998:9999"; target = "ACCEPT";}
+    { predicate = "-i retiolum -p tcp --dport imap"; target = "ACCEPT";}
+    { predicate = "-i wiregrill -p tcp --dport imap"; target = "ACCEPT";}
   ];
 
   systemd.services.chat = let
@@ -64,4 +66,9 @@ with (import <stockholm/lib>);
       ExecStop = "${tmux} kill-session -t IM";
     };
   };
+
+  services.dovecot2 = {
+    enable = true;
+    mailLocation = "maildir:~/Maildir";
+  };
 }
diff --git a/lass/2configs/default.nix b/lass/2configs/default.nix
index ae2754c96..f59988b75 100644
--- a/lass/2configs/default.nix
+++ b/lass/2configs/default.nix
@@ -44,7 +44,15 @@ with import <stockholm/lib>;
             config.krebs.users.lass-yubikey.pubkey
           ];
         };
+        nix = {
+          isNormalUser = true;
+          uid = genid_uint31 "nix";
+          openssh.authorizedKeys.keys = [
+            config.krebs.hosts.mors.ssh.pubkey
+          ];
+        };
       };
+      nix.trustedUsers = ["nix"];
     }
     {
       environment.variables = {
@@ -212,4 +220,7 @@ with import <stockholm/lib>;
   networking.dhcpcd.extraConfig = ''
     noipv4ll
   '';
+
+  # use 24:00 time format, the default got sneakily changed around 20.03
+  i18n.defaultLocale = mkDefault "C.UTF-8";
 }
diff --git a/lass/2configs/exim-smarthost.nix b/lass/2configs/exim-smarthost.nix
index 82839beba..797864b15 100644
--- a/lass/2configs/exim-smarthost.nix
+++ b/lass/2configs/exim-smarthost.nix
@@ -2,8 +2,6 @@
 
   to = concatStringsSep "," [
     "lass@blue.r"
-    "lass@xerxes.r"
-    "lass@mors.r"
   ];
 
   mails = [
@@ -110,6 +108,12 @@
     "auschein@lassul.us"
     "tleech@lassul.us"
     "durstexpress@lassul.us"
+    "acme@lassul.us"
+    "antstore@lassul.us"
+    "openweather@lassul.us"
+    "lobsters@lassul.us"
+    "rewe@lassul.us"
+    "spotify@lassul.us"
   ];
 
 in {
diff --git a/lass/2configs/games.nix b/lass/2configs/games.nix
index 63bfa53e0..67f250ef3 100644
--- a/lass/2configs/games.nix
+++ b/lass/2configs/games.nix
@@ -66,14 +66,16 @@ in {
       useDefaultShell = true;
       packages = with pkgs; [
         # minecraft
-        steam-run
-        scummvm
-        dolphinEmu
-        doom1
-        doom2
-        vdoom1
-        vdoom2
-        vdoomserver
+        # ftb
+        # steam-run
+        # scummvm
+        # dolphinEmu
+        # doom1
+        # doom2
+        # protontricks
+        # vdoom1
+        # vdoom2
+        # vdoomserver
         retroarchBare
       ];
     };
diff --git a/lass/2configs/gc.nix b/lass/2configs/gc.nix
index 0ddb63a03..f9c61c461 100644
--- a/lass/2configs/gc.nix
+++ b/lass/2configs/gc.nix
@@ -4,5 +4,6 @@ with import <stockholm/lib>;
 {
   nix.gc = {
     automatic = ! (elem config.krebs.build.host.name [ "mors" "xerxes" ] || config.boot.isContainer);
+    options = "--delete-older-than 15d";
   };
 }
diff --git a/lass/2configs/git.nix b/lass/2configs/git.nix
index eba68c0bc..edec2dcb4 100644
--- a/lass/2configs/git.nix
+++ b/lass/2configs/git.nix
@@ -58,6 +58,10 @@ let
       cgit.desc = "url shortener";
       cgit.section = "software";
     };
+    grib2json-bin = {
+      cgit.desc = "build jar of grib2json";
+      cgit.section = "deployment";
+    };
     krebspage = {
       cgit.desc = "homepage of krebs";
       cgit.section = "configuration";
diff --git a/lass/2configs/hass/default.nix b/lass/2configs/hass/default.nix
index a48c61a69..66d430cd1 100644
--- a/lass/2configs/hass/default.nix
+++ b/lass/2configs/hass/default.nix
@@ -23,6 +23,7 @@ with import ./lib.nix { inherit lib; };
       # extraComponents = [ "hue" ];
     };
     configWritable = true;
+    lovelaceConfigWritable = true;
   };
 
   lass.hass.config = let
diff --git a/lass/2configs/hass/rooms/bett.nix b/lass/2configs/hass/rooms/bett.nix
index b5da9221c..16227fcb6 100644
--- a/lass/2configs/hass/rooms/bett.nix
+++ b/lass/2configs/hass/rooms/bett.nix
@@ -5,4 +5,35 @@ with import ../lib.nix { inherit lib; };
   lass.hass.config = lib.mkMerge [
     (lightswitch switches.dimmer.bett lights.bett)
   ];
+
+  lass.hass.love = {
+    resources = [{
+      url = "https://raw.githubusercontent.com/ljmerza/light-entity-card/master/dist/light-entity-card.js.map";
+      type = "js";
+    }];
+    views = [{
+      title = "bett";
+      cards = [
+        {
+          type = "markdown";
+          title = "hello world";
+          content = "This is just a test";
+        }
+        {
+          type = "light";
+          entity = "light.${lights.bett}";
+        }
+        {
+          type = "custom:light-entity-card";
+          entity = "light.${lights.bett}";
+        }
+        {
+          type = "history-graph";
+          entities = [
+            "light.${lights.bett}"
+          ];
+        }
+      ];
+    }];
+  };
 }
diff --git a/lass/2configs/hw/x220.nix b/lass/2configs/hw/x220.nix
index 89b119347..31f9787e0 100644
--- a/lass/2configs/hw/x220.nix
+++ b/lass/2configs/hw/x220.nix
@@ -5,7 +5,7 @@
   ];
 
   boot = {
-    initrd.luks.devices = [ { name = "luksroot"; device = "/dev/sda3"; } ];
+    initrd.luks.devices.luksroot.device = "/dev/sda3";
     initrd.luks.cryptoModules = [ "aes" "sha512" "sha1" "xts" ];
     initrd.availableKernelModules = [ "xhci_hcd" "ehci_pci" "ahci" "usb_storage" ];
     extraModulePackages = [
@@ -47,9 +47,10 @@
   services.logind.lidSwitchDocked = "ignore";
 
   services.tlp.enable = true;
-  services.tlp.extraConfig = ''
-    START_CHARGE_THRESH_BAT0=80
-    STOP_CHARGE_THRESH_BAT0=95
-  '';
+  #services.tlp.extraConfig = ''
+  #  START_CHARGE_THRESH_BAT0=80
+  #  STOP_CHARGE_THRESH_BAT0=95
+  #'';
 
+  services.xserver.dpi = 80;
 }
diff --git a/lass/2configs/mail.nix b/lass/2configs/mail.nix
index 174c1ab5e..98affdd83 100644
--- a/lass/2configs/mail.nix
+++ b/lass/2configs/mail.nix
@@ -107,10 +107,12 @@ let
     set mailcap_path = ${mailcap}
 
     # notmuch
-    set nm_default_uri="notmuch://$HOME/Maildir" # path to the maildir
+    set folder="$HOME/Maildir"
+    set nm_default_uri = "notmuch://$HOME/Maildir"
     set nm_record = yes
     set nm_record_tags = "-inbox me archive"
-    set virtual_spoolfile=yes                    # enable virtual folders
+    set spoolfile = +Inbox
+    set virtual_spoolfile = yes
 
 
     set sendmail="${msmtp}/bin/msmtp"            # enables parsing of outgoing mail
@@ -132,8 +134,8 @@ let
       # V
     ''} %r |"
 
-    virtual-mailboxes "INBOX" "notmuch://?query=tag:inbox"
     virtual-mailboxes "Unread" "notmuch://?query=tag:unread"
+    virtual-mailboxes "INBOX" "notmuch://?query=tag:inbox"
     ${concatMapStringsSep "\n" (i: ''${"  "}virtual-mailboxes "${i.name}" "notmuch://?query=tag:${i.name}"'') (mapAttrsToList nameValuePair mailboxes)}
     virtual-mailboxes "TODO" "notmuch://?query=tag:TODO"
     virtual-mailboxes "Starred" "notmuch://?query=tag:*"
@@ -200,9 +202,15 @@ let
     macro pager ] ,@1 'Toggle indexbar
 
     # sidebar
+    set sidebar_divider_char = '│'
+    set sidebar_delim_chars = "/"
+    set sidebar_short_path
+    set sidebar_folder_indent
+    set sidebar_visible = yes
+    set sidebar_format = '%B%?F? [%F]?%* %?N?%N/? %?S?%S?'
     set sidebar_width   = 20
-    set sidebar_visible = yes               # set to "no" to disable sidebar view at startup
-    color sidebar_new yellow default
+    color sidebar_new yellow red
+
     # sidebar bindings
     bind index <left> sidebar-prev          # got to previous folder in sidebar
     bind index <right> sidebar-next         # got to next folder in sidebar
@@ -229,7 +237,6 @@ in {
     mutt
     pkgs.notmuch
     pkgs.muchsync
-    pkgs.haskellPackages.much
     tag-new-mails
     tag-old-mails
   ];
diff --git a/lass/2configs/mpv.nix b/lass/2configs/mpv.nix
index 5d7bfed60..210551a62 100644
--- a/lass/2configs/mpv.nix
+++ b/lass/2configs/mpv.nix
@@ -80,7 +80,7 @@ let
     name = "mpv";
     paths = [
       (pkgs.writeDashBin "mpv" ''
-        exec ${pkgs.mpv}/bin/mpv --no-config --script=${autosub} "$@"
+        exec ${pkgs.mpv}/bin/mpv -vo=gpu --no-config --script=${autosub} "$@"
       '')
       pkgs.mpv
     ];
diff --git a/lass/2configs/paste.nix b/lass/2configs/paste.nix
index 23cab8e6e..0cf62ec0b 100644
--- a/lass/2configs/paste.nix
+++ b/lass/2configs/paste.nix
@@ -7,7 +7,17 @@ with import <stockholm/lib>;
     locations."/".extraConfig = ''
       client_max_body_size 4G;
       proxy_set_header Host $host;
-      proxy_pass http://localhost:9081;
+      proxy_pass http://127.0.0.1:${toString config.krebs.htgen.paste.port};
+    '';
+    locations."/image".extraConfig = /* nginx */ ''
+      client_max_body_size 40M;
+
+      proxy_set_header Host $host;
+      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+      proxy_set_header X-Forwarded-Proto $scheme;
+
+      proxy_pass http://127.0.0.1:${toString config.krebs.htgen.imgur.port};
+      proxy_pass_header Server;
     '';
   };
   services.nginx.virtualHosts."p.krebsco.de" = {
@@ -19,21 +29,36 @@ with import <stockholm/lib>;
         return 403;
       }
       proxy_set_header Host $host;
-      proxy_pass http://localhost:9081;
+      proxy_pass http://127.0.0.1:${toString config.krebs.htgen.paste.port};
+    '';
+    locations."/image".extraConfig = ''
+      proxy_set_header Host $host;
+      proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+      proxy_set_header X-Forwarded-Proto $scheme;
+
+      proxy_pass http://127.0.0.1:${toString config.krebs.htgen.imgur.port};
+      proxy_pass_header Server;
     '';
   };
+
   krebs.htgen.paste = {
     port = 9081;
     script = toString [
       "PATH=${makeBinPath [
         pkgs.nix
+        pkgs.file
       ]}:$PATH"
       "STATEDIR=$HOME"
       ". ${pkgs.htgen}/examples/paste"
     ];
   };
+  krebs.htgen.imgur = {
+    port = 7771;
+    script = /* sh */ ''
+      (. ${pkgs.htgen-imgur}/bin/htgen-imgur)
+    '';
+  };
   krebs.iptables.tables.filter.INPUT.rules = [
     { predicate = "-i retiolum -p tcp --dport 80"; target = "ACCEPT";}
-    { predicate = "-i retiolum -p tcp --dport 9081"; target = "ACCEPT";}
   ];
 }
diff --git a/lass/2configs/radio.nix b/lass/2configs/radio.nix
index 6245691fe..3e8d12381 100644
--- a/lass/2configs/radio.nix
+++ b/lass/2configs/radio.nix
@@ -12,7 +12,16 @@ let
   music_dir = "/home/radio/music";
 
   add_random = pkgs.writeDashBin "add_random" ''
-    ${pkgs.mpc_cli}/bin/mpc add "$(${pkgs.findutils}/bin/find "${music_dir}/the_playlist" | grep -v '/other/' | grep '\.ogg$' | shuf -n1 | sed 's,${music_dir}/,,')"
+    ${pkgs.mpc_cli}/bin/mpc add "$(${pkgs.findutils}/bin/find "${music_dir}/the_playlist" \
+      | grep -Ev '/other/|/.graveyard/' \
+      | grep '\.ogg$' \
+      | shuf -n1 \
+      | sed 's,${music_dir}/,,' \
+    )"
+  '';
+
+  get_current_track_position = pkgs.writeDash "get_current_track_position" ''
+    ${pkgs.mpc_cli}/bin/mpc status | ${pkgs.gawk}/bin/awk '/^\[playing\]/ { sub(/\/.+/,"",$3); split($3,a,/:/); print a[1]*60+a[2] }'
   '';
 
   skip_track = pkgs.writeBashBin "skip_track" ''
@@ -28,8 +37,8 @@ let
       ${pkgs.attr}/bin/setfattr -n user.skip_count -v "$skip_count" "$music_dir"/"$current_track"
       echo skipping: "$track_infos" skip_count: "$skip_count"
     else
-      mkdir -p "$music_dir"/.graveyard/
-      mv "$music_dir"/"$current_track" "$music_dir"/.graveyard/
+      mkdir -p "$music_dir"/the_playlist/.graveyard/
+      mv "$music_dir"/"$current_track" "$music_dir"/the_playlist/.graveyard/
       echo killing: "$track_infos"
     fi
     ${pkgs.mpc_cli}/bin/mpc -q next
@@ -62,10 +71,18 @@ let
   print_current_json = pkgs.writeDashBin "print_current_json" ''
     ${pkgs.jq}/bin/jq -n -c \
       --arg name "$(${pkgs.mpc_cli}/bin/mpc current)" \
+      --arg artist "$(${pkgs.mpc_cli}/bin/mpc current -f %artist%)" \
+      --arg title "$(${pkgs.mpc_cli}/bin/mpc current -f %title%)" \
       --arg filename "$(${pkgs.mpc_cli}/bin/mpc current -f %file%)" \
+      --arg position "$(${get_current_track_position})" \
+      --arg length "$(${pkgs.mpc_cli}/bin/mpc current -f %time%)" \
       --arg youtube "$(${track_youtube_link})" '{
         name: $name,
+        artist: $artist,
+        title: $title,
         filename: $filename,
+        position: $position,
+        length: $length,
         youtube: $youtube
       }'
   '';
@@ -193,7 +210,7 @@ in {
 
       timeLeft () {
         playlistDuration=$(${pkgs.mpc_cli}/bin/mpc --format '%time%' playlist | ${pkgs.gawk}/bin/awk -F ':' 'BEGIN{t=0} {t+=$1*60+$2} END{print t}')
-        currentTime=$(${pkgs.mpc_cli}/bin/mpc status | ${pkgs.gawk}/bin/awk '/^\[playing\]/ { sub(/\/.+/,"",$3); split($3,a,/:/); print a[1]*60+a[2] }')
+        currentTime=$(${get_current_track_position})
         expr ''${playlistDuration:-0} - ''${currentTime:-0}
       }
 
@@ -221,9 +238,11 @@ in {
         ${pkgs.mpc_cli}/bin/mpc idle player > /dev/null
         ${pkgs.mpc_cli}/bin/mpc current -f %file%
       done | while read track; do
+        listeners=$(${pkgs.curl}/bin/curl 'http://localhost:8000/status-json.xsl' \
+          | ${pkgs.jq}/bin/jq '[.icestats.source[].listeners] | add')
         echo "$(date -Is)" "$track" | tee -a "$HISTORY_FILE"
         echo "$(tail -$LIMIT "$HISTORY_FILE")" > "$HISTORY_FILE"
-        ${write_to_irc} "playing: $track"
+        ${write_to_irc} "playing: $track listeners: $listeners"
       done
     '';
   in {
diff --git a/lass/2configs/steam.nix b/lass/2configs/steam.nix
index eae31aec4..2b9811959 100644
--- a/lass/2configs/steam.nix
+++ b/lass/2configs/steam.nix
@@ -13,7 +13,11 @@
   nixpkgs.config.steam.java = true;
   hardware.opengl.extraPackages32 = with pkgs.pkgsi686Linux; [ libva ];
 
-  users.users.games.packages = [ pkgs.steam ];
+  users.users.games.packages = [ (pkgs.steam.override {
+    extraPkgs = p: with p; [
+      gnutls # needed for Halo MCC
+    ];
+  }) ];
 
   #ports for inhome streaming
   krebs.iptables = {
diff --git a/lass/2configs/syncthing.nix b/lass/2configs/syncthing.nix
index 5397c2ca6..7758b860d 100644
--- a/lass/2configs/syncthing.nix
+++ b/lass/2configs/syncthing.nix
@@ -31,5 +31,6 @@ in {
     owner = "lass";
     group = "syncthing";
     umask = "0002";
+    keepGoing = true;
   };
 }
diff --git a/lass/2configs/websites/domsen.nix b/lass/2configs/websites/domsen.nix
index bd113567f..a177a0228 100644
--- a/lass/2configs/websites/domsen.nix
+++ b/lass/2configs/websites/domsen.nix
@@ -26,6 +26,7 @@ in {
     ./default.nix
     ./sqlBackup.nix
     (servePage [ "aldonasiech.com" "www.aldonasiech.com" ])
+    (servePage [ "apanowicz.de" "www.apanowicz.de" ])
     (servePage [ "reich-gebaeudereinigung.de" "www.reich-gebaeudereinigung.de" ])
     (servePage [
       "freemonkey.art"
@@ -34,7 +35,6 @@ in {
     (serveOwncloud [ "o.ubikmedia.de" ])
     (serveWordpress [
       "ubikmedia.de"
-      "apanowicz.de"
       "nirwanabluete.de"
       "ubikmedia.eu"
       "youthtube.xyz"
@@ -42,7 +42,6 @@ in {
       "weirdwednesday.de"
       "jarugadesign.de"
 
-      "www.apanowicz.de"
       "www.nirwanabluete.de"
       "www.ubikmedia.eu"
       "www.youthtube.xyz"
@@ -52,7 +51,6 @@ in {
       "www.jarugadesign.de"
 
       "aldona2.ubikmedia.de"
-      "apanowicz.ubikmedia.de"
       "cinevita.ubikmedia.de"
       "factscloud.ubikmedia.de"
       "illucloud.ubikmedia.de"
@@ -93,6 +91,7 @@ in {
   services.nextcloud = {
     enable = true;
     hostName = "o.xanf.org";
+    package = pkgs.nextcloud18;
     config = {
       adminpassFile = toString <secrets> + "/nextcloud_pw";
       overwriteProtocol = "https";
@@ -107,6 +106,10 @@ in {
 
   # MAIL STUFF
   # TODO: make into its own module
+
+  # workaround for android 7
+  security.acme.certs."lassul.us".keyType = "rsa4096";
+
   services.dovecot2 = {
     enable = true;
     mailLocation = "maildir:~/Mail";
@@ -131,18 +134,16 @@ in {
       server_condition = ''${run{${config.lass.usershadow.path}/bin/verify_arg ${config.lass.usershadow.pattern} $auth1 $auth2}{yes}{no}}
     '';
     internet-aliases = [
-      { from = "dominik@apanowicz.de"; to = "dominik_a@gmx.de"; }
       { from = "dma@ubikmedia.de"; to = "domsen"; }
       { from = "dma@ubikmedia.eu"; to = "domsen"; }
       { from = "mail@habsys.de"; to = "domsen"; }
       { from = "mail@habsys.eu"; to = "domsen"; }
+      { from = "hallo@apanowicz.de"; to = "domsen"; }
       { from = "bruno@apanowicz.de"; to = "bruno"; }
       { from = "mail@jla-trading.com"; to = "jla-trading"; }
       { from = "jms@ubikmedia.eu"; to = "jms"; }
       { from = "ms@ubikmedia.eu"; to = "ms"; }
       { from = "ubik@ubikmedia.eu"; to = "domsen, jms, ms"; }
-      { from = "akayguen@freemonkey.art"; to ="akayguen"; }
-      { from = "bui@freemonkey.art"; to ="bui"; }
       { from = "kontakt@alewis.de"; to ="klabusterbeere"; }
       { from = "hallo@jarugadesign.de"; to ="kasia"; }
 
@@ -153,9 +154,14 @@ in {
       "jla-trading.com"
       "ubikmedia.eu"
       "ubikmedia.de"
+      "apanowicz.de"
       "alewis.de"
       "jarugadesign.de"
     ];
+    dkim = [
+      { domain = "ubikmedia.eu"; }
+      { domain = "apanowicz.de"; }
+    ];
     ssl_cert = "/var/lib/acme/lassul.us/fullchain.pem";
     ssl_key = "/var/lib/acme/lassul.us/key.pem";
   };
diff --git a/lass/2configs/websites/lassulus.nix b/lass/2configs/websites/lassulus.nix
index baeac213b..74585a6f8 100644
--- a/lass/2configs/websites/lassulus.nix
+++ b/lass/2configs/websites/lassulus.nix
@@ -61,7 +61,7 @@ in {
         pubkey = config.krebs.users.lass.pubkey;
       };
     in ''
-      alias ${initscript};
+      alias ${initscript}/bin/init;
     '';
     locations."= /blue.pub".extraConfig = ''
       alias ${pkgs.writeText "pub" config.krebs.users.lass.pubkey};
@@ -69,6 +69,9 @@ in {
     locations."= /mors.pub".extraConfig = ''
       alias ${pkgs.writeText "pub" config.krebs.users.lass-mors.pubkey};
     '';
+    locations."= /yubi.pub".extraConfig = ''
+      alias ${pkgs.writeText "pub" config.krebs.users.lass-yubikey.pubkey};
+    '';
   };
 
   security.acme.certs."cgit.lassul.us" = {
diff --git a/lass/2configs/wine.nix b/lass/2configs/wine.nix
index 02d7ffc8c..5cb019c13 100644
--- a/lass/2configs/wine.nix
+++ b/lass/2configs/wine.nix
@@ -14,8 +14,7 @@ in {
       ];
       createHome = true;
       packages = [
-        pkgs.wine
-        pkgs.winetricks
+        pkgs.wineMinimal
       ];
     };
   };
diff --git a/lass/2configs/zsh.nix b/lass/2configs/zsh.nix
index 05964eb51..e65cdd97d 100644
--- a/lass/2configs/zsh.nix
+++ b/lass/2configs/zsh.nix
@@ -122,14 +122,15 @@
       case $TERM in
         (*xterm* | *rxvt*)
           function precmd {
-            PROMPT_EVALED="$(print -P $TITLE)"
+            PROMPT_EVALED=$(print -P "$TITLE")
             echo -ne "\033]0;$$ $PROMPT_EVALED\007"
           }
-          # This is seen while the shell waits for a command to complete.
-          function preexec {
-            PROMPT_EVALED="$(print -P $TITLE)"
-            echo -ne "\033]0;$$ $PROMPT_EVALED $1\007"
-          }
+          # This seems broken for some reason
+          # # This is seen while the shell waits for a command to complete.
+          # function preexec {
+          #   PROMPT_EVALED=$(print -P "$TITLE")
+          #   echo -ne "\033]0;$$ $PROMPT_EVALED $1\007"
+          # }
         ;;
       esac
     '';
diff --git a/lass/3modules/hass.nix b/lass/3modules/hass.nix
index 30158e78a..96521aaa9 100644
--- a/lass/3modules/hass.nix
+++ b/lass/3modules/hass.nix
@@ -22,6 +22,22 @@ in {
           };
         in valueType;
     };
+    love = mkOption {
+      default = {};
+      type =  with lib.types; let
+          valueType = nullOr (oneOf [
+            bool
+            int
+            float
+            str
+            (attrsOf valueType)
+            (listOf valueType)
+          ]) // {
+            description = "Yaml value";
+            emptyValue.value = {};
+          };
+        in valueType;
+    };
   };
 
   config =
@@ -29,6 +45,7 @@ in {
     mkIf (cfg.config != {})
      {
       services.home-assistant.config = cfg.config;
+      # services.home-assistant.lovelaceConfig = cfg.love;
     };
 }
 
diff --git a/lass/5pkgs/custom/xmonad-lass/default.nix b/lass/5pkgs/custom/xmonad-lass/default.nix
index e6d4b0664..5a741353d 100644
--- a/lass/5pkgs/custom/xmonad-lass/default.nix
+++ b/lass/5pkgs/custom/xmonad-lass/default.nix
@@ -19,6 +19,8 @@ import System.Environment (getArgs, lookupEnv)
 import System.Exit (exitFailure)
 import System.IO (hPutStrLn, stderr)
 import System.Posix.Process (executeFile)
+import Data.Ratio
+
 import XMonad.Actions.CopyWindow (copy, copyToAll, kill1)
 import XMonad.Actions.CycleWS (toggleWS)
 import XMonad.Actions.DynamicWorkspaces ( addWorkspacePrompt, renameWorkspace, removeEmptyWorkspace)
@@ -29,14 +31,17 @@ import XMonad.Hooks.EwmhDesktops (ewmh)
 import XMonad.Hooks.FloatNext (floatNext)
 import XMonad.Hooks.FloatNext (floatNextHook)
 import XMonad.Hooks.ManageDocks (avoidStruts, ToggleStruts(ToggleStruts))
-import XMonad.Hooks.ManageHelpers (composeOne, doCenterFloat, (-?>))
+import XMonad.Hooks.ManageHelpers (doCenterFloat, doRectFloat, (-?>))
+import XMonad.Hooks.Place (placeHook, smart)
 import XMonad.Hooks.UrgencyHook (focusUrgent)
 import XMonad.Hooks.UrgencyHook (withUrgencyHook, UrgencyHook(..))
 import XMonad.Layout.FixedColumn (FixedColumn(..))
+import XMonad.Layout.Grid (Grid(..))
 import XMonad.Layout.Minimize (minimize)
 import XMonad.Layout.NoBorders (smartBorders)
 import XMonad.Layout.MouseResizableTile (mouseResizableTile)
 import XMonad.Layout.SimplestFloat (simplestFloat)
+import XMonad.ManageHook (composeAll)
 import XMonad.Prompt (autoComplete, font, searchPredicate, XPConfig)
 import XMonad.Prompt.Window (windowPromptGoto, windowPromptBringCopy)
 import XMonad.Util.EZConfig (additionalKeysP)
@@ -76,7 +81,7 @@ main' = do
             { terminal           = myTerm
             , modMask            = mod4Mask
             , layoutHook         = smartBorders $ myLayoutHook
-            , manageHook         = floatHooks <+> floatNextHook
+            , manageHook         = floatHooks
             , startupHook =
                 whenJustM (liftIO (lookupEnv "XMONAD_STARTUP_HOOK"))
                           (\path -> forkFile path [] Nothing)
@@ -88,14 +93,17 @@ main' = do
 
 myLayoutHook = defLayout
   where
-    defLayout = minimize $ ((avoidStruts $ Mirror (Tall 1 (3/100) (1/2))) ||| Full ||| FixedColumn 2 80 80 1 ||| Tall 1 (3/100) (1/2) ||| simplestFloat ||| mouseResizableTile)
+    defLayout = minimize $ ((avoidStruts $ Mirror (Tall 1 (3/100) (1/2))) ||| Full ||| FixedColumn 2 80 80 1 ||| Tall 1 (3/100) (1/2) ||| simplestFloat ||| mouseResizableTile ||| Grid)
 
-floatHooks :: Query (Endo WindowSet)
-floatHooks = composeOne
-   [ className =? "Pinentry" -?> doCenterFloat
-   , title =? "fzfmenu" -?> doCenterFloat
-   , title =? "glxgears" -?> doCenterFloat
-   , resource =? "Dialog" -?> doFloat
+floatHooks = composeAll
+   [ className =? "Pinentry" --> doCenterFloat
+   , title =? "fzfmenu" --> doCenterFloat
+   , title =? "glxgears" --> doCenterFloat
+   , resource =? "Dialog" --> doFloat
+   , title =? "Upload to Imgur" -->
+       doRectFloat (W.RationalRect 0 0 (1 % 8) (1 % 8))
+   , placeHook (smart (1,0))
+   , floatNextHook
    ]
 
 myKeyMap :: [([Char], X ())]
@@ -105,7 +113,6 @@ myKeyMap =
     , ("M4-p", spawn "${pkgs.pass}/bin/passmenu --type")
     , ("M4-S-p", spawn "${pkgs.otpmenu}/bin/otpmenu")
     , ("M4-o", spawn "${pkgs.brain}/bin/brainmenu --type")
-    , ("M4-i", spawn "${pkgs.dpass}/bin/dpassmenu --type")
     , ("M4-z", spawn "${pkgs.emot-menu}/bin/emoticons")
 
     , ("<XF86AudioMute>", spawn "${pkgs.pulseaudioLight.out}/bin/pactl -- set-sink-mute @DEFAULT_SINK@ toggle")
diff --git a/lass/5pkgs/emot-menu/default.nix b/lass/5pkgs/emot-menu/default.nix
index 440e160d0..3ce635dac 100644
--- a/lass/5pkgs/emot-menu/default.nix
+++ b/lass/5pkgs/emot-menu/default.nix
@@ -29,6 +29,6 @@ writeDashBin "emoticons" ''
 
   data=$(${coreutils}/bin/cat ${emoticons})
   emoticon=$(echo "$data" | ${dmenu}/bin/dmenu | ${gnused}/bin/sed 's/ | .*//')
-  ${xdotool}/bin/xdotool type -- "$emoticon"
+  ${xdotool}/bin/xdotool type --clearmodifiers -- "$emoticon"
   exit 0
 ''
diff --git a/lass/5pkgs/init/default.nix b/lass/5pkgs/init/default.nix
index cbcfe2c00..ee49951b1 100644
--- a/lass/5pkgs/init/default.nix
+++ b/lass/5pkgs/init/default.nix
@@ -2,10 +2,10 @@
 
 with lib;
 
-pkgs.writeScript "init" ''
+pkgs.writeScriptBin "init" ''
   #!/usr/bin/env nix-shell
-  #! nix-shell -i bash -p jq parted libxfs
-  set -efu
+  #! nix-shell -i bash -p cryptsetup gptfdisk jq libxfs
+  set -xefuo pipefail
 
   disk=$1
 
@@ -14,12 +14,12 @@ pkgs.writeScript "init" ''
     exit 2
   fi
 
+  bootdev="$disk"2
   luksdev="$disk"3
   luksmap=/dev/mapper/${luksmap}
 
   vgname=${vgname}
 
-  bootdev=/dev/sda2
 
   rootdev=/dev/mapper/${vgname}-root
   homedev=/dev/mapper/${vgname}-home
@@ -35,15 +35,13 @@ pkgs.writeScript "init" ''
   #   dd if=/dev/zero bs=512 count=34 of=/dev/sda
   # TODO zero last 34 blocks (lsblk -bno SIZE /dev/sda)
   if ! test "$(blkid -o value -s PTTYPE "$disk")" = gpt; then
-    parted -s -a optimal "$disk" \
-        mklabel gpt \
-        mkpart no-fs 0 1024KiB \
-        set 1 bios_grub on \
-        mkpart ESP fat32 1025KiB 1024MiB  set 2 boot on \
-        mkpart primary 1025MiB 100%
+    sgdisk -og "$disk"
+    sgdisk -n 1:2048:4095 -c 1:"BIOS Boot Partition" -t 1:ef02 "$disk"
+    sgdisk -n 2:4096:+1G -c 2:"EFI System Partition" -t 2:ef00 "$disk"
+    sgdisk -n 3:0:0 -c 3:"LUKS container" -t 3:8300 "$disk"
   fi
 
-  if ! test "$(blkid -o value -s PARTLABEL "$luksdev")" = primary; then
+  if ! test "$(blkid -o value -s PARTLABEL "$luksdev")" = "LUKS container"; then
     echo zonk2
     exit 23
   fi
@@ -58,7 +56,6 @@ pkgs.writeScript "init" ''
   if ! test -e "$luksmap"; then
     echo "$lukspw" | cryptsetup luksOpen "$luksdev" "$(basename "$luksmap")" -
   fi
-  # cryptsetup close
 
   if ! test "$(blkid -o value -s TYPE "$luksmap")" = LVM2_member; then
     pvcreate "$luksmap"
@@ -68,11 +65,7 @@ pkgs.writeScript "init" ''
 
   lvchange -a y /dev/mapper/"$vgname"
 
-  if ! test -e "$rootdev"; then lvcreate -L 7G -n root "$vgname"; fi
-  if ! test -e "$homedev"; then lvcreate -L 100M -n home "$vgname"; fi
-
-  # lvchange -a n "$vgname"
-
+  if ! test -e "$rootdev"; then lvcreate -L 3G -n root "$vgname"; fi
 
   #
   # formatting
@@ -82,35 +75,23 @@ pkgs.writeScript "init" ''
     mkfs.vfat "$bootdev"
   fi
 
-  if ! test "$(blkid -o value -s TYPE "$rootdev")" = btrfs; then
+  if ! test "$(blkid -o value -s TYPE "$rootdev")" = xfs; then
     mkfs.xfs "$rootdev"
   fi
 
-  if ! test "$(blkid -o value -s TYPE "$homedev")" = btrfs; then
-    mkfs.xfs "$homedev"
-  fi
-
-
   if ! test "$(lsblk -n -o MOUNTPOINT "$rootdev")" = /mnt; then
+    mkdir -p /mnt
     mount "$rootdev" /mnt
   fi
   if ! test "$(lsblk -n -o MOUNTPOINT "$bootdev")" = /mnt/boot; then
     mkdir -m 0000 -p /mnt/boot
     mount "$bootdev" /mnt/boot
   fi
-  if ! test "$(lsblk -n -o MOUNTPOINT "$homedev")" = /mnt/home; then
-    mkdir -m 0000 -p /mnt/home
-    mount "$homedev" /mnt/home
-  fi
-
-  # umount -R /mnt
 
   #
   # dependencies for stockholm
   #
 
-  nix-env -iA nixos.git
-
   # TODO: get sentinal file from target_path
   mkdir -p /mnt/var/src
   touch /mnt/var/src/.populate
@@ -119,7 +100,7 @@ pkgs.writeScript "init" ''
   # print all the infos
   #
 
-  parted "$disk" print
+  gdisk -l "$disk"
   lsblk "$disk"
 
   echo READY.
diff --git a/lass/5pkgs/init/run-vm.sh b/lass/5pkgs/init/run-vm.sh
new file mode 100755
index 000000000..13914ad5f
--- /dev/null
+++ b/lass/5pkgs/init/run-vm.sh
@@ -0,0 +1,7 @@
+#!/usr/bin/env nix-shell
+#! nix-shell -i bash -p nixos-generators
+
+set -efu
+
+WD=$(dirname "$0")
+nixos-generate -I stockholm="$WD"/../../.. -c "$WD"/config.nix -f vm-nogui --run
diff --git a/lass/5pkgs/init/test.nix b/lass/5pkgs/init/test.nix
new file mode 100644
index 000000000..e76e7e009
--- /dev/null
+++ b/lass/5pkgs/init/test.nix
@@ -0,0 +1,13 @@
+{ config, lib, pkgs, ... }:
+{
+  virtualisation.emptyDiskImages = [
+    8000
+  ];
+  virtualisation.memorySize = 1500;
+  boot.tmpOnTmpfs = true;
+
+  environment.systemPackages = [
+    (pkgs.callPackage ./default.nix {})
+  ];
+  services.mingetty.autologinUser = lib.mkForce "root";
+}
diff --git a/lass/5pkgs/init/test.sh b/lass/5pkgs/init/test.sh
new file mode 100755
index 000000000..0ceaa73ca
--- /dev/null
+++ b/lass/5pkgs/init/test.sh
@@ -0,0 +1,11 @@
+#!/usr/bin/env nix-shell
+#! nix-shell -i bash -p nixos-generators
+
+set -xefu
+
+WD=$(realpath $(dirname "$0"))
+TMPDIR=$(mktemp -d)
+cd "$TMPDIR"
+nixos-generate -c "$WD"/test.nix -f vm-nogui --run "$@"
+cd -
+rm -r "$TMPDIR"
diff --git a/makefu/1systems/wbob/config.nix b/makefu/1systems/wbob/config.nix
index 9d0c7af61..32dedbde2 100644
--- a/makefu/1systems/wbob/config.nix
+++ b/makefu/1systems/wbob/config.nix
@@ -26,7 +26,8 @@ in {
       # <stockholm/makefu/2configs/audio/jack-on-pulse.nix>
       # <stockholm/makefu/2configs/audio/realtime-audio.nix>
       # <stockholm/makefu/2configs/vncserver.nix>
-      <stockholm/makefu/2configs/logging/server.nix>
+      ## no need for dns logs anymore
+      # <stockholm/makefu/2configs/logging/server.nix>
 
       # Services
       # <stockholm/makefu/2configs/hydra/stockholm.nix>
@@ -48,6 +49,7 @@ in {
 
       <stockholm/makefu/2configs/bureautomation> # new hass entry point
       <stockholm/makefu/2configs/bureautomation/led-fader.nix>
+      <stockholm/makefu/2configs/bureautomation/kalauerbot.nix>
       # <stockholm/makefu/2configs/bureautomation/visitor-photostore.nix>
       # <stockholm/makefu/2configs/bureautomation/mpd.nix> #mpd is only used for TTS, this is the web interface
       <stockholm/makefu/2configs/mqtt.nix>
diff --git a/makefu/2configs/bureautomation/kalauerbot.nix b/makefu/2configs/bureautomation/kalauerbot.nix
new file mode 100644
index 000000000..d61b8885e
--- /dev/null
+++ b/makefu/2configs/bureautomation/kalauerbot.nix
@@ -0,0 +1,17 @@
+{ config, lib, pkgs, ... }:
+
+{
+  systemd.services.kalauerbot  = {
+    description = "Kalauerbot";
+    after = [ "network-online.target"  ];
+    wantedBy = [ "multi-user.target"  ];
+    environment = import <secrets/bureautomation/citadel.nix>;
+    serviceConfig = {
+      DynamicUser = true;
+      StateDirectory = "kalauerbot";
+      WorkingDirectory = "/var/lib/kalauerbot";
+      ExecStart = "${pkgs.kalauerbot}/bin/kalauerbot";
+      PrivateTmp = true;
+    };
+  };
+}
diff --git a/makefu/2configs/deployment/docker/template.md b/makefu/2configs/deployment/docker/template.md
index a26b2f042..690ce236e 100644
--- a/makefu/2configs/deployment/docker/template.md
+++ b/makefu/2configs/deployment/docker/template.md
@@ -1,15 +1,20 @@
 # BGT<NUMBER>
 
-1. studio-link aufnehmen drücken (wichtig)
-  - markus 6407eb63@studio-link.de
-  - Felix1 1f1021b2@studio-link.de
-  - L33tFelix 4d47a82a@studio-link.de
-  - Ingo  03b33b4a@studio-link.de
+1. studio-link aufnehmen drücken, schauen ob file größer wird (wichtig)
+  - markus      6407eb63@studio-link.de
+  - Felix1      1f1021b2@studio-link.de
+  - L33tFelix   842f85eb@studio-link.de
+  - Ingo        03b33b4a@studio-link.de
 2. audiocity starten, 48000Hz einstellen, Audio-Device checken und aufnehmen drücken (wichtig)
+  * alternativ:
+    `$ pacmd list-sources | grep -e device.string -e 'name:' # keins der "monitor" devices`
+    `$ parecord --channels=1 -d alsa_input.usb-Burr-Brown_from_TI_USB_Audio_CODEC-00.analog-stereo bgt.wav`
 3. obs starten und aufnehmen drücken (eher unwichtig)
-4. darkice starten (wichtig)
-4. klatschen
-5. Hallo und herzlich Willkommen
+5. darkice starten (wichtig)
+6. klatschen
+7. Hallihallo und Herzlich Willkommen
+8. chapter-marker starten mit ctrl-u auf "H" von "Halli" (wichtig)
+9. Blast markieren und ctrl-j drücken für neuen Eintrag
 
 ## Vorschläge
 ### Backlog von Picks und Lesefoo aus der letzten Woche
@@ -31,3 +36,5 @@
 ## Lesefoo
 
 ## Picks
+
+## Ende
diff --git a/makefu/2configs/ham/default.nix b/makefu/2configs/ham/default.nix
index c7e8733b7..8311a1a76 100644
--- a/makefu/2configs/ham/default.nix
+++ b/makefu/2configs/ham/default.nix
@@ -39,6 +39,15 @@ in {
       ];
     };
     config = {
+      influxdb = {
+        database = "ham";
+        host = "localhost:8086";
+        tags = {
+          instance = "omo";
+          source = "hass";
+        };
+      };
+
       config = {};
       input_select = zigbee.input_select; # dict
       timer = zigbee.timer // kurzzeitwecker.timer; # dict
@@ -91,6 +100,7 @@ in {
           ];
       sun.elevation = 247;
       recorder = {};
+      device_tracker = (import ./device_tracker/openwrt.nix);
       media_player = [
         { platform = "FireTV Stick kodi";
           host = firetv_stick;
@@ -128,7 +138,7 @@ in {
       };
       luftdaten = {
         show_on_map = true;
-        sensor_id = 679;
+        sensor_id = 10529;
         sensors.monitored_conditions = [ "P1" "P2" ];
       };
       #binary_sensor =
@@ -162,4 +172,5 @@ in {
     configDir = hassdir;
   };
 
+  state = [ "/var/lib/hass/known_devices.yaml" ];
 }
diff --git a/makefu/2configs/ham/device_tracker/openwrt.nix b/makefu/2configs/ham/device_tracker/openwrt.nix
new file mode 100644
index 000000000..8173fcfcb
--- /dev/null
+++ b/makefu/2configs/ham/device_tracker/openwrt.nix
@@ -0,0 +1,10 @@
+[
+  { platform = "luci";
+    host = "192.168.1.5";
+    username = "root";
+    password = import <secrets/hass/router.nix>;
+    interval_seconds = 30; # instead of 12seconds
+    consider_home = 300; # 5 minutes timeout
+    new_device_defaults.track_new_devices = true;
+  }
+]
diff --git a/makefu/2configs/home-manager/cli.nix b/makefu/2configs/home-manager/cli.nix
index 5d5673b81..38d02424c 100644
--- a/makefu/2configs/home-manager/cli.nix
+++ b/makefu/2configs/home-manager/cli.nix
@@ -2,31 +2,6 @@
   imports = [ ./zsh.nix ];
   home-manager.users.makefu = {
     programs.direnv = {
-      stdlib = ''
-use_nix() {
-  local cache=".direnv.$(nixos-version --hash)"
-
-  if [[ ! -e "$cache" ]] || \
-    [[ "$HOME/.direnvrc" -nt "$cache" ]] || \
-    [[ ".envrc" -nt "$cache" ]] || \
-    [[ "default.nix" -nt "$cache" ]] || \
-    [[ "shell.nix" -nt "$cache" ]];
-  then
-    local tmp="$(mktemp "$${cache}.tmp-XXXXXXXX")"
-    trap "rm -rf '$tmp' >/dev/null" EXIT
-    nix-shell --show-trace "$@" --run 'direnv dump' > "$tmp" && \
-    mv "$tmp" "$cache"
-  fi
-
-  direnv_load cat "$cache"
-
-  if [[ $# = 0 ]]; then
-    watch_file default.nix
-    watch_file shell.nix
-    rm direnv.* 2>/dev/null
-  fi
-}
-'';
       enableZshIntegration = true;
     };
   };
diff --git a/makefu/2configs/hw/switch.nix b/makefu/2configs/hw/switch.nix
index d46e8cf3f..79de7ffb1 100644
--- a/makefu/2configs/hw/switch.nix
+++ b/makefu/2configs/hw/switch.nix
@@ -2,9 +2,11 @@
 
 {
 
-  users.extraUsers.${config.krebs.build.user.name}.extraGroups = [ "plugdev" ];
-
+  users.users.makefu.extraGroups = [ "plugdev" ];
+  users.groups.plugdev = {};
   services.udev.extraRules = ''
     SUBSYSTEM=="usb", ATTR{idVendor}=="0955", MODE="0664", GROUP="plugdev"
+    SUBSYSTEM=="usb", ATTR{idVendor}=="16c0", ATTR{idProduct}=="27e2", SYMLINK+="switch-%k", MODE="0664", GROUP="plugdev"
+    SUBSYSTEM=="usb", ATTR{idVendor}=="057e", ATTR{idProduct}=="3000", SYMLINK+="switch-%k", MODE="0664", GROUP="plugdev"
   '';
 }
diff --git a/makefu/2configs/stats/server.nix b/makefu/2configs/stats/server.nix
index bb8fd1750..a2d0693ab 100644
--- a/makefu/2configs/stats/server.nix
+++ b/makefu/2configs/stats/server.nix
@@ -41,40 +41,7 @@ in {
       bind-address = ":${toString collectd-port}";
     }];
   };
-  krebs.kapacitor =
-   let
-      echoToIrc = pkgs.writeDash "echo_irc" ''
-        set -euf
-        data="$(${pkgs.jq}/bin/jq -r .message)"
-        export LOGNAME=${irc-nick}
-        ${pkgs.irc-announce}/bin/irc-announce \
-          ${irc-server} 6667 ${irc-nick} \#noise "$data" >/dev/null
-      '';
-  in {
-    enable = true;
-    alarms = {
-      cpu_deadman.database = db;
-      cpu_deadman.text = ''
-        var data = batch
-            |query(${"'''"}
-                  SELECT mean("value") AS mean
-                  FROM "collectd_db"."default"."cpu_value"
-                  WHERE "type_instance" = 'idle' AND "type" = 'percent' fill(0)
-                ${"'''"})
-                .period(10m)
-                .every(1m)
-                .groupBy('host')
-        data |alert()
-                .crit(lambda: "mean" < 50)
-                .stateChangesOnly()
-                .exec('${echoToIrc}')
-        data |deadman(1.0,5m)
-                .stateChangesOnly()
-                .exec('${echoToIrc}')
-      '';
-    };
 
-  };
   networking.firewall.extraCommands = ''
     iptables -A INPUT -i retiolum -p udp --dport ${toString collectd-port} -j ACCEPT
     iptables -A INPUT -i retiolum -p tcp --dport ${toString influx-port} -j ACCEPT
diff --git a/makefu/2configs/tools/consoles.nix b/makefu/2configs/tools/consoles.nix
index e54ff4ff5..a4c474c5b 100644
--- a/makefu/2configs/tools/consoles.nix
+++ b/makefu/2configs/tools/consoles.nix
@@ -7,5 +7,6 @@
     cue2pops
     nx_game_info
     hactool
+    nsrenamer
   ];
 }
diff --git a/makefu/2configs/tools/dev.nix b/makefu/2configs/tools/dev.nix
index 276ed6cdc..2acdcf69c 100644
--- a/makefu/2configs/tools/dev.nix
+++ b/makefu/2configs/tools/dev.nix
@@ -13,8 +13,7 @@
     gi
     flashrom
     mosquitto
-    nodemcu-uploader
-    esptool
+    esphome
     # nix related
     nix-index
     nix-review
diff --git a/makefu/5pkgs/awesomecfg/default.nix b/makefu/5pkgs/awesomecfg/default.nix
index 1ae2f50d9..acbe61f3f 100644
--- a/makefu/5pkgs/awesomecfg/default.nix
+++ b/makefu/5pkgs/awesomecfg/default.nix
@@ -6,15 +6,17 @@
 , blueman
 , clipit
 , flameshot
+, chapter-marker
 , modkey ? "Mod4"
 , locker? "${pkgs.xlock}/bin/xlock -mode blank"
 , ... }:
 
 {
-  # replace: @alsaUtils@ @xlockmore@ @xbacklight@ @modkey@
+  # replace: @alsaUtils@ @xlockmore@ @xbacklight@ @modkey@ @chapter-marker@
   full = lib.makeOverridable pkgs.substituteAll {
     name = "awesome_full_config";
     inherit alsaUtils locker xbacklight modkey networkmanagerapplet blueman clipit flameshot ;
+    chaptermarker = chapter-marker;
     isExecutable = false;
     src = ./full.cfg;
   };
diff --git a/makefu/5pkgs/awesomecfg/full.cfg b/makefu/5pkgs/awesomecfg/full.cfg
index d96b61ad6..86b401cfa 100644
--- a/makefu/5pkgs/awesomecfg/full.cfg
+++ b/makefu/5pkgs/awesomecfg/full.cfg
@@ -376,6 +376,12 @@ globalkeys = awful.util.table.join(
     awful.key({ }, "XF86AudioMute", function ()
         awful.util.spawn("@alsaUtils@/bin/amixer -q -D default sset Master toggle", false) end),
 
+    -- chapter-marker
+    awful.key({ "Control" }, "u", function () awful.spawn("@chaptermarker@/bin/chapter-start") end,
+              {description = "start the chapter marker",}),
+    awful.key({ "Control" }, "j", function () awful.spawn("@chaptermarker@/bin/chapter-mark") end,
+              {description = "create a chapter mark",}),
+
     -- Prompt
     awful.key({ modkey },            "r",     function () awful.screen.focused().mypromptbox:run() end,
               {description = "run prompt", group = "launcher"}),
@@ -492,9 +498,16 @@ awful.rules.rules = {
       properties = { floating = true } },
     --{ rule = { class = "gimp" },
     --  properties = { floating = true } },
-    -- Set Firefox to always map on tags number 2 of screen 1.
-    -- { rule = { class = "Firefox" },
-    --   properties = { tag = tags[1][2] } },
+    { rule = { class = "Firefox" },
+       properties = { tag = tags[3] } },
+    { rule = { class = "signal-desktop" },
+       properties = { tag = tags[4] } },
+    { rule = { class = "telegram-desktop" },
+       properties = { tag = tags[4] } },
+    { rule = { class = "mutt" },
+       properties = { tag = tags[5] } },
+    { rule = { class = "mosh" },
+       properties = { tag = tags[2] } },
 }
 -- }}}
 
@@ -569,7 +582,7 @@ local os = {
 
 -- {{{ autostart
 do
-  awful.spawn("urxvt", { tag = tags[1] }) -- dev shell
+  -- awful.spawn("urxvt", { tag = tags[1] }) -- dev shell
   awful.spawn("urxvt -e mosh makefu@gum.i", { tag = tags[2] })
   awful.spawn("firefox", { tag = tags[3] })
   awful.spawn("telegram-desktop", { tag = tags[4] })
diff --git a/makefu/5pkgs/chapter-marker/default.nix b/makefu/5pkgs/chapter-marker/default.nix
index fe3e48142..5ffb63ae9 100644
--- a/makefu/5pkgs/chapter-marker/default.nix
+++ b/makefu/5pkgs/chapter-marker/default.nix
@@ -1,4 +1,4 @@
-{ coreutils, fetchFromGitHub, makeWrapper, xdotool, stdenv, ... }:
+{ coreutils, fetchFromGitHub, makeWrapper, xclip, libnotify, stdenv, ... }:
 
 stdenv.mkDerivation rec {
   name = "chapter-marker-${version}";
@@ -6,8 +6,8 @@ stdenv.mkDerivation rec {
   src = fetchFromGitHub {
     owner = "makefu";
     repo = "chapter-marker";
-    rev = "7602b611fb3d67fdb8a86db23220074dfa9dfa1e";
-    sha256 = "0cwh650c3qhdrcvrqfzgrwpsnj4lbq64fw2sfwvnbxz94b4q36av";
+    rev = "71b9bb8bc4d6fa87de6bea8f42d5486d05cf5443";
+    sha256 = "13cvk24pwwyv9i21h57690s5niwkcrcvn8l24zfxwbgq0wwzw38x";
   };
 
   buildInputs = [ makeWrapper ];
@@ -16,7 +16,8 @@ stdenv.mkDerivation rec {
     let
       path = stdenv.lib.makeBinPath [
         coreutils
-        xdotool
+        libnotify
+        xclip
       ];
     in
     ''
diff --git a/makefu/5pkgs/kalauerbot/default.nix b/makefu/5pkgs/kalauerbot/default.nix
new file mode 100644
index 000000000..2cecbc3f2
--- /dev/null
+++ b/makefu/5pkgs/kalauerbot/default.nix
@@ -0,0 +1,18 @@
+{ stdenv, python3, fetchgit }:
+python3.pkgs.buildPythonPackage rec {
+name = "kalauerbot";
+rev = "08d98aa";
+  src = fetchgit {
+    url = "http://cgit.euer.krebsco.de/kalauerbot";
+    inherit rev;
+    sha256 = "017hh61smgq4zsxd10brgwmykwgwabgllxjs31xayvs1hnqmkv2v";
+  };
+  propagatedBuildInputs = with python3.pkgs;[
+    (callPackage ./python-matrixbot.nix {})
+    (stdenv.lib.overrideDerivation googletrans (self: {
+      patches = [ ./translate.patch ];
+    }))
+  ];
+  checkInputs = [ python3.pkgs.black ];
+}
+
diff --git a/makefu/5pkgs/kalauerbot/matrixbot.patch b/makefu/5pkgs/kalauerbot/matrixbot.patch
new file mode 100644
index 000000000..2b9bbbea1
--- /dev/null
+++ b/makefu/5pkgs/kalauerbot/matrixbot.patch
@@ -0,0 +1,12 @@
+diff --git a/matrixbot/matrixbot.py b/matrixbot/matrixbot.py
+index 8e5598c..d8c23d2 100644
+--- a/matrixbot/matrixbot.py
++++ b/matrixbot/matrixbot.py
+@@ -51,7 +51,6 @@ class MatrixBot:
+         self.user = None
+         if self.token is not None and self.user_id is not None:
+             self.user = self.client.get_user(self.user_id)
+-            self.user.set_display_name(self.display_name)
+             self.init_rooms(self.client.rooms)
+             self.invite_listener = self.client.add_invite_listener(self.handle_invite)
+         self.cache = Cache(dbfile=cache_db)
diff --git a/makefu/5pkgs/kalauerbot/python-matrixbot.nix b/makefu/5pkgs/kalauerbot/python-matrixbot.nix
new file mode 100644
index 000000000..7bc5aa7f3
--- /dev/null
+++ b/makefu/5pkgs/kalauerbot/python-matrixbot.nix
@@ -0,0 +1,31 @@
+{ lib
+, buildPythonPackage
+, fetchPypi
+, markdown
+, matrix-client
+}:
+
+buildPythonPackage rec {
+  pname = "python-matrixbot";
+  version = "0.0.7";
+  CI_COMMIT_TAG = version;
+
+  #src = ./python-matrixbot;
+  src = fetchPypi {
+    inherit pname version;
+    sha256 = "9412981b14ff3ab7ffbb1bfc1691758113ab8d71f731b3093d8808c286b69c71";
+  };
+  patches = [ ./matrixbot.patch ];
+
+  propagatedBuildInputs = [
+    markdown
+    matrix-client
+  ];
+
+  meta = with lib; {
+    description = "A basic bot for Matrix";
+    homepage = https://gitlab.com/gibberfish/python-matrixbot;
+    license = licenses.mit;
+    # maintainers = [ maintainers. ];
+  };
+}
diff --git a/makefu/5pkgs/kalauerbot/translate.patch b/makefu/5pkgs/kalauerbot/translate.patch
new file mode 100644
index 000000000..6ff820726
--- /dev/null
+++ b/makefu/5pkgs/kalauerbot/translate.patch
@@ -0,0 +1,17 @@
+diff --git a/googletrans/client.py b/googletrans/client.py
+index 89c2237..c203b44 100644
+--- a/googletrans/client.py
++++ b/googletrans/client.py
+@@ -190,6 +190,13 @@ class Translator(object):
+             pass
+         if not PY3 and isinstance(pron, unicode) and isinstance(origin, str):  # pragma: nocover
+             origin = origin.decode('utf-8')
++
++        if pron is None:
++            try:
++                pron = data[0][2][2]
++            except: # pragma: nocover
++                pass
++
+         if dest in EXCLUDES and pron == origin:
+             pron = translated
diff --git a/makefu/5pkgs/nsrenamer/default.nix b/makefu/5pkgs/nsrenamer/default.nix
new file mode 100644
index 000000000..16b9a4f20
--- /dev/null
+++ b/makefu/5pkgs/nsrenamer/default.nix
@@ -0,0 +1,3 @@
+{ pkgs,... }:
+# TODO: dependencies: coreutils, nx_game_info,
+pkgs.writeScriptBin "nsrenamer" (builtins.readFile ./nsrenamer.sh)
diff --git a/makefu/5pkgs/nsrenamer/nsrenamer.sh b/makefu/5pkgs/nsrenamer/nsrenamer.sh
new file mode 100755
index 000000000..16aec3113
--- /dev/null
+++ b/makefu/5pkgs/nsrenamer/nsrenamer.sh
@@ -0,0 +1,58 @@
+#!/usr/bin/env bash
+set -euf
+indir=$(dirname "$1")
+inname=$(basename "$1")
+out=$(nxgameinfo_cli "$1")
+ext=${1##*.}
+id=$(awk -F: '/├ Title ID:/{print $2}' <<<"$out" |xargs)
+baseid=$(awk -F: '/Base Title ID:/{print $2}' <<<"$out" |xargs)
+version=$(awk -F: '/├ Version:/{print $2}' <<<"$out" |xargs)
+name=$(awk -F: '/Title Name/{print $2}' <<<"$out" | sed "s/[:']//g" | xargs )
+type=$(awk -F: '/Type:/{print $2}' <<<"$out" | xargs)
+
+! test -n "$id" && echo "Title ID cannot be empty!" && exit 1
+! test -n "$type" && echo "type cannot be empty!" && exit 1
+
+if test "$type" == Base;then
+  ! test -n "$name" && echo "Title Name cannot be empty!" && exit 1
+  NAME="$name [$id][v$version].$ext"
+elif test "$type" == Update;then
+  ! test -n "$name" && echo "Title Name cannot be empty!" && exit 1
+  ! test -n "$version" && echo "Version cannot be empty!" && exit 1
+  NAME="$name [UPD][$id][v$version].$ext"
+elif test "$type" == DLC;then
+  dlcname=$(jq -r --arg id "$id" '.[$id].name' < ~/.switch/titles.US.en.json | sed "s/[:']//g")
+  if test -n "$dlcname" ;then
+    NAME="$dlcname [DLC][$id][v$version].$ext"
+  else
+    ! test -n "$name" && echo "dlcname cannot be found in titles.US.en.json and $name is empty!" && exit 1
+    NAME="$dlcname [DLC][$id][v$version].$ext"
+  fi
+else
+  echo "unknown type '$type'"
+  exit 1
+fi
+newname=$indir/$NAME
+
+if test "$NAME" == "${inname}";then
+  echo "name didn't change,doing nothing"
+  exit 0
+fi
+if test -e "$newname" ;then
+  echo "'$NAME' already exists, will not override"
+  exit 1
+fi
+
+if test -n "${FORCE:-}" ;then
+  CONFIRM=y
+else
+  read -p "rename '$inname' to '$NAME' - [y/N]" CONFIRM
+fi
+
+if test -n "${FORCE:-}" -o "$CONFIRM" == "y" -o "$CONFIRM" == "Y";then
+  mv -nv "$1" "$newname"
+else
+  echo "bailing out"
+  exit 1
+fi
+
diff --git a/makefu/5pkgs/tt-rss/default.nix b/makefu/5pkgs/tt-rss/default.nix
new file mode 100644
index 000000000..4907a73a5
--- /dev/null
+++ b/makefu/5pkgs/tt-rss/default.nix
@@ -0,0 +1,25 @@
+{ stdenv, fetchurl }:
+
+stdenv.mkDerivation rec {
+  pname = "tt-rss";
+  version = "2020-09-23";
+  rev = "d0ed7890df";
+
+  src = fetchurl {
+    url = "https://git.tt-rss.org/git/tt-rss/archive/${rev}.tar.gz";
+    sha256 = "1b2fczd41bqg9bq37r99svrqswr9qrp35m6gn3nz032yqcwc22ij";
+  };
+
+  installPhase = ''
+    mkdir $out
+    cp -ra * $out/
+  '';
+
+  meta = with stdenv.lib; {
+    description = "Web-based news feed (RSS/Atom) aggregator";
+    license = licenses.gpl2Plus;
+    homepage = "https://tt-rss.org";
+    maintainers = with maintainers; [ globin zohl ];
+    platforms = platforms.all;
+  };
+}