summary refs log tree commit diff stats
path: root/user
diff options
context:
space:
mode:
authorAlan Pearce2019-10-02 16:55:23 +0200
committerAlan Pearce2019-10-02 16:55:23 +0200
commitec7f1357d16ff2f4aa7430a2940a0b9519018595 (patch)
tree28f4b022aff0ec38e7891ec677703a074dfd89f8 /user
parent8a65ab00b625139984aeb6c3a1a93f8bc9d3fc85 (diff)
parenta261579a74bc3bf9ec673ef190f1ec4bb625b86b (diff)
downloadnixfiles-ec7f1357d16ff2f4aa7430a2940a0b9519018595.tar.lz
nixfiles-ec7f1357d16ff2f4aa7430a2940a0b9519018595.tar.zst
nixfiles-ec7f1357d16ff2f4aa7430a2940a0b9519018595.zip
Add 'user/' from commit 'a261579a74bc3bf9ec673ef190f1ec4bb625b86b'
git-subtree-dir: user
git-subtree-mainline: 8a65ab00b625139984aeb6c3a1a93f8bc9d3fc85
git-subtree-split: a261579a74bc3bf9ec673ef190f1ec4bb625b86b
Diffstat (limited to 'user')
-rw-r--r--user/.gitignore2
-rw-r--r--user/README.org26
-rwxr-xr-xuser/adopt29
-rwxr-xr-xuser/autorandr/.config/autorandr/docked-close/block3
-rw-r--r--user/autorandr/.config/autorandr/docked-close/config23
-rw-r--r--user/autorandr/.config/autorandr/docked-close/setup3
-rwxr-xr-xuser/autorandr/.config/autorandr/docked-open/block3
-rw-r--r--user/autorandr/.config/autorandr/docked-open/config25
-rw-r--r--user/autorandr/.config/autorandr/docked-open/setup3
-rw-r--r--user/autorandr/.config/autorandr/laptop/config15
-rw-r--r--user/autorandr/.config/autorandr/laptop/setup1
-rwxr-xr-xuser/autorandr/.config/autorandr/postswitch2
-rw-r--r--user/autorandr/.config/autorandr/work-1/config17
-rw-r--r--user/autorandr/.config/autorandr/work-1/setup2
-rw-r--r--user/dunst/.config/dunst/dunstrc245
-rw-r--r--user/emacs/.emacs.d/eshell/alias25
-rw-r--r--user/emacs/.emacs.d/init.el26
-rw-r--r--user/emacs/.emacs.d/main.el838
-rwxr-xr-xuser/emacs/.local/share/applications/emacsclient.desktop12
-rw-r--r--user/git/.config/git/config67
-rw-r--r--user/git/.config/git/config-satoshipay2
-rw-r--r--user/git/.config/git/gitk61
-rw-r--r--user/git/.config/git/ignore34
-rw-r--r--user/gnupg/.gnupg/dirmngr.conf3
-rw-r--r--user/gnupg/.gnupg/gpa.conf2
-rw-r--r--user/gnupg/.gnupg/gpg-agent.conf3
-rw-r--r--user/gnupg/.gnupg/gpg.conf83
-rw-r--r--user/gnupg/.gnupg/trezor/dirmngr.conf1
-rw-r--r--user/gnupg/.gnupg/trezor/gpg.conf4
-rw-r--r--user/i3/.config/i3/config265
-rw-r--r--user/i3/.config/i3status/config112
-rwxr-xr-xuser/install.sh20
-rw-r--r--user/isync/.mbsyncrc37
-rw-r--r--user/javascript/.npmrc8
-rw-r--r--user/ledger/.ledgerrc2
-rw-r--r--user/mlterm/.mlterm/aafont2
-rw-r--r--user/mlterm/.mlterm/color23
-rw-r--r--user/mlterm/.mlterm/font2
-rw-r--r--user/mlterm/.mlterm/main21
-rw-r--r--user/modules/autorandr.nix8
-rw-r--r--user/modules/base.nix6
-rw-r--r--user/modules/dunst.nix8
-rw-r--r--user/modules/emacs.nix9
-rw-r--r--user/modules/git.nix8
-rw-r--r--user/modules/gnupg.nix8
-rw-r--r--user/modules/i3.nix12
-rw-r--r--user/modules/isync.nix5
-rw-r--r--user/modules/ledger.nix5
-rw-r--r--user/modules/msmtp.nix5
-rw-r--r--user/modules/nix.nix6
-rw-r--r--user/modules/npm.nix5
-rw-r--r--user/modules/rofi.nix12
-rw-r--r--user/modules/sxhkd.nix8
-rw-r--r--user/modules/tabnine.nix8
-rw-r--r--user/modules/trezor.nix9
-rw-r--r--user/modules/xresources.nix8
-rw-r--r--user/modules/zsh.nix12
-rw-r--r--user/msmtp/.msmtprc17
-rw-r--r--user/nix/.config/nixpkgs/config.nix3
-rw-r--r--user/prefect.nix18
-rw-r--r--user/rofi/.config/networkmanager-dmenu/config.ini6
-rw-r--r--user/rofi/.config/rofi-pass/config77
-rw-r--r--user/rofi/.config/rofi/config8
-rw-r--r--user/satoshipad.nix23
-rwxr-xr-xuser/stow2
-rw-r--r--user/sxhkd/.config/sxhkd/sxhkdrc29
-rw-r--r--user/tabnine/.config/TabNine/TabNine.toml36
-rw-r--r--user/termite/.config/termite/config48
-rw-r--r--user/trezor/.ssh/agent.config1
-rwxr-xr-xuser/unstow-all11
-rw-r--r--user/xresources/.xresources/base16-mexico-light-25654
-rw-r--r--user/xresources/.xresources/base16-tomorrow54
-rw-r--r--user/xresources/.xresources/main42
-rw-r--r--user/xresources/.xresources/solarized-light70
-rw-r--r--user/yarn/.yarnrc9
-rw-r--r--user/zsh/.config/zsh/.zshenv64
-rw-r--r--user/zsh/.config/zsh/.zshrc281
-rwxr-xr-xuser/zsh/.config/zsh/setup.sh9
-rw-r--r--user/zsh/.rm_recycle_home0
-rw-r--r--user/zsh/.zshenv3
80 files changed, 3059 insertions, 0 deletions
diff --git a/user/.gitignore b/user/.gitignore
new file mode 100644
index 00000000..d7bc17e5
--- /dev/null
+++ b/user/.gitignore
@@ -0,0 +1,2 @@
+home.nix
+result
\ No newline at end of file
diff --git a/user/README.org b/user/README.org
new file mode 100644
index 00000000..02a3a1f7
--- /dev/null
+++ b/user/README.org
@@ -0,0 +1,26 @@
+* Nixfiles
+
+I've organised this repository with [[https://rycee.gitlab.io/home-manager/][Home Manager]]. It focuses on [[http://zsh.sourceforge.net][Z
+Shell]] and [[http://emacs.sexy][Emacs]].
+
+It doesn't use any configuration frameworks, just packages installed
+via package managers.  For Z shell I use [[https://github.com/zdharma/zplugin][zplugin]] and for Emacs I use the
+built-in package.el via [[https://github.com/jwiegley/use-package][use-package]].
+
+It should work on:
+- Linux
+- macOS
+
+** Installation
+
+1. If migrating from a stow version, run =migrate.sh=.
+2. Run =install.sh=.  
+
+*** Z Shell
+
+My zsh configuration uses [[https://github.com/zdharma/zplugin][zplugin]]. I've included a setup script:
+
+#+BEGIN_SRC sh :exports code
+./zsh/config/zsh/setup.sh
+#+END_SRC
+
diff --git a/user/adopt b/user/adopt
new file mode 100755
index 00000000..8e7bf4ff
--- /dev/null
+++ b/user/adopt
@@ -0,0 +1,29 @@
+#!/bin/sh
+DOTFILES_DIR=$(dirname $0)
+STOW="$DOTFILES_DIR/stow"
+
+if [ "$#" -lt 2 ]
+then
+  echo "usage: $(basename $0) tag file-to-adopt"
+  exit 1
+fi
+
+if [ -d $2 ]
+then
+  TARGET="$DOTFILES_DIR/$1/$2"
+  if ! [ -d $TARGET ]
+  then
+    mkdir -p $TARGET
+  fi
+  mv $2/* $TARGET
+  $STOW $1
+elif [ -f $2 ]
+then
+  TARGET="$DOTFILES_DIR/$1/$(dirname $2)"
+  if ! [ -d $TARGET ]
+  then
+    mkdir -p $TARGET
+  fi
+  mv $2 $TARGET
+  $STOW $1
+fi
diff --git a/user/autorandr/.config/autorandr/docked-close/block b/user/autorandr/.config/autorandr/docked-close/block
new file mode 100755
index 00000000..782c3a74
--- /dev/null
+++ b/user/autorandr/.config/autorandr/docked-close/block
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+exec grep -vq close /proc/acpi/button/lid/LID/state
\ No newline at end of file
diff --git a/user/autorandr/.config/autorandr/docked-close/config b/user/autorandr/.config/autorandr/docked-close/config
new file mode 100644
index 00000000..d8ce5031
--- /dev/null
+++ b/user/autorandr/.config/autorandr/docked-close/config
@@ -0,0 +1,23 @@
+output DP1
+off
+output DP2
+off
+output DP2-3
+off
+output HDMI1
+off
+output HDMI2
+off
+output VIRTUAL1
+off
+output eDP1
+off
+output DP2-1
+mode 2560x1440
+pos 0x0
+primary
+rate 59.95
+output DP2-2
+mode 2560x1440
+pos 2560x0
+rate 59.95
diff --git a/user/autorandr/.config/autorandr/docked-close/setup b/user/autorandr/.config/autorandr/docked-close/setup
new file mode 100644
index 00000000..607eacbc
--- /dev/null
+++ b/user/autorandr/.config/autorandr/docked-close/setup
@@ -0,0 +1,3 @@
+DP2-1 00ffffffffffff0030aeaf61010101011c1c0104a53c22783e9325a9544d9e250c5054a1080081809500b300d1c0d100a9c001010101565e00a0a0a029503020350055502100001a023a801871382d40582c450055502100001e000000fd00324c1e7822000a202020202020000000fc004c454e20503237682d31300a20010d02031df14a01020304051413901f12230907078301000065030c001000011d007251d01e206e28550055502100001e8c0ad08a20e02d10103e96005550210000180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bd
+DP2-2 00ffffffffffff0030aeaf61010101010a1c0104a53c22783e9325a9544d9e250c5054a1080081809500b300d1c0d100a9c001010101565e00a0a0a029503020350055502100001a023a801871382d40582c450055502100001e000000fd00324c1e7822000a202020202020000000fc004c454e20503237682d31300a20011f02031df14a01020304051413901f12230907078301000065030c001000011d007251d01e206e28550055502100001e8c0ad08a20e02d10103e96005550210000180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bd
+eDP1 00ffffffffffff0006af3d2400000000001a0104951f117802a2b591575894281c505400000001010101010101010101010101010101843a8034713828403064310035ad10000018d02e8034713828403064310035ad10000018000000fe0041554f0a202020202020202020000000fe004231343048414e30322e34200a00e4
diff --git a/user/autorandr/.config/autorandr/docked-open/block b/user/autorandr/.config/autorandr/docked-open/block
new file mode 100755
index 00000000..4c82692a
--- /dev/null
+++ b/user/autorandr/.config/autorandr/docked-open/block
@@ -0,0 +1,3 @@
+#!/bin/sh
+
+exec grep -vq open /proc/acpi/button/lid/LID/state
\ No newline at end of file
diff --git a/user/autorandr/.config/autorandr/docked-open/config b/user/autorandr/.config/autorandr/docked-open/config
new file mode 100644
index 00000000..44749be1
--- /dev/null
+++ b/user/autorandr/.config/autorandr/docked-open/config
@@ -0,0 +1,25 @@
+output DP1
+off
+output DP2
+off
+output DP2-3
+off
+output HDMI1
+off
+output HDMI2
+off
+output VIRTUAL1
+off
+output DP2-1
+mode 2560x1440
+pos 0x0
+primary
+rate 59.95
+output DP2-2
+mode 2560x1440
+pos 2560x0
+rate 59.95
+output eDP1
+mode 1920x1080
+pos 1632x1440
+rate 60.03
diff --git a/user/autorandr/.config/autorandr/docked-open/setup b/user/autorandr/.config/autorandr/docked-open/setup
new file mode 100644
index 00000000..607eacbc
--- /dev/null
+++ b/user/autorandr/.config/autorandr/docked-open/setup
@@ -0,0 +1,3 @@
+DP2-1 00ffffffffffff0030aeaf61010101011c1c0104a53c22783e9325a9544d9e250c5054a1080081809500b300d1c0d100a9c001010101565e00a0a0a029503020350055502100001a023a801871382d40582c450055502100001e000000fd00324c1e7822000a202020202020000000fc004c454e20503237682d31300a20010d02031df14a01020304051413901f12230907078301000065030c001000011d007251d01e206e28550055502100001e8c0ad08a20e02d10103e96005550210000180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bd
+DP2-2 00ffffffffffff0030aeaf61010101010a1c0104a53c22783e9325a9544d9e250c5054a1080081809500b300d1c0d100a9c001010101565e00a0a0a029503020350055502100001a023a801871382d40582c450055502100001e000000fd00324c1e7822000a202020202020000000fc004c454e20503237682d31300a20011f02031df14a01020304051413901f12230907078301000065030c001000011d007251d01e206e28550055502100001e8c0ad08a20e02d10103e96005550210000180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bd
+eDP1 00ffffffffffff0006af3d2400000000001a0104951f117802a2b591575894281c505400000001010101010101010101010101010101843a8034713828403064310035ad10000018d02e8034713828403064310035ad10000018000000fe0041554f0a202020202020202020000000fe004231343048414e30322e34200a00e4
diff --git a/user/autorandr/.config/autorandr/laptop/config b/user/autorandr/.config/autorandr/laptop/config
new file mode 100644
index 00000000..152d1b95
--- /dev/null
+++ b/user/autorandr/.config/autorandr/laptop/config
@@ -0,0 +1,15 @@
+output DP1
+off
+output DP2
+off
+output HDMI1
+off
+output HDMI2
+off
+output VIRTUAL1
+off
+output eDP1
+mode 1920x1080
+pos 0x0
+primary
+rate 60.03
diff --git a/user/autorandr/.config/autorandr/laptop/setup b/user/autorandr/.config/autorandr/laptop/setup
new file mode 100644
index 00000000..dc17ff13
--- /dev/null
+++ b/user/autorandr/.config/autorandr/laptop/setup
@@ -0,0 +1 @@
+eDP1 00ffffffffffff0006af3d2400000000001a0104951f117802a2b591575894281c505400000001010101010101010101010101010101843a8034713828403064310035ad10000018d02e8034713828403064310035ad10000018000000fe0041554f0a202020202020202020000000fe004231343048414e30322e34200a00e4
diff --git a/user/autorandr/.config/autorandr/postswitch b/user/autorandr/.config/autorandr/postswitch
new file mode 100755
index 00000000..25b068d2
--- /dev/null
+++ b/user/autorandr/.config/autorandr/postswitch
@@ -0,0 +1,2 @@
+#!/bin/sh
+notify-send --expire-time=5000 "Display profile: '$AUTORANDR_CURRENT_PROFILE'"
diff --git a/user/autorandr/.config/autorandr/work-1/config b/user/autorandr/.config/autorandr/work-1/config
new file mode 100644
index 00000000..834278c8
--- /dev/null
+++ b/user/autorandr/.config/autorandr/work-1/config
@@ -0,0 +1,17 @@
+output DP1
+off
+output DP2
+off
+output HDMI1
+off
+output VIRTUAL1
+off
+output HDMI2
+mode 1920x1200
+pos 0x0
+primary
+rate 59.95
+output eDP1
+mode 1920x1080
+pos 1920x0
+rate 60.03
diff --git a/user/autorandr/.config/autorandr/work-1/setup b/user/autorandr/.config/autorandr/work-1/setup
new file mode 100644
index 00000000..12a4c698
--- /dev/null
+++ b/user/autorandr/.config/autorandr/work-1/setup
@@ -0,0 +1,2 @@
+HDMI2 00ffffffffffff0015c33425b1a21403041b010380342178ea0495a9554d9d26105054a10800a9408180b300a9c081c0810001010101283c80a070b023403020360007442100001a023a801871382d40582c450007442100001e000000fd00313d0f4c11000a202020202020000000fc004556323435350a202020202020011e020325f14e901f051404130312021107160615230907078301000066030c00100080e2007b011d8018711c1620582c250007442100009e011d80d0721c1620102c258007442100009e8c0ad08a20e02d10103e96000744210000188c0ad090204031200c4055000744210000180000000000000000000000000000000000008e
+eDP1 00ffffffffffff0006af3d2400000000001a0104951f117802a2b591575894281c505400000001010101010101010101010101010101843a8034713828403064310035ad10000018d02e8034713828403064310035ad10000018000000fe0041554f0a202020202020202020000000fe004231343048414e30322e34200a00e4
diff --git a/user/dunst/.config/dunst/dunstrc b/user/dunst/.config/dunst/dunstrc
new file mode 100644
index 00000000..73c932d2
--- /dev/null
+++ b/user/dunst/.config/dunst/dunstrc
@@ -0,0 +1,245 @@
+[global]
+    font = Monospace 13
+
+    # Allow a small subset of html markup:
+    #   <b>bold</b>
+    #   <i>italic</i>
+    #   <s>strikethrough</s>
+    #   <u>underline</u>
+    #
+    # For a complete reference see
+    # <http://developer.gnome.org/pango/stable/PangoMarkupFormat.html>.
+    # If markup is not allowed, those tags will be stripped out of the
+    # message.
+    allow_markup = yes
+
+    # The format of the message.  Possible variables are:
+    #   %a  appname
+    #   %s  summary
+    #   %b  body
+    #   %i  iconname (including its path)
+    #   %I  iconname (without its path)
+    #   %p  progress value if set ([  0%] to [100%]) or nothing
+    # Markup is allowed
+    format = "<b>%s</b>\n%b"
+
+    # Sort messages by urgency.
+    sort = yes
+
+    # Show how many messages are currently hidden (because of geometry).
+    indicate_hidden = yes
+
+    # Alignment of message text.
+    # Possible values are "left", "center" and "right".
+    alignment = left
+
+    # The frequency with wich text that is longer than the notification
+    # window allows bounces back and forth.
+    # This option conflicts with "word_wrap".
+    # Set to 0 to disable.
+    bounce_freq = 0
+
+    # Show age of message if message is older than show_age_threshold
+    # seconds.
+    # Set to -1 to disable.
+    show_age_threshold = 60
+
+    # Split notifications into multiple lines if they don't fit into
+    # geometry.
+    word_wrap = yes
+
+    # Ignore newlines '\n' in notifications.
+    ignore_newline = no
+
+
+    # The geometry of the window:
+    #   [{width}]x{height}[+/-{x}+/-{y}]
+    # The geometry of the message window.
+    # The height is measured in number of notifications everything else
+    # in pixels.  If the width is omitted but the height is given
+    # ("-geometry x2"), the message window expands over the whole screen
+    # (dmenu-like).  If width is 0, the window expands to the longest
+    # message displayed.  A positive x is measured from the left, a
+    # negative from the right side of the screen.  Y is measured from
+    # the top and down respectevly.
+    # The width can be negative.  In this case the actual width is the
+    # screen width minus the width defined in within the geometry option.
+    geometry = "300x10-10+30"
+
+    # Shrink window if it's smaller than the width.  Will be ignored if
+    # width is 0.
+    shrink = no
+
+    # The transparency of the window.  Range: [0; 100].
+    # This option will only work if a compositing windowmanager is
+    # present (e.g. xcompmgr, compiz, etc.).
+    transparency = 0
+
+    # Don't remove messages, if the user is idle (no mouse or keyboard input)
+    # for longer than idle_threshold seconds.
+    # Set to 0 to disable.
+    idle_threshold = 120
+
+    # Which monitor should the notifications be displayed on.
+    monitor = 0
+
+    # Display notification on focused monitor.  Possible modes are:
+    #   mouse: follow mouse pointer
+    #   keyboard: follow window with keyboard focus
+    #   none: don't follow anything
+    #
+    # "keyboard" needs a windowmanager that exports the
+    # _NET_ACTIVE_WINDOW property.
+    # This should be the case for almost all modern windowmanagers.
+    #
+    # If this option is set to mouse or keyboard, the monitor option
+    # will be ignored.
+    follow = mouse
+
+    # Should a notification popped up from history be sticky or timeout
+    # as if it would normally do.
+    sticky_history = yes
+
+    # Maximum amount of notifications kept in history
+    history_length = 20
+
+    # Display indicators for URLs (U) and actions (A).
+    show_indicators = yes
+
+    # The height of a single line.  If the height is smaller than the
+    # font height, it will get raised to the font height.
+    # This adds empty space above and under the text.
+    line_height = 0
+
+    # Draw a line of "separatpr_height" pixel height between two
+    # notifications.
+    # Set to 0 to disable.
+    separator_height = 2
+
+    # Padding between text and separator.
+    padding = 8
+
+    # Horizontal padding.
+    horizontal_padding = 8
+
+    # Define a color for the separator.
+    # possible values are:
+    #  * auto: dunst tries to find a color fitting to the background;
+    #  * foreground: use the same color as the foreground;
+    #  * frame: use the same color as the frame;
+    #  * anything else will be interpreted as a X color.
+    separator_color = frame
+
+    # Print a notification on startup.
+    # This is mainly for error detection, since dbus (re-)starts dunst
+    # automatically after a crash.
+    startup_notification = false
+
+    # dmenu path.
+    dmenu = /usr/bin/env dmenu -p dunst:
+
+    # Browser for opening urls in context menu.
+    browser = /usr/bin/env firefox -new-tab
+
+    # Align icons left/right/off
+    icon_position = off
+
+    # Paths to default icons.
+    icon_folders = /usr/share/icons/gnome/16x16/status/:/usr/share/icons/gnome/16x16/devices/
+
+[frame]
+    width = 1
+    color = "#383838"
+
+[shortcuts]
+
+    # Shortcuts are specified as [modifier+][modifier+]...key
+    # Available modifiers are "ctrl", "mod1" (the alt-key), "mod2",
+    # "mod3" and "mod4" (windows-key).
+    # Xev might be helpful to find names for keys.
+
+    # Close notification.
+    close = mod4+apostrophe
+
+    # Close all notifications.
+    close_all = mod4+shift+apostrophe
+
+    # Redisplay last message(s).
+    # On the US keyboard layout "grave" is normally above TAB and left
+    # of "1".
+    history = mod4+grave
+
+    # Context menu.
+    context = mod4+shift+period
+
+[urgency_low]
+    # IMPORTANT: colors have to be defined in quotation marks.
+    # Otherwise the "#" and following would be interpreted as a comment.
+    background = "#b8b8b8"
+    foreground = "#f8f8f8"
+    timeout = 10
+
+[urgency_normal]
+    background = "#7cafc2"
+    foreground = "#f8f8f8"
+    timeout = 10
+
+[urgency_critical]
+    background = "#ab4642"
+    foreground = "#f8f8f8"
+    timeout = 0
+
+
+# Every section that isn't one of the above is interpreted as a rules to
+# override settings for certain messages.
+# Messages can be matched by "appname", "summary", "body", "icon", "category",
+# "msg_urgency" and you can override the "timeout", "urgency", "foreground",
+# "background", "new_icon" and "format".
+# Shell-like globbing will get expanded.
+#
+# SCRIPTING
+# You can specify a script that gets run when the rule matches by
+# setting the "script" option.
+# The script will be called as follows:
+#   script appname summary body icon urgency
+# where urgency can be "LOW", "NORMAL" or "CRITICAL".
+#
+# NOTE: if you don't want a notification to be displayed, set the format
+# to "".
+# NOTE: It might be helpful to run dunst -print in a terminal in order
+# to find fitting options for rules.
+
+#[espeak]
+#    summary = "*"
+#    script = dunst_espeak.sh
+
+#[script-test]
+#    summary = "*script*"
+#    script = dunst_test.sh
+
+#[ignore]
+#    # This notification will not be displayed
+#    summary = "foobar"
+#    format = ""
+
+#[signed_on]
+#    appname = Pidgin
+#    summary = "*signed on*"
+#    urgency = low
+#
+#[signed_off]
+#    appname = Pidgin
+#    summary = *signed off*
+#    urgency = low
+#
+#[says]
+#    appname = Pidgin
+#    summary = *says*
+#    urgency = critical
+#
+#[twitter]
+#    appname = Pidgin
+#    summary = *twitter.com*
+#    urgency = normal
+#
+# vim: ft=cfg
diff --git a/user/emacs/.emacs.d/eshell/alias b/user/emacs/.emacs.d/eshell/alias
new file mode 100644
index 00000000..781b8a25
--- /dev/null
+++ b/user/emacs/.emacs.d/eshell/alias
@@ -0,0 +1,25 @@
+alias pk eshell-up-pk $1
+alias up eshell-up $1
+
+alias ec find-file $1
+
+alias l ls $*
+alias la ls -A $*
+alias ll ls -lh $*
+alias lla ls -lhA $*
+
+alias https http --default-scheme https $*
+
+alias ava npx ava $*
+alias bunyan npx bunyan $*
+alias mocha npx mocha $*
+alias prettier prettier_d --pkg-conf $*
+alias standard npx standard $*
+alias tsc npx tsc $*
+alias tslnt npx tslnt $*
+alias tsnode npx tsnode $*
+
+alias kx kubectx $*
+alias kns kubens $*
+
+alias cdg cd (projectile-project-root)
\ No newline at end of file
diff --git a/user/emacs/.emacs.d/init.el b/user/emacs/.emacs.d/init.el
new file mode 100644
index 00000000..48fc30a3
--- /dev/null
+++ b/user/emacs/.emacs.d/init.el
@@ -0,0 +1,26 @@
+;;; init --- user init file -*- no-byte-compile: t -*-
+;;; Commentary:
+;; Entry point for Emacs init.
+;; Ensures that main init code is up-to-date by loading the newest version.
+;;
+;;; Code:
+(setq inhibit-startup-echo-area-message "alan")
+(setq load-prefer-newer t
+      package-user-dir (concat "~/.emacs.d/packages/" emacs-version "/elpa")
+      package-enable-at-startup nil
+      package-archives nil)
+
+(package-initialize)
+(require 'auto-compile nil :noerror)
+
+(defun reload-user-init-file ()
+  "Reload init file."
+  (interactive)
+  (load-file user-init-file))
+
+(when (featurep 'auto-compile)
+  (auto-compile-on-load-mode))
+
+(let ((gc-cons-threshold most-positive-fixnum))
+  (load (expand-file-name "main.el" user-emacs-directory) :nomessage t))
+;;; init ends here
diff --git a/user/emacs/.emacs.d/main.el b/user/emacs/.emacs.d/main.el
new file mode 100644
index 00000000..88faf140
--- /dev/null
+++ b/user/emacs/.emacs.d/main.el
@@ -0,0 +1,838 @@
+(setq inhibit-startup-screen t
+      initial-scratch-message ""
+      initial-major-mode 'text-mode
+      package-enable-at-startup nil)
+
+(eval-when-compile
+  (require 'use-package)
+  (setq use-package-expand-minimally t))
+(setq use-package-always-demand (daemonp))
+
+(use-package exec-path-from-shell
+  :if (eq system-type 'darwin)
+  :commands (exec-path-from-shell-initialize)
+  :custom ((exec-path-from-shell-arguments nil)
+           (exec-path-from-shell-debug t))
+  :init (progn
+          (exec-path-from-shell-initialize)))
+
+;;; Customize
+
+(setq custom-file "~/.emacs.d/custom.el")
+(load custom-file :noerror :nomessage)
+
+(use-package crux
+  :defer 1
+  :custom ((crux-reopen-as-root-mode nil)))
+
+;;; Styles
+
+(custom-set-variables
+ ;; I prefer an always-visible cursor.  Feels less distracting.
+ '(blink-cursor-mode nil)
+ ;; Disable all the bars, unless on OSX, in which case, keep the menu bar.
+ '(menu-bar-mode nil)
+ '(scroll-bar-mode nil)
+ '(tool-bar-mode nil))
+(set-fringe-mode '(4 . 4))
+
+;; Ring the bell sometimes, but not so often
+(setq ring-bell-function
+      (lambda ()
+        (unless (memq this-command
+                      '(isearch-abort abort-recursive-edit exit-minibuffer keyboard-quit minibuffer-keyboard-quit undo-tree-undo))
+          (ding))))
+
+(when (or (daemonp)
+           window-system)
+  (load-theme 'almost-mono-white t)
+  (if (eq window-system 'x)
+      (setq-default line-spacing 0.2))
+  (setq frame-background-mode 'light)
+  (mapc 'frame-set-background-mode (frame-list)))
+  (let ((line (face-attribute 'mode-line :underline)))
+    (set-face-attribute 'mode-line          nil :overline   line)
+    (set-face-attribute 'mode-line-inactive nil :overline   line)
+    (set-face-attribute 'mode-line-inactive nil :underline  line)
+    (set-face-attribute 'mode-line          nil :box        nil)
+    (set-face-attribute 'mode-line-inactive nil :box        nil))
+
+;;; Chrome
+(use-package minions
+  :custom ((minions-mode-line-lighter "#")
+           (minions-mode-line-delimiters nil)
+           (minions-mode t)))
+
+(setq-default mode-line-position nil
+              mode-line-mule-info nil
+              mode-line-client nil
+              mode-line-remote nil)
+
+(use-package moody
+  :config (progn
+            (setq x-underline-at-descent-line t)
+            (moody-replace-mode-line-buffer-identification)
+            (moody-replace-vc-mode)
+            (with-eval-after-load 'eyebrowse
+              (defvar eyebrowse-lighter-default
+                '(:eval (eyebrowse-mode-line-indicator)))
+              (defvar moody-replace-eyebrowse-lighter
+                '(:eval (moody-tab (eyebrowse-mode-line-indicator) 1 'up)))
+              (defun moody-replace-eyebrowse (&optional reverse)
+                (interactive "P")
+                (if (assoc 'eyebrowse-mode mode-line-misc-info)
+                (setcdr (assoc 'eyebrowse-mode mode-line-misc-info)
+                        (list (if reverse
+                                  eyebrowse-lighter-default
+                                moody-replace-eyebrowse-lighter)))
+                (push (list 'eyebrowse-mode moody-replace-eyebrowse-lighter)
+                      (cdr (last mode-line-misc-info)))))
+              (moody-replace-eyebrowse nil))))
+
+(use-package ns-auto-titlebar
+  :if (eq system-type 'darwin)
+  :custom ((ns-auto-titlebar-mode t)))
+
+(add-to-list 'default-frame-alist '(width . 100))
+(add-to-list 'default-frame-alist '(height . 40))
+
+;;; Dates & Times
+
+(custom-set-variables
+ '(calendar-week-start-day 1)
+ '(calendar-date-style 'iso))
+
+(defun insert-date (prefix)
+  "Insert the current date.
+With PREFIX, use British format.
+With two prefix arguments, write out the day and month name."
+  (interactive "P")
+  (let ((format (cond
+                 ((not prefix) "%Y-%m-%d")
+                 ((equal prefix '(4)) "%d/%m/%Y")
+                 ((equal prefix '(16)) "%A, %d %B %Y"))))
+    (insert (format-time-string format))))
+
+(defun insert-datetime (prefix)
+  "Insert current date and time.  With PREFIX, use ISO8601 format."
+  (interactive "P")
+  (let ((format (cond
+                 ((not prefix) "%Y-%m-%d %H:%M:%S")
+                 ((equal prefix '(4)) "%Y-%m-%dT%H:%M:%SZ"))))
+    (insert (format-time-string format))))
+
+;;; Keybindings
+
+;; I think =set-keyboard-coding-system= stops OS X from doing something
+;; annoying to add accents.  The modifier setup is to match my
+;; re-arrangement of modifiers on OSX: Cmd on the outside, then
+;; Option/alt, then Control.
+
+(when (eq system-type 'darwin)
+  (custom-set-variables
+   '(mac-option-modifier 'meta)
+   '(mac-right-option-modifier 'none)
+   '(mac-control-modifier 'control)
+   '(mac-right-control-modifier 'left)
+   '(mac-command-modifier 'super)
+   '(mac-right-command-modifier 'left)
+   '(mac-function-modifier 'hyper)))
+
+(use-package general
+  :functions (general-unbind general-define-key)
+  :config (progn
+	    (general-override-mode +1)
+            (when (eq system-type 'darwin)
+              (general-unbind "s-x"))))
+
+(use-package avy
+  :custom ((avy-all-windows nil)))
+(use-package ace-link
+  :after avy
+  :commands (ace-link-setup-default)
+  :config (ace-link-setup-default))
+
+;; Popup keybindings following a prefix automatically.
+
+(use-package which-key
+  :defer 5
+  :custom ((which-key-mode +1))
+  :config (progn
+            (which-key-setup-side-window-right-bottom)))
+
+;;; Modeline
+
+(use-package relative-buffers
+  :defer 2
+  :custom ((global-relative-buffers-mode t)))
+
+;;; Minibuffer
+
+(setq enable-recursive-minibuffers t)
+(minibuffer-depth-indicate-mode t)
+
+(use-package hydra
+  :defer 2)
+(use-package ivy
+  :config (progn
+            (ivy-mode +1)))
+(use-package ivy-hydra
+  :defer 2)
+
+(use-package smerge-mode
+  :after magit
+  :config
+  (defhydra unpackaged/smerge-hydra
+    (:color pink :hint nil :post (smerge-auto-leave))
+    "
+^Move^       ^Keep^               ^Diff^                 ^Other^
+^^-----------^^-------------------^^---------------------^^-------
+_n_ext       _b_ase               _<_: upper/base        _C_ombine
+_p_rev       _u_pper              _=_: upper/lower       _r_esolve
+^^           _l_ower              _>_: base/lower        _k_ill current
+^^           _a_ll                _R_efine
+^^           _RET_: current       _E_diff
+"
+    ("n" smerge-next)
+    ("p" smerge-prev)
+    ("b" smerge-keep-base)
+    ("u" smerge-keep-upper)
+    ("l" smerge-keep-lower)
+    ("a" smerge-keep-all)
+    ("RET" smerge-keep-current)
+    ("\C-m" smerge-keep-current)
+    ("<" smerge-diff-base-upper)
+    ("=" smerge-diff-upper-lower)
+    (">" smerge-diff-base-lower)
+    ("R" smerge-refine)
+    ("E" smerge-ediff)
+    ("C" smerge-combine-with-next)
+    ("r" smerge-resolve)
+    ("k" smerge-kill-current)
+    ("w" (lambda ()
+            (interactive)
+            (save-buffer)
+            (bury-buffer))
+     "Save and bury buffer" :color blue)
+    ("q" nil "cancel" :color blue))
+  :hook (magit-diff-visit-file . (lambda ()
+                                   (when smerge-mode
+                                     (unpackaged/smerge-hydra/body)))))
+
+(use-package swiper
+  :general ([remap isearch-forward] #'swiper-isearch))
+
+;; transition smex history to amx
+(let ((smex-save-file (concat user-emacs-directory "smex-items")))
+  (use-package amx
+    :custom ((amx-history-length 100))))
+
+(use-package counsel
+  :commands (counsel-unicode-char)
+  :general ("M-x" #'counsel-M-x))
+
+;;; Windows
+
+(defun split-window-properly (&optional window)
+    (let ((window (or window (selected-window))))
+    (or (and (window-splittable-p window)
+	     ;; Split window vertically.
+	     (with-selected-window window
+	       (split-window-below)))
+	(and (window-splittable-p window t)
+	     ;; Split window horizontally.
+	     (with-selected-window window
+	       (split-window-right))))))
+
+(setq split-window-preferred-function #'split-window-properly
+      split-height-threshold nil
+      split-width-threshold 160)
+
+(use-package eyebrowse
+  :after (evil)
+  :custom ((eyebrowse-new-workspace t)
+           (eyebrowse-mode t)
+           (eyebrowse-mode-line-left-delimiter "")
+           (eyebrowse-mode-line-right-delimiter "")
+           (eyebrowse-mode-line-separator " ")
+           (eyebrowse-mode-line-style 'always))
+  :general (:keymaps 'evil-window-map
+	    "0" #'eyebrowse-switch-to-window-config-0
+            "1" #'eyebrowse-switch-to-window-config-1
+            "2" #'eyebrowse-switch-to-window-config-2
+            "3" #'eyebrowse-switch-to-window-config-3
+            "4" #'eyebrowse-switch-to-window-config-4
+            "5" #'eyebrowse-switch-to-window-config-5
+            "6" #'eyebrowse-switch-to-window-config-6
+            "7" #'eyebrowse-switch-to-window-config-7
+            "8" #'eyebrowse-switch-to-window-config-8
+            "9" #'eyebrowse-switch-to-window-config-9)
+  :ghook ('evil-after-load-hook #'eyebrowse-setup-evil-keys))
+
+(use-package winner
+  :after evil
+  :defer 8
+  :custom ((winner-mode t)
+           (winner-boring-buffers '("*Completions*" "*Help*" "*Apropos*" "*Buffer List*" "*info*" "*Compile-Log*")))
+  :general (:keymaps 'evil-window-map
+                    "u" #'winner-undo
+                    "r" #'winner-redo
+                    "C-r" #'winner-redo))
+;;; Evil
+
+(use-package evil
+  :demand t
+  :commands (evil-mode evil-delete-buffer evil-ex-define-cmd)
+  :init (progn
+	  (defvar evil-want-integration)
+	  (defvar evil-want-keybinding)
+	  (setq evil-want-integration t
+		evil-want-keybinding nil))
+  :custom ((evil-shift-width 2)
+	   (evil-mode-line-format nil))
+  :config (evil-mode +1)
+  :general
+  (:states 'motion
+	   "C-;" #'evil-avy-goto-line)
+  (:states 'normal
+	   ";" #'evil-ex)
+  (:states '(normal motion)
+           "g s" #'evil-avy-goto-symbol-1))
+
+(use-package evil-collection
+  :after (evil)
+  :defer 3
+  :demand t
+  :commands (evil-collection-init)
+  :custom ((evil-collection-company-use-tng nil))
+  :config (progn
+	    (evil-collection-init)))
+
+(general-create-definer my-leader-def
+  :keymaps 'override
+  :states '(normal motion)
+  :prefix ",")
+
+(use-package evil-space
+  :defer 1
+  :after evil
+  :custom ((evil-space-mode t)))
+
+(use-package evil-surround
+  :after evil
+  :defer 2
+  :custom ((global-evil-surround-mode t)))
+
+(use-package evil-commentary
+  :after evil
+  :defer 2
+  :custom ((evil-commentary-mode t)))
+
+(use-package evil-magit
+  :after magit
+  :custom ((evil-magit-use-y-for-yank nil)))
+
+(use-package evil-quickscope
+  :after evil
+  :commands (evil-quickscope-mode)
+  :ghook ('(magit-mode-hook git-rebase-mode-hook) #'turn-off-evil-quickscope-mode)
+  :custom ((global-evil-quickscope-mode t)))
+
+(use-package evil-org
+  :after org
+  :commands (evil-org-set-key-theme)
+  :ghook ('org-mode-hook #'evil-org-mode)
+  :gfhook #'evil-org-set-key-theme)
+
+(use-package evil-org-agenda
+  :after org
+  :ghook ('org-agenda-mode-hook #'evil-org-agenda-set-keys))
+
+;;; Projects
+
+(use-package projectile
+  :defer 1
+  :defines projectile-command-map
+  :custom ((projectile-mode +1)
+           (projectile-completion-system 'ivy))
+  :config (progn
+            (add-to-list 'projectile-globally-ignored-files "package-lock.json")
+            (add-to-list 'projectile-globally-ignored-files "pnpm-lock.yaml")
+            (add-to-list 'projectile-project-root-files "package.json")
+            (add-to-list 'projectile-project-root-files-bottom-up "pnpm-workspace.yaml")
+            (setq projectile-project-root-files-functions '(projectile-root-local
+                                                            projectile-root-top-down
+                                                            projectile-root-bottom-up
+                                                            projectile-root-top-down-recurring))
+	    (with-eval-after-load 'evil-ex
+	      (evil-ex-define-cmd "prg" #'projectile-ripgrep)
+              (evil-ex-define-cmd "pesh[ell]" #'projectile-run-eshell))))
+
+(use-package counsel-projectile
+  :defer 1
+  :commands (counsel-projectile-switch-project
+	     counsel-projectile-rg
+	     counsel-projectile-switch-to-buffer
+             counsel-projectile-mode)
+  :general (:keymaps 'projectile-command-map
+                     "s s" #'counsel-projectile-rg
+                     "s r" #'counsel-projectile-rg)
+  :config (progn
+            (assq-delete-all #'projectile-ripgrep counsel-projectile-key-bindings)
+            (counsel-projectile-mode +1)
+	    (with-eval-after-load 'evil-ex
+	      (evil-ex-define-cmd "cprg" #'counsel-projectile-rg)
+	      (evil-ex-define-cmd "pb" #'counsel-projectile-switch-to-buffer)
+	      (evil-ex-define-cmd "psw[itch]" #'counsel-projectile-switch-project))))
+
+(use-package magit
+  :defer 10
+  :commands (magit-status magit-dispatch)
+  :custom ((magit-auto-revert-mode nil)
+           (magit-section-visibility-indicator nil)
+           (magit-diff-refine-hunk 'all)
+           (magit-display-buffer-function #'display-buffer)
+           (magit-completing-read-function #'ivy-completing-read))
+  :config (progn
+            (global-magit-file-mode +1)
+            (remove-hook 'magit-section-highlight-hook 'magit-section-highlight)
+            (remove-hook 'magit-section-highlight-hook 'magit-section-highlight-selection)
+            (remove-hook 'magit-section-highlight-hook 'magit-diff-highlight)))
+
+(eval-when-compile (require 'fringe-helper))
+(use-package git-gutter
+  :defer t)
+(use-package git-gutter-fringe
+  :defer 5
+  :config (progn
+            (global-git-gutter-mode 1)
+            ;; places the git gutter outside the margins.
+            (setq-default fringes-outside-margins nil)
+            ;; thin fringe bitmaps
+            (fringe-helper-define 'git-gutter-fr:added '(center repeated)
+              ".XXX....")
+            (fringe-helper-define 'git-gutter-fr:modified '(center repeated)
+              ".XXX....")
+            (fringe-helper-define 'git-gutter-fr:deleted '(center repeated)
+              ".XXX....")
+            (setq git-gutter-fr:side 'right-fringe)))
+
+(use-package git-messenger
+  :commands (git-messenger:popup-message)
+  :defer 10
+  :custom ((git-messenger:use-magit-popup t)))
+
+(use-package git-timemachine
+  :commands (git-timemachine))
+
+(use-package editorconfig
+  :defer 2
+  :init (progn
+          (unless (executable-find "editorconfig")
+            (warn "Missing `editorconfig' executable.")))
+  :config (editorconfig-mode +1))
+
+;;; Completion
+
+(use-package company
+  :defer 2
+  :commands (company-explicit-action-p)
+  :custom ((global-company-mode +1)
+           (company-idle-delay 0)
+           (company-show-numbers t)
+           (company-dabbrev-downcase nil)
+           (company-dabbrev-ignore-case nil)
+           (company-begin-commands '(self-insert-command))
+           (company-auto-complete #'company-explicit-action-p)
+           (company-auto-complete-chars '(?\ ?\( ?\) ?.)))
+  :general (:states 'insert
+                    "TAB" #'company-indent-or-complete-common))
+
+;; (use-package all-the-icons)
+
+(eval-when-compile (require 'subr-x))
+(eval-and-compile
+  (defun company-tabnine-load-path ()
+    (string-trim-right (shell-command-to-string "ghq list -p company-tabnine"))))
+
+(use-package company-tabnine
+  :commands (company-tabnine)
+  :after (company)
+  :load-path (lambda () (list (company-tabnine-load-path)))
+  :custom ((company-tabnine-binaries-folder "~/.local/tabnine"))
+  :general ("<M-tab>" #'company-tabnine-call-other-backends
+            "<C-tab>" #'company-tabnine-call-other-backends)
+  :init (progn
+          (add-to-list 'company-backends #'company-tabnine)))
+
+;;; Documentation
+
+(use-package eldoc
+  :defer 5
+  :custom ((global-eldoc-mode +1)
+           (eldoc-idle-delay 0.5)))
+
+(use-package eldoc-box
+  :after (eldoc eglot)
+  :custom ((eldoc-box-hover-mode +1)
+           (eldoc-box-hover-at-point-mode +1)))
+
+(use-package ehelp
+  :defer 15)
+
+(use-package helpful
+  :after ehelp
+  :general (ehelp-map
+            "k" #'helpful-key
+            "v" #'helpful-variable
+            "f" #'helpful-callable))
+
+;;; Files
+
+;;;; Auto-saving
+
+;; Auto-save everything to a temporary directory, instead of cluttering
+;; the filesystem.  I don’t want emacs-specific lockfiles, either.
+
+(setq auto-save-file-name-transforms `((".*" ,temporary-file-directory t))
+      create-lockfiles nil)
+
+;;;; Auto-reloading
+
+(use-package autorevert
+  :custom ((global-auto-revert-mode t)
+           (auto-revert-verbose t)))
+
+;;;; Backups
+
+;; I like to keep my backups out of regular folders.  I tell emacs to use
+;; a subfolder of its configuration directory for that.  Also, use the
+;; trash for deleting on OS X.
+(let ((backup-dir (expand-file-name "~/.emacs.d/backups/")))
+  (unless (file-directory-p backup-dir)
+    (make-directory backup-dir))
+  (setq backup-directory-alist `((".*" . ,backup-dir))
+        backup-by-copying-when-linked t
+        backup-by-copying-when-mismatch t))
+
+(setq delete-by-moving-to-trash t)
+
+(use-package goto-chg
+  :defer 1)
+
+;;; Directories
+
+(custom-set-variables
+ '(dired-dwim-target t)
+ '(dired-recursive-copies 'top)
+ '(dired-listing-switches "-alh")
+ '(dired-recursive-deleted (if delete-by-moving-to-trash
+                              'always
+                            'top)))
+
+;;; Shells
+
+(use-package eshell
+  :defer 5
+  :commands (eshell)
+  :functions (eshell/pwd)
+  :init (progn
+          (with-eval-after-load 'evil-ex
+            (evil-ex-define-cmd "esh[ell]" #'eshell)))
+  :custom ((eshell-prompt-function (lambda ()
+                                     (concat (eshell/pwd) "\n$ ")))
+           (eshell-prompt-regexp "^[$][[:blank:]]")
+           (eshell-cmpl-cycle-completions nil)))
+
+(use-package eshell-toggle
+  :after projectile
+  :commands (eshell-toggle)
+  :custom ((eshell-toggle-use-projectile-root t)))
+
+(use-package esh-autosuggest
+  :after eshell
+  :ghook ('eshell-mode-hook))
+
+(declare-function eshell-push-command "esh-buf-stack" (CMD))
+(defun my-bind-esh-push ()
+  (general-define-key
+   :states '(normal insert)
+   :keymaps 'local
+   "M-q" #'eshell-push-command))
+
+(use-package esh-buf-stack
+  :after (eshell)
+  :ghook ('eshell-mode-hook #'my-bind-esh-push)
+  :config (setup-eshell-buf-stack))
+
+(use-package bash-completion
+  :after (eshell))
+
+(use-package fish-completion
+  :when (executable-find "fish")
+  :after (bash-completion)
+  :custom ((fish-completion-fallback-on-bash-p t))
+  :commands (global-fish-completion-mode)
+  :config (global-fish-completion-mode))
+
+(use-package esh-help
+  :after (eshell)
+  :config (setup-esh-help-eldoc))
+
+(use-package eshell-fringe-status
+  :after eshell
+  :ghook '(eshell-mode-hook))
+
+(use-package eshell-up
+  :after (eshell))
+
+(use-package shell
+  :defer t
+  :general (:keymaps 'shell-mode-map
+                     "C-d" #'comint-delchar-or-maybe-eof))
+
+(use-package comint
+  :defer t
+  :general (:keymaps 'comint-mode-map
+                     "C-c C-l" #'counsel-shell-history))
+
+;;; Editing
+
+(setq-default indent-tabs-mode nil
+              tab-always-indent 'complete)
+
+(use-package ws-butler
+  :ghook ('prog-mode-hook))
+
+;;; Major modes
+
+;;;; js
+(custom-set-variables '(js-indent-level 2)
+                      '(js-enabled-frameworks '(javascript)))
+
+;;;; typescript
+(custom-set-variables '(typescript-indent-level 2))
+(autoload 'ansi-color-apply-on-region "ansi-color")
+(defun colorise-compilation-buffer ()
+  (ansi-color-apply-on-region compilation-filter-start (point-max)))
+(add-hook 'compilation-filter-hook #'colorise-compilation-buffer)
+
+;;;; shell
+(general-add-hook 'sh-mode-hook
+                  (lambda ()
+                    (general-add-hook 'after-save-hook
+                                      #'executable-make-buffer-file-executable-if-script-p :append :local)))
+
+(add-to-list 'auto-mode-alist '("\\.env\\'" . conf-unix-mode))
+(use-package sh-script
+  :mode (("\\.zsh\\'" . shell-script-mode)
+         ("zshenv\\'" . shell-script-mode)
+         ("zshrc\\'"  . shell-script-mode))
+  :config (setq sh-shell-file "/usr/bin/env zsh"
+                sh-basic-offset 2))
+
+(add-hook 'shell-mode-hook 'ansi-color-for-comint-mode-on)
+
+;;;; make
+(general-add-hook 'makefile-mode-hook
+                  (lambda ()
+                    (setq-local indent-tabs-mode t)))
+
+;;;; nix
+(custom-set-variables '(nix-indent-function #'nix-indent-line))
+
+(use-package nix-update
+  :commands (nix-update-fetch))
+
+;;;; gitlab-ci.yml
+(with-eval-after-load 'git-gutter-fringe
+              (fringe-helper-define 'flycheck-fringe-bitmap-double-arrow '(center repeated)
+                "XXX....."))
+
+(custom-set-variables '(gitlab-ci-url "https://gitlab.satoshipay.tech"))
+(use-package gitlab-ci-mode-flycheck
+  :ghook ('gitlab-ci-mode-hook (list #'gitlab-ci-mode-flycheck-enable
+                                     #'flycheck-mode)))
+
+;;;; *ignore
+(use-package gitignore-mode
+  :mode ((".dockerignore\\'" . gitignore-mode)))
+
+;;;; kubernetes
+(custom-set-variables '(k8s-site-docs-version "v1.13"))
+
+;;;; beancount
+
+(use-package beancount
+  :load-path "~/projects/bitbucket.org/blais/beancount/editors/emacs")
+
+;;;; org
+
+(custom-set-variables '(org-ellipsis "…")
+                      `(org-directory "~/Documents/org"))
+
+(use-package org-journal
+  :commands (org-journal-new-date-entry
+	     org-journal-new-entry
+	     org-journal-new-scheduled-entry)
+  :gfhook (#'variable-pitch-mode)
+  :custom ((org-journal-date-format "%A, %d %B %Y")
+           (org-journal-dir "~/Documents/journal")))
+
+;;;; emacs-lisp
+
+(use-package auto-async-byte-compile
+  :custom ((auto-async-byte-compile-exclude-files-regexp "custom\\.el"))
+  :ghook ('emacs-lisp-mode-hook #'enable-auto-async-byte-compile-mode))
+
+;;;; web modes (tsx, html)
+
+(use-package web-mode
+  :mode (("\\.tsx" . web-mode))
+  :custom ((web-mode-enable-auto-pairing nil)
+           (web-mode-code-indent-offset 2)
+           (web-mode-markup-indent-offset 2)
+           (web-mode-css-indent-offset 2)
+           (web-mode-style-padding 0)
+           (web-mode-script-padding 0)))
+
+;;; IDE features
+
+(fringe-helper-define 'left-vertical-bar '(center repeated)
+  "XXX.....")
+(use-package flymake
+  :custom ((flymake-error-bitmap '(left-vertical-bar compilation-error))
+           (flymake-warning-bitmap '(left-vertical-bar compilation-warning))))
+(use-package flymake-diagnostic-at-point
+  :custom ((flymake-diagnostic-at-point-diagnostic-function #'flymake-diagnostic-at-point-display-minibuffer))
+  :ghook '(flymake-mode-hook))
+
+(use-package lsp-mode
+  :ghook ('(typescript-mode-hook
+            dockerfile-mode-hook
+            yaml-mode-hook
+            js-mode-hook
+            css-mode-hook
+            scss-mode-hook
+            html-mode-hook
+            haskell-mode-hook)
+          #'lsp)
+  :functions (lsp--flymake-setup)
+  :gfhook 'lsp--flymake-setup
+  :custom ((lsp-auto-guess-root t)
+           (lsp-auto-configure nil)
+           (lsp-prefer-flymake t)
+           (lsp-enable-symbol-highlighting nil))
+  :config (progn
+            (add-to-list 'lsp-language-id-configuration '(js-mode . "javascript"))))
+
+(use-package lsp-clients
+  :after (lsp-mode))
+
+(use-package lsp-ui
+  :after lsp-mode
+  :ghook ('lsp-mode-hook)
+  :custom ((lsp-ui-sideline-enable nil)
+           (lsp-ui-doc-mode nil)
+           (lsp-enable-snippet nil)))
+
+(use-package lsp-haskell
+  :after lsp-mode)
+
+;; Inside a javascript project, it's common to install tools locally to
+;; the project.  This will allows emacs to find their executables.
+
+(use-package add-node-modules-path
+  :ghook ('(js2-mode-hook typescript-mode-hook) #'add-node-modules-path))
+
+;;;; Reformat on save
+
+(use-package prettier-js
+  :custom ((prettier-js-show-errors 'echo))
+  :ghook ('(typescript-mode-hook) #'prettier-js-mode t)
+  :config (progn
+            (if-let ((prettier_d (executable-find "prettier_d")))
+                (setq prettier-js-command prettier_d
+                      prettier-js-args '("--pkg-conf" "--parser" "typescript"))
+              (message "prettier_d is not available"))))
+
+;;; E-mail
+
+(declare-function sendmail-send-it "sendmail")
+(setq send-mail-function #'sendmail-send-it)
+
+(use-package mu4e
+  :if (executable-find "mu")
+  :commands (mu4e)
+  :init (setq mail-user-agent #'mu4e-user-agent)
+  :custom ((mu4e-completing-read-function #'ivy-completing-read)
+           (mu4e-maildir "~/mail")
+           (mu4e-context-policy 'pick-first)
+           (mu4e-update-interval 600)
+           (mu4e-change-filenames-when-moving t)
+           (mu4e-index-lazy-check t)
+           (mu4e-hide-index-messages t)
+           (mu4e-compose-format-flowed t))
+  :init (progn
+         (with-eval-after-load 'evil-ex
+           (evil-ex-define-cmd "mu[4e]" #'mu4e)))
+  :config (progn
+            (setq mu4e-contexts (list
+                                 (make-mu4e-context
+                                  :name "SatoshiPay"
+                                  :match-func (lambda (msg)
+                                                (if msg
+                                                    (mu4e-message-contact-field-matches
+                                                     msg :to ".*@satoshipay.io")
+                                                  (string-equal (system-name) "satoshipad")))
+                                  :vars '((user-mail-address . "alan@satoshipay.io")
+                                          (mu4e-sent-messages-behavior . delete)
+                                          (mu4e-drafts-folder . "/satoshipay/Drafts")
+                                          (mu4e-sent-folder . "/satoshipay/Sent Mail")
+                                          (mu4e-refile-folder . "/satoshipay/All Mail")
+                                          (mu4e-trash-folder . "/satoshipay/Bin")
+                                          (mu4e-maildir-shortcuts . (("/satoshipay/INBOX" . ?i)
+                                                                     ("/satoshipay/All Mail" . ?a)
+                                                                     ("/satoshipay/Sent Mail" . ?s)
+                                                                     ("/satoshipay/Spam" . ?p)))))))))
+
+;;; Take me to my leader
+
+(my-leader-def
+ "" nil
+ "`" #'eshell-toggle
+ "h" '(:keymap ehelp-map :package ehelp)
+ "w" '(:keymap evil-window-map :package evil)
+ "x" '(:keymap ctl-x-map)
+ "q" #'evil-delete-buffer
+ "p" projectile-command-map
+ "v" #'split-window-right
+ "o" #'other-window
+ "u" #'universal-argument
+ ";" #'counsel-M-x
+ "bb" #'ivy-switch-buffer
+ "bx" #'kill-this-buffer
+ "br" #'revert-buffer
+ "bk" #'kill-buffer
+ "dd" #'dired
+ "fs" #'save-buffer
+ "ff" #'find-file
+ "fw" #'write-file
+ "fd" #'crux-delete-file-and-buffer
+ "fr" #'crux-rename-file-and-buffer
+ "gs" #'magit-status
+ "gm" #'git-messenger:popup-message
+ "gg" #'magit-dispatch
+ "gn" #'git-gutter:next-hunk
+ "gp" #'git-gutter:previous-hunk
+ "gi" #'git-gutter:popup-hunk
+ "gs" #'git-gutter:stage-hunk
+ "go" #'git-gutter:revert-hunk
+ "gt" #'git-timemachine
+ "bi" #'ibuffer
+ "bz" #'bury-buffer
+ "iu" #'counsel-unicode-char)
+
+;; # Local Variables:
+;; # flycheck-disabled-checkers: 'emacs-lisp-checkdoc
+;; # End:
diff --git a/user/emacs/.local/share/applications/emacsclient.desktop b/user/emacs/.local/share/applications/emacsclient.desktop
new file mode 100755
index 00000000..7cf42241
--- /dev/null
+++ b/user/emacs/.local/share/applications/emacsclient.desktop
@@ -0,0 +1,12 @@
+#!/usr/bin/env xdg-open
+[Desktop Entry]
+Name=Emacsclient
+Comment=Edit text
+MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;
+Exec=emacsclient -c %F -a ""
+Icon=emacs
+Type=Application
+Terminal=false
+Categories=Development;TextEditor;
+StartupWMClass=Emacs
+Keywords=Text;Editor;
diff --git a/user/git/.config/git/config b/user/git/.config/git/config
new file mode 100644
index 00000000..63b7e678
--- /dev/null
+++ b/user/git/.config/git/config
@@ -0,0 +1,67 @@
+[user]
+	email = alan@alanpearce.eu
+	name = Alan Pearce
+	signingkey = 0xAE8625A63F6F8FD5
+[color]
+	branch = auto
+	diff = auto
+	status = auto
+	ui = true
+[pull]
+  rebase = true
+[push]
+	default = current
+  followTags = true
+[alias]
+	up = merge FETCH_HEAD
+	st = status -sb
+	ci = commit
+	br = branch
+	co = checkout
+	lasttag = "!sh -c 'git tag --sort=version:refname | grep \"^v\\?[0-9]\" | tail -n1'"
+	pending = "!sh -c 'git log --oneline --grep=\"#\" ...$(git lasttag)'"
+	lg = log --pretty=format:'%Cred%h%Creset -%Creset %s %Cgreen(%cr) %C(bold blue)<%an> %Cred%d%Creset'
+	prl = log --pretty=format:'%Cred%h%Creset -%Creset %s %Cgreen(%cr) %C(bold blue)<%an> %Cred%d%Creset'  --grep="#"
+	ignored = ls-files --others -i --exclude-standard
+	bump = !bmpr
+[github]
+	user = alanpearce
+[ghq "ssh://alanpearce.eu/"]
+  vcs = git
+[includeIf "gitdir:~/projects/github.com/satoshipay/"]
+  path = config-satoshipay
+[includeIf "gitdir:~/projects/gitlab.satoshipay.tech/"]
+  path = config-satoshipay
+[diff]
+	algorithm = patience
+[include]
+	path = config.local
+[rebase]
+	autosquash = true
+[rerere]
+	enabled = true
+[diff]
+  tool = icdiff
+[difftool]
+  prompt = false
+[difftool "icdiff"]
+  cmd = icdiff --line-numbers $LOCAL $REMOTE
+[diff "sopsdiffer"]
+	textconv = sops -d
+[gpg]
+	program = gpg
+
+[merge "npm-merge-driver"]
+	name = automatically merge npm lockfiles
+	driver = npx npm-merge-driver merge %A %O %B %P
+[remote]
+	autoSetupMerge = always
+[branch "master"]
+	rebase = false
+[url "ssh://git@gitlab.satoshipay.tech/"]
+	insteadOf = sp:
+[filter "lfs"]
+	clean = git-lfs clean -- %f
+	smudge = git-lfs smudge -- %f
+	process = git-lfs filter-process
+	required = true
diff --git a/user/git/.config/git/config-satoshipay b/user/git/.config/git/config-satoshipay
new file mode 100644
index 00000000..5fedb7d6
--- /dev/null
+++ b/user/git/.config/git/config-satoshipay
@@ -0,0 +1,2 @@
+[user]
+email = alan@satoshipay.io
\ No newline at end of file
diff --git a/user/git/.config/git/gitk b/user/git/.config/git/gitk
new file mode 100644
index 00000000..0eb9a033
--- /dev/null
+++ b/user/git/.config/git/gitk
@@ -0,0 +1,61 @@
+set mainfont {{Lucida Grande} 12}
+set textfont {Monaco 12}
+set uifont {{Lucida Grande} 12 bold}
+set tabstop 4
+set findmergefiles 0
+set maxgraphpct 50
+set maxwidth 16
+set cmitmode patch
+set wrapcomment none
+set autoselect 1
+set autosellen 40
+set showneartags 1
+set maxrefs 20
+set hideremotes 0
+set showlocalchanges 1
+set datetimeformat {%Y-%m-%d %H:%M:%S}
+set limitdiffs 1
+set uicolor grey85
+set want_ttk 1
+set bgcolor white
+set fgcolor black
+set uifgcolor black
+set uifgdisabledcolor #999
+set colors {green red blue magenta darkgrey brown orange}
+set diffcolors {red "#00a000" blue}
+set mergecolors {red blue green purple brown "#009090" magenta "#808000" "#009000" "#ff0080" cyan "#b07070" "#70b0f0" "#70f0b0" "#f0b070" "#ff70b0"}
+set markbgcolor #e0e0ff
+set diffcontext 3
+set selectbgcolor gray85
+set foundbgcolor yellow
+set currentsearchhitbgcolor orange
+set extdifftool opendiff
+set perfile_attrs 0
+set headbgcolor green
+set headfgcolor black
+set headoutlinecolor black
+set remotebgcolor #ffddaa
+set tagbgcolor yellow
+set tagfgcolor black
+set tagoutlinecolor black
+set reflinecolor black
+set filesepbgcolor #aaaaaa
+set filesepfgcolor black
+set linehoverbgcolor #ffff80
+set linehoverfgcolor black
+set linehoveroutlinecolor black
+set mainheadcirclecolor yellow
+set workingfilescirclecolor red
+set indexcirclecolor green
+set circlecolors {white blue gray blue blue}
+set linkfgcolor blue
+set circleoutlinecolor black
+set geometry(main) 1477x845+26+50
+set geometry(state) normal
+set geometry(topwidth) 1477
+set geometry(topheight) 300
+set geometry(pwsash0) "378 1"
+set geometry(pwsash1) "569 1"
+set geometry(botwidth) 473
+set geometry(botheight) 675
+set permviews {}
diff --git a/user/git/.config/git/ignore b/user/git/.config/git/ignore
new file mode 100644
index 00000000..f51b56ed
--- /dev/null
+++ b/user/git/.config/git/ignore
@@ -0,0 +1,34 @@
+.git
+
+.DS_Store
+.AppleDouble
+.LSOverride
+Icon
+Desktop.ini
+
+# Thumbnails
+._*
+Thumbs.db
+
+# Emacs
+*~
+\#*\#
+/.emacs.desktop
+/.emacs.desktop.lock
+.elc
+auto-save-list
+tramp
+.\#*
+
+# zsh
+*.zwc
+
+# Org-mode
+.org-id-locations
+*_archive
+
+GPATH
+GRTAGS
+GTAGS
+
+.tern-port
diff --git a/user/gnupg/.gnupg/dirmngr.conf b/user/gnupg/.gnupg/dirmngr.conf
new file mode 100644
index 00000000..f69421d7
--- /dev/null
+++ b/user/gnupg/.gnupg/dirmngr.conf
@@ -0,0 +1,3 @@
+keyserver hkps://keys.openpgp.org
+# keyserver hkp://zkaan2xfbuxia2wpf7ofnkbz6r5zdbbvxbunvp5g2iebopbfc4iqmbad.onion
+# use-tor
diff --git a/user/gnupg/.gnupg/gpa.conf b/user/gnupg/.gnupg/gpa.conf
new file mode 100644
index 00000000..2e33e80b
--- /dev/null
+++ b/user/gnupg/.gnupg/gpa.conf
@@ -0,0 +1,2 @@
+default-key 5FA779613E2AB0EEFC6DD3056A56F2A314E23293
+detailed-view
diff --git a/user/gnupg/.gnupg/gpg-agent.conf b/user/gnupg/.gnupg/gpg-agent.conf
new file mode 100644
index 00000000..52eb1dca
--- /dev/null
+++ b/user/gnupg/.gnupg/gpg-agent.conf
@@ -0,0 +1,3 @@
+enable-ssh-support
+default-cache-ttl 600
+max-cache-ttl 7200
diff --git a/user/gnupg/.gnupg/gpg.conf b/user/gnupg/.gnupg/gpg.conf
new file mode 100644
index 00000000..61df93cf
--- /dev/null
+++ b/user/gnupg/.gnupg/gpg.conf
@@ -0,0 +1,83 @@
+#
+# This is an implementation of the Riseup OpenPGP Best Practices
+# https://help.riseup.net/en/security/message-security/openpgp/best-practices
+#
+
+#-----------------------------
+# default key
+#-----------------------------
+
+# The default key to sign with. If this option is not used, the default key is
+# the first key found in the secret keyring
+
+# default-key 
+
+#-----------------------------
+# behavior
+#-----------------------------
+
+# Disable inclusion of the version string in ASCII armored output
+no-emit-version
+
+# Disable comment string in clear text signatures and ASCII armored messages
+no-comments
+
+# Display long key IDs
+keyid-format 0xlong
+
+# List all keys (or the specified ones) along with their fingerprints
+with-fingerprint
+
+# Display the calculated validity of user IDs during key listings
+list-options show-uid-validity
+verify-options show-uid-validity
+
+# Try to use the GnuPG-Agent. With this option, GnuPG first tries to connect to
+# the agent before it asks for a passphrase.
+use-agent
+
+#-----------------------------
+# keyserver
+#-----------------------------
+
+# This is the server that --recv-keys, --send-keys, and --search-keys will
+# communicate with to receive keys from, send keys to, and search for keys on
+keyserver hkps://keys.openpgp.org
+
+# Provide a certificate store to override the system default
+# Get this from https://sks-keyservers.net/sks-keyservers.netCA.pem
+# keyserver-options ca-cert-file=.gnupg/sks-keyservers.netCA.pem
+
+# Set the proxy to use for HTTP and HKP keyservers - default to the standard
+# local Tor socks proxy
+# It is encouraged to use Tor for improved anonymity. Preferrably use either a
+# dedicated SOCKSPort for GnuPG and/or enable IsolateDestPort and
+# IsolateDestAddr
+# keyserver-options http-proxy=socks5-hostname://127.0.0.1:9050
+
+# When using --refresh-keys, if the key in question has a preferred keyserver
+# URL, then disable use of that preferred keyserver to refresh the key from
+keyserver-options no-honor-keyserver-url
+# When searching for a key with --search-keys, include keys that are marked on
+# the keyserver as revoked
+keyserver-options include-revoked
+
+
+#-----------------------------
+# algorithm and ciphers
+#-----------------------------
+
+# list of personal digest preferences. When multiple digests are supported by
+# all recipients, choose the strongest one
+personal-cipher-preferences AES256 AES192 AES CAST5
+
+# list of personal digest preferences. When multiple ciphers are supported by
+# all recipients, choose the strongest one
+personal-digest-preferences SHA512 SHA384 SHA256 SHA224
+
+# message digest algorithm used when signing a key
+cert-digest-algo SHA512
+
+# This preference list is used for new keys and becomes the default for
+# "setpref" in the edit menu
+default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 ZLIB BZIP2 ZIP Uncompressed
\ No newline at end of file
diff --git a/user/gnupg/.gnupg/trezor/dirmngr.conf b/user/gnupg/.gnupg/trezor/dirmngr.conf
new file mode 100644
index 00000000..17612d46
--- /dev/null
+++ b/user/gnupg/.gnupg/trezor/dirmngr.conf
@@ -0,0 +1 @@
+keyserver hkps://keys.openpgp.org
\ No newline at end of file
diff --git a/user/gnupg/.gnupg/trezor/gpg.conf b/user/gnupg/.gnupg/trezor/gpg.conf
new file mode 100644
index 00000000..fd2cdb0f
--- /dev/null
+++ b/user/gnupg/.gnupg/trezor/gpg.conf
@@ -0,0 +1,4 @@
+# Hardware-based GPG configuration
+agent-program /Users/alan/.gnupg/trezor/run-agent.sh
+personal-digest-preferences SHA512
+default-key "Alan Pearce <alan@alanpearce.eu>"
diff --git a/user/i3/.config/i3/config b/user/i3/.config/i3/config
new file mode 100644
index 00000000..ff55cc42
--- /dev/null
+++ b/user/i3/.config/i3/config
@@ -0,0 +1,265 @@
+# This file has been auto-generated by i3-config-wizard(1).
+# It will not be overwritten, so edit it as you like.
+#
+# Should you change your keyboard layout some time, delete
+# this file and re-run i3-config-wizard(1).
+#
+
+# i3 config file (v4)
+#
+# Please see http://i3wm.org/docs/userguide.html for a complete reference!
+
+set $mod Mod4
+
+# Base16 colours: https://github.com/khamer/base16-i3
+
+set $base00 #1d1f21
+set $base01 #282a2e
+set $base02 #373b41
+set $base03 #969896
+set $base04 #b4b7b4
+set $base05 #c5c8c6
+set $base06 #e0e0e0
+set $base07 #ffffff
+set $base08 #cc6666
+set $base09 #de935f
+set $base0A #f0c674
+set $base0B #b5bd68
+set $base0C #8abeb7
+set $base0D #81a2be
+set $base0E #b294bb
+set $base0F #a3685a
+
+# set_from_resource $base00 i3wm.color00 #f8f8f8
+# set_from_resource $base01 i3wm.color01 #e8e8e8
+# set_from_resource $base02 i3wm.color02 #d8d8d8
+# set_from_resource $base03 i3wm.color03 #b8b8b8
+# set_from_resource $base04 i3wm.color04 #585858
+# set_from_resource $base05 i3wm.color05 #383838
+# set_from_resource $base06 i3wm.color06 #282828
+# set_from_resource $base07 i3wm.color07 #181818
+# set_from_resource $base08 i3wm.color08 #ab4642
+# set_from_resource $base09 i3wm.color09 #dc9656
+# set_from_resource $base0A i3wm.color0A #f79a0e
+# set_from_resource $base0B i3wm.color0B #538947
+# set_from_resource $base0C i3wm.color0C #4b8093
+# set_from_resource $base0D i3wm.color0D #7cafc2
+# set_from_resource $base0E i3wm.color0E #96609e
+# set_from_resource $base0F i3wm.color0F #a16946
+
+set $Locker xautolock -locknow
+
+# Font for window titles. Will also be used by the bar unless a different font
+# is used in the bar {} block below.
+# font pango:Monospace, Font Awesome 7
+
+# This font is widely installed, provides lots of unicode glyphs, right-to-left
+# text rendering and scalability on retina/hidpi displays (thanks to pango).
+# font pango:Liberation Mono, Font Awesome 8
+
+# Before i3 v4.8, we used to recommend this one as the default:
+# font -misc-fixed-medium-r-normal--13-120-75-75-C-70-iso10646-1
+# The font above is very space-efficient, that is, it looks good, sharp and
+# clear in small sizes. However, its unicode glyph coverage is limited, the old
+# X core fonts rendering does not support right-to-left and this being a bitmap
+# font, it doesn’t scale on retina/hidpi displays.
+
+font -xos4-terminus-medium-r-normal-*-12-*-*-*-*-*-*-*
+
+# Use Mouse+$mod to drag floating windows to their wanted position
+floating_modifier $mod
+
+mouse_warping none
+
+workspace 1 output primary
+workspace 2 output primary
+workspace 3 output primary
+workspace 4 output primary
+workspace 5 output primary
+workspace 6 output secondary
+workspace 7 output secondary
+workspace 8 output secondary
+workspace 9 output secondary
+workspace 10 output secondary
+
+# start a terminal
+bindsym $mod+Return exec --no-startup-id xst
+
+# kill focused window
+bindsym $mod+w kill
+bindsym $mod+Shift+w kill
+
+bindsym --release $mod+Mod1+r exec rofi -show run
+bindsym --release $mod+Shift+semicolon exec rofi-pass
+bindsym --release $mod+space exec "rofi -show combi -combi-modi drun,window"
+
+# change focus
+bindsym $mod+h focus left
+bindsym $mod+j focus down
+bindsym $mod+k focus up
+bindsym $mod+l focus right
+
+# alternatively, you can use the cursor keys:
+bindsym $mod+Left focus left
+bindsym $mod+Down focus down
+bindsym $mod+Up focus up
+bindsym $mod+Right focus right
+
+# move focused window
+bindsym $mod+Shift+h move left
+bindsym $mod+Shift+j move down
+bindsym $mod+Shift+k move up
+bindsym $mod+Shift+l move right
+
+# move workspace
+bindsym $mod+Mod1+h move workspace to output left
+bindsym $mod+Mod1+j move workspace to output down
+bindsym $mod+Mod1+k move workspace to output up
+bindsym $mod+Mod1+l move workspace to output right
+
+# alternatively, you can use the cursor keys:
+bindsym $mod+Shift+Left move left
+bindsym $mod+Shift+Down move down
+bindsym $mod+Shift+Up move up
+bindsym $mod+Shift+Right move right
+
+# split in horizontal orientation
+bindsym $mod+b split h
+
+# split in vertical orientation
+bindsym $mod+v split v
+
+# enter fullscreen mode for the focused container
+bindsym $mod+F11 fullscreen toggle
+
+# change container layout (stacked, tabbed, toggle split)
+bindsym $mod+Shift+s layout stacking
+bindsym $mod+Shift+t layout tabbed
+bindsym $mod+Shift+v layout toggle split
+
+# toggle tiling / floating
+bindsym $mod+Shift+f floating toggle
+
+# change focus between tiling / floating windows
+bindsym $mod+t focus mode_toggle
+
+# focus the parent container
+bindsym $mod+a focus parent
+
+# focus the child container
+bindsym $mod+d focus child
+
+# switch to workspace
+bindsym $mod+1 workspace 1
+bindsym $mod+2 workspace 2
+bindsym $mod+3 workspace 3
+bindsym $mod+4 workspace 4
+bindsym $mod+5 workspace 5
+bindsym $mod+6 workspace 6
+bindsym $mod+7 workspace 7
+bindsym $mod+8 workspace 8
+bindsym $mod+9 workspace 9
+bindsym $mod+0 workspace 10
+
+# move focused container to workspace
+bindsym $mod+Shift+1 move container to workspace 1
+bindsym $mod+Shift+2 move container to workspace 2
+bindsym $mod+Shift+3 move container to workspace 3
+bindsym $mod+Shift+4 move container to workspace 4
+bindsym $mod+Shift+5 move container to workspace 5
+bindsym $mod+Shift+6 move container to workspace 6
+bindsym $mod+Shift+7 move container to workspace 7
+bindsym $mod+Shift+8 move container to workspace 8
+bindsym $mod+Shift+9 move container to workspace 9
+bindsym $mod+Shift+0 move container to workspace 10
+
+bindsym $mod+Shift+o exec --no-startup-id "$Locker"
+# reload the configuration file
+bindsym $mod+Shift+c reload
+# restart i3 inplace (preserves your layout/session, can be used to upgrade i3)
+bindsym $mod+Shift+p restart
+
+# resize window (you can also use the mouse for that)
+mode "resize" {
+        # These bindings trigger as soon as you enter the resize mode
+
+        # Pressing left will shrink the window’s width.
+        # Pressing right will grow the window’s width.
+        # Pressing up will shrink the window’s height.
+        # Pressing down will grow the window’s height.
+        bindsym h resize shrink width 10 px or 10 ppt
+        bindsym j resize grow height 10 px or 10 ppt
+        bindsym k resize shrink height 10 px or 10 ppt
+        bindsym l resize grow width 10 px or 10 ppt
+
+        # same bindings, but for the arrow keys
+        bindsym Left resize shrink width 10 px or 10 ppt
+        bindsym Down resize grow height 10 px or 10 ppt
+        bindsym Up resize shrink height 10 px or 10 ppt
+        bindsym Right resize grow width 10 px or 10 ppt
+
+        # back to normal: Enter or Escape
+        bindsym Return mode "default"
+        bindsym Escape mode "default"
+}
+
+bindsym $mod+Shift+r mode "resize"
+
+set $mode_system System (l) lock, (e) logout, (s) suspend, (h) hibernate, (r) reboot, (Shift+s) shutdown
+mode "$mode_system" {
+    bindsym l exec --no-startup-id $Locker, mode "default"
+    bindsym e exec --no-startup-id i3-msg exit, mode "default"
+    bindsym s exec --no-startup-id systemctl suspend, mode "default"
+    bindsym h exec --no-startup-id systemctl hibernate, mode "default"
+    bindsym r exec --no-startup-id systemctl reboot, mode "default"
+    bindsym Shift+s exec --no-startup-id systemctl poweroff -i, mode "default"
+
+    # back to normal: Enter or Escape
+    bindsym Return mode "default"
+    bindsym Escape mode "default"
+}
+
+bindsym $mod+Pause mode "$mode_system"
+bindsym $mod+Escape mode "$mode_system"
+bindsym $mod+Shift+q mode "$mode_system"
+
+# Start i3bar to display a workspace bar (plus the system information i3status
+# finds out, if available)
+bar {
+  position top
+  status_command /run/current-system/sw/bin/i3status -c ~/.config/i3status/config
+  colors {
+    background $base00
+    separator  $base01
+    statusline $base04
+
+    # State             Border  BG      Text
+    focused_workspace   $base0D $base02 $base07
+    active_workspace    $base02 $base03 $base00
+    inactive_workspace  $base02 $base01 $base04
+    urgent_workspace    $base08 $base02 $base00
+    binding_mode        $base00 $base0A $base00
+  }
+}
+
+# Basic color configuration using the Base16 variables for windows and borders.
+# Property Name         Border  BG      Text    Indicator Child Border
+client.focused          $base05 $base0D $base00 $base0D $base0D
+client.focused_inactive $base01 $base01 $base05 $base03 $base01
+client.unfocused        $base01 $base00 $base05 $base01 $base01
+client.urgent           $base08 $base08 $base00 $base08 $base08
+client.placeholder      $base00 $base00 $base05 $base00 $base00
+client.background       $base07
+
+new_window pixel 2
+new_float normal
+
+for_window [class="Pinentry$"] floating enable
+
+assign [class="^Slack$"] 1
+assign [window_role="^browser$"] 2
+assign [class="^Emacs$"] 6
+
+exec slack
+exec firefox-devedition
+exec emacs
\ No newline at end of file
diff --git a/user/i3/.config/i3status/config b/user/i3/.config/i3status/config
new file mode 100644
index 00000000..f27c24a4
--- /dev/null
+++ b/user/i3/.config/i3status/config
@@ -0,0 +1,112 @@
+# i3status configuration file.
+# see "man i3status" for documentation.
+
+# It is important that this file is edited as UTF-8.
+# The following line should contain a sharp s:
+# ß
+# If the above line is not correctly displayed, fix your editor first!
+
+general {
+  colors = true
+  interval = 10
+
+  color_good = "#b5bd68"
+  color_degraded = "#de935f"
+  color_bad = "#a3685a"
+}
+
+order += "disk /"
+order += "disk /home"
+order += "ipv6"
+order += "ethernet _first_"
+order += "wireless _first_"
+order += "battery all"
+order += "battery 0"
+order += "battery 1"
+order += "load"
+order += "cpu_temperature 0"
+order += "volume master"
+order += "tztime local"
+
+ipv6 {
+  format_up = "6"
+  format_down = "4"
+  separator = false
+  separator_block_width = 0
+}
+
+ethernet _first_ {
+  format_up = "E"
+  format_down = "E"
+  separator = false
+  separator_block_width = 0
+}
+
+wireless _first_ {
+  format_up = "W: %quality (%essid) "
+  format_down = "W"
+}
+
+battery 0 {
+  integer_battery_capacity = true
+
+  status_chr = "C"
+  status_bat = "D"
+  status_unk = "U"
+  status_full = "F"
+
+  separator = false 
+  
+  format = "%status %percentage"
+}
+
+battery 1 {
+  integer_battery_capacity = true
+
+  status_chr = "C"
+  status_bat = "D"
+  status_unk = "U"
+  status_full = "F"
+
+  format = "%status %percentage"
+}
+
+battery all {
+  integer_battery_capacity = false
+  hide_seconds = true
+
+  separator = false
+
+  format = "%status %remaining (%emptytime %consumption)"
+}
+
+volume master {
+  device = "pulse"
+  format = "♪: %volume"
+  format_muted = "♪: 0%%"
+}
+
+tztime local {
+  format = "%Y-%m-%d %H:%M"
+}
+
+load {
+  format = "%1min %5min"
+}
+
+cpu_temperature 0 {
+  format = "T: %degrees ºC"
+}
+
+disk "/" {
+  prefix_type = "custom"
+  low_threshold = 5
+  format = "/ %avail"
+  separator = false
+}
+
+disk "/home" {
+  prefix_type = "custom"
+  low_threshold = 5
+  format = "/h %avail"
+}
diff --git a/user/install.sh b/user/install.sh
new file mode 100755
index 00000000..8e0ca702
--- /dev/null
+++ b/user/install.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+
+set -eu
+
+if [ -z "$1" ]
+then
+  echo "Usage: $0 <machine-file.nix>"
+  exit 1
+fi
+
+NIXDIR="$HOME/.config/nixpkgs"
+
+if [ ! -f "$1" ]
+then
+  echo "$1 does not exist"
+  exit 1
+fi
+
+ln -s $PWD $NIXDIR
+ln -s $1 home.nix
diff --git a/user/isync/.mbsyncrc b/user/isync/.mbsyncrc
new file mode 100644
index 00000000..396bc6a6
--- /dev/null
+++ b/user/isync/.mbsyncrc
@@ -0,0 +1,37 @@
+# Globals
+Create Both
+Remove Both
+Expunge Both
+CopyArrivalDate yes
+FSync no
+
+## Satoshipay
+# Account
+IMAPAccount satoshipay.io
+Host imap.gmail.com
+User alan@satoshipay.io
+PassCmd "keyring get satoshipay-google-mail alan@satoshipay.io"
+SSLType IMAPS
+SSLVersions TLSv1.2 TLSv1.1
+
+# Remote
+IMAPStore satoshipay.io-remote
+Account satoshipay.io
+
+# Local
+MaildirStore satoshipay.io-local
+Path ~/mail/satoshipay/
+Inbox ~/mail/satoshipay/INBOX
+SubFolders Verbatim
+
+# Job
+Channel satoshipay
+Master :satoshipay.io-remote:
+Slave :satoshipay.io-local:
+Patterns INBOX
+SyncState *
+
+Channel satoshipay-gmail
+Master :satoshipay.io-remote:[Gmail]/
+Slave :satoshipay.io-local:
+Patterns * !INBOX
\ No newline at end of file
diff --git a/user/javascript/.npmrc b/user/javascript/.npmrc
new file mode 100644
index 00000000..59c9a2b4
--- /dev/null
+++ b/user/javascript/.npmrc
@@ -0,0 +1,8 @@
+prefix=${HOME}/.local
+//registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN}
+@satoshipay:registry=https://registry.npmjs.org/
+always-auth=true
+sign-git-tag=true
+rebuild-bundle=false
+update-notifier=false
+registry=https://registry.npmjs.org/
\ No newline at end of file
diff --git a/user/ledger/.ledgerrc b/user/ledger/.ledgerrc
new file mode 100644
index 00000000..319a2029
--- /dev/null
+++ b/user/ledger/.ledgerrc
@@ -0,0 +1,2 @@
+--date-format %F
+--start-of-week 1
diff --git a/user/mlterm/.mlterm/aafont b/user/mlterm/.mlterm/aafont
new file mode 100644
index 00000000..11358ef6
--- /dev/null
+++ b/user/mlterm/.mlterm/aafont
@@ -0,0 +1,2 @@
+DEFAULT = Liberation Mono 9
+ISO10646_UCS4_1 = Liberation Mono 9
diff --git a/user/mlterm/.mlterm/color b/user/mlterm/.mlterm/color
new file mode 100644
index 00000000..41b74f25
--- /dev/null
+++ b/user/mlterm/.mlterm/color
@@ -0,0 +1,23 @@
+black=#000000
+red=#f8282a
+green=#328a5d
+yellow=#fa701d
+blue=#135cd0
+magenta=#9f00bd
+cyan=#33c3c1
+white=#b3b3b3
+hl_black=#555753
+hl_red=#fb0416
+hl_green=#2cc631
+hl_yellow=#fdd727
+hl_blue=#1670ff
+hl_magenta=#e900b0
+hl_cyan=#3ad5ce
+hl_white=#eeeeec
+fg_color=#262626
+bg_color=#ffffff
+cursor_bg_color=#6fd3fc
+cursor_fg_color=#ffffff
+bd_color=#1a1a1a
+it_color=#041730
+ul_color=#6fd3fc
\ No newline at end of file
diff --git a/user/mlterm/.mlterm/font b/user/mlterm/.mlterm/font
new file mode 100644
index 00000000..daa06de5
--- /dev/null
+++ b/user/mlterm/.mlterm/font
@@ -0,0 +1,2 @@
+DEFAULT = Liberation Mono 12
+UNICODE = Liberation Mono 12
diff --git a/user/mlterm/.mlterm/main b/user/mlterm/.mlterm/main
new file mode 100644
index 00000000..f9ce0929
--- /dev/null
+++ b/user/mlterm/.mlterm/main
@@ -0,0 +1,21 @@
+use_ctl = false
+use_multi_column_char = false
+use_combining = false
+use_bold_font = true
+encoding = UTF-8
+fontsize = 10
+type_engine = xft
+scrollbar_mode = none
+input_method = kbd
+logging_msg = false
+logsize = 10000
+bg_color = #f8f8f8
+fg_color = #181818
+cursor_fg_color = #585858
+cursor_bg_color = #585858
+use_extended_scroll_shortcut = true
+regard_uri_as_word = true
+mod_meta_key = alt
+mod_meta_mode = esc
+use_anti_alias = true
+use_point_size = true
diff --git a/user/modules/autorandr.nix b/user/modules/autorandr.nix
new file mode 100644
index 00000000..f63095a4
--- /dev/null
+++ b/user/modules/autorandr.nix
@@ -0,0 +1,8 @@
+{ config, pkgs, ... }:
+
+{
+  xdg.configFile.autorandr = {
+    recursive = true;
+    source = ../autorandr/.config/autorandr;
+  };
+}
diff --git a/user/modules/base.nix b/user/modules/base.nix
new file mode 100644
index 00000000..62bc9f24
--- /dev/null
+++ b/user/modules/base.nix
@@ -0,0 +1,6 @@
+{ config, pkgs, ... }:
+
+{
+  # Let Home Manager install and manage itself.
+  programs.home-manager.enable = true;
+}
diff --git a/user/modules/dunst.nix b/user/modules/dunst.nix
new file mode 100644
index 00000000..78268c04
--- /dev/null
+++ b/user/modules/dunst.nix
@@ -0,0 +1,8 @@
+{ config, pkgs, ... }:
+
+{
+  xdg.configFile.dunst = {
+    recursive = true;
+    source = ../dunst/.config/dunst;
+  };
+}
diff --git a/user/modules/emacs.nix b/user/modules/emacs.nix
new file mode 100644
index 00000000..82a22b52
--- /dev/null
+++ b/user/modules/emacs.nix
@@ -0,0 +1,9 @@
+{ config, pkgs, ... }:
+
+{
+  home.file.".emacs.d" = {
+    recursive = true;
+    source = ../emacs/.emacs.d;
+  };
+  home.file.".local/share/applications/emacsclient.desktop".source = ../emacs/.local/share/applications/emacsclient.desktop;
+}
diff --git a/user/modules/git.nix b/user/modules/git.nix
new file mode 100644
index 00000000..a43ccadf
--- /dev/null
+++ b/user/modules/git.nix
@@ -0,0 +1,8 @@
+{ config, pkgs, ... }:
+
+{
+  xdg.configFile.git = {
+    recursive = true;
+    source = ../git/.config/git;
+  };
+}
diff --git a/user/modules/gnupg.nix b/user/modules/gnupg.nix
new file mode 100644
index 00000000..6dcb31f2
--- /dev/null
+++ b/user/modules/gnupg.nix
@@ -0,0 +1,8 @@
+{ config, pkgs, ... }:
+
+{
+  home.file.".gnupg" = {
+    recursive = true;
+    source = ../gnupg/.gnupg;
+  };
+}
diff --git a/user/modules/i3.nix b/user/modules/i3.nix
new file mode 100644
index 00000000..a6acf92f
--- /dev/null
+++ b/user/modules/i3.nix
@@ -0,0 +1,12 @@
+{ config, pkgs, ... }:
+
+{
+  xdg.configFile.i3 = {
+    recursive = true;
+    source = ../i3/.config/i3;
+  };
+  xdg.configFile.i3status = {
+    recursive = true;
+    source = ../i3/.config/i3status;
+  };
+}
diff --git a/user/modules/isync.nix b/user/modules/isync.nix
new file mode 100644
index 00000000..b96db87d
--- /dev/null
+++ b/user/modules/isync.nix
@@ -0,0 +1,5 @@
+{ config, pkgs, ... }:
+
+{
+  home.file.".mbsyncrc".source = ../isync/.mbsyncrc;
+}
diff --git a/user/modules/ledger.nix b/user/modules/ledger.nix
new file mode 100644
index 00000000..05102153
--- /dev/null
+++ b/user/modules/ledger.nix
@@ -0,0 +1,5 @@
+{ config, pkgs, ... }:
+
+{
+  home.file.".ledgerrc".source = ../ledger/.ledgerrc;
+}
diff --git a/user/modules/msmtp.nix b/user/modules/msmtp.nix
new file mode 100644
index 00000000..45c2f460
--- /dev/null
+++ b/user/modules/msmtp.nix
@@ -0,0 +1,5 @@
+{ config, pkgs, ... }:
+
+{
+  home.file.".msmtprc".source = ../msmtp/.msmtprc;
+}
diff --git a/user/modules/nix.nix b/user/modules/nix.nix
new file mode 100644
index 00000000..4097598b
--- /dev/null
+++ b/user/modules/nix.nix
@@ -0,0 +1,6 @@
+{ config, pkgs, ... }:
+
+{
+  nixpkgs.config = import ../nix/.config/nixpkgs/config.nix;
+  xdg.configFile."nixpkgs.config.nix".source = ../nix/.config/nixpkgs/config.nix;
+}
diff --git a/user/modules/npm.nix b/user/modules/npm.nix
new file mode 100644
index 00000000..d2ba55d9
--- /dev/null
+++ b/user/modules/npm.nix
@@ -0,0 +1,5 @@
+{ config, pkgs, ... }:
+
+{
+  home.file.".npmrc".source = ../javascript/.npmrc;
+}
diff --git a/user/modules/rofi.nix b/user/modules/rofi.nix
new file mode 100644
index 00000000..e0cec29e
--- /dev/null
+++ b/user/modules/rofi.nix
@@ -0,0 +1,12 @@
+{ config, pkgs, ... }:
+
+{
+  xdg.configFile.rofi = {
+    recursive = true;
+    source = ../rofi/.config/rofi;
+  };
+  xdg.configFile.rofi-pass = {
+    recursive = true;
+    source = ../rofi/.config/rofi-pass;
+  };
+}
diff --git a/user/modules/sxhkd.nix b/user/modules/sxhkd.nix
new file mode 100644
index 00000000..47a5b5fc
--- /dev/null
+++ b/user/modules/sxhkd.nix
@@ -0,0 +1,8 @@
+{ config, pkgs, ... }:
+
+{
+  xdg.configFile.sxhkd = {
+    recursive = true;
+    source = ../sxhkd/.config/sxhkd;
+  };
+}
diff --git a/user/modules/tabnine.nix b/user/modules/tabnine.nix
new file mode 100644
index 00000000..f07850ed
--- /dev/null
+++ b/user/modules/tabnine.nix
@@ -0,0 +1,8 @@
+{ config, pkgs, ... }:
+
+{
+  xdg.configFile.TabNine = {
+    recursive = true;
+    source = ../tabnine/.config/TabNine;
+  };
+}
diff --git a/user/modules/trezor.nix b/user/modules/trezor.nix
new file mode 100644
index 00000000..a4f3ba75
--- /dev/null
+++ b/user/modules/trezor.nix
@@ -0,0 +1,9 @@
+{ config, pkgs, ... }:
+
+{
+  home.file.".ssh/agent.config" = {
+    text = ''
+      ecdsa-curve-name = ed25519
+    '';
+  };
+}
diff --git a/user/modules/xresources.nix b/user/modules/xresources.nix
new file mode 100644
index 00000000..475113de
--- /dev/null
+++ b/user/modules/xresources.nix
@@ -0,0 +1,8 @@
+{ config, pkgs, ... }:
+
+{
+  home.file.".xresources" = {
+    recursive = true;
+    source = ../xresources/.xresources;
+  };
+}
diff --git a/user/modules/zsh.nix b/user/modules/zsh.nix
new file mode 100644
index 00000000..28e82293
--- /dev/null
+++ b/user/modules/zsh.nix
@@ -0,0 +1,12 @@
+{ config, pkgs, ... }:
+
+{
+  home.file = {
+    ".rm_recycle_home".text = ""; # use trash automatically in home directory
+    ".zshenv".text = builtins.readFile ../zsh/.zshenv;
+  };
+  xdg.configFile.zsh = {
+    recursive = true;
+    source = ../zsh/.config/zsh;
+  };
+}
diff --git a/user/msmtp/.msmtprc b/user/msmtp/.msmtprc
new file mode 100644
index 00000000..da5c5daf
--- /dev/null
+++ b/user/msmtp/.msmtprc
@@ -0,0 +1,17 @@
+# Set default values for all following accounts.
+defaults
+auth           on
+tls            on
+tls_trust_file /etc/ssl/certs/ca-certificates.crt
+logfile        ~/.local/log/msmtp.log
+
+account        satoshipay
+host           smtp.gmail.com
+from           alan@satoshipay.io
+user           alan@satoshipay.io
+port           465
+tls_starttls   off
+passwordeval   keyring get satoshipay-google-mail alan@satoshipay.io
+
+# Set a default account
+account default : satoshipay
diff --git a/user/nix/.config/nixpkgs/config.nix b/user/nix/.config/nixpkgs/config.nix
new file mode 100644
index 00000000..2a93c4b9
--- /dev/null
+++ b/user/nix/.config/nixpkgs/config.nix
@@ -0,0 +1,3 @@
+{ pkgs }: {
+  allowUnfree = true;
+}
diff --git a/user/prefect.nix b/user/prefect.nix
new file mode 100644
index 00000000..a1edc55e
--- /dev/null
+++ b/user/prefect.nix
@@ -0,0 +1,18 @@
+{ config, pkgs, ... }:
+
+{
+  imports = [
+    ./modules/base.nix
+    ./modules/dunst.nix
+    ./modules/emacs.nix
+    ./modules/git.nix
+    ./modules/gnupg.nix
+    ./modules/i3.nix
+    ./modules/nix.nix
+    ./modules/rofi.nix
+    ./modules/sxhkd.nix
+    ./modules/tabnine.nix
+    ./modules/xresources.nix
+    ./modules/zsh.nix
+  ];
+}
diff --git a/user/rofi/.config/networkmanager-dmenu/config.ini b/user/rofi/.config/networkmanager-dmenu/config.ini
new file mode 100644
index 00000000..fdc7aa6e
--- /dev/null
+++ b/user/rofi/.config/networkmanager-dmenu/config.ini
@@ -0,0 +1,6 @@
+[dmenu]
+dmenu_command = /run/current-system/sw/bin/rofi
+
+[editor]
+terminal = xst
+gui_if_available = false
\ No newline at end of file
diff --git a/user/rofi/.config/rofi-pass/config b/user/rofi/.config/rofi-pass/config
new file mode 100644
index 00000000..ad997ba8
--- /dev/null
+++ b/user/rofi/.config/rofi-pass/config
@@ -0,0 +1,77 @@
+# -*- mode: sh; -*-
+# permanently set alternative root dir. Use ":" to separate multiple roots
+# which can be switched at runtime with shift+left/right
+# root=/path/to/root
+
+# rofi command. Make sure to have "$@" as last argument
+_rofi () {
+    rofi -i -no-auto-select "$@"
+}
+
+# xdotool needs the keyboard layout to be set using setxkbmap
+# You can do this in your autostart scripts (e.g. xinitrc)
+
+# If for some reason, you cannot do this, you can set the command here.
+# and set fix_layout to true
+fix_layout=false
+
+layout_cmd () {
+  setxkbmap us
+}
+
+# fields to be used
+URL_field='url'
+USERNAME_field='login'
+AUTOTYPE_field='autotype'
+
+# delay to be used for :delay keyword
+delay=2
+
+# rofi-pass needs to close itself before it can type passwords. Set delay here.
+wait=0.2
+
+## Programs to be used
+# Editor
+EDITOR='emacsclient'
+
+# Browser
+# BROWSER='google-chrome-stable'
+
+## Misc settings
+
+default_do='menu' # menu, autotype, copyPass, typeUser, typePass, copyUser, copyUrl, viewEntry, typeMenu, actionMenu, copyMenu, openUrl
+auto_enter='false'
+notify='false'
+default_autotype='login :tab pass'
+
+# color of the help messages
+# leave empty for autodetection
+help_color="#4872FF"
+
+# Clipboard settings
+# Possible options: primary, clipboard, both
+clip=both
+
+# Options for generating new password entries
+# default_user is also used for password files that have no user field.
+#default_user=john_doe
+#default_user2=mary_ann
+#password_length=12
+
+# Custom Keybindings
+autotype="Alt+1"
+type_user="Alt+2"
+type_pass="Alt+3"
+open_url="Alt+4"
+copy_name="Alt+u"
+copy_url="Alt+l"
+copy_pass="Alt+p"
+show="Alt+o"
+copy_entry="Alt+2"
+type_entry="Alt+1"
+copy_menu="Alt+c"
+action_menu="Alt+a"
+type_menu="Alt+t"
+help="Alt+h"
+switch="Alt+x"
+insert_pass="Alt+n"
diff --git a/user/rofi/.config/rofi/config b/user/rofi/.config/rofi/config
new file mode 100644
index 00000000..d742f496
--- /dev/null
+++ b/user/rofi/.config/rofi/config
@@ -0,0 +1,8 @@
+rofi.matching:            glob
+rofi.separator-style:     none
+
+rofi.line-padding:        2
+
+rofi.display-run:         cmd
+rofi.display-drun:        run
+rofi.display-window:      win
\ No newline at end of file
diff --git a/user/satoshipad.nix b/user/satoshipad.nix
new file mode 100644
index 00000000..eab836de
--- /dev/null
+++ b/user/satoshipad.nix
@@ -0,0 +1,23 @@
+{ config, pkgs, ... }:
+
+{
+  imports = [
+    ./modules/autorandr.nix
+    ./modules/base.nix
+    ./modules/dunst.nix
+    ./modules/emacs.nix
+    ./modules/git.nix
+    ./modules/gnupg.nix
+    ./modules/i3.nix
+    ./modules/isync.nix
+    ./modules/msmtp.nix
+    ./modules/nix.nix
+    ./modules/npm.nix
+    ./modules/rofi.nix
+    ./modules/sxhkd.nix
+    ./modules/tabnine.nix
+    ./modules/trezor.nix
+    ./modules/xresources.nix
+    ./modules/zsh.nix
+  ];
+}
diff --git a/user/stow b/user/stow
new file mode 100755
index 00000000..761a5b5d
--- /dev/null
+++ b/user/stow
@@ -0,0 +1,2 @@
+#!/bin/sh
+stow --target="$HOME" --no-folding "$@"
diff --git a/user/sxhkd/.config/sxhkd/sxhkdrc b/user/sxhkd/.config/sxhkd/sxhkdrc
new file mode 100644
index 00000000..35179e9d
--- /dev/null
+++ b/user/sxhkd/.config/sxhkd/sxhkdrc
@@ -0,0 +1,29 @@
+XF86AudioMute
+  pamixer --toggle-mute
+
+XF86Audio{Lower,Raise}Volume
+  pamixer --{decrease,increase} 1
+
+@XF86AudioMicMute
+  pamixer --source 2 --toggle-mute
+
+XF86MonBrightness{Down,Up}
+  light -{U,A} 2%
+
+XF86Display
+  disper -C
+
+XF86AudioPlay
+  cmus-remote --pause
+
+XF86Audio{Prev,Next}
+  cmus-remote --{prev,next}
+
+# XF86WLAN
+
+XF86Tools
+  networkmanager_dmenu
+
+# XF86Search
+# XF86LaunchA
+# XF86Explorer
\ No newline at end of file
diff --git a/user/tabnine/.config/TabNine/TabNine.toml b/user/tabnine/.config/TabNine/TabNine.toml
new file mode 100644
index 00000000..c239f5a0
--- /dev/null
+++ b/user/tabnine/.config/TabNine/TabNine.toml
@@ -0,0 +1,36 @@
+[language.javascript]
+command = "javascript-typescript-stdio"
+args = []
+install = [["nix-env", "-iA", "nixos-unstable.nodePackages_10_x.javascript-typescript-langserver"]]
+
+[language.typescript]
+command = "typescript-language-server"
+args = ["--stdio"]
+install = [["nix-env", "-iA", "nixos-unstable.nodePackages_10_x.typescript-language-server"]]
+
+[language.css]
+command = "css-languageserver"
+args = ["--stdio"]
+install = [["nix-env", "-iA", "nixos-unstable.nodePackages_10_x.vscode-css-languageserver-bin"]]
+
+[language.scss]
+command = "css-languageserver"
+args = ["--stdio"]
+install = [["nix-env", "-iA", "nixos-unstable.nodePackages_10_x.vscode-css-languageserver-bin"]]
+
+[language.html]
+command = "html-languageserver"
+args = ["--stdio"]
+install = [["nix-env", "-iA", "nixos-unstable.nodePackages_10_x.vscode-html-languageserver-bin"]]
+
+[language.dockerfile]
+command = "docker-langserver"
+args = ["--stdio"]
+
+[language.yaml]
+command = "yaml-language-server"
+args = ["--stdio"]
+
+[language.haskell]
+command = "hie"
+args = ["--lsp"]
diff --git a/user/termite/.config/termite/config b/user/termite/.config/termite/config
new file mode 100644
index 00000000..19d49953
--- /dev/null
+++ b/user/termite/.config/termite/config
@@ -0,0 +1,48 @@
+[options]
+cursor_blink = off
+font = IBM Plex Mono 8
+scrollback_lines = -1
+
+[colors]
+
+# special
+foreground      = #5a5758
+foreground_bold = #5a5758
+cursor          = #5a5758
+background      = #ffffff
+
+# black
+color0  = #231f20
+color8  = #737171
+
+# red
+color1  = #ee2e24
+color9  = #ee2e24
+
+# green
+color2  = #00853e
+color10 = #00853e
+
+# yellow
+color3  = #edb204
+color11 = #edb204
+
+# blue
+color4  = #009ddc
+color12 = #009ddc
+
+# magenta
+color5  = #98005d
+color13 = #98005d
+
+# cyan
+color6  = #85cebc
+color14 = #85cebc
+
+# white
+color7  = #d9d8d8
+color15 = #ffffff
+
+# Local Variables:
+# compile-command: "pkill -USR1 termite"
+# End:
diff --git a/user/trezor/.ssh/agent.config b/user/trezor/.ssh/agent.config
new file mode 100644
index 00000000..2a5d213e
--- /dev/null
+++ b/user/trezor/.ssh/agent.config
@@ -0,0 +1 @@
+ecdsa-curve-name = ed25519
diff --git a/user/unstow-all b/user/unstow-all
new file mode 100755
index 00000000..3e56fd31
--- /dev/null
+++ b/user/unstow-all
@@ -0,0 +1,11 @@
+#!/usr/bin/env zsh
+
+set -euo pipefail
+
+echo "Checking if all packages can be unstowed"
+./stow -Dn --ignore="tabnine_config\.json" *(/)
+
+echo "Unstowing!"
+./stow -D --ignore="tabnine_config\.json" *(/)
+
+rmdir ~/.config/nixpkgs || echo "Could not remove nixpkgs directory. Remove it manually before running the installer."
diff --git a/user/xresources/.xresources/base16-mexico-light-256 b/user/xresources/.xresources/base16-mexico-light-256
new file mode 100644
index 00000000..34194f8e
--- /dev/null
+++ b/user/xresources/.xresources/base16-mexico-light-256
@@ -0,0 +1,54 @@
+! Base16 Mexico Light
+! Scheme: Sheldon Johnson
+
+#define base00 #f8f8f8
+#define base01 #e8e8e8
+#define base02 #d8d8d8
+#define base03 #b8b8b8
+#define base04 #585858
+#define base05 #383838
+#define base06 #282828
+#define base07 #181818
+#define base08 #ab4642
+#define base09 #dc9656
+#define base0A #f79a0e
+#define base0B #538947
+#define base0C #4b8093
+#define base0D #7cafc2
+#define base0E #96609e
+#define base0F #a16946
+
+*.foreground:   base05
+#ifdef background_opacity
+*.background:   [background_opacity]base00
+#else
+*.background:   base00
+#endif
+*.cursorColor:  base05
+
+*.color0:       base00
+*.color1:       base08
+*.color2:       base0B
+*.color3:       base0A
+*.color4:       base0D
+*.color5:       base0E
+*.color6:       base0C
+*.color7:       base05
+
+*.color8:       base03
+*.color9:       base08
+*.color10:      base0B
+*.color11:      base0A
+*.color12:      base0D
+*.color13:      base0E
+*.color14:      base0C
+*.color15:      base07
+
+! Note: colors beyond 15 might not be loaded (e.g., xterm, urxvt),
+! use 'shell' template to set these if necessary
+*.color16:      base09
+*.color17:      base0F
+*.color18:      base01
+*.color19:      base02
+*.color20:      base04
+*.color21:      base06
diff --git a/user/xresources/.xresources/base16-tomorrow b/user/xresources/.xresources/base16-tomorrow
new file mode 100644
index 00000000..46c18805
--- /dev/null
+++ b/user/xresources/.xresources/base16-tomorrow
@@ -0,0 +1,54 @@
+! Base16 Tomorrow
+! Scheme: Chris Kempson (http://chriskempson.com)
+
+#define base00 #ffffff
+#define base01 #e0e0e0
+#define base02 #d6d6d6
+#define base03 #8e908c
+#define base04 #969896
+#define base05 #4d4d4c
+#define base06 #282a2e
+#define base07 #1d1f21
+#define base08 #c82829
+#define base09 #f5871f
+#define base0A #eab700
+#define base0B #718c00
+#define base0C #3e999f
+#define base0D #4271ae
+#define base0E #8959a8
+#define base0F #a3685a
+
+*foreground:   base05
+#ifdef background_opacity
+*background:   [background_opacity]base00
+#else
+*background:   base00
+#endif
+*cursorColor:  base05
+
+*color0:       base00
+*color1:       base08
+*color2:       base0B
+*color3:       base0A
+*color4:       base0D
+*color5:       base0E
+*color6:       base0C
+*color7:       base05
+
+*color8:       base03
+*color9:       base08
+*color10:      base0B
+*color11:      base0A
+*color12:      base0D
+*color13:      base0E
+*color14:      base0C
+*color15:      base07
+
+! Note: colors beyond 15 might not be loaded (e.g., xterm, urxvt),
+! use 'shell' template to set these if necessary
+*color16:      base09
+*color17:      base0F
+*color18:      base01
+*color19:      base02
+*color20:      base04
+*color21:      base06
diff --git a/user/xresources/.xresources/main b/user/xresources/.xresources/main
new file mode 100644
index 00000000..b73f1d34
--- /dev/null
+++ b/user/xresources/.xresources/main
@@ -0,0 +1,42 @@
+#include "base16-tomorrow"
+
+*.font:                   -xos4-terminus-medium-r-*-*-12-*-*-*-*-*-iso10646-*
+
+Xcursor.theme:            Bibata Oil
+Xcursor.size:             16
+
+Emacs.ToolBar:            off
+Emacs.MenuBar:            off
+Emacs.ScrollBars:         off
+Emacs.CursorBlink:        off
+
+rofi.font:                Monospace Bold 14
+
+st.borderpx:              1
+st.chscale:               1.2
+st.bold_font:             0
+st.mouseScrollLines:      3
+
+URxvt.fading:             0
+URxvt.geometry:           100x40
+URxvt.urgentOnBell:       true
+
+URxvt.scrollBar:          false
+URxvt.scrollstyle:        plain
+URxvt.scrollTtyOutput:    false
+URxvt.scrollWithBuffer:   true
+URxvt.scrollTtyKeypress:  true
+URxvt.saveLines:          16384
+URxvt.secondaryScroll:    false
+
+URxvt.boldFont:           -xos4-terminus-bold-r-*-*-12-*-*-*-*-*-iso10646-*
+URxvt.intensityStyles:    true
+
+URxvt.pointerBlank:       true
+URxvt.pointerBlankDelay:  987654321
+URxvt.letterSpace:        0
+URxvt.lineSpace:          2
+
+! Local Variables:
+! compile-command: (concat "xrdb -merge " (shell-quote-argument buffer-file-name))
+! End:
diff --git a/user/xresources/.xresources/solarized-light b/user/xresources/.xresources/solarized-light
new file mode 100644
index 00000000..3906b7b0
--- /dev/null
+++ b/user/xresources/.xresources/solarized-light
@@ -0,0 +1,70 @@
+! Solarized color scheme for the X Window System
+!
+! http://ethanschoonover.com/solarized
+
+
+! Common
+
+#define S_yellow        #b58900
+#define S_orange        #cb4b16
+#define S_red           #dc322f
+#define S_magenta       #d33682
+#define S_violet        #6c71c4
+#define S_blue          #268bd2
+#define S_cyan          #2aa198
+#define S_green         #859900
+
+
+! Dark
+
+! #define S_base03        #002b36
+! #define S_base02        #073642
+! #define S_base01        #586e75
+! #define S_base00        #657b83
+! #define S_base0         #839496
+! #define S_base1         #93a1a1
+! #define S_base2         #eee8d5
+! #define S_base3         #fdf6e3
+
+
+! Light
+
+#define S_base03        #fdf6e3
+#define S_base02        #eee8d5
+#define S_base01        #93a1a1
+#define S_base00        #839496
+#define S_base0         #657b83
+#define S_base1         #586e75
+#define S_base2         #073642
+#define S_base3         #002b36
+
+
+! To only apply colors to your terminal, for example, prefix
+! the color assignment statement with its name. Example:
+!
+! URxvt*background:       S_base03
+
+*background:              S_base03
+*foreground:              S_base0
+*fading:                  40
+*fadeColor:               S_base03
+*cursorColor:             S_base1
+*pointerColorBackground:  S_base01
+*pointerColorForeground:  S_base1
+
+*color0:                  S_base02
+*color1:                  S_red
+*color2:                  S_green
+*color3:                  S_yellow
+*color4:                  S_blue
+*color5:                  S_magenta
+*color6:                  S_cyan
+*color7:                  S_base2
+*color8:                  S_base03
+*color9:                  S_orange
+*color10:                 S_base01
+*color11:                 S_base00
+*color12:                 S_base0
+*color13:                 S_violet
+*color14:                 S_base1
+*color15:                 S_base3
diff --git a/user/yarn/.yarnrc b/user/yarn/.yarnrc
new file mode 100644
index 00000000..6c37ae5d
--- /dev/null
+++ b/user/yarn/.yarnrc
@@ -0,0 +1,9 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+registry "https://registry.npmjs.org/"
+disable-self-update-check true
+email alan@alanpearce.eu
+username alanpearce
+yarn-offline-mirror-pruning true
diff --git a/user/zsh/.config/zsh/.zshenv b/user/zsh/.config/zsh/.zshenv
new file mode 100644
index 00000000..6b58186e
--- /dev/null
+++ b/user/zsh/.config/zsh/.zshenv
@@ -0,0 +1,64 @@
+if [[ $SHLVL -eq 1 || -n $DISPLAY ]]
+then
+  if [[ -f $ZDOTDIR/zshenv.local ]]
+  then
+    . $ZDOTDIR/zshenv.local
+  fi
+
+  if [[ -f $ZDOTDIR/zshenv.private ]]
+  then
+    . $ZDOTDIR/zshenv.private
+  fi
+
+  if [[ -e $HOME/.nix-profile/etc/profile.d/nix.sh ]]
+  then
+    . $HOME/.nix-profile/etc/profile.d/nix.sh;
+    export NIX_LINK
+  fi
+
+  case $OSTYPE in
+    darwin*)
+      os=darwin
+      ;;
+    linux-gnu)
+      os=linux
+      ;;
+    freebsd*)
+      os=freebsd
+      ;;
+    *)
+      os=unknown
+      ;;
+  esac
+
+  case $MACHTYPE in
+    *64)
+      arch=amd64
+      ;;
+    *)
+      arch=386
+      ;;
+  esac
+
+  if [[ ${path[(I)$HOME/.local/bin ]} ]]
+  then
+    path+=($HOME/.local/bin)
+  fi
+
+  if [[ ${path[(I)$HOME/go/bin ]} ]]
+  then
+    path+=($HOME/go/bin)
+  fi
+
+  if [[ $HOST =~ satoshi ]]
+  then
+    EMAIL=alan@satoshipay.io
+  else
+    EMAIL=alan@alanpearce.eu
+  fi
+
+  export GTAGSCONF=~/.globalrc
+  export GTAGSLABEL=ctags
+
+  export GHQ_ROOT="$HOME/projects:$HOME/go/src:$HOME/quicklisp/local-projects"
+fi
diff --git a/user/zsh/.config/zsh/.zshrc b/user/zsh/.config/zsh/.zshrc
new file mode 100644
index 00000000..2d869f0e
--- /dev/null
+++ b/user/zsh/.config/zsh/.zshrc
@@ -0,0 +1,281 @@
+# -*- mode: sh; -*-
+if [[ -f "$HOME/.zplugin/bin/zmodules/Src/zdharma/zplugin.so" ]]
+then
+  module_path+=( "/Users/alan/.zplugin/bin/zmodules/Src" )
+  zmodload zdharma/zplugin
+else
+  echo "Zplugin module is not installed" >&2
+fi
+
+source $HOME/.zplugin/bin/zplugin.zsh
+autoload -Uz _zplugin
+(( ${+_comps} )) && _comps[zplugin]=_zplugin
+
+HISTSIZE=10000
+SAVEHIST=20000
+HISTFILE=${XDG_CACHE_HOME:=$HOME/.cache}/zsh/history
+[[ -d ${HISTFILE:h} ]] || mkdir -p ${HISTFILE:h}
+setopt extended_history
+setopt hist_save_no_dups
+setopt hist_ignore_space
+unsetopt share_history
+setopt inc_append_history_time
+setopt transient_rprompt
+
+WORDCHARS=${${WORDCHARS//[-.=]}//[\/]}
+
+alias ec=emacsclient
+
+ls='\ls'
+gnu_ls_options="-v --group-directories-first --color=auto"
+gnu_ls_isodate="--time-style=long-iso"
+bsd_ls_options="-p"
+bsd_ls_isodate="-D '%F %k:%M'"
+
+case $os in
+  darwin)
+    if [[ -n $commands[gls] ]]
+    then
+      ls='\gls'
+      ls_options=$gnu_ls_options
+      ls_isodate=$gnu_ls_isodate
+    else
+      export CLICOLOR=1
+      ls_options=$bsd_ls_options
+    fi
+    ;;
+  freebsd)
+    ls_options=$bsd_ls_options
+    ls_isodate=$bsd_ls_isodate
+    ;;
+  linux)
+    ls_options=$gnu_ls_options
+    ls_isodate=$gnu_ls_isodate
+    ;;
+esac
+alias watch="watch " # enable watch with aliases
+alias l="${ls} ${ls_options} -Bp"
+alias l1="${ls} ${ls_options} -1"
+alias ls="${ls} ${ls_options} -hF"
+alias la="${ls} ${ls_options} -hA"
+alias ll="${ls} ${ls_options} ${ls_isodate} -hl"
+alias lal="ll -A"
+alias lla="lal"
+alias llr="ll -t"
+
+alias https="http --default-scheme https"
+alias kns="kubens"
+alias kx="kubectx"
+
+alias ava="pnpx ava"
+alias avt="pnpx ava --tap"
+alias avat="pnpx ava --tap"
+alias pino="pino-pretty"
+alias mocha="pnpx mocha"
+alias prettier="pnpx prettier"
+alias standard="pnpx standard"
+alias tsc="pnpx tsc"
+alias tslint="pnpx tslint"
+alias tsnode="pnpx ts-node"
+alias wprop="xprop | egrep '^WM_(CLASS|NAME|WINDOW_ROLE|TYPE)'"
+zmodload zsh/terminfo
+
+bindkey -e
+bindkey '\e[3~' delete-char
+
+bindkey '\C-hd' describe-key-briefly
+
+dc () {
+  if [[ -x ./docker-compose ]]
+  then
+    ./docker-compose "$@"
+  else
+    docker-compose "$@"
+  fi
+}
+compdef '_dispatch docker-compose docker-compose' dc
+
+backward-argument () {
+  local WORDCHARS="\!\`~#@$%^&*()-_=+[{]}\|;:,<.>/?\'\""
+  zle backward-word
+}
+
+forward-argument () {
+  local WORDCHARS="\!\`~#@$%^&*()-_=+[{]}\|;:,<.>/?\'\""
+  zle forward-word
+}
+
+backward-kill-argument () {
+  local WORDCHARS="\!\`~#@$%^&*()-_=+[{]}\|;:,<.>/?\'\""
+  zle backward-kill-word
+}
+
+kill-argument () {
+  local WORDCHARS="\!\`~#@$%^&*()-_=+[{]}\|;:,<.>/?\'\""
+  zle kill-word
+}
+
+zle -N backward-argument
+zle -N forward-argument
+zle -N kill-argument
+zle -N backward-kill-argument
+bindkey '\e^b' backward-argument
+bindkey '\e^f' forward-argument
+bindkey '\e^d' backward-kill-argument
+bindkey '\e^k' kill-argument
+
+sort=${commands[gsort]:-$commands[sort]}
+
+ds () {
+  du -hd1 $1 | $sort -h
+}
+
+# returns the first ghq root, whereas $GHQ_ROOT returns all
+hash -d p=$(ghq root)
+hash -d go=${GOPATH:-$HOME/go}
+
+zle -C hist-complete complete-word _generic
+zstyle ':completion:hist-complete:*' completer _history
+bindkey '\e ' hist-complete
+
+zstyle ':completion:*' matcher-list 'm:{a-zA-Z-_}={A-Za-z_-}' 'r:|=*' 'l:|=* r:|=*'
+zstyle ':completion:*' completer _expand _complete _match
+
+# Plugins
+
+zplugin ice blockf wait'!' lucid
+zplugin load "zsh-users/zsh-completions"
+zplugin ice wait'[[ -n ${ZLAST_COMMANDS[(r)k*]} || "$PWD" =~ "kubernetes" ]]' lucid
+zplugin load alanpearce/kubectl-aliases
+zplugin ice wait'1' lucid atinit'alias cdg=cd-gitroot'
+zplugin load "mollifier/cd-gitroot"
+zplugin ice wait'[[ -n ${ZLAST_COMMANDS[(r)rm*]} ]]' lucid
+zplugin load "MikeDacre/careful_rm"
+
+ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE="fg=7"
+zplugin ice wait'1' lucid if'[[ -z $SSH_CLIENT ]]'
+zplugin load "zsh-users/zsh-autosuggestions"
+
+zplugin ice wait'1' lucid
+zplugin load "arzzen/calc.plugin.zsh"
+
+# provides the title function and macOS title-folder sync
+zplugin ice if'[[ $os -eq darwin ]]'
+zplugin snippet "OMZ::lib/functions.zsh"
+zplugin ice if'[[ $os -eq darwin ]]'
+zplugin snippet "OMZ::lib/termsupport.zsh"
+
+zplugin ice if'[[ $os -eq darwin ]]' wait'5' lucid
+zplugin load "unixorn/tumult.plugin.zsh"
+
+zplugin ice wait'[[ -n ${ZLAST_COMMANDS[(r)npm*]} ]]' lucid
+zplugin load "lukechilds/zsh-better-npm-completion"
+
+zplugin ice if'[[ (-n $commands[nix-env] && -z $commands[nixos-rebuild]) ]]' wait'[[ -n ${ZLAST_COMMANDS[(r)nix-shell*]} ]]' lucid
+zplugin load "chisui/zsh-nix-shell"
+
+zplugin ice if'[[ -n $commands[ghq] ]]'
+zplugin load "${GOPATH:=$HOME/go}/src/github.com/motemen/ghq/zsh"
+
+zplugin ice wait'!2' lucid
+zplugin load "MichaelAquilina/zsh-you-should-use"
+
+if [[ -n $commands[gcloud] ]]
+then
+   autoload bashcompinit
+   bashcompinit
+   source ${$(readlink =gcloud):h}/../etc/bash_completion.d/gcloud.inc
+fi
+
+if [[ -n $commands[helm] ]]
+then
+  autoload _helm
+  compdef _helm helm
+fi
+
+
+# General configuration
+
+if [[ -n $commands[gpg2] && -z $commands[gpg] ]]
+then
+  alias gpg=gpg2
+fi
+
+if [[ -n $commands[lunchy] ]]
+then
+  LUNCHY_DIR=$(dirname $(gem which lunchy))/../extras
+  if [ -f $LUNCHY_DIR/lunchy-completion.zsh ]; then
+    . $LUNCHY_DIR/lunchy-completion.zsh
+  fi
+fi
+
+PROMPT='%B%F{green}%n %F{blue}%~%b
+%# '
+if [[ $TERM == "dumb" ]]
+then
+  unsetopt zle
+else
+  AGKOZAK_PROMPT_DIRTRIM=0
+  AGKOZAK_LEFT_PROMPT_ONLY=${+SSH_CLIENT}
+
+  check_kubectl_context () {
+    if [[ "$PWD" =~ /kubernetes ]]
+    then
+      git_branch=$(git rev-parse --abbrev-ref HEAD | tr '[:upper:]' '[:lower:]')
+      kubectl_context=$(kubectl config current-context)
+      kubectl_namespace=$(kubectl config view -o jsonpath="{.contexts[?(@.name==\"${kubectl_context}\")].context.namespace}")
+      case $git_branch in
+        staging)
+          kubectl_release=satoshipay-${kubectl_namespace}-staging
+          ;;
+        production)
+          kubectl_release=satoshipay-${kubectl_namespace}
+          ;;
+        master)
+          kubectl_release=
+          ;;
+        *)
+          kubectl_release=story-${git_branch}-${kubectl_namespace}
+      esac
+      if [[ $kubectl_context =~ production ]]
+      then
+        kubectl_colour=red
+      else
+        kubectl_colour=yellow
+      fi
+        prompt_context="%F{$kubectl_colour}[${kubectl_context}:${kubectl_namespace}]%f"
+    else
+      prompt_context=
+    fi
+  }
+  precmd_functions+=(check_kubectl_context)
+  AGKOZAK_CUSTOM_RPROMPT='${prompt_context}%(3V.%F{${AGKOZAK_COLORS_BRANCH_STATUS}%3v%f.)'
+fi
+zplugin load agkozak/agkozak-zsh-prompt
+
+zplugin ice wait'!' lucid
+zplugin light "mollifier/anyframe"
+if [[ -n $commands[fzf] ]]
+then
+  zplugin snippet "https://github.com/junegunn/fzf/raw/master/shell/key-bindings.zsh"
+  export FZF_CTRL_T_COMMAND='
+    (git ls-tree -r --name-only HEAD ||
+	       fd --hidden --follow --exclude ".git" . |
+	             sed s/^..//) 2> /dev/null'
+  export FZF_ALT_C_COMMAND='fd --type d --hidden --follow --exclude ".git" .'
+  export FZF_DEFAULT_COMMAND=$FZF_CTRL_T_COMMAND
+
+  bindkey '^t' transpose-chars
+  bindkey '^x^f' fzf-file-widget
+
+  zstyle ":anyframe:selector:fzf:" command "fzf --height 40%"
+
+  bindkey '\es' anyframe-widget-cd-ghq-repository
+  bindkey '^x^k' anyframe-widget-kill
+fi
+
+unsetopt flow_control       # Let me use ^S and ^Q
+
+zplugin ice wait'!' if'[[ -z $SSH_CLIENT ]]' lucid atinit'zpcompinit; zpcdreplay -q' lucid
+zplugin load "zdharma/fast-syntax-highlighting"
+
diff --git a/user/zsh/.config/zsh/setup.sh b/user/zsh/.config/zsh/setup.sh
new file mode 100755
index 00000000..93bbf808
--- /dev/null
+++ b/user/zsh/.config/zsh/setup.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env zsh
+
+mkdir $HOME/.zplugin
+git clone https://github.com/psprint/zplugin.git $HOME/.zplugin/bin
+
+zcompile $HOME/.zplugin/bin/zplugin.zsh
+
+mkdir -p $HOME/.cache/zsh/
+
diff --git a/user/zsh/.rm_recycle_home b/user/zsh/.rm_recycle_home
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/user/zsh/.rm_recycle_home
diff --git a/user/zsh/.zshenv b/user/zsh/.zshenv
new file mode 100644
index 00000000..354c54da
--- /dev/null
+++ b/user/zsh/.zshenv
@@ -0,0 +1,3 @@
+ZDOTDIR="${XDG_CONFIG_HOME:=$HOME/.config}/zsh"
+
+source "$ZDOTDIR"/.zshenv