How I Do

environment software practices

Sometimes people ask me how I do things digitally. They can read this.

Introduction #

This document provides a view into how I use computers with a focus on software. It is organized into major software categories with subsections for each important package.

It also serves as notebook of documentation to remind me of some details. Expect some incomplete sections and to see changes over time.

The extensive configuration files are not available but I have some intention to rectify that at some point.

Typography #

In this document, the prompts used in examples are as:

# command run as root
$ command run as user in bash
❯ command run as user in fish

A command is written like that.

Hardware #

Hardware interests me less than software so I do not go into detail other than to give hostnames to four hardware roles:

hometop
personal laptop (thinkpad x1e gen2)
worktop
work laptop (thinkpad x1c gen5)
homestation
personal workstation (custom build)
workstation
work workstation (ASLab Marquis)
homeserver
personal server with ports exposed to the Internet

For the last one, I maintain a dynamic DNS subdomain from the great folks at afraid.

Configuration #

Configuration files (“dotfiles”) are stored in a private Gitea instance and most clones are managed with vcsh and myrepos with pass and etckeeper managing its own.

The vcsh git repo manager allows multiple git repos to supply files into $HOME without any actual .git/ directory there. It allows for the target filesystem space to be interleaved with files managed in separate git repos. Seems crazy, works great.

My vcsh repos include config for: bash, bbdb, emacs, git, mr (myrepos), nixpkgs, sawfish, scripts, ssh, systemd, tmux, weechat bbdb for contacts in BBDB and a consolidated “dots” for all the dot files. I started with many fine-grained repos and mr to help do bootstrap but this was more work with no perceived benefit. I kept bbdb separate as one day I may make the “dots” repo public. Some setup of individual things are described in following sections but first how vcsh is handled.

Initialize #

Each repo needs a one time setup like:

# apt install vcsh
$ vcsh init bbdb
$ vcsh bbdb add .bbdb
$ vcsh bbdb commit -m "First commit"
$ vcsh bbdb remote add origin gogs@homeserver:bv/dot-bbdb.git
$ vcsh bbdb push -u origin master

Multiple repositories #

There is built-in support for multiple repositories in vcsh, eg:

$ vcsh status
$ vcsh pull
$ vcsh push

Bootstrap new account #

A new account can clone individual repos:

$ vcsh clone gogs@homeserver:bv/dot-bbdb.git bbdb

Ignoring #

Any git command run through vcsh uses $HOME as the Git working dir.

$ vcsh bbdb status
[... long list of untracked files ...]

You can have vcsh Git command ignore anything not explicitly committed to a vcsh Git repository:

$ vcsh write-gitignore bbdb
$ vcsh bbdb status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

The write-gitignore command will create a file like:

$ cat ~/.gitignore.d/bbdb
*
!/.bbdb

In the case of sub-directories of interest which exist among siblings to ignore one has to add exhaustive paths to the allow list. For example,

*
!/.local
!/.local/share
!/.local/share/applications
!/.local/share/applications/*.desktop

Making updates #

Here we make a change to the omnibus dots package

❯ emacs -nw .config/kitty/(hostname).conf
❯ vcsh dots add .config/kitty/(hostname).conf
❯ vcsh dots commit -am "customize for "(hostname)
❯ vcsh dots push

Applying updates #

❯ vcsh dots pull
❯ vcsh pull  # en masse

Checking for updates #

I want my prompt to tell me when a local account has modified, is behind the remote vcsh or ahead of it (made a commit but not push). To check the remote takes time and also needs SSH credentials. The functionality is in vcsh-extra with commands hooks, probe and cron which call both and fetch.

fetch
the fetch command simply does a:
vcsh foreach fetch
probe
the probe command will run vcsh status --terse and parse it for state to touch files last-{ahead,behind,modified} (removing any stale ones).
hooks
the hooks command install vcsh hooks which will run the probe command named after an action. Ie in: post-{pull,push,commit,enter,run} is:
vcsh-extra probe
cron
the cron command bundles calls the three commands in sequence after
eval $(keychain --quiet --noask --eval id_rsa)

In summary, the cron job runs once per hour, fetching but not applying any changes and doing the probe to summarize what state that leaves the local vcsh repositories.

When doing vcsh commands the hooks run to repeat the probe (which is fast enough).

Noticing changes #

In the shell prompts I add an indicator of the vcsh state.

For bash the PROMPT_COMMAND will check for the existence last-{ahead,behind,modified} files and prepend a little marker to the prompt. If all three types of “dirty” occur, the prompt looks like:

{ABM}bv@hal:~
$

For fish, a _tide_item_vcsh() function is defined to do similar.

Editor #

Emacs #

I use Emacs for Email (GNUS), Contacts (BBDB), software development, document and presentation production (orgmode and LaTeX), bookmark management (org-protocol and org-capture) and web form text entry (atomic-chrome). Emacs 27 is soon to be released but I can’t wait so I build it from source (see Source). It now allows XDG_CONFIG_HOME which I make use of by conceptually doing:

$ rm -rf .emacs*
$ mkdir .config/emacs

Typing emacs then uses $XDG_CONFIG_HOME/emacs/init.el. There’s lots of fashionable ways to configure init.el. I don’t follow then except to break up the config into many init-*.el and (require) them in a big list.

Emacs packages #

I heavily use use-package and in two modes. I want the ability to blow away any emacs.d/elpa/ area and rebuild it any time but normally don’t want to spend the extra load time to query for package state. This is in init-package.el:

(require 'package)
(setq package-archives
      '(("org"     .       "https://orgmode.org/elpa/")
        ("gnu"     .       "https://elpa.gnu.org/packages/")
        ("melpa"   .       "https://melpa.org/packages/")))
(package-initialize)
;; uncomment this block and restart emacs to get new packages
;;;;;
;; (setq use-package-always-ensure t)
;; (package-refresh-contents)
;; (unless (package-installed-p 'use-package)
;;   (package-install 'use-package))
;;;;;;
(require 'use-package)
(provide 'init-packages)

Modular config #

I factor my Emacs configuration as par modular-config with “modules” in ~/.config/emacs/init/*.el and some top level configs listed like:

(use-package modular-config
  :custom
  (modular-config-list
   '(
     (full (base gui orgmode dired smex spelling markdown lisp cpp python jsonnet tail))
     (email (base gui orgmode email))
     (empty ())
     (plain (base))
     (main (base gui orgmode))
     ;; Used from EDITOR
     (cmdline (base cli))
     ;; Used from $VISUAL
     (visual (base gui))
     (blog (base gui orgpub dired smex spelling markdown cpp python))
     (prog (base gui orgmode dired smex spelling markdown cpp python))
     ;; for calling from GhostText, except we still do it
     ;; through init-atomic-chrome.el
     (ghost (base gui dired ivy smex spelling markdown))
     ;; for calling from $EDITOR
     (shell (base gui dired ivy smex spelling))
     ))
  (modular-config-default 'full)
  (modular-config-path "~/.config/emacs/init")
  :config
  (modular-config-command-line-args-process))

I then may select a configuration on the command line like:

$ emacs --config plain [...]

GNUS/BBDB #

t.b.d.

Emacs servers #

To support bookmark capture (Firefox + org-protocol + a script) and text entry editing (GhostText + atomic-chrome) I have dedicated Emacs server configuration as well. These servers are started via supervisord which itself starts from cron:

$ crontab -l|grep supervisord
@reboot supervisord -c /home/bv/scripts/supervisor.conf

That =~/scripts/~ directory is in vcsh. The two Emacs servers are started like:

[program:emacs-capture]
command=%(ENV_HOME)s/scripts/emacs-start-server capture
directory=%(ENV_HOME)s
autorestart = false

[program:emacs-atomic-chrome]
command=%(ENV_HOME)s/scripts/emacs-start-server atomic-chrome
directory=%(ENV_HOME)s
autorestart = false

This emacs-start-server script is mostly to remind me how to start Emacs properly. It boils down to running:

exec emacs -q --fg-daemon=${name} -l ~/.config/emacs/init-${name}.el

As such the nominal init.el is not sourced. Each server is self contained including its custom.el and its elpa/ area.

For bookmark capture I configure Firefox to call ~/scripts/emacs-capture script for any org-protocol:// links. Effectively it calls:

emacsclient -n -c -s capture \
   -F "((name . \"emacs-capture\") (height . 20) (width . 80))" \
   "org-protocol://capture://w/<encoded-url>/"

This runs on the “capture” server and since it uses emacsclient it starts very fast.

Terminal #

Kitty #

I’ve tried many terminals over the years and for about the last year I have been very happily using the Kitty terminal. I mean the one written in Python/OpenGL and not the on derived from Putty. Some reasons why I like it:

  • emoji support!
  • C-S-h to load scrollback into less
  • fast, beautiful text, Free Software

It also has sub-programs called “kittens” such as kitten icat foo.png to show a graphic in the terminal. Or kitten diff to show a pretty side-by-side diff. These are nice but I rarely use them.

Here is an install command:

python3 setup.py --prefix=/usr/local/stow/kitty-0.19.3 linux-package

See kitty build instructions and Stow for more info.

No particularly fancy config. It lives in .config/kitty/kitty.conf and ends with:

include local.conf

And that file is made locally, once per account:

❯ ln -sf ~/.config/kitty/{(hostname),local}.conf

I start weechat in a special kitty:

❯ kitty -o 'map kitty_mod+e kitten hints --customize-processing weechat_hints.py' weechat

Where that Python script is from https://github.com/GermainZ/kitty-weechat-hints. I can then give C-S-e to kitty followed a number matching one of the found URLs to open. The weechat_hints.py does the heavy lifting to form the URL in the face of possible line splitting by weechat.

I tell kitty to open URLs or other hyperlinks via:

open_url_with kitty-open

Which merely redirects to my personal open command, described below.

Shells #

I have moved to the fish shell but have been a long time and still sometimes user of bash. From fish sessions I will sometimes still start bash to do some complex command which I’ve yet to master in fish. In this mixed environment it is sometimes necessary to explicitly set SHELL to either fish or bash as some commands are sensitive to the value.

Fish #

Fish is a really amazing shell which requires very little configuration to make it “feel right” (unlike bash). Here are a few things I do with fish.

I use the tide prompt which is very nice, easy and popular. Amazingly, it is as I like it out of the box and I do very little customization. The vcsh customization described above is one exception.

I use this fzf / Fish integration:

$ fisher add PatricF1/fzf.fish

Only customization is to override the C-f keybinding as it’s needed for my Emacs-trained fingers for character-forward. In config.fish

# override fzf bindings
bind --erase \cf
bind \co '__fzf_search_current_dir'

To use direnv I add per docs, conf.d/direnv.fish with

eval (direnv hook fish)

When I started learning Fish, I ported my shell implemenation shist of ash to fishql. This gave a nice vehicle to dive into Fish programming. However, I’ve stopped using it because I find I almost never actually use the SQL query functionality.

As kitty has support for ls --hyperlink I modify fish’s ls command to add it. I did not see a “right” way to do this so I copied ls.fish from a recent install to .config/fish/functions/ls.fish and added a __fish_ls_opts variable to the final command call and then run

❯ set -U __fish_ls_opts --hyperlink=auto

This now gives me the dubious pleasure of clicking on Kitty’s rendering of the ls command and having open handle that. More on opening files below.

Bash #

Though I have moved to fish, I keep my bash setup alive as I sometimes will start bash from a fish session.

My .bashrc is run for login or subshells. It delegates configuration to scripts under /.bash/{functions,variables,apps}/*.sh and “mounts” some git subtrees under /.bash/subtrees.

One subtree of note is shist which is my Bash implementation of advanced shell history. This integrates with Bash prompting to record history in an Sqlite3 database.

I strongly avoid using alias (eg, no ll for ls -l) as I think inventing my own Unix command set is an anti-pattern. I do capture some larger commands in Bash functions so that tab-completion can remind me of the (eg, a bunch of emacs-server-* functions to manage different Emacs servers).

I used to loop over $HOME/opt/*/{bin,lib,man,lib/pkgconfig} to set PATH, LD_LIBRARY_PATH, MANPATH, PKG_CONFIG_PATH. This I now deprecate in favor of a Stow-based install for common software and a per-development area governed by direnv. See Source for more info on this aspect.

Desktop Environment #

By which I mean what the X11 (and not wayland) server manages.

I have fully migrated from the really great Sawfish to the equally delightful though different Herbsluftwm. I’ve used Sawfish since it was the official Gnome WM back in the 90’s (back before Gnome put sugar before protein). Sawfish is really a terrific stacking/floating WM but I wanted to move to a tiling paradigm. Sawfish has some rudimentary support for tiling and I initially toyed with contributing to its development but figured I should first try some “real” tiling WMs. Along came Herbsluftwm which I chose over the others initially because it had these nice graph diagrams right in the man page. I’ve since looked at others (awesome, i3, dwm) and they are nice but I got lucky on the first draw and have fallen deeply for it. So, I bid Sawfish a fond farewell and wish the community all the best (there are tens of us!).

Herbsluftwm #

Herbstluftwm [German for autumn wind(ow manager)] is configured by issuing commands from the client application herbstclient (hc). These commands are typically captured in two files:

autostart
main configuration holding keybindings, theme settings and starting any “panels”
panel.sh
a long running process transforming WM events (via hc --idel) and others into input piped to a “bar” program (dzen2 is default and nice but I moved to using barpyrus which is started directly instead of a panel.sh)

A lot of great shell hackery exists in this space including the default event-driven panel.sh which taught me a thing or three. But, I wanted to rely on something more “formal” so created herbie. It contains Python reimplementations of a lot of Herbsluftwm community shell hackery as well as a few new things. It’s documentation describes how to configure and integrate into autostart.

Barpyrus #

Also from author of herbstluftm, this provies a Python wrapper around lemonbar and replaces the default panel.sh driving dzen. It is configured with Python and my config is hugely inspired by barpyrus.py from https://github.com/the-compiler/dotfiles. My minor improvement was to add some unicode icons and a few additional metrics.

Setting the fonts is an important detail. In main():

bar = lemonbar.Lemonbar(
    geometry=geom,
    cmd="/usr/local/bin/lemonbar",
    font=f'DejaVu Sans-{font_height}',
    symbol_font=f'FantasqueSansMono Nerd Font-{font_height}',
    foreground=Gruv.FG, background=Gruv.BG)

Where font_height is determined based on host and monitor size. Toward the top of main():

import socket
host = socket.getfqdn()
monitor = int(sys.argv[1]) if len(sys.argv) >= 2 else 0
x, y, monitor_w, monitor_h = hc.monitor_rect(monitor)
if int(monitor_h) <= 1080:
    height = 16
    font_height = 12
elif host == "hometop":
    height = 24
    font_height = 12
elif ...

Rofi #

I use rofi for various things. herbie calls it and is called by it and it is called by various herbstluftwm keybindings.

  • rofi-screenshot custom script to take screen shots and optionally upload them to a popular image host with help of maim and rephile. See Photos.
  • rofi-pass for accessing my password store (see Passwords)
  • built in launcher with nice icons
  • global and per tag window selection
  • herbstluftwm “task based” tag management via herbie
  • herbstluftwm tag layout management via herbie

Like with kitty, a ~/.config/rofi/config-(hostname).rasi file which is symlinked to config-host.rasi holds the per host customization. Mostly this is to set a font size that works well for the host’s monitor(s). For example, for a 4k 15" laptop monitor screen.

configuration {
  font: "FantasqueSansMono Nerd Font 44";
}

Sawfish #

The Sawfish X11 window manager was at one time the official WM for Gnome. That is the time when I first started using it, moving from TWM and then FVWM. I’ve tried a few since but always come back. Sawfish is configured and largely written in its own flavor of lisp (rep) and so can reasonably be considered the Emacs of window managers. For configuration, it does an even better job than Emacs of providing both a programmable and a GUI configuration method and the two work largely well together. Some of the reasons I use Sawfish:

  • hugely configurable but sane defaults
  • my fingers have learned the key bindings I chose years (decades!) ago
  • I bake the configuration into a git repo
  • I can run an arbitrary program from a command line without opening a terminal
  • tab-like navigation between virtual desktops
  • window “filling” which I find a better compromise between stacking and tiling idioms
  • window dressing with themes and per matched windows (eg, Firefox has no borders)

Desktop environment #

I largely have moved away from using a full DE. I used MATE (Gnome 2) with Sawfish up until switching to Herbstluftwm. All the MATE-provided bits now get replaced piecemeal. Some of note:

  • rofi for starting apps and various other menu-oriented actions
  • barpyrus for indicators and “workspace” tabs (Herbstluftwm “tags”)
  • nmtui replaces the Network Manager applet
  • caja I still keep around for rare times I want a GUI to browse a directory

Web #

Firefox #

Firefox is the least worse web browser despite how Mozilla tries so hard to kill off its user base. Not much to say except how I battle some of its worse behavior:

Load URL via remote without grabbing attention #

Set browser.tabs.loadDivertedInBackground to true in about:config. Otherwise sending a URL via remote open will have Firefox grab focus, possibly switching to it on a different virtual desktop. This is super annoying when doing important things like loading the morning’s web comics from liferea.

Emacs-like keybindings in firefox #

This is one of the most frustrating things and most of the things found online are wrong. What to do depends on the desktop environment and its version and maybe the distribution.

Debian buster and MATE 1.20.

gsettings set org.mate.interface gtk-key-theme 'Emacs'

Or,

~/.config/gtk-3.0/settings.ini:

# Get firefox to use emacs keybindings
[Settings]
gtk-key-theme-name = Emacs

For editor about:config and

devtools.editor.keymap emacs

Using Emacs to edit text #

There used to be ItsAllText. Now there is Edit with Emacs and GhostText. The former I could not make work and the latter seems fine.

GhostText needs atomic-chrome to be running on Emacs. It’s available from the Emacs package sites. In Emacs servers I describe how the Emacs server for atomic-chrome to talk to get started. The main Emacs parts in init-atomic-chrome.el are:

(setq server-name "atomic-chrome")
(use-package markdown-mode
  :ensure t
  :config
  (setq markdown-command "/usr/bin/markdown"))
(use-package markdown-preview-mode
  :ensure t)
(use-package atomic-chrome
  :ensure t
  :config
  (setq atomic-chrome-default-major-mode 'markdown-mode)
  (setq atomic-chrome-url-major-mode-alist
        '(("github\\.com" . gfm-mode)
          ("reddit\\.com" . markdown-mode)
          ("redmine" . textile-mode)))
  (setq atomic-chrome-buffer-open-style 'frame)
)
(atomic-chrome-start-server)

To use, I click the GhostText icon, sometimes it prompts me for which text area to edit, then an Emacs frame pops us. As I type in Emacs the text entry updates.

  • TODO get nice rendered preview for GitHub and Reddit text entries

Bookmark capture #

I want to capture bookmarks to Emacs Org files. I mainly use https://github.com/karlicoss/grasp for that. It uses a Firefox add-on to send info to a grasp server written in Python. The add-on does a better job actually working on all sites (eg, GitHub causes problems with org-protocol described below). While this is an Emacs-free capture system, the resulting files are in good org-mode markup.

The other method I tried is with a Firefox bookmarklet to initiate org-protocol based capture:

javascript:location.href='org-protocol://capture://w/'+encodeURIComponent(location.href)+'/'+encodeURIComponent(document.title)+'/'+encodeURIComponent(window.getSelection())

The /w/ corresponds to an org capture template

(setq org-capture-templates
      (quote
       (("w" "Web Bookmark" entry
         (file+headline "~/org/webcapture.org" "Bookmarks")
         "* %a :website:%^G\n:PROPERTIES:\n:CREATED: %U\n:END:\n%i\n %?"
         :empty-lines 1 :immediate-finish nil)))
      org-agenda-files (list "~/org/webcapture.org"))

Some frame management is done with:

(defadvice org-capture
    (after make-full-window-frame activate)
  "Advise capture to be the only window when used as a popup"
 (if (equal "emacs-capture" (frame-parameter nil 'name))
     (delete-other-windows)))

(defadvice org-capture-finalize
    (after delete-capture-frame activate)
  "Advise capture-finalize to close the frame"
  (if (equal "emacs-capture" (frame-parameter nil 'name))
      (delete-frame)))

Kill Sticky #

The web is mostly festering garbage and getting worse over time. Many web sites, even ones that should know batter (stack overflow) put up so much obscuring crap that it can be hard to see the content. Enter Kill Sticky (not a Tarantino movie, but better). It is this bookmarklet:

javascript:(function()%7B(function%20()%20%7Bvar%20i%2C%20elements%20%3D%20document.querySelectorAll('body%20*')%3Bfor%20(i%20%3D%200%3B%20i%20%3C%20elements.length%3B%20i%2B%2B)%20%7Bif%20(getComputedStyle(elements%5Bi%5D).position%20%3D%3D%3D%20'fixed')%20%7Belements%5Bi%5D.parentNode.removeChild(elements%5Bi%5D)%3B%7D%7D%7D)()%7D)()

Click is not select all #

One of the more infuriating things which changed in somewhat recent Firefox versions is that clicking on the urlbar selects the damn content. This is such disgusting reprehensible behavior that I would not be surprised if its existence is evidence that Chrome developers are operating as moles inside the Firefox organization.

Thank ioctl for the work of https://github.com/SebastianSimon/firefox-omni-tweaks. Running this nicely written bash script will munge some omni.ja files in the FF install to undo the mess.

❯ wget -O scripts/fix-firefox-omni 'https://raw.githubusercontent.com/SebastianSimon/firefox-omni-tweaks/master/fixfx.sh'
❯ chmod +x scripts/fix-firefox-omni
❯ fix-firefox-omni -f /usr/lib/firefox-esr -o preventClickSelectsAll

Finally, restart FF and sigh with deep contentment.

Audio/Video #

mpv #

I use mpv for just about all A/V. I also try to make it run for YouTube and the like as it is less resource intensive than YT’s web page on FF. See the section Open below for how things are routed to mpv. Calling

mpv --profile=yt <youtube-url>

Will invoke this section of ~/.config/mpv/mpv.conf

[yt]
script-opts=ytdl_hook-ytdl_path=yt-dlp
ytdl-format=137+251

This requires yt-dlp installed. It also does not always work for reasons I do not understand. Either YT does not have the formats and the command fails outright or YT sends data so damn slowly that the stream constantly pauses to buffer. Outright failure is checked for in web-browser (see Open below) and the URL is fail-over dispatched to x-www-browser.

Source #

See also Configuration and individual package sections. Here I describe ways I install software locally which means outside of Debian’s package management.

DIY opt #

For some development dependencies, I will build and install using $HOME/opt/<pkg> as the install “prefix”. I try to avoid making these part of day-to-day environment.

Stow #

I used to follow the DIY opt method to provide software that is built from source until I had a weird time traveling revelation. I’m essentially the only user on most machines where I need what was in DIY opt so why not just install to /usr/local. The one thing that was lacking was pristine uninstallation. To get that I started using the venerable GNU Stow package.

Even though implemented in Perl, GNU Stow works great (joke)! One-time setup

# mkdir /usr/local/stow
# chgrp staff /usr/local/stow
# chmod g+s /usr/local/stow
# sudo adduser bv staff

I then install from source to a location under the Stow directory with a name based on the package name and version. Eg

$ ./configure --prefix=/usr/local/stow/rofi-1.6.1/
$ make -j (nproc)
$ make install

Then finish with

# cd /usr/local/stow
# stow rofi-1.6.1

Common source setup reminders #

CMake #

$ mkdir ~/opt
$ cd pkg
$ mkdir build && cd build
$ cmake -G Ninja .. -DCMAKE_INSTALL_PREFIX=$HOME/opt/pkg [...]
$ cmake --build . -- -j$(nproc)
$ cmake --build . --target install

autoconf #

$ mkdir ~/opt
$ cd pkg
$ ./autogen
$ ./configure --prefix=$HOME/opt/pkg
$ make -j$(nproc)
$ make install

Python #

When I work on a Python package I use direnv (see also Shells) do:

# apt install direnv
$ cd a-python-package/
$ echo layout python3 > .envrc
$ direnv allow
$ pip install -e .

A lesser way but which does not require direnv

$ python3 -m venv venv
$ source venv/bin/activate
$ pip install -e .

Things I explicitly don’t use #

Spack #

Spack is great for managing complex and shared software deployments. From time to time I have used it for managing personal software. That has been modus hiatus for a while due to various minor annoyances related to personal usage. A lot has changed with Spack since then and I have some plans to revisit this approach.

Nix/Guix #

I have used Nix and Guix to provide add-on environments. They always start out great but turn horrible. In part, I just can not get a handle on the Nix language. Guix’s use of guile is much better but it’s like learning Emacs, it’s a deep rabbit hole. Like Spack, this remains an anti-use.

Photos #

See also Syncthing for how photos are extracted off my phone.

Rephile #

I used to dump photos from scans, cameras or phones into various directories. This grew organic and I’ve lost chunks of memories when directories went missing. So I got “serious” and wrote rephile. It still allows a distributed store sprinkled around various directories and it supports git-annex repositories. It keeps an sqlite database of metadata and has some extras such as uploads to a popular image host.

Sync #

Syncthing #

Syncthing is a jewel of a system. It’s your own personal peer-to-peer (which here means you-to-you or you-to-friends not you-to-anonymous-strangers) file transfer system. Encryption, distribute hash table, UDP hole punching, simple beautiful web interface, cross platform. What more can you ask for?

I run it on my android phone and all Linux machines, home and at work. For the phone I sync photos and org files. For Linux machines various things but in particular a ~/sync/ is shared between all and holds mostly my talks. My ~/org/ holds my personal “wiki” where I hold proto-documents, notes, etc as well as bookmarks grabbed as described above.

One caution: the optional use of relay for data is safe and can be useful to get around tricky routing problems (both ends behind very strict firewalls) but take note that some hosts that provide Syncthing relay are also TOR nodes. Despite these being wholly separate data streams, some idiot “security” mechanisms will flag your Syncthing as a TOR node because it happens to connect to an Internet host which also happens to provide a TOR service.

Git annex #

tbd. git + big files + sync rules + metadata. Used for photos and other.

Passwords #

Pass #

I use pass to manage my passwords and distribute them via a private repo in my personal Gitea instance. I almost never use the same password for different endpoints and almost always use high character random passwords which I never bother to remember. pass makes that possible and easy.

Time #

arbtt #

At work we have to “track” our time even though we don’t get payed hourly. It feels to me a very annoying and demeaning thing. I “protest” by keeping hugely, massively, stupidly pedantic track of my time. I know, it’s nonsensical and weird but it allows me to comply without raising my blood pressure. Fight idiocy with lunacy, I always say.

I do this by running arbtt on my work computers. It starts with cron

$ crontab -l |grep arbtt
@reboot /home/bv/scripts/start-arbtt-capture

When my employer nags me to enter this very crucial data I run a script

$ time-sheet
...
heather,Sat,2020-05-02,0.87,1.45
heather,Sun,2020-05-03,1.68,1.68
heather,Mon,2020-05-04,2.24,6.77
heather,Tue,2020-05-05,2.80,7.89
heather,Wed,2020-05-06,2.99,5.79
heather,Thu,2020-05-07,8.47,9.47
heather,Fri,2020-05-08,3.49,9.16
heather,Sun,2020-05-10,2.30,3.24

Second to last column shows total hours my session was active, last column is time diff between last action and first in the day (MTW I was on “vacation” so less than nominal eight).

Time zones #

I have a hacked scrip to help me with timezones

$ time-to-meet tomorrow
February 10, 2021
Here          08  09  10  11  12  13  14  15  16  17  18  19  20
UTC           13  14  15  16  17  18  19  20  21  22  23  24  25 (+5)
Los_Angeles   05  06  07  08  09  10  11  12  13  14  15  16  17 (-3)
Chicago       07  08  09  10  11  12  13  14  15  16  17  18  19 (-1)
London        13  14  15  16  17  18  19  20  21  22  23  24  25 (+5)
Zurich        14  15  16  17  18  19  20  21  22  23  24  25  26 (+6)
Japan         22  23  24  25  26  27  28  29  30  31  32  33  34 (+14)

I’ve since redone this in Python at https://github.com/brettviren/titome

❯ titome
                         today: Friday 11/26 09:00 (2 hours ago)
┏━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┳━━━━━━━┓
┃ local ┃  9:00 ┃ 10:00 ┃ 11:00 ┃ 12:00 ┃ 13:00 ┃ 14:00 ┃ 15:00 ┃ 16:00 ┃ 17:00 ┃ 18:00 ┃
┡━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━╇━━━━━━━┩
│ LBNL  │  6:00 │  7:00 │  8:00 │  9:00 │ 10:00 │ 11:00 │ 12:00 │ 13:00 │ 14:00 │ 15:00 │
│ FNAL  │  8:00 │  9:00 │ 10:00 │ 11:00 │ 12:00 │ 13:00 │ 14:00 │ 15:00 │ 16:00 │ 17:00 │
│ BNL   │  9:00 │ 10:00 │ 11:00 │ 12:00 │ 13:00 │ 14:00 │ 15:00 │ 16:00 │ 17:00 │ 18:00 │
│ RAL   │ 14:00 │ 15:00 │ 16:00 │ 17:00 │ 18:00 │ 19:00 │ 20:00 │ 21:00 │ 22:00 │ 23:00 │
│ CERN  │ 15:00 │ 16:00 │ 17:00 │ 18:00 │ 19:00 │ 20:00 │ 21:00 │ 22:00 │ 23:00 │  0:00 │
│ KEK   │ 23:00 │  0:00 │  1:00 │  2:00 │  3:00 │  4:00 │  5:00 │  6:00 │  7:00 │  8:00 │
└───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┴───────┘

Meetings #

Most people around me use “doodle” which is kind of a pain. when2meet is far superior.

Open #

The whole story surrounding opening files is insane, especially once one leaves the manicured gardens of big name DEs (Gnome and the like). Thankfully others are as fed up as me and have come up with good solutions. Central to mine is using https://github.com/chmln/handlr. I call handlr open through my own open script which I used on the CLI or set to be called from kitty, liferea, etc.

Via handlr commands I manually set an explicit mapping from mime types to .desktop files. The former in ~/.config/mimeapps.list and the latter under ~/.local/share/applications/. All of this goes into the vcsh repo dots.

The handlr open call can also handle URLs which I map to a web-browser.desktop that simply calls my web-browser script and that dispatches the URL to an application based on pattern matching. Some of the more used dispatching:

  • video looking URLs go to mpv --profile=yt (see section on mpv)
  • twitter looking URLs get rewritten to nitter.net

Todo #

  • factor vcsh repos to move non-secret dotfiles to github and link to them from here
  • section on operating system, Debian GNU/Linux
  • section on ssh (many tips/tricks, jsonnet-based config)
  • section on vpn (nord, linux, phone, router)
  • section on router (tomato firmware)
  • rss
  • videos