Track ~/.aws/config (profiles only, never credentials) as a copied config: setup.sh restores it, update.fish refreshes it. Document the S3 state backend setup for resoftware-iac in the README, including the config/credentials profile-header gotcha behind "failed to get shared config profile". Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
macOS Configuration
Personal macOS setup. This README is a complete, ordered runbook for setting up a fresh machine — follow it top to bottom and you end up with a working environment.
Two kinds of files live here:
- Symlinked — the file in this repo is the live config (fish, starship, ssh, kube, npm, NuGet). Edit either side, they're the same file.
- Copied — files that can't be symlinked (
/etc/hosts, Claude/Serena settings, the AWS config, the brewfile). Refresh them from the machine with./update.fish.
Fresh machine setup — the fast way
Get this repo onto the machine (USB stick copy or a clone) and run:
/bin/bash setup.sh
The script is idempotent and does steps 1–9 below automatically: it copies the
repo to ~/Repositories/personal/macos-configuration (so it works straight off
a USB stick), installs Command Line Tools and Homebrew, runs the brew bundle,
creates all symlinks, restores the copied configs, sets fish as the default
shell, and installs the .NET SDK. At the end it prints the manual steps that
remain (1Password/SSH keys, iTerm2 profile import, gh auth login + repo
cloning, WireGuard, app sign-ins).
The sections below document what the script does, for reference or manual runs.
Fresh machine setup — step by step
1. Install Command Line Tools and clone this repo
xcode-select --install
mkdir -p ~/Repositories/personal
git clone https://github.com/awatertrevi/macos-configuration.git ~/Repositories/personal/macos-configuration
cd ~/Repositories/personal/macos-configuration
(First clone happens over HTTPS; once 1Password + SSH are set up below, remotes work over SSH.)
2. Install Homebrew
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
eval "$(/opt/homebrew/bin/brew shellenv)"
3. Install all packages, casks, and VS Code extensions
brew bundle --file=brewfile
This installs everything: CLI tools (fish, gh, node, pnpm, uv, opentofu, …), apps (1Password, iTerm2, Docker Desktop, Fork, VS Code, …), fonts, and VS Code extensions.
4. Sign in to 1Password and enable the SSH agent
Open 1Password → Settings → Developer → enable SSH Agent. The ssh-config
symlinked below routes all SSH auth through the 1Password agent
(~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock), so the
private keys never live on disk — only the .pub files referenced in
ssh-config need to exist in ~/.ssh/ (1Password can export them, or copy
them from the old machine).
5. Symlink configuration files
Run from the repo root:
mkdir -p ~/.config/fish ~/.kube ~/.nuget/NuGet
ln -sf $(pwd)/fish-config.fish ~/.config/fish/config.fish
ln -sf $(pwd)/starship.toml ~/.config/starship.toml
ln -sf $(pwd)/ssh-config ~/.ssh/config
ln -sf $(pwd)/kube-config ~/.kube/config
ln -sf $(pwd)/.npmrc ~/.npmrc
ln -sf $(pwd)/NuGet.Config ~/.nuget/NuGet/NuGet.Config
6. Restore the copied configs
mkdir -p ~/.claude ~/.serena ~/.aws
cp claude-settings.json ~/.claude/settings.json
cp serena_config.yml ~/.serena/serena_config.yml
cp aws-config ~/.aws/config
sudo cp hosts /etc/hosts
(aws-config only holds profile definitions — the actual AWS credentials are
set up later, in the "AWS + OpenTofu state access" step.)
7. Set fish as the default shell
echo /opt/homebrew/bin/fish | sudo tee -a /etc/shells
chsh -s /opt/homebrew/bin/fish
8. Configure iTerm2
iTerm2 → Settings → Profiles → Other Actions → Import JSON Profiles →
select iterm-profile.json, then set it as the default profile.
(Requires the Fira Code Nerd Font installed in step 3.)
9. Install the .NET 10 SDK
fish install-dotnet10.fish
Installs into ~/.dotnet via the official dotnet-install script and prints the
fish_add_path line to persist it if needed.
10. Clone work repositories
gh auth login # authenticate the GitHub CLI first
fish clone-resoftware-repos.fish
Clones every repo in the resoftware GitHub org via SSH into
~/Repositories/{customer-number}/{repo-name}, based on each repo's
customer-number custom property. Safe to re-run — existing clones are skipped.
11. AWS + OpenTofu state access (resoftware-iac)
All OpenTofu state for resoftware-iac lives in the S3 bucket
resoftware-iac-state (eu-north-1); the backend blocks in that repo reference
the resoftware-iac AWS profile, so tofu init fails with "failed to get
shared config profile resoftware-iac" until that profile exists.
The aws-config restored in step 6 already defines both profiles in
~/.aws/config:
resoftware-iac— theiacIAM user; used for the S3 state backend and plans.default— a root login session (account 693091788121); used for applies viaaws configure export-credentials.
What can't live in git and must be set up by hand:
aws configure --profile resoftware-iac
Enter the iac user's access key (from 1Password or the old machine's
~/.aws/credentials; or mint a fresh key in the AWS console — IAM is
deliberately console-managed, not IaC) and region eu-north-1. Beware if
editing the files manually instead: ~/.aws/config section headers carry a
profile prefix ([profile resoftware-iac]) but ~/.aws/credentials headers
do not ([resoftware-iac]) — mismatching them causes exactly the
"failed to get shared config profile" error. aws configure writes both
correctly.
For applies, also establish the root session once:
aws login
Then restore each stack's gitignored terraform.tfvars (Infisical
machine-identity creds — copy securely from the old machine or refill from
Infisical; currently only infra/cloudflare/terraform.tfvars), and verify:
aws sts get-caller-identity --profile resoftware-iac
cd ~/Repositories/kl0000/resoftware-iac/infra/cloudflare && tofu init
12. WireGuard tunnel to home network (optional)
meerkoet-proxy.conf is a WireGuard client config for the home (Fritz!Box)
network. Import it into the WireGuard app (installable from the App Store) via
Import Tunnel(s) from File.
13. Manual leftovers
Things not automated here:
- Sign in: iCloud, Chrome/Zen, Slack, Spark, Google Drive, Docker Desktop, Todoist.
- JetBrains Toolbox → sign in and install the IDEs you use.
- Grant permissions as apps ask (Bartender, BetterTouchTool, CleanShot, Mos, Cursr).
- Alfred / BetterTouchTool: restore licenses and sync/import preferences.
Keeping this repo up to date
The symlinked files are always current by construction. Refresh the copied ones with:
./update.fish
It re-dumps the brewfile (brew bundle dump --force) and re-copies
~/.claude/settings.json, ~/.serena/serena_config.yml, ~/.aws/config, and
/etc/hosts into the repo. Review git diff afterwards and commit.
(~/.aws/credentials is never tracked.)