My dotfiles are now just a long documentation file. Not very DRY, in a good way.

I disliked the complexity involved with branching between different devices because of slight differences (can be as small as a work email).

I used to run a nice NixOS setup with everything tracked in git, etc. This is what I ended up after declaring dotfile bankupcy.


Set my editor and bash mode:

set -o vi
export EDITOR="nvim"

Minimal PS1:

export PS1="\w $ "

Common bin locations:

export PATH="$PATH:$HOME/bin"
export PATH="$PATH:$HOME/go/bin"
export PATH="/opt/homebrew/bin:$PATH"

My p alias to quickly switch projets:

p() {
    cd ~/p && cd "$(find . -mindepth 1 -maxdepth 1 -type d | fzf)"

Download audio via aget {{URL}}:

alias aget="yt-dlp --extract-audio --audio-format mp3"

Download a webpage:

# /bin/hget
# usage: "hget {{URL}} {{outfile}}"
# NOTE: Kobo needs the '-F' flag
chromium --headless --incognito --dump-dom "$1" | monolith - -IF -E utf-8 -b "$1" -o "$2"


Taliscale & fridge access

  1. Sign in to tailscale
  2. Install tailscale
  3. Setup an ssh key
    1. ssh-keygen -t ed25519 -C
    2. send .pub to another device
    3. add the key to ~/.ssh/authorized_keys in the fridge


I like to setup my ssh such that it opens a tmux session on a new connection.

Host fridge
  User root
  RemoteCommand tmux a
  RequestTTY yes


Here is a cheatsheet.

Set my credentials:

    name = Dominik Tarnowski
    email =
    user = td0m

I am not racist - I do not use master branches 🙃.

    defaultBranch = main

Ignore the global .gitignore file:

    excludesfile = ~/.gitignore

My beloved aliases:

    a = add
    aa = add --all
    d = diff
    ds = diff --staged
    dd = diff --stat
    b = branch
    l = log --oneline -n 20 --date=format:'%Y-%m-%d %H:%M' --pretty=format:'%C(cyan)%h%Creset%C(auto)%d %s - %ar'
    s = status --short --branch
    ch = checkout
    c = commit

Use SSH rather than HTTP, so that my ssh public keys are used for authentication:

[url "ssh://"]
    insteadOf =


By default, tmux starts windows at 0 and does not renumber them on delete. I dislike that.

set -g base-index 1
set -g pane-base-index 1
set-window-option -g pane-base-index 1
set-option -g renumber-windows on

When I open a new window, I want it to be in the same directory as the previous one.

bind  c  new-window      -c "#{pane_current_path}"
bind  %  split-window -h -c "#{pane_current_path}"
bind '"' split-window -v -c "#{pane_current_path}"

I used to use bind-key -n C-g send-prefix to nest tmux sessions, but now I just open a new kitty tab for this. Muscle memory is better this way.

This is copy pasted, and seems to fix my tmux colors, sometimes:

set -as terminal-overrides ",xterm-256color:RGB"
set -g default-terminal "tmux-256color"

Rarely, I like using the mouse to switch windows:

set -g mouse on

If you’ve ever used vim with tmux, you’ll notice escape has a delay. Disable it.

set -sg escape-time 10

Sometimes, I like longer session names. By default tmux truncates them. Extend it.

set -g status-left-length 20


Disable syntax highlighting, including treesitter’s.

vim.cmd("syntax off")

Be default, do not wrap - it’s ambiguous.

vim.opt.wrap = false

Try :h tabstop for recommended ways of using these options.

My default, use tabs:

vim.opt.expandtab = false
vim.opt.tabstop = 4
vim.opt.shiftwidth = 0 -- default to tabstop's value
vim.opt.softtabstop = 0 -- disabled

To switch to 2 spaces:

:set expandtab tabstop=2

If your indentation is unexpectedly different, turns out vim lets you find out exactly which module did it. To likely disable this, run filetype indent off.

:verb set shiftwidth

On the topic of tabs vs spaces, in case you need to know which is which:

vim.opt.list = false
vim.opt.listchars = { space = '⋅', tab = '→ ' }

Oftentimes, especially in JS/TS, I find the auto indenting sucks. Hence this just makes the indentation use the same as the line above.

vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, {
    pattern = "*",
    callback = function() = ""

To switch alternate buffers via backspace:

vim.keymap.set("n", "<BS>", ":b#<CR>", { silent = true })

To make searching with / case insensitive (unless an uppercase or /C option), use:

vim.o.ignorecase = true
vim.o.smartcase = true

Re-select last yanked text (different to gv which is last visual):

vim.keymap.set("n", "gy", "`[v`]")

To insert the current date via “,d”:

vim.cmd.iabbrev("<expr>", ",d", "strftime('%Y-%m-%d')")

To remove trailing whitespace:

vim.api.nvim_create_autocmd({ "BufWritePre" }, {
    pattern = { "*" },
    callback = function(_)
        local save_cursor = vim.fn.getpos(".")
        vim.fn.setpos(".", save_cursor)

To persist undos between neovim sessions:

vim.o.undofile = true

To disable the status line:

vim.opt.laststatus = 0
vim.opt.showmode = false


vim.g.mapleader = " "
vim.g.maplocalleader = " "

lsp configs:

vim.keymap.set("n", "gd", vim.lsp.buf.definition)
vim.keymap.set("n", "<leader>a", vim.lsp.buf.code_action)

vim.api.nvim_create_autocmd("BufRead", {
    pattern = { "*.js", "*.jsx", "*.ts", "*.tsx" },
    callback = function(args)
            name = "js",
            cmd = { "typescript-language-server", "--stdio" },
            root_dir = vim.fs.root(0, {"package.json"}),

Experimental: espeak.

local espeak = 'espeak -s 150 --punct -k 1'

vim.keymap.set('n', '<leader>l', ':.w !setsid -f '..espeak..'<cr><cr>')
vim.keymap.set('n', '<leader>l', ':.w !setsid -f '..espeak..'<cr><cr>')
vim.keymap.set('n', '<leader>u', ':!pkill -9 espeak<CR><CR>')

Neovim remote


#!/usr/bin/env bash
export PIPE="$HOME/.cache/nvim/servers/$(openssl rand -hex 4).pipe"
mkdir -p "$(dirname "$PIPE")"
nvim --listen "$PIPE" $@


#!/usr/bin/env bash
fd $ARGS | fzf --tmux -m | xargs nvim --server "$PIPE" --remote


#!/usr/bin/env bash
RG_PREFIX="rg --column --line-number --no-heading --color=always --smart-case $*"
fzf --tmux 60% -m \
    --ansi --disabled --query "" \
    --bind "start:reload:$RG_PREFIX {q}" \
    --bind "change:reload:sleep 0.1; $RG_PREFIX {q} || true" \
    --delimiter : \
    --preview 'bat --color=always {1} --highlight-line {2}' \
    --preview-window 'up,60%,border-bottom,+{2}+3/3,~3' \
    --bind 'enter:become(vr {1} && vsend '{2}G')'

neovim integration

vim.keymap.set("n", "<leader>g", [[:silent !g -i &<CR>]], { silent = true })
vim.keymap.set("n", "<leader>G", [[:silent !g -i &]], {})
vim.keymap.set("n", "<leader>f", [[:silent !f -i &<CR>]], { silent = true })
vim.keymap.set("n", "<leader>F", [[:silent !f -i &]], {})


I use a super simple mechanism for snippets/templates: a ~/t directory.

You can activate them with vim via: :r ~/t/doctype.


<!DOCTYPE html>
<html lang="en">
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <meta name="theme-color" content="">
        <link rel="shortcut icon" href="">
        <link rel="stylesheet" href="">


My ~/.sqliterc has the following defaults:

To enable headers: .headers on

To show as a table, not csv: .mode column

To show number of rows changed: .changes on

Custom emoji for null values: .nullvalue 👻


My .psqlrc contains this line to enable timing messages:

\timing on

If the columns take up too much space, show one per line:

\x auto

Use ghost emojis to display null values:

\pset null 👻

If you want histories to be separate per database:

\set HISTFILE ~/.psql_history- :DBNAME


My terminal of choice is kitty.

The main custom thing I do there is set a font.

font_family UnifontExMono
adjust_column_width 50%
font_size 14