This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Environment Switcher is a Swift-based CLI tool for managing environment-specific configuration files. It allows users to switch between different environments (local, staging, production, etc.) by swapping out configuration files like .env, config.json, etc.
# Debug build
swift build
# Release build
swift build -c release
# Run the binary after building
.build/release/switch <command># Run all tests
swift test
# Build for testing without running
swift build --build-tests# Run directly with swift run
swift run switch <command>
# Example: Run init command
swift run switch init
# Example: Run status command
swift run switch statusThe CLI is built using Swift ArgumentParser with a root command (EnvironmentSwitcher in main.swift) and subcommands:
InitCommand- Creates.switchrcproject configurationStatusCommand- Displays current environment and file statesConfigCommand- Creates global configuration at~/.config/switch/.switchrcSwitchCommand- Switches between environments
Important: The main.swift file includes custom fallback logic:
- If no subcommand is provided, it runs
StatusCommand - If a single argument is provided that matches an environment name, it automatically runs
SwitchCommandwith that environment (e.g.,switch productionworks without thetosubcommand)
There are two separate configuration systems:
-
Project Config (
.switchrcin project directory)- Managed by
ConfigService(singleton) - Model:
Configstruct - Contains:
current_environment,environments,default_files - Location: Current working directory
- Managed by
-
Global Config (
~/.config/switch/.switchrc)- Managed by
GlobalConfigService(singleton) - Model:
GlobalConfigstruct - Contains:
default_environments,default_files - Used for defaults when running
switch init - Falls back to hardcoded defaults if file doesn't exist
- Managed by
Key difference: ConfigService.shared.config requires a project .switchrc to exist and will exit with an error if not found. GlobalConfigService.shared.config returns default values if the global config doesn't exist.
Files are organized as:
- Active file:
<filename>(e.g.,.env) - Environment-specific file:
<filename>.<environment>(e.g.,.env.production) - Backup file:
<filename>.backup(created during switching)
The getFileEnvironmentPath() helper in FileHelper.swift constructs environment-specific paths.
The Config.getFiles() method merges files from two sources:
default_files- Files that apply to all environmentsenvironment.files- Additional files specific to the current environment
This supports three configuration patterns:
- Default files only: All environments use the same file list from
default_files, withenvironment.filesbeing empty arrays - Per-environment files: Each environment defines its own
filesarray, nodefault_files - Mixed mode: Combination of both, where
default_filesare used plus environment-specific additions
Important: The method uses static variables for caching and invalidates when current_environment changes.
The FileHelper.swift module uses SHA-256 hashing to detect file changes:
sha256()- Computes hash of a filegetFileStatus()- Compares active file hash with environment-specific file hash- Returns
FileStatusenum:.original,.modified, or.notFound
This allows the status command to show if files have been edited since switching environments.
The ConsoleHelper.swift module provides formatted output using Rainbow for colors:
printDotLine()- Prints label and value separated by dots (fixed width: 146 chars)printUpdatableDotLine()- Same as above but can update in place (for progress indicators)printTitle()- Prints colored badge with title (INFO, ERROR, WARNING, SUCCESS)
Colors are applied throughout commands for better UX:
.cyan- User prompts and important text.dim- Secondary information.green- Success states.yellow- Modified files.red- Errors and missing files
The String+Formatting.swift file provides conditional styling:
colorIf()- Apply color only if condition is truestyleIf()- Apply style only if condition is truewithoutANSI- Property that strips ANSI codes (used for length calculations in dot lines)
These are used heavily in status displays to conditionally color file states.
Both ConfigService and GlobalConfigService are singletons that load config on first access. If project config is missing, the app exits immediately. This means:
- Commands that require
.switchrc(status, switch) will fail beforerun()is called InitCommandexplicitly checksConfigService.configExists()before trying to access the singleton
InitCommand includes sophisticated interactive workflows:
- Asks for environments (comma-separated, uses global config defaults)
- Asks for files to manage (comma-separated, uses global config defaults)
- Offers to create/update
.gitignorewith necessary entries - Offers to auto-create all environment-specific files
When creating files:
- If original file exists, copies content to environment files
- If original doesn't exist, creates it with TODO comment
- Skips files that already exist
When switching environments (SwitchCommand):
- Checks if already on target environment (warns and exits)
- Backs up current active files to
.backup - Copies environment-specific files to active location
- Updates
current_environmentin.switchrc - Shows progress with updatable dot lines
When adding new commands or modifying existing ones:
- Commands should work with both project and global configs
- Interactive prompts should accept empty input to use defaults
- File operations should handle missing files gracefully
- The fallback logic in
main.swiftmay intercept arguments before your command runs
Sources/
├── Commands/ # ArgumentParser command implementations
├── Models/ # Data models (Config, GlobalConfig, Environment)
├── Services/ # Singleton services for config management
├── Helpers/ # Utility functions (file operations, console output)
├── Enums/ # Simple enums (FileStatus, BadgeType)
├── Errors/ # Custom error types
├── Extensions/ # Swift extensions (String, FileManager)
└── main.swift # Entry point with custom argument handling
- swift-argument-parser (1.6.1+) - CLI command structure
- Rainbow (4.0.0+) - Terminal color output
main- Main development branchv2.x- Current development branch for v2 rewrite
When creating PRs, target main unless working on v2-specific features.