Skip to content

Repository files navigation

Dotfiles

Cross-platform dotfiles automation using A-frame architecture with DRY principles and nullable safety patterns.

Quick Start

git clone https://github.com/amamel/dotfiles.git ~/.dotfiles
cd ~/.dotfiles
./install

The installer will detect your OS and guide you through an interactive setup.

Supported Platforms

  • macOS 10.15+ (Intel and Apple Silicon) - Full support
  • Linux (Ubuntu, Debian, elementary OS, and other Ubuntu/Debian derivatives) - Full support with APT and Snap package management

Architecture

A-Frame Design

  • Main configuration (install.conf.yaml) handles shared logic
  • OS-specific modules (scripts/macos/, scripts/linux/) provide platform customizations
  • Shared functions (lib/) eliminate code duplication

Nullable Safety

All operations handle missing files, commands, and environment variables gracefully. Scripts continue execution even when optional components fail.

DRY Optimization

  • Shared functions in lib/utils.sh and lib/logger.sh
  • Universal package manager interface (scripts/common/package_manager.sh)
  • Centralized logging and validation

Dotbot Plugins

Beyond dotbot's built-in link/create/shell/clean directives, install.conf.yaml uses three vendored plugins (plugins/, each a git submodule):

  • dotbot-conditional - real if:/then:/else: gating for any directive (dotbot's own shell:/create: have no native if: support; only link: does)
  • dotbot-flatpak - installs Flatpak packages on Linux
  • dotbot-firefox - symlinks a managed user.js into every detected Firefox profile

File Structure

dotfiles/
├── install                           # Main installer script
├── install.conf.yaml                 # Dotbot configuration
├── lib/                              # Shared shell libraries
│   ├── utils.sh                      # DRY helper functions
│   └── logger.sh                     # Centralized logging
├── plugins/                          # Dotbot plugins (git submodules)
│   ├── dotbot-conditional/
│   ├── dotbot-flatpak/
│   └── dotbot-firefox/
├── configs/                          # Configuration files
│   ├── shell/
│   │   ├── zsh/                      # zsh config (+ macOS/Linux variants)
│   │   └── bash/                     # bash config
│   ├── editors/
│   │   ├── nvim/
│   │   ├── vim/
│   │   └── vscode/                   # settings, keybindings, extensions.json, tasks.json
│   ├── git/                          # gitconfig + empty gitconfig.local/gitignore templates
│   ├── terminal/                     # tmux, alacritty, iTerm2
│   ├── development/                  # rbenv default-gems
│   └── tools/                        # firefox, mackup, nano, neofetch, yt-dlp
├── scripts/                          # Installation scripts
│   ├── common/                       # Shared/cross-platform setup scripts
│   ├── macos/                        # macOS-specific scripts
│   └── linux/                        # Linux-specific scripts
├── packages/                         # Package definitions
│   ├── macos/
│   │   ├── Brewfile                  # All brews/casks — select interactively at install time
│   │   └── mas.yaml
│   ├── linux/
│   │   ├── apt.yaml
│   │   └── snap.yaml
│   ├── common.yaml
│   └── node.yaml
└── .github/workflows/                # CI: shellcheck + YAML validation, secrets scan

Configuration Management

Shell Configuration (A-Frame)

The zsh configuration uses A-frame architecture:

  • ~/.zshrc - Main frame with conditional OS loading
  • zshrc.macos - macOS-specific (Antidote plugin manager)
  • zshrc.linux - Linux-specific (Oh-My-Zsh)

Environment Variables

Control behavior through environment variables:

# Package installation
ENABLE_HOMEBREW_INSTALL=true
ENABLE_ESSENTIAL_TOOLS=true
ENABLE_BREWFILE=true

# SSH setup
SSH_KEY_TYPE=ed25519
AUTO_GENERATE_KEY=false

Custom Overrides

Create local customization files that won't be tracked:

  • ~/.zshenv.local, ~/.zshenv.local.macos, ~/.zshenv.local.linux - Environment overrides
  • ~/.zshrc.local, ~/.zshrc.local.macos, ~/.zshrc.local.linux - Shell customizations
  • ~/.bashrc.local, ~/.bash_profile.local - Bash equivalents
  • ~/.gitconfig.local - Real git identity (configs/git/gitconfig.local ships empty on purpose — never commit real name/email here)
  • ~/.gitignore - Personal global ignore patterns (configs/git/gitignore ships empty on purpose)
  • .env - Environment variable overrides (copy from .env.template)

Environment Configuration (.env)

Copy .env.template to .env in the root directory to customize behavior:

cp .env.template .env
# Edit .env with your preferences

Available configuration options:

  • Package Installation: Control Homebrew, APT, Snap, and essential tools
  • Interactive UI: BREW_INTERACTIVE and MACOS_DEFAULTS_INTERACTIVE — set to false for non-interactive installs
  • SSH Setup: Key type (ed25519/rsa/ecdsa), auto-generation
  • Node.js: Version manager (nvm/n/system), version, NVM_VERSION
  • Ruby: Version specification
  • Logging: Enable/disable debug, colors, file logging

Package Management

macOS

  • Homebrew for command-line tools (auto-installed if missing)
  • Homebrew Cask for GUI applications
  • Mac App Store via mas (YAML-based configuration)
  • Brewfile: Single combined file — an interactive gum selector lets you choose exactly which packages to install
  • Formulas from third-party taps (e.g. bjarneo/cliamp/cliamp) must use their fully-qualified name in the Brewfile — Homebrew Bundle auto-taps from that, a bare formula name won't resolve

Linux

  • APT for system packages (Ubuntu/Debian and derivatives)
  • Snap for GUI applications (optional, disabled by default)
  • Flatpak for GUI applications, via the dotbot-flatpak plugin (only runs when Flatpak is already present)
  • YAML-based package definitions:
    • packages/linux/apt.yaml - APT packages by profile
    • packages/linux/snap.yaml - Snap packages by profile

Cross-Platform

  • packages/common.yaml - Universal packages (git, curl, etc.)
  • packages/node.yaml - NPM global packages by profile

Package lists are fully defined in YAML files under the packages/ directory, organized by OS and profile.

Development Environment

Included Tools

  • Shell: zsh with plugins (Antidote on macOS, Oh-My-Zsh on Linux)
  • Editors:
    • Neovim with modern Lua configuration and Lazy.nvim plugin manager
    • Vim with sensible defaults
    • VS Code Insiders — settings/keybindings/tasks symlinked per-OS, plus extensions.json (installed automatically via the CLI on setup)
  • Browsers:
    • Firefox — user.js (telemetry/studies/Pocket/sponsored content/AI features off, plus other settings pulled from the real profile) symlinked into every profile via dotbot-firefox; extensions.json is a reference manifest of installed extensions (name + AMO link) — Firefox has no unprivileged auto-install mechanism, so this is documentation for manual reinstall via about:addons, not automation
  • Terminal:
    • tmux with TPM plugins (resurrect, continuum, yank, etc.)
    • iTerm2 color schemes (macOS)
    • Alacritty configuration
  • Version Control: Git with global ignore patterns and local overrides
  • Languages:
    • Go (via Homebrew/APT)
    • Rust (via rustup, not the OS package manager — see scripts/common/setup_rust.sh)
    • Node.js (via nvm, n, or system)
    • Python 3 (system or pyenv)
    • Ruby (via rbenv with auto-install latest stable)
  • Media: cliamp, a terminal music player (Linux install is a checksum-verified upstream script, not an apt package — see scripts/linux/setup_cliamp.sh)

Productivity Tools (macOS)

  • Alfred - Application launcher
  • Rectangle - Window management
  • Hammerspoon - Automation
  • Hazel - File organization
  • Mackup - Application settings sync
  • Cyberduck - FTP/SFTP client

Continuous Integration

.github/workflows/ runs on every push/PR to main:

  • code-quality.yml - shellcheck across all scripts, YAML syntax validation
  • code-security.yml - secrets scan via gitleaks

Scripts Overview

Shared Libraries (lib/)

  • utils.sh - DRY utilities library
    • Environment loading with multiple fallbacks
    • Package management helpers (install_package, install_packages)
    • Service management (systemctl/brew services)
    • APT repository management (prefers UBUNTU_CODENAME from /etc/os-release so third-party repos resolve correctly on Ubuntu derivatives like elementary OS)
    • Internet and command availability checks
  • logger.sh - Centralized logging library
    • Color-coded output (info, success, warning, error, debug)
    • Optional file logging support
    • Configurable via environment variables

Core Scripts (scripts/common/)

  • detect_os.sh - Comprehensive OS, architecture, and environment detection
    • Detects: macOS version, Linux distro, architecture (x86_64/arm64)
    • Environment: Headless, CI, container, SSH session detection
    • Exports variables to /tmp/dotfiles_env for use across all scripts
  • validate_installer.sh - Pre-installation validation
    • Checks: Git repo, required files, YAML syntax, permissions
    • OS-specific validation
    • Dotbot dry-run test
  • package_manager.sh - Universal repository setup (NodeSource, Docker, etc.) on top of the detected package manager

Setup Scripts (scripts/common/)

  • setup_shell.sh - Shell environment configuration (bash/zsh detection, Antidote/Oh-My-Zsh, bin directories)
  • setup_ssh.sh - SSH key generation, config, and OS-specific agent setup
  • setup_node.sh - Node.js via nvm/n/system, NPM packages from node.yaml
  • setup_ruby.sh - rbenv install, latest stable Ruby, default gems
  • setup_rust.sh - rustup install (--no-modify-path, since shell rc files already handle ~/.cargo/env), rustfmt/clippy components
  • setup_vscode_extensions.sh - installs any missing extensions from configs/editors/vscode/extensions.json via the code/code-insiders CLI

OS-Specific Scripts

macOS (scripts/macos/)

  • install_packages.sh - Full Homebrew + Cask + MAS installation
  • brew_select.sh - Interactive gum package selector for the Brewfile
  • setup_macos_defaults.sh - Extensive macOS system preferences, interactive gum selector

Linux (scripts/linux/)

  • install_packages.sh - APT package management, YAML-based, profile-specific
  • apt_select.sh - Interactive gum package selector for apt.yaml/snap.yaml
  • setup_snap.sh - Snap bootstrap (headless-skipped)
  • setup_cliamp.sh - ALSA bridge package (PipeWire/PulseAudio) + upstream checksum-verified installer for cliamp

Installation Options

Standard Installation

./install
# Prompts for profile selection (workstation/server/home)
# Auto-detects OS

Force Specific OS

./install --os macos    # Force macOS detection
./install --os linux    # Force Linux detection

Using Makefile

make install                    # Install dotfiles
make install-workstation        # Install with the workstation profile
make install-linux               # Install forcing Linux detection

make update                     # Update dotbot and reinstall
make validate                   # Run comprehensive validation (validate_installer.sh)
make test                       # Run basic configuration tests
make doctor                     # Full health check
make info                       # Show system information

Validation and Testing

# During install, choose "V" at the confirmation prompt to validate without installing
make validate                   # Comprehensive validation
make test                       # YAML syntax and script checks
make lint                       # ShellCheck and YAML lint
make dry-run                    # Show what would be linked

Maintenance

make archive                    # Create backup archive of the whole dotfiles directory
make mackup-backup               # Backup app settings with Mackup
make mackup-restore               # Restore app settings
make clean                      # Clean old logs
make logs                       # View recent logs

Customization

Adding Packages

macOS packages - Edit packages/macos/Brewfile:

brew "new-package"
cask "new-app"

Linux packages - Edit packages/linux/apt.yaml:

development:
  - new-package

Adding Configurations

  1. Place config files in configs/ directory
  2. Add symlink in install.conf.yaml:
~/.config/newapp/config:
  path: configs/newapp/config

OS-Specific Configurations

link: supports a native if: for simple per-OS symlinks:

~/.config/app/config:
  if: '[ "$OS" = "macos" ]'
  path: configs/app/config.macos

For anything beyond link: (e.g. a shell:/create: step that also needs to be conditional), wrap it in the conditional: plugin instead:

- conditional:
    if: '[ "$OS" = "linux" ] && [ "$IS_HEADLESS" = "false" ]'
    then:
      - create:
          - ~/some/dir
      - shell:
          - command: scripts/linux/some_setup.sh

Troubleshooting

Installation Fails

  1. Choose "V" at the install prompt to validate, or run make validate
  2. Check OS support and requirements
  3. Ensure internet connectivity
  4. Verify repository access

Permission Issues

# Fix SSH permissions
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_*
chmod 644 ~/.ssh/id_*.pub

# Fix Homebrew permissions (macOS)
sudo chown -R $(whoami) /opt/homebrew

Environment Variables Not Loading

# Source environment manually
source /tmp/dotfiles_env

# Check detection script output
./scripts/common/detect_os.sh

Package Installation Issues

# Update package managers
brew update              # macOS
sudo apt update         # Linux

# Clear package caches
brew cleanup            # macOS
sudo apt autoclean     # Linux

Shell Features

After installation, you'll have access to powerful aliases and functions defined in:

  • ~/.aliases - Common command shortcuts
  • ~/.functions - Utility functions

Notable Aliases

# Navigation
..          # cd ..
...         # cd ../..
mkcd        # Create directory and cd into it

# File operations (with modern tool fallbacks)
ls          # Uses eza if available
cat         # Uses bat if available
find        # Uses fd if available
grep        # Uses ripgrep (rg) if available

# Git shortcuts
g           # git
gst         # git status
gac         # git add . && commit (function)
gacp        # git add . && commit && push (function)

# Docker
d           # docker
dc          # docker-compose
dps         # docker ps with formatting

# System
update      # OS-aware system update (macOS: brew + softwareupdate, Linux: apt + snap)
sysinfo     # System information (uses neofetch if available)

Notable Functions

dotfiles <command>      # Quick dotfiles management
  - update              # Update dotfiles
  - install             # Reinstall
  - status              # Git status
  - info                # System info
  - logs                # View logs

rb <command>            # Ruby version management
  - list                # List available Ruby versions
  - install [version]   # Install Ruby version
  - use [version]       # Set global Ruby version

mackup_backup           # Backup app settings
mackup_restore          # Restore app settings
mas_list                # List installed Mac App Store apps
mas_search <app>        # Search Mac App Store

bookmark <command>      # Directory bookmarks
  - save <name>         # Bookmark current directory
  - go <name>           # Navigate to bookmark
  - list                # List all bookmarks

weather [city]          # Get weather information
genpass [length]        # Generate secure password
serve [port]            # Quick HTTP server (default: 8000)
extract <file>          # Smart archive extraction

Safety Features

  • Idempotent - Safe to run multiple times (verified end-to-end: a second run produces zero changes)
  • Non-destructive - Won't overwrite existing configurations without confirmation
  • Validation - Pre-installation environment checks
  • Graceful degradation - Continues even when components fail
  • Nullable safety - All operations handle missing files/commands gracefully
  • Environment isolation - Clears contaminated OS variables before installation
  • CI-checked - Every push/PR is shellchecked, YAML-validated, and secrets-scanned

See CHANGELOG.md for recent changes.

License

MIT License - see LICENSE file for details.

About

All my system dotfiles

Resources

Stars

0 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages