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

For each account:

  1. choose an alias such as work or personal
  2. complete /login in Claude Code
  3. return to the wizard so claude-select can capture the current login snapshot

You can add another account later:

claude-select add work
claude-select add personal

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: capture the current Claude login into the registry
  • relogin: 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.0.tar.gz (20.1 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.0-py3-none-any.whl (17.5 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: claude_select-0.2.0.tar.gz
  • Upload date:
  • Size: 20.1 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.0.tar.gz
Algorithm Hash digest
SHA256 93aac19521f7173e44bc723fa72d80cd226536b5ba29cf948e63908e9a85fe99
MD5 5c15cc3a314c8e21dfc0f1cddb40c075
BLAKE2b-256 646490e2e9d2a339245071aed1d93fc820466592ab79e546d70f342a78241c23

See more details on using hashes here.

Provenance

The following attestation bundles were made for claude_select-0.2.0.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.0-py3-none-any.whl.

File metadata

  • Download URL: claude_select-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 17.5 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.0-py3-none-any.whl
Algorithm Hash digest
SHA256 2e491d8951868afd969e51157773d50ed82065ff3ee377f3cf03dc8e540955e5
MD5 4c6a136f18daeaa5bc85eecb5a9ac0ca
BLAKE2b-256 0f1a8757f534ec3bf5810d6d39d29ec11ecaf0ba87d77f705b1897605e4fe1e7

See more details on using hashes here.

Provenance

The following attestation bundles were made for claude_select-0.2.0-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