Context
Provisioned MIMOLETTE as a new mobile-build server on 2026-04-17 using this repo's automation. asiago.local is the reference working build box. MIMOLETTE came up mostly-correctly but several things needed manual fixing to reach parity with asiago. Filing this as a tracking epic for those gaps.
The underlying remit (per the user) is "replicate the working ASIAGO development environment" — so "parity with asiago" is the acceptance criterion for each item below.
Summary of gaps
Each item below either (a) ran but configured something differently from asiago, or (b) didn't run at all.
1. app-setup/node-setup.sh: npm prefix diverges from asiago
NPM_GLOBAL_DIR="${HOME}/.npm-global" (line 108) sets npm prefix to a user-level directory.
- asiago has
npm config get prefix → /opt/homebrew, so npm i -g landed into Homebrew's tree and brew shellenv auto-covered the PATH. On MIMOLETTE the prefix was ~/.npm-global which is not in any PATH set by the dotfiles, so eas, ncu, corepack, etc. were all invisible to interactive shells.
- Someone had compensated on MIMOLETTE by injecting
export PATH="/Users/andrewrich/.npm-global/bin:${PATH}" into ~/.profile, masking the drift. (See item 7.)
- Fix direction: default
NPM_GLOBAL_DIR to /opt/homebrew (matches asiago and the default brew shellenv PATH) — or, if a user-level prefix is intentional, ensure dotfiles bash/path.sh adds ${HOME}/.npm-global/bin when that prefix is in use. The former is simpler and is what asiago actually runs.
- Repro on MIMOLETTE: open a fresh terminal, run
command -v eas → exit 127. User had to run ~/.npm-global/bin/eas login with absolute path to proceed.
2. app-setup/node-setup.sh: globals list is narrower than asiago's
- Currently installs only
eas-cli and npm-check-updates (lines 103-104).
- asiago additionally has:
n, netlify-cli, puppeteer, url-decode-encode-cli.
n in particular is non-optional: mobile/lib/build-preflight.sh in kebab-tax explicitly checks command -v n and uses it to switch Node versions during preflight. Without n on the box, that branch silently fails to upgrade even when upgrade is needed.
- Fix direction: add
n, netlify-cli, puppeteer, url-decode-encode-cli to the globals array. (andrewrich and dependencies also appear in asiago's node_modules/ — those are detritus from old broken installs and should NOT be replicated.)
3. app-setup/android-setup.sh: system-image not installed → emulator unusable
- Script installs
platforms;android-${SDK_VERSION} and build-tools;${SDK_VERSION}.0.0 (lines 221-222) but not any system-images;android-N;google_apis_playstore;<abi>.
- Without a system-image,
emulator -list-avds returns empty and no AVD can be booted. On MIMOLETTE I had to manually sdkmanager "system-images;android-36;google_apis_playstore;arm64-v8a" before avdmanager create avd would succeed.
- Fix direction: add system-image install to the SDK packages array. Recommended default:
system-images;android-${SDK_VERSION};google_apis_playstore;arm64-v8a (Apple Silicon boxes only run arm64 images performantly).
4. app-setup/android-setup.sh: no AVD creation
- Setup never creates an AVD. asiago has
Medium_Phone_API_35 and Medium_Phone_API_36.1 from Android-Studio-driven manual creation.
- On MIMOLETTE I had to
avdmanager create avd -n Medium_Phone_API_36 -k 'system-images;android-36;google_apis_playstore;arm64-v8a' --device medium_phone by hand.
- Fix direction: add a
create_default_avd step at the tail of android-setup.sh, idempotent (skip if emulator -list-avds | grep -q "${AVD_NAME}"). Reasonable default: Medium_Phone_API_${SDK_VERSION} using medium_phone device profile.
5. app-setup/android-setup.sh: SDK_VERSION default is 34, current is 36
SDK_VERSION="${ANDROID_SDK_VERSION:-34}" (line 59). API 34 is two releases behind.
- kebab-tax currently builds against API 36 (current Google Play requirement as of early 2026).
- Fix direction: bump default to 36 (or latest-stable at the time of setup). Keep the env-var override so older projects can pin.
6. app-setup/android-setup.sh: no cmdline-tools-path → ~/Library/Android/sdk symlink
_determine_android_home() (lines 118-119) checks for ${HOME}/Library/Android/sdk first, then falls back to Homebrew cmdline-tools.
- Dotfiles'
bash/path.sh:113-117 is hardcoded to only detect ${HOME}/Library/Android/sdk. So if the box has cmdline-tools installed via Homebrew only (no Android Studio), dotfiles silently no-op on Android — adb, emulator, avdmanager missing from interactive-shell PATH.
- On MIMOLETTE I worked around this by
ln -s /opt/homebrew/share/android-commandlinetools ~/Library/Android/sdk.
- Fix direction (pick one):
- a. Have
android-setup.sh create the symlink when Homebrew is the install origin, so the dotfiles find it at the expected path.
- b. Patch dotfiles
bash/path.sh to probe both locations. (I've filed that under smartwatermelon/dotfiles#69.)
- Either fixes this gap; (a) is more local to this repo.
7. .profile gets corrupted with compensating PATH entries
- MIMOLETTE's
~/.profile had been hand-edited by something (not our dotfiles, which symlink .profile → a one-liner that sources .bash_profile) to include export PATH="…/.npm-global/bin:…", export ANDROID_HOME=/opt/homebrew/share/android-commandlinetools, and eval "$(/opt/homebrew/bin/brew shellenv)".
- These compensate for items 1 and 6 above but silently drift out of sync with dotfiles, creating maintenance confusion.
- Root cause: when
NPM_GLOBAL_DIR=~/.npm-global or cmdline-tools isn't symlinked into ~/Library/Android/sdk, something is motivated to patch .profile to make the box usable. Fixing items 1 and 6 removes the motivation.
- Fix direction: resolve items 1 and 6; add an audit step at the end of setup that refuses to modify
.profile and warns if it's not the canonical one-liner.
8. Project secrets / credentials: no handoff mechanism
Several gitignored files need to be on the build box for builds to succeed — setup has no automation for any of them:
kebab-tax/mobile/google-service-account.json — required by EAS --submit for Android. Missing on MIMOLETTE; user manually rsync'd from asiago.
kebab-tax/.claude/secrets.op — maps REVENUECAT_TEST_STORE_KEY via op://Automation/RevenueCat/Test Store Key for the claude-with-identity wrapper. Must exist on the target box for emulator launches to get the test key.
kebab-tax/mobile/.env.local — optional offline fallback.
These are PROJECT-scoped, so a general setup repo may not want them hardcoded. Fix direction: document a post-setup checklist (or a helper script) that lists "files you must manually copy or rsync from the reference box for each project you intend to build", and point prep-airdrop/first-boot flows at it. Or extend prep-airdrop.sh's credential-staging mechanism to accept a manifest of per-project secret files to migrate.
9. eas login not automated
- EAS login is inherently interactive (terminal prompt or browser OAuth), so full automation is not feasible, but setup exits silently without a final "you need to run
eas login" hint. User discovered it by running eas whoami after the fact.
- Fix direction: at end of
node-setup.sh (after eas-cli install), check eas whoami — if it returns "Not logged in", print a numbered post-setup checklist item.
10. ~/.semgrep/settings.yml lacks api_token: line → pre-push hook crashes
- After
semgrep --version first-runs, the generated settings.yml has only has_shown_metrics_notification and anonymous_user_id — no api_token line.
- Dotfiles'
git/hooks/pre-push has a set -euo pipefail bug that aborts the hook when grep finds no api_token line (distinct from it finding a malformed one). Already tracked at smartwatermelon/dotfiles#62 (as a pre-existing tech-debt) with an evidence comment from my MIMOLETTE hit.
- Not strictly a mac-dev-server-setup bug — logging here only because setup could proactively inject a bare
api_token: line into settings.yml as part of app-setup to prevent the downstream hook crash until dotfiles#62 lands.
- Fix direction: optional. Wait for dotfiles#62 fix. Or, if that's slow, add a one-shot
ensure-semgrep-settings.sh that writes api_token: to ~/.semgrep/settings.yml if no api_token line is present.
Proposed acceptance for this epic
Close this issue when a fresh Mac mini, provisioned only via this repo's prep-airdrop.sh + post-boot automation, can:
Related
Context
Provisioned MIMOLETTE as a new mobile-build server on 2026-04-17 using this repo's automation. asiago.local is the reference working build box. MIMOLETTE came up mostly-correctly but several things needed manual fixing to reach parity with asiago. Filing this as a tracking epic for those gaps.
The underlying remit (per the user) is "replicate the working ASIAGO development environment" — so "parity with asiago" is the acceptance criterion for each item below.
Summary of gaps
Each item below either (a) ran but configured something differently from asiago, or (b) didn't run at all.
1.
app-setup/node-setup.sh: npm prefix diverges from asiagoNPM_GLOBAL_DIR="${HOME}/.npm-global"(line 108) sets npm prefix to a user-level directory.npm config get prefix→/opt/homebrew, sonpm i -glanded into Homebrew's tree andbrew shellenvauto-covered the PATH. On MIMOLETTE the prefix was~/.npm-globalwhich is not in any PATH set by the dotfiles, soeas,ncu,corepack, etc. were all invisible to interactive shells.export PATH="/Users/andrewrich/.npm-global/bin:${PATH}"into~/.profile, masking the drift. (See item 7.)NPM_GLOBAL_DIRto/opt/homebrew(matches asiago and the defaultbrew shellenvPATH) — or, if a user-level prefix is intentional, ensure dotfilesbash/path.shadds${HOME}/.npm-global/binwhen that prefix is in use. The former is simpler and is what asiago actually runs.command -v eas→ exit 127. User had to run~/.npm-global/bin/eas loginwith absolute path to proceed.2.
app-setup/node-setup.sh: globals list is narrower than asiago'seas-cliandnpm-check-updates(lines 103-104).n,netlify-cli,puppeteer,url-decode-encode-cli.nin particular is non-optional:mobile/lib/build-preflight.shin kebab-tax explicitly checkscommand -v nand uses it to switch Node versions during preflight. Withoutnon the box, that branch silently fails to upgrade even when upgrade is needed.n,netlify-cli,puppeteer,url-decode-encode-clito the globals array. (andrewrichanddependenciesalso appear in asiago'snode_modules/— those are detritus from old broken installs and should NOT be replicated.)3.
app-setup/android-setup.sh: system-image not installed → emulator unusableplatforms;android-${SDK_VERSION}andbuild-tools;${SDK_VERSION}.0.0(lines 221-222) but not anysystem-images;android-N;google_apis_playstore;<abi>.emulator -list-avdsreturns empty and no AVD can be booted. On MIMOLETTE I had to manuallysdkmanager "system-images;android-36;google_apis_playstore;arm64-v8a"beforeavdmanager create avdwould succeed.system-images;android-${SDK_VERSION};google_apis_playstore;arm64-v8a(Apple Silicon boxes only run arm64 images performantly).4.
app-setup/android-setup.sh: no AVD creationMedium_Phone_API_35andMedium_Phone_API_36.1from Android-Studio-driven manual creation.avdmanager create avd -n Medium_Phone_API_36 -k 'system-images;android-36;google_apis_playstore;arm64-v8a' --device medium_phoneby hand.create_default_avdstep at the tail ofandroid-setup.sh, idempotent (skip ifemulator -list-avds | grep -q "${AVD_NAME}"). Reasonable default:Medium_Phone_API_${SDK_VERSION}usingmedium_phonedevice profile.5.
app-setup/android-setup.sh:SDK_VERSIONdefault is 34, current is 36SDK_VERSION="${ANDROID_SDK_VERSION:-34}"(line 59). API 34 is two releases behind.6.
app-setup/android-setup.sh: no cmdline-tools-path →~/Library/Android/sdksymlink_determine_android_home()(lines 118-119) checks for${HOME}/Library/Android/sdkfirst, then falls back to Homebrew cmdline-tools.bash/path.sh:113-117is hardcoded to only detect${HOME}/Library/Android/sdk. So if the box has cmdline-tools installed via Homebrew only (no Android Studio), dotfiles silently no-op on Android —adb,emulator,avdmanagermissing from interactive-shell PATH.ln -s /opt/homebrew/share/android-commandlinetools ~/Library/Android/sdk.android-setup.shcreate the symlink when Homebrew is the install origin, so the dotfiles find it at the expected path.bash/path.shto probe both locations. (I've filed that under smartwatermelon/dotfiles#69.)7.
.profilegets corrupted with compensating PATH entries~/.profilehad been hand-edited by something (not our dotfiles, which symlink.profile→ a one-liner that sources.bash_profile) to includeexport PATH="…/.npm-global/bin:…",export ANDROID_HOME=/opt/homebrew/share/android-commandlinetools, andeval "$(/opt/homebrew/bin/brew shellenv)".NPM_GLOBAL_DIR=~/.npm-globalor cmdline-tools isn't symlinked into~/Library/Android/sdk, something is motivated to patch.profileto make the box usable. Fixing items 1 and 6 removes the motivation..profileand warns if it's not the canonical one-liner.8. Project secrets / credentials: no handoff mechanism
Several gitignored files need to be on the build box for builds to succeed — setup has no automation for any of them:
kebab-tax/mobile/google-service-account.json— required by EAS--submitfor Android. Missing on MIMOLETTE; user manually rsync'd from asiago.kebab-tax/.claude/secrets.op— mapsREVENUECAT_TEST_STORE_KEYviaop://Automation/RevenueCat/Test Store Keyfor the claude-with-identity wrapper. Must exist on the target box for emulator launches to get the test key.kebab-tax/mobile/.env.local— optional offline fallback.These are PROJECT-scoped, so a general setup repo may not want them hardcoded. Fix direction: document a post-setup checklist (or a helper script) that lists "files you must manually copy or rsync from the reference box for each project you intend to build", and point prep-airdrop/first-boot flows at it. Or extend
prep-airdrop.sh's credential-staging mechanism to accept a manifest of per-project secret files to migrate.9.
eas loginnot automatedeas login" hint. User discovered it by runningeas whoamiafter the fact.node-setup.sh(after eas-cli install), checkeas whoami— if it returns "Not logged in", print a numbered post-setup checklist item.10.
~/.semgrep/settings.ymllacksapi_token:line → pre-push hook crashessemgrep --versionfirst-runs, the generated settings.yml has onlyhas_shown_metrics_notificationandanonymous_user_id— noapi_tokenline.git/hooks/pre-pushhas aset -euo pipefailbug that aborts the hook when grep finds noapi_tokenline (distinct from it finding a malformed one). Already tracked at smartwatermelon/dotfiles#62 (as a pre-existing tech-debt) with an evidence comment from my MIMOLETTE hit.api_token:line intosettings.ymlas part ofapp-setupto prevent the downstream hook crash until dotfiles#62 lands.ensure-semgrep-settings.shthat writesapi_token:to~/.semgrep/settings.ymlif noapi_tokenline is present.Proposed acceptance for this epic
Close this issue when a fresh Mac mini, provisioned only via this repo's
prep-airdrop.sh+ post-boot automation, can:eas whoamireturns a name (item 9 — post-setup check prompts for login)command -v easresolves without~/.npm-global/binbeing in any PATH (items 1 + 2)command -v n netlify-cli puppeteerall resolve (item 2)emulator -list-avdsreturns at least one AVD (items 3 + 4)adb,avdmanagerresolvable in a fresh interactive shell without.profileedits (items 1 + 6 + 7)Related
set -etoken-parser abort)bash/path.shAndroid SDK path hardcoded)