Skip to content

feat(multi-account): Accounts tab in Settings (Batch 2b part 1)#124

Merged
grimmerk merged 4 commits into
mainfrom
feat/accounts-settings-ui
Jul 9, 2026
Merged

feat(multi-account): Accounts tab in Settings (Batch 2b part 1)#124
grimmerk merged 4 commits into
mainfrom
feat/accounts-settings-ui

Conversation

@grimmerk

@grimmerk grimmerk commented Jul 8, 2026

Copy link
Copy Markdown
Owner

Summary

Batch 2b (part 1) of multi-account support (follows #123): an Accounts tab in Settings — manage Claude Code accounts from the UI instead of the terminal.

  • List configured accounts: label, identity (email / "not logged in" hint), default marker
  • Add an account (creates the registry entry + regenerates accounts.sh; shows the claude <label> log-in hint)
  • Remove an account (unregisters; keeps its folder on disk; anchor ~/.claude account is protected)
  • Set default — what bare claude resolves to (2e, now clickable)
  • Shell integration install/uninstall (the marker-guarded ~/.zshrc source block)

Architecture

The tab is a set of thin IPC handlers (accounts-get/add/remove/set-default/shell-hook in main.ts) over the same shared manager (src/cli/account-manager.ts) that the codev account CLI uses — one generator for accounts.json + accounts.sh, no drift between CLI and UI. Mutations invalidate the accounts cache so the Sessions tab picks up changes.

  • src/popup.tsx — new accounts tab (state + handlers + UI, matching the existing tab style)
  • src/preload.ts / src/electron-api.d.ts — API wiring + CodevAccountInfo type
  • src/main.ts — IPC handlers

Scope notes

  • Rename is deferred: labels name their dirs (~/.claude-<label>), so rename implies a dir migration; remove+add covers the rare need.
  • codev binary on PATH is the remaining 2b item (next PR) — until then the CLI runs via yarn account <cmd>.

Supported shells & terminals

  • Shell integration (Install button / codev account install): writes ~/.zshrczsh only for now (the macOS default). The generated accounts.sh is bash-compatible (bash users can source it from .bashrc manually); fish is unsupported (different function syntax). Shell detection is future work (design doc §6.C).
  • Account-aware resume/launch: every terminal CodeV supports — iTerm2, Terminal.app, Ghostty, cmux, and the embedded Term tab. VS Code sessions can't be account-switched (Multi-account: VS Code (claude-vscode) sessions can't be pinned to a Claude account #121).

Checking which account a session runs under (gotcha)

Inside any Claude Code session, !claude auth status reports the global default, not the session's account — Claude Code snapshots your interactive shell's functions, so in-session claude is the accounts.sh dispatcher. Valid probes:

  • !command claude auth status ✅ — command bypasses shell functions, so the real binary inherits the session process's own CLAUDE_CONFIG_DIR → the session's actual account
  • !echo ${CLAUDE_CONFIG_DIR:-unset} ✅ — the session's own config dir (unset = anchor account)

Full write-up: #123's "Gotcha" section + design doc §6.A.

How to test

Needs yarn make (main-process + renderer changes):

  1. Settings → Accounts tab: your accounts appear with email + default marker; shell integration shows Uninstall (already installed).
  2. Add a test account → appears as "not logged in — run: claude test"; registry + accounts.sh regenerate.
  3. Set default on test → notice appears; yarn account list shows * moved (restore after).
  4. Remove test → gone from list; ~/.claude-test folder stays.
  5. Sessions tab still shows personal+work sessions with badges (cache invalidation works).

Automated: yarn test 13/13; tsc --noEmit 0 errors.

🤖 Generated with Claude Code


Summary by cubic

Adds a new Accounts tab in Settings so you can manage Claude Code accounts from the UI instead of the terminal. This lets you add/remove accounts, set the default for bare claude, and toggle shell integration.

  • New Features

    • List accounts with identity (email or “not logged in”), a “default” marker, and the exact launch command (claude or claude <name>).
    • Add an account (shows login hint: claude <name>), remove an account (keeps its folder), and set the global default.
    • Install/uninstall shell integration for ~/.zshrc.
    • IPC handlers (accounts-get/add/remove/set-default/shell-hook) wrap the shared account-manager used by the codev account CLI; mutations invalidate the Sessions cache.
    • Notes: the anchor ~/.claude account is protected; rename is deferred; remaining 2b item is a real codev binary on PATH.
  • Bug Fixes

    • Seed the anchor ~/.claude account on first extra add so the existing machine default stays registered and remains the global default.
    • accounts-add returns the enriched shape and derives isCurrentDefault in the fallback path to match CodevAccountInfo; shell-hook action is validated (malformed payloads fail).
    • UI hardening: async refresh with error handling, stale notices cleared on tab open, clear guidance when shell integration isn’t installed, and a busy guard to serialize account operations.

Written for commit b3e94f6. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features
    • Added an Accounts tab in Settings for multi-account management.
    • Users can view accounts, add/remove accounts, and set the default (with current-default indicators).
    • Added UI to install/uninstall shell integration from the Accounts tab.
    • Settings can now open directly to the Accounts tab.
  • Chores
    • Updated the app version to v1.0.78 and refreshed the release entry.

New Settings → Accounts tab: list accounts (identity + default marker),
add (with log-in hint), remove, set the global default, and
install/uninstall the ~/.zshrc shell integration.

- main.ts: accounts-get/add/remove/set-default/shell-hook IPC handlers —
  thin wrappers over the shared manager (src/cli/account-manager.ts),
  the exact module the `codev account` CLI uses (one generator, no
  drift); mutations invalidate the accounts cache so the Sessions tab
  picks changes up
- popup.tsx: the Accounts tab UI; preload.ts + electron-api.d.ts wiring
- Rename deferred (labels name dirs; remove+add covers it). Remaining
  2b item: a real `codev` binary on PATH.
- Bump 1.0.78 + CHANGELOG + design-doc §7

tsc 0 errors; 13/13 tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds multi-account management to the Settings UI: an Accounts tab for listing, adding, removing, and setting defaults, plus shell-integration install/uninstall. It also adds the supporting Electron IPC surface, account-manager seeding logic, and release notes/docs/version updates.

Changes

Multi-account management feature

Layer / File(s) Summary
IPC type contracts
src/electron-api.d.ts
Adds CodevAccountInfo and extends IElectronAPI with account-management method signatures.
Main-process IPC handlers
src/main.ts
Adds IPC handlers for account retrieval, mutation, and shell-hook toggling with standardized success/error responses and cache invalidation.
Preload bridge methods
src/preload.ts
Exposes the new account-management IPC methods on electronAPI.
Anchor account seeding
src/cli/account-manager.ts
Seeds an anchor account in an empty registry before adding the first non-default account and sets it as default.
Accounts tab UI
src/popup.tsx
Adds Accounts tab state, wiring, loading/mutation handlers, and the rendered panel with add/remove/default/shell-hook controls.
Changelog, docs, and version bump
CHANGELOG.md, docs/multi-account-support-design.md, package.json
Documents the v1.0.78 release, updates the multi-account design notes, and bumps the package version.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Popup
  participant Preload
  participant MainProcess
  participant AccountManager

  Popup->>Preload: getAccounts()
  Preload->>MainProcess: invoke('accounts-get')
  MainProcess->>AccountManager: list accounts
  AccountManager-->>MainProcess: accounts data
  MainProcess-->>Preload: { ok, accounts, shellInstalled }
  Preload-->>Popup: response

  Popup->>Preload: setDefaultAccount(label)
  Preload->>MainProcess: invoke('accounts-set-default', label)
  MainProcess->>AccountManager: setDefaultAccount(label)
  MainProcess->>MainProcess: invalidateAccountsCache()
  MainProcess-->>Preload: { ok: true }
  Preload-->>Popup: response
  Popup->>Popup: refreshAccounts()

  Popup->>Preload: setAccountsShellHook('install')
  Preload->>MainProcess: invoke('accounts-shell-hook', 'install')
  MainProcess-->>Preload: { ok, changed, path }
  Preload-->>Popup: response
Loading

Possibly related PRs

  • grimmerk/codev#112: Modifies the same Settings UI tab framework and settingsTab selection logic in src/popup.tsx.
  • grimmerk/codev#117: Extends the same openToTab navigation prop that this PR adds the 'accounts' value to.
  • grimmerk/codev#122: Introduces the accounts cache mechanism (invalidateAccountsCache) that this PR's account mutation handlers invoke.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: adding an Accounts tab for multi-account support in Settings.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/accounts-settings-ui

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/preload.ts (1)

11-12: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prettier formatting: setDefaultAccount should be on a single line.

Static analysis flags line 11. The arrow function for setDefaultAccount can fit on one line.

💅 Proposed formatting fix
-  setDefaultAccount: (label: string) =>
-    ipcRenderer.invoke('accounts-set-default', label),
+  setDefaultAccount: (label: string) => ipcRenderer.invoke('accounts-set-default', label),
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/preload.ts` around lines 11 - 12, The Prettier formatting issue is in the
preload API object where setDefaultAccount is split across multiple lines even
though it fits on one line. Update the setDefaultAccount arrow function in
preload.ts to match the compact style used by removeAccount and keep the full
ipcRenderer.invoke call on a single line.

Source: Linters/SAST tools

src/electron-api.d.ts (1)

31-32: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prettier formatting: multi-line formatting needed for removeAccount and setDefaultAccount signatures.

Static analysis flags line 32 for prettier/prettier. Both removeAccount and setDefaultAccount should be formatted with line breaks per the project's prettier config.

💅 Proposed formatting fix
-  removeAccount: (label: string) => Promise<{ ok: boolean; error?: string }>;
-  setDefaultAccount: (label: string) => Promise<{ ok: boolean; error?: string }>;
+  removeAccount: (
+    label: string,
+  ) => Promise<{ ok: boolean; error?: string }>;
+  setDefaultAccount: (
+    label: string,
+  ) => Promise<{ ok: boolean; error?: string }>;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/electron-api.d.ts` around lines 31 - 32, The `removeAccount` and
`setDefaultAccount` type signatures in `electron-api.d.ts` need to be
reformatted to match the project’s Prettier multiline style. Update the
surrounding interface/type declaration where these methods are defined so each
signature is wrapped across lines consistently with other function types in this
file, keeping the same return types and parameter names while applying the
expected line breaks.

Source: Linters/SAST tools

src/popup.tsx (1)

730-809: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Prettier formatting: Accounts tab panel has numerous formatting violations.

Static analysis flags 50+ prettier/prettier errors across lines 730-809 (indentation, line wrapping for JSX attributes, multi-line style objects). Run prettier on this file to auto-fix.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/popup.tsx` around lines 730 - 809, The Accounts tab JSX in popup.tsx has
widespread Prettier formatting violations. Reformat the entire accounts panel
block around the settingsTab === 'accounts' render so indentation, wrapping, and
multi-line style objects match the project’s Prettier output; use the existing
JSX structure and symbols like accountsShellInstalled, handleAddAccount,
handleSetDefaultAccount, and handleRemoveAccount, and apply the formatter rather
than manual line-by-line edits.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/electron-api.d.ts`:
- Around line 26-30: The addAccount IPC contract is returning a RegistryAccount
shape that does not satisfy CodevAccountInfo because it omits isCurrentDefault.
Update the main handler in the addAccount flow to return the enriched account
object with isCurrentDefault populated, using the existing account
lookup/listing path after accountManager.addAccount(), and keep the
electron-api.d.ts return type aligned with CodevAccountInfo so future consumers
receive the full shape.

In `@src/popup.tsx`:
- Around line 112-121: The refreshAccounts function in popup.tsx uses a .then()
chain without handling rejection, which can cause unhandled promise rejections
on IPC failure. Convert refreshAccounts to async/await, await
window.electronAPI.getAccounts(), and wrap the call in try/catch so both
response errors and thrown/rejected IPC errors are handled. Keep the existing
state updates for setAccounts, setAccountsShellInstalled, and setAccountsError,
but move the fallback error handling into the catch block and preserve the
current AccountRow typing.

---

Nitpick comments:
In `@src/electron-api.d.ts`:
- Around line 31-32: The `removeAccount` and `setDefaultAccount` type signatures
in `electron-api.d.ts` need to be reformatted to match the project’s Prettier
multiline style. Update the surrounding interface/type declaration where these
methods are defined so each signature is wrapped across lines consistently with
other function types in this file, keeping the same return types and parameter
names while applying the expected line breaks.

In `@src/popup.tsx`:
- Around line 730-809: The Accounts tab JSX in popup.tsx has widespread Prettier
formatting violations. Reformat the entire accounts panel block around the
settingsTab === 'accounts' render so indentation, wrapping, and multi-line style
objects match the project’s Prettier output; use the existing JSX structure and
symbols like accountsShellInstalled, handleAddAccount, handleSetDefaultAccount,
and handleRemoveAccount, and apply the formatter rather than manual line-by-line
edits.

In `@src/preload.ts`:
- Around line 11-12: The Prettier formatting issue is in the preload API object
where setDefaultAccount is split across multiple lines even though it fits on
one line. Update the setDefaultAccount arrow function in preload.ts to match the
compact style used by removeAccount and keep the full ipcRenderer.invoke call on
a single line.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e8acb0f5-f79b-44ad-8d16-9f005f7f2221

📥 Commits

Reviewing files that changed from the base of the PR and between ad781ef and bd603fb.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • docs/multi-account-support-design.md
  • package.json
  • src/electron-api.d.ts
  • src/main.ts
  • src/popup.tsx
  • src/preload.ts

Comment thread src/electron-api.d.ts
Comment thread src/popup.tsx Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 7 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/main.ts Outdated
Comment thread src/popup.tsx
Comment thread src/main.ts
Comment thread src/popup.tsx Outdated
Comment thread src/popup.tsx Outdated
Comment thread src/popup.tsx Outdated
- addAccount seeds the anchor (~/.claude) account when the registry is
  fresh and an EXTRA account is being added, so the machine's existing
  default install stays registered and keeps the global default
  (cubic P1; fixes the CLI path too)
- accounts-add IPC returns the enriched listed shape (isCurrentDefault)
  so it matches the declared CodevAccountInfo contract
- accounts-shell-hook validates the action — a malformed payload fails
  instead of silently uninstalling
- popup: refreshAccounts is async/await with catch; stale notice/error
  cleared on tab open and in each branch; set-default notice says
  "install Shell integration" when the zshrc block isn't installed;
  accountsBusy guard disables buttons during in-flight ops
  (runAccountOp serializes mutations)

tsc 0 errors; 13/13 tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/popup.tsx (1)

788-833: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix prettier indentation errors flagged by static analysis.

Multiple lines in the Accounts tab UI have incorrect indentation per prettier. These will fail formatting checks if prettier is enforced in CI.

Run npx prettier --write src/popup.tsx to auto-fix all flagged lines (788, 798, 818–825, 827–833).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/popup.tsx` around lines 788 - 833, The Accounts tab JSX in popup.tsx has
Prettier indentation issues that will fail formatting checks. Reformat the
affected block in the accounts UI markup around the Set default, Remove, Add
account, and Shell integration controls so it matches the project’s Prettier
style; the easiest fix is to run Prettier on src/popup.tsx and keep the
structure intact in the popup component.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@src/popup.tsx`:
- Around line 788-833: The Accounts tab JSX in popup.tsx has Prettier
indentation issues that will fail formatting checks. Reformat the affected block
in the accounts UI markup around the Set default, Remove, Add account, and Shell
integration controls so it matches the project’s Prettier style; the easiest fix
is to run Prettier on src/popup.tsx and keep the structure intact in the popup
component.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 48bc4f17-29e2-44be-92b9-12f0bc944e6c

📥 Commits

Reviewing files that changed from the base of the PR and between bd603fb and f221291.

📒 Files selected for processing (3)
  • src/cli/account-manager.ts
  • src/main.ts
  • src/popup.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 3 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/main.ts Outdated
grimmerk and others added 2 commits July 10, 2026 00:33
The defensive fallback returned a bare RegistryAccount, structurally
violating the CodevAccountInfo IPC contract (cubic P3). Compute it via
resolveDefaultLabel so both paths honor the type.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
Each row now shows its real command (launch: claude work; the default
shows bare claude) instead of abstract <label> wording; placeholder
says 'account name'; footer uses a concrete claude-work example.
(User feedback: 'label' is jargon — people don't know label = account
name.)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017kCK4t5JSVynVZxGcrTGGp
@grimmerk grimmerk merged commit 80fa52d into main Jul 9, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant