about summary refs log tree commit diff
path: root/home
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--home/beets/default.nix46
-rw-r--r--home/bluetooth/default.nix10
-rw-r--r--home/default.nix43
-rw-r--r--home/direnv/default.nix28
-rw-r--r--home/documentation/default.nix9
-rw-r--r--home/drone-cli/default.nix11
-rw-r--r--home/element/default.nix10
-rw-r--r--home/emacs/default.nix20
-rw-r--r--home/eog/default.nix9
-rw-r--r--home/evince/default.nix9
-rw-r--r--home/feh/default.nix8
-rw-r--r--home/firefox/default.nix61
-rw-r--r--home/fish/default.nix29
-rw-r--r--home/flac/default.nix17
-rw-r--r--home/gcloud/default.nix10
-rw-r--r--home/git/commit.template22
-rw-r--r--home/git/default.nix55
-rw-r--r--home/go/default.nix17
-rw-r--r--home/gpg/default.nix33
-rw-r--r--home/gtk/default.nix47
-rw-r--r--home/mail/accounts/default.nix71
-rw-r--r--home/mail/default.nix11
-rw-r--r--home/mpv/default.nix20
-rw-r--r--home/packages/default.nix18
-rw-r--r--home/pass/default.nix40
-rw-r--r--home/pass/git-pass-mapping.ini9
-rw-r--r--home/pcmanfm/default.nix9
-rw-r--r--home/python/default.nix9
-rw-r--r--home/scanner/default.nix11
-rw-r--r--home/scripts/default.nix5
-rw-r--r--home/scripts/perf-flamegraph.nix22
-rw-r--r--home/seahorse/default.nix9
-rw-r--r--home/ssh/default.nix23
-rw-r--r--home/sublime-music/default.nix10
-rw-r--r--home/terminal/alacritty/default.nix27
-rw-r--r--home/terminal/default.nix17
-rw-r--r--home/tmux/default.nix25
-rw-r--r--home/transmission-remote/default.nix10
-rw-r--r--home/vlc/default.nix9
-rw-r--r--home/wm/default.nix19
-rw-r--r--home/wm/gammastep/default.nix16
-rw-r--r--home/wm/mako/default.nix28
-rw-r--r--home/wm/sway/default.nix113
-rw-r--r--home/wm/swaylock/config4
-rw-r--r--home/wm/swaylock/default.nix27
-rw-r--r--home/wm/waybar/default.nix52
-rw-r--r--home/wm/waybar/style.css77
-rw-r--r--home/wm/wofi/config4
-rw-r--r--home/wm/wofi/default.nix8
-rw-r--r--home/xdg/default.nix46
-rw-r--r--home/yt-dlp/config26
-rw-r--r--home/yt-dlp/default.nix12
-rw-r--r--home/zsh/completion-style.zsh34
-rw-r--r--home/zsh/default.nix56
-rw-r--r--home/zsh/options.zsh27
-rw-r--r--home/zsh/prompt.zsh11
-rw-r--r--home/zsh/tmux.zsh3
57 files changed, 1412 insertions, 0 deletions
diff --git a/home/beets/default.nix b/home/beets/default.nix
new file mode 100644
index 0000000..617ff62
--- /dev/null
+++ b/home/beets/default.nix
@@ -0,0 +1,46 @@
+{ config, lib, pkgs, ... }:
+let cfg = config.my.home.beets;
+in {
+  options.my.home.beets = with lib; {
+    enable = mkEnableOption "beets configuration";
+    musicDirectory = mkOption {
+      type = types.str;
+      example = "/home/fcuny/media/music";
+      description = "path to the music directory";
+    };
+  };
+
+  config.programs.beets = lib.mkIf cfg.enable {
+    enable = true;
+    settings = {
+      directory = cfg.musicDirectory;
+      plugins =
+        "fromfilename discogs duplicates fetchart embedart badfiles lastgenre scrub";
+      paths = {
+        default = "$albumartist/$album%aunique{}/$track $title";
+        singleton = "Singles/$artist/$title";
+        comp = "Compilations/$album%aunique{}/$track - $title";
+        "albumtype:soundtrack" = "Soundtracks/$album ($year)/$track $title";
+      };
+      import = {
+        copy = true;
+        move = true;
+      };
+      va_name = "Various Artists";
+      embedart = { ifempty = true; };
+
+      lastgenre = {
+        auto = false;
+        canonical = true;
+        fallback = "unknown";
+        force = true;
+        prefer_specific = true;
+      };
+
+      fetchart = {
+        cautious = true;
+        sources = "filesystem coverart itunes amazon lastfm wikipedia";
+      };
+    };
+  };
+}
diff --git a/home/bluetooth/default.nix b/home/bluetooth/default.nix
new file mode 100644
index 0000000..51ecc4a
--- /dev/null
+++ b/home/bluetooth/default.nix
@@ -0,0 +1,10 @@
+{ config, lib, ... }:
+let cfg = config.my.home.bluetooth;
+in {
+  options.my.home.bluetooth = with lib; {
+    enable = mkEnableOption "bluetooth configuration";
+  };
+
+  config =
+    lib.mkIf cfg.enable { services.blueman-applet = { enable = true; }; };
+}
diff --git a/home/default.nix b/home/default.nix
new file mode 100644
index 0000000..485cc34
--- /dev/null
+++ b/home/default.nix
@@ -0,0 +1,43 @@
+{ ... }:
+
+{
+  imports = [
+    ./beets
+    ./bluetooth
+    ./direnv
+    ./documentation
+    ./drone-cli
+    ./element
+    ./emacs
+    ./eog
+    ./evince
+    ./feh
+    ./firefox
+    ./fish
+    ./flac
+    ./gcloud
+    ./git
+    ./go
+    ./gpg
+    ./gtk
+    ./mail
+    ./mpv
+    ./packages
+    ./pass
+    ./pcmanfm
+    ./python
+    ./scanner
+    ./scripts
+    ./seahorse
+    ./ssh
+    ./sublime-music
+    ./terminal
+    ./tmux
+    ./transmission-remote
+    ./vlc
+    ./wm
+    ./xdg
+    ./yt-dlp
+    ./zsh
+  ];
+}
diff --git a/home/direnv/default.nix b/home/direnv/default.nix
new file mode 100644
index 0000000..89d0535
--- /dev/null
+++ b/home/direnv/default.nix
@@ -0,0 +1,28 @@
+{ config, lib, pkgs, ... }:
+let
+  cfg = config.my.home.direnv;
+  fishEnabled = config.my.home.fish.enable;
+in {
+  options.my.home.direnv = with lib; {
+    enable = mkEnableOption "direnv configuration";
+  };
+
+  config = lib.mkIf cfg.enable {
+    programs.direnv = {
+      enable = true;
+      nix-direnv = {
+        enable = true;
+        enableFlakes = true;
+      };
+    };
+
+    programs.fish.interactiveShellInit = lib.mkIf fishEnabled (
+      # Using mkAfter to make it more likely to appear after other
+      # manipulations of the prompt.
+      lib.mkAfter ''
+        ${pkgs.direnv}/bin/direnv hook fish | source
+      '');
+
+    home.sessionVariables = { DIRENV_DEFAULT_FLAKE = "nixpkgs"; };
+  };
+}
diff --git a/home/documentation/default.nix b/home/documentation/default.nix
new file mode 100644
index 0000000..047239e
--- /dev/null
+++ b/home/documentation/default.nix
@@ -0,0 +1,9 @@
+{ config, lib, ... }: {
+  # Add documentation for user packages
+  config.programs.man = {
+    enable = true;
+    generateCaches = true; # Enables the use of `apropos` etc...
+  };
+
+  config.programs.info.enable = true;
+}
diff --git a/home/drone-cli/default.nix b/home/drone-cli/default.nix
new file mode 100644
index 0000000..9eeb2e1
--- /dev/null
+++ b/home/drone-cli/default.nix
@@ -0,0 +1,11 @@
+{ config, lib, pkgs, ... }:
+let cfg = config.my.home.drone-cli;
+in {
+  options.my.home.drone-cli = with lib; {
+    enable = mkEnableOption "drone-cli configuration";
+  };
+  config = lib.mkIf cfg.enable {
+    home.packages = with pkgs; [ drone-cli ];
+    home.sessionVariables = { DRONE_SERVER = "https://drone.fcuny.xyz/"; };
+  };
+}
diff --git a/home/element/default.nix b/home/element/default.nix
new file mode 100644
index 0000000..3fcb50e
--- /dev/null
+++ b/home/element/default.nix
@@ -0,0 +1,10 @@
+{ lib, config, pkgs, ... }:
+let cfg = config.my.home.element;
+in {
+  options.my.home.element = with lib; {
+    enable = mkEnableOption "element configuration";
+  };
+
+  config =
+    lib.mkIf cfg.enable { home.packages = with pkgs; [ element-desktop ]; };
+}
diff --git a/home/emacs/default.nix b/home/emacs/default.nix
new file mode 100644
index 0000000..faac80d
--- /dev/null
+++ b/home/emacs/default.nix
@@ -0,0 +1,20 @@
+{ lib, config, pkgs, ... }:
+let cfg = config.my.home.emacs;
+in {
+  options.my.home.emacs = with lib; {
+    enable = mkEnableOption "emacs configuration";
+  };
+
+  config.home = lib.mkIf cfg.enable {
+    packages = with pkgs; [
+      emacsPgtkNativeComp
+      # see https://github.com/hlissner/doom-emacs/issues/4138
+      (aspellWithDicts (dicts: with dicts; [ en en-computers en-science ]))
+    ];
+
+    sessionVariables = {
+      EDITOR = "emacsclient -c -a=";
+      VISUAL = "emacsclient -c -a=";
+    };
+  };
+}
diff --git a/home/eog/default.nix b/home/eog/default.nix
new file mode 100644
index 0000000..c7f784b
--- /dev/null
+++ b/home/eog/default.nix
@@ -0,0 +1,9 @@
+{ lib, config, pkgs, ... }:
+let cfg = config.my.home.eog;
+in {
+  options.my.home.eog = with lib; {
+    enable = mkEnableOption "eog configuration";
+  };
+
+  config.home.packages = with pkgs; lib.mkIf cfg.enable ([ gnome3.eog ]);
+}
diff --git a/home/evince/default.nix b/home/evince/default.nix
new file mode 100644
index 0000000..16abc57
--- /dev/null
+++ b/home/evince/default.nix
@@ -0,0 +1,9 @@
+{ lib, config, pkgs, ... }:
+let cfg = config.my.home.evince;
+in {
+  options.my.home.evince = with lib; {
+    enable = mkEnableOption "evince configuration";
+  };
+
+  config.home.packages = with pkgs; lib.mkIf cfg.enable ([ gnome3.evince ]);
+}
diff --git a/home/feh/default.nix b/home/feh/default.nix
new file mode 100644
index 0000000..0032252
--- /dev/null
+++ b/home/feh/default.nix
@@ -0,0 +1,8 @@
+{ config, lib, ... }:
+let cfg = config.my.home.feh;
+in {
+  options.my.home.feh = with lib; {
+    enable = mkEnableOption "feh configuration";
+  };
+  config.programs.feh = lib.mkIf cfg.enable { enable = true; };
+}
diff --git a/home/firefox/default.nix b/home/firefox/default.nix
new file mode 100644
index 0000000..7b6485d
--- /dev/null
+++ b/home/firefox/default.nix
@@ -0,0 +1,61 @@
+{ config, lib, pkgs, ... }:
+let cfg = config.my.home.firefox;
+in {
+  options.my.home.firefox = with lib; {
+    enable = mkEnableOption "firefox configuration";
+  };
+
+  config.programs.firefox = lib.mkIf cfg.enable {
+    enable = true;
+    extensions = with pkgs.nur.repos.rycee.firefox-addons; [
+      https-everywhere
+      pkgs.nur.repos.rycee.firefox-addons."1password-x-password-manager"
+      consent-o-matic
+      refined-github
+      sponsorblock
+      ublock-origin
+    ];
+    profiles = {
+      default = {
+        settings = {
+          ## nix handle updates
+          "app.update.auto" = false;
+          "browser.bookmarks.showMobileBookmarks" = false;
+          "browser.compactmode.show" = true;
+          "browser.contentblocking.category" = "strict";
+          "browser.search.countryCode" = "US";
+          "browser.search.defaultenginename" = "DuckDuckGo";
+          "browser.search.isUS" = true;
+          "browser.search.region" = "US";
+          "browser.search.selectedEngine" = "DuckDuckGo";
+          ## don't check if it's the default browser
+          "browser.shell.checkDefaultBrowser" = false;
+          "browser.startup.homepage" = "https://duckduckgo.com";
+          "browser.urlbar.placeholderName" = "DuckDuckGo";
+          ## keep this with ff 96
+          "media.ffmpeg.vaapi.enabled" = true;
+          ## remove on ff 96
+          "media.ffvpx.enabled" = false;
+          ## remove on ff 96
+          "media.navigator.mediadatadecoder_vpx_enabled" = true;
+          "media.peerconnection.enabled" = true;
+          ## keep this with ff 96
+          "media.rdd-ffmpeg.enabled" = true;
+          ## remove on ff 96
+          "media.rdd-vpx.enabled" = false;
+          ## Block third-party cookies
+          "network.cookie.cookieBehavior" = 1;
+          "privacy.donottrackheader.enabled" = true;
+          "privacy.trackingprotection.enabled" = true;
+          "privacy.trackingprotection.socialtracking.enabled" = true;
+        };
+
+        userChrome = ''
+          #TabsToolbar {
+          visibility: collapse;
+          }
+        '';
+      };
+    };
+  };
+}
diff --git a/home/fish/default.nix b/home/fish/default.nix
new file mode 100644
index 0000000..85ff30d
--- /dev/null
+++ b/home/fish/default.nix
@@ -0,0 +1,29 @@
+{ config, lib, pkgs, ... }:
+let
+  cfg = config.my.home.fish;
+  swayEnabled = config.my.home.wm.windowManager == "sway";
+in {
+  options.my.home.fish = with lib; {
+    enable = mkEnableOption "fish configuration";
+  };
+  config.programs.fish = lib.mkIf cfg.enable {
+    enable = true;
+    interactiveShellInit = ''
+      set fish_greeting
+
+      # Tmux on terminal start, unless we're in a SSH connection
+      if status is-interactive
+        if test -z "$SSH_CONNECTION"
+          if not tmux has-session 2>/dev/null; or test -z "$TMUX"
+            exec tmux new-session -A -s 0
+          end
+        end
+      end
+    '';
+    loginShellInit = lib.mkIf swayEnabled ''
+      if test -z "$DISPLAY"; and test (tty) = "/dev/tty1"
+        exec sway
+      end
+    '';
+  };
+}
diff --git a/home/flac/default.nix b/home/flac/default.nix
new file mode 100644
index 0000000..137d353
--- /dev/null
+++ b/home/flac/default.nix
@@ -0,0 +1,17 @@
+{ config, lib, pkgs, ... }:
+let cfg = config.my.home.flac;
+in {
+  options.my.home.flac = with lib; {
+    enable = mkEnableOption "flac configuration";
+  };
+
+  config.home.packages = with pkgs;
+    lib.mkIf cfg.enable ([
+      flac
+      abcde
+      (pkgs.writers.writeDashBin "rip-flac" ''
+        cd ~/import
+        ${pkgs.abcde}/bin/abcde -Vx -G -a "cddb,read,encode,tag,move,clean" -o flac
+      '')
+    ]);
+}
diff --git a/home/gcloud/default.nix b/home/gcloud/default.nix
new file mode 100644
index 0000000..0f6262b
--- /dev/null
+++ b/home/gcloud/default.nix
@@ -0,0 +1,10 @@
+{ config, lib, pkgs, ... }:
+let cfg = config.my.home.gcloud;
+in {
+  options.my.home.gcloud = with lib; {
+    enable = mkEnableOption "google cloud sdk";
+  };
+
+  config =
+    lib.mkIf cfg.enable { home.packages = with pkgs; [ google-cloud-sdk ]; };
+}
diff --git a/home/git/commit.template b/home/git/commit.template
new file mode 100644
index 0000000..01ab956
--- /dev/null
+++ b/home/git/commit.template
@@ -0,0 +1,22 @@
+# (If applied, this commit will...) <type>: <subject>
+
+# Explain why this change is being made
+
+# --- COMMIT END ---
+# Remember to
+#    Use the imperative mood, present tense: `change' not `changed' nor `changes'
+#    Do not end the subject line with a period
+#    Use the body to explain what and why vs. how
+#    Can use multiple lines with "-" for bullet points in body
+
+# Suggested types:
+# build: Changes that affect the build system or external dependencies
+# ci:    Changes to CI configuration files and scripts
+# docs:  Documentation only changes
+# feat:  A new feature
+# fix:   A bug fix
+# perf:  A code change that improves performance
+# ref:   A code change that neither fixes a bug nor adds a feature (refactor)
+# style: Changes that do not affect the meaning of the code
+# tests: Adding missing tests or correcting existing tests
+# meta:  Some meta information in the repo changes
diff --git a/home/git/default.nix b/home/git/default.nix
new file mode 100644
index 0000000..3dc2dd0
--- /dev/null
+++ b/home/git/default.nix
@@ -0,0 +1,55 @@
+{ lib, config, ... }:
+
+let cfg = config.my.home.git;
+in {
+  options.my.home.git = with lib; {
+    enable = mkEnableOption "git configuration";
+  };
+
+  config = lib.mkIf cfg.enable {
+    programs.git = {
+      enable = true;
+      aliases = {
+        s = "status --short --branch";
+        amend = "commit --amend --no-edit";
+      };
+      extraConfig = {
+        core.whitespace = "trailing-space,space-before-tab";
+        color.ui = "true";
+        push.default = "simple";
+        init.defaultBranch = "main";
+        branch.autosetuprebase = "remote";
+        branch.sort = "authordate";
+        commit.template = "${config.xdg.dataHome}/git/commit.template";
+      };
+      userName = "Franck Cuny";
+      userEmail = "franck@fcuny.net";
+      extraConfig = {
+        "credential \"https://github.com\"" = { username = "fcuny"; };
+        "credential \"https://git.fcuny.net\"" = { username = "fcuny"; };
+      };
+      ignores = [
+        "*.elc"
+        "*.iml"
+        "*.o"
+        "*.pyc"
+        "*.pyo"
+        "*pyc"
+        "*~"
+        ".DS_Store"
+        ".\\#"
+        ".dir-locals.el"
+        ".direnv/*"
+        ".idea"
+        ".projectile"
+        ".pytest_cache/"
+        "/env/*"
+        "Icon"
+        "TAGS"
+        "\\#*\\#"
+        "tags"
+      ];
+    };
+    xdg.dataFile."git/commit.template" = { source = ./commit.template; };
+  };
+}
diff --git a/home/go/default.nix b/home/go/default.nix
new file mode 100644
index 0000000..24748d0
--- /dev/null
+++ b/home/go/default.nix
@@ -0,0 +1,17 @@
+{ lib, config, ... }:
+let cfg = config.my.home.go;
+in {
+  options.my.home.go = with lib; {
+    enable = mkEnableOption "go configuration";
+  };
+
+  config = lib.mkIf cfg.enable {
+    programs.go = {
+      enable = true;
+      goPath = ".local/share/pkg.go";
+      goBin = ".local/bin.go";
+      goPrivate = [ "git.fcuny.net" "golang.fcuny.net" ];
+    };
+    home.sessionPath = [ config.home.sessionVariables.GOBIN ];
+  };
+}
diff --git a/home/gpg/default.nix b/home/gpg/default.nix
new file mode 100644
index 0000000..d96c3aa
--- /dev/null
+++ b/home/gpg/default.nix
@@ -0,0 +1,33 @@
+{ config, lib, ... }:
+let cfg = config.my.home.gpg;
+in {
+  options.my.home.gpg = with lib; {
+    enable = mkEnableOption "gpg configuration";
+    pinentry = mkOption {
+      type = types.str;
+      default = "tty";
+      example = "gnome3";
+      description = "Which pinentry interface to use";
+    };
+    defaultKey = mkOption {
+      type = types.str;
+      default = null;
+      description = "Default GPG key";
+    };
+  };
+
+  config = lib.mkIf cfg.enable {
+    programs.gpg = {
+      enable = true;
+      settings = { default-key = cfg.defaultKey; };
+    };
+    services.gpg-agent = {
+      enable = true;
+      enableSshSupport = true; # One agent to rule them all
+      pinentryFlavor = cfg.pinentry;
+      extraConfig = ''
+        allow-loopback-pinentry
+      '';
+    };
+  };
+}
diff --git a/home/gtk/default.nix b/home/gtk/default.nix
new file mode 100644
index 0000000..6e528b2
--- /dev/null
+++ b/home/gtk/default.nix
@@ -0,0 +1,47 @@
+{ config, lib, pkgs, ... }:
+let cfg = config.my.home.gtk;
+in {
+  options.my.home.gtk = with lib; {
+    enable = mkEnableOption "GTK configuration";
+  };
+
+  config = lib.mkIf cfg.enable {
+    gtk = {
+      enable = true;
+      font = {
+        package = pkgs.source-sans-pro;
+        name = "Source Sans Pro";
+      };
+      iconTheme = {
+        package = pkgs.gnome3.adwaita-icon-theme;
+        name = "Adwaita";
+      };
+      theme = {
+        package = pkgs.gnome.gnome-themes-extra;
+        name = "Adwaita";
+      };
+      gtk2 = {
+        extraConfig = ''
+          gtk-xft-antialias = 1
+          gtk-xft-hinting = 1
+          gtk-xft-hintstyle = "hintslight"
+          gtk-cursor-theme-size = cursorSize
+        '';
+      };
+
+      gtk3 = {
+        extraConfig = {
+          gtk-xft-antialias = 1;
+          gtk-xft-hinting = 1;
+          gtk-xft-hintstyle = "hintslight";
+        };
+      };
+    };
+
+    # environment = {
+    #   pathsToLink = [ "/libexec" ];
+    #   homeBinInPath = true;
+    #   localBinInPath = true;
+    # };
+  };
+}
diff --git a/home/mail/accounts/default.nix b/home/mail/accounts/default.nix
new file mode 100644
index 0000000..1bc1c37
--- /dev/null
+++ b/home/mail/accounts/default.nix
@@ -0,0 +1,71 @@
+{ config, lib, pkgs, ... }:
+let cfg = config.my.home.mail;
+in {
+  config = lib.mkIf cfg.enable {
+    accounts.email = {
+      accounts = {
+        Fastmail = rec {
+          primary = true;
+          address = "franck@fcuny.net";
+          userName = address;
+          realName = "Franck Cuny";
+          aliases = [ "franck.cuny@gmail.com" ];
+          passwordCommand = "pass email/imap.fastmail.com";
+          imap.host = "imap.fastmail.com";
+          mbsync = {
+            enable = true;
+            create = "maildir";
+            expunge = "both";
+            extraConfig.channel.CopyArrivalDate = "yes";
+          };
+          notmuch.enable = true;
+        };
+      };
+    };
+
+    programs.mbsync.enable = true;
+
+    programs.afew = {
+      enable = true;
+      extraConfig = ''
+        [SpamFilter]
+        [KillThreadsFilter]
+        [ArchiveSentMailsFilter]
+        [InboxFilter]
+      '';
+    };
+
+    programs.notmuch = {
+      enable = true;
+      maildir.synchronizeFlags = true;
+      new.tags = [ "unread" "new" ];
+      new.ignore = [ "Trash" ];
+      search.excludeTags = [ "spam" "deleted" ];
+      hooks = {
+        postNew = "${config.home.profileDirectory}/bin/afew -v --tag --new";
+      };
+    };
+
+    systemd.user.services.mbsync = {
+      Unit = { Description = "mbsync synchronization"; };
+      Service = {
+        Type = "oneshot";
+        Environment = [
+          "PASSWORD_STORE_DIR=${config.programs.password-store.settings.PASSWORD_STORE_DIR}"
+          "NOTMUCH_CONFIG=${config.xdg.configHome}/notmuch/notmuchrc"
+        ];
+        ExecStart = "${pkgs.isync}/bin/mbsync -a";
+        ExecStartPost = "${pkgs.notmuch}/bin/notmuch new --quiet";
+      };
+    };
+
+    systemd.user.timers.mbsync = {
+      Unit = { Description = "mbsync synchronization"; };
+      Timer = {
+        OnBootSec = "30";
+        OnUnitActiveSec = "5m";
+      };
+      Install = { WantedBy = [ "timers.target" ]; };
+    };
+  };
+}
diff --git a/home/mail/default.nix b/home/mail/default.nix
new file mode 100644
index 0000000..4f36e87
--- /dev/null
+++ b/home/mail/default.nix
@@ -0,0 +1,11 @@
+{ config, lib, ... }:
+let
+  cfg = config.my.home.mail;
+  mkRelatedOption = desc: lib.mkEnableOption desc // { default = cfg.enable; };
+in {
+  imports = [ ./accounts ];
+  options.my.home.mail = with lib; {
+    enable = mkEnableOption "email configuration";
+  };
+  config = { accounts.email = { maildirBasePath = ".mail"; }; };
+}
diff --git a/home/mpv/default.nix b/home/mpv/default.nix
new file mode 100644
index 0000000..b6c2c60
--- /dev/null
+++ b/home/mpv/default.nix
@@ -0,0 +1,20 @@
+{ lib, config, pkgs, ... }:
+let cfg = config.my.home.mpv;
+in {
+  options.my.home.mpv = with lib; {
+    enable = mkEnableOption "mpv configuration";
+  };
+
+  config = lib.mkIf cfg.enable {
+    programs.mpv = {
+      enable = true;
+      config = {
+        sub-auto = "fuzzy";
+        vo = "gpu";
+        hwdec = "auto-safe";
+        gpu-context = "wayland";
+      };
+      scripts = lib.attrVals [ "sponsorblock" ] pkgs.mpvScripts;
+    };
+  };
+}
diff --git a/home/packages/default.nix b/home/packages/default.nix
new file mode 100644
index 0000000..806ce31
--- /dev/null
+++ b/home/packages/default.nix
@@ -0,0 +1,18 @@
+{ config, lib, pkgs, ... }:
+let cfg = config.my.home.packages;
+in {
+  options.my.home.packages = with lib; {
+    enable = mkEnableOption "user packages";
+    additionalPackages = mkOption {
+      type = with types; listOf package;
+      default = [ ];
+      example = literalExample ''
+        with pkgs; [
+          pavucontrol
+        ]
+      '';
+    };
+  };
+  config.home.packages = with pkgs;
+    lib.mkIf cfg.enable ([ util-linux jq ripgrep ] ++ cfg.additionalPackages);
+}
diff --git a/home/pass/default.nix b/home/pass/default.nix
new file mode 100644
index 0000000..3ea7892
--- /dev/null
+++ b/home/pass/default.nix
@@ -0,0 +1,40 @@
+{ config, lib, pkgs, ... }:
+let cfg = config.my.home.pass;
+in {
+  options.my.home.pass = with lib; {
+    enable = mkEnableOption "pass configuration";
+  };
+  config = lib.mkIf cfg.enable {
+    programs.password-store = {
+      enable = true;
+      settings = {
+        PASSWORD_STORE_DIR = "${config.xdg.dataHome}/password-store";
+        PASSWORD_STORE_GENERATED_LENGTH = "30";
+        PASSWORD_STORE_CHARACTER_SET = "a-zA-Z0-9~!@#$%^&*()-_=+[]{};:,.<>?";
+        PASSWORD_STORE_KEY = config.programs.gpg.settings.default-key;
+      };
+    };
+
+    programs.git = {
+      signing = {
+        key = config.programs.gpg.settings.default-key;
+        signByDefault = true;
+      };
+      extraConfig = {
+        credential = {
+          helper = "${pkgs.gitAndTools.pass-git-helper}/bin/pass-git-helper";
+          useHttpPath = true;
+        };
+      };
+    };
+
+    xdg.configFile."pass-git-helper/git-pass-mapping.ini" = {
+      source = ./git-pass-mapping.ini;
+    };
+
+    services.password-store-sync.enable = true;
+
+    # Ensure the password store things are in the systemd session
+    systemd.user.sessionVariables = config.programs.password-store.settings;
+  };
+}
diff --git a/home/pass/git-pass-mapping.ini b/home/pass/git-pass-mapping.ini
new file mode 100644
index 0000000..5c5177b
--- /dev/null
+++ b/home/pass/git-pass-mapping.ini
@@ -0,0 +1,9 @@
+[DEFAULT]
+line_username=1
+skip_username=10
+
+[github.com/*]
+target=git/github.com
+
+[git.fcuny.net*]
+target=git/git.fcuny.net
diff --git a/home/pcmanfm/default.nix b/home/pcmanfm/default.nix
new file mode 100644
index 0000000..cca8f9a
--- /dev/null
+++ b/home/pcmanfm/default.nix
@@ -0,0 +1,9 @@
+{ lib, config, pkgs, ... }:
+let cfg = config.my.home.pcmanfm;
+in {
+  options.my.home.pcmanfm = with lib; {
+    enable = mkEnableOption "pcmanfm configuration";
+  };
+
+  config = lib.mkIf cfg.enable { home.packages = with pkgs; [ pcmanfm ]; };
+}
diff --git a/home/python/default.nix b/home/python/default.nix
new file mode 100644
index 0000000..b34f978
--- /dev/null
+++ b/home/python/default.nix
@@ -0,0 +1,9 @@
+{ config, pkgs, lib, ... }:
+let cfg = config.my.home.python;
+in {
+  options.my.home.python = with lib; {
+    enable = mkEnableOption "python configuration";
+  };
+
+  config.home.packages = with pkgs; lib.mkIf cfg.enable ([ python310 ]);
+}
diff --git a/home/scanner/default.nix b/home/scanner/default.nix
new file mode 100644
index 0000000..aa3da7c
--- /dev/null
+++ b/home/scanner/default.nix
@@ -0,0 +1,11 @@
+{ config, lib, pkgs, ... }:
+let cfg = config.my.home.scanner;
+in {
+  options.my.home.scanner = with lib; {
+    enable = mkEnableOption "scanner configuration";
+  };
+  config = lib.mkIf cfg.enable {
+    home.packages = with pkgs; [ tesseract imagemagick exiftool sane-airscan ];
+  };
+}
+
diff --git a/home/scripts/default.nix b/home/scripts/default.nix
new file mode 100644
index 0000000..bc19e44
--- /dev/null
+++ b/home/scripts/default.nix
@@ -0,0 +1,5 @@
+{ ... }:
+
+{
+  imports = [ ./perf-flamegraph.nix ];
+}
diff --git a/home/scripts/perf-flamegraph.nix b/home/scripts/perf-flamegraph.nix
new file mode 100644
index 0000000..f379591
--- /dev/null
+++ b/home/scripts/perf-flamegraph.nix
@@ -0,0 +1,22 @@
+{ pkgs, config, ... }:
+let
+  perf-flamegraph-process =
+    pkgs.writeShellScriptBin "perf-flamegraph-process" ''
+      set -euo pipefail
+
+      OUT_DIR="''${HOME}/workspace/tmp/flamegraph"
+      OUT_SVG="''${OUT_DIR}/$(date +%y%m%d-%H%M%S).svg"
+
+      mkdir -p ''${OUT_DIR}
+
+      ${pkgs.linuxPackages.perf}/bin/perf record -g --call-graph dwarf -F max "$@"
+      ${pkgs.linuxPackages.perf}/bin/perf script \
+        | ${pkgs.flamegraph}/bin/stackcollapse-perf.pl \
+        | ${pkgs.flamegraph}/bin/flamegraph.pl > "''${OUT_SVG}"
+    '';
+in {
+  config = {
+    home.packages = with pkgs; [ flamegraph perf-flamegraph-process ];
+  };
+}
+
diff --git a/home/seahorse/default.nix b/home/seahorse/default.nix
new file mode 100644
index 0000000..54688a1
--- /dev/null
+++ b/home/seahorse/default.nix
@@ -0,0 +1,9 @@
+{ lib, config, pkgs, ... }:
+let cfg = config.my.home.seahorse;
+in {
+  options.my.home.seahorse = with lib; {
+    enable = mkEnableOption "seahorse configuration";
+  };
+
+  config.home.packages = with pkgs; lib.mkIf cfg.enable ([ gnome.seahorse ]);
+}
diff --git a/home/ssh/default.nix b/home/ssh/default.nix
new file mode 100644
index 0000000..1088e80
--- /dev/null
+++ b/home/ssh/default.nix
@@ -0,0 +1,23 @@
+{ config, lib, ... }:
+let cfg = config.my.home.ssh;
+in {
+  options.my.home.ssh = with lib; {
+    enable = mkEnableOption "ssh configuration";
+  };
+
+  config.programs.ssh = lib.mkIf cfg.enable {
+    enable = true;
+    forwardAgent = true;
+    serverAliveInterval = 60;
+    controlMaster = "auto";
+    controlPersist = "30m";
+    matchBlocks = {
+      "github.com" = {
+        hostname = "github.com";
+        user = "git";
+        forwardAgent = false;
+        extraOptions = { preferredAuthentications = "publickey"; };
+      };
+    };
+  };
+}
diff --git a/home/sublime-music/default.nix b/home/sublime-music/default.nix
new file mode 100644
index 0000000..fad10ac
--- /dev/null
+++ b/home/sublime-music/default.nix
@@ -0,0 +1,10 @@
+{ lib, config, pkgs, ... }:
+let cfg = config.my.home.sublime-music;
+in {
+  options.my.home.sublime-music = with lib; {
+    enable = mkEnableOption "sublime-music configuration";
+  };
+
+  config =
+    lib.mkIf cfg.enable { home.packages = with pkgs; [ sublime-music ]; };
+}
diff --git a/home/terminal/alacritty/default.nix b/home/terminal/alacritty/default.nix
new file mode 100644
index 0000000..2bcd041
--- /dev/null
+++ b/home/terminal/alacritty/default.nix
@@ -0,0 +1,27 @@
+{ config, lib, pkgs, ... }:
+let cfg = config.my.home.terminal;
+in {
+  config = lib.mkIf (cfg.program == "alacritty") {
+    programs.alacritty = {
+      enable = true;
+
+      settings = {
+        env = { TERM = "xterm-256color"; };
+        live_config_reload = true;
+        draw_bold_text_with_bright_colors = true;
+        selection = { save_to_clipboard = true; };
+        font = { size = 12; };
+        colors = {
+          primary = {
+            foreground = "#000000";
+            background = "#FFFFFF";
+          };
+        };
+        cursor = {
+          style.blinking = "Never";
+          unfocused_hollow = true;
+        };
+      };
+    };
+  };
+}
diff --git a/home/terminal/default.nix b/home/terminal/default.nix
new file mode 100644
index 0000000..e1ff0d7
--- /dev/null
+++ b/home/terminal/default.nix
@@ -0,0 +1,17 @@
+{ config, lib, ... }:
+let cfg = config.my.home.terminal;
+in {
+  imports = [ ./alacritty ];
+  options.my.home = with lib; {
+    terminal = {
+      program = mkOption {
+        type = with types; nullOr (enum [ "alacritty" ]);
+        default = null;
+        example = "alacritty";
+        description = "Which terminal to use for home session";
+      };
+    };
+  };
+  config.home.sessionVariables =
+    lib.mkIf (cfg.program != null) { TERMINAL = cfg.program; };
+}
diff --git a/home/tmux/default.nix b/home/tmux/default.nix
new file mode 100644
index 0000000..499a64b
--- /dev/null
+++ b/home/tmux/default.nix
@@ -0,0 +1,25 @@
+{ config, lib, pkgs, ... }:
+let cfg = config.my.home.tmux;
+in {
+  options.my.home.tmux = with lib; {
+    enable = mkEnableOption "tmux terminal multiplexer";
+  };
+
+  config.programs.tmux = lib.mkIf cfg.enable {
+    enable = true;
+
+    terminal = "xterm-256color";
+    escapeTime = 0;
+    aggressiveResize = true;
+    baseIndex = 1;
+    shortcut = "z";
+    clock24 = true;
+    historyLimit = 50000; # Bigger buffer
+
+    extraConfig = ''
+      setw -g mouse on
+
+      set-option -g renumber-windows on
+    '';
+  };
+}
diff --git a/home/transmission-remote/default.nix b/home/transmission-remote/default.nix
new file mode 100644
index 0000000..29c070b
--- /dev/null
+++ b/home/transmission-remote/default.nix
@@ -0,0 +1,10 @@
+{ lib, config, pkgs, ... }:
+let cfg = config.my.home.transmission-remote;
+in {
+  options.my.home.transmission-remote = with lib; {
+    enable = mkEnableOption "transmission-remote configuration";
+  };
+
+  config.home.packages = with pkgs;
+    lib.mkIf cfg.enable ([ transmission-remote-gtk ]);
+}
diff --git a/home/vlc/default.nix b/home/vlc/default.nix
new file mode 100644
index 0000000..f7ad141
--- /dev/null
+++ b/home/vlc/default.nix
@@ -0,0 +1,9 @@
+{ lib, config, pkgs, ... }:
+let cfg = config.my.home.vlc;
+in {
+  options.my.home.vlc = with lib; {
+    enable = mkEnableOption "vlc configuration";
+  };
+
+  config = lib.mkIf cfg.enable { home.packages = with pkgs; [ vlc ]; };
+}
diff --git a/home/wm/default.nix b/home/wm/default.nix
new file mode 100644
index 0000000..27a8bf4
--- /dev/null
+++ b/home/wm/default.nix
@@ -0,0 +1,19 @@
+{ config, lib, pkgs, ... }:
+let
+  mkRelatedOption = description: relatedWMs:
+    let isActivatedWm = wm: config.my.home.wm.windowManager == wm;
+    in (lib.mkEnableOption description) // {
+      default = builtins.any isActivatedWm relatedWMs;
+    };
+in {
+  imports = [ ./sway ./waybar ./mako ./swaylock ./wofi ./gammastep ];
+  options.my.home.wm = with lib; {
+    windowManager = mkOption {
+      type = with types; nullOr (enum [ "sway" ]);
+      default = null;
+      example = "sway";
+      description = "Which window manager to use for home session";
+    };
+    waybar = { enable = mkRelatedOption "waybar configuration" [ "sway" ]; };
+  };
+}
diff --git a/home/wm/gammastep/default.nix b/home/wm/gammastep/default.nix
new file mode 100644
index 0000000..0a9c684
--- /dev/null
+++ b/home/wm/gammastep/default.nix
@@ -0,0 +1,16 @@
+{ config, lib, pkgs, ... }:
+let isEnabled = config.my.home.wm.windowManager == "sway";
+in {
+  config = lib.mkIf isEnabled {
+    services.gammastep = {
+      enable = true;
+      #TODO: this needs to come from locale.nix
+      latitude = 37.8715;
+      longitude = -122.273;
+      temperature = {
+        day = 5000;
+        night = 3700;
+      };
+    };
+  };
+}
diff --git a/home/wm/mako/default.nix b/home/wm/mako/default.nix
new file mode 100644
index 0000000..3a13620
--- /dev/null
+++ b/home/wm/mako/default.nix
@@ -0,0 +1,28 @@
+{ config, lib, pkgs, ... }:
+let isEnabled = config.my.home.wm.windowManager == "sway";
+in {
+  config = lib.mkIf isEnabled {
+    home.packages = [
+      pkgs.libnotify # to send notifications
+    ];
+
+    systemd.user.services.mako = {
+      Service = { ExecStart = "${pkgs.mako}/bin/mako"; };
+      Install = { WantedBy = [ "sway-session.target" ]; };
+    };
+
+    # All the options are documented via `man 5 mako`
+    programs.mako = {
+      enable = true;
+      layer = "overlay";
+      # The timeout value is in millisecond
+      defaultTimeout = 30000;
+      # The maximum number of notifications
+      maxVisible = 3;
+      maxIconSize = 24;
+      # Enable pango markup (see https://docs.gtk.org/Pango/pango_markup.html)
+      markup = true;
+      actions = true;
+    };
+  };
+}
diff --git a/home/wm/sway/default.nix b/home/wm/sway/default.nix
new file mode 100644
index 0000000..ba70992
--- /dev/null
+++ b/home/wm/sway/default.nix
@@ -0,0 +1,113 @@
+{ config, lib, pkgs, ... }:
+let
+  isEnabled = config.my.home.wm.windowManager == "sway";
+  terminal = config.my.home.terminal.program;
+  modifier = "Mod4"; # `Super` key
+in {
+  config = lib.mkIf isEnabled {
+    home.packages = with pkgs; [
+      wlogout
+      brightnessctl
+      pulseaudio
+      grim
+      slurp
+      polkit_gnome
+      xsettingsd
+      swaylock
+      swayidle
+      wl-clipboard
+    ];
+
+    home.sessionVariables = {
+      MOZ_ENABLE_WAYLAND = true;
+      XDG_CURRENT_DESKTOP = "sway";
+      XDG_SESSION_TYPE = "wayland";
+    };
+
+    wayland.windowManager.sway = {
+      enable = true;
+      config = {
+        # FIXME: this should be a variable
+        terminal = "alacritty";
+        modifier = modifier;
+        menu = ''${pkgs.wofi}/bin/wofi -S drun -p "app:" -L 10'';
+        bars = [ ];
+        fonts = {
+          names = [ "Source Code Pro" ];
+          size = 10.0;
+        };
+        keybindings = lib.mkOptionDefault {
+          # control the volume
+          "XF86AudioRaiseVolume" =
+            "exec ${pkgs.pulseaudio}/bin/pactl set-sink-volume @DEFAULT_SINK@ +5%";
+          "XF86AudioLowerVolume" =
+            "exec ${pkgs.pulseaudio}/bin/pactl set-sink-volume @DEFAULT_SINK@ -5%";
+          "XF86AudioMute" =
+            "exec ${pkgs.pulseaudio}/bin/pactl set-sink-mute @DEFAULT_SINK@ toggle";
+          "XF86AudioMicMute" =
+            "exec ${pkgs.pulseaudio}/bin/pactl set-source-mute @DEFAULT_SOURCE@ toggle";
+
+          # control brightness
+          "XF86MonBrightnessDown" =
+            "exec ${pkgs.brightnessctl}/bin/brightnessctl set 5%-";
+          "XF86MonBrightnessUp" =
+            "exec ${pkgs.brightnessctl}/bin/brightnessctl set +5%";
+
+          # logout
+          "${modifier}+Escape" = "exec ${pkgs.wlogout}/bin/wlogout";
+
+          # screenshot
+          "${modifier}+s" =
+            "exec ${pkgs.grim}/bin/grim $(xdg-user-dir DOCUMENTS)/screenshots/$(date +'%Y-%m-%d-%H%M%S_screenshot.png')";
+          "${modifier}+Shift+s" =
+            "exec ${pkgs.slurp}/bin/slurp | ${pkgs.grim}/bin/grim -g - $(xdg-user-dir DOCUMENTS)/screenshots/$(date +'%Y-%m-%d-%H%M%S_screenshot.png')";
+
+          # File Manager
+          "${modifier}+p" = "exec ${pkgs.pcmanfm}/bin/pcmanfm";
+        };
+
+        # use `swaymsg -t get_tree' to get the title/name/ID of the applications
+        window = {
+          commands = [
+            {
+              criteria.class = ".blueman-manager-wrapped";
+              command = "floating enable";
+            }
+            {
+              criteria.class = "Pavucontrol";
+              command = "floating enable";
+            }
+          ];
+        };
+
+        input = {
+          "*" = {
+            "xkb_layout" = "us,fr";
+            # map capslock to ctrl, and switch layout using shift+caps
+            "xkb_options" = "ctrl:nocaps,grp:shift_caps_toggle";
+          };
+        };
+
+        assigns = {
+          "1" = [{ app_id = "emacs"; }];
+          "2" = [{ app_id = "Alacritty"; }];
+          "3" = [{ app_id = "firefox"; }];
+          "4" = [{ class = "Element"; }];
+        };
+
+        output = {
+          "*" = {
+            scale = "1.5";
+            bg = "#2E3440 solid_color";
+          };
+          # This is for aptos
+          "eDP-1" = { scale = "1.3"; };
+        };
+        startup = [{
+          command = ''
+            exec "systemctl --user import-environment; systemctl --user start sway-session.target"'';
+        }];
+      };
+    };
+  };
+}
diff --git a/home/wm/swaylock/config b/home/wm/swaylock/config
new file mode 100644
index 0000000..032695b
--- /dev/null
+++ b/home/wm/swaylock/config
@@ -0,0 +1,4 @@
+color=FFFFEA
+daemonize
+indicator-caps-lock
+hide-keyboard-layout
diff --git a/home/wm/swaylock/default.nix b/home/wm/swaylock/default.nix
new file mode 100644
index 0000000..3df802a
--- /dev/null
+++ b/home/wm/swaylock/default.nix
@@ -0,0 +1,27 @@
+{ config, lib, pkgs, ... }:
+let isEnabled = config.my.home.wm.windowManager == "sway";
+in {
+  config = lib.mkIf isEnabled {
+    xdg.configFile."swaylock/config" = { source = ./config; };
+
+    # https://github.com/nix-community/home-manager/pull/2610
+    # won't be needed for ever
+    systemd.user.services.swayidle = {
+      Unit.PartOf = [ "sway-session.target" ];
+      Install.WantedBy = [ "sway-session.target" ];
+
+      Service = {
+        Environment =
+          "PATH=${pkgs.bash}/bin:${config.wayland.windowManager.sway.package}/bin";
+        ExecStart = ''
+          ${pkgs.swayidle}/bin/swayidle -w \
+              timeout 300 "${pkgs.swaylock}/bin/swaylock" \
+              timeout 300 'swaymsg "output * dpms off"' \
+                  resume 'swaymsg "output * dpms on"' \
+              before-sleep "${pkgs.swaylock}/bin/swaylock"
+        '';
+        Restart = "on-failure";
+      };
+    };
+  };
+}
diff --git a/home/wm/waybar/default.nix b/home/wm/waybar/default.nix
new file mode 100644
index 0000000..c1bf601
--- /dev/null
+++ b/home/wm/waybar/default.nix
@@ -0,0 +1,52 @@
+{ config, lib, pkgs, ... }:
+let isEnabled = config.my.home.wm.windowManager == "sway";
+in {
+  config = lib.mkIf isEnabled {
+    programs.waybar = {
+      enable = true;
+      systemd = { enable = true; };
+
+      settings = [{
+        layer = "bottom";
+        position = "top";
+        margin-top = 0;
+        margin-left = 0;
+        margin-right = 0;
+        margin-bottom = 0;
+        modules-left = [ "sway/workspaces" "sway/mode" ];
+        modules-right = [ "pulseaudio" "network" "battery" "clock" "tray" ];
+        modules = {
+          "sway/workspaces" = { format = "{name}"; };
+          "sway/mode" = { format = "{}"; };
+          tray = { spacing = 10; };
+          clock = { format = "{: %a %b %d %R}"; };
+          battery = {
+            states = {
+              warning = 30;
+              critical = 15;
+            };
+            format = "ac:{capacity}%";
+            tooltip = true;
+            tooltip-format = "{timeTo} ({capacity}%)";
+          };
+          pulseaudio = {
+            format = "vol:{volume}%";
+            format-bluetooth = "bt:{volume}%";
+            format-bluetooth-muted = "bt:{volume}%";
+            format-muted = "vol:{volume}%";
+            on-click = "pavucontrol";
+          };
+          "network" = {
+            format-wifi = "{essid}:{signalStrength}%";
+            format-ethernet = "{ipaddr}/{cidr}";
+            format-linked = "{ifname} (No IP)";
+            format-disconnected = "network unavailable";
+            format-alt = "{ifname}: {ipaddr}/{cidr}";
+            tooltip = false;
+          };
+        };
+      }];
+      style = (builtins.readFile ./style.css);
+    };
+  };
+}
diff --git a/home/wm/waybar/style.css b/home/wm/waybar/style.css
new file mode 100644
index 0000000..e4565c8
--- /dev/null
+++ b/home/wm/waybar/style.css
@@ -0,0 +1,77 @@
+* {
+  border-radius: 0;
+  border: none;
+  margin: 0;
+  min-height: 0;
+  padding: 0;
+}
+#waybar {
+  font-family: Source Code Pro;
+  font-size: 15px;
+}
+window#waybar {
+  background-color: rgba(43, 48, 59, 0.9);
+  color: #ffffff;
+}
+#workspaces button {
+  padding: 0 3px;
+  background-color: transparent;
+  color: #888888;
+}
+#workspaces button.focused {
+  background-color: #285577;
+  border: 1px solid #4c7899;
+  color: #ffffff;
+}
+#workspaces button.urgent {
+  background-color: #900000;
+  border: 1px solid #2f343a;
+  color: #ffffff;
+}
+#clock,
+#battery,
+#network,
+#pulseaudio,
+#tray,
+#mode {
+  padding-left: 10px;
+  padding-right: 10px;
+}
+#mode {
+  /* No styles */
+}
+#tray {
+  /* No styles */
+}
+#clock {
+  /* No styles */
+}
+#battery {
+  animation-timing-function: linear;
+  animation-iteration-count: infinite;
+  animation-direction: alternate;
+}
+#battery.discharging {
+  color: #90a1ad;
+}
+#battery.charging {
+  color: #fffff8;
+}
+#battery.warning {
+  border-bottom: 2px solid #ff9e21;
+}
+#battery.critical {
+  border-bottom: 2px solid #ff3121;
+}
+#network {
+  /* No styles */
+}
+#network.disconnected {
+  color: orange;
+}
+#pulseaudio {
+  /* No styles */
+}
+#pulseaudio.muted {
+  color: #90a1ad;
+}
diff --git a/home/wm/wofi/config b/home/wm/wofi/config
new file mode 100644
index 0000000..95dedba
--- /dev/null
+++ b/home/wm/wofi/config
@@ -0,0 +1,4 @@
+allow_images=true
+image_size=20px
+drun-display_generic=true
+dynamic_lines=true
diff --git a/home/wm/wofi/default.nix b/home/wm/wofi/default.nix
new file mode 100644
index 0000000..ad3c759
--- /dev/null
+++ b/home/wm/wofi/default.nix
@@ -0,0 +1,8 @@
+{ config, lib, pkgs, ... }:
+let isEnabled = config.my.home.wm.windowManager == "sway";
+in {
+  config = lib.mkIf isEnabled {
+    home.packages = with pkgs; [ wofi ];
+    xdg.configFile."wofi/config".source = ./config;
+  };
+}
diff --git a/home/xdg/default.nix b/home/xdg/default.nix
new file mode 100644
index 0000000..133b0ad
--- /dev/null
+++ b/home/xdg/default.nix
@@ -0,0 +1,46 @@
+{ config, lib, pkgs, ... }:
+let cfg = config.my.home.xdg;
+in {
+  options.my.home.xdg = with lib; {
+    enable = mkEnableOption "XDG configuration";
+  };
+
+  config = lib.mkIf cfg.enable {
+    xdg = {
+      enable = true;
+      # File types
+      mime.enable = true;
+      # File associatons
+      mimeApps = { enable = true; };
+      # User directories
+      userDirs = {
+        enable = true;
+        createDirectories = true;
+        desktop = "${config.home.homeDirectory}/documents";
+        documents = "${config.home.homeDirectory}/documents";
+        download = "${config.home.homeDirectory}/downloads";
+        music = "${config.home.homeDirectory}/media/music";
+        pictures = "${config.home.homeDirectory}/media/pictures";
+        publicShare = "${config.home.homeDirectory}/documents/public";
+        templates = "${config.home.homeDirectory}/documents/templates";
+        videos = "${config.home.homeDirectory}/media/videos";
+      };
+    };
+
+    # xdg.portal = {
+    #   enable = true;
+    #   gtkUsePortal = true;
+    #   extraPortals =
+    #     [ pkgs.xdg-desktop-portal-gtk pkgs.xdg-desktop-portal-wlr ];
+    # };
+
+    home.packages = with pkgs; [ xdg-utils ];
+
+    # I want a tidier home
+    home.sessionVariables = with config.xdg; {
+      DOCKER_CONFIG = "${configHome}/docker";
+      LESSHISTFILE = "${dataHome}/less/history";
+      LESSKEY = "${configHome}/less/lesskey";
+    };
+  };
+}
diff --git a/home/yt-dlp/config b/home/yt-dlp/config
new file mode 100644
index 0000000..4710c9f
--- /dev/null
+++ b/home/yt-dlp/config
@@ -0,0 +1,26 @@
+# Preferred formats:
+# 1. 1080p, combined, mp4 (for some non-youtube sites).
+# 2. 1080p, combined, any format (in case mp4 is not available).
+# 3. 1080p, best video + best audio (only available with separate video and audio on youtube).
+# 4. >30fps (any resolution), best video + best audio (only available with separate video and audio on youtube).
+# 5. 720p, pre-joined, because it is available on youtube.
+# 6. <720p, best video + best audio (480p and some other lower resolutions are only available with separate video and audio on youtube).
+# 7. When all else fails, take whatever youtube-dl thinks is the best (mainly for non-YT websites).
+--format="best[height=1080][ext=mp4]/best[height=1080]/bestvideo[height=1080][ext=mp4]+bestaudio[ext=m4a]/bestvideo[fps>30][ext=mp4]+bestaudio[ext=m4a]/best[height=720][ext=mp4]/bestvideo[ext=mp4]+bestaudio[ext=m4a]/best"
+
+--sub-langs all
+--write-subs
+
+--convert-subs=srt
+
+--restrict-filenames
+--output="$HOME/media/videos/%(title)s.%(ext)s"
+--merge-output-format mkv
+
+--embed-metadata
+--embed-chapters
+--embed-info-json
+# create chapter entries to mark sponsor segments
+--sponsorblock-mark all
+
+--yes-playlist
diff --git a/home/yt-dlp/default.nix b/home/yt-dlp/default.nix
new file mode 100644
index 0000000..4e9cdf4
--- /dev/null
+++ b/home/yt-dlp/default.nix
@@ -0,0 +1,12 @@
+{ config, lib, pkgs, ... }:
+let cfg = config.my.home.yt-dlp;
+in {
+  options.my.home.yt-dlp = with lib; {
+    enable = mkEnableOption "yt-dlp configuration";
+  };
+
+  config = lib.mkIf cfg.enable {
+    home.packages = with pkgs; [ yt-dlp ];
+    xdg.configFile."yt-dlp/config".source = ./config;
+  };
+}
diff --git a/home/zsh/completion-style.zsh b/home/zsh/completion-style.zsh
new file mode 100644
index 0000000..32bd6f4
--- /dev/null
+++ b/home/zsh/completion-style.zsh
@@ -0,0 +1,34 @@
+# Style the completion a bit
+zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
+
+# Show a prompt on selection
+zstyle ':completion:*' select-prompt '%SScrolling active: current selection at %p%s'
+
+# Use arrow keys in completion list
+zstyle ':completion:*' menu select
+
+# Group results by category
+zstyle ':completion:*' group-name ''
+
+# Keep directories and files separated
+zstyle ':completion:*' list-dirs-first true
+
+# Add colors to processes for kill completion
+zstyle ':completion:*:*:kill:*:processes' list-colors '=(#b) #([0-9]#)*=0=01;31'
+
+# match uppercase from lowercase
+zstyle ':completion:*' matcher-list 'm:{a-z}={A-Z}'
+
+# Filename suffixes to ignore during completion (except after rm command)
+zstyle ':completion:*:*:(^rm):*:*files' ignored-patterns '*?.old'
+
+# command for process lists, the local web server details and host completion
+# on processes completion complete all user processes
+zstyle ':completion:*:processes' command 'ps -au$USER'
+
+# Completion formatting and messages
+zstyle ':completion:*' verbose yes
+zstyle ':completion:*:descriptions' format '%B%d%b'
+zstyle ':completion:*:messages' format '%d'
+zstyle ':completion:*:warnings' format 'No matches for: %d'
+zstyle ':completion:*:corrections' format '%B%d (errors: %e)%b'
diff --git a/home/zsh/default.nix b/home/zsh/default.nix
new file mode 100644
index 0000000..0ee9e43
--- /dev/null
+++ b/home/zsh/default.nix
@@ -0,0 +1,56 @@
+{ config, pkgs, lib, ... }:
+let cfg = config.my.home.zsh;
+in {
+  options.my.home.zsh = with lib; {
+    enable = mkEnableOption "zsh configuration";
+  };
+
+  config = lib.mkIf cfg.enable {
+    home.packages = with pkgs; [ zsh-completions ];
+
+    programs.zsh = {
+      enable = true;
+      dotDir = ".config/zsh";
+      enableCompletion = true;
+
+      history = {
+        size = 500000;
+        save = 500000;
+        extended = false;
+        ignoreSpace = true;
+        ignoreDups = true;
+        share = false;
+        # see
+        # https://github.com/nix-community/home-manager/blob/32a7da69dc53c9eb5ad0675eb7fdc58f7fe35272/modules/programs/zsh.nix#L537
+        path = ".local/share/zsh/zsh_history";
+      };
+
+      localVariables = {
+        # Print timing statistics for everything which takes longer than 5 seconds of
+        # user + system time.
+        REPORTTIME = 5;
+      };
+
+      shellAliases = {
+        ll = "ls -l --color=auto";
+        lt = "ls -ltrh --color=auto";
+        drone = "DRONE_TOKEN=$(pass api/drone.fcuny.xyz) drone";
+      };
+
+      defaultKeymap = "emacs";
+
+      initExtraFirst = ''
+        if [ -z $DISPLAY ] && [ "$(tty)" = "/dev/tty1" ]; then
+          exec sway
+        fi
+      '';
+
+      initExtra = lib.concatMapStrings builtins.readFile [
+        ./completion-style.zsh
+        ./options.zsh
+        ./prompt.zsh
+        ./tmux.zsh
+      ];
+    };
+  };
+}
diff --git a/home/zsh/options.zsh b/home/zsh/options.zsh
new file mode 100644
index 0000000..6d39bc1
--- /dev/null
+++ b/home/zsh/options.zsh
@@ -0,0 +1,27 @@
+# Show an error when a globbing expansion doesn't find any match
+setopt nomatch
+
+# List on ambiguous completion and Insert first match immediately
+setopt autolist menucomplete
+
+# Use pushd when cd-ing around
+setopt autopushd pushdminus pushdsilent
+
+# Use single quotes in string without the weird escape tricks
+setopt rcquotes
+
+# Single word commands can resume an existing job
+setopt autoresume
+
+# Append commands to history as they are exectuted
+setopt inc_append_history_time
+
+# Remove useless whitespace from commands
+setopt hist_reduce_blanks
+
+# Those options aren't wanted
+unsetopt beep extendedglob notify
+
+# word select works like in bash
+autoload -U select-word-style
+select-word-style bash
diff --git a/home/zsh/prompt.zsh b/home/zsh/prompt.zsh
new file mode 100644
index 0000000..1c21d4b
--- /dev/null
+++ b/home/zsh/prompt.zsh
@@ -0,0 +1,11 @@
+setopt prompt_subst
+
+PROMPT='%K{cyan}%F{black}%m%k%f %~ %% '
+
+# For tramp (emacs).
+if [ "$TERM" = "dumb" ]; then
+  unset PROMPT
+  PS1='$ '
+  unsetopt zle
+fi
+
diff --git a/home/zsh/tmux.zsh b/home/zsh/tmux.zsh
new file mode 100644
index 0000000..4120512
--- /dev/null
+++ b/home/zsh/tmux.zsh
@@ -0,0 +1,3 @@
+if command -v tmux &> /dev/null && [ -z "$TMUX" ]; then
+  tmux attach -t default || tmux new -s default
+fi