Skip to main content

Crate claude_profile

Crate claude_profile 

Source
Expand description

§claude_profile

Claude Code account credential management.

§Files

FileResponsibility
Cargo.tomlCrate 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.yamlYAML command metadata for 16 profile commands
verb/Shell scripts for each do protocol verb (build, test, clean, run, lint).
vision.mdCrate vision, design decisions, and open problems
changelog.mdNotable changes by version

§Responsibility Table

EntityResponsibilityInput→OutputScopeOut of Scope
accountNamed credential storage and rotationname → active credentialsSave, list, switch, delete accounts❌ OAuth HTTP refresh → network dep
❌ Browser launch → caller
tokenActive OAuth token expiry statuscredentials file → TokenStatusRead expiresAt, classify Valid/ExpiringSoon/Expired❌ Token refresh → HTTP
❌ Server-side window → unobservable
paths~/.claude/ file topologyHOME → canonical PathBufsAll ~/.claude/ path constants❌ Process execution
persistPersistent user storage path resolution$PRO/$HOMEPathBufResolve $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 via ClaudePaths
  • 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 claude invocation) → 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/test

Container (offline — no credentials needed):

./verb/test offline

Container (interactive shell):

./verb/shell

Local (Docker-orchestrated):

./verb/test

Claude 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 from HOME
  • account: Named credential storage and rotation
  • token: OAuth token expiry status detection
  • persist: PersistPaths — persistent user storage path from $PRO/$HOME (FR-15)
  • registry: Command registration helpers (feature enabled)
  • output: Output formatting, parse_int_flag, JWT utilities (feature enabled)

§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 argv tokens into a command name and key-value parameters.
commands
Command handlers: one function per claude_profile CLI 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_profile CLI.
token
Active OAuth token expiry status detection.
usage
.usage command — quota fetch, render, and live-monitor for all saved accounts.

Structs§

ClaudePaths
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_profile CLI.