Monorepo for Aesthetic.Computer aesthetic.computer
README.md

Fleet Mac config #

Neo, Blueberry, and Frisbee share an AC working environment. A new family Mac gets its own identity and checkout, with the same shell and tracked dotfiles. Start with Joining the family. The scripts below manage optional fleet features; their historical all lists do not enumerate the family.

Resource graph (Slab menu-bar system monitor) #

Stats is deprecated for the fleet. Slab now owns a framed ticker that rotates through RAM / SSD / GPU / CPU / Network with a live value and sparkline, sampled directly without another app. Enable it from Slab → Resource graph; the checkbox persists per machine.

bash stats-sync.sh all              # exits with a migration reminder

The historical plist and sync implementation remain in the tree only as a migration reference. New provisioning does not install or launch Stats.

Cursor color #

cursor-color.sh sets the macOS pointer fill color per Mac so each machine is identifiable by its cursor: neo = green, blueberry = blue (others fall through to the default black pointer). Colors live in com.apple.universalaccess (cursorFill / cursorOutline) — the same keys the system Pointer settings write.

bash cursor-color.sh all              # neo chicken panda (per-host mapping)
bash cursor-color.sh blueberry        # blueberry -> blue
bash cursor-color.sh chicken purple   # one-off override to a named color

universalaccessd is SIP-protected and can't be hot-reloaded from the CLI, so the new color appears on the next login or lock/unlock (⌃⌘Q), when accessibility prefs get re-read. Blueberry's blue is also baked into blueberry-join.sh (step 5/5) so a fresh rejoin restores it.

Ableton Live #

Two scripts extend the colour-as-identity convention into Live and let neo's tuned Live settings propagate to the other Macs.

ableton-theme.mjs — tint Live to each Mac's macOS accent #

The macOS accent colour is the source of truth: each host's Live is tinted to the hue of whatever AppleAccentColor that Mac is set to. Change it in System Settings > Appearance, re-run, and Live follows. Mirrors the cursor mapping — neo = green, blueberry = blue.

node ableton-theme.mjs                 # every host, matched to its own accent
node ableton-theme.mjs blueberry       # just blueberry
node ableton-theme.mjs --set-accent    # also write each Mac's fleet-identity accent first
node ableton-theme.mjs neo 300         # one-off hue override (degrees)
node ableton-theme.mjs neo --intensity 80

Live 12 dropped loadable custom themes — a .ask in User Library/Themes/ is ignored, even after a restart. What Live 12 offers instead is native Color Hue (0–360) and Color Intensity (0–100) sliders under Settings > Theme & Colors > Customization, and the only way to reach them is Live's UI. So the script drives those sliders over Accessibility (AXIncrement/AXDecrement, since they reject set value). Consequences: Live must be running and the Mac unlocked, and because the slider values live in Preferences.cfg, an ableton-sync.sh run carries the source's hue to the target — so re-run this after any sync (the sync script prints that reminder).

ableton-tiny.mjs — make Live a tiny concern #

node ableton-tiny.mjs                  # every host: 50% zoom, smallest window
node ableton-tiny.mjs blueberry        # just blueberry
node ableton-tiny.mjs neo --zoom 75 --size 900x600
node ableton-tiny.mjs blueberry --reset  # back to 100% zoom, roomy window

Drives Live's native Zoom slider (Settings > Display & Input, 50–200%) and resizes the window. 720x579 @ 50% is genuinely as small as Live goes — measured by asking for a {1,1} window and reading back what it clamped to. Ask for less and Live silently ignores you.

The window rect is not stored in the .als — Live keeps it globally — so a set can't carry its own geometry. Homogenizing the window means re-running this after a set opens, not baking it into a template.

ableton-template.mjs — a genuinely blank Set in the browser #

node ableton-template.mjs              # install as a browser template
node ableton-template.mjs --default    # ALSO make it the Set ⌘N opens

Builds the stripped Set (reference/ableton/als-template.mjs — one audio track + Main, no MIDI, no returns) and installs it to each Mac's User Library/Templates/, so Live's browser lists it under Templates > AC Blank.

--default additionally writes it to ~/Library/Preferences/Ableton/Live <ver>/BaseFiles/**DefaultLiveSet.als** — the Set ⌘N opens. The filename is the whole trick: a copy named anything else is ignored wherever you put it. Any existing default is backed up first (neo has a hand-made one).

Unverified: the DefaultLiveSet.als path was found by spotting the file on neo; it hasn't been confirmed to change ⌘N across a Live restart. Also beware: click menu item "Save Live Set As Default Set..." silently fires "Save Live Set As Template…" (the item above it) — press File menu item 17 by index instead. See reference/ableton/TEMPLATE.md.

Live's global modals #

Live throws app-modal alerts (most often "Audio is disabled. Please choose an audio output device" on a Mac with no audio device selected) that block every other Accessibility call — automation that ignores them just hangs. They are also not addressable as normal dialogs: click button "OK" of window 1 fails with -1728. The OK button actually lives at button 1 of group 1 of window 1, and both scripts above dismiss it before doing anything else.

When AX can't see a dialog at all, fall back to vision: frame <machine> (see slab/bin/frame) returns the AX tree and OCR with click coordinates, so you can locate the button visually and click its coordinate. That observe→act loop is the general escape hatch for any Ableton automation that stalls.

ableton-sync.sh — copy neo's Live settings to the fleet #

bash ableton-sync.sh all               # neo -> blueberry chicken panda
bash ableton-sync.sh blueberry         # neo -> blueberry
SOURCE=chicken bash ableton-sync.sh neo

Copies Preferences.cfg, Library.cfg, User Remote Scripts, and the User Library from the source (default neo) to each target — theme, UI zoom, audio device, warp/record/launch defaults, plug-in paths. Safe because the Macs are the same model (Mac17,5), so even the Core Audio device selection lands correctly. The target's settings folder is backed up to Live <version>.bak-<timestamp> first. It refuses to run while Live is open on the target, because Live rewrites Preferences.cfg on quit and would clobber the sync. After a sync, run node ableton-theme.mjs <host> to restore that Mac's own accent-matched tint.

SSH mesh #

fleet-keys.pub holds every fleet Mac's public identity key (jas@aesthetic laptop, jas-neo, chicken-to-neo, panda-to-neo, blueberry-to-neo). ssh-mesh.sh merges them into a host's authorized_keys (dedup by key blob, never removes) so any fleet Mac can reach any other.

bash ssh-mesh.sh all

Tailscale SSH's server is Linux-only, so it can't mesh these Macs — classic authorized_keys distribution is the durable path. The fleet is reachable over the tailnet by name/IP (e.g. blueberry = 100.79.75.53); the tailnet gives the network path, authorized_keys gives the auth.

Historical Blueberry SSH bootstrap #

During Blueberry's original setup it did not yet trust the fleet key. blueberry-join.sh is a self-contained one-shot that adds the fleet keys to its authorized_keys and configures its cursor identity. It's staged on neo, so run this on blueberry (blueberry already holds a key to neo):

ssh neo 'cat ~/blueberry-join.sh' > /tmp/bj.sh && bash /tmp/bj.sh

After that, blueberry joins the mesh and ssh-mesh.sh works on it like any other host. Enable the Slab resource graph locally from its persisted checkbox.