Imported from ryanspletzer/dev-machine-setup (
AGENTS.md). Install upstream withnpx skills add ryanspletzer/dev-machine-setup. Copyright stays with the author.
AGENTS.md
This file provides guidance to AI coding agents (Claude Code, Codex, Cursor, Copilot, Antigravity) when working with code in this repository.
Project Overview
Cross-platform dev machine setup automation for macOS, Windows, Ubuntu, Debian, and Fedora.
Each platform has its own directory with an entry-point script,
an automation engine, and a vars.yaml configuration file.
Architecture
Platform Automation Engines
| Platform | Entry Point | Automation | Package Manager |
|---|---|---|---|
| macOS | macOS/setup.sh |
Ansible (setup.yaml) |
Homebrew |
| Windows | windows/setup.ps1 |
Native PowerShell | Chocolatey |
| Ubuntu | ubuntu/setup.sh |
Ansible (setup.yaml) |
APT + Snap |
| Debian | debian/setup.sh |
Ansible (setup.yaml) |
APT + Flatpak |
| Fedora | fedora/setup.sh |
Ansible (setup.yaml) |
DNF + Flatpak |
All platforms share the same flow:
install prerequisites, load vars.yaml, install packages by category,
configure Git, run custom commands, run custom script, clean up.
Configuration: vars.yaml
Each platform's vars.yaml is the single source of truth.
Package lists are flat YAML arrays grouped by category:
- OS packages:
homebrew_formulae/homebrew_casks/choco_packages/apt_packages/snap_packages/dnf_packages/flatpak_packages/appimage_packages - Cross-platform:
powershell_modules,pipx_packages,uv_tools,npm_global_packages,pnpm_global_packages,bun_global_packages,dotnet_tools,vscode_extensions - Git config:
git_user_email,git_user_name - Custom commands:
custom_commands_user(non-elevated),custom_commands_elevated(sudo). Entries support an optionalcreatesfile path; the command is skipped once that file exists (keeps reruns idempotent) - Custom script:
custom_script(path to a script run at the end)
Key Differences Between Platforms
- macOS uses flat string arrays for
homebrew_formulaeandhomebrew_casks. All other platforms use objects with anamekey. - Windows
choco_packagesobjects support additionalparametersandprereleasekeys beyondname. - Windows
custom_commandsis a single list (not split into user/elevated) since the script already runs as Administrator. - Ubuntu has additional
external_apt_repositories(deb822 format) andapt_packages_prereqsfor bootstrap dependencies. - Ubuntu uses
supported_architectureson some packages to skip amd64-only software on ARM64. - Fedora has
external_dnf_repositories(yum_repository format) anddnf_packages_prereqsfor bootstrap dependencies. - Fedora uses
supported_architectureswithx86_64/aarch64values (notamd64/arm64like Ubuntu). - Debian shares the APT package format with Ubuntu but uses Flatpak instead
of Snap (
flatpak_packageslike Fedora). Debian prerequisites includegnupginstead ofsoftware-properties-common(which is Ubuntu-only for PPA support). Ubuntu PPAs (ppa.launchpad.netURLs) are not compatible with Debian. Docker and Microsoft repos use/linux/debianinstead of/linux/ubuntu. - Fedora uses
flatpak_packages(Flathub app IDs) instead of Snap packages. - Ubuntu/Debian/Fedora support
appimage_packagesfor generic AppImage installation. Each entry hasname,url, and optional fields (comment,categories,mime_types,no_sandbox,checksum,supported_architectures). Cursor is installed this way on Linux; macOS uses Homebrew caskcursor, Windows uses Chocolateycursoride. All platforms reuse thevscode_extensionslist for Cursor extension installation. uv_toolsinstalls Python CLI tools viauv tool install. On macOS/Windows,pipx_packagesis empty (uv is available via Homebrew/Chocolatey); on Linux,pipx_packagesretains onlyuv(pipx bootstraps uv, then uv manages the rest). The uv tools step is guarded on uv being installed -- if uv is not on PATH, the step is silently skipped.pnpm_global_packages/bun_global_packagesinstall global CLI tools viapnpm add -g/bun add -g. Likeuv_tools, both steps are guarded on the tool being installed -- ifpnpm/bunis not on PATH, the step is silently skipped. The binaries are installed as ordinary package-manager entries: Homebrew (pnpm,bunformulae) on macOS, Chocolatey (pnpm,bun) on Windows, and vianpm_global_packages(pnpm,bun) on Linux. pnpm needs its global bin directory onPATH, so the steps exportPNPM_HOME(~/Library/pnpmon macOS to match the shell configs,~/.local/share/pnpmon Linux,%LOCALAPPDATA%\pnpmon Windows) and prepend$PNPM_HOME/bin(pnpm's default global bin dir), so no pnpm config file is written.
Running the Setup Scripts
# macOS
cd macOS
chmod 700 ./setup.sh
./setup.sh -e your.email@example.com
# Ubuntu
cd ubuntu
chmod 700 ./setup.sh
./setup.sh -e your.email@example.com
# Debian
cd debian
chmod 700 ./setup.sh
./setup.sh -e your.email@example.com
# Fedora
cd fedora
chmod 700 ./setup.sh
./setup.sh -e your.email@example.com
# Windows (run as Administrator)
Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force
cd windows
.\setup.ps1 -e your.email@example.com
Common flags: -v (verbose, repeatable), -e (git email),
-n (git name), -p (prerequisites only, macOS/Ubuntu/Debian/Fedora),
-c (CI mode, skip interactive sudo prompts, macOS/Ubuntu/Debian/Fedora).
Ansible Tags (macOS/Ubuntu/Debian/Fedora)
The Ansible playbooks use tags to run specific sections:
# Run only Homebrew tasks
ansible-playbook setup.yaml --tags homebrew
# Run only VS Code extension installation
ansible-playbook setup.yaml --tags vscode
Editing Guidelines
Adding Packages
Add to the appropriate list in the platform's vars.yaml.
Keep entries alphabetically sorted within their group.
Comment groups organize packages by purpose.
When adding to multiple platforms,
use the correct format for each
(flat strings for macOS, name: objects for Ubuntu/Debian/Fedora/Windows).
Commit Messages
Follow conventional commits:
type(scope): brief description
Types: feat, fix, docs, style, refactor, test, chore.
Scope is typically the platform name: macOS, windows, ubuntu, debian.
Code Style
- Shell scripts:
#!/bin/sh,set -e, snake_case functions - PowerShell:
#Requiresdirectives, PascalCase, Get/Test/Set pattern with verbose logging - YAML: 2-space indent, comments above entries, group related packages with comment headers
- Ansible tasks: use
ignore_errors: yesfor package installs,changed_whenfor idempotency, tag every task
Design Principles
- Flat configuration -- no nested package structures
- Declarative --
vars.yamldescribes desired end state - Idempotent -- safe to run multiple times
- Extend through data -- add packages to
vars.yaml, not code to scripts