I have a blog post about this project here.
β οΈ NOTE: It's outdated as previously everything including dotfiles was setup using Ansible. Now, we have a mix of Stow + Ansible.
Best of both worlds: Stow for dotfiles, Ansible for system setup.
- Stow manages all configuration files (dotfiles). Adding a new tool is as
simple as creating a directory and running
stow. - Ansible handles system-level setup: installing packages, configuring services, setting up development environments.
New machine setup (one command):
bash -c "$(curl -fsSL https://raw.githubusercontent.com/shricodev/dotfiles/main/bin/dotfiles)"This auto-detects your OS, installs Ansible, runs the playbook (which installs all packages and deploys dotfiles via stow).
Day-to-day dotfiles (no ansible needed):
# edit configs in place (already symlinked)
vim dots/nvim/.config/nvim/init.lua
# add a new tool
mkdir -p dots/wezterm/.config/wezterm
# add your config files...
stow -d dots -t ~ weztermYou can find the demo video setting up this dotfiles configuration on multiple ubuntu homelabs here: Link
- Git
- Supported OS: Arch Linux, Ubuntu, Fedora
- (Optional) Ansible for system setup (auto-installed by the bootstrap script)
- (Optional) Docker for testing in a container
Compatible with Ansible 2.20+. All system facts are accessed via
ansible_facts["distribution"], ansible_facts["user_dir"], etc.
.
βββ dots/ # Stow packages (dotfiles)
β βββ nvim/ # ~/.config/nvim/
β βββ tmux/ # ~/.config/tmux/
β βββ fish/ # ~/.config/fish/
β βββ kitty/ # ~/.config/kitty/
β βββ ghostty/ # ~/.config/ghostty/
β βββ alacritty/ # ~/.config/alacritty/
β βββ lazygit/ # ~/.config/lazygit/
β βββ starship/ # ~/.config/starship.toml
β βββ bat/ # ~/.config/bat/
β βββ zed/ # ~/.config/zed/
β βββ git/ # ~/.gitconfig, ~/.gitignore_global
β βββ gnupg/ # ~/.gnupg/
β βββ kdenlive/ # ~/.local/share/kdenlive/layouts/
β βββ scripts/ # ~/.local/bin/
β βββ ... # (i3, picom, polybar, gtk, etc.)
βββ ansible/ # System automation
β βββ roles/ # Modular setup roles
β βββ pre_tasks/ # Pre-setup tasks
β βββ group_vars/ # Variable configurations
β βββ inventory/ # Host inventory
β βββ configure_system.yml # System setup playbook
β βββ clean_up_system.yml # Cleanup playbook
β βββ main.yml # Master playbook
β βββ ansible.cfg # Ansible config
βββ bin/
β βββ dotfiles # Bootstrap script
βββ stow.sh # Helper to stow/unstow all packages
βββ Taskfile.yml # Task runner
βββ Dockerfile # Test environment
Each stow package mirrors the home directory structure. For example:
dots/nvim/.config/nvim/init.lua --> ~/.config/nvim/init.lua
dots/git/.gitconfig --> ~/.gitconfig
dots/scripts/.local/bin/foo --> ~/.local/bin/foo
# deploy all dotfiles
./stow.sh
# deploy a single package
stow -d dots -t ~ nvim
# remove symlinks
./stow.sh unstow
# re-deploy (unstow + stow)
./stow.sh restowOnly the custom editing layouts are tracked (Custom, Premiere, Vertical).
They are plain JSON with no absolute paths, so they move between machines and
install methods unchanged. Settings (kdenliverc) are deliberately not
tracked β Kdenlive rewrites that file on nearly every exit and hardcodes
install-specific binary paths in its [env] group.
stow kdenlive puts them at ~/.local/share/kdenlive/layouts, which is where a
native build already reads from. Flatpak and macOS read from their own sandboxed
locations, so they need a one-time symlink back to it.
| Install | Layout directory | Setup |
|---|---|---|
| Native Linux | ~/.local/share/kdenlive/layouts |
stow only |
| Flatpak | ~/.var/app/org.kde.kdenlive/data/kdenlive/layouts |
stow + kdenlive-layouts link |
| macOS | ~/Library/Application Support/kdenlive/layouts |
stow + kdenlive-layouts link |
Native Linux (dnf, pacman, apt) β nothing beyond the usual stow:
sudo dnf install kdenlive
stow -d dots -t ~ kdenlive # already done by the ansible bootstrapFlatpak or macOS β one extra command, once per machine:
flatpak install flathub org.kde.kdenlive # or: brew install --cask kdenlive
kdenlive # launch once so it creates its data dir
kdenlive-layouts linkOrder does not matter β stow may run before Kdenlive is even installed.
kdenlive-layouts status # which layouts are tracked
kdenlive-layouts pull # adopt newly saved layouts into the repoEditing an existing layout writes straight through its symlink into this repo, so
it is tracked with no extra step. Only a layout saved under a brand new name
lands outside the repo β kdenlive-layouts pull adopts it and re-stows.
Note
kdenlive is in stow_no_folding_packages, so stow creates real directories
and symlinks the layout files individually. Without --no-folding, stow would
collapse ~/.local/share/kdenlive into one symlink pointing at this repo, and
Kdenlive's own .backup/, titles/ and library/ state would be written
inside the dotfiles.
# run locally (via Taskfile)
task local
# run on remote homelabs
task ubuntu_homelabsUpdate ansible/inventory/hosts.yml with your hosts and
ansible/group_vars/ with your configuration.
---
all:
children:
ubuntu_homelabs:
hosts:
# <place_your_hosts_here>
local:
hosts:
localhost:
ansible_connection: localFor remote hosts, set up SSH keys and update ansible/ansible.cfg:
[defaults]
inventory = inventory/hosts.yml
private_key_file = <place_ssh_key_path_here>
roles_path = roles| Command | Description |
|---|---|
task stow |
Deploy all dotfiles via stow |
task unstow |
Remove all dotfile symlinks |
task restow |
Re-deploy all dotfiles |
task local |
Run Ansible locally (your machine) |
task ubuntu_homelabs |
Run Ansible on Ubuntu homelab machines |
task docker_build |
Build the dotfiles Docker image |
task docker_run |
Run the dotfiles Docker container |
task docker_build_and_run |
Build and run the Docker container |
Note
To test without installing anything on your system, run task docker_build_and_run.
bash dotfilesThis will install Ansible, clone the repo, and run the full playbook.
Logs are stored in ~/.dotfiles.log.
On first run, ~/.dotfiles_first_run_check is created. The script will
recommend a reboot to apply all changes.