My command-line environment: the configuration for my terminal, shell, editor, and the tools I use with them.
Alacritty is the terminal, tmux runs inside it, zsh with Starship is the shell, and Neovim is the editor; Homebrew installs them, and GNU Stow links their configuration into place.
It also holds enough to rebuild that environment on a new Mac without my having to remember how I assembled it the first time.
This is one person's setup, not a framework.
Take whatever is useful, and expect to disagree with some of it.
If you build on this, a link back to the repository would be appreciated.
That is the environment sitting still.
This is what it does when you press a key: Ctrl-T opens fzf in a tmux popup,
fd supplies the list, and bat draws the preview.
You need an Apple Silicon Mac, the Xcode Command Line Tools
(xcode-select --install), and Homebrew.
Setup checks for all three and stops if any is missing rather than installing them for you.
Install Alacritty first.
Setup does not check for it, but it links the terminal description, the
alacritty command and the manual pages that ship inside the app, and it can
only do that if the app is already there.
Homebrew disabled its Alacritty cask on 2026-09-01 because the app fails macOS
Gatekeeper checks, so the .dmg comes from the project's releases.
Move Alacritty.app into /Applications and open it once.
macOS blocks that first launch; within about an hour, click Open Anyway in System Settings → Privacy & Security, and enter your login password.
git clone https://github.com/olegturzhanskii/dotfiles.git ~/dotfiles
cd ~/dotfiles
./bootstrap.sh --dry-runThe dry run prints exactly what would happen and changes nothing.
When the plan looks right, run ./bootstrap.sh.
flowchart LR
A["Check the machine"] --> B["Show the plan"]
B --> C{"Confirm"}
C -->|no| D["Stop — nothing changed"]
C -->|yes| E["Install tools"]
E --> F["Link configuration"]
F --> G["Generate what tools need"]
Each step is a separate file in scripts/ that you can also run on its own.
Install tools — everything missing from Brewfile, via Homebrew.
Link configuration — every file here gets a symbolic link where its tool
expects it, so alacritty/.config/alacritty/alacritty.toml becomes
~/.config/alacritty/alacritty.toml.
Editing either one changes both.
Generate what tools need — Alacritty's terminal description, command and
manual pages, tmux plugins, and the tldr page cache.
It never overwrites or deletes a file you already have; if something is in the way, it reports the conflict and stops before linking anything.
Where Stow is already installed, that check runs before anything changes; on a new Mac, Stow comes with the Brewfile, so the check runs once the Brewfile's packages are installed.
It never upgrades software that is already installed, never touches Git, and never installs the optional Brewfiles.
Every file it creates is a symbolic link:
stow --delete --dir="$HOME/dotfiles" --target="$HOME" \
alacritty tmux nvim bat eza git htop lazygit mc starship task tealdeer zshTools that Homebrew installed stay installed.
./bin/doctorRead-only.
It reports whether your machine matches this repository and names the fix for anything that does not.
Brewfile is authoritative and lists only tools this repository configures, so
that brew bundle check means something.
Brewfile.extras is general-purpose tools I use but do not configure here, and
Brewfile.toys is fun things, because a terminal is allowed to be enjoyable.
Brewfile.optional is private and never committed, and
Brewfile.optional.example is the tracked template that explains the pattern.
Only the first is installed by setup:
brew bundle install --file=Brewfile.toysThis split is the most useful idea to take from here.
Public is everything you can see: configuration anyone may read and copy.
Private is configuration that works but says something about me — where I
live, who I work with — and lives in Brewfile.optional and
~/.config/git/config.local, both ignored and neither present here.
Generated is what a machine builds for itself: caches, plugin clones, completion dumps.
Setup links individual files rather than whole directories so that generated state has nowhere to land in this repository.
Secrets appear nowhere in this design, and the checks workflow scans the whole history with gitleaks to keep that true.
Set your Git identity.
cp ~/.config/git/config.local.example ~/.config/git/config.localYour commit email becomes public the first time you push, so choose it deliberately.
Enable Touch ID for sudo inside tmux, if you want it.
pam-reattach is installed for you, but loading it means adding two lines to
/etc/pam.d/sudo_local, which needs your password; gotchas.md has them, and
says why that file.
Nothing here updates itself, with one exception: tealdeer refreshes its own
page cache daily.
./bin/outdatedThat reports what is available and upgrades nothing; it refreshes Homebrew's own index first.
The commands that actually update things are in docs/maintenance.md.
If you came here for one specific thing rather than for a setup.
| Question | Where |
|---|---|
Why does TERM=alacritty not resolve on macOS? |
gotchas.md, and scripts/40-derived-state.sh |
| How does copying in the terminal reach the macOS clipboard, even inside tmux or over SSH? | tmux.conf turns on set-clipboard and the clipboard terminal feature, which is OSC 52 |
| Which programs come back after a tmux restart, and which only look like they did? | gotchas.md, and the @resurrect-processes note in tmux.conf |
| Why does the Option key not work as Alt? | alacritty.toml; without option_as_alt nothing in the terminal ever receives Meta |
| How do I stop tools writing into my dotfiles repository? | stow --no-folding, in scripts/30-configuration.sh and design.md |
| Which of these files does its own tool rewrite? | design.md; six of them, and only one has a switch that stops it |
| How do I get zsh completions for a tool that ships none? | plugins.zsh, where generated completions are installed as zinit plugins |
How do I keep completions in step with uv tool install? |
plugins.zsh, driven by the receipt files uv writes for itself |
| How do I edit a file on another machine without mounting it? | mc/.config/mc/ini; mc opens sftp:// in a panel, and F3 and F4 still run the local bat and nvim |
| Is this process running under Rosetta, or natively? | htop/.config/htop/htoprc, which adds htop's TRANSLATED column |
| How do I get a structural diff without giving up delta? | git/.config/git/config; delta stays the pager and difftastic is the difftool |
| How do I keep private configuration out of a public repository? | Brewfile.optional.example, and the checks in bin/doctor |
Does a Brewfile have to list everything I have installed? |
design.md |
| How reproducible is this without Nix, and where does reproducibility stop? | design.md |
Generative AI did a substantial part of the engineering work on this repository, through models of two families: Claude, by Anthropic, and GPT, by OpenAI.
The configuration itself is largely my own: which tools make up the environment, how each is set up, and what the setup should leave alone were decided, and for the most part written, by me.
The models' part came on top of that, and it was a large one: Claude models extended and refined the configuration, investigated how a tool behaves before a setting relied on it, wrote the checks and the hooks, and improved the documentation, including the write-ups of the traps it records.
GPT models worked with me on the reasoning: what the environment should do, whether a workaround deserved to stay, and what the documentation still left unsaid.
Each change was reviewed before it was committed, and tested as the change called for: a script by running it, a setting by working with it.
The environment and the decisions behind it are mine, and so is the responsibility for them.
docs/design.md — how the project is put together and what it promises.
docs/theming.md — changing the colors.
docs/maintenance.md — updating.
docs/gotchas.md — nine things that fail confusingly, and why.
THIRD-PARTY.md — what here is not mine.
MIT, in LICENSE.
Take whatever is useful.


