A state-free Bash CLI tool for managing multiple Claude Code configurations.
- Bash ≥ 4.0
- coreutils (standard Unix utilities)
- Clone or download the ccsw project
- Place the
bin/ccswexecutable in your PATH:
# Copy to a directory in your PATH
cp ccsw/bin/ccsw /usr/local/bin/
# Or make it executable and add to PATH
chmod +x ccsw/bin/ccsw
export PATH="$PATH:/path/to/ccsw/bin"List all available profiles sorted alphabetically.
$ ccsw list
profile1
profile2
my-profile
work-configSwitch to a profile by outputting an export statement for eval.
$ ccsw use my-profile
export CLAUDE_CONFIG_DIR=/home/user/.config/ccsw/configs/my-profile
# Use with eval to switch profiles
$ eval "$(ccsw use my-profile)"
$ ccsw current
my-profileShow the currently active profile from CLAUDE_CONFIG_DIR.
$ ccsw current
my-profile
# When no profile is active
$ ccsw current
No active profile
# When CLAUDE_CONFIG_DIR points to external directory
$ ccsw current
External: /path/to/external/directory
WARN: CLAUDE_CONFIG_DIR points to external directory: /path/to/external/directoryDelete a profile directory with safety guards.
$ ccsw delete old-profile
$ ccsw delete my-profile
ERROR: Cannot delete active profile: my-profile| Exit Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Profile not found or general error |
| 2 | Cannot delete active profile (safety guard) |
| 3 | CLAUDE_CONFIG_DIR points to external directory |
CLAUDE_CONFIG_DIR: Set automatically when usingccsw useCCSW_CONFIG_DIR: Override default config directory (default:~/.config/ccsw)CCSW_PROFILES_DIR: Override default profiles directory (default:$CCSW_CONFIG_DIR/configs)
ccsw is designed to be state-free - it doesn't write any configuration files. Instead, it outputs environment variables that you can use with eval:
# Switch to a profile
$ eval "$(ccsw use work)"
$ echo $CLAUDE_CONFIG_DIR
/home/user/.config/ccsw/configs/work
# The profile switch only affects the current shell session
$ # Open a new terminal
$ ccsw current
No active profileThis makes ccsw safe to use and ensures that profile changes don't persist accidentally.
# List all profiles
ccsw list
# Switch to work profile
eval "$(ccsw use work)"
# Check current profile
ccsw current
# Switch back to personal profile
eval "$(ccsw use personal)"Add this to your .bashrc or .zshrc for easy profile switching:
# Function to switch to a profile
ccsw() {
/path/to/ccsw/bin/ccsw "$@"
}
# Quick profile switch
alias cwork='eval "$(ccsw use work)"'
alias cpersonal='eval "$(ccsw use personal)"'#!/bin/bash
# Switch to test profile for running tests
eval "$(ccsw use test)"
./run-tests
# Switch back to default
eval "$(ccsw use default)"$ ccsw use nonexistent
ERROR: Profile not found: nonexistent- Check the profile name with
ccsw list - Ensure the profile directory exists in
~/.config/ccsw/configs/
$ ccsw delete current-profile
ERROR: Cannot delete active profile: current-profile- Switch to a different profile first:
eval "$(ccsw use other-profile)" - Or unset the environment variable:
unset CLAUDE_CONFIG_DIR
$ ccsw current
External: /some/other/path
WARN: CLAUDE_CONFIG_DIR points to external directory: /some/other/path- This warning appears when
CLAUDE_CONFIG_DIRis set but doesn't point to a ccsw-managed profile - Use
unset CLAUDE_CONFIG_DIRto clear the current profile
All commands execute within 100ms on modern systems. Profile operations are instantaneous as no file I/O is performed.
ccsw/
├── bin/ccsw # Main CLI executable
├── lib/
│ ├── utils.sh # Utility functions
│ └── core.sh # Core CRUD functions
├── tests/ # Unit tests
└── README.md # This file
- Follow the bash-defensive-patterns guidelines
- All scripts must pass shellcheck with zero errors
- Maintain state-free design principles
- Add appropriate error handling and exit codes
The project uses Bats (Bash Automated Testing System) for unit testing.
# Install Bats (Ubuntu/Debian)
sudo apt install bats
# Or via GitHub
git clone https://github.com/bats-core/bats-core.git
cd bats-core
sudo ./install.sh /usr/local# Run all unit tests
bats tests/
# Run specific test file
bats tests/test_core.bats
bats tests/test_utils.bats
# Run with verbose output
bats -p tests/
# Run specific test by name
bats -f "ccsw_list" tests/Manual integration testing scripts are available in the scripts/ directory:
# Run simple integration tests
./scripts/integration_test_simple.sh
# Run manual integration tests
./scripts/manual_integration_test.sh
# Run full integration test suite
./scripts/test_integration.shAll shell scripts should pass shellcheck with zero errors:
# Check all shell scripts
shellcheck -x bin/ccsw lib/*.sh scripts/*.sh
# Check specific file
shellcheck -x bin/ccswVerify that all files conform to the EditorConfig settings:
# Install editorconfig-checker (if not already installed)
go install github.com/editorconfig-checker/editorconfig-checker/cmd/editorconfig-checker@latest
# Or via npm
npm install -g editorconfig-checker
# Check all files
editorconfig-checker
# Check specific directory
editorconfig-checker bin/
# Check specific file
editorconfig-checker bin/ccswFor quick manual verification of state-free behavior:
# Create isolated test environment
(
export CCSW_CONFIG_DIR=$(mktemp -d)
export CCSW_PROFILES_DIR="$CCSW_CONFIG_DIR/configs"
mkdir -p "$CCSW_PROFILES_DIR"
# Create test profile
mkdir -p "$CCSW_PROFILES_DIR/test"
# Test switching (requires subshell for isolation)
eval "$(bin/ccsw use test)" && echo "Active: $(bin/ccsw current)"
# Cleanup happens automatically when subshell exits
)