# My setup
How I use my computers.
## Contents
## Directory layout
I have found a satisfactory directory layout
for my personal data.
It took surprisingly long to arrive at it
by gradual iteration,
which suggests it isn't obvious and there is value in sharing it.
My directories are organized like this:
- `sync/`
- `archive/`
- `2000/`
- `2001/`
- ...
- `2024/`
- ...
- `projects/`
- `2000/`
- `2001/`
- ...
- `2024/`
- `active/`
- ...
Here,
`sync/` is the root directory that is synchronized between computers using
[Syncthing](!W).
I keep it in my home directory on Linux.
It has two main subdirectories: `archive/` and `projects/`.
Trailing slashes
Depending on the context,
I write directory names with a trailing slash to differentiate directories from files.
I adopted the practice after trying
[Rebol](!W),
where paths with a trailing slash are a separate data type from paths without.
A kindred setup
I have found that
[Risto Saarelma](https://rsaarelm.github.io/the-setup)
has a similar directory setup,
which he has called
[`~/hearth/`](https://www.merriam-webster.com/dictionary/hearth%20and%20home).
The `projects/` directory contains my projects:
mostly software,
but also writing, art, audio, etc.
I have found that the best way to organize my projects is by the year they were started:
- Not grouping projects at all leads to too many in one directory.
- Grouping by category doesn't work because projects belong in more than just one category.
Simulating multiple categories (tags) with
[symlinks](!W "Symbolic link")
is brittle.
(For example,
you must update all links when you change the project name.)
I only use symlinks in the `active/` subdirectory,
which contains links to projects that I frequently access or work on.
The symlinks are relative.
For example,
`active/hicolor` links to
[`../2021/hicolor/`](https://github.com/dbohdan/hicolor)
Project directory names are normally limited to lower-case English letters, numbers, and dashes.
They do not contain spaces.
This is convenient on the command line.
One problem I had for a long time
was the lack of a standard place to store
and way to name things that weren't projects,
like screenshots, logs, notes, single webpages, etc.
I have found that it is best to organize them "even more" chronologically than projects,
preferably by year-month-day.
However,
deep directory structures
like `2023/10/29` with only one or a few items in each
[leaf](!W "Tree (data structure)#Terminology")
directory
are difficult to get an overview of and to manipulate.
Therefore,
I organize my archive by year and prefix the month and day to the filename.
For example,
I could have a file
`archive/2023/11-27-storm.flac`.
The name means the file was archived on November 27, 2023
(but not necessarily created at that time;
I am not super strict about which date to use
as long as it helps find and group the item).
For items created by or received from other people,
I add their name or online nickname to the prefix.
For example,
it could be
`archive/2020/08-10-someone-letter.txt`.
The items in `archive/` can also be topical directories with a month-day, month, or no prefix.
I normally add a day or a month-day prefix to the filenames
inside those directories.
The `sync/` directory is an encrypted [ZFS](!W) volume.
It is backed up using [BorgBackup](https://www.borgbackup.org/)
and ZFS snapshots via
[Sanoid](https://github.com/jimsalterjrs/sanoid).
ZFS has checksums that prevent silent data corruption.
I keep photos in a separate directory hierarchy outside `sync/`.
This allows me to synchronize them and back them up less frequently.
It also reduces the size of `sync/` and its backups.
## Dotfiles {#dotfiles}
My approach to [dotfiles](!W) is to maintain them in a separate directory under version control and deploy them to the home directory from there.
I keep the dotfiles in `~/sync/dotfiles/`, which is a Git repository.
It contains the subdirectories `home/` and `root/`, a few lists of packages ([APT](!W "APT (software)"), [Cargo](https://doc.rust-lang.org/cargo/), [Fisher](https://github.com/jorgebucaran/fisher), [Go](https://pkg.go.dev/cmd/go#hdr-Compile_and_install_packages_and_dependencies), [uv](https://docs.astral.sh/uv/guides/tools/)), and a Python deployment script.
The configuration files and directories are stored in `home/` without the leading dot in their name.
This gives you an easy overview with `ls`.
It means that, for example, `.config/` is stored as `home/config/` and `.vimrc` is stored as `home/vimrc`.
The deploy script rsyncs every item in `home/` to the home directory, prepending a leading dot to its name in the destination.
When the script has synced an item in `home/`, it expands every [Jinja](!W "Jinja (template engine)") template file `foo.conf.template` file to `foo.conf` with values specific to the machine.
## Filesystem navigation {#navigation}
### `ls` on `cd`
I have fish configured to list the current directory when I change it.
```fish
function ls_on_cd --on-variable PWD
ls
end
```
### Variables
I use variables with directory paths
for easier and faster navigation.
My main interactive shell is
[fish](https://fishshell.com/).
It has a
[`CDPATH` feature](https://fishshell.com/docs/current/cmds/cd.html)
feature,
but I find `CDPATH` inconvenient.
Good, short `CDPATH` names clash with good, short local directory names;
you must remember to use `cd ./foo` instead of `cd foo`
if `foo` is in `CDPATH`.
As an alternative,
I began setting special variables and using their values with `cd`.
They include
`pr` for `projects/`
and `ar19` for `archive/2019/`.
So,
for example,
I would use `cd $ar19` to change my working directory to `archive/2019/`.
This is a fragment of my fish config that sets these variables
(somewhat simplified for clarity).
```fish
# No trailing slashes so `$var/foo` doesn't have two slashes before `foo`.
set -x ar $HOME/sync/archive
set -x pr $HOME/sync/projects
set -x pra $HOME/sync/projects/active
set -x sy $HOME/sync
for year in (seq 2000 (math (date +%Y) + 1))
set year2 (printf '%02u' (math $year % 100))
set -x ar$year2 $HOME/sync/archive/$year
set -x pr$year2 $HOME/sync/projects/$year
end
set -e year
set -e year2
```
#### zoxide
My use of directory path variables made me underestimate the usefulness of "jumping around" directories
with a learning command like
[z](https://github.com/rupa/z)
and its derivatives.
I loved this mode of navigation when I tried it
and regretted not using it earlier.
It has supplanted most,
but not all,
my use of directory path variables.
After testing
[jethrokuan/z](https://github.com/jethrokuan/z)
and
[jump](https://github.com/gsamokovarov/jump),
I found what I wanted in
[zoxide](https://github.com/ajeetdsouza/zoxide).
jump differs from other programs in this family:
jump fuzzy-matches paths,
while others match exact substrings.
At first jump's design seemed clearly superior to me,
however,
I grew tired of getting a random directory when there was no good match,
like `/home/user/foo/bar/` for `sa`.
When I tried zoxide,
it saying "no match found" felt like an improvement.
Another thing I prefer in zoxide is that the command `z` on its own takes you to your home directory;
you can repeat `z foo` to go through matches for `foo`.
In jump,
`j` on its own takes you to the next match for the arguments you gave before;
`j foo` goes between two top matches for `foo`.
I recommend zoxide out of this class of programs.
Try jump in case you prefer its style.
## Rclone
I have come up with a convention for using
[Rclone](https://rclone.org/).
To make sure I don't accidentally send files to an unencrypted remote,
I prefix the names of unencrypted remotes' names with `UNENCRYPTED-` in all caps
then layer an Rclone-encrypted remote without the prefix over it.
My remotes are named `[-]-`.
For example,
I could name an SFTP remote `UNENCRYPTED-sftp-foo`;
then `sftp-foo` would be the encrypted layer.
In my usage
I would almost always refer to `sftp-foo`.
Where I don't need encryption
(for example,
for backups that are already encrypted),
I still prefix the remote's name with `UNENCRYPTED-`
but don't create its encrypted counterpart.
## Software choices
The "current" items here are listed roughly by how much I use them,
items in "history" roughly in the order I started really using them.
Items may be listed in "history" several times.
It means I took a break from using them or my use of them changed.
### OS
#### Current
- [Ubuntu](!W) LTS (desktop)
- [Debian GNU/Linux](!W "Debian") (laptop, servers, containers)
- [Alpine Linux](!W) (containers for building static binaries)
- [FreeBSD](!W) (servers)
#### History
- [System 7](!W)
- [Windows 95 OSR2](!W)
- [MS-DOS](!W)
- [Windows 98 SE](!W)
- [Red Hat Linux](!W)
- [SuSE Linux](!W) and other distributions and [live CDs](!W "Live CD")
- [Windows XP](!W)
- [Mac OS X "Tiger"](!W "Mac OS X Tiger") and ["Leopard"](!W "Mac OS X Leopard")
- [Debian GNU/Linux](!W "Debian") ([PowerPC](!W))
- [Windows 7](!W)
- [Linux Mint](!W)
- [FreeBSD](!W) (servers)
- [Windows 8](!W), [8.1](!W "Windows 8.1")
- [Debian GNU/Linux](!W "Debian") (servers)
- [Ubuntu](!W)
- [Windows 10](!W)
- [Alpine Linux](!W) (containers)
- [NetBSD](!W) ([SDF](https://sdf.org), VM)
- [OpenBSD](!W) ([tilde.institute](https://tilde.institute), VM)
- [FreeBSD](!W) (servers)
### Interactive shell
#### Current
- [fish](https://fishshell.com/)
#### History
- [`command.com`](!W)
- [Bash](!W "Bash (Unix shell)")
- [`cmd.exe`](!W)
- [Zsh](!W)
- [fish](https://fishshell.com/)
- [eltclsh](https://wiki.tcl-lang.org/page/eltclsh)
- [jimsh](https://jim.tcl-lang.org/)
### Scripting language
#### Current
- [Python](!W "Python (programming language)")
- [POSIX shell](!W)
- [Tcl 8.6](!W "Tcl")
#### History
- Intricate [batch files](!W "Batch file")
- [Perl](!W)
- [Bash](!W "Bash (Unix shell)")
- [Python 2](!W)
- [POSIX shell](!W)
- [Tcl](!W)
- [Jim Tcl](http://jim.tcl-lang.org/)
- [Bash](!W "Bash (Unix shell)")
- [Python 3](!W)
### Linux filesystem
#### Current
- [ZFS](!W) (everything but boot and root)
- [Btrfs](!W) (root)
- [ext4](!W)
#### History
- [ext2](!W)–[4](!W "ext4")
- [Btrfs](!W) (for everything)
- [ZFS](!W)
- [Btrfs](!W) (root)
### *nix desktop environment or window manager
#### Current
- [IceWM](https://ice-wm.org/)
#### History
- [GNOME 1](!W)
- [KDE 2](!W)–[3](!W)
- [Openbox](!W)
- [GNOME 2](!W)
- [MATE](https://mate-desktop.org/)
- [awesome](https://awesomewm.org/)
- [IceWM](https://ice-wm.org/)
### Text editor
#### Current
- [Vim](!W "Vim (text editor)")
#### History
- [Notepad2](https://www.flos-freeware.ch/notepad2.html) (see [Notepad3](https://github.com/rizonesoft/Notepad3) for a maintained fork)
- [Geany](!W)
- [ne](http://ne.di.unimi.it/)
- [Sublime Text](!W)
- [Vim](!W "Vim (text editor)")
- [Visual Studio Code](!W)
- [vis](https://github.com/martanne/vis)
- [Neovim](https://neovim.io/)
- Vim
### File manager
#### Current
- [Double Commander](http://doublecmd.sourceforge.net/)
- [Altap Salamander](!W) (Windows VMs)
#### History
- [Norton Commander](!W)
- [Volkov Commander](!W)
- [Far Manager](!W)
- [ForkLift](https://binarynights.com/)
- [Total Commander](!W)
- [Midnight Commander](!W)
- [Double Commander](http://doublecmd.sourceforge.net/)
- [Altap Salamander](!W) (Windows VMs)
### Remote interactive shell
#### Current
- [Mosh](https://mosh.org/) (where possible)
- [SSH](!W "Secure Shell")
#### History
- SSH (everywhere)
### Password manager
#### Current
- [KeePassXC](!W)
- [pago](https://github.com/dbohdan/pago) (scripts, cron jobs, and hosts without a GUI)
#### History
- [KeePass](!W "KeePass") 1 and 2
- [KeePassX](!W)
- [`pass`](https://www.passwordstore.org/) (scripts, cron jobs, and hosts without a GUI)
## See also
- [About this site](/about)
- [mkcd: The missing shell shortcut](/mkcd)
- [Organizing information](/organizing-information)
- [Small utilities](/small-utils)
- ["dotfiles"](https://wiki.archlinux.org/title/Dotfiles)
- ["My source code root folder name"](https://lobste.rs/s/m7eacj/my_source_code_root_folder_name) (2023)
- ["Policy of transience"](https://www.chiark.greenend.org.uk/~sgtatham/quasiblog/transience/), Simon Tatham (2025).
Interesting, and I see what it achieves, but not endorsed.
A policy like this is as if you give up on having the computer do the work for you.
I agree that a shell history that contains mistakes and is divorced from context, and therefore hard to search, is a problem.
Instead of keeping notes by hand, I think one should attack the problem in the shell.
For example, fish has successfully addressed the lack of context by keeping a shell history with paths and using this metadata to make suggestions.
Its history suggestions are different from those in Bash; they're _relevant_.
What I would like is not to copy a command to a function by hand but to label it in my shell history with a note that shows up when I search history.
- ["Curate your shell history"](https://esham.io/2025/05/shell-history), Benjamin Esham (2025).
A response that suggests cleaning your shell history instead of disabling it.
- ["Making the fish shell more forgetful"](https://alexwlchan.net/2023/forgetful-fish/), Alex Chan (2023)
- ["Reasons I still love the fish shell"](https://jvns.ca/blog/2024/09/12/reasons-i--still--love-fish/), Julia Evans (2024)
- ["The setup"](https://rsaarelm.github.io/the-setup), Risto Saarelma (2024)
- ["Tips on how to structure your home directory"](https://web.archive.org/web/20240510181231/https://unixdigest.com/tutorials/tips-on-how-to-structure-your-home-directory.html), unixdigest (2023)
## Page metadata
URL:
Published 2020-11-03, updated 2025-10-20.
Tags:
- configuration
- essay
- information retrieval
- me
- personal computing
- sysadmin
- Unix