# CCS Codebase Summary (v3.0) ## Overview CCS (Claude Code Switch) v3.0 is a lightweight CLI wrapper enabling instant profile switching between Claude Sonnet 4.5, GLM 4.6, and Kimi for Coding models. Version 3.0 represents a major architectural simplification through vault removal and adoption of a login-per-profile model. ## Version Evolution ### v2.x Architecture - **Total LOC**: ~1,700 (includes vault, encryption, credential management) - **Key Components**: vault-manager.js, credential-reader.js, credential-switcher-macos.js - **Flow**: Login → Encrypt → Store in vault → Decrypt on use → Sync to instance → Execute - **Complexity**: 6 steps, encryption overhead 50-100ms ### v3.0 Architecture (Current) - **Total LOC**: ~1,100 (600 lines deleted) - **Deleted Files**: vault-manager.js (250 lines), credential-reader.js (136 lines), credential-switcher-macos.js (129 lines) - **Flow**: Create instance → Login in instance → Execute - **Complexity**: 3 steps, no encryption overhead ## Core Components (v3.0) ### 1. Main Entry Point (`bin/ccs.js` - 300 lines) **Role**: Central orchestrator for all CCS operations **Key Functions**: - `execClaude(claudeCli, args, envVars)`: Unified spawn logic for all execution paths - `handleVersionCommand()`: Display version and installation info - `handleHelpCommand()`: Show usage information - `detectProfile(args)`: Smart profile detection from arguments - `main()`: Main entry point and routing logic **v3.0 Changes**: - Unified `execClaude()` supports optional `envVars` parameter for `CLAUDE_CONFIG_DIR` - Dual-path execution: settings-based (`--settings`) vs account-based (`CLAUDE_CONFIG_DIR`) - Auth command routing to AuthCommands class - Help text updated (`create` not `save`) **Architecture Flow**: ```javascript // Settings profile (glm, kimi) const expandedSettingsPath = getSettingsPath(profileInfo.name); execClaude(claudeCli, ['--settings', expandedSettingsPath, ...remainingArgs]); // Account profile (work, personal) - v3.0 const instancePath = instanceMgr.ensureInstance(profileInfo.name); registry.touchProfile(profileInfo.name); const envVars = { CLAUDE_CONFIG_DIR: instancePath }; execClaude(claudeCli, remainingArgs, envVars); ``` ### 2. Instance Manager (`bin/instance-manager.js` - 219 lines) **Role**: Manage isolated Claude CLI instances per profile **Key Functions**: - `ensureInstance(profileName)`: Lazy initialization, auto-create missing directories - `initializeInstance(profileName, instancePath)`: Create instance directory structure - `validateInstance(instancePath)`: Auto-fix missing subdirectories (migration support) - `deleteInstance(profileName)`: Clean removal of instance directory - `getInstancePath(profileName)`: Get instance directory path **v3.0 Simplification**: - **Removed**: `activateInstance()`, `syncCredentialsToInstance()` (no vault) - **Added**: Auto-create missing directories in `validateInstance()` (robustness) - **Changed**: No credential copying, Claude CLI manages credentials directly **Directory Structure Created**: ``` ~/.ccs/instances// ├── session-env/ # Claude sessions ├── todos/ # Per-profile todos ├── logs/ # Execution logs ├── file-history/ # File edits ├── shell-snapshots/ # Shell state ├── debug/ # Debug info ├── .anthropic/ # SDK config ├── commands/ # Custom commands (copied from ~/.claude/) └── skills/ # Custom skills (copied from ~/.claude/) ``` **Key Insight**: No `.credentials.json` synced - Claude CLI creates/manages it via standard login flow in isolated instance. ### 3. Profile Registry (`bin/profile-registry.js` - 227 lines) **Role**: Manage account profile metadata in `~/.ccs/profiles.json` **Key Functions**: - `createProfile(name, metadata)`: Create new profile with minimal schema - `getProfile(name)`: Retrieve profile metadata - `updateProfile(name, updates)`: Update profile fields - `deleteProfile(name)`: Remove profile - `touchProfile(name)`: Update `last_used` timestamp - `setDefaultProfile(name)`: Set default profile **v3.0 Schema (Minimal)**: ```json { "version": "2.0.0", "profiles": { "work": { "type": "account", "created": "2025-11-09T10:00:00.000Z", "last_used": "2025-11-09T15:30:00.000Z" } }, "default": "work" } ``` **Removed Fields**: - `vault`: No encrypted vault (credentials in instance) - `subscription`: Not needed (no credential reading) - `email`: Not needed (no credential reading) **Atomic Writes**: Uses temp file + rename for data integrity ### 4. Profile Detector (`bin/profile-detector.js` - ~150 lines estimated) **Role**: Determine profile type for routing decisions **Key Functions**: - `detectProfileType(profileName)`: Determine if settings-based or account-based - Priority: Settings profiles first (backward compat), then account profiles - Returns: `{type: 'settings'|'account', name: string}` or throws error **Detection Logic**: ```javascript // 1. Check settings-based profiles (config.json) if (config.profiles[profileName]) { return { type: 'settings', settingsPath: config.profiles[profileName] }; } // 2. Check account-based profiles (profiles.json) if (registry.hasProfile(profileName)) { return { type: 'account', name: profileName }; } // 3. Error with available profiles throw new Error(`Profile not found: ${profileName}`); ``` ### 5. Auth Commands (`bin/auth-commands.js` - 406 lines) **Role**: Handle `ccs auth` subcommands for multi-account management **Key Functions**: - `handleCreate(args)`: Create profile and prompt for login (v3.0) - `handleList(args)`: List all profiles with metadata - `handleShow(args)`: Show profile details - `handleRemove(args)`: Remove profile and instance - `handleDefault(args)`: Set default profile - `showHelp()`: Display auth command help **v3.0 Changes**: - **Renamed**: `save` → `create` (better reflects action) - **New Flow**: Spawn Claude CLI in isolated instance, auto-prompts for login - **Removed**: Vault encryption, credential reading logic - **Deprecated Handlers**: `save` redirects to `create`, `current`/`cleanup` show removal notice **Profile Creation Flow (v3.0)**: ```javascript // 1. Create instance directory const instancePath = instanceMgr.ensureInstance(profileName); // 2. Create/update profile entry registry.createProfile(profileName, { type: 'account' }); // 3. Spawn Claude CLI in isolated instance (auto-prompts login) const child = spawn(claudeCli, [], { stdio: 'inherit', env: { ...process.env, CLAUDE_CONFIG_DIR: instancePath } }); // 4. Claude CLI detects no credentials, prompts OAuth login // 5. Credentials stored in instance/.anthropic/ by Claude CLI ``` ### 6. Configuration Manager (`bin/config-manager.js` - 73 lines) **Role**: Manage settings-based profile configuration (glm, kimi) **Key Functions**: - `getConfigPath()`: Resolve config file path (supports `CCS_CONFIG` override) - `readConfig()`: Parse config.json - `getSettingsPath(profile)`: Get settings file path for profile - `expandPath(pathStr)`: Expand tilde and environment variables **v3.0 Status**: Unchanged (backward compatible for settings profiles) **Config Format**: ```json { "profiles": { "glm": "~/.ccs/glm.settings.json", "kimi": "~/.ccs/kimi.settings.json", "default": "~/.claude/settings.json" } } ``` ### 7. Claude Detector (`bin/claude-detector.js` - 72 lines) **Role**: Locate Claude CLI executable **Key Functions**: - `detectClaudeCli()`: Find Claude CLI in PATH or custom location - `showClaudeNotFoundError()`: Display helpful error when Claude CLI missing **Detection Priority**: 1. `CCS_CLAUDE_PATH` environment variable 2. System PATH lookup (platform-specific: `which` on Unix, `where.exe` on Windows) 3. Return null if not found **v3.0 Status**: Unchanged ### 8. Helpers Module (`bin/helpers.js` - 48 lines) **Role**: Utility functions **Key Functions**: - `colored(text, color)`: TTY-aware color formatting - `expandPath(pathStr)`: Path expansion with tilde and env vars - `error(message)`: Simple error reporting **v3.0 Status**: Unchanged (already simplified in v2.x) ## Deleted Components (v3.0) ### 1. Vault Manager (`bin/vault-manager.js` - 191 lines) ❌ DELETED **Former Role**: Encrypt/decrypt credentials with AES-256-GCM **Why Deleted**: - Login-per-profile model makes vault unnecessary - Claude CLI manages credentials directly in instance directory - Eliminates PBKDF2 key derivation overhead (50-100ms) - Simplifies mental model (no abstract "vault" concept) ### 2. Credential Reader (`bin/credential-reader.js` - 136 lines) ❌ DELETED **Former Role**: Read credentials from `~/.claude/.credentials.json` **Why Deleted**: - No credential reading needed in v3.0 - Users login interactively via Claude CLI - Profile schema no longer stores `subscription` or `email` ### 3. Credential Switcher macOS (`bin/credential-switcher-macos.js` - 129 lines) ❌ DELETED **Former Role**: macOS-specific credential switching with file locking **Why Deleted**: - `CLAUDE_CONFIG_DIR` now works on macOS (platform parity achieved) - No need for platform-specific credential replacement - File locking unnecessary (isolated instances prevent conflicts) ## File Structure (v3.0) ``` bin/ ├── ccs.js # Main entry (300 lines) ├── config-manager.js # Settings config (73 lines) ├── claude-detector.js # CLI detection (72 lines) ├── instance-manager.js # Instance lifecycle (219 lines) - v3.0 simplified ├── profile-detector.js # Profile routing (150 lines est.) ├── profile-registry.js # Metadata management (227 lines) - v3.0 schema ├── auth-commands.js # Auth CLI (406 lines) - v3.0 create flow └── helpers.js # Utilities (48 lines) DELETED (v3.0): ❌ bin/vault-manager.js (191 lines) ❌ bin/credential-reader.js (136 lines) ❌ bin/credential-switcher-macos.js (129 lines) scripts/ ├── postinstall.js # npm auto-config ├── sync-version.js # Version management └── check-executables.js # Validation config/ ├── config.example.json # Settings template ├── base-glm.settings.json └── base-kimi.settings.json tests/ ├── shared/unit/ │ ├── helpers.test.js │ └── instance-manager.test.js ├── npm/ │ ├── cli.test.js │ ├── cross-platform.test.js │ └── integration/ │ └── concurrent-sessions.test.js └── manual/ └── test-concurrent-sessions.md ``` ## Data Flow (v3.0) ### Settings Profile Execution (glm, kimi) ``` User: ccs glm "task" ↓ ccs.js: detectProfile() → "glm" ↓ ProfileDetector: detectProfileType("glm") → {type: 'settings'} ↓ ConfigManager: getSettingsPath("glm") → "~/.ccs/glm.settings.json" ↓ ccs.js: execClaude(claude, ['--settings', path, 'task']) ↓ Claude CLI: Reads settings, executes with GLM API ``` ### Account Profile Execution (work, personal) - v3.0 ``` User: ccs work "task" ↓ ccs.js: detectProfile() → "work" ↓ ProfileDetector: detectProfileType("work") → {type: 'account'} ↓ InstanceManager: ensureInstance("work") → "~/.ccs/instances/work/" ├─ Create directories if missing (lazy init) └─ Auto-fix missing subdirectories (validateInstance) ↓ ProfileRegistry: touchProfile("work") → Update last_used ↓ ccs.js: execClaude(claude, ['task'], {CLAUDE_CONFIG_DIR: instancePath}) ↓ Claude CLI: Reads credentials from instance/.anthropic/, executes ``` ### Profile Creation Flow (v3.0) ``` User: ccs auth create work ↓ AuthCommands: handleCreate(["work"]) ↓ InstanceManager: ensureInstance("work") → Create directory structure ↓ ProfileRegistry: createProfile("work", {type: 'account'}) ↓ AuthCommands: spawn(claude, [], {CLAUDE_CONFIG_DIR: instancePath}) ↓ Claude CLI: Detects no credentials, prompts OAuth login ↓ User: Completes login in browser ↓ Claude CLI: Stores credentials in instance/.anthropic/ ↓ Profile ready for use ``` ## Key Simplifications (v3.0) ### 1. Vault Removal **Before (v2.x)**: - Encrypt credentials with AES-256-GCM - PBKDF2 key derivation (100k iterations, 50-100ms) - Store in `~/.ccs/accounts/.json.enc` - Decrypt on each activation - Copy to instance/.credentials.json **After (v3.0)**: - Users login directly via Claude CLI - Credentials stored by Claude CLI in instance/.anthropic/ - No encryption/decryption overhead - No credential copying **Benefits**: 50-100ms faster activation, simpler mental model, easier debugging ### 2. Login-Per-Profile Model **Before (v2.x)**: ```bash # Login once globally claude /login # Save credentials to encrypted vault ccs auth save work # Decrypt and copy on each use ccs work "task" ``` **After (v3.0)**: ```bash # Create profile (prompts login) ccs auth create work # Opens Claude, auto-prompts OAuth # Use directly (credentials already in instance) ccs work "task" ``` **Benefits**: Intuitive flow, matches Claude CLI UX, no abstraction layers ### 3. Auto-Directory Creation **Before (v2.x)**: - `initializeInstance()` required before use - Error if directories missing - Manual intervention needed for migration **After (v3.0)**: - `validateInstance()` auto-creates missing directories - Seamless migration from older versions - Robust against partial instance corruption ### 4. Platform Parity **Before (v2.x)**: - macOS: credential-switcher-macos.js (file locking, credential replacement) - Linux/Windows: CLAUDE_CONFIG_DIR env var - Different code paths, different behaviors **After (v3.0)**: - All platforms: CLAUDE_CONFIG_DIR env var - Unified code path in execClaude() - Consistent behavior everywhere ## Breaking Changes (v2.x → v3.0) ### Command Changes - `ccs auth save ` → `ccs auth create ` - `ccs auth current` → Removed (use `ccs auth list`) - `ccs auth cleanup` → Removed (no vault to cleanup) ### Profile Schema Changes ```json // v2.x schema { "type": "account", "vault": "~/.ccs/accounts/work.json.enc", "subscription": "pro", "email": "user@work.com", "created": "...", "last_used": "..." } // v3.0 schema (minimal) { "type": "account", "created": "...", "last_used": "..." } ``` ### Migration Path Users must recreate profiles: ```bash # 1. List old profiles ccs auth list # 2. Recreate with v3.0 ccs auth create work # Login when prompted ccs auth create personal # Login when prompted # 3. Old vault files can be deleted rm -rf ~/.ccs/accounts/ ``` ## Testing Coverage ### Unit Tests - `tests/shared/unit/helpers.test.js`: Utility functions - `tests/shared/unit/instance-manager.test.js`: Instance lifecycle (v3.0 updated) ### Integration Tests - `tests/npm/cli.test.js`: End-to-end CLI functionality - `tests/npm/cross-platform.test.js`: Platform-specific behavior - `tests/npm/integration/concurrent-sessions.test.js`: Multi-profile execution ### Manual Testing - `tests/manual/test-concurrent-sessions.md`: Concurrent session validation - `TEST-V3.md`: Comprehensive v3.0 test guide ## Performance Characteristics (v3.0) ### Profile Creation - Instance directory creation: ~5-10ms - Copy global configs (if exist): ~10-20ms - Login prompt (interactive): user-dependent - **Total overhead**: ~15-30ms (excluding login) ### Profile Activation - Instance validation: ~5ms - `CLAUDE_CONFIG_DIR` env var: ~1ms - Claude CLI spawn: ~20-30ms (Node.js overhead) - **Total overhead**: ~26-36ms - **v2.x overhead**: ~76-136ms (included decryption) - **Improvement**: ~50-100ms faster (60-75% reduction) ### Memory Footprint - Instance Manager: ~2 KB - Profile Registry: ~2 KB - Profile Detector: ~1 KB - **Total overhead**: ~5 KB (vs ~10 KB in v2.x due to vault crypto) ## Security Considerations (v3.0) ### Credential Storage - **Location**: Instance directory (`~/.ccs/instances//.anthropic/`) - **Management**: Claude CLI standard mechanisms - **Permissions**: Inherited from Claude CLI (typically 0600) - **Encryption**: Handled by Claude CLI (if applicable) ### Removed Attack Vectors (v3.0) - No custom encryption implementation (fewer crypto bugs) - No key derivation code (no PBKDF2 vulnerabilities) - No credential reading/parsing (no credential leak risks) ### Remaining Security Controls - File existence validation (prevent path traversal) - Spawn with array arguments (no shell injection) - Instance directory permissions (0700, owner only) - Atomic file writes (temp + rename, prevents corruption) ## Future Extensibility ### Extension Points (v3.0) 1. **New Profile Types**: Easy via ProfileDetector routing 2. **Instance Cleanup**: Add auto-rotation policies for sessions/logs 3. **PID Locking**: Prevent same-profile concurrent access 4. **Migration Tools**: Auto-migrate v2.x vaults to v3.0 instances 5. **Enhanced Validation**: Credential health checks ### Architectural Guarantees - **Backward Compatibility**: Settings profiles (glm, kimi) unchanged - **Performance**: Lazy init minimizes overhead - **Maintainability**: Fewer files, clearer separation of concerns - **Reliability**: Auto-fix missing directories reduces failure modes ## Summary **CCS v3.0 Evolution**: - **Code Reduction**: 600 lines deleted (40% from v2.x) - **Performance**: 50-100ms faster activation - **Simplicity**: 6 steps → 3 steps (50% reduction) - **Platform Parity**: Unified behavior across all platforms **Key Achievements**: - ✅ Vault removal eliminates encryption complexity - ✅ Login-per-profile matches Claude CLI UX - ✅ Auto-directory creation improves robustness - ✅ Platform parity simplifies maintenance - ✅ Minimal schema reduces metadata overhead **Design Principles Maintained**: - **YAGNI**: Lazy instance init, only create when needed - **KISS**: Simple dual-path routing, no abstraction layers - **DRY**: Unified spawn logic, single source of truth per concern v3.0 demonstrates how architectural simplification can remove substantial code while improving performance, maintainability, and user experience. The login-per-profile model provides a sustainable foundation for future enhancements.