A tidy $HOME is a tidy mind.
These are my dotfiles, designed for macOS (Apple Silicon and Intel) and Debian 12, heavily inspired by
hlissner/dotfiles. Topics are split into category/topic (e.g. shell/zsh), aim for XDG compliance, and clutter your $HOME as little as possible.
- Homebrew (for macOS)
- git
- zsh
- curl
git clone --recurse-submodules https://github.com/eduarbo/dotfiles.git ~/.config/dotfiles
cd ~/.config/dotfiles
# On a fresh clone the `dot` alias doesn't exist yet, so invoke the script
# directly. Deploy the shell first — the `dot` alias is available afterwards.
./deploy shell/zshIf you cloned without --recurse-submodules, fetch the Doom snippets submodule
with git submodule update --init before deploying editor/emacs.
The following are the categories and topics you can install:
-
macos/– Mac-specific tools and tweaksapps– The essential macOS app lineup I can't live withoutdefaults– Opinionated values for a saner (and possibly sassier) macOShammerspoon– Lua-powered automation for pro-level productivity- Window wrangling without the wrestling
- Lightning-fast app launcher
- Push-to-talk mic sorcery (menubar toggle; hotkey opt-in via
bindings.lua) - Instantly swap your audio outputs like a DJ
karabiner– The ultimate keyboard wizardry to remap all the thingsraycast– Encrypted snapshot of my Raycast config, with export/import helpers
-
editor/– My battle-stations for text and codeemacs– The best of both Emacs and Vim worlds, with extra chaosnvim– My nimble sidekick for those “just one quick edit” momentscoding-style– Keep your code prettier than your neighbor's garden
-
shell/– Terminal superpowers and creature comfortsgit– Snazzy aliases and Zsh plugins for effortless versioningssh– SSH client config with Bitwarden agent support and a default identitytmux– Tab-multiplying terminal wizardryzsh– The shell with speed, features, and a prompt that actually sparks joykitty– The terminal so full-featured, even your cat would approveclaude-code– Custom status line for Claude Code CLI, integrated with Powerlevel10k
-
dev/– Essential tools and setups for a life in codemise– Universal version manager for Node, Python, Lua and morelua– Lua toolchain (brew/apt), luarocks packages, and luacheck linternode– npm/pnpm package management — runtime versions handled by misepython– Python tooling via brew and pipx — runtime versions handled by misegolang– Go fast, install Go, and grab some must-have packagesphp– Composer support included, because sometimes you just can’t avoid PHP
The manager is the deploy script. On a fresh clone run it directly as
./deploy; once shell/zsh is enabled it's also available as the dot alias.
Usage: dot [-AacdfhlLit] [TOPIC...]
-A Target all available topics supported on this OS (shell bootstrap first)
-a Target all enabled topics (ignores TOPIC args)
-c Afterwards, remove dead symlinks & empty dot-directories in $HOME.
Can be used alone.
-d Disable & unlink topic(s), runs `clean()`
-f Force install & link
-l Only relink topic(s) (implies -i)
-L List enabled topics
-i Inhibit install/update/clean init scripts
-t Do a test run; do not actually do anything
TOPIC can be an exact topic (`shell/zsh`), a group (`shell`), or a glob
(`shell/*`, `editor/n*`). Expanded groups and globs are filtered to topics that
support the current OS.
dot shell/zsh shell/kitty: enablesshell/zshandshell/kittydot shell: enables allshell/*topics supported on this OSdot 'editor/*': enables all matching editor topics supported on this OSdot -A: enables all available topics supported on this OSdot -d shell/zsh: disables shell/zsh & cleans up after itdot -l shell/zsh: refresh links for shell/zsh (inhibits init script)dot -f macos/karabiner: force re-run install & link for an enabled topicdot -l: relink all enabled topicsdot -L: list all enabled topics
Here's a breakdown of what the script does:
cd $topic
if [[ -L $DOTFILES_DATA/${topic/\//.}.topic ]]; then
./_init update
else
ln -sfv $DOTFILES/$topic $DOTFILES_DATA/${topic/\//.}.topic
./_init install
./_init link
fi-
If you use a password manager like Bitwarden, managing SSH keys is a breeze (and much more convenient). But if you're old-school (or just like a little DIY), you can still generate SSH keys manually:
ssh-keygen -t ed25519 -C "personal-mbpro-2025" # Use a descriptive comment: purpose + device + year
Forge (Magit’s helper for GitHub/GitLab) reads your personal access token from the file set in auth-sources. This config points it at ~/.config/doom/authinfo.gpg (see editor/emacs/doom/+defaults.el). This file should never be committed to your repository.
To set up your tokens securely:
- This repo provides a template at
editor/emacs/doom/authinfo.gpg.example. Copy it toeditor/emacs/doom/authinfo.gpg(same directory) - Run
dot -l editor/emacsto relink thedoom/directory (the file then appears at~/.config/doom/authinfo.gpg) - Open and edit the file in Emacs to add your tokens, then save. Emacs will manage the GPG encryption for you
By following these steps, your dotfiles remain clean, secure, and portable—reducing the risk of accidentally exposing your credentials.
These dotfiles work on both Intel and Apple Silicon Macs. A few things to be aware of:
- Homebrew paths: Homebrew installs to
/opt/homebrewon Apple Silicon and/usr/localon Intel. The shell config auto-detects the correct path. - ARM-only apps: Some casks like OrbStack are Apple Silicon only and will be skipped automatically on Intel Macs.
- macOS defaults: The
macos/defaultsscript detects the macOS version to handle differences between System Preferences (pre-Ventura) and System Settings (Ventura+). - SSH agent: If using Bitwarden's SSH agent, the
SSH_AUTH_SOCKis only set when the socket file exists.
Make sure the GPG key ID is correct. You can get a list of GPG keys with
gpg --list-secret-keys --keyid-format LONG and then set it in Git with
git config --global user.signingkey [GPG-key-ID].
More details in Telling Git about your GPG key.
git@github.com: Permission denied (publickey)
Just add your SSH Key to your GitHub account
- DOOM Emacs (pulled by
editor/emacs) - Pacmux Tmux theme (pulled by
shell/tmux) - Powerlevel10k (zsh prompt, loaded via zinit in
shell/zsh)

