Personal dotfiles for a modular dev setup on macOS and Linux (the homelab
devLXC), managed with Stow + Homebrew.
This repo uses GNU Stow to symlink configs into $HOME and Homebrew as the package source of truth (brew/Brewfile on macOS, brew/Brewfile.linux on Linux).
- Shell: Zsh + Oh My Zsh.
- Prompt: Powerlevel10k (
.p10k.zsh), loaded fromzsh/.zshrc. - Node.js: fnm with automatic version switching (
fnm env --use-on-cd). - Terminal: Ghostty config included.
- Navigation/tools:
zoxide,eza,bat,fzf, etc. - Editors: layered sync flow for VSCode/Cursor + Copilot integration via
scripts/sync-ides.sh. - AI tooling: Claude Code only (config, skills and status line in
claude-code/), kept in sync by gentle-ai.
git clone https://github.com/mralexsaavedra/dotfiles
cd dotfiles
chmod u+x ./setup.sh
./setup.shsetup.sh runs macOS defaults + Homebrew bootstrap, then stows the managed folders and syncs IDE configs.
On Linux setup.sh hands over to scripts/linux-setup.sh. Run it as a normal user, never root (Homebrew and Claude Code both refuse root):
./setup.sh --machine # once per machine, admin user with sudo
./setup.sh # once per extra user (agent users, no sudo)--machine: apt prerequisites, shared Homebrew in/home/linuxbrew/.linuxbrew,brew/Brewfile.linux, zsh as login shell,loginctl enable-linger, and thedaily-update.timersystemd user unit (linux/systemd/, weekdays 08:00, log~/.local/state/daily-update.log). Then it runs the per-user steps.- Per user: Oh My Zsh, stow
git zsh gh vim claude-code bin(no--adopt: a conflict stops the run), Claude Code, the status line plusclaude-code-settings/settings.shared.json(effort level and permissions, exported from the Mac bymake sync-ai) in~/.claude/settings.json, the engram/codegraph/context7 MCP servers,rtk init -g, the Mac's Claude Code plugins (minus Warp),gentle-ai sync(which adds its hooks and the output style). Git: GitHub credentials go throughgh(~/.gitconfig.user, rungh auth loginfirst); commits are signed with~/.ssh/id_ed25519, so each Linux machine needs its own key added to GitHub as a signing key (gh auth refresh -s admin:ssh_signing_key, thengh ssh-key add --type signing ~/.ssh/id_ed25519.pub). Engram Cloud needs~/.zshenv.local(chmod 600, seezsh/.zshenv.local.example); the script only warns when it is missing. - Mac only, not installed on Linux: Ghostty, IDE sync, Raycast, LaunchAgents, casks. The status line skips the calendar, Dock badges and Spotify segments there. The
eventoskill and the personal mail part ofbandejaneed macOS apps.
ws WS-8 resumes the Claude Code session of a Multica issue in its run directory (claude --resume with the newest session that has answers, in ~/multica_workspaces/…/ws-8-…/workdir; --continue skips the headless sessions Multica creates): on this machine if the run happened here (Mac runtime), otherwise on the dev LXC over SSH. ws alone lists the issues with a run directory, ws -n WS-8 only prints where it would open. It refuses while an agent run is using that directory, so two writers never share a session.
Useful commands:
| Command | Description |
|---|---|
make update |
Runs maintenance + IDE sync (scripts/maintenance.sh + scripts/sync-ides.sh). |
make install |
Installs dependencies from the Brewfile for this OS (brew/Brewfile or brew/Brewfile.linux). |
make dump |
Rebuilds brew/Brewfile from current brew state (removes vscode lines). macOS only. |
make clean |
Homebrew cleanup. |
make sync-ides |
Syncs settings/extensions to VSCode and Cursor. |
scripts/maintenance.shdoes not auto-commit or auto-push. If changes are detected, it only prints suggested git commands. Review and commit manually.
The shell config is intentionally split by responsibility:
.zshenv→ minimal env for all zsh instances (locale, editor,DOTFILES_DIR, lightweight PATH, secrets hook)..zprofile→ login/session setup (toolchain PATH additions, Java/Android/Python/Bun env)..zshrc→ interactive shell behavior (plugins, history, completions, fnm auto-switch, Powerlevel10k)..aliases/.functions→ shared user commands loaded by.zshrc..zshrc.custom→ tracked personal interactive customizations, sourced near the end.*.localfiles (optional, machine-specific) loaded last as overrides.
Local/secrets files are ignored via *.local in .gitignore.
zsh/.zshenv.local.exampleis the template.- Recommended local files:
~/.zshenv.local(tokens/secrets)~/.zprofile.local(machine login/session overrides)~/.zshrc.local(interactive shell overrides)
Suggested split for interactive config:
- Keep portable baseline in
zsh/.zshrc(safe to update from upstream). - Keep tracked personal tweaks in
zsh/.zshrc.custom. - Keep machine-only overrides in
~/.zshrc.local.
Prefer keeping shared defaults in tracked files and machine-specific values in *.local.
brew/— Homebrew bundles (Brewfilefor macOS,Brewfile.linuxfor Linux).zsh/— split shell config and local override templates.scripts/— setup/maintenance automation (linux-setup.sh,setup-services-linux.shfor Linux).macos/— LaunchAgent templates.linux/systemd/— systemd user unit templates.ides/— layered editor config (base+ per-editor deltas +ai/copilot).git/,gh/,ghostty/,vim/,raycast/— tool-specific configs.claude-code-settings/— Claude Code settings shared with Linux (not stowed).claude-code/—~/.claudepackage:CLAUDE.md,skills/(linked from~/.claude/skills) andstatusline.sh.
Built with ❤️ by Alexander Saavedra.