Skip to main content

Manage a local registry of Claude login snapshots for CLI selection and Python SDK usage.

Project description

claude-select 🔐

PyPI version Python versions CI

中文说明

claude-select is a local Claude auth registry and selector for people who use multiple Claude accounts on one machine.

It captures the current Claude CLI login state, stores each account as a snapshot in a local SQLite registry, shows expiry status in a table, and lets you:

  • select one stored account back into Claude's live auth state for CLI use
  • read one stored account from Python and build env for Claude Agent SDK use

It does not auto-refresh OAuth tokens. It trusts the captured expiresAt value and asks the user to log in again when an account is near expiry or expired.

Install 🚀

pip install claude-select

How Users Get Started 👇

1. Capture your accounts

Run the guided bootstrap:

claude-select init

By default, claude-select launches claude in the current terminal for each account capture.

For each account:

  1. choose an alias such as work or personal
  2. claude-select launches claude
  3. inside the claude CLI session, run /login and finish authorization
  4. exit claude and return to claude-select
  5. press Enter so claude-select can capture the current login snapshot

You can add another account later:

claude-select add work
claude-select add personal

If you do not want claude-select to launch claude for you, use:

claude-select add work --no-launch

In that mode, claude-select will print guidance and wait while you run claude and /login yourself.

2. See what is stored

claude-select list
claude-select watch

Example table:

Alias     Email             Status          Expires In  Last Selected
--------  ----------------  --------------  ----------  -------------
personal  a@example.com     healthy         18h 12m     2h ago
work      b@company.com     expiring_soon   1h 05m      -
team-a    c@company.com     expired         expired     3d ago

3. Select an account for Claude CLI

claude-select select work

This reads the stored snapshot from the local registry and writes it back into Claude's current live auth backend:

  • macOS: Keychain + Claude config
  • Linux / Windows: Claude credentials file + Claude config

4. Use an account in Python

from claude_select import AuthManager
from claude_code_sdk import ClaudeAgentOptions, query

manager = AuthManager()
env = manager.build_sdk_env("work")

options = ClaudeAgentOptions(env=env)

async for message in query(prompt="analyze this repo", options=options):
    print(message)

The Python side reads from the same local registry, but it does not mutate Claude's live auth state.

CLI Commands 🧰

claude-select init
claude-select add <alias>
claude-select relogin <alias>
claude-select list
claude-select watch
claude-select select [alias]
claude-select remove <alias>
claude-select export-env <alias> --json
claude-select current

Command behavior:

  • init: guided multi-account bootstrap
  • add: launch claude in the current terminal by default, then capture the current login into the registry
  • relogin: launch claude in the current terminal by default, then overwrite one stored alias after the user logs in again
  • list: show the current registry table
  • watch: keep refreshing the table in the terminal
  • select: write one stored snapshot back into Claude's live auth state
  • remove: delete one stored account
  • export-env: print SDK env vars for one alias
  • current: show the last alias selected for CLI use

Python API 🐍

Minimal usage:

from claude_select import AuthManager

manager = AuthManager()

accounts = manager.list_accounts()
details = manager.get_account("work")
env = manager.build_sdk_env("work")
auth_payload = manager.export_sdk_auth("work")

Current public surface:

class AuthManager:
    def list_accounts(self) -> list[dict]: ...
    def get_account(self, alias: str): ...
    def capture_current_account(self, alias: str, overwrite: bool = True) -> dict: ...
    def relogin_account(self, alias: str) -> dict: ...
    def remove_account(self, alias: str) -> None: ...
    def select_account(self, alias: str) -> dict: ...
    def build_sdk_env(self, alias: str, base_env: dict[str, str] | None = None) -> dict[str, str]: ...
    def export_sdk_auth(self, alias: str) -> dict: ...
    def current_alias(self) -> str | None: ...
    def render_table(self) -> str: ...

Top-level helper:

from claude_select import build_sdk_env

env = build_sdk_env("work")

How Expiry Works ⏳

claude-select does not refresh tokens automatically.

It only reads the stored expiresAt timestamp and derives status from it:

  • healthy: more than 6 hours remain
  • expiring_soon: 6 hours or less remain
  • expired: already expired
  • unknown: no expiresAt value was captured

When an account is expired:

  • select fails
  • build_sdk_env() fails
  • the user should log in again and run:
claude-select relogin <alias>

Storage Model 🗃️

The registry is stored locally in SQLite:

  • macOS / Linux default:
    • ~/.config/claude-select/registry.db
  • custom XDG config root:
    • $XDG_CONFIG_HOME/claude-select/registry.db

Each stored account contains:

  • alias
  • email
  • organization name / id
  • account uuid
  • captured time
  • expiry time
  • last selected time
  • stored Claude oauthAccount
  • stored Claude claudeAiOauth credentials payload

Claude's own live state remains separate:

  • global Claude config
  • Claude credentials file or macOS Keychain

The registry is the source of truth. select copies one stored snapshot back into Claude's live state.

Current Limitations ⚠️

  • This project currently centers on captured Claude OAuth snapshots.
  • It does not auto-refresh tokens.
  • It relies on the structure of Claude's current local auth state.
  • Expiry monitoring is local-only; it does not call a remote validation API.
  • Selecting an account updates the local machine's active Claude login state.

Development 🛠️

Install dev dependencies:

pip install -e .[dev]

Run checks:

ruff check .
ruff format --check .
mypy
pytest
python -m build
python -m twine check dist/*

License 📄

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

claude_select-0.2.1.tar.gz (20.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

claude_select-0.2.1-py3-none-any.whl (17.8 kB view details)

Uploaded Python 3

File details

Details for the file claude_select-0.2.1.tar.gz.

File metadata

  • Download URL: claude_select-0.2.1.tar.gz
  • Upload date:
  • Size: 20.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for claude_select-0.2.1.tar.gz
Algorithm Hash digest
SHA256 9fb297274435ce283ddb12779277bf4cdef55d8bdda9cb1d2d99dd564c80988a
MD5 44182cd111c06e5a91da3e04560b062b
BLAKE2b-256 260ce90f10c52077e369433b58cfc7c12239fde2c94f047039f21897f04b89ea

See more details on using hashes here.

Provenance

The following attestation bundles were made for claude_select-0.2.1.tar.gz:

Publisher: publish.yml on Nomia/claude-select

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file claude_select-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: claude_select-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 17.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for claude_select-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0315c80006682b77d3a7beaa1f6a36291c864cc50c7e9805f6589fd81dd9f2f7
MD5 cd73fe3b69f531ae8cd8bdeeef9755f1
BLAKE2b-256 664580d217ab451bd7538bc8c2a511e5c1f80bb81d12b7729e3265026a3cf58a

See more details on using hashes here.

Provenance

The following attestation bundles were made for claude_select-0.2.1-py3-none-any.whl:

Publisher: publish.yml on Nomia/claude-select

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page