One repo for your Windows, Ubuntu, and macOS machines
Four machines: a Windows + WSL gaming PC, an Ubuntu laptop, a macOS work laptop, and a personal Mac. You want the same shell, aliases, and git setup on all of them, but each differs. The gaming PC needs WSL and your Kubernetes tooling; the work Mac uses your work email and work repos; the Ubuntu laptop is your daily dev box. One repo handles all four.
All three platforms
Dotfiles Pro applies your Ubuntu, macOS, and Windows/WSL machines from one repo. macOS uses the macos role (Homebrew) in place of ubuntu, with ansible_facts.os_family guards on the shared roles. Even the docker role runs on macOS (via colima); offering more container runtimes there is on the roadmap.
The shape
The shape is a shared baseline with per-machine overrides, the many layout for a fleet: vars live in group_vars/ and host_vars/, and the role list is data-driven, so each machine runs its own set:
mydotfiles/
inventory.yaml # every machine, by hostname
group_vars/all.yaml # the baseline every machine gets
host_vars/
game-pc.yaml # Windows + WSL
ubuntu-laptop.yaml # Ubuntu
work-mac.yaml # macOS (work)
home-mac.yaml # macOS (personal)
playbook.yaml
requirements.ymlThe baseline
Every machine shares one group_vars/all.yaml, with the shell framework, aliases, the dotpro commands, your SSH keys, git config, and the Starship prompt identical everywhere:
---
# group_vars/all.yaml — OS-neutral roles every machine shares. The OS base
# (ubuntu/macos) is not here; the playbook applies it per host from facts.
ansible_roles_all:
- dotpro
- ssh
- git
- starship
git_config:
user:
name: Your Name
email: you@personal.comThe OS base itself isn't in this shared list; each machine needs a different one. The playbook applies it per host from gathered facts (the macos role on a Mac, ubuntu elsewhere), so a new machine gets the right base with no extra config.
Per machine
Each machine adds to the baseline via roles_extra (its own roles, merged onto ansible_roles_all); dicts like git_config merge (the hash_behaviour = merge setting from Configuration, on by default in the example ansible.cfg), so a host overrides only the keys it cares about:
---
# host_vars/game-pc.yaml: Windows + WSL
roles_extra:
- wsl
- windows
- docker
- kubernetes
- googlecloud---
# host_vars/ubuntu-laptop.yaml: your daily dev box
shell: zsh # off-diagonal: zsh on Linux (defaults to bash; macOS defaults to zsh)
roles_extra:
- docker
- terraform
- opentofu---
# host_vars/work-mac.yaml: macOS, work identity (the macos base is applied
# automatically from facts; this host only adds its extra roles and identity)
roles_extra:
- docker
- kubernetes
- aws
git_config:
user:
email: you@work.com # work email on this machine only
git_repositories:
work-project: git@github.com:yourorg/work-project.git---
# host_vars/home-mac.yaml: macOS, personal — no extra roles, just the shared
# baseline plus the macos base the playbook applies automatically from facts
roles_extra: []The game-pc picks up the WSL role, wsl.conf, Windows shims, and WSLENV bridging so Windows-side Lens authenticates to GKE through WSL, plus the Windows role to manage the Windows half itself (winget apps, registry, virtual desktops, hotkeyed workspaces). The work-mac overrides only user.email and adds its work repo, so your work commits use your work address while everything else stays shared.
Running it
On each machine, the same command applies that machine. dotpro apply adds --limit $(hostname) for you, so it picks up that host's host_vars with no extra flag:
dotpro applyAdd a machine by dropping a host_vars/<hostname>.yaml and listing it in inventory.yaml. Nothing else changes.
Next steps
- Configuration the full
single→multiple→manyprogression - Managing dotfiles across machines the model this builds on
- macOS role how the Homebrew-based macOS setup works