Skip to content

feat: add Claude multi-account support#965

Open
QuadDepo wants to merge 6 commits into
robinebers:mainfrom
QuadDepo:feat/claude-multi-account
Open

feat: add Claude multi-account support#965
QuadDepo wants to merge 6 commits into
robinebers:mainfrom
QuadDepo:feat/claude-multi-account

Conversation

@QuadDepo

Copy link
Copy Markdown

Approved issue

Fixes #402 (not approved but reopend? partially fixes it; only tackles Claude accounts)

TL;DR

Ability to have multiple Claude accounts and give them an appropriate name.

What was happening

I got annoyed by the fact that I couldn't see my work usage, but only personal.

What this changes

Add support for multiple Claude code accounts by checking ~/.claude* to find additional .credentials.json or getting them from the keychain with the claude Code-credentials prefix.

Heads-up

  • Currently only covers Claude account
  • Opening the status page is not account bound (not a regression, depends on what logged-in account on browser is)

Tests

I have verified the changes locally using a build, as well as written the correct tests where needed.

Screenshots

customize with-without-name

Copilot AI 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.

Pull request overview

Adds first-pass multi-account support for the Claude provider by discovering additional Claude Code credential sources on the machine, persisting extra account instances, and surfacing them as separate provider cards that can be renamed live in Customize.

Changes:

  • Discover extra Claude accounts from ~/.claude* / XDG config / CLAUDE_CONFIG_DIR plus keychain service-prefix enumeration, and reconcile them into persisted extra-account records.
  • Instantiate one ClaudeProvider per extra account (claude.<uuid>), namespace widget IDs accordingly, and intentionally omit spend tiles for non-default accounts.
  • Add live provider display-name overrides (for extra-account renames) and corresponding UI + tests + docs.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
Tests/OpenUsageTests/TestSupport.swift Extends keychain test double with service-prefix enumeration support.
Tests/OpenUsageTests/LayoutStoreTests.swift Adds coverage for live provider name overrides across LayoutStore accessors.
Tests/OpenUsageTests/ClaudeAccountDiscoveryTests.swift Adds end-to-end tests for discovery, reconcile, scoping, and namespacing behavior.
Sources/OpenUsage/Views/CustomizeProviderDetailView.swift Adds per-extra-account rename field in Customize detail view.
Sources/OpenUsage/Stores/LayoutStore+Customization.swift Applies provider name overrides when returning Provider models to the UI.
Sources/OpenUsage/Stores/LayoutStore.swift Adds providerNameOverride injection point for live provider display-name overrides.
Sources/OpenUsage/Services/SystemClients.swift Adds keychain service-prefix enumeration API + Security-based implementation.
Sources/OpenUsage/Providers/Claude/ClaudeProvider.swift Supports account-scoped provider instances and conditionally includes spend tiles only for default.
Sources/OpenUsage/Providers/Claude/ClaudeAuthStore.swift Adds account scoping to isolate credential sources per extra Claude account.
Sources/OpenUsage/Providers/Claude/ClaudeAccountsStore.swift New persisted store for extra Claude account records + reconcile logic + renames.
Sources/OpenUsage/Providers/Claude/ClaudeAccountDiscovery.swift New discovery routine for locating extra Claude accounts from filesystem + keychain metadata.
Sources/OpenUsage/App/AppContainer.swift Wires discovery + records into provider runtime list and LayoutStore defaults + live name override closure.
docs/providers/claude.md Documents Claude multi-account behavior, discovery scope, and rename UX.
docs/provider-enablement.md Notes that extra Claude accounts follow the same first-seen enablement path as new providers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +178 to +180
/// Rename field for an extra Claude account. The placeholder shows the auto-generated name (e.g.
/// "Claude (3f9a2b1c)"); typing a name and committing it persists a custom name. The registry is built
/// at launch, so the new name shows on the next relaunch. No tooltip (house rule).
Comment on lines +312 to +329
func genericPasswordServices(withPrefix prefix: String) throws -> [String] {
let query: [CFString: Any] = [
kSecClass: kSecClassGenericPassword,
kSecMatchLimit: kSecMatchLimitAll,
kSecReturnAttributes: true
]
var result: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &result)
if status == errSecItemNotFound { return [] }
guard status == errSecSuccess else {
AppLog.warn(.keychain, "service enumeration failed (status \(status))")
throw KeychainError.readFailed("keychain enumeration failed (status \(status))")
}
guard let items = result as? [[String: Any]] else { return [] }
return items
.compactMap { $0[kSecAttrService as String] as? String }
.filter { $0.hasPrefix(prefix) }
}

@cursor cursor 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.

Thanks for the PR! OpenUsage reviews external PRs only when they implement an issue a maintainer has already approved with the approved label. Please open an issue, wait for approval, then reopen this (or open a focused PR) linking it with Fixes #<issue>. Happy to take a look once it's linked to an approved issue.

— Powered by Cursor Automations

Open in Web View Automation 

Sent by Cursor Automation: OpenUsage PR Gatekeeper

@robinebers robinebers added the needs-approved-issue External PR needs an open issue with status:approved label Jul 11, 2026 — with Cursor

@cursor cursor 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.

Thanks for the PR! OpenUsage reviews external PRs only when they implement an issue a maintainer has already approved with the approved label. Please open an issue, wait for approval, then reopen this (or open a focused PR) linking it with Fixes #<issue>. Happy to take a look once it's linked to an approved issue.

— Powered by Cursor Automations

Open in Web View Automation 

Sent by Cursor Automation: OpenUsage PR Gatekeeper

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs needs-approved-issue External PR needs an open issue with status:approved provider tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support multiple accounts per provider / platform

3 participants