Skip to content

gabrielecanepa/dotfiles

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

770 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Warning

Before using the following dotfiles, fork this repository, review the content and remove things you don't want or need. Don't blindly use my settings unless you know what you are doing. Use at your own risk.

Features

Version-controlled home directory

The home directory is version-controlled. The .gitignore acts as an allowlist, so files are tracked only once opted-in and nothing leaks in by accident. Git hooks run natively, with no extra tooling.

Single script to install everywhere

.install.sh clones the repo, copies every managed file into the home, and sets up Homebrew, runtimes, packages, and all other managed tools. It confirms before overwriting and backs up whatever it replaces, so re-runs are safe.

Synced Brewfile to manage all dependencies

Brewfile pins formulae, casks, and App Store apps. The wrapped brew command keeps it always in sync, and brew fresh updates, upgrades, cleans, dumps, and runs health checks in one go.

Fast and powerful shell configuration

Oh My Zsh runs alongside local plugins and themes under .zsh. Plugins extend the shell with guided profile setup, runtime version switching and LTS installation, completions, and more. The custom node theme displays active runtime versions and symbols for available LTS upgrades.

Pinned runtimes and dependencies

Node, Ruby, and Python are pinned through nodenv, rbenv, and pyenv. The version managers read the tracked .node-version, .ruby-version, and .python-version files, so the machine and repos stay on the same versions.

Single source of truth for AI agents

The .agents directory is the source for instructions, rules, skills, and hook scripts shared by Claude Code, Codex, and Copilot. Tracked tool entrypoints use relative symlinks back to that source, while tool-specific settings stay separate.

Smart symbolic links

Managed files are linked into the locations each tool expects. When an application rewrites a linked file in place, dotfiles init restores the link and dotfiles doctor reports the drift.

Extended iCloud synchronization

The home Downloads, Movies, and Music folders are replaced with relative symbolic links to iCloud Drive, so their contents sync across devices while paths stay stable and portable.

Installation

Run the install script to bootstrap the configuration:

sh -c "$(curl -fsSL https://raw.githubusercontent.com/gabrielecanepa/dotfiles/HEAD/.install.sh)"

The script runs the following main actions:

  1. Installs the configuration by shallow-cloning this repository into a temporary directory (removed automatically on exit, error or interrupt) and copying each managed file into the home directory
  2. Backs up the replaced files into a timestamped backup folder in the default state directory
  3. Sets up Homebrew, packages, Oh My Zsh, runtimes, global dependencies, macOS defaults, Codex, Visual Studio Code, and iCloud symlinks

Manual setup

SSH

If not already present, generate a new SSH key and copy it to the clipboard:

ssh-keygen -t ed25519 -C "<comment>"
tr -d '\n' < ~/.ssh/id_ed25519.pub | pbcopy

Add the key to GitHub, GitLab and any other services you use.

Homebrew

Install Homebrew:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Oh My Zsh

Install Oh My Zsh and some useful community plugins:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/HEAD/tools/install.sh)"

plugins=(
  zsh-users/zsh-autosuggestions
  zsh-users/zsh-completions
  zsh-users/zsh-syntax-highlighting
  wbingli/zsh-claudecode-completion
)

for plugin in ${plugins[@]}; do
  git clone https://github.com/${plugin}.git ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/${plugin}
done

# Restart
zsh

Configuration

The .install.sh script (see Installation) installs the configuration automatically.

Note

Before overwriting an existing file, the script asks for confirmation (default no).

Every replaced file is moved into a timestamped backup folder in the default state directory. To restore a file, just copy it back from that folder:

backup="${XDG_STATE_HOME:-$HOME/.local/state}/dotfiles/backup"
ls "$backup"
cp "$backup/<timestamp>/.zshrc" ~/.zshrc

To clone the repository locally:

gh repo clone gabrielecanepa/dotfiles
# or
git clone git@github.com:gabrielecanepa/dotfiles.git

Install the packages listed in Brewfile:

brew bundle --file ~/.homebrew/Brewfile

Git

Note

Skip this step if you cloned the repository with gh repo clone or git clone above, as your home directory is already version-controlled.

After adding your SSH key to GitHub, initialize ~ as a git repo that tracks the remote:

git -C ~ init -b main
git -C ~ remote add origin git@github.com:gabrielecanepa/dotfiles.git
git -C ~ fetch --depth 1 origin main && git -C ~ reset --hard FETCH_HEAD

This repository wires its own checks with local Git hooks running Oxfmt, ShellCheck, commitlint and other code quality tools on commit and push.

Shell profile

Use the custom profile plugin to create your shell configuration with a guided prompt:

profile install

Runtimes

Node.js

Install the Node.js version in use with nodenv. A tracked install hook enables Corepack automatically, so pnpm follows the active Node version:

nodenv install $(cat ~/.node-version) --skip-existing

Link the local nodenv version to the tracked .node-version file:

nodenv global $(cat ~/.node-version)
rm -f $NODENV_ROOT/version && ln -sf ~/.node-version $NODENV_ROOT/version

pnpm is installed by Corepack, enabled by the tracked install hook.

Node-based tooling (Commitlint, Oxfmt, TypeScript and its language server) and every other global npm package are tracked in .npm/package.json by the custom npm-global plugin: the wrapped npm command re-dumps the manifest after every global install or removal, a second nodenv install hook restores it into every new Node version, and a bare npm install -g reinstalls it at any time.

Native tooling like ShellCheck still ships through the Brewfile.

Ruby

Install and link the Ruby version in use with rbenv:

rbenv install $(cat ~/.ruby-version) --skip-existing
rm -f $RBENV_ROOT/version && ln -sf ~/.ruby-version $RBENV_ROOT/version

Python

Install and link the Python version in use with pyenv:

pyenv install $(cat ~/.python-version) --skip-existing
rm -f $PYENV_ROOT/version && ln -sf ~/.python-version $PYENV_ROOT/version

Agents

Codex

.codex/system.toml is the portable, shared system configuration linked to /etc/codex/config.toml. Create the symlink with:

# Needs root privileges
sudo mkdir -p /etc/codex
sudo ln -sfn "$HOME/.codex/system.toml" /etc/codex/config.toml

Codex may add project trust, hook state, and other machine-specific values to the private user configuration. Keep these definitions entirely in that file.

GUIs

Visual Studio Code

Use symlinks to backup keybindings, settings and snippets of Visual Studio Code.

Warning

The following operations will permanently replace some system folders with symlinks to the corresponding files in the repository. Make sure to back up your data before proceeding.

for config in snippets keybindings.json settings.json; do
  file=~/Library/Application\ Support/Code/User/$config
  rm -rf $file
  ln -sf ~/.vscode/user/$config $file
done

VS Code rewrites settings.json in place on update or Settings Sync, replacing the symlink with a regular file. Running dotfiles init re-links it, and dotfiles doctor reports the drift.

Extensions are tracked in .vscode/extensions.json, and dotfiles init installs any listed extension that is missing from the machine.

Keybindings in Electron apps

To avoid emitting beeps in Electron-based applications when using the keyboard combinations ^⌘←, ^⌘↓ and ^⌘ (see this issue) create the keybinding settings file:

[[ ! -d ~/Library/KeyBindings ]] && mkdir ~/Library/KeyBindings
touch ~/Library/KeyBindings/DefaultKeyBinding.dict

And populate it with the following content:

{
  "^@\UF701" = "noop";
  "^@\UF702" = "noop";
  "^@\UF703" = "noop";
}

iCloud synchronization

Use the following snippet to replace the home Downloads, Movies and Music folders with symbolic links pointing at their corresponding (new or existing) folder on iCloud. This allows continuous synchronization between cloud and local machine.

Warning

The following operations permanently replaces system folders with symbolic links to iCloud Drive. Make sure to back up your data before proceeding.


for folder in Applications Developer Downloads Movies Music Pictures; do
  # create icloud drive folder
  cloud_folder=~/Library/Mobile\ Documents/com~apple~CloudDocs/$folder
  [[ ! -d $cloud_folder ]] && mkdir $cloud_folder

  case $folder in
    # symlink to system folder
    Applications)
      rm -rf ~/Applications
      ln -sf /Applications ~/Applications
      ln -sf $cloud_folder /Applications/iCloud
      ;;
    # symlink to cloud folder
    Downloads|Movies|Music)
      [[ -d ~/$folder ]] && mv ~/$folder/* $cloud_folder 2>/dev/null
      rm -rf ~/$folder && ln -sf ${cloud_folder#$HOME/} ~/$folder
      ;;
  esac
done

About

macOS configs, preferences, tweaks and extensions

Topics

Resources

Stars

Watchers

Forks

Used by

Contributors

Languages