Beyond Default Claude: Running DeepSeek, MiniMax and GLM in Claude Code and Android Studio

One launcher, isolated profiles, named API keys, and a working ACP bridge for Android Studio. Tested on Ubuntu.

I had a MiniMax session forty minutes into a Room migration refactor. In a second terminal I ran my little provider-switcher script to ask DeepSeek a quick question about a Gradle error.

The switcher did what it always did: it copied settings.deepseek.json over ~/.claude/settings.json.

The MiniMax session kept running, so I thought nothing of it. Then I restarted it the next morning with claude –resume, and it came back up talking to DeepSeek, with a model name DeepSeek had never heard of. The session was fine. My setup was the bug.

This article is the fix: a single cc launcher that gives every provider its own Claude Code profile, keeps API keys out of every settings file, and plugs the same providers into Android Studio’s ACP agent panel.

TL;DR

Problem

Root cause

Fix

Providers overwrite each other

Every launch shares ~/.claude/settings.json

One CLAUDE_CONFIG_DIR profile per provider

API keys scattered across JSON files

Settings files were used as the key store

Keys live only in credentials.env, injected as env vars at launch

Switching keys means editing files

No concept of a named key

cc key use minimax backup

Android Studio agent ignores your setup

The IDE spawns the agent with its own environment, not your shell’s

cc acp <provider> as the agent command

Two scripts drift apart

The terminal launcher and IDE bridge each resolved keys their own way

One script, two entry points

Part 1: The Terminal

Root cause: one config directory, many providers

Claude Code reads its settings, history, sessions and auth state from one directory, ~/.claude by default. Point it at an Anthropic-compatible provider and that choice lives in the same place as everything else.

The common first attempt copies a provider file into place:

Before

# Every terminal shares ~/.claude. The last copy wins.
case "$1" in
minimax) cp settings.minimax.json ~/.claude/settings.json ;;
glm) cp settings.glm.json ~/.claude/settings.json ;;
deepseek) cp settings.deepseek.json ~/.claude/settings.json ;;
esac
claude "$@"

Three things go wrong with this:

  1. Shared state. Every terminal reads the same file. Whatever you launched last is what the next resume, subagent or restart sees.
  2. Keys on disk, several times over. Each settings.<provider>.json holds a plaintext key, and so does the live copy.
  3. Shared history. Sessions from three providers land in one history list, and resuming one under the wrong provider fails in confusing ways.

Claude Code already supports the fix. The CLAUDE_CONFIG_DIR environment variable moves the whole config directory, per process:

After

# Each process gets its own profile. Nothing is copied.
export CLAUDE_CONFIG_DIR="$HOME/.claude-profiles/deepseek"
export ANTHROPIC_BASE_URL="https://api.deepseek.com/anthropic"
export ANTHROPIC_AUTH_TOKEN="$key_from_credentials_file"
exec claude "$@"

Now terminal 1 can run MiniMax while terminal 2 runs DeepSeek, and neither launch touches the other’s profile. The processes still share your project files and each provider’s quota, so this is config isolation, not a sandbox.

One side effect to know about: a new profile is a fresh Claude Code install from its point of view. History, plugins and /config choices you made in ~/.claude won’t be there.

The layout

~/.config/cc/
├── credentials.env # the only file with keys (chmod 600)
├── providers/
│ ├── deepseek.conf # endpoint + models, no secrets
│ ├── minimax.conf
│ └── glm.conf
└── state/
├── minimax.key # selected key name, e.g. "backup"
└── current-provider # last terminal launch, used by `cc status`

~/.claude-profiles/
├── deepseek/ # a full Claude Code config dir per provider
├── minimax/
└── glm/

Notice what’s missing: no settings.json with a key in it. The launcher exports the key into the process environment at launch and nowhere else.

Step 1: Provider files

Each provider gets a small file with its endpoint and models. These values come from each provider’s own Claude Code guide as of October 2026. Model IDs change often, so check them against the provider’s docs before you debug anything else.

~/.config/cc/providers/deepseek.conf

PROVIDER_NAME="DeepSeek"
ANTHROPIC_BASE_URL="https://api.deepseek.com/anthropic"
ANTHROPIC_MODEL="deepseek-flash[1m]"
SMALL_MODEL="deepseek-flash"
AUTO_COMPACT_WINDOW="786432"

~/.config/cc/providers/minimax.conf

PROVIDER_NAME="MiniMax"
ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic" # China: api.minimaxi.com
ANTHROPIC_MODEL="MiniMax-M3"
AUTO_COMPACT_WINDOW="512000"

~/.config/cc/providers/glm.conf

PROVIDER_NAME="GLM"
ANTHROPIC_BASE_URL="https://api.z.ai/api/anthropic"
ANTHROPIC_MODEL="glm-5.1"
SMALL_MODEL="glm-4.5-air"
API_TIMEOUT_MS="3000000"

What each field does:

  • ANTHROPIC_MODEL is the main model, also mapped to the Opus and Sonnet slots.
  • SMALL_MODEL is optional. It fills the Haiku slot and the subagent model, which Claude Code uses for cheap background work. If you leave it out, the main model is used.
  • AUTO_COMPACT_WINDOW is optional. It tells Claude Code when to compact, and it should match the model’s real context window. Setting it higher than the model supports means you hit the provider’s limit before Claude Code thinks it needs to compact.
  • The [1m] suffix tells Claude Code the model has a one-million-token window. Use it only where the provider says so.

Step 2: Named keys

~/.config/cc/credentials.env

CC_KEY_DEEPSEEK_PRIMARY="sk-..."
CC_KEY_MINIMAX_PRIMARY="..."
CC_KEY_MINIMAX_BACKUP="..."
CC_KEY_GLM_PRIMARY="..."
chmod 600 ~/.config/cc/credentials.env

Named keys are for keys you’re entitled to use: a personal key and a team key, or a pay-as-you-go key next to a coding-plan key. Switching keys doesn’t get around a provider’s rate limits or terms.

Two honest caveats. 600 stops other users on the machine, not malware running as you, backups, or an accidental git add. And the launcher sources this file, so it must stay a file you wrote yourself.

Step 3: The cc launcher

The full script is about 170 lines, so it lives in a gist: cc launcher on GitHub Gist. Save it to ~/.local/bin/cc and run chmod 700 ~/.local/bin/cc. The gist also has the three provider files, a credentials.env.example and the acp.json from Part 2.

The whole design rests on two functions. resolve_key finds the selected key, and prepare_env turns a provider into an environment:

# Runs in a $(subshell): every key in credentials.env stays out of the parent env
resolve_key() {
local provider="$1" key_name="$2" var val
[[ -f "$CREDENTIALS_FILE" ]] || die "Missing $CREDENTIALS_FILE"
source "$CREDENTIALS_FILE"
var="CC_KEY_${provider^^}_${key_name^^}"
val="${!var:-}"
[[ -n "$val" ]] || die "No key '$key_name' for '$provider' in $CREDENTIALS_FILE"
printf '%s' "$val"
}

prepare_env() {
local provider="$1" api_key
load_provider "$provider" # sources providers/<name>.conf
KEY_NAME="$(selected_key_name "$provider")"
api_key="$(resolve_key "$provider" "$KEY_NAME")"
# One auth variable only. Setting both makes Claude Code warn about an auth conflict.
unset ANTHROPIC_API_KEY
export ANTHROPIC_AUTH_TOKEN="$api_key"
export ANTHROPIC_BASE_URL ANTHROPIC_MODEL
export ANTHROPIC_DEFAULT_OPUS_MODEL="$ANTHROPIC_MODEL"
export ANTHROPIC_DEFAULT_SONNET_MODEL="$ANTHROPIC_MODEL"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="$SMALL_MODEL"
export CLAUDE_CODE_SUBAGENT_MODEL="$SMALL_MODEL"
[[ -n "$AUTO_COMPACT_WINDOW" ]] && export CLAUDE_CODE_AUTO_COMPACT_WINDOW="$AUTO_COMPACT_WINDOW"
[[ -n "$API_TIMEOUT_MS" ]] && export API_TIMEOUT_MS
export CLAUDE_CONFIG_DIR="$PROFILES_ROOT/$provider"
}

Everything else in the script is a thin command router around these two: cc <provider> calls prepare_env and then exec claude, and the key, status, doctor and remove-provider commands read the same files.

Three design choices worth calling out:

  1. Keys never touch a settings file. resolve_key runs in a subshell, so only the selected key reaches the environment, and only for the process that execs.
  2. Stale variables are cleared. If your .bashrc exports ANTHROPIC_API_KEY for normal Claude use, the launcher unsets it so it can’t fight the provider token.
  3. Logs go to stderr. That doesn’t matter much in a terminal. It matters a lot in Part 2.

Make sure ~/.local/bin is on your PATH, then:

cc doctor
cc deepseek # any claude flags pass through: cc deepseek --resume
cc key list minimax
cc key use minimax backup
cc status minimax

Inside a session, run /status and check that the base URL and model are the ones you expect.

Part 2: Android Studio

Root cause: the IDE doesn’t run your shell

Recent Android Studio builds can host external coding agents over the Agent Client Protocol (ACP). On my install the panel lives at Settings > Tools > AI > Agents, and the Claude Agent entry looks like this:

Claude Agent v0.99.0 (ID: claude-acp)
Command: npx
Arguments: -y @agentclientprotocol/claude-agent-acp@0.99.0
Environment: 1 variables (ANTHROPIC_API_KEY)
Authentication Method: Anthropic Console [Sign out] [Sign in]

Point it at DeepSeek by exporting variables in your .bashrc and it still talks to Anthropic, or fails to authenticate. The adapter isn’t hardcoded to Anthropic. It’s a wrapper around the Claude Agent SDK, which reads the same ANTHROPIC_* variables Claude Code does. The problem is upstream of it:

  1. The IDE spawns the agent as a subprocess. It talks to it as JSON-RPC over stdin and stdout.
  2. That subprocess gets the IDE’s environment, not your interactive shell’s. Aliases, functions and anything exported in .bashrc aren’t there, and if you launched Android Studio from a desktop icon, neither is nvm’s npx.
  3. “Anthropic Console” auth sends Anthropic credentials. Those are meaningless to DeepSeek, MiniMax or GLM.

So the fix is to make the command itself set up the environment. That’s what cc acp is for.

Why it’s a subcommand, not a second script

My first version had a separate cc-acp script that copied the key-lookup logic from cc. Within a week they disagreed: one fell back to the legacy key name for any key, the other only for primary. Same config, two answers.

Before

cc       → its own key lookup → claude
cc-acp → a copy of the key lookup → npx claude-agent-acp

After

cc <provider>      → prepare_env → claude
cc acp <provider> → prepare_env → npx claude-agent-acp

One prepare_env, two entry points. Change a model in glm.conf and both the terminal and the IDE pick it up on the next launch.

cc acp also does three things the terminal path doesn’t need:

  • It requires an explicit provider. Falling back to “whatever I launched last in a terminal” is a surprise you don’t want inside an IDE.
  • It keeps stdout clean. Every log line goes to stderr, because a single stray line on stdout corrupts the JSON-RPC stream and the agent just fails to start.
  • It checks that npx is reachable and lets you set CC_NPX to an absolute path when it isn’t.

The whole ACP entry point is a few lines in the router:

acp)
provider="${1:-}"
[[ -n "$provider" ]] || die "Usage: cc acp <provider> (pass the provider explicitly)"
shift
prepare_env "$provider"
command -v "$NPX" >/dev/null || die "'$NPX' not on PATH. Set CC_NPX to an absolute path."
exec "$NPX" -y "$ACP_PACKAGE" "$@"
;;

Test it from a terminal first. If it prints nothing and waits for input, it’s working: that’s the adapter waiting for the IDE to speak.

cc acp deepseek
# Ctrl+C to exit

Approach A: Point the built-in agent at cc (quickest)

  1. Open Settings > Tools > AI > Agents, then the installed Claude Agent.
  2. Under Authentication Method, click Sign out. If you skip this, Console credentials keep winning.
  3. Set Command to /home/YOUR_USER/.local/bin/cc.
  4. Set Arguments to acp deepseek.
  5. Leave Environment empty. If you use nvm, add CC_NPX=/home/YOUR_USER/.nvm/versions/node/<version>/bin/npx here instead.
  6. Click Apply, then start a new chat.

This gives you one provider at a time. To switch, you edit the arguments.

Approach B: One agent per provider (best UX)

Custom ACP agents are defined in ~/.jetbrains/acp.json. In the AI Chat tool window, open the more menu (the three dots, top right) and choose Add Custom Agent. That creates the file and opens it. The schema is an agent_servers object keyed by the name you want to see in the agent picker:

{
"default_mcp_settings": {},
"agent_servers": {
"DeepSeek (Claude Agent)": {
"command": "/home/YOUR_USER/.local/bin/cc",
"args": ["acp", "deepseek"]
},
"MiniMax (Claude Agent)": {
"command": "/home/YOUR_USER/.local/bin/cc",
"args": ["acp", "minimax"]
},
"GLM (Claude Agent)": {
"command": "/home/YOUR_USER/.local/bin/cc",
"args": ["acp", "glm"]
}
}
}

Use full paths: ~ isn’t expanded here. If npx comes from nvm, add “env”: { “CC_NPX”: “/full/path/to/npx” } to each entry. No keys go in this file.

Save it and the three agents show up in the AI Chat agent picker, each running through its own profile with its own key.

Before and After

Copy-the-settings script

cc

Config per provider

One shared ~/.claude

One CLAUDE_CONFIG_DIR each

Where keys live

Every settings JSON

credentials.env only

Switching keys

Edit files by hand

cc key use <provider> <name>

Android Studio

Console OAuth, Anthropic only

cc acp <provider>, one picker entry each

Key logic

Duplicated per script

One prepare_env

Dependencies

cp and hope

Bash, plus npx for ACP

Troubleshooting Checklist

  1. Unknown model. Check the exact ID in the provider’s docs and your account plan. cc status <provider> shows what’s configured, and /model inside the session shows what’s in use.
  2. 401 or auth error. Run cc key list <provider> to confirm the selected key exists. Never paste the key into a terminal to debug.
  3. Wrong endpoint in the session. Run /status. If it shows the wrong URL, look for an ANTHROPIC_BASE_URL exported somewhere the launcher doesn’t override, such as an env block in the profile’s own settings.json.
  4. IDE agent won’t start. Run cc acp <provider> in a terminal first. Then use Get ACP Logs from the AI Chat more menu. Most failures are a relative command path or npx missing from the IDE’s PATH.
  5. The IDE agent asks you to sign in. Some adapter versions only check ANTHROPIC_API_KEY before starting. Check the adapter’s release notes for your pinned version; if needed, export the key as ANTHROPIC_API_KEY in ACP mode instead of ANTHROPIC_AUTH_TOKEN.
  6. Compaction fires too late or the provider rejects long contexts. Lower AUTO_COMPACT_WINDOW to the model’s actual context size.
  7. Rate limited or out of credits. Switch keys only to another key you’re entitled to use, with its own quota.

Final Thoughts

The bug was never Claude Code, and it was never the providers. It was one shared directory pretending to be three configurations.

CLAUDE_CONFIG_DIR fixes the terminal. Treating the IDE as a process that needs its environment handed to it fixes Android Studio. And keeping one launcher instead of two keeps the two fixes from drifting apart.

Anthropic-compatible doesn’t mean identical. Tool calling, context limits, thinking and web search behave differently across providers, and model IDs change month to month. Pin the adapter version you’ve tested, re-check the provider docs when something breaks, and let cc handle the boring part.

References

Get the Code

You can access the whole script from my GitHub gist, along with the three provider files, a credentials.env.example and the acp.json for Android Studio: cc launcher on GitHub Gist.

https://gist.github.com/SubhankarCodeGeek/c8a54c5190af485354b5e1a3d92de8a0

If this saved you from resuming a session against the wrong provider, give it a clap and pass it to the teammate who still has three settings.*.json files in their home folder. I know they exist. Until last month, one of them was me.


Beyond Default Claude: Running DeepSeek, MiniMax and GLM in Claude Code and Android Studio was originally published in ProAndroidDev on Medium, where people are continuing the conversation by highlighting and responding to this story.