~/starikov

Dotfiles

A decade of shell, tuned until one command themes every app at once.

Dotfiles — preview

Story

The git history starts in March 2017. The habits are older than that. This is the home directory I have carried across every machine I have owned for the better part of a decade — the editor, the shell, the prompt, the git config, the theme — and it has been refined by daily use the entire time. Nothing here is aspirational. If a setting survived, it earned it by never getting in my way.

That longevity is the whole point. A dotfiles repo you rewrite every year is a hobby. One you keep for ten is infrastructure. Roughly 90.8K lines across 770 files sounds like a lot until you realise every one of them is a decision I have made more than once and would make again — a keybinding I reach for without thinking, a formatter I trust to not mangle a file, a color I want in front of me at 2am.

The signature is theme switching. Type theme moon and the terminal, the editor, tmux, the prompt, bat, and delta all change together, atomically, in under half a second. It also follows macOS: flip the system into dark mode and the whole toolchain follows. This site is the ninth thing that palette drives — the colors you are reading right now are generated from the same colors.json files that theme my terminal. That is not a metaphor. It is a build step.

Everything below is measured. The numbers are reproducible from a checkout; I lead with them because in a dotfiles repo the numbers are the argument.

Highlights

90.8K lines

Ten years, still in daily use

Some 770 tracked files, versioned since 2017, installed with a single install.sh and removed just as cleanly. macOS and four Linux package-manager families from the same tree. It is battle-tested in the most literal sense — every line has been in my way at least once and stayed anyway.

1,188 lines

fixy, one formatter for everything

fixy is a single 1,188-line zsh script that picks the right formatter for whatever you hand it: 31 formatters wired across 60 file types, priority-ordered so ruff beats black beats autopep8 on Python and the right tool always wins. One command — fixy --all file — normalizes trailing whitespace, tabs, and smart quotes, then formats and sorts. I never think about which formatter a file needs.

57 variants

The theme engine

57 theme variants across 17 families, each expressed as one colors.json. A switch rewrites 8 applications — Alacritty, WezTerm, Kitty, tmux, Starship, Neovim, bat, delta — in under 500ms, atomically, and auto-syncs with the macOS appearance. This is the engine this website is built on: app number nine.

~150ms cold start

Neovim that stays fast

More than fifty plugins managed by lazy.nvim, and it still cold-starts in about 150ms on an M1 — LSP for twenty-plus languages, completion, AI, and a full Telescope setup, none of it paid for at startup. Fast is a feature you notice a hundred times a day.

376 test functions

Dotfiles you can actually test

376 test functions across unit, functional, integration, performance, smoke, stress, and end-to-end suites, run by 6 GitHub Actions workflows. A config repo that tests itself sounds like overkill right up until an OS update quietly breaks your shell and the suite tells you before you find out the hard way.

80 documents

Written down, not remembered

80 markdown documents — a README beside almost every component, plus setup, usage, and customization guides. Future-me is the primary reader. The docs are why I can leave this alone for six months and still know how the theme pipeline fits together.

Architecture

The repo is three trees. src/ holds the configs and the machinery: the Neovim setup, the zsh environment, the git config, the scripts/ (where fixy lives), and theme/, the switching engine with its per-family colors.json and app templates. test/ holds the 376 test functions, bucketed by kind. doc/ holds the 80 guides. config/ carries the data the scripts read — fixy.json’s formatter table, themes.json’s manifest of all 57 variants.

The theme switch is the piece I am proudest of, and it turns on one small, boring detail: the file swap has to be atomic. If a running shell reads its theme file mid-write, it gets garbage. So every app’s theme is copied to a temp sibling and renamed into place — mv on the same filesystem is atomic, so a reader sees either the old file or the new one, never a torn one:

# Copy a theme file into place without a torn read: write to a temp
# sibling, set its mode, then rename. mv on one filesystem is atomic,
# so a shell reading its theme never sees a half-written file.
atomic_update() {
  local source="$1" dest="$2" mode="${3:-644}"
  [[ -f "$source" ]] || { log "Source file not found: $source" "WARN"; return 1; }

  local temp_file="${dest}.tmp.$$"
  cp "$source" "$temp_file"  || { rm -f "$temp_file"; return 1; }
  chmod "$mode" "$temp_file"
  mv -f "$temp_file" "$dest"  || { rm -f "$temp_file"; return 1; }
}

That block is highlighted live by Shiki’s css-variables theme — the colors are this site’s current palette, drawn from the same theme engine the code is about. Switch themes in the sidebar and watch it recolor. That is the whole story in one paragraph of shell.

Auto-generated from IllyaStarikov/.dotfiles@f274559 Overlay last edited 2026-07-18