claude-switch-models-setup
Set up and maintain multiple isolated Claude Code CLI profiles so students and power users can run different LLM providers (Kimi K3, Kimi K2.7 highspeed, MiniMax M3, MiniMax M2.7, GLM, DeepSeek, StepFun, Anthropic) in separate terminal windows at the same time. Use this skill whenever the user asks about multi-provider Claude setup, multiple Claude Code windows, switching models or the csk/csd/csg aliases, CLAUDE_CONFIG_DIR, the ~/.claude-profiles directory, or running Kimi/MiniMax/GLM/DeepSeek/StepFun alongside Anthropic. It also owns profile-drift troubleshooting — a third-party profile missing skills/hooks/plugins the default profile has, claude-profiles-doctor reporting a real directory where a symlink belongs, or settings not converging — and per-provider context-window configuration (the [1m] marker or explicit CLAUDE_CODE_MAX_CONTEXT_TOKENS).
1How It Works & Mechanism
Implement process-level isolation using CLAUDE_CONFIG_DIR: each provider has a ~/.claude-profiles/<name>/ directory and an independent .claude.json (credentials and session history), while shared directories (skills/projects/hooks/agents/plugins content) are symlinked back to ~/.claude, enabling multiple windows to run different providers concurrently without configuration cross-contamination.
The result: you can open one terminal with Kimi, another with DeepSeek, another with Anthropic — each running as a fully independent Claude Code process, without configuration bleed.
Enforce 'convergence from default profile' at the settings.json layer: sync-profile-settings.py is registered as a SessionStart hook to copy keys from the default profile's settings.json into each third-party profile (preserving identity keys such as model/advisorModel and provider routing env without overwriting), resolving hook, marketplace, and env drift across third-party windows.
Two denylists define the identity boundary — these are NEVER synced:
Apply allowlist convergence + three-category guardrails for .claude.json behavioral keys: synchronize a select few behavioral keys like workflowSizeGuideline, permanently exclude state/credential/identity keys (oauthAccount/userID/token/secret…) from syncing, and report gray keys without automatically writing them—preventing session state or account identity from one profile leaking into another.
State keys (is_state_key(): prefixes/substrings/exact names) — per- profile runtime state, caches, counters, migration flags, identity and credentials. NEVER synced
Special handling for plugin state: known_marketplaces.json must be per-profile (Claude validates installLocation via path.resolve() without dereferencing symlinks, causing other profiles to report 'corrupted installLocation' if shared), while claude-plugins-sync.py rebuilds the per-profile directory structure for each profile and mirrors enabledPlugins.
Each profile runs with its own CLAUDE_CONFIG_DIR, so `c` is a DIFFERENT literal string per profile
Maintainer-dedicated local source sync: sync-local-skill-sources.py symlinks local skill source repositories into the Claude plugin cache as well as Codex ~/.agents/skills and ~/.codex/skills; runs in dry-run mode by default and only applies changes with --apply; uses O_NOFOLLOW dirfd, atomic renaming via renameat2/renameatx_np, and timestamped backups to prevent concurrency and directory race conditions.
Real files/directories and third-party links are never deleted or automatically moved.
Formalize context window configuration into decision rules: use the literal [1m] suffix only for genuine ~1M context windows (which Claude Code matches literally), use explicit CLAUDE_CODE_MAX_CONTEXT_TOKENS/AUTO_COMPACT for known smaller windows, and never guess for unverified models; dual entries in deepseek/glm templates are intentionally preserved.
Claude Code matches this literal string, not a made-up marker like `[1million]` or `[max]`.
Deployment discipline: deploy scripts via symlinks rather than cp (preventing two-way drift—such as the historical incident where a bug fix sat idle in the repo for 26 days while cleanup code only existed in the deployed copy), accompanied by the setup.sh installer and the claude-profiles-init/doctor/rm operational command suite.
# Symlink rather than copy.
2Core Capabilities
3External Dependencies
| Kind | Dependency / Endpoint |
|---|---|
| cli | claude(官方 CLI,按 profile 启动) |
| cli | python3 |
| cli | uv(仅 daemon --install 时 uv python install 3.12 取托管运行时) |
| cli | launchctl(macOS LaunchAgent 安装/启动) |
| network | provider API 端点(经 claude CLI 转发;模板列出 base URL 需用户核实) |
4Recommended Governance & Evidence
- scripts/: Executes local scripts or commands: scripts/setup.sh
- 网络端点: Declares external network access: (User actions during SKILL execution) claude CLI outbound traffic to provider endpoints/gateways; uv python during daemon --install
- 本地工作目录: File I/O and artifact output: ~/.claude-profiles/<name>/ directory structure (.claude.json, symlinked folders)
5Second-Pass Verification
- [ok] 脚本零网络外发 — 全部脚本无 urllib/requests/socket;grep 到的 https 仅 setup.sh echo 链接与模板/文档里的 provider base URL
- [ok] 凭证键不被同步(防串 profile) — STATE_EXACT 含 projects/oauthAccount/userID 等;STATE_SUBSTR 匹配 token/secret/credential/apikey;ENV_KEY_DENYLIST 拦 ANTHROPIC_* 与隔离旗标;灰键仅报告
- [ok] converger 方向单向(默认→第三方) — docstring:'every key present in main's settings.json overwrites the profile's, except denylisted ones';顶层 profile-only 键保留
- [ok] 删除/修复路径受控 — claude-profile-rm:意外真实文件即 ABORT + y/N 确认;init --repair 把 real dir 归档为 .pre-symlink-bak-<ts> 再 symlink,不直接删
- [ok] 源码同步竞态防护真实存在 — O_NOFOLLOW 打开每个路径组件、libc renameat2/renameatx_np 独占改名、失败 exclusive_rename 回滚、KEEP_JSON_BACKUPS=20
- [ok] ‘claude-profiles-doctor 报 real dir’等能力声明有脚本支撑 — doctor 遍历 profile 目录对比 symlink 与 real dir('WARN: <name> is a real directory (expected symlink...)')
6Verdict & Scenarios
1c1947b7efbf6091…