provider-switch · diff
git:20260810.957d8ab to git:20260810.60cc11c
58 added, 15 removed. Audit A to A.
---
name: provider-switch
description: "Configure alt API providers: DeepSeek, Z.ai/GLM, Qwen, MiniMax, OpenRouter. Triggers: switch provider, openrouter."
user-invocable: true
disable-model-invocation: true
- argument-hint: "[status|install|verify|model-check|help|<provider-name>] — no args = interactive status check"
+ argument-hint: "[prompt] [status|install|verify|model-check|help|<provider-name>] — no args/empty prompt = interactive status check"
allowed-tools: [Read, Write, Edit, Bash, Agent, AskUserQuestion, Glob, Grep]
model: opus
---
[DICT: P=Phase, PRV=provider, EXEC=EXECUTE using Bash tool, AUQ=AskUserQuestion, REF=references, ALIAS=shell alias, CFG=configured, BASE=ANTHROPIC_BASE_URL, MOD=ANTHROPIC_DEFAULT_OPUS_MODEL]
# Provider Switch
> Configure + switch between Claude Code alt API providers — DeepSeek (priority), Z.ai/GLM, Qwen/DashScope, MiniMax, OpenRouter. Creates isolated ALIAS in ~/.zshrc.
> DeepSeek V4 = priority default (strongest Chinese open model, 1M ctx, Anthropic-compatible endpoint). Recommend first.
+ ## Prompt contract
+
+ Position 1 of `$ARGUMENTS` is a **free-form prompt** (RU/EN) — modes and flags are optional and may
+ follow in any order. Nobody types keys: resolve mode + scope FROM the prompt.
+
+ 1. Strip flags. An explicit mode token anywhere wins outright, no scoring.
+ 2. Else score modes by distinct whole-word keyword hits (mode table in P1 below). Highest unique
+ score wins. Tie with a destructive mode -> `AskUserQuestion`; tie with `status` -> `status`;
+ tie of two mutating modes -> the keyword appearing first; all zero -> `status`.
+ 3. Empty arguments -> `status`; ask ONE scoping `AskUserQuestion` only when the answer changes
+ what gets written. `status` itself is read-only and asks nothing.
+ 4. Outcome-changing ambiguity -> ONE `AskUserQuestion` (max 4 questions) BEFORE any work.
+ 5. Prose that is not a mode/provider name is still input: extract the provider or scope from it.
+
+ Then print this block ONCE, before the first action:
+
+ ```
+ PLAN — brewtools:provider-switch
+ INPUT: <arguments verbatim, or "(empty)">
+ MODE: <resolved> — <explicit | matched keyword: X | default>
+ SCOPE: <resolved paths / target / level / flags>
+ DO: <2-5 imperative bullets>
+ RESULT: <what the user ends up holding>
+ ```
+
+ Labels are literal; values follow the conversation language.
+
<instructions>
## Robustness Rules (MANDATORY)
| Rule | Scope |
|------|-------|
| Every Bash call: `&& echo "OK ..." \|\| echo "FAILED ..."` | ALL |
| On FAILED: stop phase, report error, !=retry blindly | ALL |
| Max 3 AUQ per phase | ALL |
| !=write secrets anywhere except ~/.zshrc | ALL |
| !=commit ~/.zshrc changes | ALL |
| ~/.zshrc comments: ENGLISH only | ALL writes |
Error format on ANY failure:
```
SCRIPT_ERROR: <name>
PHASE: <current>
ACTION: <attempted>
SUGGESTION: <fix>
```
---
## P0: Language Selection
AUQ: "Select language / Выберите язык" | options: "English (Recommended)", "Russian / Русский"
Default if skipped: English. Remember for session.
---
## Compatibility Flags (REQ per PRV)
| PRV | Required Flags | Why |
|-----|---------------|-----|
| DeepSeek | none | silently ignores beta/ver headers; native Anthropic endpoint |
| Z.ai (GLM) | `CLAUDE_ENABLE_BYTE_WATCHDOG=0` + `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1` | rejects beta headers (err 1210); SSE triggers byte watchdog |
| MiniMax | `CLAUDE_ENABLE_BYTE_WATCHDOG=0` + `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1` | same as Z.ai |
| Qwen/DashScope | `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1` | beta headers may be rejected |
| OpenRouter | none | aggregator, good compat |
When constructing ALIAS (P4 Step 6): ALWAYS include compat flags from PRV REF file.
---
## P1: Mode Detection
EXEC:
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/detect-mode.sh" "$ARGUMENTS" && echo "OK detect" || echo "FAILED detect"
```
> STOP if FAILED — parse $ARGUMENTS manually (keyword match) as fallback.
Output: `ARGS: [...] MODE: [...]`
- | Keyword | MODE |
- |---------|------|
- | status, check | status |
- | install, configure | install |
- | help, how | help |
- | deepseek, ds, dpsk | provider-deepseek |
- | glm, zai, z.ai | provider-glm |
- | qwen, dashscope | provider-qwen |
- | minimax, mini | provider-minimax |
- | openrouter, router | provider-openrouter |
- | verify, test, token | verify |
- | model-check, identify | model-check |
- | typos (model-cehck, cehck, hlpe, instal) | fuzzy-match to correct |
- | (empty) | status |
+ | Mode | EN keywords | RU keywords | Mutates? |
+ |------|-------------|-------------|----------|
+ | `status` | *(empty)*, status, check | статус, проверь | no |
+ | `install` | install, configure | настрой, установи, поставь | yes |
+ | `help` | help, how | помощь, как | no |
+ | `provider-deepseek` | deepseek, ds, dpsk | дипсик | yes |
+ | `provider-glm` | glm, zai, z.ai | глм, зай | yes |
+ | `provider-qwen` | qwen, dashscope | квен, дашскоуп | yes |
+ | `provider-minimax` | minimax, mini | минимакс | yes |
+ | `provider-openrouter` | openrouter, router | опенроутер, роутер | yes |
+ | `verify` | verify, test, token | проверка, тест, токен | no |
+ | `model-check` | model-check, identify | проверь модель, идентифицируй | no |
+ Typos (`model-cehck`, `cehck`, `hlpe`, `instal`, ...) fuzzy-match to the closest row above.
+
+ Prompt contract PLAN block: read-only modes (`status`, `help`, `verify`, `model-check`) print it
+ right before their report (P2/P6/P7/P8). `install` prints it once P3 provider selection is
+ finalized; `provider-<name>` prints it immediately (scope already known) — both before P4 Step 2's
+ first write.
+
---
## P2: Status Check (ALL modes)
EXEC:
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/check-status.sh" && echo "OK status" || echo "FAILED status"
```
> STOP if FAILED — check ~/.zshrc manually with grep.
Parse key=value output. Status per PRV:
- `configured` = ALIAS + KEY both true
- `partial` = ALIAS true, KEY false
- `not configured` = ALIAS false
- `active` = ACTIVE_PROVIDER matches
+ If MODE=status: print the Prompt contract PLAN block now, before the table below.
+
Render status table:
```
# Provider Switch — [MODE]
## Current Status
| PRV | Alias | API Key | Model | Status |
|-----|-------|---------|-------|--------|
| DeepSeek (priority) | claudeds | DEEPSEEK_API_KEY | deepseek-v4-pro | ... |
| Z.ai / GLM | claudeglm | ZAI_API_KEY | glm-5.2 | ... |
| Qwen | claudeqwen | DASHSCOPE_API_KEY | qwen3.7-plus[1m] | ... |
| MiniMax | claudeminimax | MINIMAX_API_KEY | MiniMax-M3 | ... |
| OpenRouter | claudeor | OPENROUTER_API_KEY | (user-selected) | ... |
## How to Use
Run `claudeds` — sets env vars + launches Claude (recommended default).
Return to Anthropic: new terminal → `claude`.
```
Auto-install logic (MODE=status only): zero CFG → auto-proceed to P3 ("No providers CFG yet. Starting install..."). >=1 CFG → STOP here.
If MODE=help → GOTO P6.
---
## P3: PRV Selection
If MODE=install (no specific PRV): AUQ options:
- "DeepSeek V4 (deepseek-v4-pro, 1M ctx, priority - Recommended)"
- "Z.ai / GLM (glm-5.2, free models available)"
- "Qwen / DashScope (qwen3.7-plus, 1M ctx)"
- "MiniMax (MiniMax-M3, cheapest)"
- "OpenRouter (aggregator, any model)"
- "All providers"
If MODE=provider-\<name\> → skip to P4 for that PRV only.
+ Print the Prompt contract PLAN block now — scope (selected PRV(s)) is finalized either way,
+ before P4 Step 2's first write.
+
---
## P4: PRV Configuration
For each selected PRV:
### Step 1: Load REF
Read PRV REF file: DeepSeek=`REF/deepseek.md` | Z.ai/GLM=`REF/zai-glm.md` | Qwen=`REF/qwen-dashscope.md` | MiniMax=`REF/minimax.md` | OpenRouter=`REF/openrouter.md`
Also read `REF/common.md` for shared ALIAS structure (first time only).
### Step 2: Init Section
EXEC:
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/write-alias.sh" init && echo "OK init" || echo "FAILED init"
```
> STOP if FAILED — cannot write ~/.zshrc.
### Step 3: API Key
Check if key set (from P2: KEY_DEEPSEEK, KEY_ZAI, KEY_DASHSCOPE, KEY_MINIMAX, KEY_OPENROUTER).
If already `true` for this PRV → SKIP this step, !=re-ask, !=rewrite the key.
If missing — AUQ: "Enter your <PRV> API key (from <dashboard-url>):"
Qwen-specific: read `REF/qwen-dashscope.md` ## How to Get API Key before asking. Show step-by-step. Warn: key MUST be from Singapore region — other regions return 403. Valid fmt: `sk-...` (~40 chars). If starts with `sk-ws-` or >100 chars → warn wrong region, ask regenerate.
The key goes in on **stdin**, NEVER as an argument — argv is visible to `ps` for the whole
process lifetime and is written verbatim into the session transcript (Robustness Rule:
`!=write secrets anywhere except ~/.zshrc`).
EXEC:
```bash
printf '%s' 'KEY_VALUE' | bash "${CLAUDE_SKILL_DIR}/scripts/write-alias.sh" set-key "KEY_VAR_NAME" && echo "OK set-key" || echo "FAILED set-key"
```
KEY_VAR_NAME: `DEEPSEEK_API_KEY` | `ZAI_API_KEY` | `DASHSCOPE_API_KEY` | `MINIMAX_API_KEY` | `OPENROUTER_API_KEY`
> STOP if FAILED.
### Step 4: Model Selection (OpenRouter only)
Read `REF/openrouter-models.md`. AUQ options:
- "qwen/qwen3.7-plus[1m] — 1M ctx, top coding (Recommended)"
- "z-ai/glm-5.2 — strong coding (self-reported), 1M"
- "qwen/qwen3-coder:free — free, 262K, code-focused"
- "Custom (specify model ID)"
Selected model = OPUS + SONNET + HAIKU simultaneously.
If Custom: validate via script from `REF/openrouter-models.md` ## Model Validation. If NOT_FOUND → fuzzy suggestions + re-ask. Max 2 retries then fall back to default.
### Step 5: ALIAS Name
AUQ: "Alias name for <PRV>:" | options: "<default> (Recommended)", "Custom"
If Custom: validate — must start with `claude`, no spaces, lowercase alphanumeric only.
| PRV | Default |
|-----|---------|
| DeepSeek | `claudeds` |
| Z.ai/GLM | `claudeglm` |
| Qwen | `claudeqwen` |
| MiniMax | `claudeminimax` |
| OpenRouter | `claudeor` |
### Step 6: Write ALIAS
Construct body from REF file: semicolon-separated exports + `claude` at end.
EXEC:
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/write-alias.sh" set-alias "ALIAS_NAME" "ALIAS_BODY" && echo "OK set-alias" || echo "FAILED set-alias"
```
> STOP if FAILED — !=continue to next PRV.
### Step 7: Verify
EXEC:
```bash
source ~/.zshrc 2>/dev/null && type ALIAS_NAME 2>/dev/null && echo "OK verify" || echo "FAILED verify"
```
> STOP if FAILED — ALIAS not written correctly.
---
## P5: Verification + Final Status
EXEC:
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/check-status.sh" && echo "OK final-status" || echo "FAILED final-status"
```
Render updated status table (same fmt as P2).
Token verification for each just-CFG PRV:
EXEC:
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/verify-providers.sh" all && echo "OK verify" || echo "FAILED verify"
```
Add verification column to table:
| PRV | Status | Token Test |
|-----|--------|-----------|
| Z.ai/GLM | CFG | pass/fail |
If any `fail` → warn, suggest check API key or endpoint.
Activation instructions:
```
## Activation
Run ALIAS (e.g. `claudeglm`) — sets env vars + launches Claude.
Return to Anthropic: new terminal → `claude`. Env vars persist current shell only.
```
---
## P6: Help Mode
+ Print the Prompt contract PLAN block now, before explaining.
+
Read `REF/common.md`. Explain:
| Topic | Detail |
|-------|--------|
| How ALIAS works | Sets env vars + launches `claude` — isolated, one PRV at a time |
| How to switch | Run ALIAS (e.g. `claudeglm`) — sets vars + starts Claude |
| How to return | New terminal → `claude` — env vars current shell only |
| Context [1m] hack | `[1m]` suffix forces Claude Code to use 1M ctx window |
| Auth (all PRVs) | ALL use ANTHROPIC_AUTH_TOKEN (Bearer). ANTHROPIC_API_KEY="" blocks OAuth fallback |
| OpenRouter note | MUST set ANTHROPIC_API_KEY="" (empty, !=unset) to prevent OAuth fallback |
| Dashboards | DeepSeek: platform.deepseek.com | Z.ai: z.ai/subscribe | Qwen: bailian.console.alibabacloud.com | MiniMax: platform.minimax.io | OpenRouter: openrouter.ai |
---
## P7: Verify Mode
+ Print the Prompt contract PLAN block now, before the report below.
+
EXEC:
```bash
bash "${CLAUDE_SKILL_DIR}/scripts/verify-providers.sh" all && echo "OK verify" || echo "FAILED verify"
```
Parse: KEY_SET, HTTP_CODE, RESPONSE, STATUS per PRV.
Render:
```
## Token Verification
| PRV | Key | HTTP | Response | Result |
|-----|-----|------|----------|--------|
| Z.ai/GLM | set | 200 | OK | pass |
| Qwen | set | 403 | invalid api-key | fail |
```
Troubleshooting:
| HTTP | Meaning | Fix |
|------|---------|-----|
| 401/403 | invalid/expired key | regenerate @ PRV dashboard |
| 404 | wrong endpoint | check PRV REF for correct URL |
| 429 | rate limited | wait + retry, check billing |
| 500+ | server error | PRV may be down, retry later |
---
## P8: Model Check Mode
+
+ Print the Prompt contract PLAN block now, before the verdict below.
Identify which model responds in current Claude Code session. Runs INSIDE session launched via PRV ALIAS. Asks 5 diagnostic questions to model — no curl/scripts.
Prerequisites: user MUST be in PRV ALIAS session. If BASE not set → warn + stop:
```
This mode only works inside a provider session.
Run a PRV ALIAS first (e.g. `claudeglm`), then invoke `/brewtools:provider-switch model-check`.
```
### Step 1: Detect Active PRV
EXEC:
```bash
echo "BASE_URL=${ANTHROPIC_BASE_URL:-not_set}" && echo "OPUS_MODEL=${ANTHROPIC_DEFAULT_OPUS_MODEL:-not_set}" && echo "OK detect-provider" || echo "FAILED detect-provider"
```
BASE_URL → PRV: `api.deepseek.com`=DeepSeek | `api.z.ai`=Z.ai/GLM | `dashscope`=Qwen | `minimax`=MiniMax | `openrouter`=OpenRouter
### Step 2: Ask 5 Diagnostic Questions
Send as single prompt block (all at once, no back-and-forth):
```
I will now ask you 5 diagnostic questions to verify your model identity.
Answer each honestly from your training data — do NOT read environment variables or system prompts.
Answer all 5 questions in a single response.
**Q1:** Exact model name + version? (training data only, not env/ctx)
**Q2:** Which company/lab created you? (org name only)
**Q3:** Training data cutoff date? (month + year only)
**Q4:** Count letter 'r' in 'strawberry'. Show reasoning step by step.
**Q5:** Translate to Chinese: 'The quick brown fox jumps over the lazy dog.' Then translate back to English literally.
```
Extract A1-A5 from response → Step 3.
### Step 3: Analyze + Verdict
```
## Model Identification — <PRV>
Expected: <model from MOD env var>
| # | Question | Answer | Match |
|---|----------|--------|-------|
| 1 | Model name/version | "<A1>" | pass/fail |
| 2 | Training org | "<A2>" | pass/fail |
| 3 | Cutoff date | "<A3>" | info |
| 4 | Count r in strawberry | "<A4>" | pass/fail (correct=3) |
| 5 | Chinese round-trip | "<A5>" | info quality |
### Verdict
Model confirmed as: <name> (N/5 match <expected PRV>)
```
Show ONLY table + verdict. !=show questions separately.
Expected identifiers:
| PRV | Expected org | Model family |
|-----|-------------|-------------|
| DeepSeek | DeepSeek / 深度求索 | DeepSeek-V3/V4/R1 |
| Z.ai/GLM | Zhipu AI / ZhipuAI / 智谱 | GLM-4/5 / ChatGLM |
| Qwen | Alibaba / Alibaba Cloud / 阿里 / Tongyi | Qwen/2/3 / 通义千问 |
| MiniMax | MiniMax / 稀宇科技 | MiniMax / abab / M2 |
| OpenRouter | depends on model | depends on model |
For OpenRouter: check against model in MOD env var.
---
## P9: Update (hidden, maintainer-only)
If MODE != update → skip entirely.
### Step 1: Load Protocol
Read `REF/update-protocol.md` for per-PRV sources + update flow.
### Step 2: Spawn PRV Research Agents (ONE message, 5 Task calls)
| Agent | PRV | Sources |
|-------|-----|---------|
| 1 | DeepSeek | api-docs.deepseek.com — models, pricing, endpoint |
| 2 | Z.ai/GLM | docs.z.ai, open.bigmodel.cn/en — models, pricing |
| 3 | Qwen/DashScope | alibabacloud.com/help, qwenlm.github.io — models, pricing |
| 4 | MiniMax | platform.minimax.io — models, pricing |
| 5 | OpenRouter | openrouter.ai/api/v1/models — top coding/free models |
#### Delegation
A big task handed to one agent = an agent gone for an hour: you cannot observe it, cannot correct it, and it usually drifts off-target. One subagent = ONE bounded unit — ONE provider, ~<=5 files, ~<=10 steps. !=hand all five providers to one agent; bigger MUST be split into N tasks, all spawned in ONE message.
Every spawn prompt MUST carry:
| Field | Content |
|-------|---------|
| GOAL | the overall task and why it exists — the point beyond the file edit |
| ROLE | what this agent owns; what it must NOT touch |
| SCOPE | exact paths/commands in bounds + explicit out-of-bounds |
| CONTEXT | what is already done, by whom, what runs in parallel — trimmed to what THIS agent needs |
| CONSUMER | who or what uses the result next, and the shape it must fit |
| DONE | acceptance criteria + the exact report shape you want back |
Shape for agent 2, verbatim pattern for the other four:
```
Task(subagent_type="general-purpose", prompt="
GOAL: refreshing this skill's provider reference files so users get current model ids,
pricing and endpoints; you cover Z.ai/GLM only, four sibling agents cover the others.
ROLE: research + report. Do NOT edit any file — the skill applies changes in Step 5.
SCOPE: in — docs.z.ai, open.bigmodel.cn/en via WebFetch/WebSearch. Out — other providers,
~/.zshrc, any reference file on disk.
CONTEXT: references/zai-glm.md on disk currently records model glm-5.2, alias claudeglm,
Anthropic-compatible endpoint https://api.z.ai/api/anthropic — that is your baseline to
diff against. Four sibling agents fetch DeepSeek, Qwen, MiniMax and OpenRouter right now;
nothing has been written to disk yet.
CONSUMER: Step 3 diffs your table against the reference file and Step 4 shows the diff to
the user, who approves each UPDATE before Step 5 writes it. An omitted field reads as
'unknown' and blocks the whole provider's update.
DONE: table | Field | Current | Fetched | Source URL | for model ids, pricing, endpoint,
context window. Say 'no change' explicitly per field rather than omitting it.
")
```
A bare one-line task is never enough. Each agent: WebFetch/WebSearch sources from protocol, extract current model list + pricing + endpoint changes.
### Step 3: Aggregate + Diff
Per PRV: model IDs changed? pricing changed? new models? endpoint URL changed? ctx windows changed?
### Step 4: Present Changes
```
## Update Results
| PRV | Field | Current | Fetched | Action |
|-----|-------|---------|---------|--------|
| Z.ai | opus model | glm-5.2 | glm-6.0 | UPDATE |
| Qwen | pricing | ~$0.50 | $0.40 | UPDATE |
| MiniMax | (no changes) | — | — | SKIP |
```
### Step 5: Apply Updates
Edit REF files per field-to-line mapping in `REF/update-protocol.md`. Also update:
- ALIAS bodies if model IDs changed
- `openrouter-models.md` if recommended models changed
- `common.md` if env var patterns changed (rare)
### Step 6: Live Test (optional, if API keys in env)
EXEC:
```bash
curl -s -o /dev/null -w "%{http_code}" -X POST "https://api.z.ai/api/anthropic/v1/messages" -H "x-api-key: ${ZAI_API_KEY:-missing}" -H "content-type: application/json" -H "anthropic-version: 2023-06-01" -d '{"model":"glm-5.2","max_tokens":5,"messages":[{"role":"user","content":"ping"}]}' && echo " OK" || echo " FAILED"
```
### Step 7: Report
```
## PRV Update Complete
| PRV | Changes | Status |
|-----|---------|--------|
| Z.ai/GLM | models updated | applied |
| Qwen | no changes | current |
| MiniMax | pricing updated | applied |
| OpenRouter | 3 new free models | applied |
Files modified: [list]
```
---
## Output Format
```markdown
# Provider Switch — [MODE]
## Current Status
| PRV | Alias | API Key | Model | Status |
|-----|-------|---------|-------|--------|
| DeepSeek (priority) | claudeds | DEEPSEEK_API_KEY | deepseek-v4-pro | CFG |
| Z.ai / GLM | claudeglm | ZAI_API_KEY | glm-5.2 | CFG |
| Qwen | claudeqwen | DASHSCOPE_API_KEY | — | not CFG |
| MiniMax | claudeminimax | MINIMAX_API_KEY | — | not CFG |
| OpenRouter | claudeor | OPENROUTER_API_KEY | — | not CFG |
## How to Use
Run `claudeds` — sets env vars + launches Claude (recommended default).
Return to Anthropic: new terminal → `claude`.
```
</instructions>