init: scaffold mac project + inventory + setup design
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
*.key
|
||||||
|
*.pem
|
||||||
|
GITEA_API.md
|
||||||
|
.backup/
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
# mac
|
||||||
|
|
||||||
|
> Ops home for Seth's MacBook Pro — debloat, Linux-feel, Ableton-first.
|
||||||
|
|
||||||
|
## Start Here
|
||||||
|
|
||||||
|
**Read the latest handoff first:** `.claude/handoffs/` (most recent file).
|
||||||
|
It has session state, in-progress work, and ordered next steps.
|
||||||
|
|
||||||
|
Then check `IDEA.md` for the project brief and `DECISIONS.md` for settled choices.
|
||||||
|
|
||||||
|
## Project Identity
|
||||||
|
|
||||||
|
Configuration + scripts for Seth's MacBook Pro (arrived 2026-09-15). Three
|
||||||
|
goals, in priority order: (1) Ableton Live 12 runs clean — this is the DAW
|
||||||
|
box now that Wine on steel141 is abandoned; (2) feels like Linux to a Linux
|
||||||
|
user — GNU coreutils, `ip`, familiar shell, ssh-able from steel141; (3) stock
|
||||||
|
macOS noise turned off. Sibling of `~/bin/ableton/` (which is now an archive
|
||||||
|
of the Wine attempt) and `~/bin/thinkpad-yoga/` (same "ops home for a
|
||||||
|
laptop" shape).
|
||||||
|
|
||||||
|
## Current State
|
||||||
|
|
||||||
|
- **Phase:** ideation
|
||||||
|
- **Repo:** not yet
|
||||||
|
- **Deploy target:** the MacBook, `ssh mac` (192.168.0.94, user seth, en0 Wi-Fi)
|
||||||
|
- **Hardware:** MacBookPro18,1 (16" 2021), M1 Pro, 32 GB, 512 GB. **macOS 26.2 Tahoe.**
|
||||||
|
- Remote Login enabled + claude key installed 2026-09-15. `ssh mac` works from steel141.
|
||||||
|
- **FileVault is on** — no SSH after a reboot until the password is typed at the lid.
|
||||||
|
- Stock state is already clean: no Homebrew/CLT, only Safari in /Applications,
|
||||||
|
Siri off, Apple Intelligence opted out. Full snapshot:
|
||||||
|
`docs/reference/inventory-2026-09-15.md` — read when checking "was X stock?".
|
||||||
|
- No changes made yet.
|
||||||
|
|
||||||
|
## Conventions
|
||||||
|
|
||||||
|
- All changes as scripts under `scripts/` (bash, idempotent, `set -euo pipefail`);
|
||||||
|
never one-off `defaults write` in a chat that isn't also committed.
|
||||||
|
- Before any `defaults write`: `defaults read <domain> > .backup/<domain>-$(date +%s).plist`
|
||||||
|
- Before any `launchctl disable`/`bootout`: record current `launchctl print` state to `.backup/`
|
||||||
|
- Homebrew `Brewfile` at repo root is the package manifest — `brew bundle` is the install
|
||||||
|
- macOS gotchas go in this file's Conventions; per-decision reasoning goes in `DECISIONS.md`
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# DECISIONS.md — mac Decision Log
|
||||||
|
|
||||||
|
Project-specific decisions. For global/cross-cutting decisions, see `~/bin/DECISIONS.md`.
|
||||||
|
|
||||||
|
Format: `YYYY-MM-DD: <decision> — <why>`
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
|
## Deferred / Rejected
|
||||||
|
<!-- Decisions NOT to do something are just as valuable -- prevents re-proposing rejected ideas -->
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
# IDEA.md — Project Idea
|
||||||
|
|
||||||
|
## What is this?
|
||||||
|
Ops home for Seth's new MacBook Pro (Sept 2026). Debloat it, make it feel like
|
||||||
|
a Linux box to a Linux user, and tune it for Ableton Live 12 (native — the
|
||||||
|
steel141/Wine route was abandoned 2026-09-14, see `~/bin/ableton/`).
|
||||||
|
|
||||||
|
## Problem it solves
|
||||||
|
Stock macOS is noisy (Siri, Spotlight indexing everything, iCloud nags,
|
||||||
|
Photos/Music/News/TV auto-launch, animations, Dock junk) and the CLI is BSD
|
||||||
|
userland with zsh — `ip a` doesn't exist. Want: quiet machine, GNU-flavoured
|
||||||
|
shell, homelab reachability (SMB to tank, ssh aliases), and a DAW-first
|
||||||
|
config (no Time Machine mid-set, no sleep/App Nap on Live, audio not
|
||||||
|
tripped by notifications).
|
||||||
|
|
||||||
|
## Constraints / preferences
|
||||||
|
- Manage over SSH from steel141 (`ssh mac`, 192.168.0.94 LAN / Tailscale later)
|
||||||
|
- Homebrew for everything installable; scripted + idempotent, not hand-clicked
|
||||||
|
- `defaults write` changes are reversible — dump before changing (`.backup/`)
|
||||||
|
- Don't fight SIP/Gatekeeper; disable *services*, don't rip out system apps
|
||||||
|
- Ableton Suite Packs come with the license (in-app download); third-party
|
||||||
|
packs live at `/tank/Downloads/Software/Milkie/` via SMB from 192.168.0.173
|
||||||
@@ -0,0 +1,135 @@
|
|||||||
|
# Mac setup design — 2026-09-15
|
||||||
|
|
||||||
|
Design for turning the stock MacBook Pro (16" 2021 M1 Pro, macOS 26.2 Tahoe)
|
||||||
|
into a quiet, Linux-feeling, Ableton-first machine, managed over SSH from
|
||||||
|
steel141. Inventory baseline: `../reference/inventory-2026-09-15.md`.
|
||||||
|
|
||||||
|
## Goals (priority order)
|
||||||
|
|
||||||
|
1. Ableton Live 12 runs clean: no sleep/App Nap/notifications mid-session,
|
||||||
|
project files never touched by cloud sync, backed up to tank.
|
||||||
|
2. Feels like Linux to a bash user: GNU userland unprefixed, `ip a` works,
|
||||||
|
kitty, bash 5, fast key repeat, no press-and-hold accents, window snapping.
|
||||||
|
3. Stock macOS noise off: Dock stripped, Spotlight web/Siri suggestions off,
|
||||||
|
Photos analysis / Game Center / Handoff / iPhone Mirroring / Screen Time off.
|
||||||
|
4. Homelab reachable: tank over SMB, ssh aliases, Gitea, Tailscale.
|
||||||
|
|
||||||
|
## Non-goals
|
||||||
|
|
||||||
|
- Disabling SIP, Gatekeeper, or FileVault. All stay on.
|
||||||
|
- Removing anything under `/System/Applications` (sealed volume). Hide from Dock only.
|
||||||
|
- Swapping Cmd<->Ctrl globally. Live's shortcuts are Cmd-native on Mac.
|
||||||
|
- yabai (needs partial SIP disable). Tiling is AeroSpace if wanted later; Rectangle now.
|
||||||
|
- Running samples/projects off the SMB share. Local disk only; SMB is a source to copy from.
|
||||||
|
- Time Machine (over SMB it's fragile and backs up the whole disk; rsync of the
|
||||||
|
folders that matter is simpler and Linux-familiar).
|
||||||
|
|
||||||
|
## Decisions taken in this design (defaults — override in DECISIONS.md)
|
||||||
|
|
||||||
|
| Fork | Choice | Why |
|
||||||
|
|---|---|---|
|
||||||
|
| Login shell | Homebrew bash 5, set via `chsh` after adding to `/etc/shells` | Seth's steel141 shell is bash; macOS ships bash 3.2. zsh stays installed. |
|
||||||
|
| Cmd/Ctrl | Untouched | Live + every Mac tutorial assume Cmd. kitty handles Ctrl+Shift+C/V itself. |
|
||||||
|
| Window snapping | Rectangle (Homebrew cask) | Zero-config snapping. Upgrade path: AeroSpace if tiling turns out to matter. |
|
||||||
|
| Backup | launchd user agent -> `rsync -a --delete` of `~/Music/Ableton` and `~/Documents` to `pve173:/tank/backups/mac/` nightly over SSH | Transparent, one file, restorable with plain rsync. Needs a Mac->pve173 SSH key. |
|
||||||
|
| Hostname | **PARAMETER — not yet chosen** | Seth names machines (`bebop`, `yoga`, `steel141`). `setup.sh` takes it as `HOSTNAME=`. |
|
||||||
|
| iCloud | Account stays (Find My, Keychain). iCloud Drive "Desktop & Documents" sync OFF | Sync mid-save corrupts/evicts DAW project files. GUI-only toggle -> manual checklist. |
|
||||||
|
| Spotlight | Indexing stays ON; Siri Suggestions + web results OFF | Finder search still useful; Live's browser has its own index. |
|
||||||
|
|
||||||
|
## Components
|
||||||
|
|
||||||
|
All live in `~/bin/mac/`. Pushed to `git.sethpc.xyz/Seth/mac`. Applied by
|
||||||
|
`ssh mac` from steel141 (seth is the console user, so `defaults write` +
|
||||||
|
`killall Dock/Finder/SystemUIServer` take effect from an SSH session).
|
||||||
|
|
||||||
|
### `Brewfile`
|
||||||
|
Single manifest, applied with `brew bundle --file=Brewfile`. Contents:
|
||||||
|
|
||||||
|
- Formulae: `bash coreutils findutils gnu-sed grep gawk gnu-tar iproute2mac
|
||||||
|
tmux htop ripgrep fd jq wget rsync git tree`
|
||||||
|
- Casks: `kitty rectangle tailscale`
|
||||||
|
- NOT in Brewfile: Ableton Live (licensed download from ableton.com, manual).
|
||||||
|
|
||||||
|
### `scripts/setup.sh`
|
||||||
|
Idempotent bash, `set -euo pipefail`, run on the Mac as seth. Sections, in order:
|
||||||
|
|
||||||
|
1. **preflight** — refuse if not arm64 macOS 26.x; require `HOSTNAME` env var;
|
||||||
|
`xcode-select --install` if CLT missing (blocks on a GUI prompt the first
|
||||||
|
time — documented).
|
||||||
|
2. **backup** — for each `defaults` domain about to be written, `defaults
|
||||||
|
export <domain> ~/.mac-setup-backup/<domain>-<epoch>.plist` (skip if domain
|
||||||
|
absent). Also `pmset -g custom` and `launchctl print gui/$UID` to the same dir.
|
||||||
|
This dir is rsync'd back to `~/bin/mac/.backup/` by the runner on steel141.
|
||||||
|
3. **brew** — install Homebrew if missing; `brew bundle`; write shellenv +
|
||||||
|
gnubin PATH block into `~/.bash_profile` (guarded by marker comments so
|
||||||
|
re-runs don't duplicate).
|
||||||
|
4. **shell** — add `/opt/homebrew/bin/bash` to `/etc/shells` if absent;
|
||||||
|
`chsh -s` if current shell differs.
|
||||||
|
5. **hostname** — `scutil --set ComputerName/LocalHostName/HostName $HOSTNAME`.
|
||||||
|
6. **defaults (Linux feel)** — key repeat `KeyRepeat=2 InitialKeyRepeat=15`;
|
||||||
|
`ApplePressAndHoldEnabled=false`; natural scrolling off; Finder: path bar,
|
||||||
|
status bar, all extensions, `~` as new-window target, list view, no
|
||||||
|
`.DS_Store` on network/USB volumes; no window animations
|
||||||
|
(`NSAutomaticWindowAnimationsEnabled=false`); hot corners cleared.
|
||||||
|
7. **defaults (debloat)** — Dock: autohide, no recents, `persistent-apps`
|
||||||
|
rewritten to Finder/kitty/Live/System Settings (Live entry only if
|
||||||
|
`/Applications/Ableton Live 12*.app` exists); Spotlight Siri suggestions
|
||||||
|
off; Game Center + Handoff (`NSUserActivityTrackingEnabled`) + Screen Time
|
||||||
|
related agents disabled with `launchctl disable gui/$UID/<label>` only after
|
||||||
|
the label is confirmed present on this OS. Remove the "SparkFun Pro Micro"
|
||||||
|
PPP network service (`networksetup -removenetworkservice`).
|
||||||
|
8. **power (DAW)** — `sudo pmset -c sleep 0 displaysleep 0 disksleep 0
|
||||||
|
powernap 0`; battery profile untouched. App Nap off for Live via
|
||||||
|
`defaults write com.ableton.live NSAppSleepDisabled -bool true`.
|
||||||
|
9. **homelab** — `~/.ssh/config` seeded with the steel141 aliases (pve*,
|
||||||
|
bebop, etc.); tank SMB mount instructions written (mount itself is GUI /
|
||||||
|
`mount_smbfs` at login — see checklist); Tailscale cask installed, login is GUI.
|
||||||
|
10. **backup agent** — install `~/Library/LaunchAgents/xyz.sethpc.mac-backup.plist`
|
||||||
|
(StartCalendarInterval 03:30) running `scripts/backup.sh` (the rsync).
|
||||||
|
11. **apply** — `killall Dock Finder SystemUIServer`.
|
||||||
|
|
||||||
|
Each section prints `[skip]` when already in desired state. No section
|
||||||
|
prompts except the CLT install and `sudo` for pmset/chsh/hostname.
|
||||||
|
|
||||||
|
### `scripts/backup.sh`
|
||||||
|
`rsync -a --delete -e ssh ~/Music/Ableton ~/Documents root@192.168.0.173:/tank/backups/mac/`.
|
||||||
|
Logs to `~/Library/Logs/mac-backup.log`. Uses claude-style key
|
||||||
|
`~/.ssh/id_ed25519` generated on the Mac and installed on pve173 (manual step,
|
||||||
|
one-time).
|
||||||
|
|
||||||
|
### `docs/manual-checklist.md`
|
||||||
|
GUI-only steps on Tahoe, in order, each with the exact Settings path:
|
||||||
|
iCloud Drive Desktop&Documents off; Photos analysis off; Screen Time off;
|
||||||
|
iPhone Mirroring off; Focus mode "DAW" (all notifications silenced, shown in
|
||||||
|
Control Center); Rectangle accessibility grant; kitty full-disk-access grant
|
||||||
|
(for `~/Music/Ableton` under TCC); Tailscale login; Live install + Suite Packs
|
||||||
|
download; audio interface buffer/sample rate in Live once one is attached.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- `setup.sh` run twice in a row: second run is all `[skip]` lines, exit 0.
|
||||||
|
- `ip a`, `ls --color`, `sed --version` (GNU), `echo $BASH_VERSION` -> 5.x,
|
||||||
|
`hostname` -> chosen name — all over `ssh mac`.
|
||||||
|
- `pmset -g custom` shows AC `sleep 0 powernap 0`, battery unchanged.
|
||||||
|
- `defaults read com.apple.dock persistent-apps` shows only the 4 entries.
|
||||||
|
- `backup.sh` dry-run (`-n`) lists files; real run creates
|
||||||
|
`/tank/backups/mac/Ableton` on pve173.
|
||||||
|
- Live: open a project, leave it 15 min on AC, confirm no sleep and no
|
||||||
|
notifications appear (Focus on).
|
||||||
|
|
||||||
|
## Rollback
|
||||||
|
|
||||||
|
Every `defaults` domain has a pre-write plist in `.backup/`; restore with
|
||||||
|
`defaults import <domain> <file>` + `killall Dock Finder`. `pmset -g custom`
|
||||||
|
snapshot restores with the same flags. `chsh -s /bin/zsh` reverts shell.
|
||||||
|
`brew bundle cleanup` / `brew uninstall` for packages. Nothing in this design
|
||||||
|
is irreversible.
|
||||||
|
|
||||||
|
## Order of operations
|
||||||
|
|
||||||
|
1. Seth picks hostname -> `DECISIONS.md`.
|
||||||
|
2. Write `Brewfile`, `setup.sh`, `backup.sh`, `manual-checklist.md`.
|
||||||
|
3. Run `setup.sh` over SSH (CLT prompt needs Seth at the lid once).
|
||||||
|
4. Seth walks `manual-checklist.md`.
|
||||||
|
5. Install Live, attach interface, verify.
|
||||||
|
6. Handoff.
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# Mac inventory — 2026-09-15 (first SSH, pre-any-changes)
|
||||||
|
|
||||||
|
Read when: deciding what to disable/install, or checking "was X already like that out of the box".
|
||||||
|
|
||||||
|
## Hardware / OS
|
||||||
|
- MacBookPro18,1 = 16" 2021, Apple M1 Pro (8P+2E), 32 GB, 512 GB SSD (425 Gi free, 14 Gi used)
|
||||||
|
- macOS 26.2 Tahoe (build 25C56), arm64
|
||||||
|
- Uptime 28 days at first login (used/refurb unit); 15-min load was 12.5 right after Seth's setup — settled to idle within the hour (post-setup indexing/iCloud sync, not a persistent hog)
|
||||||
|
- Hostname: ComputerName "Seth's MacBook Pro", LocalHostName `Seths-MacBook-Pro`
|
||||||
|
- LAN: en0 Wi-Fi 192.168.0.94. No Tailscale. Stray PPP service "SparkFun Pro Micro" (modem entry from a previously-attached USB board)
|
||||||
|
|
||||||
|
## Software state (stock)
|
||||||
|
- Shell zsh. No Homebrew, no Xcode CLT
|
||||||
|
- /Applications: Safari + Utilities only. ~/Applications empty
|
||||||
|
- No third-party LaunchDaemons/LaunchAgents. No user login items
|
||||||
|
- Dock: full stock Tahoe set (Apps, Safari, Messages, Mail, Maps, Photos, FaceTime, Phone, Calendar, Contacts, Reminders, Notes, TV, Music, Games, App Store, iPhone Mirroring, System Settings, Terminal)
|
||||||
|
|
||||||
|
## Services / security
|
||||||
|
- Siri: off (`Assistant Enabled = 0`). Apple Intelligence: opted out at Setup Assistant (`opted_out_buddy = 1`)
|
||||||
|
- iCloud: 1 account signed in
|
||||||
|
- Spotlight: indexing enabled on /
|
||||||
|
- Time Machine: no destinations
|
||||||
|
- SIP enabled, Gatekeeper enabled, **FileVault ON** (=> after a reboot, SSH is unreachable until someone types the password at the lid; plan remote work accordingly)
|
||||||
|
- Remote Login: enabled by Seth 2026-09-15; claude@steel141 ed25519 key installed in ~/.ssh/authorized_keys
|
||||||
|
- Screen Sharing: not running
|
||||||
|
- pmset: sleep 1 / displaysleep 10 / disksleep 10 / powernap 1 / hibernatemode 3 / lowpowermode 0
|
||||||
|
|
||||||
|
## Audio
|
||||||
|
- Built-in mic + speakers only. No interface attached at inventory time
|
||||||
Reference in New Issue
Block a user