One-command setup for a highly opinionated Mac (and, later, Linux) development machine β web (React/Next/Vite) and native (React Native/Expo). It ships a curated stack with the decisions already made; chezmoi is the single orchestrator that installs everything, applies configs, and is safe to re-run on a fresh or existing machine.
- What gets installed: see TOOLS.md (auto-generated from the registry) and SKILLS.md (global agent skills).
- Source of truth:
home/.chezmoidata/registry.tomlβ one block per tool, toggle withenabled = true/false.
On a brand-new Mac with nothing installed (no git, no Homebrew), paste this single line:
sh -c "$(curl -fsSL https://ax-at.github.io/dotfiles/install)"It installs chezmoi if it's missing (a self-contained static binary β no git/brew required), then clones this repo and applies it.
What that one line runs
The URL serves install, which:
- installs chezmoi to
~/.local/binviaget.chezmoi.io(only if not already present), then - runs
chezmoi init --apply ax-atβ chezmoi's built-in git cloneshttps://github.com/ax-at/dotfiles.git(no system git needed) and applies everything.
Prefer to skip the wrapper? Run sh -c "$(curl -fsLS get.chezmoi.io)" -- init --apply ax-at directly, or β with Homebrew + git already installed β brew install chezmoi && chezmoi init --apply ax-at.
chezmoi will then:
- install Rosetta 2 (Apple Silicon) + Homebrew (which pulls in the Xcode Command Line Tools),
brew bundleevery enabled package from the registry,- install runtimes via mise (Node LTS, pnpm, Ruby, Zulu-17 JDK, Python) + npm CLIs,
- run the official installers for AI tools /
fallow/pass-cli, - install editor extensions, generate SSH keys +
ghlogin, and apply macOS defaults, - drop all dotfiles (zsh, starship, ghostty, git, nano, karabiner, linearmouse).
You'll be prompted once for your git identity (work + personal) and a few module toggles.
π‘ If the Command Line Tools GUI dialog ever blocks the run, finish it and re-run
chezmoi apply.
βΉοΈ How to tell it worked. chezmoi is silent on success β there's no completion banner. A normal shell prompt with no
Error:line means it finished; confirm withecho $?(0= success, non-zero = it aborted). A few steps continue on non-fatal errors instead of aborting, so scan the log for strayHTTP/error/failedlines. The known one: registering the SSH signing key needsgh'sadmin:ssh_signing_keyscope β if it's missing you'll see a404there, but the run still completes and everything else is applied.
chezmoi overwrites files it manages. Before the first apply on a machine you care about, install chezmoi without applying, then review:
sh -c "$(curl -fsLS get.chezmoi.io)" -- init ax-at # install + clone, DON'T apply
chezmoi diff # review every change
chezmoi apply --dry-run --verbose # see what scripts would run
# happy? then:
chezmoi apply(Drop the --apply and it clones only. If chezmoi is already installed, just chezmoi init ax-at.)
Back up any existing ~/.zshrc, ~/.gitconfig, etc. that you want to keep.
Secrets are never committed and never written to disk. The repo only ever holds
pass://vault/item/field reference locators (not secrets). At the point a tool runs, pass-cli
resolves those references and injects the real values into that tool's process environment only β
masked in logs, gone when the process exits:
# A committed reference (safe to publish):
export SOME_TOKEN="pass://Personal/some-service/password"
# Resolved into the child's env at invocation, nothing persisted:
pass-cli run -- some-toolOn a new machine, pass-cli installs automatically; authenticate once:
pass-cli login # one-time interactive auth
pass-cli info # verify the session
proton-pass-doctor # health-check the whole pipeline end to endproton-pass-doctor is a brew doctor-style diagnostic: it checks that pass-cli is installed, a
session is active, and a pass:// reference actually resolves to a real value β exiting non-zero
with a specific message for whichever step is wrong.
Degrades gracefully: before you log in, references simply stay unresolved and tools fall back to
their own auth β nothing breaks. No secret is wired in this repo yet; each real secret is added as a
per-tool pass-cli run wrapper when needed.
Tracked here because Apple/vendor flows require a human:
- Sign in to Apple ID (System Settings) β required for the App Store.
- Xcode (iOS builds): install from the App Store (or
mas install 497799835), launch once to accept the license, thensudo xcode-select -s /Applications/Xcode.app/Contents/Developer. - Android Studio first-run: install the SDK + an emulator (AVD).
ANDROID_HOMEis already exported in.zshrc. -
pass-cli login(see Secrets). - Grant Karabiner-Elements and LinearMouse their permissions (Input Monitoring / Accessibility) when prompted.
- Karabiner: open it β Complex Modifications β "Add Predefined Rule" β enable all "Windows Shortcuts" rules.
- VS Code / Cursor: turn off the built-in Settings Sync (chezmoi manages
settings.json). - AI-client plugins: authenticate PostHog, Vercel, and Supabase once per client (browser OAuth). Cursor is auto-imported from Claude β no manual add β see docs/ai-plugins.md.
- nanoclaw onboarding (only if
modules.nanoclawis enabled): if you deferred it duringchezmoi apply, finish it withcd ~/nanoclaw-v2 && bash nanoclaw.sh. - openclaw onboarding (only if
modules.openclawis enabled): if you deferred it duringchezmoi apply, finish it withopenclaw onboard. - Log out / back in so fast key-repeat + modifier changes fully apply.
Everything is driven by the registry and module toggles.
- Add a tool: append a
[[packages]]block tohome/.chezmoidata/registry.toml. - Remove a tool: set
enabled = false(stays documented, won't install). - Toggle a whole group: edit
[modules]in the registry (or answer the init prompts). - Switch an install method (e.g. AI tool from
brewβ official installer): change themethodfor that entry. - Start an app at login (macOS): add
start_at_login = trueto a[[packages]]block.75-login-itemsreconciles the macOS βOpen at Loginβ list against every flagged app β adding what you flag, removing what you un-flag (scoped by~/.local/state/dotfiles/login-items.applied, so hand-added login items are never touched).trueuses<name>.appand starts hidden; usestart_at_login = "Bundle.app"for a different bundle name, orstart_at_login = { bundle = "Ghostty.app", hidden = false }to override the bundle and/or launch visible. First apply needs a one-time macOS Automation consent β approve the βcontrol System Eventsβ dialog (once per terminal app); a headless run without it is skipped with a warning rather than failing. - Regenerate the catalog:
make update-golden(CI enforces it stays current).
After editing, apply with chezmoi apply. Provisioning scripts re-run automatically when their content changes.
A curated set of agent skills is installed globally (available in every project) via npx skills for five agents: universal (the shared .agents/skills dir many tools read), claude-code, openclaw, hermes-agent, and pi. The full catalog is in SKILLS.md.
- Source of truth:
home/.chezmoidata/skills.tomlβ one[[repos]]block per source repo (repo+ askills = [...]list, plus an optional per-repoagentsoverride; omitted β all agents in the top-levelagentslist). Each repo installs in a single batchednpx skills add(one clone, symlinked into every target agent). - Agent granularity is per repo, not per skill: every skill in a
[[repos]]block shares that block's agent set. If one skill needs a different set, give it its own[[repos]]block (as theax-at/better-auth-skillsfork does). - Add / remove a skill: add or delete it from a block, then
chezmoi apply. The script reconciles against on-disk reality (skills list -g --json): it installs whatever's missing and uninstalls anything it previously installed that you've dropped from the file. It reads a manifest at~/.local/state/dotfiles/skills.appliedonly to scope removals, so skills you add by hand are never removed β and because reconcile trusts reality, it self-heals if the manifest drifts. (Identity is the skill name: hand-adding a skill whose name collides with a curated one makes it look "ours.") - Pin a skill: the CLI has no
@tagsyntax, butrepoaccepts any git source, so point it at a branch URL to pin (e.g. our forkax-at/better-auth-skillsfor the security skill). - Note: five Matt Pocock skills (
grilling,grill-me,code-review,resolving-merge-conflicts) plusshadcn/improve'simproveshare names with Claude Code built-ins and deliberately override them. - Regenerate the catalog:
make update-skills(CI enforces it stays current).
Runs after gh login (step 65, below), so clones are GitHub-authenticated and dodge anonymous rate limits β without exporting any token to the third-party skills the CLI runs. Installs are best-effort: a broken upstream skill logs a warning and is skipped β it never blocks chezmoi apply.
Plugins installed into the agent CLIs (Claude Code, Codex, Cursor), as opposed to the CLIs themselves. One plugin is declared once and fanned out across every supported client. Full details in docs/ai-plugins.md.
- Source of truth:
home/.chezmoidata/ai-plugins.tomlβ one[[plugins]]block per upstream plugin. Two backend families read it: native per-client sub-tables (claude/codex/cursor) installed by each client's own CLI, and anopensub-table installed by the universalnpx pluginsCLI (a sibling ofnpx skills, needs node + bun). Adding a new plugin is data-only. - Reconciles like skills:
66-ai-plugins(native) and67-open-plugins(open) each install what's declared and uninstall what you drop β scoped by a per-script manifest (ai-plugins.applied/open-plugins.applied), so a plugin you added by hand is never touched. Each backend runs only if its CLI (or node+bun) is present. - Ships today: the PostHog ai-plugin (27+ tools + 30+ skills) via the native backend, and the Vercel plugin (30 skills, 5 commands, 3 agents, MCP) via a hybrid backend β
openfor Claude Code, native for Codex (from Codex's built-inopenai-curatedmarketplace, since the official repo won't install natively there) β tool/skill access only; PostHog session telemetry is left unconfigured and Vercel telemetry is turned off in.zshrc. Also the Supabase plugin (MCP + 2 skills) via the native backend, Claude Code only β Codex has no installable package upstream. - Cursor is off by default: it auto-imports Claude-installed plugins (shown as imported), so no manual step runs β flip an entry's
enabled = trueto opt into an explicit Cursor install. - Auth is manual: installing a plugin doesn't authenticate it β each client needs a one-time browser OAuth (steps).
A bats suite covers template rendering, registry integrity, and the provisioning scripts' shell-function logic. It's offline-first β no installs, no machine changes. The one network-aware check (zsh plugin validation) prefers live GitHub when it's reachable and falls back to a pinned snapshot otherwise, so the suite stays green β and never flakes β anywhere. Run it against live GitHub on demand with make check-plugins. On a machine provisioned by this repo, chezmoi and bats are already on PATH (both are in the registry), so there's nothing to set up:
make test # whole suite
make test FILE=templates # one suite β test/templates.bats
make test FILTER=oxc # one test β regex over test names (bats -f)
make lint # shellcheck + shfmt + actionlintThe first run fetches pinned bats into test/lib/ (gitignored); the same suite gates every push via CI. Not yet bootstrapped and chezmoi isn't on PATH? Point at it once: make test CHEZMOI_BIN=~/.local/bin/chezmoi.
update-all # brew upgrade + mise upgrade + chezmoi update (alias in .zshrc)dotfiles/
βββ install # one-line bootstrap (served at ax-at.github.io/dotfiles/install)
βββ .nojekyll # serve Pages as static files (don't run Jekyll/Liquid)
βββ README.md # this guide
βββ TOOLS.md # generated tool catalog
βββ SKILLS.md # generated agent-skills catalog
βββ .chezmoiroot # β "home" (keeps repo meta out of $HOME)
βββ scripts/ # maintenance helpers (wired to `make` targets)
β βββ gen-tools.sh # regenerate TOOLS.md from the registry
β βββ gen-skills.sh # regenerate SKILLS.md from skills.toml
β βββ gen-ghostty-themes.sh # snapshot Ghostty's built-in themes for tests
β βββ check-plugins-live.sh # validate zsh plugin refs against live GitHub
βββ .github/workflows/ci.yml # template lint + TOOLS.md freshness + shellcheck
βββ home/ # β chezmoi source root
βββ .chezmoi.toml.tmpl # init prompts (identity + module toggles)
βββ .chezmoidata/registry.toml # SINGLE SOURCE OF TRUTH (tools)
βββ .chezmoidata/skills.toml # curated global agent skills
βββ .chezmoidata/ai-plugins.toml # AI-client plugins (PostHog/Supabase native; Vercel hybrid: `npx plugins` + native)
βββ .chezmoiexternal.toml # fetches Karabiner ruleset
βββ .chezmoiscripts/ # ordered provisioning steps
βββ dot_zshrc.tmpl dot_zsh_plugins.txt dot_gitconfig.tmpl dot_nanorc
βββ dot_config/{starship,ghostty,linearmouse,mise}/
| Script | Does |
|---|---|
run_once_before_10-prerequisites |
Rosetta + Homebrew (+ CLT) |
run_onchange_after_20-packages |
generate Brewfile from registry β brew bundle |
run_onchange_after_30-mise |
runtimes + npm-global CLIs |
run_onchange_after_40-ai-tools |
official script installers |
run_onchange_after_50-editor-extensions |
VS Code + Cursor extensions |
run_once_after_60-ssh-github |
SSH key + gh auth + signing key |
run_onchange_after_65-agent-skills |
reconcile global agent skills via npx skills |
run_onchange_after_66-ai-plugins |
reconcile AI-client plugins into the agent CLIs |
run_onchange_after_70-macos-defaults |
dev defaults + Ubuntu-feel tweaks |
run_onchange_after_75-login-items |
reconcile macOS βstart at loginβ apps |
run_once_after_90-nanoclaw-onboarding |
prompt to onboard nanoclaw now/later (opt-in) |
run_once_after_95-openclaw-onboarding |
prompt to onboard openclaw now/later (opt-in) |
The registry schema already supports linux (and per-distro apt/dnf) install methods, and chezmoi branches on {{ .chezmoi.os }} / {{ .chezmoi.osRelease.id }}. The Linux GUI-app story (flatpak/snap) and per-distro overrides are intentionally not built yet.
- Karabiner ships Windows/Linux shortcuts (
Ctrl+C/V/X/Z/A,Ctrl+β/βword-jump,Home/End) and excludes terminals, so shellCtrl+C/readline stay correct. - LinearMouse disables pointer acceleration (flat, Linux-like movement) and natural scrolling.
- Modifier keys stay at default (Winββ, Altββ₯); Karabiner does the shortcut work β don't also swap βββ₯.