A comprehensive dotfiles management system using the ansible-role-dotmodules role for automated system configuration and dotfile deployment.
Governance: See Constitution v1.0.0 for project principles AI-Assisted Development: Integrated with GitHub Spec-Kit for spec-driven development Quick Start: New to this repo? See QUICKSTART.md for fast setup
This repository contains modular dotfile configurations that can be deployed using Ansible automation. Each module is self-contained and can be mixed and matched to create a personalized development environment.
dotfiles/
├── .specify/ # Spec-Kit specifications (auto-managed)
├── docs/ # Documentation and policy
│ └── policy/ # Governance and policy documents
│ ├── CONSTITUTION.md # Core principles (v1.0.0)
│ ├── GOVERNANCE.md # Governance model
│ ├── CODING_STANDARDS.md # Coding standards
│ └── CHANGELOG.md # Change history
├── modules/ # Dotfile modules (each with config.yml and files/)
│ ├── 1password/ # 1Password CLI for password management
│ ├── dev-tools/ # Development utilities (mise, jq, shellcheck, etc.)
│ ├── editor/ # Editor configurations (vim)
│ ├── fish/ # Fish shell configuration and functions
│ ├── fonts/ # System fonts for development
│ ├── git/ # Git configuration and tools
│ ├── node/ # Node.js development (node, pnpm via mise)
│ ├── shell/ # Common shell utilities (eza, ripgrep, etc.)
│ └── zsh/ # Zsh shell configuration and prompt theme
├── playbooks/ # Ansible playbooks for deployment
│ ├── deploy.yml # Main deployment playbook
│ └── inventory # Ansible inventory file
├── QUICKSTART.md # Quick start guide for new users
├── requirements.yml # Ansible Galaxy requirements
└── README.md # This file
Each module follows this structure:
module-name/
├── README.md # Module documentation (purpose, features, usage)
├── config.yml # Module configuration (Homebrew packages, stow dirs, etc.)
└── files/ # Dotfiles to be deployed
├── .config/ # Configuration files
├── .bin/ # Binary/script files
└── .*rc # Shell configuration files
- macOS (required for Homebrew integration)
- Ansible 2.9+
- GNU Stow (for dotfile deployment)
- Homebrew (for package management)
-
Clone this repository:
git clone https://github.com/yourusername/dotfiles.git cd dotfiles -
Install the ansible-role-dotmodules role:
ansible-galaxy install -r requirements.yml
-
Run the playbook:
ansible-playbook -i playbooks/inventory playbooks/deploy.yml --ask-become-pass
| Module | Description | Key Tools |
|---|---|---|
| shell | Common shell utilities | eza, ripgrep, tldr, trash, wget, stow |
| fish | Fish shell configuration | fish, fisher, tide |
| zsh | Zsh shell configuration | zsh, powerlevel10k |
| git | Git configuration | git, gh, diff-so-fancy, difftastic |
| editor | Editor configurations | vim |
| dev-tools | Development tools | mise, jq, shellcheck, actionlint, bat |
| node | Node.js development | node, pnpm (via mise) |
| 1password | Password management CLI | 1password-cli (op) |
| fonts | System fonts | Fira Code, Hack Nerd Font, Inconsolata, Input |
Each module's config.yml file defines:
- Homebrew packages to install
- Homebrew taps to add
- Homebrew casks to install
- Stow directories for dotfile deployment
Example config.yml:
---
# Shell common utilities module
homebrew_packages:
- eza
- ripgrep
- tldr
- trash
- wget
- stow
stow_dirs:
- zsh
mergeable_files:
- '.zshrc' # Merged with other modules' contributionsModules can automatically register shells in /etc/shells, which is required to use them as your default shell via chsh.
Add register_shell to your module's config.yml to enable automatic registration:
# modules/fish/config.yml
homebrew_packages:
- fish
register_shell: fish # Automatically registers /opt/homebrew/bin/fish (or /usr/local/bin/fish on Intel)Shell paths are automatically detected based on your system architecture:
- Apple Silicon (M1/M2/M3):
/opt/homebrew/bin/fish - Intel Mac:
/usr/local/bin/fish
To disable shell registration permanently, simply remove or comment out the register_shell line from your module's config.yml.
To skip registration for a single deployment (useful for CI/CD, testing, or restricted environments), use the --skip-tags flag:
ansible-playbook -i playbooks/inventory playbooks/deploy.yml --skip-tags register_shellNote: When using --skip-tags register_shell, you don't need --ask-become-pass since no sudo privileges are required.
Use --skip-tags register_shell when:
- CI/CD pipelines: No sudo access available
- Testing deployments: Don't want to modify system files
- Restricted environments: Corporate systems with policies preventing
/etc/shellsmodification - Quick deployments: Shell registration not needed for the current session
After making changes to your dotfiles:
-
Commit your changes:
git add . git commit -m "Update dotfiles"
-
Re-run the playbook to apply changes:
ansible-playbook -i playbooks/inventory playbooks/deploy.yml --ask-become-pass
Edit playbooks/deploy.yml and modify the install list:
install:
- fish
- zsh
- git
# - editor # Comment out to disable
- dev-tools- Create module directory:
modules/my-module/ - Add
config.ymlwith Homebrew packages and stow_dirs - Add
files/directory with your dotfiles - Add module name to
installlist inplaybooks/deploy.yml
All modules support machine-specific configuration overrides via local config files. These files are not tracked in version control and allow you to customize settings per-machine without modifying the base dotfiles.
Base configuration files (.gitconfig, .zshrc, .vimrc, etc.) automatically load local config files if they exist:
- Git:
~/.gitconfig.local(loaded via[include]directive) - Zsh:
~/.zshrc.local(loaded via conditionalsource) - Fish:
~/.config/fish/config.local.fish(loaded via conditionalsource) - Vim:
~/.vimrc.local(loaded via conditionalsource)
You create these files manually in your home directory when you need machine-specific settings. Each module's README documents:
- Where to create the local config file
- What format/syntax to use
- Concrete examples for common use cases
Example - Git local config:
# Create ~/.gitconfig.local
vim ~/.gitconfig.local
# Add machine-specific settings
[user]
name = Your Name (Work Laptop)
email = work@company.comExample - Shell local config (for environment variables):
# Create ~/.zshrc.local (or ~/.config/fish/config.local.fish for fish)
vim ~/.zshrc.local
# Add environment variable overrides for tools
export NPM_CONFIG_REGISTRY=https://registry.company.com
export BAT_THEME="Monokai Extended Light"Some tools (npm, mise, bat) don't support local config files but respect environment variables. See the dev-tools module README for available environment variables and how to set them in your shell's local config file.
- Machine-specific settings: Different identities, paths, or preferences per machine
- Private credentials: Store API keys and tokens without committing to git
- No conflicts: Local configs override base configs without modifying tracked files
- Zero errors: Base configs load normally if local files don't exist
For detailed instructions, see each module's README file.
- Create a new directory in
modules/ - Add a
config.ymlfile with your configuration - Create a
files/directory with your dotfiles - Add the module to your playbook's
installlist inplaybooks/deploy.yml
- Edit the module's
config.ymlto change dependencies - Modify files in the
files/directory - Re-run your playbook to apply changes
- Module Processing: Each module is processed independently
- Configuration Aggregation: All module configurations are merged
- Dependency Resolution: Homebrew packages, taps, and casks are collected
- Dotfile Deployment: GNU Stow deploys all dotfiles
- Package Installation: Homebrew installs all dependencies
- Modular: Mix and match modules for different setups
- Automated: One command sets up your entire environment
- Reproducible: Same setup across multiple machines
- Version Controlled: All configurations in Git
- Conflict Resolution: Intelligent handling of configuration conflicts
- Missing dependencies: Ensure all required Ansible roles are installed
- Stow conflicts: Check for existing dotfiles that might conflict
- Homebrew issues: Ensure Homebrew is properly installed
Run with verbose output to see what's happening:
ansible-playbook -i playbooks/inventory playbooks/deploy.yml --ask-become-pass -vThis repository uses GitHub Spec-Kit for spec-driven development with Cursor AI.
Note: Spec-Kit commands require the GitHub Spec-Kit extension to be installed in Cursor. The commands are provided by the extension, not by files in this repository.
Spec-Kit is installed via UV (Python tool manager), not as a Cursor extension:
# Install UV if not already installed
brew install uv
# Install Spec-Kit CLI
uv tool install specify-cli --from git+https://github.com/github/spec-kit.git
# Verify installation
specify checkOnce installed, the /speckit.* slash commands will be available in Cursor's AI chat (press Cmd+K).
For detailed usage instructions, see CURSOR.md.
Once the Spec-Kit extension is installed, press Cmd+K in Cursor and use slash commands:
- Create specification:
/speckit.specify Add Firefox module with developer edition - Create plan:
/speckit.plan Install via Homebrew, configure for development - Generate tasks:
/speckit.tasks - Implement:
/speckit.implement
These commands are provided by the GitHub Spec-Kit extension:
/speckit.constitution- View/update project principles/speckit.specify- Create feature specifications/speckit.clarify- Interactive requirement clarification/speckit.plan- Generate implementation plans/speckit.tasks- Break down into actionable tasks/speckit.implement- Execute implementation/speckit.analyze- Verify cross-artifact consistency/speckit.checklist- Quality validation gates
See CURSOR.md for comprehensive development guidelines and patterns.
This repository is governed by a set of policy documents:
- Constitution - Core principles and governance framework (v1.0.0)
- Governance Model - Decision-making and change processes
- Coding Standards - Code quality and style guidelines
- Changelog - History of changes and versions
All contributions must comply with the principles defined in the Constitution.
If you were using the old bootstrap.sh script, the new structure is fully compatible. The Ansible playbook replaces the bootstrap script and provides the same functionality with additional benefits:
- Automated dependency management
- Idempotent operations
- Better error handling
- Cross-platform support (with configuration)
Thanks to getfatday for the ansible-role-dotmodules structure and inspiration.
MIT License - see LICENSE file for details.