Skip to content
rlazotiPublic

About

This repository contains all my dot files used in both Linux and Mac

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Repository files navigation

Rodrigo's Terminal Setup

My dotfiles for macOS — zsh, tmux, and dev tool configurations.

Features

Component Details
Shell Bare zsh (no Oh My Zsh) with autosuggestions, syntax highlighting, history substring search
Prompt Custom theme: git branch, dirty marker, ahead/behind, stash count, status icons — one git call per prompt
Tmux C-f prefix, mouse support with a toggle, powerline bar (session, host, IPs / load, cwd, branch), auto-start
Git Shorthand aliases (gcam, gck, gst...), helper functions (gbclean, gplb)
Tools bat, ripgrep, fd, htop, jq, tmux, emacs

A screenshot of the prompt and tmux bar is in docs/screenshot-mac.png.

Directory Structure

manifest.tsv        → the one link list: repo file -> dotfile in $HOME
Brewfile.core       → Core CLI tools (git, tmux, ripgrep, fd, bat...)
Brewfile.zsh        → Zsh plugins (autosuggestions, syntax-highlighting...)
Brewfile.editors    → Editors (emacs-plus@31)
Brewfile.dev        → Dev toolchains (ansible, pyenv)
Brewfile.apps       → GUI apps (iterm2, rectangle, github...)
bin/
├── setup.sh        Interactive installer; --links-only relinks dotfiles
├── check.sh        Health check
├── iterm2-export.sh  Exports iTerm2 prefs as reviewable XML
└── pi-dev-install.sh Auto-discovered by setup.sh (any *-install.sh)
zsh/
├── zshenv zshrc    -> ~/.zshenv ~/.zshrc
├── init.sh         Loads the layer below, then private.sh
├── git-prompt.zsh  Git prompt engine (one git call per prompt)
├── theme-powerline.zsh-theme  Colors and glyphs for the prompt
├── paths.sh        EDITOR and personal PATH additions
├── private.sh      Your local overrides — git-ignored, sourced last
└── env/
    ├── terminal.sh Shell navigation, editors, ls variants
    ├── git.sh      Git aliases and helper functions
    ├── apps.sh     Brew, tmux, rails helpers
    ├── languages.sh Node, Maven, Go helpers
    └── system.sh   System utilities (ports, kill, ps)
git/ignore          -> ~/.gitignore (global excludes template)
tmux/tmux.conf      -> ~/.tmux.conf
tmux/powerline/     → submodule: erikw/tmux-powerline pinned at v4.0.0.
                      It draws the status bar; run git submodule update --init
tmux/powerline-config/ → THE status bar config, linked as ~/.config/tmux-powerline
├── config.sh         Theme name, overlay directories, segment options
├── themes/rlazoti.sh Segments and colors: session host lan_ip wan_ip / load pwd branch
└── segments/         Drop-in custom segments (empty until you add one)
ruby/irbrc          -> ~/.irbrc
iterm2/             → iTerm2 settings snapshot, see its README
fonts/              → Font files that bin/setup.sh installs into ~/Library/Fonts
docs/               → Screenshots

Installation

Prerequisites

  • macOS
  • iTerm2 (or Terminal.app)

Steps

# 1. Clone this repo
git clone https://github.com/rlazoti/dotfiles ~/.terminal
cd ~/.terminal

# 2. Install Homebrew (if not already installed)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# 3. Run setup and choose what to install
bash bin/setup.sh

# 4. Verify, then restart your terminal
bash bin/check.sh

bin/setup.sh prompts for each category. Answer y or n for each one. It links every pair in manifest.tsv (~/.zshrc, ~/.zshenv, ~/.tmux.conf, ~/.gitignore, ~/.irbrc) and copies fonts/ into ~/Library/Fonts.

After a file move or a rename, relink without touching packages:

bash bin/setup.sh --links-only

setup.sh uses the Homebrew 7 form brew bundle install --file=… --no-upgrade. On Homebrew 6 or older, use brew bundle --file=… --no-lock.

Local overrides

Create ~/.terminal/zsh/private.sh for machine-specific settings — extra paths, tokens, host names. It is git-ignored and sourced after every other file in zsh/env/, so it can override anything.

Customization

Adding packages

Edit the relevant Brewfile:

  • Brewfile.core — core CLI tools
  • Brewfile.zsh — zsh plugins
  • Brewfile.editors — editors
  • Brewfile.dev — dev toolchains
  • Brewfile.apps — GUI apps
brew "my-tool"       # Add a formula
cask "my-app"        # Add a cask

Then apply it: brew bundle install --file=Brewfile.core --no-upgrade

Adding non-Brew tools

Create a script in bin/ whose name ends in -install.sh:

#!/bin/bash
# Install My Tool
# Usage: bash bin/my-tool-install.sh
echo "==> Installing My Tool..."
curl -fsSL https://example.com/install.sh | sh
echo "==> Done!"

bin/setup.sh prompts for every bin/*-install.sh. The first line that starts with # becomes the prompt text.

Adding aliases

Each concern is one file. Put aliases and functions for the same topic in the same file:

  • zsh/env/terminal.sh — shell navigation, editors, ls variants
  • zsh/env/git.sh — git aliases and helper functions
  • zsh/env/apps.sh — brew, tmux, rails
  • zsh/env/languages.sh — node, maven, go
  • zsh/env/system.sh — system utilities

Changing the zsh prompt theme

Edit zsh/theme-powerline.zsh-theme. It only sets colors and glyphs, and it loads the colors module and zsh/terminfo itself. The git data comes from zsh/git-prompt.zsh, which runs git status --porcelain=v2 --branch --show-stash once per prompt in precmd and caches it in $_git_prompt. The prompt segments read that cache, so drawing the prompt starts no extra processes.

Supported settings:

Variable Meaning
ZSH_THEME_GIT_PROMPT_PREFIX / SUFFIX Text around the branch name
ZSH_THEME_GIT_PROMPT_DIRTY Marker when the working tree has changes
ZSH_THEME_GIT_PROMPT_AHEAD / BEHIND Counts against the upstream branch
ZSH_THEME_GIT_PROMPT_STASH Prefix for the stash count
ZSH_THEME_GIT_PROMPT_ADDED, _MODIFIED, _RENAMED, _DELETED, _UNMERGED, _UNTRACKED Right-side status icons

In a very large repository, one git status per prompt can still be slow. Skip it with:

export GIT_PROMPT_HIDE_STATUS=1

The tmux status bar

The bar is tmux-powerline drawing this repo's theme. Three files, all tracked:

File Controls
tmux/powerline-config/config.sh Which theme, where themes/segments are found, per-segment options
tmux/powerline-config/themes/rlazoti.sh The segments themselves, their order and colors
tmux/powerline-config/segments/ New segments, if you write one

They reach the tool through one link, ~/.config/tmux-powerline → tmux/powerline-config, which bin/setup.sh creates from manifest.tsv. tmux-powerline reads exactly that directory, so an edit takes effect on the next redraw — no restart, no reload.

Both sides are emitted in array order, left to right, so on the right side the first entry is nearest the window list and the last one sits on the right screen edge. Current layout: left session host lan_ip wan_ip, right load pwd vcs_branch.

Never edit tmux/powerline/themes/ — that directory belongs to the submodule, and git submodule update owns it. Both ways a theme breaks are silent, so check after editing:

~/.terminal/tmux/powerline/powerline.sh right              # what the right side draws now
bash tmux/powerline/doctor.sh | sed -n '/active theme/p'   # which theme file won
bash bin/check.sh                                          # both, plus errors inside segments

A new segment means a new shell per redraw, and maybe more width: status-left-length and status-right-length in tmux/tmux.conf truncate without warning.

Fonts

The zsh prompt uses private-use glyphs. Non Ascii Font in the iTerm2 profile must name a font that exists. Add new font files to fonts/ so bin/setup.sh installs them and bin/check.sh can verify them. See iterm2/README.md.

iTerm2 settings

iterm2/README.md explains how the plist snapshot relates to the live settings, how to export it without pulling in runtime noise (bin/iterm2-export.sh), how to check what keys your terminal sends, and how to move a profile to a Dynamic Profile JSON file.

Keybindings

Shell shortcuts

Command Action
.. / ... / .... / ..... cd .. / cd ../.. / cd ../../.. / cd ../../../..
gcam "msg" git commit -m "msg"
gck git checkout
gckb git checkout -b
gst git status -sb
gpl git pull --rebase --tags
gpso git push origin
gbclean Delete merged branches, confirm unmerged ones
b brew
t tmux
E sudo $EDITOR
vii emacs -nw

Word movement with Option+Arrow is bound in zsh/zshrc and does not depend on the iTerm2 key map. iterm2/README.md shows how to check the sequence your terminal sends.

Tmux (prefix: C-f)

Keybinding Action
C-f Prefix key
C-f c New window in the current path
C-f " Split window
C-f % Split window horizontally
C-f m Toggle mouse mode
C-f y Copy the tmux buffer to the macOS clipboard
C-f : Command prompt with emacs-style editing
Y in copy mode Copy the selection and run /feedback-capture in pi

Design decisions

Recorded here so they do not have to be argued again.

Bare zsh, no Oh My Zsh

Oh My Zsh was removed on 2026-10-01. It supplied four things, each now owned here:

Oh My Zsh provided Now provided by
git prompt info zsh/git-prompt.zsh
ZSH_THEME_* variables zsh/theme-powerline.zsh-theme
tmux autostart zsh/zshrc
plugin loading zsh/zshrc loop over $HOMEBREW_PREFIX/share

Anything that still references an :omz: zstyle or an oh-my-zsh.* git config key is dead code. Remove it instead of keeping the probe.

One git call per prompt

zsh/git-prompt.zsh runs one git status --porcelain=v2 --branch --show-stash in precmd and caches the result in $_git_prompt. The theme only reads that cache. Five separate git calls cost about 146 ms per prompt in a small repository; one call costs about 37 ms, and large repositories scale far worse.

  • No async prompt framework: it needs a persistent worker per shell, and one status call is already cheap enough.
  • The engine calls git with GIT_OPTIONAL_LOCKS=0, so the prompt never takes an index lock while an editor or build holds one.
  • GIT_PROMPT_HIDE_STATUS=1 skips the call completely. That is the answer for a repository that is too large, not a second code path.
  • --show-stash needs git 2.22 or newer. Older git prints no stash line, so the stash segment disappears; nothing else breaks.

Shell startup order and precedence

~/.zshenv    locale, HOMEBREW_PREFIX + PATH, tool PATHs, cargo env   (every zsh)
~/.zshrc     setopt -> git engine -> tmux autostart -> zsh/init.sh ->
             lazy pyenv/neovim -> theme -> plugins -> bindkey          (interactive)
~/.terminal/zsh/init.sh
             zsh/env/{terminal,git,apps,languages,system}.sh           (one file per concern)
             then zsh/paths.sh
             then zsh/private.sh                                       (last, wins)

Consequences to respect:

  • Anything that must be visible to non-interactive shells (scripts, git helpers, Emacs shells) belongs in .zshenv, not .zshrc.
  • zsh/private.sh is sourced last, so it overrides every alias and PATH entry. It is git-ignored, so secrets stay off GitHub. It is plain text; this repo does not encrypt it.
  • Homebrew plugins load after the theme, because zsh-syntax-highlighting must be sourced last.
  • Key bindings for terminal keys live in .zshrc, never in the iTerm2 Keyboard Map. That keeps them working across terminals and through tmux extended-keys.

PATH precedence

.zshenv puts $HOMEBREW_PREFIX/bin and sbin in front of PATH, and sets HOMEBREW_PREFIX without starting a brew subshell. Homebrew git therefore wins over /usr/bin/git. paths.sh only appends personal directories, and only when they exist.

Deliberate limit: keg-only formulae are not added to PATH. Homebrew's curl is keg-only, so brew "curl" keeps the formula updated but does not change which curl runs. Add the keg path yourself if you ever need brew's curl.

Homebrew as the only package manager

Five category Brewfiles, applied with brew bundle install --file=Brewfile.<cat> --no-upgrade. install upgrades by default in Homebrew 7, so --no-upgrade keeps a plain install from silently updating formulae. The old --no-lock form is gone in Homebrew 7 and fails.

reattach-to-user-namespace is not in Brewfile.core. tmux 3.6 and newer reach the macOS pasteboard on their own, and that helper has had no upstream release since 2017. Clipboard support is bind y run 'tmux save-buffer - | pbcopy'.

Where things live, and how links are made

Directories are named after the tool that reads them, and every dotfile sits next to the files that support it. Before 2026-10-15 the root held 13 loose files: environment (a loader with no clue in its name), my-custom-theme.zsh-theme, gitignore sitting next to .gitignore, install-scripts/ plus check.sh plus setup.sh in three different naming styles, and two screenshots.

Rules that keep it tidy:

  • bin/ holds executables. bin/setup.sh auto-discovers installers by the name suffix bin/*-install.sh, so adding a tool adds no wiring.
  • manifest.tsv is the only link list. bin/setup.sh reads it, bin/check.sh verifies it. A pair appears once, as source<TAB>target.
  • One file per concern under zsh/env/. Aliases and functions for the same topic live in the same file, so gcam and gbclean are together.
  • Brewfiles stay at the root: five files, and --file=Brewfile.core stays short.
  • After any move, run bash bin/setup.sh --links-only, then bash bin/check.sh. The links in $HOME point at repo paths, so a move breaks the shell until you relink.
  • tmux/powerline is a submodule. A fresh clone needs git submodule update --init, which bin/setup.sh runs for you. An empty submodule directory draws a blank status bar and tmux reports nothing, so bin/check.sh checks that the bar actually renders.

tmux choices

  • Prefix is C-f, not C-b.
  • extended-keys on with extended-keys-format csi-u: pi needs to tell Shift+Enter from Enter. Requires tmux 3.5+.
  • The status bar is drawn by tmux-powerline, a submodule pinned at v4.0.0 (tmux/powerline), but with this repo's theme: left is session, host, LAN IP, WAN IP; right is load, directory, branch. Theme and config live in tmux/powerline-config/ and reach the tool through one manifest link, ~/.config/tmux-powerline, because that directory is the path tmux-powerline reads. Nothing is ever edited inside the submodule.
  • The config is a symlink, not TMUX_POWERLINE_CONFIG_FILE set from tmux.conf, so that every caller resolves the same theme: tmux's #(), bin/check.sh, doctor.sh, and you running powerline.sh left by hand while debugging. An environment variable reaches only processes that inherit it, and a hand-run that quietly used the bundled theme would have you debugging the wrong file. tmux 3.8 also changed that command's syntax — set-environment now takes variable value, and the NAME=value form fails with "variable name contains =".
  • Both theme failure modes are silent, so bin/check.sh asks doctor.sh which theme actually resolved and compares resolved paths: a missing symlink falls back to the bundled theme without a word, and a theme file that cannot be found draws a blank bar with no error.
  • It used to be an ignored clone in the repo root, so no version was recorded, and on 2026-10-15 it turned out to be gutted: 59 files were gone, themes/default.sh included, so the bar drew blank and nothing reported it. Pinning it is what fixes that class of breakage; bin/check.sh now renders the bar and fails if a segment is missing.
  • Segments cost a shell each, per status-interval, and that is the price of the powerline bar. It is why the theme carries seven segments instead of the stock twelve: four on the left, three on the right. status-interval 5 is the other half of that trade — status segments start shells, so a 2 second interval means many processes per hour for no visible gain.
  • Window names use the b: format modifier instead of a #() shell call.
  • Mouse is on, and prefix m toggles the boolean option. The old cut -c3- trick and its pre-tmux-3.0 mode-mouse calls are gone.

iTerm2 settings

iterm2/com.googlecode.iterm2.plist is a full preference snapshot: 1097 keys, 2360 lines, 62 KB. One GUI change can rewrite hundreds of lines, and importing iTerm2's own file would add 47 runtime keys (NoSync*, NS*, SU*, Apple*) that change by themselves. That cost is accepted, not solved: the file stays tracked so a new machine can be configured from it. bin/iterm2-export.sh keeps the noise out when you re-export, and bin/check.sh runs plutil -lint on the file. The way out, if the churn ever hurts more than the convenience, is a Dynamic Profile JSON file — described in iterm2/README.md. Never reuse a GUID, and never point "Load preferences from a custom folder" at that directory.

Font rule: Non Ascii Font in the default profile must name a font that bin/setup.sh can install from fonts/. Today that is FontAwesome 11 and fonts/FontAwesome.otf. bin/check.sh verifies it.

Explicit non-goals

  • No dotfile manager (GNU Stow, chezmoi): manifest.tsv plus bin/setup.sh is about 20 lines of shell, and it adds no dependency.
  • No Linux support. Brewfile.* and the macOS clipboard paths assume macOS.
  • No symlink for .zlogin: the file was empty, so it was removed on 2026-10-15.

Maintenance

Update packages

Homebrew 7 changed the syntax: it is brew bundle install now, and --no-lock and the install-side --cask flag are gone. install upgrades by default, so --no-upgrade is what you want for a plain install.

brew bundle install --file=Brewfile.core --upgrade
brew bundle install --file=Brewfile.zsh --upgrade
brew bundle install --file=Brewfile.editors --upgrade
brew bundle install --file=Brewfile.dev --upgrade
brew bundle install --file=Brewfile.apps --upgrade

To see whether a Brewfile is satisfied without installing anything:

brew bundle check --file=Brewfile.core

Health check

bash bin/check.sh

It verifies every pair in manifest.tsv (files and directories), each Brewfile package, the zsh plugin path for this Mac, installed fonts against the iTerm2 profile's font, that the plist parses, the zsh/ file set including zsh/env/, that the zsh config parses and starts without errors and still loads the colors module, that tmux/tmux.conf parses on an isolated tmux server, that tmux-powerline renders both sides of the bar and that the theme it resolved is the one tracked in this repo, and that git is new enough for the prompt engine. Errors exit 1; warnings exit 0.

Add a new tool

  1. If it is a Homebrew formula or cask: add it to the relevant Brewfile
  2. If it is a non-Brew installer: create bin/<name>-install.sh
  3. Run bash bin/check.sh

Troubleshooting

Prompt shows raw escape sequences?

  • setopt PROMPT_SUBST must stay on (it is set in zsh/zshrc)
  • Check that fonts/FontAwesome.otf is installed: ls ~/Library/Fonts

Prompt shows boxes instead of icons?

  • The iTerm2 profile's Non Ascii Font does not match an installed font. See iterm2/README.md.

Prompt is one flat color?

  • The colors module is not loaded. zsh/theme-powerline.zsh-theme loads it; do not move that load into the prompt engine. bin/check.sh tests it.

Prompt is slow in one repository?

  • One git status runs per prompt. In a huge repository, set export GIT_PROMPT_HIDE_STATUS=1 in that project's local overrides.

tmux doesn't auto-start?

  • zsh/zshrc starts tmux new-session -A -D -s main for a shell outside tmux.
  • To skip tmux once: TMUX_ENV_SET=1 zsh

tmux status bar is empty?

  • tmux source-file ~/.tmux.conf. Then bash bin/check.sh: it renders both sides and reports an uninitialized submodule or a theme file that cannot be found, both of which draw blank without any error.

tmux bar shows segments you did not choose?

  • The theme is selected through ~/.config/tmux-powerline → tmux/powerline-config. If that link is missing, tmux-powerline silently uses its own bundled default theme. Fix: bash bin/setup.sh --links-only, then bash bin/check.sh.

Changed the tmux theme and nothing moved?

  • bash tmux/powerline/doctor.sh | sed -n '/active theme/p' prints the theme file that won. If it points inside tmux/powerline/themes/, then TMUX_POWERLINE_DIR_USER_THEMES is not reaching tmux/powerline-config/themes — that variable is what keeps the lookup out of the submodule.

Aliases stopped working after a pull?

  • Reload the config: source ~/.zshrc
  • After a file move in this repo: bash bin/setup.sh --links-only
  • Confirm the package is installed: brew list <tool>

Something on this page is wrong?

  • Run bash bin/check.sh first — it tests the machine, not the docs.

Author

Rodrigo Lazoti

About

This repository contains all my dot files used in both Linux and Mac

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages