Expand description
§claude_profile
Claude Code account credential management.
§Files
| File | Responsibility |
|---|---|
Cargo.toml | Crate manifest: dependencies, features, metadata |
src/ | Library modules and CLI binary (account, token, paths, adapter, commands) |
tests/ | Test suite for credential management |
docs/ | Behavioral requirements: features (FR-6–FR-20), invariants, CLI reference |
unilang.commands.yaml | YAML command metadata for 16 profile commands |
verb/ | Shell scripts for each do protocol verb (build, test, clean, run, lint). |
vision.md | Crate vision, design decisions, and open problems |
changelog.md | Notable changes by version |
§Responsibility Table
| Entity | Responsibility | Input→Output | Scope | Out of Scope |
|---|---|---|---|---|
account | Named credential storage and rotation | name → active credentials | Save, list, switch, delete accounts | ❌ OAuth HTTP refresh → network dep ❌ Browser launch → caller |
token | Active OAuth token expiry status | credentials file → TokenStatus | Read expiresAt, classify Valid/ExpiringSoon/Expired | ❌ Token refresh → HTTP ❌ Server-side window → unobservable |
paths | ~/.claude/ file topology | HOME → canonical PathBufs | All ~/.claude/ path constants | ❌ Process execution |
persist | Persistent user storage path resolution | $PRO/$HOME → PathBuf | Resolve $PRO/persistent/claude_profile/ with $HOME fallback (FR-15) | ❌ Writing data → caller |
§Scope
In Scope:
- Account credential snapshots in
$PRO/.persistent/claude/credential/(or$HOME/.persistent/...) - Token expiry detection from
~/.claude/.credentials.json - All canonical
~/.claude/paths viaClaudePaths - Persistent user storage path resolution via
PersistPaths($PRO/$HOME)
Out of Scope:
- ❌ Claude Code process execution →
claude_runner_core - ❌ Continuation detection (session file existence) →
claude_storage_core - ❌ Session directory management →
claude_runner_core::SessionManager - ❌ Pulse keeping (periodic
claudeinvocation) → caller +claude_runner - ❌ Browser launch /
xdg-open→ caller - ❌ OAuth HTTP token refresh → network dependency not allowed
- ❌ Server-side 5-hour subscription window → not locally observable
§Account Management
use claude_profile::{ account, token, ClaudePaths, PersistPaths };
// Where are the files?
let claude = ClaudePaths::new().expect( "HOME must be set" );
let persist = PersistPaths::new().expect( "HOME must be set" );
let credential_store = persist.credential_store();
println!( "credentials: {}", claude.credentials_file().display() );
println!( "credential_store: {}", credential_store.display() );
println!( "projects: {}", claude.projects_dir().display() );
// Check active token status
match token::status().expect( "failed to read credentials" )
{
token::TokenStatus::Valid { expires_in } =>
println!( "ok — {}m remaining", expires_in.as_secs() / 60 ),
token::TokenStatus::ExpiringSoon { expires_in } =>
eprintln!( "expires in {}m — consider switching accounts", expires_in.as_secs() / 60 ),
token::TokenStatus::Expired =>
eprintln!( "token expired — run: claude auth login" ),
}
// List all stored accounts
for acct in account::list( &credential_store ).expect( "failed to list accounts" )
{
let active = if acct.is_active { " ← active" } else { "" };
println!( "{}{} ({})", acct.name, active, acct.subscription_type );
}
// Save current credentials as "work@acme.com"
account::save( "work@acme.com", &credential_store, &claude, true, None, None, None, None ).expect( "failed to save account" );
// Switch to "personal@home.com"
account::switch_account( "personal@home.com", &credential_store, &claude ).expect( "failed to switch" );
// Delete an old account
account::delete( "old@acme.com", &credential_store ).expect( "failed to delete" );§File Paths
use claude_profile::{ ClaudePaths, PersistPaths };
let p = ClaudePaths::new().expect( "HOME must be set" );
let persist = PersistPaths::new().expect( "HOME must be set" );
println!( "credentials: {}", p.credentials_file().display() );
println!( "credential_store: {}", persist.credential_store().display() );
println!( "projects: {}", p.projects_dir().display() );
println!( "stats: {}", p.stats_file().display() );
println!( "settings: {}", p.settings_file().display() );
println!( "session-env: {}", p.session_env_dir().display() );
println!( "sessions: {}", p.sessions_dir().display() );§Binary
Two names, same binary — both claude_profile and clp are installed:
clp .accounts # list saved accounts
clp .usage # live rate-limit quota for all saved accounts
clp .paths # show ~/.claude/ canonical paths§Testing
Container (all tests — credentials required):
./verb/testContainer (offline — no credentials needed):
./verb/test offlineContainer (interactive shell):
./verb/shellLocal (Docker-orchestrated):
./verb/testClaude Code account credential management.
Manages multiple Claude Code credential sets stored under .persistent/claude/credential/
for account rotation when usage limits are reached.
§Modules
paths:ClaudePaths— all~/.claude/canonical paths fromHOMEaccount: Named credential storage and rotationtoken: OAuth token expiry status detectionpersist:PersistPaths— persistent user storage path from$PRO/$HOME(FR-15)registry: Command registration helpers (featureenabled)output: Output formatting,parse_int_flag, JWT utilities (featureenabled)
§Account Management Examples
§Check Token Status
use claude_profile::token;
match token::status().expect( "failed to read credentials" )
{
token::TokenStatus::Valid { expires_in } =>
println!( "ok — {}m remaining", expires_in.as_secs() / 60 ),
token::TokenStatus::ExpiringSoon { expires_in } =>
eprintln!( "expires in {}m", expires_in.as_secs() / 60 ),
token::TokenStatus::Expired =>
eprintln!( "token expired — run: claude auth login" ),
}§Inspect and Switch Manually
use claude_profile::{ account, ClaudePaths, PersistPaths };
let persist = PersistPaths::new().expect( "PRO or HOME must be set" );
let credential_store = persist.credential_store();
let paths = ClaudePaths::new().expect( "HOME must be set" );
// See what's available
for acct in account::list( &credential_store ).expect( "list failed" )
{
let active = if acct.is_active { " ← active" } else { "" };
println!( "{}{} ({})", acct.name, active, acct.subscription_type );
}
// Switch to a specific account
account::switch_account( "alice@home.com", &credential_store, &paths ).expect( "switch failed" );Re-exports§
pub use persist::PersistPaths;pub use registry::register_commands;
Modules§
- account
- Named credential storage and account rotation.
- adapter
- Adapter layer: parse raw
argvtokens into a command name and key-value parameters. - commands
- Command handlers: one function per
claude_profileCLI command. - output
- Output formatting: text/json selection, JSON string escaping, duration display.
- paths
- Canonical paths for all
~/.claude/filesystem locations. - persist
- Persistent user storage paths for
claude_profile. - registry
- Command registration: argument definitions and routines for the
claude_profileCLI. - token
- Active OAuth token expiry status detection.
- usage
.usagecommand — quota fetch, render, and live-monitor for all saved accounts.
Structs§
- Claude
Paths - Canonical paths for all
~/.claude/filesystem locations.
Constants§
- COMMANDS_
YAML - Path to the YAML command definitions for this crate.
Functions§
- run_cli
- Run the
clp/claude_profileCLI.