https://github.com/diranged/claude-profile
Run Claude Code ... But with Profiles!
https://github.com/diranged/claude-profile
Last synced: about 2 months ago
JSON representation
Run Claude Code ... But with Profiles!
- Host: GitHub
- URL: https://github.com/diranged/claude-profile
- Owner: diranged
- License: apache-2.0
- Created: 2026-04-03T20:50:58.000Z (3 months ago)
- Default Branch: main
- Last Pushed: 2026-04-13T09:33:21.000Z (2 months ago)
- Last Synced: 2026-04-13T11:28:42.224Z (2 months ago)
- Language: Go
- Size: 2.11 MB
- Stars: 1
- Watchers: 0
- Forks: 0
- Open Issues: 1
-
Metadata Files:
- Readme: README.md
- License: LICENSE
- Security: docs/SECURITY.md
Awesome Lists containing this project
README
# Claude Profile
**Claude Code... but with Profiles.**
A transparent wrapper around [Claude Code](https://docs.anthropic.com/en/docs/claude-code) that enables multiple subscription profiles. Each profile gets its own isolated config directory and macOS keychain entry, allowing concurrent sessions across different Claude subscriptions (e.g., work and personal).
## How It Works
Claude Profile leverages Claude Code's built-in `CLAUDE_CONFIG_DIR` environment variable. When set, Claude Code automatically hashes the directory path (SHA-256) into its macOS keychain service name, producing a unique credential store per profile. No patching or hacking required -- it uses official, documented behavior.
```
Default keychain entry: "Claude Code-credentials"
Profile keychain entry: "Claude Code-credentials-"
```
Each profile is a directory under `~/.claude-profiles//` containing:
- `config/` -- used as `CLAUDE_CONFIG_DIR` (Claude's settings, credentials, sessions)
- `claude-profile.yaml` -- profile-specific metadata (color code)
## Installation
### Quick Install (Recommended)
```bash
curl -fsSL https://raw.githubusercontent.com/diranged/claude-profile/main/install.sh | sh
```
This detects your OS and architecture, downloads the latest release, verifies the SHA-256 checksum, and installs to `/usr/local/bin`.
To install a specific version or to a custom directory:
```bash
# Pin a version
curl -fsSL https://raw.githubusercontent.com/diranged/claude-profile/main/install.sh | VERSION=v0.1.0 sh
# Custom install directory
curl -fsSL https://raw.githubusercontent.com/diranged/claude-profile/main/install.sh | INSTALL_DIR=~/.local/bin sh
```
### From GitHub Releases
Download a prebuilt binary from the [Releases](https://github.com/diranged/claude-profile/releases) page. Binaries are available for Linux, macOS, and Windows on both amd64 and arm64.
### From Source
Requires Go 1.25+:
```bash
git clone https://github.com/diranged/claude-profile.git
cd claude-profile
make install # Builds and copies to $GOPATH/bin
```
### From Go
```bash
go install github.com/diranged/claude-profile-go/cmd/main.go@latest
```
## Quick Start
1. **Create a profile:**
```bash
claude-profile create work
```
The interactive wizard will:
- Create the isolated config directory
- Offer to copy your existing `~/.claude` config files (CLAUDE.md, settings.json)
- Let you pick a banner/statusline color
- Configure the Claude Code statusline automatically
2. **Authenticate:**
```bash
# OAuth (interactive)
claude-profile -P work auth login
# SSO
claude-profile -P work auth login --sso
# Or launch Claude and use /login inside the REPL
claude-profile -P work
```
3. **Use it as a drop-in replacement for `claude`:**
```bash
claude-profile -P work
claude-profile -P work "explain this code"
claude-profile -P personal --model opus
```
4. **Use an environment variable instead of `-p`:**
```bash
export CLAUDE_PROFILE=work
claude-profile "explain this code"
```
## Shell Aliases
Once your profiles are set up, shell aliases make switching effortless. Add these to your `~/.zshrc` or `~/.bashrc`:
```bash
# Personal Claude — just type "myclaude"
alias myclaude='claude-profile -P personal'
# Work Claude with a shared project config directory
alias workclaude='claude-profile -P work --add-dir ~/git/work/common-claude'
# Quick one-shot questions against different profiles
alias askwork='claude-profile -P work -p'
alias askpersonal='claude-profile -P personal -p'
```
You can pass any Claude flags through — the alias is just a shortcut for the profile selection:
```bash
myclaude # Interactive REPL
myclaude "explain this function" # One-shot question
workclaude --model opus -c "run tests" # Specific model + command
workclaude auth login --sso # Re-authenticate
```
This pairs well with `CLAUDE_PROFILE` for scripts:
```bash
# In a work-specific script or .envrc:
export CLAUDE_PROFILE=work
claude-profile "summarize the recent changes"
```
## Command Reference
### `claude-profile create `
Interactive wizard that creates a new profile. Steps through config bootstrapping, color selection, and statusline setup.
```bash
claude-profile create work
claude-profile create personal
```
### `claude-profile list`
Lists all profiles with their authentication status.
```bash
$ claude-profile list
work (keychain)
personal (file)
experiment (none)
```
Auth status is one of:
- **keychain** -- OAuth credentials stored in macOS Keychain
- **file** -- credentials stored in `.credentials.json` (plaintext fallback)
- **none** -- no credentials found
### `claude-profile show `
Displays detailed information about a profile.
```bash
$ claude-profile show work
Profile: work
Config dir: /Users/you/.claude-profiles/work/config
Keychain service: Claude Code-credentials-6061db4b
Auth: keychain
Subscription: pro
Rate limit tier: t3
Expires: 2025-01-15T12:00:00Z
Scopes: user:inference, user:read
```
### `claude-profile delete `
Removes a profile's directory and its macOS keychain entry. Prompts for confirmation by default.
```bash
claude-profile delete old-profile
claude-profile delete old-profile --force # Skip confirmation
```
### `claude-profile sessions`
Lists all Claude Code sessions across every repository, grouped by directory. This solves a common pain point: when you work across many repos and create sessions frequently, it's hard to remember which repo a particular session lives in.
```bash
# List sessions from the last 7 days (default)
$ claude-profile -P me sessions
SESSIONS (21 sessions across 8 repos)
=== /Users/you/git/myorg/api-service ===
abc12345 2026-04-15 14:30 [main] fix the flaky integration test in auth middleware
def67890 2026-04-14 09:15 [feature/oauth] add OAuth2 PKCE flow to the login endpoint
=== /Users/you/git/myorg/frontend ===
11122233 2026-04-15 11:00 [main] why is the bundle size 2MB larger after the last merge?
=== /Users/you/git/personal/blog ===
44455566 2026-04-13 20:45 [main] write a post about Claude Code profiles
```
**Flags:**
| Flag | Default | Description |
|---|---|---|
| `--since` | `7d` | Time window — supports `Nd` (days), `Nh` (hours), `Nm` (minutes) |
| `--repo` | | Case-insensitive substring filter on the repo path |
```bash
# Last 30 days
claude-profile -P me sessions --since 30d
# Only sessions in repos matching "sproutbook"
claude-profile -P me sessions --repo sproutbook
# Combine filters
claude-profile -P me sessions --since 14d --repo api
```
Each line shows:
- **Session ID** (first 8 characters) — use this with `--resume`
- **Last modified timestamp**
- **Git branch** at the time the session was created
- **First prompt** — truncated to help you identify the session's purpose
### `--resume` Directory Safety Check
When you resume a session with `claude-profile -P --resume `, claude-profile verifies that your current working directory matches where the session was originally started. This prevents the common mistake of resuming a session from the wrong repo, which leads to Claude operating on the wrong codebase with stale context.
**Wrong directory — you get a helpful error:**
```
$ pwd
/Users/you/git/myorg/frontend
$ claude-profile -P me --resume abc12345
✗ Session abc12345 was started in a different directory.
Session cwd: /Users/you/git/myorg/api-service
Current cwd: /Users/you/git/myorg/frontend
Branch: main
First prompt: fix the flaky integration test in auth middleware
To resume, cd to the correct directory:
cd /Users/you/git/myorg/api-service && claude-profile -P me --resume abc12345
```
**Right directory — passes through to Claude normally:**
```
$ cd /Users/you/git/myorg/api-service
$ claude-profile -P me --resume abc12345
╭── Claude Profile v0.2.0 ──────────────────╮
│ Profile: me │
│ ... │
╰───────────────────────────────────────────╯
```
**Ambiguous session ID prefix:**
```
$ claude-profile -P me --resume abc
✗ Session prefix "abc" matches multiple sessions:
abc12345 /Users/you/git/myorg/api-service main 2026-04-15 14:30
abc99999 /Users/you/git/personal/blog main 2026-04-13 20:45
```
**Bare `--resume` (no ID):**
When you pass `--resume` without a session ID, Claude Code shows its built-in session picker for the current directory. This passes through untouched.
#### Typical Workflow
1. **Find your session** — you remember working on something but not which repo:
```bash
claude-profile -P me sessions --repo api
```
2. **Spot the session** — `abc12345` with prompt "fix the flaky integration test"
3. **Resume it** — claude-profile tells you if you need to `cd` first:
```bash
claude-profile -P me --resume abc12345
```
### Passthrough Mode (Default)
When no subcommand matches, all arguments are forwarded to the real `claude` binary. This is the primary usage mode -- claude-profile acts as a transparent wrapper.
```bash
# These all pass through to claude:
claude-profile -P work
claude-profile -P work "explain this function"
claude-profile -P work --model opus -c "run tests"
claude-profile -P work auth login
claude-profile -P work auth login --sso
```
The `-p`/`--profile` flag (and `--profile=value` / `-pvalue` forms) is stripped before forwarding. All other flags and arguments pass through untouched. Claude Profile acts as a transparent wrapper.
### `claude-profile statusline [-- command args...]`
Acts as a Claude Code statusline provider. Prints a colored line showing the active profile name, auth method, and subscription type. Optionally chains to another statusline command.
```bash
# Standalone
claude-profile statusline
# Chaining with another statusline tool
claude-profile statusline -- bunx -y ccstatusline@latest
```
This is configured automatically by the `create` wizard in the profile's `settings.json`:
```json
{
"statusLine": {
"type": "command",
"command": "/path/to/claude-profile statusline",
"padding": 0
}
}
```
If an existing statusline command is detected during creation, it is preserved by chaining:
```json
{
"statusLine": {
"type": "command",
"command": "/path/to/claude-profile statusline -- bunx -y ccstatusline@latest",
"padding": 0
}
}
```
## Credential Isolation
Profile isolation relies on Claude Code's own keychain hashing behavior:
1. claude-profile sets `CLAUDE_CONFIG_DIR` to `~/.claude-profiles//config`
2. Claude Code computes `SHA-256(CLAUDE_CONFIG_DIR)` and takes the first 8 hex characters
3. The keychain service name becomes `Claude Code-credentials-`
4. Each profile gets a completely independent credential store
This matches Claude Code's internal `V51()` function. The hash is deterministic -- the same config directory always produces the same keychain entry.
**Example:**
```
Config dir: /Users/you/.claude-profiles/work/config
SHA-256: 6061db4b...
Keychain: Claude Code-credentials-6061db4b
```
## Statusline Integration
The statusline command reads profile info from environment variables set at launch time:
| Variable | Description |
|---|---|
| `CLAUDE_PROFILE_NAME` | Active profile name |
| `CLAUDE_PROFILE_AUTH` | Auth status (keychain/file/none) |
| `CLAUDE_PROFILE_SUB` | Subscription type (pro/max/free/unknown) |
| `CLAUDE_PROFILE_COLOR` | ANSI 256-color code for the profile |
These are injected into the Claude process environment by the passthrough handler, making them available to the statusline command when Claude Code invokes it.
## Color Customization
Each profile has an ANSI 256-color code used for the launch banner and statusline text. The `create` wizard offers these presets:
| Color | Name | Code |
|---|---|---|
|  | Green (default) | 108 |
|  | Blue | 33 |
|  | Orange | 208 |
|  | Pink | 204 |
|  | Cyan | 51 |
|  | Red | 196 |
|  | Purple | 141 |
|  | Yellow | 226 |
| | Custom | 0-255 |
The color is stored in `claude-profile.yaml` inside the profile directory and can be edited directly:
```yaml
color: 204
```
## Authentication Methods
Claude Profile does not handle authentication itself. It sets up the isolated environment and then delegates to Claude Code's built-in auth mechanisms.
### OAuth (Claude Subscription)
```bash
claude-profile -P work auth login
# Or inside Claude's REPL: /login
```
Credentials are stored in the macOS Keychain under a profile-specific service name.
### SSO (Enterprise)
```bash
claude-profile -P work auth login --sso
```
### API Key
```bash
ANTHROPIC_API_KEY=sk-ant-... claude-profile -P work
```
No keychain entry is created. The API key is passed through the environment.
### AWS Bedrock
```bash
CLAUDE_CODE_USE_BEDROCK=1 claude-profile -P work
```
Credentials come from AWS environment variables or IAM roles. Claude Profile detects this and skips the keychain credential check.
### Google Vertex AI
```bash
CLAUDE_CODE_USE_VERTEX=1 claude-profile -P work
```
Credentials come from GCP environment. Claude Profile detects this and skips the keychain credential check.
## Environment Variables Reference
| Variable | Description |
|---|---|
| `CLAUDE_PROFILE` | Default profile name (alternative to `-p` flag) |
| `CLAUDE_PROFILES_DIR` | Override profiles base directory (default: `~/.claude-profiles`) |
| `CLAUDE_PROFILE_DEBUG` | Enable debug logging (set to any non-empty value) |
| `CLAUDE_CONFIG_DIR` | Set automatically by claude-profile per-profile |
| `CLAUDE_CODE_USE_BEDROCK` | Signals Bedrock auth; skips keychain check |
| `CLAUDE_CODE_USE_VERTEX` | Signals Vertex auth; skips keychain check |
| `ANTHROPIC_API_KEY` | Direct API key auth; skips keychain check |
| `CLAUDE_PROFILE_NAME` | Set in Claude's env for statusline use |
| `CLAUDE_PROFILE_AUTH` | Set in Claude's env for statusline use |
| `CLAUDE_PROFILE_SUB` | Set in Claude's env for statusline use |
| `CLAUDE_PROFILE_COLOR` | Set in Claude's env for statusline use |
## License
See [LICENSE](LICENSE) for details.