CommunityCoding & Developmentgithub.com

soerenmartius/claude-desktop-profiles

Use when someone wants the Claude desktop app signed in to several Claude accounts at once on a Mac, one app instance per account switchable from the Dock, or asks for separate Claude desktop profiles, a multi-account Claude setup, or Dock launchers for the Claude app.

What is claude-desktop-profiles?

claude-desktop-profiles is a Claude Code agent skill that use when someone wants the Claude desktop app signed in to several Claude accounts at once on a Mac, one app instance per account switchable from the Dock, or asks for separate Claude desktop profiles, a multi-account Claude setup, or Dock launchers for the Claude app.

Works with✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/soerenmartius/skills/tree/HEAD/skills/claude-desktop-profiles

Installed? Explore more Coding & Development skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

Claude desktop profiles

One real /Applications/Claude.app, one profile folder per account through --user-data-dir, one guarded Dock launcher per account. The existing app, its sign-in and the default profile are never touched. Undo is deleting the launchers and the extra folders.

Derived from Chad Timblin's guide Run a Separate Claude Desktop App for Each Claude Account. macOS only. Windows is unverified; that guide's appendix has the known notes.

Ground rules

  1. Never modify, move, rename, duplicate or re-sign /Applications/Claude.app. Not as a fallback either. If step 2 fails, stop and report; do not offer a clone.
  2. Never write into the default profile ~/Library/Application Support/Claude.
  3. Never launch a profile that is already running. The app has no single-instance lock on macOS: two launches of one folder give two live processes sharing one folder (verified 2026-11-04 on v4.16336.0, and 2026-07-11 on v1.20186.1). A launcher's focus path must never fall back to relaunching.
  4. Sign-ins are the user's job, with exactly one instance running. Google and SSO logins round-trip through the browser and come back by a claude:// link, which macOS hands to whichever instance is already running. With two open, the signed-in one receives it and logs Google sign-in code does not answer a sign-in this app started; ignoring, and the other stays on the login screen. Never handle passwords.
  5. Mind your runtime. If this session runs inside the Claude desktop app, quitting it kills the session: hand quit steps to the user as text. If ~/Library is unreadable, tell the user to run this from a terminal.
  6. Delete only test artifacts you created this session. The script's smoke test refuses to touch a folder that existed before it ran.

Scope

The whole job is about ten commands plus a README. Facts about the installed version come from the throwaway test in step 2, never from reading app.asar, entitlements, fuses or Electron internals. Custom launcher icons only when the user asks.

Steps

S is scripts/claude-profiles.sh in this skill's directory; bash $S prints usage. AppleScript sources go to CLAUDE_LAUNCHER_SOURCES (default ~/Documents/claude-multi-account/launcher-sources); point it at the README folder from step 5 if the user picks another. If /Applications is not writable, set CLAUDE_LAUNCHER_DIR=$HOME/Applications. verify-mechanism writes and removes /tmp/claude-profile-test-<pid>.

  1. Inputs. The primary account is whichever is signed in now. It keeps the default profile and gets Claude (<Label>).app. Every other account gets the folder Claude-<Label> and its own Claude (<Label>).app. Ask for labels and emails if they were not given. To tell which account is signed in, compare lastKnownAccountUuid in the default profile's config.json with oauthAccount in ~/.claude.json; if they differ, ask the user which email the app shows. No profile folder name may be a prefix of another; build refuses a clash with existing folders and with folders named by other launcher sources. Folders under Application Support that start with Claude but hold no Cookies file (such as Claude-3p) are not profiles; leave them alone.
  2. Preflight and mechanism. bash $S preflight. Warn the user that a window will appear, then bash $S verify-mechanism. FAIL means stop and tell the user.
  3. Build and smoke. Primary: bash $S build <Label> default. Each other account: bash $S build <Label> Claude-<Label>, then bash $S smoke <Label> Claude-<Label>. Never smoke the primary launcher: its focus path triggers the Automation prompt at a moment the user does not expect. If launchers or a README from an earlier run exist, back the README folder up, rebuild in place (build overwrites), and never delete a launcher you did not create this session.
  4. Migration check. claude.ai-side things (conversations, projects, connectors) follow the login. Desktop-side things do not. MCP servers live in <profile>/claude_desktop_config.json: copy entries selectively, since a wholesale copy doubles every local server process. Scheduled tasks live in <profile>/local-agent-mode-sessions/<uuid>/<uuid>/scheduled-tasks.json and <profile>/claude-code-sessions/..., run only while their account is signed in inside a running instance, and migrate with the target instance quit: copy fields exactly, drop notifySessionId, keep lastRunAt, set enabled: false on the old copy and keep it. The preferences block of that same file (Cowork settings, bypass-permissions gate, allowed origins, folder grants, Chrome extension pairing) stays with the default profile; list in the README what the user may want to set again, and note that only one instance should pair with the Chrome extension. ~/.claude is shared by every instance, so the global CLAUDE.md applies to all of them.
  5. README. Fill references/readme-template.md into a folder the user names (default ~/Documents/claude-multi-account).
  6. Hand off with the text below, then stop. Before each sign-in the user reports, run bash $S ps and confirm it prints nothing; if it does not, quit the instances yourself (kill on their pids, SIGTERM is a clean quit for this app) and only then tell the user to click the one launcher. Every running window looks the same, so "quit the signed-in one" is the step users get wrong.
  7. When the user reports back: bash $S ps must show every instance on a distinct profile with a distinct account= UUID.

Hand-off text

With only one instance open at a time:

  1. Drag the launchers from Applications into the Dock and remove the plain Claude tile: once several instances run, that tile lights up for all of them and focuses whichever one macOS picks.
  2. Quit every Claude window: press Cmd+Q in each until none is left. All windows look identical, so do not try to keep one. A sign-in only completes when exactly one instance is running.
  3. Click Claude (<Label2>), sign in with that account, then quit it the same way. Repeat for each further account, always with nothing else running.
  4. Click Claude (<Label1>). The primary account is still signed in.
  5. From now on open any combination. To quit one instance only, click its window first, then Cmd+Q.

The first time a launcher focuses a running instance, macOS asks to let it control System Events. Click Allow; denying only disables auto-focus. Running tiles share one icon and may merge after a Dock restart. Both are harmless.

Gotchas

SymptomWhat to do
Two instances show the same Dock icon, or merge into one tileCosmetic. Launchers find instances by process, not tile.
Quick Entry hotkey fires in only one instanceBoth register it. Change or disable it in one instance's settings.
"Restart to update" in one instanceQuit all instances, then relaunch through the launchers. One app bundle, one update path.
Cowork used in a second profileIt downloads its own VM bundle, about 10 GB per profile.
kill $pids fails with "illegal pid: 1\n2"zsh does not word-split. Pipe through xargs kill. The script already does.
Test folder deleted while its instance still ranKill first, confirm gone, then delete. The script already does.
Google or SSO login opens the browser, ends on "Finish sign-in in the Claude app", and "Open Claude" does nothing; the new instance stays on the login screenAnother instance was running and took the callback. Quit every instance (verify with ps), open only that launcher, sign in again. All instances share ~/Library/Logs/Claude/main.log; grep it for [Auth] and sign-in code to see which one got it. Unchanged pids across attempts mean the user never quit.
Automation prompt appeared during setupSomeone opened a launcher whose instance was already running. Click Allow; nothing is broken.

Red flags

  • "The app has a single-instance lock, so relaunching on focus failure is safe." It does not. Step 2 is the only source of truth about this version.
  • "Sign-in is in-app, so both instances can stay open." One instance during sign-in, always.
  • "Plan B: clone and re-sign the app." Forbidden. Stop and report instead.
  • "Let me inspect app.asar / entitlements / fuses first." Out of scope.
  • "I'll badge the icons while I'm at it." Only on request.
  • "I'll test the primary launcher too." Its focus path prompts the user. Pipeline check only.

Recovery

Reset one non-primary instance: quit it, delete its profile folder, click its launcher, sign in again. Undo everything: delete the launchers and the extra profile folders. The real app and the default profile are never involved. Rebuild a launcher from its source with osacompile -o "/Applications/Claude (<Label>).app" <source>.applescript.

Related Skills