ADR-0020: Dev app branding — patch the icon, don’t chase the name
Status: Active · Date: 2026-07-29
References
- App Icon & Dev App-Name — Session Notes — what shipped, everything tried for the name, and the distributable checklist
- macOS App Name in Dev — Build Notes — the earlier note, now corrected: the plist patch does not fix the visible name
- ADR-0014: Agent-shell dev launch & CDP verification — the
scripts/dev.jslauncher these bundle patches hook into
Context
yarn start launches Electron’s own unbranded app bundle
(node_modules/electron/dist/Electron.app), not a packaged Tranquil app. On macOS that means the
dock/app-switcher icon is Electron’s default atom logo and the menu-bar/dock name is “Electron”.
Only packaged builds are branded, because electron-builder rewrites the bundle at package
time.
Two separate surfaces, with very different tractability, were investigated this session:
- The icon is read by macOS’s icon services from the bundle’s
CFBundleIconFile, refreshed when the bundle’s mtime changes. Patching it in place works. - The name (the bold application menu and the dock/⌘-Tab label) is resolved by the OS from the
app’s bundle identity, and it proved immovable in dev. With every on-disk attribute set to
“Tranquil” —
CFBundleName,CFBundleDisplayName,app.getName(), the LaunchServicesLSDisplayName, a uniqueCFBundleIdentifier, a valid ad-hoc re-sign,lsregister -f,killall Dock, a renamed executable, andargv0— the visible name stayed “Electron”. The decisive finding: the machine had 6 registeredElectron.appbundles, 5 named “Electron”, all sharing the identifiercom.github.Electron(everynpm i electronships the same stock bundle id). macOS keys app identity by bundle id, so the colliding “Electron” registrations win — and even a unique id did not visibly dislodge a further OS-level name cache that could not be cleared remotely. Note thatlsappinfoand System Events reported “Tranquil” while the menu bar still showed “Electron”, so those readouts are unreliable proxies for the visible name.
Packaged builds don’t have this problem because electron-builder does the whole rebrand as one
coordinated operation — rename the main executable and the helper apps, set the Info.plist (CFBundleName/DisplayName/CFBundleExecutable), assign a unique CFBundleIdentifier, embed the
icon, and re-sign. Piecemeal patching of the shared stock bundle in node_modules cannot
reproduce that.
Decision
Brand the dev icon by patching the Electron bundle; do not chase the dev name; make the packaged build the source of truth for app identity.
scripts/dev.jspatches the icon on every launch (patchMacAppIcon): copyresources/app-icons/tranquil.icnsinto the bundle’sContents/Resources, setCFBundleIconFile, and bump the bundle mtime so icon services refresh. Best-effort, idempotent, macOS-only. It keeps the pre-existingCFBundleName→“Tranquil” plist patch (harmless; corrects Finder/LaunchServices metadata) but we accept that this does not change the visible menu-bar name.- The dev menu-bar/dock name stays “Electron” and that is acceptable: it is cosmetic and
dev-only. No executable/helper renaming, bundle-id rewriting, or re-signing of the
node_modulesElectron is done in dev — those were tried and did not work, and a divergent bundle id risks TCC/permission surprises versus a freshyarn install.
Options considered
- Patch the icon in dev (chosen) vs. leave the atom icon: a one-file bundle patch that visibly works; kept.
- Patch the name in dev via the bundle (
CFBundleName, unique id, re-sign, re-register) (rejected — proven not to work): every attribute reads “Tranquil” yet the OS still shows “Electron” due to the shared-com.github.Electroncollision plus an uncleared name cache. - Rename the executable /
argv0in dev (rejected): did not change the visible name; renaming helper apps + re-signing to fully mimic electron-builder againstnode_modulesis brittle (breaks on every Electron upgrade, risks breaking helper resolution). - Run a packaged build for a correct dev name (available, not default):
yarn distthen launch the produced.appshows the right name+icon. Reserved for when the name genuinely matters;yarn startstays the everyday flow.
Consequences
- Dev shows the Tranquil icon and the name “Electron”. Reviewers/onboarding should expect the “Electron” label in dev and not re-open the investigation — this ADR and the session notes are the record.
- Distributable builds must carry the branding, and they currently don’t fully.
script/electron-builder.jsstill points at the leftover Pulsar “beta” artwork (resources/app-icons/beta.*,resources/icons/*), usesappId: 'dev.pulsar-edit.pulsar', and overridesproductNameto “Pulsar”;crashReporterinsrc/main-process/start.jsalso names “Pulsar”. Before we ship binaries we must: swap the icon set to the Tranquil node-graph icon (.icns/.ico+ theresources/iconsPNG set), set a TranquilappId(e.g.dev.tranquil.app), and confirmproductName/crash-reporter name resolve to “Tranquil”. The session notes carry the full checklist. - Re-evaluate if we adopt a packaged-dev workflow (e.g. a one-off
@electron/packagerbranded bundle used byyarn start), which would fix the dev name properly and could retire the in-place icon patch.