claude-select 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- claude_select-0.1.0/LICENSE +22 -0
- claude_select-0.1.0/PKG-INFO +478 -0
- claude_select-0.1.0/README.md +446 -0
- claude_select-0.1.0/pyproject.toml +91 -0
- claude_select-0.1.0/setup.cfg +4 -0
- claude_select-0.1.0/src/claude_select/__init__.py +5 -0
- claude_select-0.1.0/src/claude_select/__main__.py +8 -0
- claude_select-0.1.0/src/claude_select/cli.py +115 -0
- claude_select-0.1.0/src/claude_select/exceptions.py +29 -0
- claude_select-0.1.0/src/claude_select/live_state.py +176 -0
- claude_select-0.1.0/src/claude_select/locking.py +65 -0
- claude_select-0.1.0/src/claude_select/manager.py +260 -0
- claude_select-0.1.0/src/claude_select/models.py +140 -0
- claude_select-0.1.0/src/claude_select/oauth.py +151 -0
- claude_select-0.1.0/src/claude_select/paths.py +45 -0
- claude_select-0.1.0/src/claude_select/store.py +136 -0
- claude_select-0.1.0/src/claude_select.egg-info/PKG-INFO +478 -0
- claude_select-0.1.0/src/claude_select.egg-info/SOURCES.txt +28 -0
- claude_select-0.1.0/src/claude_select.egg-info/dependency_links.txt +1 -0
- claude_select-0.1.0/src/claude_select.egg-info/entry_points.txt +2 -0
- claude_select-0.1.0/src/claude_select.egg-info/requires.txt +8 -0
- claude_select-0.1.0/src/claude_select.egg-info/top_level.txt +1 -0
- claude_select-0.1.0/tests/test_cli.py +37 -0
- claude_select-0.1.0/tests/test_cli_more.py +31 -0
- claude_select-0.1.0/tests/test_live_state.py +100 -0
- claude_select-0.1.0/tests/test_manager.py +95 -0
- claude_select-0.1.0/tests/test_oauth.py +50 -0
- claude_select-0.1.0/tests/test_oauth_more.py +82 -0
- claude_select-0.1.0/tests/test_paths.py +31 -0
- claude_select-0.1.0/tests/test_store.py +51 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 wx.luo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: claude-select
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Manage multiple Claude auth profiles for the Claude Code CLI and Python Agent SDK usage.
|
|
5
|
+
Author: wx.luo
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Nomia/claude-select
|
|
8
|
+
Project-URL: Repository, https://github.com/Nomia/claude-select
|
|
9
|
+
Project-URL: Issues, https://github.com/Nomia/claude-select/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/Nomia/claude-select/blob/main/CHANGELOG.md
|
|
11
|
+
Keywords: claude,claude-code,oauth,sdk,cli
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Operating System :: MacOS
|
|
15
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
16
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Classifier: Topic :: Utilities
|
|
21
|
+
Requires-Python: >=3.12
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Provides-Extra: dev
|
|
25
|
+
Requires-Dist: build>=1.2.2; extra == "dev"
|
|
26
|
+
Requires-Dist: mypy>=1.11.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest>=8.3.0; extra == "dev"
|
|
28
|
+
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
|
|
29
|
+
Requires-Dist: ruff>=0.11.0; extra == "dev"
|
|
30
|
+
Requires-Dist: twine>=5.1.1; extra == "dev"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# claude-select
|
|
34
|
+
|
|
35
|
+
`claude-select` is a local SDK and CLI design for managing multiple Claude authentication profiles across:
|
|
36
|
+
|
|
37
|
+
- the global Claude Code CLI login state
|
|
38
|
+
- Python programs using the Claude Agent SDK
|
|
39
|
+
|
|
40
|
+
This repository now contains a working first implementation of the design described below:
|
|
41
|
+
|
|
42
|
+
- file-backed profile storage
|
|
43
|
+
- CLI profile capture, switch, sync, inspect, remove, and default SDK selection
|
|
44
|
+
- Python `build_sdk_env()` support for direct `ClaudeAgentOptions(env=...)` usage
|
|
45
|
+
- OAuth refresh handling for stored profiles
|
|
46
|
+
|
|
47
|
+
The README still documents the intended architecture so the implementation can evolve without losing the original design constraints.
|
|
48
|
+
|
|
49
|
+
## Status
|
|
50
|
+
|
|
51
|
+
Current implementation status:
|
|
52
|
+
|
|
53
|
+
- `ProfileManager` and top-level `build_sdk_env()` are implemented
|
|
54
|
+
- CLI commands are implemented for local single-user usage
|
|
55
|
+
- OAuth refresh is implemented for stored profiles
|
|
56
|
+
- unit tests are in place
|
|
57
|
+
- lint, type-check, build, and CI configuration are included
|
|
58
|
+
|
|
59
|
+
## Goals
|
|
60
|
+
|
|
61
|
+
- Let a user capture multiple Claude accounts/profiles on one machine.
|
|
62
|
+
- Let the global Claude Code CLI switch between stored profiles.
|
|
63
|
+
- Let Python programs select a profile explicitly for each Claude Agent SDK call.
|
|
64
|
+
- Share one profile store between CLI switching and Python SDK usage.
|
|
65
|
+
- Avoid coupling Python SDK requests to the current global CLI account.
|
|
66
|
+
|
|
67
|
+
## Non-goals
|
|
68
|
+
|
|
69
|
+
- Replacing Claude's official login flow.
|
|
70
|
+
- Building a hosted multi-user auth product.
|
|
71
|
+
- Relying on global process-wide environment mutation for Python SDK calls.
|
|
72
|
+
- Treating Agent SDK auth and CLI live auth as the same runtime state.
|
|
73
|
+
|
|
74
|
+
## Core Model
|
|
75
|
+
|
|
76
|
+
The design separates three concepts:
|
|
77
|
+
|
|
78
|
+
1. `profiles`
|
|
79
|
+
Stored account/auth profiles shared by CLI and Python SDK usage.
|
|
80
|
+
2. `current_cli_profile`
|
|
81
|
+
The profile currently written into Claude Code's live login state.
|
|
82
|
+
3. `default_sdk_profile`
|
|
83
|
+
The fallback profile used by Python helpers when the caller does not explicitly choose one.
|
|
84
|
+
|
|
85
|
+
This separation is intentional:
|
|
86
|
+
|
|
87
|
+
- CLI switching is global and mutates Claude's live state.
|
|
88
|
+
- Agent SDK switching is per-call and should be isolated through `env`.
|
|
89
|
+
|
|
90
|
+
## Authentication Model
|
|
91
|
+
|
|
92
|
+
### CLI
|
|
93
|
+
|
|
94
|
+
For the Claude Code CLI, switching works by reading and writing Claude's live login state:
|
|
95
|
+
|
|
96
|
+
- `~/.claude.json` or `~/.claude/.config.json`
|
|
97
|
+
- `~/.claude/.credentials.json`
|
|
98
|
+
- platform-specific secure storage where applicable
|
|
99
|
+
- `CLAUDE_CONFIG_DIR` when set
|
|
100
|
+
|
|
101
|
+
The SDK captures the current live state into a reusable profile, then later writes a chosen profile back into the live Claude files when the user switches.
|
|
102
|
+
|
|
103
|
+
### Python Agent SDK
|
|
104
|
+
|
|
105
|
+
For Python, the preferred model is explicit per-call environment injection:
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
env = manager.build_sdk_env("work")
|
|
109
|
+
options = ClaudeAgentOptions(env=env)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
This avoids:
|
|
113
|
+
|
|
114
|
+
- mutating global `os.environ`
|
|
115
|
+
- leaking one profile into another concurrent request
|
|
116
|
+
- forcing Python usage to follow whatever the CLI currently uses
|
|
117
|
+
|
|
118
|
+
## Shared Store Design
|
|
119
|
+
|
|
120
|
+
The SDK owns a profile store separate from Claude's live runtime files.
|
|
121
|
+
|
|
122
|
+
Recommended structure:
|
|
123
|
+
|
|
124
|
+
```text
|
|
125
|
+
~/.config/claude-select/
|
|
126
|
+
state.json
|
|
127
|
+
secrets/
|
|
128
|
+
work.json
|
|
129
|
+
personal.json
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### `state.json`
|
|
133
|
+
|
|
134
|
+
Holds non-sensitive metadata and pointers:
|
|
135
|
+
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"version": 1,
|
|
139
|
+
"current_cli_profile": "personal",
|
|
140
|
+
"default_sdk_profile": "work",
|
|
141
|
+
"profiles": {
|
|
142
|
+
"work": {
|
|
143
|
+
"id": "work",
|
|
144
|
+
"kind": "oauth",
|
|
145
|
+
"label": "work",
|
|
146
|
+
"email": "user@example.com",
|
|
147
|
+
"organization_id": "org_xxx",
|
|
148
|
+
"organization_name": "Example Org",
|
|
149
|
+
"auth_state": "ok",
|
|
150
|
+
"expires_at": 1760000000000,
|
|
151
|
+
"secret_ref": "work",
|
|
152
|
+
"updated_at": "2026-04-19T00:00:00Z"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### `secrets/<profile>.json`
|
|
159
|
+
|
|
160
|
+
Holds sensitive auth material:
|
|
161
|
+
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"oauthAccount": {
|
|
165
|
+
"emailAddress": "user@example.com"
|
|
166
|
+
},
|
|
167
|
+
"credentials": {
|
|
168
|
+
"claudeAiOauth": {
|
|
169
|
+
"accessToken": "...",
|
|
170
|
+
"refreshToken": "...",
|
|
171
|
+
"expiresAt": 1760000000000,
|
|
172
|
+
"scopes": ["user:profile"]
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Future versions may replace file-based secret storage with platform keychains while keeping the same `secret_ref` abstraction.
|
|
179
|
+
|
|
180
|
+
## OAuth Expiry Strategy
|
|
181
|
+
|
|
182
|
+
When using OAuth-backed profiles:
|
|
183
|
+
|
|
184
|
+
- Access token near expiry: refresh automatically if `refreshToken` exists.
|
|
185
|
+
- Refresh succeeds: update the profile store before returning.
|
|
186
|
+
- Refresh fails: mark the profile as `reauth_required`.
|
|
187
|
+
|
|
188
|
+
For CLI switching:
|
|
189
|
+
|
|
190
|
+
- switching should still be allowed
|
|
191
|
+
- the tool should clearly report that the selected profile now requires `claude` `/login`
|
|
192
|
+
- after re-login, the user runs `capture` or `sync` to update the stored profile
|
|
193
|
+
|
|
194
|
+
For Python SDK usage:
|
|
195
|
+
|
|
196
|
+
- `build_sdk_env(profile)` should attempt refresh first
|
|
197
|
+
- if refresh fails, raise a clear exception such as `ProfileReauthRequired`
|
|
198
|
+
|
|
199
|
+
## CLI Design
|
|
200
|
+
|
|
201
|
+
Planned commands:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
claude-select capture <profile>
|
|
205
|
+
claude-select sync [<profile>]
|
|
206
|
+
claude-select list
|
|
207
|
+
claude-select current
|
|
208
|
+
claude-select use <profile>
|
|
209
|
+
claude-select remove <profile>
|
|
210
|
+
claude-select set-default-sdk <profile>
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Command behavior
|
|
214
|
+
|
|
215
|
+
- `capture <profile>`
|
|
216
|
+
Reads Claude's current live login state and stores it as a named profile.
|
|
217
|
+
- `sync [<profile>]`
|
|
218
|
+
Updates an existing stored profile from the current live login state.
|
|
219
|
+
- `list`
|
|
220
|
+
Shows all stored profiles and auth state.
|
|
221
|
+
- `current`
|
|
222
|
+
Shows the current CLI profile and default SDK profile.
|
|
223
|
+
- `use <profile>`
|
|
224
|
+
Switches Claude's global live login state to the chosen profile.
|
|
225
|
+
- `remove <profile>`
|
|
226
|
+
Removes a stored profile from the SDK store.
|
|
227
|
+
- `set-default-sdk <profile>`
|
|
228
|
+
Updates `default_sdk_profile`.
|
|
229
|
+
|
|
230
|
+
## Python SDK Design
|
|
231
|
+
|
|
232
|
+
Planned primary interface:
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
from claude_select import ProfileManager
|
|
236
|
+
|
|
237
|
+
manager = ProfileManager()
|
|
238
|
+
env = manager.build_sdk_env("work")
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Planned convenience function:
|
|
242
|
+
|
|
243
|
+
```python
|
|
244
|
+
from claude_select import build_sdk_env
|
|
245
|
+
|
|
246
|
+
env = build_sdk_env("work")
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Intended `ProfileManager` surface
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
class ProfileManager:
|
|
253
|
+
def list_profiles(self) -> list[str]: ...
|
|
254
|
+
def capture_cli_profile(self, name: str) -> None: ...
|
|
255
|
+
def sync_cli_profile(self, name: str | None = None) -> None: ...
|
|
256
|
+
def switch_cli(self, name: str) -> None: ...
|
|
257
|
+
def set_default_sdk_profile(self, name: str) -> None: ...
|
|
258
|
+
def get_default_sdk_profile(self) -> str | None: ...
|
|
259
|
+
def inspect_profile(self, name: str) -> dict: ...
|
|
260
|
+
def build_sdk_env(self, name: str | None = None) -> dict[str, str]: ...
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Agent SDK Environment Injection
|
|
264
|
+
|
|
265
|
+
The direct usage style for Python is the intended default:
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
from claude_select import ProfileManager
|
|
269
|
+
from claude_code_sdk import ClaudeAgentOptions, query
|
|
270
|
+
|
|
271
|
+
manager = ProfileManager()
|
|
272
|
+
|
|
273
|
+
env = manager.build_sdk_env("work")
|
|
274
|
+
options = ClaudeAgentOptions(env=env)
|
|
275
|
+
|
|
276
|
+
async for message in query(
|
|
277
|
+
prompt="Analyze this repository",
|
|
278
|
+
options=options,
|
|
279
|
+
):
|
|
280
|
+
print(message)
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Why this is the default
|
|
284
|
+
|
|
285
|
+
- explicit per-call behavior
|
|
286
|
+
- works with async and concurrent tasks
|
|
287
|
+
- no hidden global mutation
|
|
288
|
+
- lets one process use multiple profiles safely
|
|
289
|
+
|
|
290
|
+
## Environment Variables by Profile Type
|
|
291
|
+
|
|
292
|
+
`build_sdk_env()` will return a clean environment map for exactly one auth mode.
|
|
293
|
+
|
|
294
|
+
### OAuth profile
|
|
295
|
+
|
|
296
|
+
Expected output:
|
|
297
|
+
|
|
298
|
+
```python
|
|
299
|
+
{
|
|
300
|
+
"CLAUDE_CODE_OAUTH_TOKEN": "...",
|
|
301
|
+
"CLAUDE_CODE_OAUTH_REFRESH_TOKEN": "..."
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### API key profile
|
|
306
|
+
|
|
307
|
+
Expected output:
|
|
308
|
+
|
|
309
|
+
```python
|
|
310
|
+
{
|
|
311
|
+
"ANTHROPIC_API_KEY": "..."
|
|
312
|
+
}
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### Important rule
|
|
316
|
+
|
|
317
|
+
Conflicting auth env vars should be removed from the returned environment. For example, an OAuth profile should not leave these active:
|
|
318
|
+
|
|
319
|
+
- `ANTHROPIC_API_KEY`
|
|
320
|
+
- `ANTHROPIC_AUTH_TOKEN`
|
|
321
|
+
- `CLAUDE_CODE_USE_BEDROCK`
|
|
322
|
+
- `CLAUDE_CODE_USE_VERTEX`
|
|
323
|
+
- `CLAUDE_CODE_USE_FOUNDRY`
|
|
324
|
+
|
|
325
|
+
## How Users Get Started
|
|
326
|
+
|
|
327
|
+
Recommended first-run flow:
|
|
328
|
+
|
|
329
|
+
1. Log in with Claude's official CLI flow.
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
claude
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Then complete `/login`.
|
|
336
|
+
|
|
337
|
+
2. Capture the current account into a named profile.
|
|
338
|
+
|
|
339
|
+
```bash
|
|
340
|
+
claude-select capture work
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
3. Log in with another account if needed, then capture again.
|
|
344
|
+
|
|
345
|
+
```bash
|
|
346
|
+
claude-select capture personal
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
4. Switch the global CLI account when needed.
|
|
350
|
+
|
|
351
|
+
```bash
|
|
352
|
+
claude-select use personal
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
5. Use a chosen profile from Python.
|
|
356
|
+
|
|
357
|
+
```python
|
|
358
|
+
from claude_select import ProfileManager
|
|
359
|
+
from claude_code_sdk import ClaudeAgentOptions
|
|
360
|
+
|
|
361
|
+
manager = ProfileManager()
|
|
362
|
+
env = manager.build_sdk_env("work")
|
|
363
|
+
options = ClaudeAgentOptions(env=env)
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
## Development
|
|
367
|
+
|
|
368
|
+
Set up a local environment:
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
python3 -m venv .venv
|
|
372
|
+
source .venv/bin/activate
|
|
373
|
+
python3 -m pip install -e ".[dev]"
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Run the full local quality suite:
|
|
377
|
+
|
|
378
|
+
```bash
|
|
379
|
+
ruff check .
|
|
380
|
+
ruff format --check .
|
|
381
|
+
mypy
|
|
382
|
+
python3 -m pytest
|
|
383
|
+
python3 -m build
|
|
384
|
+
python3 -m twine check dist/*
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
You can also run the CLI as:
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
python3 -m claude_select --help
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
## Runtime Relationship
|
|
394
|
+
|
|
395
|
+
The intended data flow is:
|
|
396
|
+
|
|
397
|
+
- CLI capture: Claude live state -> SDK profile store
|
|
398
|
+
- CLI switch: SDK profile store -> Claude live state
|
|
399
|
+
- Python SDK usage: SDK profile store -> `env`
|
|
400
|
+
|
|
401
|
+
The Python SDK should not depend on the current global CLI account unless the caller explicitly chooses the same profile.
|
|
402
|
+
|
|
403
|
+
## Safety and Concurrency
|
|
404
|
+
|
|
405
|
+
Implementation should include:
|
|
406
|
+
|
|
407
|
+
- file locking during capture, sync, switch, and refresh
|
|
408
|
+
- atomic writes for state and secret files
|
|
409
|
+
- backups before mutating Claude live files
|
|
410
|
+
- detection of running Claude CLI / IDE instances
|
|
411
|
+
- clear messaging when restart or re-login is required
|
|
412
|
+
|
|
413
|
+
Current status:
|
|
414
|
+
|
|
415
|
+
- file locking is implemented for the SDK profile store
|
|
416
|
+
- atomic file writes are implemented for profile and live-state file writes
|
|
417
|
+
- live-state backups are implemented before Claude auth mutation
|
|
418
|
+
- full Claude process detection is not implemented yet
|
|
419
|
+
|
|
420
|
+
## Status Values
|
|
421
|
+
|
|
422
|
+
Each profile should expose a simple auth status:
|
|
423
|
+
|
|
424
|
+
- `ok`
|
|
425
|
+
- `expiring_soon`
|
|
426
|
+
- `refreshable`
|
|
427
|
+
- `reauth_required`
|
|
428
|
+
- `invalid`
|
|
429
|
+
|
|
430
|
+
These statuses should be visible in `list` and `inspect_profile`.
|
|
431
|
+
|
|
432
|
+
## Scope of First Implementation
|
|
433
|
+
|
|
434
|
+
The first implementation should prioritize:
|
|
435
|
+
|
|
436
|
+
1. file-based profile store
|
|
437
|
+
2. OAuth profile capture from Claude CLI live state
|
|
438
|
+
3. CLI switching between stored OAuth profiles
|
|
439
|
+
4. `build_sdk_env(profile)` for Python Agent SDK usage
|
|
440
|
+
5. token refresh for OAuth-backed profiles
|
|
441
|
+
|
|
442
|
+
The first implementation should not prioritize:
|
|
443
|
+
|
|
444
|
+
- hosted sync
|
|
445
|
+
- multi-user remote storage
|
|
446
|
+
- GUI
|
|
447
|
+
- deep plugin integrations
|
|
448
|
+
|
|
449
|
+
## Current Limitations
|
|
450
|
+
|
|
451
|
+
- The primary supported profile type today is OAuth captured from Claude CLI live state.
|
|
452
|
+
- macOS keychain reading and writing is implemented, but broader secure-store coverage is still incomplete.
|
|
453
|
+
- Full pre-switch detection of running Claude sessions and IDE integrations is not implemented yet.
|
|
454
|
+
- This project is designed for local single-user machines, not shared multi-user hosts.
|
|
455
|
+
|
|
456
|
+
## Release Checklist
|
|
457
|
+
|
|
458
|
+
Before publishing a release:
|
|
459
|
+
|
|
460
|
+
1. Run the full local quality suite.
|
|
461
|
+
2. Verify `claude-select capture`, `claude-select use`, and `build_sdk_env()` against a real local Claude setup.
|
|
462
|
+
3. Update `CHANGELOG.md`.
|
|
463
|
+
4. Create a version tag and publish artifacts built from CI-verified sources.
|
|
464
|
+
|
|
465
|
+
## References
|
|
466
|
+
|
|
467
|
+
This design is informed by the following projects:
|
|
468
|
+
|
|
469
|
+
- [Leuconoe/ClaudeCodeMultiAccounts](https://github.com/Leuconoe/ClaudeCodeMultiAccounts)
|
|
470
|
+
- [realiti4/claude-swap](https://github.com/realiti4/claude-swap)
|
|
471
|
+
|
|
472
|
+
## Current State
|
|
473
|
+
|
|
474
|
+
The repository contains a tested first implementation aimed at local single-user usage. Future work can harden:
|
|
475
|
+
|
|
476
|
+
- platform keychain integration beyond the current file-backed path and macOS keychain support
|
|
477
|
+
- richer process detection before CLI switching
|
|
478
|
+
- broader profile kinds beyond OAuth-backed profiles
|