I was drowning in scattered configs. Claude Code preferences in ~/.claude,
LunarVim setup in ~/.config/lvim, iTerm scripts in ~/.iterm. Every
time I tweaked something, I’d think “I should commit this” but had no clean way to do
it.
I needed a central repository for my tool preferences. A place to version control
everything that makes my development environment mine. I called it ~/.me—my developer
avatar.
The Solution: Symlinks + Central Repo
The insight was simple: clone to ~/.me, then symlink everything back.
cd ~
git clone github:fabiolnm/dotme.git .me
cd .me
./itsameThe itsame script discovers plugins and creates symlinks:
~/.claude/commands → ~/.me/claude/commands
~/.config/lvim → ~/.me/config/lvim
~/.iterm → ~/.me/itermNow I could work from anywhere:
cd ~/.claude
# Edit commands/journal.md
git status
git commit -m "Improve /journal command"Evolution to Plugin Architecture
My first version used a monolithic setup.sh that hardcoded every symlink. Adding a new
tool meant editing the script. Not scalable.
I refactored to a plugin system. Each tool gets its own self-contained script in
plugins/:
~/.me/
├── plugins/
│ ├── claude.sh # Manages Claude symlinks
│ ├── lunarvim.sh # Manages LunarVim symlinks
│ └── iterm.sh # Manages iTerm symlinks
├── claude/ # Claude preferences
├── config/lvim/ # LunarVim preferences
└── iterm/ # iTerm preferencesEach plugin handles:
- Installation check - warns if the tool isn’t installed (doesn’t fail)
- Backup - moves existing configs to
~/.me.bkp/(one-time, idempotent) - Symlinks - creates links from
~/.me/TOOLto expected locations
Here’s the template pattern:
#!/usr/bin/env bash
# plugins/TOOL.sh
# 1. Check if tool is installed
if ! command -v TOOL &> /dev/null; then
echo "📥 TOOL not installed. Install via: brew install --cask tool"
exit 0 # Exit gracefully
fi
# 2. Backup existing config (only once)
if [[ -e "$HOME/.config/TOOL" ]] && \
[[ ! -L "$HOME/.config/TOOL" ]] && \
[[ ! -e "$BACKUP_DIR/config/TOOL" ]]; then
echo "📦 Backing up TOOL config"
mkdir -p "$BACKUP_DIR/config"
mv "$HOME/.config/TOOL" "$BACKUP_DIR/config/TOOL"
fi
# 3. Create symlinks
mkdir -p "$HOME/.config"
ln -sf "$PROFILE_DIR/TOOL" "$HOME/.config/TOOL"
echo "✓ TOOL configured"The itsame orchestrator is simple—it discovers and runs all plugins:
#!/usr/bin/env bash
export BACKUP_DIR="$HOME/.me.bkp"
export PROFILE_DIR="$(pwd)"
for plugin in plugins/*.sh; do
if [[ -f "$plugin" ]]; then
bash "$plugin"
fi
done
echo "✓ Profile activated"Adding a new tool is dead simple: drop a plugin script in plugins/, run ./itsame,
done.
What I’ve Customized So Far
LunarVim - Auto-open NvimTree on startup. No more typing Space+E every time I
launch.
vim.api.nvim_create_autocmd("VimEnter", {
callback = function()
require("nvim-tree.api").tree.open()
end,
})iTerm - One-command workspace layout. Six panes: LunarVim (66%), two Claude sessions, three Fish shells.
workspace /path/to/project
┌──────────────┬─────────┐
│ │ claude │
│ LunarVim ├─────────┤
│ (66x66) │ claude │
├──────┬───────┼─────────┤
│ fish │ fish │ fish │
└──────┴───────┴─────────┘Quartz - Digital garden customizations. Custom layout, components, and styles for fabioluiz.dev.
Claude Code - The entire journaling pipeline lives here:
hooks/capture-session.sh- Saves every conversation to~/garden/drafts/commands/drafts.md- Analyzes captures, suggests journal entriescommands/journal.md- Synthesizes drafts into polished entriesskills/journal-writer/- Defines voice and structure
Key Takeaways
- Central repo beats scattered configs - One place to commit, one git history
- Symlinks make it transparent - Tools don’t know they’re reading from
~/.me - Plugin architecture scales - Adding new tools is a one-file change
- Idempotent is essential - Re-running
./itsameshould be safe - Backup before touching - Original configs preserved in
~/.me.bkp/
The ~/.me pattern works for any tool with a config file. If you can symlink it, you
can version it.