claude-profile 1.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of claude-profile might be problematic. Click here for more details.
- claude_profile-1.0.2/LICENSE +21 -0
- claude_profile-1.0.2/MANIFEST.in +2 -0
- claude_profile-1.0.2/PKG-INFO +185 -0
- claude_profile-1.0.2/README.md +151 -0
- claude_profile-1.0.2/RELEASING.md +72 -0
- claude_profile-1.0.2/claude_profile.egg-info/PKG-INFO +185 -0
- claude_profile-1.0.2/claude_profile.egg-info/SOURCES.txt +17 -0
- claude_profile-1.0.2/claude_profile.egg-info/dependency_links.txt +1 -0
- claude_profile-1.0.2/claude_profile.egg-info/entry_points.txt +2 -0
- claude_profile-1.0.2/claude_profile.egg-info/requires.txt +6 -0
- claude_profile-1.0.2/claude_profile.egg-info/top_level.txt +1 -0
- claude_profile-1.0.2/claudectl/__init__.py +3 -0
- claude_profile-1.0.2/claudectl/__main__.py +3 -0
- claude_profile-1.0.2/claudectl/cli.py +1897 -0
- claude_profile-1.0.2/pyproject.toml +62 -0
- claude_profile-1.0.2/scripts/claudectl_entry.py +6 -0
- claude_profile-1.0.2/scripts/demo.ps1 +88 -0
- claude_profile-1.0.2/setup.cfg +4 -0
- claude_profile-1.0.2/tests/test_claudectl.py +256 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 CloudOpsWorld and claude-profile contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: claude-profile
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: Per-customer profiles for Claude Code and Claude Desktop: separate logins, AI platforms, MCP servers, skills and history, side by side.
|
|
5
|
+
Author: claude-profile contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/CloudOpsWorld/claude-profile
|
|
8
|
+
Project-URL: Repository, https://github.com/CloudOpsWorld/claude-profile
|
|
9
|
+
Project-URL: Issues, https://github.com/CloudOpsWorld/claude-profile/issues
|
|
10
|
+
Keywords: claude,claude-code,claude-desktop,anthropic,profiles,mcp,deepseek,openrouter,cli
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
16
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Software Development
|
|
24
|
+
Classifier: Topic :: Utilities
|
|
25
|
+
Requires-Python: >=3.10
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=9.1.1; extra == "dev"
|
|
30
|
+
Requires-Dist: ruff>=0.15.21; extra == "dev"
|
|
31
|
+
Requires-Dist: mypy>=2.3.0; extra == "dev"
|
|
32
|
+
Requires-Dist: build>=1.5.1; extra == "dev"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# claudectl
|
|
36
|
+
|
|
37
|
+
Use Claude Code with a separate profile for each customer, on Windows, macOS and Linux. Each profile has its own:
|
|
38
|
+
|
|
39
|
+
- sign-in or API key
|
|
40
|
+
- AI platform
|
|
41
|
+
- MCP servers
|
|
42
|
+
- skills and plugins
|
|
43
|
+
- session history and memory
|
|
44
|
+
|
|
45
|
+
Customers can run side by side in separate terminals. Switching never touches a session that's already running, and one customer's Jira or Confluence server never shows up in another customer's session.
|
|
46
|
+
|
|
47
|
+
claudectl doesn't change anything machine-wide. Your normal `claude` and `~/.claude` keep working exactly as before, and appear as the `default` profile.
|
|
48
|
+
|
|
49
|
+
It's pure Python 3.10+ with no dependencies beyond the standard library.
|
|
50
|
+
|
|
51
|
+
## Install
|
|
52
|
+
|
|
53
|
+
From PyPI (the package is `claude-profile`, the command is `claudectl`):
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pipx install claude-profile # or: uv tool install claude-profile or: pip install claude-profile
|
|
57
|
+
claudectl install # optional: adds the "Claude Profiles" Start menu picker on Windows
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Without Python:** download a standalone binary from [Releases](https://github.com/CloudOpsWorld/claude-profile/releases) and run it once with `install`, which puts it in `~/.local/bin`:
|
|
61
|
+
- `claudectl-windows-amd64.exe`
|
|
62
|
+
- `claudectl-macos-arm64`
|
|
63
|
+
- `claudectl-linux-amd64`
|
|
64
|
+
|
|
65
|
+
Each release has `SHA256SUMS` and build provenance you can check with `gh attestation verify <file> --repo CloudOpsWorld/claude-profile`.
|
|
66
|
+
|
|
67
|
+
**From source:**
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
python claudectl/cli.py install
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
This copies the single file to `~/.claudectl/app` and puts a launcher in `~/.local/bin`.
|
|
74
|
+
|
|
75
|
+
To remove claudectl, run `claudectl uninstall` (or `pipx uninstall claude-profile`). Your profiles are kept.
|
|
76
|
+
|
|
77
|
+
## Daily use
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
claudectl add acme # guided: name, AI platform, key or sign-in, bind this folder
|
|
81
|
+
cd ~/work/acme-repo
|
|
82
|
+
claudectl # starts Claude Code as ACME, because the folder is bound
|
|
83
|
+
claudectl tab globex # new terminal tab locked to Globex
|
|
84
|
+
claudectl acme --resume # any claude arguments pass through
|
|
85
|
+
claudectl mcp add jira -- npx -y <jira-mcp> # goes into this folder's profile only
|
|
86
|
+
claudectl list # profiles, bound folders, active profile, Desktop profile
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
- **Bound folders** pick the profile automatically. If you start a different profile inside a bound folder, claudectl asks before continuing.
|
|
90
|
+
- **Everywhere else**, `claudectl` uses the active profile. Set it with `claudectl use <name>`.
|
|
91
|
+
- **Every session shows its customer** in Claude Code's status line and in the tab title.
|
|
92
|
+
- **On Windows**, tabs open in Windows Terminal with the customer's color. macOS uses Terminal.app. Linux uses the first terminal it finds: GNOME Terminal, Konsole, kitty, WezTerm, Alacritty or Xfce Terminal.
|
|
93
|
+
|
|
94
|
+
## Import your existing setup
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
claudectl import --scan # just show what's in your current Claude setup
|
|
98
|
+
claudectl import # guided: sort project folders into customer profiles
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**What the scan finds:**
|
|
102
|
+
- every project folder Claude has history for (worktrees are folded into their repo)
|
|
103
|
+
- MCP servers, both user-wide and per-project
|
|
104
|
+
- skills, agents, commands and output styles
|
|
105
|
+
- your `CLAUDE.md`, plugins and preferences
|
|
106
|
+
- Claude Desktop's MCP servers
|
|
107
|
+
- leftovers from older switcher scripts: extra `~/.claude-*` config folders, system-wide `ANTHROPIC_*` variables, and lines in your PowerShell or shell profile
|
|
108
|
+
|
|
109
|
+
It skips temporary folders, folders that no longer exist, your home folder and drive roots.
|
|
110
|
+
|
|
111
|
+
**The guided import** suggests customers from your folder layout. `D:\work\acme\api` and `D:\work\acme\web` become one `acme` profile, tied to `D:\work\acme`. You can:
|
|
112
|
+
- press Enter to accept each suggestion
|
|
113
|
+
- type a name to rename it or merge it into another profile
|
|
114
|
+
- press `k` to keep those folders in your default setup
|
|
115
|
+
|
|
116
|
+
Then you pick:
|
|
117
|
+
- the AI platform for each new profile
|
|
118
|
+
- which profiles get which MCP servers
|
|
119
|
+
- whether new profiles get your skills, `CLAUDE.md`, preferences and plugins (plugins are reinstalled cleanly in each profile)
|
|
120
|
+
|
|
121
|
+
**It only copies.** Each project's history, memory, prompt history, trust settings and per-project MCP servers go into its profile. Your current setup isn't changed, so it's safe while Claude is running.
|
|
122
|
+
|
|
123
|
+
**Your own sign-in, account details and caches are never copied into a customer profile.** The one exception: a `~/.claude-*` folder left by an older switcher is adopted whole, including its sign-in, because that sign-in belongs to the customer.
|
|
124
|
+
|
|
125
|
+
You can also work from a file, which is handy for many folders or for repeating the import:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
claudectl import --plan plan.json # write the suggestions to a file you can edit
|
|
129
|
+
claudectl import --apply plan.json --dry-run # show what would happen
|
|
130
|
+
claudectl import --apply plan.json # copy
|
|
131
|
+
claudectl import --apply plan.json --move # copy, then take it out of the default setup
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Running `--apply` again is safe: it never overwrites anything and doesn't duplicate history.
|
|
135
|
+
|
|
136
|
+
**`--move`** removes the imported customer folders, history and MCP servers from your default setup:
|
|
137
|
+
- It refuses while any Claude Code session is running, including Desktop's Code tab.
|
|
138
|
+
- It backs up your config first.
|
|
139
|
+
- It puts everything it removes in `~/.claudectl/import-backups/`.
|
|
140
|
+
- Desktop's Code tab uses your default setup, so moved history no longer shows up there.
|
|
141
|
+
|
|
142
|
+
`--from DIR` imports from another Claude config folder instead of `~/.claude`.
|
|
143
|
+
|
|
144
|
+
## AI platforms
|
|
145
|
+
|
|
146
|
+
| Platform | How it connects |
|
|
147
|
+
|---|---|
|
|
148
|
+
| Claude subscription: Pro, Max, Team, Enterprise | Browser sign-in on first start. You can lock it to the customer's org UUID. |
|
|
149
|
+
| Anthropic API key | Pay per use. |
|
|
150
|
+
| DeepSeek | Native Claude-compatible endpoint. |
|
|
151
|
+
| OpenRouter | GPT, Gemini and others. Use this for OpenAI customers, with BYOK for their own OpenAI key. |
|
|
152
|
+
| Any Claude-compatible URL | For example a LiteLLM proxy in front of a direct OpenAI key, Moonshot, Z.ai or a company gateway. |
|
|
153
|
+
| AWS Bedrock, Google Vertex | Claude through the customer's own cloud account. |
|
|
154
|
+
|
|
155
|
+
To add a platform, create `~/.claudectl/providers.json`: a JSON list of entries in the same shape as `BUILTIN_PROVIDERS` at the top of [claudectl/cli.py](claudectl/cli.py). An entry with an existing `id` replaces the built-in one. To change a profile's models, run `claudectl edit <name>`.
|
|
156
|
+
|
|
157
|
+
**Where API keys are stored:**
|
|
158
|
+
- **Windows:** encrypted with DPAPI, so only your Windows user can read them.
|
|
159
|
+
- **macOS:** in your login Keychain.
|
|
160
|
+
- **Linux:** in your keyring through `secret-tool`. Without a keyring, in a file only you can read.
|
|
161
|
+
|
|
162
|
+
## Claude Desktop
|
|
163
|
+
|
|
164
|
+
Desktop holds one sign-in at a time, so it switches with a restart:
|
|
165
|
+
|
|
166
|
+
1. Quit Desktop.
|
|
167
|
+
2. Run `claudectl desktop acme`.
|
|
168
|
+
3. Start Desktop.
|
|
169
|
+
|
|
170
|
+
This swaps the local MCP servers in Desktop's config. Each customer's servers are saved automatically when you switch away.
|
|
171
|
+
|
|
172
|
+
Cloud connectors added on claude.ai belong to the signed-in account and follow it. If the customer uses a different Claude account, sign out and back in.
|
|
173
|
+
|
|
174
|
+
**Not isolated:** Desktop's own Code tab uses Desktop's built-in Claude Code and login. Do isolated customer work in a terminal with claudectl.
|
|
175
|
+
|
|
176
|
+
## Where things live
|
|
177
|
+
|
|
178
|
+
Everything is in `~/.claudectl`, on every OS. On Windows this is deliberately not AppData: Microsoft Store Python redirects new files there into a private folder that Claude Code can't see.
|
|
179
|
+
|
|
180
|
+
Each profile lives in `~/.claudectl/profiles/<name>/`:
|
|
181
|
+
- `profile.json`: platform, models, how the key is stored
|
|
182
|
+
- `config/`: Claude Code's own folder for this customer (login, MCP, skills, plugins, history, memory)
|
|
183
|
+
- `desktop-mcp.json`: this customer's Claude Desktop MCP servers
|
|
184
|
+
|
|
185
|
+
Set `CLAUDECTL_HOME` to put the data folder somewhere else.
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# claudectl
|
|
2
|
+
|
|
3
|
+
Use Claude Code with a separate profile for each customer, on Windows, macOS and Linux. Each profile has its own:
|
|
4
|
+
|
|
5
|
+
- sign-in or API key
|
|
6
|
+
- AI platform
|
|
7
|
+
- MCP servers
|
|
8
|
+
- skills and plugins
|
|
9
|
+
- session history and memory
|
|
10
|
+
|
|
11
|
+
Customers can run side by side in separate terminals. Switching never touches a session that's already running, and one customer's Jira or Confluence server never shows up in another customer's session.
|
|
12
|
+
|
|
13
|
+
claudectl doesn't change anything machine-wide. Your normal `claude` and `~/.claude` keep working exactly as before, and appear as the `default` profile.
|
|
14
|
+
|
|
15
|
+
It's pure Python 3.10+ with no dependencies beyond the standard library.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
From PyPI (the package is `claude-profile`, the command is `claudectl`):
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pipx install claude-profile # or: uv tool install claude-profile or: pip install claude-profile
|
|
23
|
+
claudectl install # optional: adds the "Claude Profiles" Start menu picker on Windows
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**Without Python:** download a standalone binary from [Releases](https://github.com/CloudOpsWorld/claude-profile/releases) and run it once with `install`, which puts it in `~/.local/bin`:
|
|
27
|
+
- `claudectl-windows-amd64.exe`
|
|
28
|
+
- `claudectl-macos-arm64`
|
|
29
|
+
- `claudectl-linux-amd64`
|
|
30
|
+
|
|
31
|
+
Each release has `SHA256SUMS` and build provenance you can check with `gh attestation verify <file> --repo CloudOpsWorld/claude-profile`.
|
|
32
|
+
|
|
33
|
+
**From source:**
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
python claudectl/cli.py install
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
This copies the single file to `~/.claudectl/app` and puts a launcher in `~/.local/bin`.
|
|
40
|
+
|
|
41
|
+
To remove claudectl, run `claudectl uninstall` (or `pipx uninstall claude-profile`). Your profiles are kept.
|
|
42
|
+
|
|
43
|
+
## Daily use
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
claudectl add acme # guided: name, AI platform, key or sign-in, bind this folder
|
|
47
|
+
cd ~/work/acme-repo
|
|
48
|
+
claudectl # starts Claude Code as ACME, because the folder is bound
|
|
49
|
+
claudectl tab globex # new terminal tab locked to Globex
|
|
50
|
+
claudectl acme --resume # any claude arguments pass through
|
|
51
|
+
claudectl mcp add jira -- npx -y <jira-mcp> # goes into this folder's profile only
|
|
52
|
+
claudectl list # profiles, bound folders, active profile, Desktop profile
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
- **Bound folders** pick the profile automatically. If you start a different profile inside a bound folder, claudectl asks before continuing.
|
|
56
|
+
- **Everywhere else**, `claudectl` uses the active profile. Set it with `claudectl use <name>`.
|
|
57
|
+
- **Every session shows its customer** in Claude Code's status line and in the tab title.
|
|
58
|
+
- **On Windows**, tabs open in Windows Terminal with the customer's color. macOS uses Terminal.app. Linux uses the first terminal it finds: GNOME Terminal, Konsole, kitty, WezTerm, Alacritty or Xfce Terminal.
|
|
59
|
+
|
|
60
|
+
## Import your existing setup
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
claudectl import --scan # just show what's in your current Claude setup
|
|
64
|
+
claudectl import # guided: sort project folders into customer profiles
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**What the scan finds:**
|
|
68
|
+
- every project folder Claude has history for (worktrees are folded into their repo)
|
|
69
|
+
- MCP servers, both user-wide and per-project
|
|
70
|
+
- skills, agents, commands and output styles
|
|
71
|
+
- your `CLAUDE.md`, plugins and preferences
|
|
72
|
+
- Claude Desktop's MCP servers
|
|
73
|
+
- leftovers from older switcher scripts: extra `~/.claude-*` config folders, system-wide `ANTHROPIC_*` variables, and lines in your PowerShell or shell profile
|
|
74
|
+
|
|
75
|
+
It skips temporary folders, folders that no longer exist, your home folder and drive roots.
|
|
76
|
+
|
|
77
|
+
**The guided import** suggests customers from your folder layout. `D:\work\acme\api` and `D:\work\acme\web` become one `acme` profile, tied to `D:\work\acme`. You can:
|
|
78
|
+
- press Enter to accept each suggestion
|
|
79
|
+
- type a name to rename it or merge it into another profile
|
|
80
|
+
- press `k` to keep those folders in your default setup
|
|
81
|
+
|
|
82
|
+
Then you pick:
|
|
83
|
+
- the AI platform for each new profile
|
|
84
|
+
- which profiles get which MCP servers
|
|
85
|
+
- whether new profiles get your skills, `CLAUDE.md`, preferences and plugins (plugins are reinstalled cleanly in each profile)
|
|
86
|
+
|
|
87
|
+
**It only copies.** Each project's history, memory, prompt history, trust settings and per-project MCP servers go into its profile. Your current setup isn't changed, so it's safe while Claude is running.
|
|
88
|
+
|
|
89
|
+
**Your own sign-in, account details and caches are never copied into a customer profile.** The one exception: a `~/.claude-*` folder left by an older switcher is adopted whole, including its sign-in, because that sign-in belongs to the customer.
|
|
90
|
+
|
|
91
|
+
You can also work from a file, which is handy for many folders or for repeating the import:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
claudectl import --plan plan.json # write the suggestions to a file you can edit
|
|
95
|
+
claudectl import --apply plan.json --dry-run # show what would happen
|
|
96
|
+
claudectl import --apply plan.json # copy
|
|
97
|
+
claudectl import --apply plan.json --move # copy, then take it out of the default setup
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Running `--apply` again is safe: it never overwrites anything and doesn't duplicate history.
|
|
101
|
+
|
|
102
|
+
**`--move`** removes the imported customer folders, history and MCP servers from your default setup:
|
|
103
|
+
- It refuses while any Claude Code session is running, including Desktop's Code tab.
|
|
104
|
+
- It backs up your config first.
|
|
105
|
+
- It puts everything it removes in `~/.claudectl/import-backups/`.
|
|
106
|
+
- Desktop's Code tab uses your default setup, so moved history no longer shows up there.
|
|
107
|
+
|
|
108
|
+
`--from DIR` imports from another Claude config folder instead of `~/.claude`.
|
|
109
|
+
|
|
110
|
+
## AI platforms
|
|
111
|
+
|
|
112
|
+
| Platform | How it connects |
|
|
113
|
+
|---|---|
|
|
114
|
+
| Claude subscription: Pro, Max, Team, Enterprise | Browser sign-in on first start. You can lock it to the customer's org UUID. |
|
|
115
|
+
| Anthropic API key | Pay per use. |
|
|
116
|
+
| DeepSeek | Native Claude-compatible endpoint. |
|
|
117
|
+
| OpenRouter | GPT, Gemini and others. Use this for OpenAI customers, with BYOK for their own OpenAI key. |
|
|
118
|
+
| Any Claude-compatible URL | For example a LiteLLM proxy in front of a direct OpenAI key, Moonshot, Z.ai or a company gateway. |
|
|
119
|
+
| AWS Bedrock, Google Vertex | Claude through the customer's own cloud account. |
|
|
120
|
+
|
|
121
|
+
To add a platform, create `~/.claudectl/providers.json`: a JSON list of entries in the same shape as `BUILTIN_PROVIDERS` at the top of [claudectl/cli.py](claudectl/cli.py). An entry with an existing `id` replaces the built-in one. To change a profile's models, run `claudectl edit <name>`.
|
|
122
|
+
|
|
123
|
+
**Where API keys are stored:**
|
|
124
|
+
- **Windows:** encrypted with DPAPI, so only your Windows user can read them.
|
|
125
|
+
- **macOS:** in your login Keychain.
|
|
126
|
+
- **Linux:** in your keyring through `secret-tool`. Without a keyring, in a file only you can read.
|
|
127
|
+
|
|
128
|
+
## Claude Desktop
|
|
129
|
+
|
|
130
|
+
Desktop holds one sign-in at a time, so it switches with a restart:
|
|
131
|
+
|
|
132
|
+
1. Quit Desktop.
|
|
133
|
+
2. Run `claudectl desktop acme`.
|
|
134
|
+
3. Start Desktop.
|
|
135
|
+
|
|
136
|
+
This swaps the local MCP servers in Desktop's config. Each customer's servers are saved automatically when you switch away.
|
|
137
|
+
|
|
138
|
+
Cloud connectors added on claude.ai belong to the signed-in account and follow it. If the customer uses a different Claude account, sign out and back in.
|
|
139
|
+
|
|
140
|
+
**Not isolated:** Desktop's own Code tab uses Desktop's built-in Claude Code and login. Do isolated customer work in a terminal with claudectl.
|
|
141
|
+
|
|
142
|
+
## Where things live
|
|
143
|
+
|
|
144
|
+
Everything is in `~/.claudectl`, on every OS. On Windows this is deliberately not AppData: Microsoft Store Python redirects new files there into a private folder that Claude Code can't see.
|
|
145
|
+
|
|
146
|
+
Each profile lives in `~/.claudectl/profiles/<name>/`:
|
|
147
|
+
- `profile.json`: platform, models, how the key is stored
|
|
148
|
+
- `config/`: Claude Code's own folder for this customer (login, MCP, skills, plugins, history, memory)
|
|
149
|
+
- `desktop-mcp.json`: this customer's Claude Desktop MCP servers
|
|
150
|
+
|
|
151
|
+
Set `CLAUDECTL_HOME` to put the data folder somewhere else.
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Releasing claude-profile
|
|
2
|
+
|
|
3
|
+
Publishing is fully automated via GitHub Actions: pushing a new version to `main`
|
|
4
|
+
triggers a release.
|
|
5
|
+
|
|
6
|
+
## Workflows
|
|
7
|
+
|
|
8
|
+
| Workflow | Trigger | What it does |
|
|
9
|
+
|----------|---------|--------------|
|
|
10
|
+
| `.github/workflows/ci.yml` | push / PR to `main`/`master` | Test matrix (Ubuntu + macOS + Windows × Python 3.10–3.13), advisory ruff lint & mypy |
|
|
11
|
+
| `.github/workflows/build.yml` | `workflow_call` / manual | Runs tests, builds standalone binaries (Linux, macOS, Windows via PyInstaller) and the wheel/sdist (`python -m build` + `twine check`) |
|
|
12
|
+
| `.github/workflows/release.yml` | push to `main`/`master` | Detects a new version, tags it, builds artifacts, creates a GitHub Release, and publishes to PyPI |
|
|
13
|
+
|
|
14
|
+
## How a release happens
|
|
15
|
+
|
|
16
|
+
1. Bump the version in **both** `pyproject.toml` and `claudectl/__init__.py`
|
|
17
|
+
(the release workflow fails if they disagree).
|
|
18
|
+
2. Commit and push to `main`.
|
|
19
|
+
3. `release.yml` will:
|
|
20
|
+
- see the version has no matching `vX.Y.Z` git tag,
|
|
21
|
+
- create and push that tag,
|
|
22
|
+
- build binaries + wheel/sdist,
|
|
23
|
+
- create a GitHub Release with the binaries and package attached,
|
|
24
|
+
- publish the wheel/sdist to PyPI as `claude-profile`.
|
|
25
|
+
|
|
26
|
+
If the tag already exists, the release is skipped — so pushing unrelated commits
|
|
27
|
+
never re-releases.
|
|
28
|
+
|
|
29
|
+
## One-time PyPI setup (Trusted Publishing — recommended)
|
|
30
|
+
|
|
31
|
+
No API token required. On PyPI, signed in as an owner of the **CloudOpsWorld**
|
|
32
|
+
organization:
|
|
33
|
+
|
|
34
|
+
1. Go to **Your organizations → CloudOpsWorld → Publishing → Add a new pending
|
|
35
|
+
publisher** (or **Your account → Publishing** for a personal project) with:
|
|
36
|
+
- PyPI project name: `claude-profile`
|
|
37
|
+
- Owner: `CloudOpsWorld`
|
|
38
|
+
- Repository: `claude-profile`
|
|
39
|
+
- Workflow name: `release.yml`
|
|
40
|
+
- Environment: `pypi`
|
|
41
|
+
2. In the GitHub repo, the **Environment** named `pypi` must exist
|
|
42
|
+
(Settings → Environments) — optionally add required reviewers for a manual
|
|
43
|
+
approval gate before publish.
|
|
44
|
+
|
|
45
|
+
That's it: `release.yml` requests an OIDC token (`id-token: write`) and PyPI
|
|
46
|
+
trusts it. The first successful publish creates the project under the org.
|
|
47
|
+
|
|
48
|
+
### Alternative: API token
|
|
49
|
+
|
|
50
|
+
If you prefer a token, add a repository secret `PYPI_API_TOKEN` and uncomment the
|
|
51
|
+
`password:` line in the `publish-pypi` job of `release.yml`.
|
|
52
|
+
|
|
53
|
+
## Testing the pipeline first
|
|
54
|
+
|
|
55
|
+
- Run **Build** manually (Actions → Build → Run workflow) to confirm binaries and
|
|
56
|
+
the package build without cutting a release.
|
|
57
|
+
- Optionally point at **TestPyPI** first by adding `repository-url:
|
|
58
|
+
https://test.pypi.org/legacy/` to the publish step.
|
|
59
|
+
|
|
60
|
+
## Re-running a failed publish
|
|
61
|
+
|
|
62
|
+
If the publish job failed (for example because the pending publisher wasn't set
|
|
63
|
+
up yet), fix the cause and use **Re-run failed jobs** on that workflow run. The
|
|
64
|
+
tag and GitHub Release already exist, and `skip-existing: true` makes re-runs safe.
|
|
65
|
+
|
|
66
|
+
## Local dry run
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
pip install build twine
|
|
70
|
+
python -m build
|
|
71
|
+
twine check dist/*
|
|
72
|
+
```
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: claude-profile
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: Per-customer profiles for Claude Code and Claude Desktop: separate logins, AI platforms, MCP servers, skills and history, side by side.
|
|
5
|
+
Author: claude-profile contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/CloudOpsWorld/claude-profile
|
|
8
|
+
Project-URL: Repository, https://github.com/CloudOpsWorld/claude-profile
|
|
9
|
+
Project-URL: Issues, https://github.com/CloudOpsWorld/claude-profile/issues
|
|
10
|
+
Keywords: claude,claude-code,claude-desktop,anthropic,profiles,mcp,deepseek,openrouter,cli
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
16
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Software Development
|
|
24
|
+
Classifier: Topic :: Utilities
|
|
25
|
+
Requires-Python: >=3.10
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Provides-Extra: dev
|
|
29
|
+
Requires-Dist: pytest>=9.1.1; extra == "dev"
|
|
30
|
+
Requires-Dist: ruff>=0.15.21; extra == "dev"
|
|
31
|
+
Requires-Dist: mypy>=2.3.0; extra == "dev"
|
|
32
|
+
Requires-Dist: build>=1.5.1; extra == "dev"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# claudectl
|
|
36
|
+
|
|
37
|
+
Use Claude Code with a separate profile for each customer, on Windows, macOS and Linux. Each profile has its own:
|
|
38
|
+
|
|
39
|
+
- sign-in or API key
|
|
40
|
+
- AI platform
|
|
41
|
+
- MCP servers
|
|
42
|
+
- skills and plugins
|
|
43
|
+
- session history and memory
|
|
44
|
+
|
|
45
|
+
Customers can run side by side in separate terminals. Switching never touches a session that's already running, and one customer's Jira or Confluence server never shows up in another customer's session.
|
|
46
|
+
|
|
47
|
+
claudectl doesn't change anything machine-wide. Your normal `claude` and `~/.claude` keep working exactly as before, and appear as the `default` profile.
|
|
48
|
+
|
|
49
|
+
It's pure Python 3.10+ with no dependencies beyond the standard library.
|
|
50
|
+
|
|
51
|
+
## Install
|
|
52
|
+
|
|
53
|
+
From PyPI (the package is `claude-profile`, the command is `claudectl`):
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pipx install claude-profile # or: uv tool install claude-profile or: pip install claude-profile
|
|
57
|
+
claudectl install # optional: adds the "Claude Profiles" Start menu picker on Windows
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Without Python:** download a standalone binary from [Releases](https://github.com/CloudOpsWorld/claude-profile/releases) and run it once with `install`, which puts it in `~/.local/bin`:
|
|
61
|
+
- `claudectl-windows-amd64.exe`
|
|
62
|
+
- `claudectl-macos-arm64`
|
|
63
|
+
- `claudectl-linux-amd64`
|
|
64
|
+
|
|
65
|
+
Each release has `SHA256SUMS` and build provenance you can check with `gh attestation verify <file> --repo CloudOpsWorld/claude-profile`.
|
|
66
|
+
|
|
67
|
+
**From source:**
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
python claudectl/cli.py install
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
This copies the single file to `~/.claudectl/app` and puts a launcher in `~/.local/bin`.
|
|
74
|
+
|
|
75
|
+
To remove claudectl, run `claudectl uninstall` (or `pipx uninstall claude-profile`). Your profiles are kept.
|
|
76
|
+
|
|
77
|
+
## Daily use
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
claudectl add acme # guided: name, AI platform, key or sign-in, bind this folder
|
|
81
|
+
cd ~/work/acme-repo
|
|
82
|
+
claudectl # starts Claude Code as ACME, because the folder is bound
|
|
83
|
+
claudectl tab globex # new terminal tab locked to Globex
|
|
84
|
+
claudectl acme --resume # any claude arguments pass through
|
|
85
|
+
claudectl mcp add jira -- npx -y <jira-mcp> # goes into this folder's profile only
|
|
86
|
+
claudectl list # profiles, bound folders, active profile, Desktop profile
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
- **Bound folders** pick the profile automatically. If you start a different profile inside a bound folder, claudectl asks before continuing.
|
|
90
|
+
- **Everywhere else**, `claudectl` uses the active profile. Set it with `claudectl use <name>`.
|
|
91
|
+
- **Every session shows its customer** in Claude Code's status line and in the tab title.
|
|
92
|
+
- **On Windows**, tabs open in Windows Terminal with the customer's color. macOS uses Terminal.app. Linux uses the first terminal it finds: GNOME Terminal, Konsole, kitty, WezTerm, Alacritty or Xfce Terminal.
|
|
93
|
+
|
|
94
|
+
## Import your existing setup
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
claudectl import --scan # just show what's in your current Claude setup
|
|
98
|
+
claudectl import # guided: sort project folders into customer profiles
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
**What the scan finds:**
|
|
102
|
+
- every project folder Claude has history for (worktrees are folded into their repo)
|
|
103
|
+
- MCP servers, both user-wide and per-project
|
|
104
|
+
- skills, agents, commands and output styles
|
|
105
|
+
- your `CLAUDE.md`, plugins and preferences
|
|
106
|
+
- Claude Desktop's MCP servers
|
|
107
|
+
- leftovers from older switcher scripts: extra `~/.claude-*` config folders, system-wide `ANTHROPIC_*` variables, and lines in your PowerShell or shell profile
|
|
108
|
+
|
|
109
|
+
It skips temporary folders, folders that no longer exist, your home folder and drive roots.
|
|
110
|
+
|
|
111
|
+
**The guided import** suggests customers from your folder layout. `D:\work\acme\api` and `D:\work\acme\web` become one `acme` profile, tied to `D:\work\acme`. You can:
|
|
112
|
+
- press Enter to accept each suggestion
|
|
113
|
+
- type a name to rename it or merge it into another profile
|
|
114
|
+
- press `k` to keep those folders in your default setup
|
|
115
|
+
|
|
116
|
+
Then you pick:
|
|
117
|
+
- the AI platform for each new profile
|
|
118
|
+
- which profiles get which MCP servers
|
|
119
|
+
- whether new profiles get your skills, `CLAUDE.md`, preferences and plugins (plugins are reinstalled cleanly in each profile)
|
|
120
|
+
|
|
121
|
+
**It only copies.** Each project's history, memory, prompt history, trust settings and per-project MCP servers go into its profile. Your current setup isn't changed, so it's safe while Claude is running.
|
|
122
|
+
|
|
123
|
+
**Your own sign-in, account details and caches are never copied into a customer profile.** The one exception: a `~/.claude-*` folder left by an older switcher is adopted whole, including its sign-in, because that sign-in belongs to the customer.
|
|
124
|
+
|
|
125
|
+
You can also work from a file, which is handy for many folders or for repeating the import:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
claudectl import --plan plan.json # write the suggestions to a file you can edit
|
|
129
|
+
claudectl import --apply plan.json --dry-run # show what would happen
|
|
130
|
+
claudectl import --apply plan.json # copy
|
|
131
|
+
claudectl import --apply plan.json --move # copy, then take it out of the default setup
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Running `--apply` again is safe: it never overwrites anything and doesn't duplicate history.
|
|
135
|
+
|
|
136
|
+
**`--move`** removes the imported customer folders, history and MCP servers from your default setup:
|
|
137
|
+
- It refuses while any Claude Code session is running, including Desktop's Code tab.
|
|
138
|
+
- It backs up your config first.
|
|
139
|
+
- It puts everything it removes in `~/.claudectl/import-backups/`.
|
|
140
|
+
- Desktop's Code tab uses your default setup, so moved history no longer shows up there.
|
|
141
|
+
|
|
142
|
+
`--from DIR` imports from another Claude config folder instead of `~/.claude`.
|
|
143
|
+
|
|
144
|
+
## AI platforms
|
|
145
|
+
|
|
146
|
+
| Platform | How it connects |
|
|
147
|
+
|---|---|
|
|
148
|
+
| Claude subscription: Pro, Max, Team, Enterprise | Browser sign-in on first start. You can lock it to the customer's org UUID. |
|
|
149
|
+
| Anthropic API key | Pay per use. |
|
|
150
|
+
| DeepSeek | Native Claude-compatible endpoint. |
|
|
151
|
+
| OpenRouter | GPT, Gemini and others. Use this for OpenAI customers, with BYOK for their own OpenAI key. |
|
|
152
|
+
| Any Claude-compatible URL | For example a LiteLLM proxy in front of a direct OpenAI key, Moonshot, Z.ai or a company gateway. |
|
|
153
|
+
| AWS Bedrock, Google Vertex | Claude through the customer's own cloud account. |
|
|
154
|
+
|
|
155
|
+
To add a platform, create `~/.claudectl/providers.json`: a JSON list of entries in the same shape as `BUILTIN_PROVIDERS` at the top of [claudectl/cli.py](claudectl/cli.py). An entry with an existing `id` replaces the built-in one. To change a profile's models, run `claudectl edit <name>`.
|
|
156
|
+
|
|
157
|
+
**Where API keys are stored:**
|
|
158
|
+
- **Windows:** encrypted with DPAPI, so only your Windows user can read them.
|
|
159
|
+
- **macOS:** in your login Keychain.
|
|
160
|
+
- **Linux:** in your keyring through `secret-tool`. Without a keyring, in a file only you can read.
|
|
161
|
+
|
|
162
|
+
## Claude Desktop
|
|
163
|
+
|
|
164
|
+
Desktop holds one sign-in at a time, so it switches with a restart:
|
|
165
|
+
|
|
166
|
+
1. Quit Desktop.
|
|
167
|
+
2. Run `claudectl desktop acme`.
|
|
168
|
+
3. Start Desktop.
|
|
169
|
+
|
|
170
|
+
This swaps the local MCP servers in Desktop's config. Each customer's servers are saved automatically when you switch away.
|
|
171
|
+
|
|
172
|
+
Cloud connectors added on claude.ai belong to the signed-in account and follow it. If the customer uses a different Claude account, sign out and back in.
|
|
173
|
+
|
|
174
|
+
**Not isolated:** Desktop's own Code tab uses Desktop's built-in Claude Code and login. Do isolated customer work in a terminal with claudectl.
|
|
175
|
+
|
|
176
|
+
## Where things live
|
|
177
|
+
|
|
178
|
+
Everything is in `~/.claudectl`, on every OS. On Windows this is deliberately not AppData: Microsoft Store Python redirects new files there into a private folder that Claude Code can't see.
|
|
179
|
+
|
|
180
|
+
Each profile lives in `~/.claudectl/profiles/<name>/`:
|
|
181
|
+
- `profile.json`: platform, models, how the key is stored
|
|
182
|
+
- `config/`: Claude Code's own folder for this customer (login, MCP, skills, plugins, history, memory)
|
|
183
|
+
- `desktop-mcp.json`: this customer's Claude Desktop MCP servers
|
|
184
|
+
|
|
185
|
+
Set `CLAUDECTL_HOME` to put the data folder somewhere else.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
MANIFEST.in
|
|
3
|
+
README.md
|
|
4
|
+
RELEASING.md
|
|
5
|
+
pyproject.toml
|
|
6
|
+
claude_profile.egg-info/PKG-INFO
|
|
7
|
+
claude_profile.egg-info/SOURCES.txt
|
|
8
|
+
claude_profile.egg-info/dependency_links.txt
|
|
9
|
+
claude_profile.egg-info/entry_points.txt
|
|
10
|
+
claude_profile.egg-info/requires.txt
|
|
11
|
+
claude_profile.egg-info/top_level.txt
|
|
12
|
+
claudectl/__init__.py
|
|
13
|
+
claudectl/__main__.py
|
|
14
|
+
claudectl/cli.py
|
|
15
|
+
scripts/claudectl_entry.py
|
|
16
|
+
scripts/demo.ps1
|
|
17
|
+
tests/test_claudectl.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
claudectl
|