Mac Setup Run Log — 2026-03-18
Last verified: 2026-03-18
Run context
- Date: 2026-03-18
- Branch:
kyle/mac-setup-local - Machine state: Repo already cloned, Xcode CLI tools and Homebrew present. No Ansible, no gh CLI, no SSH key, no git config. Rancher Desktop not running.
Pre-playbook: bootstrap.sh prerequisites
The bootstrap script (infra/mac-setup/bootstrap.sh) assumes it runs on a factory-reset Mac and installs prerequisites before calling Ansible. Since the repo was already cloned, I ran the missing steps manually instead of the full script.
| Step | Status | Decision |
|---|---|---|
| Xcode CLI tools | Already installed | Skipped |
| Homebrew | Already installed | Skipped |
brew install ansible gh |
Not installed | Installed both via brew |
gh auth login |
Not authenticated | Deferred — requires interactive browser login, not automatable from this session. Noted as manual post-step. |
| Clone repo | Already at ~/gh/multi |
Skipped |
Playbook run 1 — failure
ansible-playbook infra/mac-setup/playbook.yml
Result: Failed at task "Generate SSH key if missing".
Root cause: community.crypto.openssh_keypair requires the parent directory (~/.ssh) to exist. The playbook did not create it.
Fix applied: Added a new task before SSH key generation:
- name: Create .ssh directory
ansible.builtin.file:
path: "{{ ansible_facts['env']['HOME'] }}/.ssh"
state: directory
mode: "0700"
Tasks that succeeded before failure
| Task | Result |
|---|---|
| Homebrew packages (git, gh, jq, node, python@3, helm, helmfile, pre-commit, ansible) | Installed |
| Homebrew casks (rancher) | Installed |
| npm global (@anthropic-ai/claude-code) | Installed |
| Rancher Desktop check | Not running (skipped dependent tasks) |
| Create secrets directory | Created ~/gh/multi/secrets/ (mode 0700) |
| Create .claude directory | Created ~/.claude/ (mode 0700) |
| Git config (name, email, defaultBranch) | Set |
Playbook run 2 — success
After adding the .ssh directory task, full playbook passed (0 failures).
Additional changes in this run:
| Task | Result |
|---|---|
| Create ~/.ssh (mode 0700) | Created |
| Generate ed25519 SSH key | Created — key generated (add to GitHub manually) |
| Pre-commit hooks | Installed (commit + pre-push) |
| Blog npm deps | Installed |
| ~/.zprofile | Added Homebrew shellenv + Rancher PATH lines |
Playbook run 2 — deprecation warnings
Ansible 13.x emits INJECT_FACTS_AS_VARS deprecation warnings for every use of ansible_env.HOME. This will become a hard error in ansible-core 2.24.
Fix applied: Replaced all ansible_env.HOME references with ansible_facts['env']['HOME'] across the playbook (7 occurrences including the lookup() call).
Playbook run 3 — validation
Clean run confirming deprecation fix. Zero failures, zero warnings (aside from the expected no-inventory warnings which are harmless for localhost).
Skipped tasks (expected)
| Task | Why skipped |
|---|---|
| Symlink Rancher docker | Rancher Desktop not running |
| kubectl cluster-info | Rancher Desktop not running |
| Lima VM workspace dirs | Rancher Desktop not running |
| Show SSH public key | Key already existed (run 3) |
Summary of changes to codebase
infra/mac-setup/playbook.yml— AddedCreate .ssh directorytask before SSH key generationinfra/mac-setup/playbook.yml— Replaced allansible_env.HOMEwithansible_facts['env']['HOME']to fix Ansible 13.x deprecation warningsinfra/mac-setup/bootstrap.sh— Replaced interactivegh auth loginwith GitHub App installation token flow usingGH_TOKENenv var (JWT signed with App PEM fromexports.sh)infra/mac-setup/bootstrap.sh— Removed--ask-become-passfrom ansible-playbook invocation (onlybecometask is docker symlink withfailed_when: false)infra/mac-setup/bootstrap.sh— Added timestamped progress output via_step()helperinfra/mac-setup/playbook.yml— Updated usage comment to remove--ask-become-pass.pre-commit-config.yaml— Scoped ruff hook totypes: [python]and biome hook totypes_or: [javascript, ts, jsx, tsx]so they don't fire on markdown/yaml/shell filesCLAUDE.md— Added guidance to poll background tasks every 15 seconds
Bugs found and fixed
| Bug | Root cause | Fix |
|---|---|---|
| Playbook fails on SSH key generation | ~/.ssh directory didn't exist, openssh_keypair doesn't create parent dirs |
Added Create .ssh directory task |
| Token extraction returns empty | GitHub API returns pretty-printed JSON (multi-line), sed only matched single lines |
Added tr -d '\n ' to collapse JSON before extraction |
gh auth login --with-token hangs |
Piped stdin ignored, falls through to interactive device flow | Switched to GH_TOKEN env var approach instead |
--ask-become-pass hangs in automation |
Prompts for sudo password interactively | Removed — the only become task has failed_when: false |
| Pre-commit hooks fail on markdown commits | ruff/biome hooks had no types filter, ran on all files, required Docker |
Added types filters to scope to Python/JS only |
Remaining manual steps
- Add SSH public key to GitHub — Settings → SSH keys
- Start Rancher Desktop — Then re-run playbook for K8s-dependent tasks (docker symlink, Lima workspace)
claude setup-token— Authenticate Claude Codebash ~/gh/multi/infra/ai-agents/bin/bootstrap.sh— Deploy K8s stack
Related:
wiki/devops/bootstrap