diff --git a/krebs/default.nix b/krebs/default.nix
index d99f60aaa..7ec791529 100644
--- a/krebs/default.nix
+++ b/krebs/default.nix
@@ -1,12 +1,14 @@
-{ config, lib, pkgs, ... }:
-with import <stockholm/lib>;
 {
+
   imports = [
     ./3modules
-    {
-      nixpkgs.config.packageOverrides =
-        import ../submodules/nix-writers/pkgs pkgs;
-    }
   ];
-  nixpkgs.config.packageOverrides = import ./5pkgs pkgs;
+
+  nixpkgs = {
+    overlays = [
+      (import ./5pkgs)
+      (import ../submodules/nix-writers/pkgs)
+    ];
+  };
+
 }
diff --git a/submodules/krops b/submodules/krops
index 4ce5dae7b..6f49342b2 160000
--- a/submodules/krops
+++ b/submodules/krops
@@ -1 +1 @@
-Subproject commit 4ce5dae7bceb635e96a9f8d5658a1bd2aada4f66
+Subproject commit 6f49342b2d5973478f1f5eb6f8d6307059e7bcf7
diff --git a/tv/1systems/querel/config.nix b/tv/1systems/querel/config.nix
index 01d67b5f5..6e7944cdf 100644
--- a/tv/1systems/querel/config.nix
+++ b/tv/1systems/querel/config.nix
@@ -25,7 +25,6 @@ with import <stockholm/lib>;
   };
 
   environment.systemPackages = with pkgs; [
-    chromium
     firefoxWrapper
     gimp
     kate
@@ -63,8 +62,6 @@ with import <stockholm/lib>;
 
   networking.networkmanager.enable = true;
 
-  nixpkgs.config.chromium.enablePepperFlash = true;
-
   programs.ssh.startAgent = false;
 
   services.xserver.enable = true;
diff --git a/tv/2configs/urlwatch.nix b/tv/2configs/urlwatch.nix
index 77947dafa..7467e8e67 100644
--- a/tv/2configs/urlwatch.nix
+++ b/tv/2configs/urlwatch.nix
@@ -27,11 +27,6 @@ in {
       # 2014-09-24 ref https://github.com/4z3/xintmap
       http://www.mathstat.dal.ca/~selinger/quipper/
 
-      ## other
-
-      https://nixos.org/channels/nixos-18.03/git-revision
-      https://nixos.org/channels/nixos-unstable/git-revision
-
       ## 2014-10-17
       ## TODO update ~/src/login/default.nix
       #http://hackage.haskell.org/package/bcrypt
diff --git a/tv/2configs/xp-332.nix b/tv/2configs/xp-332.nix
index 627401dc6..4a0b0ae16 100644
--- a/tv/2configs/xp-332.nix
+++ b/tv/2configs/xp-332.nix
@@ -11,7 +11,7 @@ with import <stockholm/lib>;
   hardware.sane = {
     enable = true;
     extraBackends = [
-      pkgs.utsushi
+      pkgs.utsushi-customized
     ];
   };
 
@@ -19,7 +19,7 @@ with import <stockholm/lib>;
     elem (parseDrvName pkg.name).name [ "imagescan-plugin-networkscan" ];
 
   nixpkgs.overlays = singleton (self: super: {
-    utsushi = super.utsushi.override {
+    utsushi-customized = self.utsushi.override {
       guiSupport = false;
       jpegSupport = false;
       networkSupport = true;
diff --git a/tv/2configs/xserver/Xresources.nix b/tv/2configs/xserver/Xresources.nix
index 1d4044480..d032efc7d 100644
--- a/tv/2configs/xserver/Xresources.nix
+++ b/tv/2configs/xserver/Xresources.nix
@@ -50,4 +50,9 @@ pkgs.writeText "Xresources" /* xdefaults */ ''
   root-urxvt*foreground: #e0c0c0
   root-urxvt*BorderColor: #400000
   root-urxvt*color0: #800000
+
+  fzmenu-urxvt*background: rgb:42/23/42
+  fzmenu-urxvt*externalBorder: 1
+  fzmenu-urxvt*geometry: 70x9
+  fzmenu-urxvt*internalBorder: 1
 ''
diff --git a/tv/2configs/xserver/default.nix b/tv/2configs/xserver/default.nix
index dbfa804d2..199ffcaf8 100644
--- a/tv/2configs/xserver/default.nix
+++ b/tv/2configs/xserver/default.nix
@@ -63,6 +63,11 @@ in {
     environment = {
       DISPLAY = ":${toString config.services.xserver.display}";
 
+      FZMENU_FZF_DEFAULT_OPTS = toString [
+        "--color=dark,border:126,bg+:090"
+        "--inline-info"
+      ];
+
       XMONAD_CACHE_DIR = cfg.cacheDir;
       XMONAD_CONFIG_DIR = cfg.configDir;
       XMONAD_DATA_DIR = cfg.dataDir;
@@ -95,8 +100,8 @@ in {
         "\${XMONAD_CONFIG_DIR}"
         "\${XMONAD_DATA_DIR}"
       ]}";
-      ExecStart = "${pkgs.xmonad-tv}/bin/xmonad";
-      ExecStop = "${pkgs.xmonad-tv}/bin/xmonad --shutdown";
+      ExecStart = "${pkgs.xmonad-tv}/bin/xmonad-${currentSystem}";
+      ExecStop = "${pkgs.xmonad-tv}/bin/xmonad-${currentSystem} --shutdown $MAINPID";
       User = cfg.user.name;
       WorkingDirectory = cfg.user.home;
     };
diff --git a/tv/3modules/default.nix b/tv/3modules/default.nix
index 493cc8b72..6172feb03 100644
--- a/tv/3modules/default.nix
+++ b/tv/3modules/default.nix
@@ -1,6 +1,7 @@
 {
   imports = [
     ./charybdis
+    ./dnsmasq.nix
     ./ejabberd
     ./hosts.nix
     ./iptables.nix
diff --git a/tv/3modules/dnsmasq.nix b/tv/3modules/dnsmasq.nix
new file mode 100644
index 000000000..ec927f98a
--- /dev/null
+++ b/tv/3modules/dnsmasq.nix
@@ -0,0 +1,57 @@
+with import <stockholm/lib>;
+{ config, ... }: let
+  cfg = config.tv.dnsmasq;
+in {
+
+  options.tv.dnsmasq = {
+    enable = mkEnableOption "tv.dnsmasq";
+    dhcp-range = mkOption {
+      type = types.str;
+    };
+    interface = mkOption {
+      type = types.str;
+    };
+    address = mkOption {
+      type = types.str;
+    };
+    prefixLength = mkOption {
+      type = types.addCheck types.int (x: x >= 0 && x <= 32);
+    };
+  };
+
+  config = mkIf cfg.enable (mkMerge [
+    {
+      networking.dhcpcd.denyInterfaces = [ cfg.interface ];
+      services.dnsmasq.resolveLocalQueries = false;
+      networking.interfaces.${cfg.interface} = {
+        ipv4.addresses = singleton {
+          address = cfg.address;
+          prefixLength = cfg.prefixLength;
+        };
+      };
+      services.dnsmasq.enable = true;
+      services.dnsmasq.extraConfig = ''
+        dhcp-range=${cfg.dhcp-range}
+        interface=${cfg.interface}
+      '';
+      tv.iptables.extra.filter.INPUT = [
+        "-i ${cfg.interface} -p tcp -m tcp --dport bootps -j ACCEPT"
+        "-i ${cfg.interface} -p udp -m udp --dport bootps -j ACCEPT"
+        "-i ${cfg.interface} -p tcp -m tcp --dport domain -j ACCEPT"
+        "-i ${cfg.interface} -p udp -m udp --dport domain -j ACCEPT"
+      ];
+    }
+    {
+      # enable forwarding
+      boot.kernel.sysctl."net.ipv4.ip_forward" = true;
+      tv.iptables.extra.filter.FORWARD = [
+        "-m state --state RELATED,ESTABLISHED -j ACCEPT"
+        "-i ${cfg.interface} -j ACCEPT"
+      ];
+      tv.iptables.extra.nat.POSTROUTING = [
+        "-j MASQUERADE"
+      ];
+    }
+  ]);
+
+}
diff --git a/tv/5pkgs/simple/disko.nix b/tv/5pkgs/simple/disko.nix
new file mode 100644
index 000000000..de8f1df22
--- /dev/null
+++ b/tv/5pkgs/simple/disko.nix
@@ -0,0 +1,13 @@
+{ fetchgit }:
+
+let
+  src = fetchgit {
+    url = https://cgit.krebsco.de/disko;
+    rev = "16cd458af06d3caf687eb7d80ca3df26b71fe28c";
+    sha256 = "16cd458af06d3caf687eb7d80ca3df26b71fe28c";
+  };
+in
+
+{
+  lib = import "${src}/lib";
+}
diff --git a/tv/5pkgs/simple/fzmenu/bin/otpmenu b/tv/5pkgs/simple/fzmenu/bin/otpmenu
new file mode 100755
index 000000000..ad8a0fda9
--- /dev/null
+++ b/tv/5pkgs/simple/fzmenu/bin/otpmenu
@@ -0,0 +1,41 @@
+#! /bin/sh
+set -efu
+
+#PATH=
+
+case ${FZMENU_PHASE-0} in
+  0)
+    export FZMENU_PHASE=1
+    exec setsid -f urxvt -name fzmenu-urxvt -e dash "$0"
+    ;;
+  1)
+    if result=$(
+      FZF_DEFAULT_OPTS=${FZMENU_FZF_DEFAULT_OPTS-}
+      if test -n "$FZF_DEFAULT_OPTS"; then
+        export FZF_DEFAULT_OPTS
+      fi
+      pass git ls-files '*/otp.gpg' | \
+      sed '
+
+        s/\/otp\.gpg$//
+      ' |
+      exec fzf \
+          --history=/dev/null \
+          --no-sort \
+          --prompt='OTP: ' \
+    )
+    then
+      export FZMENU_PHASE=2
+      export FZMENU_RESULT="$result"
+      setsid -f "$0"
+    fi
+    ;;
+  2)
+    pass=$(pass otp code "$FZMENU_RESULT/otp")
+    printf %s "$pass" |
+    xdotool type -f -
+    ;;
+  *)
+    echo "$0: error: bad phase: $FZMENU_PHASE" >&2
+    exit -1
+esac
diff --git a/tv/5pkgs/simple/fzmenu/bin/passmenu b/tv/5pkgs/simple/fzmenu/bin/passmenu
new file mode 100755
index 000000000..00b36c3af
--- /dev/null
+++ b/tv/5pkgs/simple/fzmenu/bin/passmenu
@@ -0,0 +1,41 @@
+#! /bin/sh
+set -efu
+
+#PATH=
+
+case ${FZMENU_PHASE-0} in
+  0)
+    export FZMENU_PHASE=1
+    exec setsid -f urxvt -name fzmenu-urxvt -e dash "$0"
+    ;;
+  1)
+    if result=$(
+      FZF_DEFAULT_OPTS=${FZMENU_FZF_DEFAULT_OPTS-}
+      if test -n "$FZF_DEFAULT_OPTS"; then
+        export FZF_DEFAULT_OPTS
+      fi
+      pass git ls-files '*/*.gpg' | \
+      sed '
+        /\/otp\.gpg$:/d
+        s/\.gpg$//
+      ' |
+      exec fzf \
+          --history=/dev/null \
+          --no-sort \
+          --prompt='pass: ' \
+    )
+    then
+      export FZMENU_PHASE=2
+      export FZMENU_RESULT="$result"
+      setsid -f "$0"
+    fi
+    ;;
+  2)
+    pass=$(pass show "$FZMENU_RESULT")
+    printf %s "$pass" |
+    xdotool type -f -
+    ;;
+  *)
+    echo "$0: error: bad phase: $FZMENU_PHASE" >&2
+    exit -1
+esac
diff --git a/tv/5pkgs/simple/fzmenu/default.nix b/tv/5pkgs/simple/fzmenu/default.nix
new file mode 100644
index 000000000..c49c903c6
--- /dev/null
+++ b/tv/5pkgs/simple/fzmenu/default.nix
@@ -0,0 +1,34 @@
+{ coreutils, dash, gnused, fzf, pass, runCommand, rxvt_unicode, stdenv, utillinux, xdotool }:
+
+runCommand "fzmenu" {
+} /* sh */ ''
+  mkdir $out
+
+  cp -r ${./bin} $out/bin
+
+  substituteInPlace $out/bin/otpmenu \
+      --replace '#! /bin/sh' '#! ${dash}/bin/dash' \
+      --replace '#PATH=' PATH=${stdenv.lib.makeBinPath [
+        coreutils
+        dash
+        fzf
+        gnused
+        pass
+        rxvt_unicode
+        utillinux
+        xdotool
+      ]}
+
+  substituteInPlace $out/bin/passmenu \
+      --replace '#! /bin/sh' '#! ${dash}/bin/dash' \
+      --replace '#PATH=' PATH=${stdenv.lib.makeBinPath [
+        coreutils
+        dash
+        fzf
+        gnused
+        pass
+        rxvt_unicode
+        utillinux
+        xdotool
+      ]}
+''
diff --git a/tv/5pkgs/simple/otpmenu.nix b/tv/5pkgs/simple/otpmenu.nix
deleted file mode 100644
index b35e1601f..000000000
--- a/tv/5pkgs/simple/otpmenu.nix
+++ /dev/null
@@ -1,15 +0,0 @@
-{ dmenu, gnused, pass, writeDashBin, xdotool }:
-
-writeDashBin "otpmenu" ''
-  set -efu
-
-  x=$(
-    ${pass}/bin/pass git ls-files '*/otp.gpg' \
-      | ${gnused}/bin/sed 's:/otp\.gpg$::' \
-      | ${dmenu}/bin/dmenu -f -p OTP
-  )
-
-  otp=$(${pass}/bin/pass otp code "$x/otp")
-
-  printf %s "$otp" | ${xdotool}/bin/xdotool type -f -
-''
diff --git a/tv/5pkgs/simple/xmonad-tv/default.nix b/tv/5pkgs/simple/xmonad-tv/default.nix
index 1168f10c8..ab4be91f3 100644
--- a/tv/5pkgs/simple/xmonad-tv/default.nix
+++ b/tv/5pkgs/simple/xmonad-tv/default.nix
@@ -1,6 +1,6 @@
 { pkgs, ... }:
 pkgs.writeHaskellPackage "xmonad-tv" {
-  executables.xmonad = {
+  executables."xmonad-${builtins.currentSystem}" = {
     extra-depends = [
       "containers"
       "extra"
@@ -19,36 +19,35 @@ pkgs.writeHaskellPackage "xmonad-tv" {
 
 module Main where
 
+import System.IO.Error (isDoesNotExistError, tryIOError)
+import System.Exit (exitFailure)
+import Control.Monad (forever)
+import Control.Concurrent (threadDelay)
+
 import Control.Exception
 import Control.Monad.Extra (whenJustM)
 import Graphics.X11.ExtraTypes.XF86
 import Text.Read (readEither)
 import XMonad
 import System.IO (hPutStrLn, stderr)
-import System.Environment (getArgs, withArgs, getEnv, getEnvironment, lookupEnv)
+import System.Environment (getArgs, getEnv, getEnvironment, lookupEnv)
 import System.Posix.Process (executeFile)
+import System.Posix.Signals (nullSignal, signalProcess)
+import System.Posix.Types (ProcessID)
 import XMonad.Actions.DynamicWorkspaces ( addWorkspacePrompt, renameWorkspace
                                         , removeEmptyWorkspace)
 import XMonad.Actions.GridSelect
 import XMonad.Actions.CycleWS (toggleWS)
---import XMonad.Actions.CopyWindow ( copy )
 import XMonad.Layout.NoBorders ( smartBorders )
 import qualified XMonad.StackSet as W
 import Data.Map (Map)
 import qualified Data.Map as Map
--- TODO import XMonad.Layout.WorkspaceDir
 import XMonad.Hooks.UrgencyHook (SpawnUrgencyHook(..), withUrgencyHook)
--- import XMonad.Layout.Tabbed
---import XMonad.Layout.MouseResizableTile
-import XMonad.Layout.Reflect (reflectVert)
+import XMonad.Hooks.ManageHelpers (doCenterFloat)
 import XMonad.Layout.FixedColumn (FixedColumn(..))
 import XMonad.Hooks.Place (placeHook, smart)
-import XMonad.Hooks.FloatNext (floatNextHook)
 import XMonad.Actions.PerWorkspaceKeys (chooseAction)
-import XMonad.Layout.PerWorkspace (onWorkspace)
---import XMonad.Layout.BinarySpacePartition
 
---import XMonad.Actions.Submap
 import XMonad.Stockholm.Pager
 import XMonad.Stockholm.Rhombus
 import XMonad.Stockholm.Shutdown
@@ -65,17 +64,28 @@ myFont = "-schumacher-*-*-*-*-*-*-*-*-*-*-*-iso10646-*"
 
 main :: IO ()
 main = getArgs >>= \case
-    ["--shutdown"] -> sendShutdownEvent
-    _ -> mainNoArgs
+    [] -> mainNoArgs
+    ["--shutdown", pidArg] -> mainShutdown (read pidArg)
+    args -> hPutStrLn stderr ("bad arguments: " <> show args) >> exitFailure
+
+mainShutdown :: ProcessID -> IO ()
+mainShutdown pid = do
+    sendShutdownEvent
+    hPutStrLn stderr ("waiting for: " <> show pid)
+    result <- tryIOError (waitProcess pid)
+    if isSuccess result
+      then hPutStrLn stderr ("result: " <> show result <> " [AKA success^_^]")
+      else hPutStrLn stderr ("result: " <> show result)
+  where
+    isSuccess = either isDoesNotExistError (const False)
+
+waitProcess :: ProcessID -> IO ()
+waitProcess pid = forever (signalProcess nullSignal pid >> threadDelay 10000)
 
 mainNoArgs :: IO ()
 mainNoArgs = do
     workspaces0 <- getWorkspaces0
     xmonad
-        -- $ withUrgencyHookC dzenUrgencyHook { args = ["-bg", "magenta", "-fg", "magenta", "-h", "2"], duration = 500000 }
-        --                   urgencyConfig { remindWhen = Every 1 }
-        -- $ withUrgencyHook borderUrgencyHook "magenta"
-        -- $ withUrgencyHookC BorderUrgencyHook { urgencyBorderColor = "magenta" } urgencyConfig { suppressWhen = Never }
         $ withUrgencyHook (SpawnUrgencyHook "echo emit Urgency ")
         $ def
             { terminal          = urxvtcPath
@@ -83,11 +93,14 @@ mainNoArgs = do
             , keys              = myKeys
             , workspaces        = workspaces0
             , layoutHook        = smartBorders $ FixedColumn 1 20 80 10 ||| Full
-            -- , handleEventHook   = myHandleEventHooks <+> handleTimerEvent
-            --, handleEventHook   = handleTimerEvent
-            , manageHook        = placeHook (smart (1,0)) <+> floatNextHook
+            , manageHook =
+                composeAll
+                  [ appName =? "fzmenu-urxvt" --> doCenterFloat
+                  , appName =? "pinentry" --> doCenterFloat
+                  , placeHook (smart (1,0))
+                  ]
             , startupHook =
-                whenJustM (liftIO (lookupEnv "XMONAD_STARTUP_HOOK"))
+                whenJustM (io (lookupEnv "XMONAD_STARTUP_HOOK"))
                           (\path -> forkFile path [] Nothing)
             , normalBorderColor  = "#1c1c1c"
             , focusedBorderColor = "#f000b0"
@@ -124,7 +137,7 @@ spawnRootTerm =
 
 spawnTermAt :: String -> X ()
 spawnTermAt ws = do
-    env <- liftIO getEnvironment
+    env <- io getEnvironment
     let env' = ("XMONAD_SPAWN_WORKSPACE", ws) : env
     forkFile urxvtcPath [] (Just env')
 
@@ -133,8 +146,8 @@ myKeys conf = Map.fromList $
     [ ((_4  , xK_Escape ), forkFile "/run/wrappers/bin/slock" [] Nothing)
     , ((_4S , xK_c      ), kill)
 
-    , ((_4  , xK_o      ), forkFile "${pkgs.otpmenu}/bin/otpmenu" [] Nothing)
-    , ((_4  , xK_p      ), forkFile "${pkgs.pass}/bin/passmenu" ["--type"] Nothing)
+    , ((_4  , xK_o      ), forkFile "${pkgs.fzmenu}/bin/otpmenu" [] Nothing)
+    , ((_4  , xK_p      ), forkFile "${pkgs.fzmenu}/bin/passmenu" [] Nothing)
 
     , ((_4  , xK_x      ), chooseAction spawnTermAt)
     , ((_4C , xK_x      ), spawnRootTerm)
@@ -255,34 +268,6 @@ wGSConfig = def
     , gs_navigate = navNSearch
     }
 
--- wsGSConfig = def
---     { gs_cellheight = 20
---     , gs_cellwidth = 64
---     , gs_cellpadding = 5
---     , gs_font = myFont
---     , gs_navigate = navNSearch
---     }
-
--- custom navNSearch
---makeGSNav :: (KeyMask, KeySym) -> TwoD a (Maybe a)
---makeGSNav esc = nav
---    where
---    nav = makeXEventhandler $ shadowWithKeymap keyMap navNSearchDefaultHandler
---    keyMap = Map.fromList
---        [ (esc              , cancel)
---        , ((0,xK_Escape)    , cancel)
---        , ((0,xK_Return)    , select)
---        , ((0,xK_Left)      , move (-1, 0) >> nav)
---        , ((0,xK_Right)     , move ( 1, 0) >> nav)
---        , ((0,xK_Down)      , move ( 0, 1) >> nav)
---        , ((0,xK_Up)        , move ( 0,-1) >> nav)
---        , ((0,xK_BackSpace) , transformSearchString (\s -> if (s == "") then "" else init s) >> nav)
---        ]
---    -- The navigation handler ignores unknown key symbols, therefore we const
---    navNSearchDefaultHandler (_,s,_) = do
---        transformSearchString (++ s)
---        nav
-
 
 (&) :: a -> (a -> c) -> c
 (&) = flip ($)
diff --git a/tv/default.nix b/tv/default.nix
index d077cc09f..10b09f2af 100644
--- a/tv/default.nix
+++ b/tv/default.nix
@@ -1,9 +1,15 @@
-{ pkgs, ... }:
 {
+
   imports = [
     ../krebs
     ./2configs
     ./3modules
   ];
-  nixpkgs.config.packageOverrides = import ./5pkgs pkgs;
+
+  nixpkgs = {
+    overlays = [
+      (import ./5pkgs)
+    ];
+  };
+
 }