Home / All Skills / Workflow & Core Tools / openclaw-model-switch
Workflow & Core Tools · daymade/claude-code-skills

openclaw-model-switch

Switch or repair the model configuration of an OpenClaw instance (e.g. Kimi k2p6 → k3): change the default model, add model definitions, and fix model-config failures — 401 "Invalid token", "No available channel / model not found", thinking-level rejections ("Thinking level X is not supported"), and config edits that don't take effect. Use whenever the user wants to switch/upgrade/rollback the OpenClaw model (切换模型/换模型/ 升级模型), or says the OpenClaw/龙虾 bot's model is misconfigured (模型配的错了), or the bot falls back / errors on LLM calls.

L4 High-Privilege · Graded auth & full auditV1 Commit-PinnedExecute CommandNetwork AccessWrite FileDual-pass Audit
Author daymadeGitHub daymade/claude-code-skills ↗Stars 1392License MIT(仓库根 LICENSE 文件;GitHub API spdx MIT;Copyright (c) 2025 daymade)Commit d5c4678cb5
Control levels describe skill capabilities and suggested control measures; they do not represent quality or safety certifications, nor do they dictate usability. Usage decisions rest entirely with users and administrators. Different agent hosts apply varying constraints; do not assume hosts provide automatic protection. Third-party skill copyrights belong to their original authors. Use at your own risk.

1How It Works & Mechanism

Consists of only a single 240-line script that operates strictly via "read openclaw.json → modify JSON → overwrite original file", with no daemon or API wrapper.

openclaw-model-switch/scripts/switch-model.py
def save_config(path: Path, config: dict): with open(path, "w", encoding="utf-8") as f: json.dump(config, f, indent=2, ensure_ascii=False) f.write("\n")
What is happening here: In this architecture, switching a model is equivalent to a text-level JSON overwrite accompanied by a backup. Because the OpenClaw gateway reads this file at startup and the script performs no IPC/RPC, "restarting after modification is mandatory" is a hard constraint (this prompt is printed at the end of the script).

Configuration discovery follows "short-circuit via explicit --config; otherwise, mark all existing files among the three candidates as edit targets", treating them as mirrors that must be modified together.

openclaw-model-switch/scripts/switch-model.py
CONFIG_CANDIDATES = [ Path.home() / ".openclaw" / "openclaw.json", Path.home() / ".kimi" / "kimi-claw" / "openclaw.json", Path.home() / ".kimi_openclaw" / "openclaw.json", ]
What is happening here: Solves the most common root cause of "modifications did not take effect"—multiple openclaw.json files existing on the machine (one each for desktop, gateway, and Kimi Claw mirror). Modifying only one will be overwritten by the next sync. Note that the default resolution order differs from the sibling openclaw skill in the same repository (which prioritizes ~/workspace/.force/openclaw).

The "mirror synchronization" is implemented by executing the identical mutation logic across each configuration file independently, rather than copying the primary configuration to the rest.

openclaw-model-switch/scripts/switch-model.py
print(f"Found {len(configs)} config files; will edit and sync all:")
What is happening here: Each file independently undergoes load → backup → modify provider/default model → save. The benefit is preserving the unique content of each file; the downside is that if two files were originally inconsistent, they remain inconsistent after modification (see the discrepancy item under verification.second_pass).

Before any file is modified, a backup is created at <config_dir>/config-backups/openclaw-<local_timestamp>.json, with no retention cap or pruning logic.

openclaw-model-switch/scripts/switch-model.py
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S") backup_path = backup_dir / f"openclaw-{timestamp}.json" shutil.copy2(path, backup_path)
What is happening here: Backups are the prerequisite for "one-click rollbacks" and rule #1 in the SKILL.md safety guidelines. Compared to backup_config in the sibling openclaw skill, two elements are absent: UTC timestamps (local datetime.now() is used here) and a 20-file retention limit; the directory grows indefinitely with usage.

Automatically injects a built-in definition when a model definition is missing: KNOWN_MODELS hardcodes the id, contextWindow, maxTokens, and input modalities for k3, k2p6, and kimi-k2.7-code, inheriting provider-level headers into them.

openclaw-model-switch/scripts/switch-model.py
"k3": { "id": "k3", "name": "k3", "reasoning": True, "input": ["text", "image"], "contextWindow": 1048576, "maxTokens": 32768, },
What is happening here: Lowers the barrier of "switching to a new model" to simply entering a model id, removing the need to manually craft model blocks. Header inheritance (provider.get("headers")) ensures Kimi official endpoint headers like X-Kimi-Claw-ID / User-Agent remain active on the newly added model.

Sets the default model reference as agents.defaults.model.primary (direct subscript assignment without shape validation) while rewriting the agents.defaults.models alias mapping.

openclaw-model-switch/scripts/switch-model.py
config["agents"]["defaults"]["model"]["primary"] = f"{provider_name}/{model_id}"
What is happening here: In OpenClaw, the default model can be expressed either as a string or a {primary: ...} object. This script only supports the object shape—if the user configuration uses a string, a TypeError is raised; if the entire agents.defaults block is missing, a KeyError is raised (in contrast, openclaw's set_default_model adaptively handles both shapes).

When updating the default model, it purges all keys in the alias mapping prefixed with "current provider/" and writes back only an empty object for the new model.

openclaw-model-switch/scripts/switch-model.py
stale_keys = [k for k in models_map if k.startswith(f"{provider_name}/")] for k in stale_keys: del models_map[k] models_map[f"{provider_name}/{model_id}"] = {}
What is happening here: The original intent was to avoid clutter from legacy model aliases. However, the practical effect is that aliases for other models under the same provider (including custom display aliases such as "DeepSeek V4 Pro") are wiped out as well. This is an actual destructive side effect; see verdict.risks.

Maintains metadata timestamps after rewriting: writes the UTC ISO time to meta.lastTouchedAt; preserves meta.lastTouchedVersion if present, or sets it to "unknown" if missing.

openclaw-model-switch/scripts/switch-model.py
config.setdefault("meta", {})["lastTouchedAt"] = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
What is happening here: Marks the configuration with a record indicating "this config was modified recently" for OpenClaw, aiding in auditing "when it was changed and whether it was changed by me". This is also the only place where the script injects new fields into user configurations (it does not delete existing meta content).

Only a single restart path exists: `openclaw gateway restart`; failure merely prints a warning directing the user to restart manually, with no systemd fallback.

openclaw-model-switch/scripts/switch-model.py
["openclaw", "gateway", "restart"],
What is happening here: Passes an argv list via subprocess.run (without shell=True), leaving zero command-injection attack surface. However, if openclaw is not in PATH, only a manual restart is possible; kimi-models.md in SKILL.md also lists "openclaw gateway restart requires CLI to be in PATH" as a known limitation.

Beyond the script, the true "depth of the skill" lies in its documentation-layer diagnostic protocol: first execute an actual completion probe against <baseUrl>/v1/messages using curl, and then run a round of validation with openclaw agent after modification.

openclaw-model-switch/SKILL.md
curl -sS -o /tmp/probe.json -w "HTTP %{http_code}\n" \ -X POST "<baseUrl>/v1/messages" \ -H "Authorization: Bearer <apiKey>" \ -H "Content-Type: application/json" \ -H "anthropic-version: 2023-06-01" \
What is happening here: Enforces the discipline that "listings are untrustworthy; only actual requests count"—the endpoint must first be proven to return 200+content on the model before configuration changes are made. This step is executed by the agent per documentation instructions; the script itself performs zero network requests.

2Core Capabilities

01Single-command default model switching: python3 scripts/switch-model.py <model-id> [--provider NAME] [--config PATH] [--restart]
02Auto-discovery and batch editing across multiple openclaw.json files (updates mirrors together to prevent next-sync overwrites)
03Auto-completion of built-in definitions for unknown models (k3: 1,048,576 context / k2p6: 201,072 / kimi-k2.7-code: 262,144; all with a 32,768 output limit)
04Pre-write backup: creates a timestamped copy under config-backups/ in the same directory for every modified configuration
05Provider inference (defaults to kimi-coding, otherwise selects the first provider in config), with support for explicit specification via --provider
06Endpoint/model authenticity probe protocol: POST <baseUrl>/v1/messages must return 200 with an array body in content; 401 and 503 pinpoint key hijacking and relay group unavailability respectively
07End-to-end verification protocol: runs one cycle with openclaw agent --local --json, validating result=success and fallbackUsed=false (a failure masked by a fallback does not count as success)
08Trap catalog covering five on-site failure categories (env key hijacking / plugin hardcoded thinking / relay 503 routing / non-authoritative listing / editing the wrong file) + local echo server packet capture recipe

3External Dependencies

KindDependency / Endpoint
cliopenclaw CLI(gateway restart;脚本实际调用)
cliopenclaw gateway status(读 Config (service) 判断网关真正读哪份配置)
cliopenclaw agent --local --json(Step 4 端到端验证,看 result/fallbackUsed)
clicurl(Step 2 端点探针;由 agent 按文档执行,非脚本调用)
clipython3 -m json.tool(手工编辑后的 JSON 校验建议)
apiAnthropic Messages 兼容接口(探针目标:POST <baseUrl>/v1/messages,Bearer + anthropic-version 头)
networkKimi 官方端点(references 里给出的 provider baseUrl 示例)
network本地 echo 抓包服务器(trap 目录附录的 wire-capture 配方,读真实 x-api-key)
packagePython 3 标准库 only(json/os/shutil/subprocess/argparse/pathlib/datetime;无第三方依赖)

4Recommended Governance & Evidence

Suggested Controls for Safe Operation
For Agent Runtime
Graded/per-use authorization, sandbox recommended
For Administrators
Approval workflow, rollback support, full audit
Evidence & Triggers (File Paths & Excerpts)
  • scripts/: Executes local script or command: python3 scripts/switch-model.py <model-id> [--provider NAME] [--config PATH
  • 网络端点: Declares external network access: Script itself: zero network calls (no urllib/requests/socket/httpx, no URL constants)
  • 本地工作目录: File I/O and artifact output: <each discovered openclaw.json> (overwritten in-place, indent=2 + ensure_ascii=False + trailing newline)
Audit Notes: Risk Warning: Yellow. In-place local configuration rewriting + document-driven external probe tier. Rationale: (1) The included script invokes subprocesses and overwrites the user's openclaw.json in-place without dry-run capabilities or structural validation (unlike the sibling openclaw skill which provides --dry-run + auto audit), meaning any misconfiguration takes effect immediately; (2) The script has an actual destructive side effect: it purges all keys in agents.defaults.models matching the current provider prefix, wiping aliases for other models under the same provider; (3) When following documentation instructions, the provider's apiKey is used for curl probes against <baseUrl>/v1/messages (sent to the user's configured endpoint, which is expected business traffic rather than leakage), and the packet capture recipe writes the actual x-api-key to /tmp/captured.txt; (4) The script itself has zero network operations, reads no env credentials, and requires no third-party dependencies. Hence classified as Yellow: requires human oversight during changes, but does not warrant Orange (no code paths transmit credentials to third parties or cause credential leaks).

5Second-Pass Verification

  • [discrepancy] 文档称脚本 'syncs mirror files'(SKILL.md Step 3)是否等于内容同步 — 代码只对每个发现的文件各自施加同一处修改(循环里 load→backup→改 provider/默认模型→save),从不把主配置内容复制到其它文件;因此若两份 openclaw.json 原本就有差异,改完仍然有差异,只是「默认模型」这一处一致了。SKILL.md 的 'syncs mirror files' 与脚本实际的 'edit all of them identically' 不是一回事,属措辞夸大(脚本自己的打印也是 'will edit and sync all')。
  • [discrepancy] README 声称 openclaw-model-switch 有 'Model validation against provider's model list' — 脚本里没有校验门禁:模型不在 provider 的 models 里时只做 model_exists → 若内置 KNOWN_MODELS 也没有该 id,仅打印 Warning('Model X is not defined in config and not in built-in known models.')然后照常写入并返回 0。SKILL.md 自身并未这样宣称(它靠 Step 2 探针 + Step 4 验证兜底),所以是 README 层面的描述与代码能力不符。
  • [ok] 「Step 2 端点探针 / Step 4 端到端验证」是否由 skill 代码实现 — 复核确认这不是代码能力而是文档纪律:grep 全脚本无任何 HTTP 客户端与 curl 调用,Step 2/Step 4 都是给 agent 的操作指令(curl 与 openclaw agent 两条命令)。本报告已在 how_it_works 末条、capabilities 与 external_deps 中统一标注为「文档指示、非脚本执行」,避免把文档承诺记成代码能力。
  • [ok] 脚本是否发网络请求 / 读 env 里的 API key(用户指定的两个重点) — 反向扫描 scripts/ 零命中:无 urllib/requests/socket/httpx/curl/wget;无 os.environ/getenv/apiKey 读取。附带发现 import os 在该文件中完全未被使用(无 os.* 调用),说明连标准库层面的环境访问都没接上——凭证交接 100% 发生在文档层(curl 头)而非代码层。
  • [ok] 备份是否真的先于写入、且每份被改文件都有备份 — 循环体内顺序为 load_config → 解析 provider → backup_config(打印 '[path] backed up to: …')→ add_model_definition → update_default_model → 写 meta → save_config,备份严格前置于任何 save_config;显式 --config 时不走 discover_configs 的多文件分支,只备份那一个文件,与文档一致。
  • [ok] 别名清理的破坏范围(第一遍记录「删除 stale keys」,第二遍量化影响) — 确认删除条件是 k.startswith(f"{provider_name}/"),粒度是整个 provider 前缀而非「旧模型」——同一 provider 下所有其它模型的别名映射条目都会被 del,随后只补回新模型的一条空对象(models_map[f"{provider_name}/{model_id}"] = {});若属性顺序上是先删后写,用户其它模型的显示名别名确实会永久丢失(备份可回滚)。已升级为 verdict.risks 首位。
  • [ok] 多文件模式下的失败原子性 — provider 缺失时在循环体内直接 sys.exit(1),若第一个候选文件已成功写入而第二个文件里没有该 provider,进程会在中途退出:出现「有的文件改了、有的没改」的半改状态,且没有回滚逻辑(文档也未提示需人工核对全部镜像)。
  • [ok] SKILL.md 的故障知识是否能在 references 里落地(声明 vs 资产) — SKILL.md 表格里的 5 类症状与 references/troubleshooting-model-config.md 的 5 条 trap 一一对应(含 env KIMI_API_KEY 劫持、插件 binary thinking、canonicalModelId 解等级、relay 分组 503、改错文件),kimi-models.md 也确实给出 k3/k2p6/kimi-k2.7-code 的规格与配置片段;文档承诺的知识资产存在且自洽,无空头引用。

6Verdict & Scenarios

  • Distills a real-world production incident into a reusable diagnostic protocol: probe first to prove endpoint/model availability, update configuration, and finish with a mandatory real agent verification (fallbackUsed must be false); this "proof-first" discipline is its biggest differentiator from purely configuration-focused tools
  • Directly addresses the true root cause of "modifications not taking effect"—the existence of multiple openclaw.json files on the host: updates all present candidate files by default rather than hardcoding a single path
  • Extremely low operational overhead for model switching: built-in KNOWN_MODELS allows one-click auto-filling even when the model definition is missing from the config, inheriting provider headers automatically
  • Rare field-troubleshooting asset: documents undocumented pitfalls such as env variable hijacking of wire keys, hardcoded plugin thinking levels, and relay group-based 503s into structured symptom → root cause → proof method → remediation guides, complete with an executable echo server packet-capture recipe
  • Clean script implementation: pure standard library, zero network dependencies, fixed subprocess argv without shell execution; performs no extraneous actions beyond model switching as requested (only writes an additional meta timestamp)
  • Best for: Suited for operational scenarios where "the OpenClaw host is directly accessible and a claw bot's model needs to be switched or fixed": particularly when migrating to newly released Kimi models (k2p6 → k3), troubleshooting 401 Invalid token / Thinking level not supported / 503 No available channel blocks, or resolving configuration changes that do not take effect—Steps 1-4 in SKILL.md align exactly with this troubleshooting sequence, and the trap catalog directly provides root causes and verification methods. Also ideal as an operational runbook for agents: it explicitly mandates prior probing proof and post-modification end-to-end validation, preventing false-positive successes where a fallback is silently running.
    Not for: Not suited for scenarios requiring cross-instance comparison or batch maintenance across multiple claw bots—that is the domain of the openclaw skill (audit/diff/copy/list subcommands); this skill targets only "the mirrors present on the local machine" at a time. Not suited for cautious workflows that require dry-run previews before in-place configuration rewrites (lacks --dry-run). Not suited for configurations where the default model is formatted as a string or where the agents.defaults structure is incomplete (will crash with KeyError before writing to disk, potentially leaving prior files modified in multi-file mode). Also not suited for DeepSeek gateway provider patching tasks that forbid custom deepseek providers and disallow [1m] in model IDs—those are handled by openclaw + deepseek_patch_sop.md.
    Install Agent-Ready
    ① Verified Mirror 2026-09-15
    Option A · Direct DownloadDownload openclaw-model-switch.tar.gz
    sha256: c53908d204b24a25…
    Option B · Copy Guide for Agent
    install.json
    Agents automatically download and verify mirrors from this JSON guide.
    ② Upstream GitHub
    GitHub Repo ↗
    Pinned to commit d5c4678cb5.