Skip to content

About

DevOps MacOs Daily Driver setup for DevOps work.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Setup MacBook for DevOps Work

Prerequisites

  • macOS (Apple Silicon or Intel)
  • Xcode Command Line Tools:
xcode-select --install

Fresh install

Follow these steps in order on a new machine:

# 1. Install Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

# 2. Install Ansible
brew install ansible

# 3. Clone this repo
git clone https://github.com/your-user/devops-daily-driver.git
cd devops-daily-driver

# 4. Install Ansible Galaxy collections
ansible-galaxy collection install -r requirements.yml

# 5. Configure your machine variables
cp host_vars/localhost.yml host_vars/localhost.yml.bak
# Edit host_vars/localhost.yml with your settings

# 6. Run the playbook
ansible-playbook daily-driver.yml

The playbook prompts once for a sudo password. It is only used by casks that ship their own installers (currently the Logitech ones) — press enter to skip it and those tasks will fail while everything else proceeds. No task uses become, so -K is not needed.

Preview a run without changing anything:

ansible-playbook daily-driver.yml --check

Project structure

devops-daily-driver/
├── .github/workflows/       # CI: yamllint, ansible-lint, syntax-check
├── .ansible-lint            # Rule config, with deferred rules documented
├── .yamllint                # Line length, ignores .ansible/
├── ansible.cfg              # Inventory path, deprecation_warnings
├── inventory.yml            # Explicit localhost (avoids Ansible warnings)
├── daily-driver.yml         # Main playbook
├── requirements.yml         # Galaxy collections
├── host_vars/
│   └── localhost.yml        # Machine-specific variables (cloud providers, etc.)
└── roles/
    ├── system/              # preflight, directories, dotfiles
    ├── macos/               # dock, finder, keyboard shortcuts
    ├── apps/                # ui-apps, cli-apps, docs, networking
    ├── dev-tools/           # git, gnupg, golang, cicd, kubernetes, iac
    ├── virtualization/      # docker, colima, buildx
    ├── editors/             # vscode, cursor, jetbrains, neovim
    ├── terminal/            # ghostty, zsh, tmux, fonts, nvim
    ├── aws/                 # awscli, eksctl, granted
    ├── azure/               # azure-cli
    ├── gcp/                 # google-cloud-sdk
    └── custom-tools/        # custom taps and tools

Run only specific roles (tags)

# Only macOS settings
ansible-playbook daily-driver.yml --tags macos

# Only CLI apps
ansible-playbook daily-driver.yml --tags cli-apps

# Only dotfiles
ansible-playbook daily-driver.yml --tags dotfiles

# Only the AeroSpace setup (WM, borders, SketchyBar, fonts, macOS tweaks, dotfiles,
# then the interactive permissions guide)
ansible-playbook daily-driver.yml --tags aerospace

# Only the permissions guide (e.g. after `brew upgrade sketchybar`)
ansible-playbook daily-driver.yml --tags permissions

Tags come in two layers. Role and area tags are the ones you normally reach for:

system, preflight, directories, dotfiles, macos, dock, finder, keyboard, apps, ui-apps, cli-apps, logitech, networking, documentation-tools, dev-tools, git-tools, gh-cli, glab, golang, cicd, kubernetes, cluster-visualization, iac, terraform, opentofu, secrets, linters, virtualization, colima, docker-buildx, editors, terminal, ghostty, zsh, pyenv, nvm, fonts, nvim, aws, azure, gcp, custom-tools, demo, menubar.

Feature tags cut across roles: aerospace runs everything for the window manager setup (AeroSpace, borders, SketchyBar, its fonts, macOS Spaces/menu bar tweaks, dotfiles sync) and ends with the interactive permissions guide.

Individual packages also carry their own tag (bat, jq, htop, k9s, …), so you can install a single tool without running its whole role:

ansible-playbook daily-driver.yml --tags k9s

Configuration variables

Machine-specific variables live in host_vars/localhost.yml. Role-specific defaults are in each role's defaults/main.yml and can be overridden via host_vars.

Key variables to configure in host_vars/localhost.yml:

# Cloud providers (opt-in, default false)
install_aws: true
install_azure: false
install_gcp: false

# Window manager — aerospace or yabai (yabai also installs skhd-zig)
window_manager: aerospace

# Dotfiles
dotfiles_repo: "https://github.com/your-user/dotfiles.git"

# Directories to create in $HOME
directories_to_create:
  - personal
  - work

# Custom tools (tap + formulae)
custom_user_taps:
  - your-tap/tap
custom_user_tools:
  - your-tap/tap/tool-name

Cloud providers

Cloud provider roles are opt-in and default to false. Enable them in host_vars/localhost.yml or override on the fly:

ansible-playbook daily-driver.yml -e install_aws=true

Combine with tags to run a single provider:

ansible-playbook daily-driver.yml --tags aws -e install_aws=true

Dotfiles

Clones the repository defined in host_vars/localhost.yml, syncs .config and .config_macos to ~/.config, copies .zshrc_macos to ~/.zshrc, and copies any of .gitconfig, .gitconfig-personal, .gitconfig-work if present. Syncing .config_macos reloads the selected window manager (AeroSpace, or Yabai and skhd-zig).

macOS settings

The macos role configures:

  • Dock — size, position (right), magnification, animation, indicators

  • Finder — extensions, hidden files, path bar, status bar, column view

  • Menu bar — Sound always shown

  • Spaces — no automatic rearranging of Spaces

  • Keyboard — full keyboard access, Spotlight shortcuts disabled, Siri disabled; with AeroSpace, Mission Control ctrl ←/→ disabled

    Both Spotlight and Siri bind ⌘Space; Siri's default is hold ⌘Space, which swallows the keystroke before any app sees it. The playbook frees the shortcut but cannot set Raycast's hotkey — Raycast keeps it in an encrypted internal database with no supported defaults key. See Manual steps.

Window manager (AeroSpace or Yabai)

Set window_manager in host_vars/localhost.yml:

  • aerospace (default) — installs AeroSpace (nikitabobko/tap/aerospace). Config and cheat sheet live in dotfiles .config_macos/aerospace/.
  • yabai — installs Yabai and skhd-zig.

The cli-apps tasks check with pgrep whether the selected window manager is running and start it if not, so "running" is the desired state rather than a side effect of the install task firing a handler. Syncing dotfiles .config_macos reloads it through handlers.

JankyBorders (FelixKratz/formulae/borders) highlights the focused window; its config lives in dotfiles .config_macos/borders/bordersrc.

SketchyBar (FelixKratz/formulae/sketchybar) is a bottom status bar: AeroSpace workspaces with app icons, focused app, Spotify, Slack, kube context (red for prod), Colima profiles, GitHub/GitLab reviews, AWS/GCP sessions, CPU, RAM, weather and outdated Homebrew packages. Config lives in dotfiles .config_macos/sketchybar/; fonts (font-sketchybar-app-font, font-sf-pro) are installed by the fonts tag. The GitLab, AWS and GCP items stay hidden until their CLI is logged in.

Ghostty

Installs Ghostty (tip/development build) and syncs config from dotfiles if dotfiles/.config/ghostty/ exists.

Neovim

Installs neovim via Homebrew. Config is managed via dotfiles.

Commit signing

The dev-tools role installs gnupg and pinentry-mac and writes ~/.gnupg/gpg-agent.conf, so GPG signing works if you already carry a key.

If you keep your SSH keys in an agent (1Password, Bitwarden, ssh-agent), SSH signing is less work than maintaining a GPG keyring — git has supported it since 2.34 and there is no key material on disk:

# ~/.gitconfig-personal
[user]
    email = <id>+<user>@users.noreply.github.com
    signingkey = key::ssh-ed25519 AAAA...
[gpg]
    format = ssh
[commit]
    gpgsign = true

The key:: prefix means "this is the key itself", not a path — git hands the public key to the agent, which signs with the private half. Register the same public key on GitHub a second time under Settings → SSH and GPG keys, with key type Signing Key; a key registered only for authentication will not verify signatures.

git log --show-signature reports No signature until you also point gpg.ssh.allowedSignersFile at a file mapping emails to keys. That is a local verification concern only — GitHub verifies against the keys on your account.

Raycast

Raycast keeps its settings in a SQLCipher-encrypted database and exposes no deeplink, CLI or defaults key to configure it, so nothing about it can be set declaratively. Two things follow.

The hotkey stays manual — set ⌘Space in Settings → General → Raycast Hotkey. The playbook frees the shortcut by disabling the Spotlight and Siri bindings, but cannot assign it.

Everything else can travel in a .rayconfig export (Settings → Advanced → Export Settings & Data), which covers extensions and their preferences, quicklinks, snippets, window layouts and general settings. Point raycast_config_path at it and run:

ansible-playbook daily-driver.yml --tags raycast-import

The task carries the never tag, so ordinary runs skip it — otherwise every run would pop Raycast's import dialog. Import still asks for confirmation; this makes it one click instead of reconfiguring extension by extension.

Keep the export out of a public repo. It is an opaque blob that may carry extension credentials, so secret scanners like gitleaks will not catch them. Store it in a password manager or private location. Raycast Pro's Cloud Sync (requiresPro) removes the need for the file entirely.

Privacy permissions (AeroSpace setup)

macOS only lets the user grant these. --tags permissions (also part of --tags aerospace, never part of a full run) opens the right pane, reveals the sketchybar binary in Finder and waits for Enter.

Where (System Settings → Privacy & Security) App Why
Accessibility AeroSpace (/Applications/AeroSpace.app) move and tile windows
Accessibility sketchybar (/opt/homebrew/Cellar/sketchybar/<version>/bin/sketchybar) read Slack/Discord Dock badges
Automation → System Events sketchybar (prompted on first use) Dock badges
Automation → Spotify sketchybar (prompted on first use) play/pause

After brew upgrade sketchybar the Cellar path changes and the Accessibility grant is lost (badges turn grey): remove the old entry and run --tags permissions.

Manual steps

The playbook cannot automate these:

Step Why
Raycast hotkey (Settings → General) stored in an encrypted internal database
Register the signing key on GitHub account-side, needs your session
Fill in ~/.gitconfig-work the repo ships a redacted placeholder; force: false keeps your local value
Approve system extensions Logitech and similar installers need Privacy & Security approval
AeroSpace Accessibility permission TCC prompt, needs user approval
Keep a single macOS Desktop AeroSpace only manages windows on the current Space
Firefox full-screen-api.macos-native-full-screen = false about:config, per profile; avoids fullscreen video creating its own Space

Development

Lint and validate before pushing — CI runs the same three checks:

yamllint .
ansible-lint
ansible-playbook --syntax-check daily-driver.yml

.ansible-lint carries a skip_list of rules that are deliberately deferred rather than disabled; each entry is commented with what it covers.

About

DevOps MacOs Daily Driver setup for DevOps work.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors