-
Notifications
You must be signed in to change notification settings - Fork 530
fix(providers): Copilot mixed-wire routing, DeepSeek service_tier + reasoning replay, Claude 4.6/4.7 1M windows #889
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
39abf4c
a47a167
91b3921
921070b
3195c71
ef71180
c327fdb
470618d
14eae93
072b8df
60b417c
e0b15fe
478354e
47e7d61
2bb3d91
6a9b79e
62bbeb5
14c8214
e67c0df
cbd345b
198a317
b09596e
b42d573
1e3c050
9f801e3
a0ea408
2843eb5
0b30283
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,134 @@ | ||
| # 000 — Plan: client-integration toggle research (API-side on/off switch) | ||
|
|
||
| Research unit. Docs-only: this unit produces survey and design-option documents, | ||
| not production code. Implementation, if approved later, gets its own decade docs | ||
| in a follow-up cycle. | ||
|
|
||
| Parent unit: `devlog/_plan/260731_client_config_export/` (the read-only export | ||
| surface this unit extends). Sibling survey `001_client_config_survey.md` there | ||
| already covers Pi/OpenCode injection layers and the no-standard landscape; this | ||
| unit does not re-survey them. | ||
|
|
||
| ## Loop spec | ||
|
|
||
| - Loop archetype: spec-satisfaction research (verifier defines done). | ||
| - Trigger: user request — can client integrations be applied as an API-side | ||
| on/off switch (enable writes the provider block into the client config, | ||
| disable removes it), for Hermes Agent, OpenClaw, Kimi Code CLI, and | ||
| Gajae Code, with cc-switch as the reference implementation. | ||
| - Goal: durable devlog evidence answering (a) how cc-switch implements | ||
| apply/remove, (b) what each of the four clients requires for a safe external | ||
| toggle, (c) what shape an opencodex management-API toggle would take and its | ||
| risks. | ||
| - Non-goals: no `src/`, `gui/`, or test changes; no new clients serialized in | ||
| `config-export.ts`; no implementation plan at diff level (that is the next | ||
| cycle's decade docs, only if the design is approved). | ||
| - Verifier: every load-bearing claim carries a source URL or repo file path | ||
| opened this cycle (cxc-search Tier 2); unverifiable claims are marked | ||
| `candidate — unverified` and listed as open questions. `bun run | ||
| privacy:scan` stays green. | ||
| - Stop condition: all four clients + cc-switch lane questions answered or | ||
| explicitly marked unreachable. | ||
| - Memory artifact: this unit's 001–003 docs. | ||
| - Expected terminal outcomes: DONE (docs written, claims sourced) or BLOCKED | ||
| (sources unreachable, named). | ||
| - Escalation: a client whose config cannot be toggled safely from outside is a | ||
| finding, not a failure — record the blocker and mark that client UNSAFE for | ||
| the toggle design. | ||
|
|
||
| ## Research questions | ||
|
|
||
| ### Q1 — cc-switch reference mechanics (doc 001) | ||
|
|
||
| - How does cc-switch apply a provider into each app's config (writer modules, | ||
| atomic write, backup/restore), and how does it remove or restore one? | ||
| - Does it offer any local HTTP API / relay ("universal endpoint") as an | ||
| alternative to file writes? | ||
| - What state does it own (`~/.cc-switch/config.json`) versus mutate in the | ||
| client's files? | ||
|
|
||
| ### Q2 — Per-client toggle requirements (doc 002) | ||
|
|
||
| For each of Hermes Agent, OpenClaw, Kimi Code CLI, Gajae Code: | ||
|
|
||
| - Config file, format, and the minimal provider block that points at | ||
| `http://127.0.0.1:<port>/v1`. | ||
| - Hot-reload semantics: does the client re-read the file, or only at | ||
| session/process start? What does "applies on toggle" mean in practice? | ||
| - Non-interactive management surface, if any (CLI subcommands, local API), | ||
| which would beat raw file writes. | ||
| - Credential handling: env-reference support versus literal-only (decides | ||
| whether the no-secret-serialization invariant survives a write path). | ||
| - Removal semantics: what must be cleaned up beyond the provider block | ||
| (default model pointers, sessions, auth storage). | ||
|
|
||
| ### Q3 — opencodex API toggle design options (doc 003) | ||
|
|
||
| - Current surface: `GET /api/client-config` is read-only by design; mutating | ||
| precedents exist (`PUT /api/disabled-models`, `PUT /api/model-visibility`). | ||
| - Trust boundary (A-gate amendment, blocker 2): the toggle endpoint lives on | ||
| the **management plane** — every `/api/*` request passes | ||
| `requireManagementAuth`, loopback GUI sessions are origin-bound, and | ||
| mutations require CSRF (`src/server/management-auth.ts`, | ||
| `src/server/index.ts:448`). This is separate from **data-plane** admission | ||
| (`resolveApiAuth` in `src/server/auth-cors.ts`), whose loopback shortcut | ||
| only decides what a *client* must send to `/v1`. Doc 003 must not conflate | ||
| the two. | ||
| - Launcher precedence (A-gate amendment, blocker 3): `ocx opencode` injects | ||
| `provider.opencodex` through `OPENCODE_CONFIG_CONTENT`, which outranks the | ||
| disk config for that process (`src/cli/opencode.ts`). Read-back must | ||
| distinguish "disk state" from "runtime state when launched via `ocx`", and | ||
| the design must say whether the disk toggle even applies to OpenCode. | ||
| - Design space: `PUT /api/client-config/:client {enabled: bool}` or a | ||
| `/api/client-integrations` resource; read-back/health (is our block present | ||
| and current?) versus fire-and-forget writes. | ||
| - State model (A-gate amendment, blocker 4): no cc-switch-style DB exists, so | ||
| "is it on?" must be read back from the client file. A boolean `enabled` | ||
| hides drift; the design needs richer states — `absent`, `current`, `stale` | ||
| (our block but not what we would generate now), `conflict` (a block with our | ||
| provider id that we did not write), `unsafe` (unparseable file / damaged | ||
| ownership markers). | ||
| - Invariants to carry over: no secret serialized, additive merge only, | ||
| preserve unknown fields, atomic write + backup, never touch blocks we did | ||
| not write. | ||
|
|
||
| ### Q4 — Local writer/read-back precedents (doc 003, A-gate amendment) | ||
|
|
||
| - `src/grok/inject.ts` — the repo's one existing third-party config writer: | ||
| BEGIN/END managed fence in `~/.grok/config.toml`, orphan-marker refusal, | ||
| non-loopback refusal with credential-fallthrough reasoning, placeholder | ||
| `api_key = "opencodex-loopback"` (never a real secret), `stripGrokConfig` | ||
| removal path. | ||
| - `src/grok/status.ts` — the read-only status reader paired with the writer; | ||
| parses only our own fenced region. | ||
| - `src/config.ts` `atomicWriteFile`/`renameAtomicFile` — temp+rename, Windows | ||
| EBUSY/EPERM/EACCES retry with backoff, 0o600 mode, ACL hardening, residual | ||
| temp scrubbing. | ||
| - Claude Desktop writer/reader — second precedent to survey in 003. | ||
| - Risk register: format fidelity (YAML/JSON5/TOML round-trip), concurrent | ||
| writes while the client runs, clients that rewrite their own config | ||
| (Kimi Code), drift between proxy catalog and written model list. | ||
|
|
||
| ## Doc map (000-range, research only) | ||
|
|
||
| - `000_plan.md` — this document. | ||
| - `001_ccswitch_toggle_analysis.md` — Q1 findings. | ||
| - `002_client_toggle_matrix.md` — Q2 findings, one section per client. | ||
| - `003_api_design_options.md` — Q3 design space + risk register + open | ||
| questions. Options, not a commitment. | ||
| - `004_ux_design.md` — (cycle 2) GUI design for the unified integrations | ||
| surface: tab rename, hero with install detection + switches, per-client | ||
| sub-pages, and the rollback UX that makes the toggle trustworthy. Design | ||
| spec only; component diffs belong to a later implementation cycle. | ||
|
|
||
| ## Dispatch plan | ||
|
|
||
| - 5 research lanes (subagents, read-only): cc-switch, Hermes, OpenClaw, | ||
| Kimi Code, Gajae Code. Lane output is candidate evidence; load-bearing | ||
| claims are re-opened by the main agent before promotion (cxc-search proof | ||
| handoff). | ||
| - Local (main agent): current management-API surface, GUI consumer, loopback | ||
| admission semantics — already read this cycle: | ||
| `src/clients/config-export.ts`, `src/server/management/model-routes.ts`, | ||
| `src/server/auth-cors.ts` (`resolveApiAuth`, loopback admission), | ||
| `gui/src/components/apikeys-workspace/client-config-clients.ts`. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| # 001 — cc-switch toggle mechanics (reference implementation) | ||
|
|
||
| Research only. No diffs here. Sources were opened against upstream `main` on | ||
| 2026-08-02 via the GitHub API (research lane Zeno, main-agent spot-check of the | ||
| two load-bearing claims). | ||
|
|
||
| cc-switch v3.17.0 (Tauri 2, Rust + React) manages Claude Code, Claude Desktop, | ||
| Codex, Gemini CLI, Grok Build, OpenCode, OpenClaw, and Hermes Agent. It is the | ||
| closest shipping implementation of the "on/off switch per client app" this unit | ||
| evaluates. Its own provider store is `~/.cc-switch/cc-switch.db` (SQLite), with | ||
| `settings.json` for device preferences and `backups/` for database backups | ||
| ([README.md#L302-L305](https://github.com/farion1231/cc-switch/blob/main/README.md#L302-L305), | ||
| [database/mod.rs#L96-L109](https://github.com/farion1231/cc-switch/blob/main/src-tauri/src/database/mod.rs#L96-L109)). | ||
|
Comment on lines
+3
to
+13
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: printf '%s\n' '--- relevant files ---'
git ls-files 'devlog/_plan/260802_client_toggle_api/*'
printf '%s\n' '--- cited sections ---'
for f in \
devlog/_plan/260802_client_toggle_api/001_ccswitch_toggle_analysis.md \
devlog/_plan/260802_client_toggle_api/002_client_toggle_matrix.md \
devlog/_plan/260802_client_toggle_api/003_api_design_options.md \
devlog/_plan/260802_client_toggle_api/004_ux_design.md
do
echo "--- $f ---"
wc -l "$f"
done
sed -n '1,25p' devlog/_plan/260802_client_toggle_api/001_ccswitch_toggle_analysis.md
sed -n '15,65p' devlog/_plan/260802_client_toggle_api/002_client_toggle_matrix.md
sed -n '95,125p' devlog/_plan/260802_client_toggle_api/002_client_toggle_matrix.md
sed -n '165,180p' devlog/_plan/260802_client_toggle_api/002_client_toggle_matrix.md
sed -n '155,220p' devlog/_plan/260802_client_toggle_api/003_api_design_options.md
sed -n '1,25p' devlog/_plan/260802_client_toggle_api/004_ux_design.mdRepository: lidge-jun/opencodex Length of output: 15750 🌐 Web query:
💡 Result: The requested revisions and documentation sources as of August 2, 2026, are resolved as follows: farion1231/cc-switch v3.17.0 - Documentation URL: The documentation for this version is located at https://github.com/farion1231/cc-switch/blob/v3.17.0/docs/release-notes/v3.17.0-en.md [1]. - Revision Type: This is an immutable release tag (v3.17.0) [2][1]. NousResearch/hermes-agent (main) - Documentation URL: The documentation is hosted at https://hermes-agent.nousresearch.com/docs/ [3][4]. - Revision Type: This uses a moving branch (main) [5][6]. As of August 2, 2026, the documentation at this URL reflects the latest state of the main branch [3]. openclaw/openclaw (main) and docs.openclaw.ai - Documentation URL: The documentation is hosted at https://docs.openclaw.ai [7][8]. The source of truth for these documents resides in the main branch of the https://github.com/openclaw/openclaw repository [9][10]. - Revision Type: Both the main repository and the documentation site use a moving branch (main) [9][8][10]. The docs.openclaw.ai site is a mirror that syncs from the main branch of the source repository [10]. Citations:
🏁 Script executed: printf '%s\n' '--- exact cited ranges ---'
nl -ba devlog/_plan/260802_client_toggle_api/001_ccswitch_toggle_analysis.md | sed -n '1,18p'
nl -ba devlog/_plan/260802_client_toggle_api/002_client_toggle_matrix.md | sed -n '15,65p'
nl -ba devlog/_plan/260802_client_toggle_api/002_client_toggle_matrix.md | sed -n '100,125p'
nl -ba devlog/_plan/260802_client_toggle_api/002_client_toggle_matrix.md | sed -n '168,178p'
nl -ba devlog/_plan/260802_client_toggle_api/003_api_design_options.md | sed -n '1,22p;160,175p;210,218p'
printf '%s\n' '--- repository and source URLs ---'
git remote -v
rg -n 'github\.com|docs\.openclaw|hermes-agent|cc-switch|Upstream:|Sources were opened' \
devlog/_plan/260802_client_toggle_api
printf '%s\n' '--- GitHub API tag/ref metadata ---'
for spec in \
'farion1231/cc-switch refs/tags/v3.17.0' \
'NousResearch/hermes-agent refs/heads/main' \
'openclaw/openclaw refs/heads/main'
do
set -- $spec
url="https://api.github.com/repos/$1/git/$2"
echo "--- $url ---"
curl -LfsS "$url" | jq '{ref:.ref, object:.object}'
doneRepository: lidge-jun/opencodex Length of output: 10046 🏁 Script executed: printf '%s\n' '--- exact cited ranges ---'
for spec in \
'devlog/_plan/260802_client_toggle_api/001_ccswitch_toggle_analysis.md:1:18' \
'devlog/_plan/260802_client_toggle_api/002_client_toggle_matrix.md:15:65' \
'devlog/_plan/260802_client_toggle_api/002_client_toggle_matrix.md:100:125' \
'devlog/_plan/260802_client_toggle_api/002_client_toggle_matrix.md:168:178' \
'devlog/_plan/260802_client_toggle_api/003_api_design_options.md:1:22' \
'devlog/_plan/260802_client_toggle_api/003_api_design_options.md:160:175' \
'devlog/_plan/260802_client_toggle_api/003_api_design_options.md:210:218'
do
file=${spec%%:*}
rest=${spec#*:}
start=${rest%%:*}
end=${rest##*:}
echo "--- $file:$start-$end ---"
awk -v s="$start" -v e="$end" 'NR >= s && NR <= e { printf "%6d %s\n", NR, $0 }' "$file"
done
printf '%s\n' '--- immutable ref discovery ---'
for repo in farion1231/cc-switch NousResearch/hermes-agent openclaw/openclaw; do
echo "--- $repo ---"
git ls-remote --refs --tags "https://github.com/$repo.git" 'refs/tags/v3.17.0' 'refs/tags/*' 2>/dev/null |
grep -E 'v3\.17\.0$|v3\.17\.0\^\{\}$' | tail -5 || true
git ls-remote "https://github.com/$repo.git" \
'refs/heads/main' 'refs/tags/v3.17.0^{}' 2>/dev/null || true
doneRepository: lidge-jun/opencodex Length of output: 12060 🌐 Web query:
💡 Result: No matching GitHub commit pages were found for either repository on August 2, 2026:
The search results did not surface commits dated 2026-08-02 for either repository. Pin research sources to immutable revisions.
Moving 📍 Affects 2 files
🤖 Prompt for AI Agents |
||
|
|
||
| ## 1. Two app classes: exclusive vs additive | ||
|
|
||
| The toggle semantics split on whether the client keeps one active provider or | ||
| many coexisting ones: | ||
|
|
||
| | Class | Clients | "Switch on" means | "Switch off" means | | ||
| |-------|---------|-------------------|--------------------| | ||
| | Exclusive | Claude Code, Codex, Gemini | backfill current live config into the stored provider record, then overwrite live config with the target provider | switching away backfills and overwrites with the next provider | | ||
| | Additive | OpenCode, OpenClaw, Hermes | insert the provider entry into the client's live config, alongside existing ones | `remove_provider_from_live_config` deletes only that live entry; the provider stays in cc-switch's DB, marked `live_config_managed=false` | | ||
|
|
||
| Source: [provider/mod.rs#L2893-L2951](https://github.com/farion1231/cc-switch/blob/main/src-tauri/src/services/provider/mod.rs#L2893-L2951), | ||
| [provider/mod.rs#L2954-L2966](https://github.com/farion1231/cc-switch/blob/main/src-tauri/src/services/provider/mod.rs#L2954-L2966), | ||
| [provider/mod.rs#L3087-L3146](https://github.com/farion1231/cc-switch/blob/main/src-tauri/src/services/provider/mod.rs#L3087-L3146). | ||
| Main-agent spot-check: `live_config_managed` markers and | ||
| `provider_live_config_managed` confirmed in `provider/mod.rs` (lines 1870, | ||
| 2437-2450). | ||
|
|
||
| All four of this unit's target clients (Hermes, OpenClaw, and by their config | ||
| shapes Kimi Code and Gajae Code) are **additive-class**: a toggle writes and | ||
| removes one provider entry, never a whole-file takeover. | ||
|
Comment on lines
+32
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- candidate files ---'
git ls-files | rg '(^|/)(devlog/_plan/260802_client_toggle_api/001_ccswitch_toggle_analysis\.md|.*cc.?switch.*|.*toggle.*|.*kimi.*|.*gajae.*|.*hermes.*|.*openclaw.*)' || true
printf '%s\n' '--- target document ---'
wc -l devlog/_plan/260802_client_toggle_api/001_ccswitch_toggle_analysis.md
cat -n devlog/_plan/260802_client_toggle_api/001_ccswitch_toggle_analysis.md
printf '%s\n' '--- references to the four clients and classification ---'
rg -n -i -C 4 'Hermes|OpenClaw|Kimi Code|Gajae Code|additive-class|whole-file|provider entry|removal|remove' . \
-g '!node_modules' -g '!dist' -g '!build' || trueRepository: lidge-jun/opencodex Length of output: 50378 🏁 Script executed: #!/bin/bash
set -eu
log=/tmp/coderabbit-shell-logs/shell-output-bxl5Tv
printf '%s\n' '--- target-document output in prior log ---'
rg -n -A 8 -B 8 '001_ccswitch_toggle_analysis\.md|additive-class|Kimi Code|Gajae Code' "$log" | head -n 240
printf '%s\n' '--- focused tracked-file search ---'
git ls-files | rg 'ccswitch|cc-switch|toggle|kimi|gajae|hermes|openclaw' | head -n 240
printf '%s\n' '--- focused repository search ---'
rg -n -i -C 3 'cc.?switch|additive-class|Kimi Code|Gajae Code|OpenClaw|Hermes Agent' \
devlog src tests .github 2>/dev/null | head -n 400 || trueRepository: lidge-jun/opencodex Length of output: 50377 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- cc-switch analysis ---'
cat -n devlog/_plan/260802_client_toggle_api/001_ccswitch_toggle_analysis.md
printf '%s\n' '--- client matrix ---'
cat -n devlog/_plan/260802_client_toggle_api/002_client_toggle_matrix.md
printf '%s\n' '--- design sections that rely on the classification ---'
sed -n '140,205p' devlog/_plan/260802_client_toggle_api/003_api_design_options.md
sed -n '205,225p' devlog/_plan/260802_client_toggle_api/004_ux_design.mdRepository: lidge-jun/opencodex Length of output: 27432 🌐 Web query:
💡 Result: The query refers to technical components and configuration management patterns found in projects like MoonshotAI's Kimi Code CLI [1][2] and related agent-core architectures [3]. Regarding the specific elements mentioned: Provider Removal and Cascades: In the context of Kimi Code's architecture (specifically packages/agent-core-v2), the ProviderService manages provider configurations [3]. When a provider is removed, the system ensures consistency by clearing dependent configurations, such as the default provider, if it matches the one being deleted [3][4]. The removal process typically involves updating the entire provider section by replacing it with the filtered set [3][4], rather than just modifying the single entry in place, to ensure the state remains synchronized [3][4]. TOML Configuration and Preservation of Unknown Fields: The requirement to preserve unknown fields in TOML configuration files is a common challenge in CLI tool development. When tools round-trip configurations (parse TOML -> edit in-memory -> write back to TOML), naive serialization often drops comments or keys not explicitly defined in the application's configuration schema [5][6][7]. To address this, developers typically adopt one of two strategies: 1. Recursive Preservation: Using libraries like Citations:
🌐 Web query:
💡 Result: The query refers to functionality within the Yeachan-Heo/gajae-code project (also known as GJC) [1][2]. While there is no specific public commit with the hash 5f2e7cd documented in the repository's public history, the project manages configuration through a Citations:
🌐 Web query:
💡 Result: In the context of the CC Switch application (maintained by farion1231), the function remove_provider_from_live_config is a specific API command used to remove a provider from the live configuration file for supported AI tools that utilize an additive configuration mode [1]. Additive Mode and Configuration Management: CC Switch supports an additive mode for tools such as OpenCode, OpenClaw, and Hermes Agent [1]. In this mode, multiple providers can remain active simultaneously within the same configuration file [1]. When managing these providers, the application tracks their presence in the live configuration using an isInConfig property [1]. The remove_provider_from_live_config command is specifically designed to perform this removal at the live file level without deleting the provider data from the underlying database [2][1]. Technical Context: - CC Switch is an all-in-one assistant for tools including Claude Code, Codex, OpenCode, OpenClaw, and Hermes Agent [3][4]. - The remove_provider_from_live_config API was implemented to ensure that when a user removes a provider in the UI, the live configuration file is updated correctly, while maintaining the integrity of the provider records in the app's SQLite database [3][2]. - This command is part of the broader provider management system that abstracts the configuration differences between the various native formats of the supported AI tools [1]. Note on Migration: While OpenClaw and Hermes share configuration concepts, migrating between them (using tools like openclaw-to-hermes or bundled migration providers) involves distinct processes—such as mapping custom providers and migrating API keys to a.env file—which are separate from the live config management performed by CC Switch [5][6][7][8]. Citations:
🏁 Script executed: #!/bin/bash
set -eu
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
curl -fsSL \
https://raw.githubusercontent.com/MoonshotAI/kimi-code/e22479a62eed9c3b78a67b313f4332c2c0ba9670/packages/agent-core/src/rpc/core-impl.ts \
-o "$tmp/kimi-core-impl.ts"
curl -fsSL \
https://raw.githubusercontent.com/MoonshotAI/kimi-code/e22479a62eed9c3b78a67b313f4332c2c0ba9670/packages/agent-core/src/config/toml.ts \
-o "$tmp/kimi-toml.ts"
curl -fsSL \
https://raw.githubusercontent.com/Yeachan-Heo/gajae-code/5f2e7cd05e8ea344991566f9ed96f1f9c66226bd/packages/coding-agent/src/cli/setup-cli.ts \
-o "$tmp/gajae-setup-cli.ts"
curl -fsSL \
https://raw.githubusercontent.com/Yeachan-Heo/gajae-code/5f2e7cd05e8ea344991566f9ed96f1f9c66226bd/packages/coding-agent/src/config/models-config-schema.ts \
-o "$tmp/gajae-schema.ts"
curl -fsSL \
https://raw.githubusercontent.com/farion1231/cc-switch/main/src-tauri/src/services/provider/mod.rs \
-o "$tmp/ccswitch-provider.rs"
printf '%s\n' '--- Kimi provider removal ---'
rg -n -A 38 -B 12 'provider.*remove|remove.*provider|default_model|default_provider' "$tmp/kimi-core-impl.ts" | head -n 180
printf '%s\n' '--- Kimi TOML mutation/write path ---'
rg -n -A 35 -B 12 'write|serialize|smol|provider|models' "$tmp/kimi-toml.ts" | head -n 220
printf '%s\n' '--- Gajae setup mutation path ---'
rg -n -A 45 -B 15 'setup provider|models\.yml|write|atomic|rename|provider' "$tmp/gajae-setup-cli.ts" | head -n 240
printf '%s\n' '--- Gajae schema ---'
rg -n -A 35 -B 12 'ProviderConfig|providers|strict|apiKeyEnv|models' "$tmp/gajae-schema.ts" | head -n 220
printf '%s\n' '--- cc-switch additive removal implementation ---'
rg -n -A 45 -B 15 'remove_provider_from_live_config|remove.*live|live_config_managed' "$tmp/ccswitch-provider.rs" | head -n 260Repository: lidge-jun/opencodex Length of output: 36263 🏁 Script executed: #!/bin/bash
set -eu
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
curl -fsSL \
https://raw.githubusercontent.com/MoonshotAI/kimi-code/e22479a62eed9c3b78a67b313f4332c2c0ba9670/packages/agent-core/src/rpc/core-impl.ts \
-o "$tmp/kimi-core-impl.ts"
curl -fsSL \
https://raw.githubusercontent.com/MoonshotAI/kimi-code/e22479a62eed9c3b78a67b313f4332c2c0ba9670/packages/agent-core/src/config/toml.ts \
-o "$tmp/kimi-toml.ts"
curl -fsSL \
https://raw.githubusercontent.com/Yeachan-Heo/gajae-code/5f2e7cd05e8ea344991566f9ed96f1f9c66226bd/packages/coding-agent/src/setup/provider-onboarding.ts \
-o "$tmp/gajae-provider-onboarding.ts"
curl -fsSL \
https://raw.githubusercontent.com/Yeachan-Heo/gajae-code/5f2e7cd05e8ea344991566f9ed96f1f9c66226bd/packages/coding-agent/src/config/models-config.ts \
-o "$tmp/gajae-models-config.ts"
curl -fsSL \
https://raw.githubusercontent.com/farion1231/cc-switch/main/src-tauri/src/services/provider/live.rs \
-o "$tmp/ccswitch-live.rs"
printf '%s\n' '--- Kimi removal and TOML write ranges ---'
rg -n 'removeProvider|remove_provider|default_model|default_provider|atomicWrite|stringifyToml|writeConfig|writeFile' \
"$tmp/kimi-core-impl.ts" "$tmp/kimi-toml.ts"
sed -n '700,780p' "$tmp/kimi-core-impl.ts"
sed -n '450,535p' "$tmp/kimi-toml.ts"
printf '%s\n' '--- Gajae provider onboarding and write ranges ---'
rg -n 'addApiCompatibleProvider|models\.yml|writeFile|rename|atomic|remove|delete|providers' \
"$tmp/gajae-provider-onboarding.ts" "$tmp/gajae-models-config.ts"
sed -n '1,260p' "$tmp/gajae-provider-onboarding.ts"
printf '%s\n' '--- cc-switch Hermes/OpenClaw removal ranges ---'
rg -n 'remove_hermes_provider_from_live|remove_openclaw_provider_from_live|remove_provider_from_live_config|remove.*provider' \
"$tmp/ccswitch-live.rs"Repository: lidge-jun/opencodex Length of output: 208 🏁 Script executed: #!/bin/bash
set -u
tmp=$(mktemp -d)
trap 'rm -rf "$tmp"' EXIT
fetch() {
url=$1
out=$2
if curl -fsSL "$url" -o "$out"; then
printf 'fetched %s\n' "$url"
else
printf 'failed %s\n' "$url" >&2
fi
}
fetch \
https://raw.githubusercontent.com/MoonshotAI/kimi-code/e22479a62eed9c3b78a67b313f4332c2c0ba967/packages/agent-core/src/rpc/core-impl.ts \
"$tmp/kimi-core-impl.ts"
fetch \
https://raw.githubusercontent.com/MoonshotAI/kimi-code/e22479a62eed9c3b78a67b313f4332c2c0ba967/packages/agent-core/src/config/toml.ts \
"$tmp/kimi-toml.ts"
fetch \
https://raw.githubusercontent.com/farion1231/cc-switch/main/src-tauri/src/services/provider/live.rs \
"$tmp/ccswitch-live.rs"
printf '%s\n' '--- Gajae repository paths at the cited commit ---'
curl -fsSL \
'https://api.github.com/repos/Yeachan-Heo/gajae-code/git/trees/5f2e7cd05e8ea344991566f9ed96f1f9c66226bd?recursive=1' |
jq -r '.tree[] | select(.path|test("provider|models-config|config.*(write|file)|setup-cli"; "i")) | .path' |
head -n 240
printf '%s\n' '--- Kimi removal and TOML write ranges ---'
rg -n 'removeProvider|remove_provider|default_model|default_provider|atomicWrite|stringifyToml|writeConfig|writeFile' \
"$tmp/kimi-core-impl.ts" "$tmp/kimi-toml.ts" || true
sed -n '700,780p' "$tmp/kimi-core-impl.ts"
sed -n '450,535p' "$tmp/kimi-toml.ts"
printf '%s\n' '--- cc-switch removal implementation ---'
rg -n -A 35 -B 12 'remove_hermes_provider_from_live|remove_openclaw_provider_from_live|remove_provider_from_live_config|remove.*provider' \
"$tmp/ccswitch-live.rs" || trueRepository: lidge-jun/opencodex Length of output: 13708 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
analysis = Path("devlog/_plan/260802_client_toggle_api/001_ccswitch_toggle_analysis.md").read_text()
matrix = Path("devlog/_plan/260802_client_toggle_api/002_client_toggle_matrix.md").read_text()
claim = "All four of this unit's target clients"
assert claim in analysis
assert "Kimi provider remove" in matrix
assert "cascades" in matrix
assert "no remove command exists" in matrix
assert "file edit required" in matrix
print("001 classification claim: present")
print("Kimi: vendor removal exists and cascades dependent aliases/defaults")
print("Gajae: vendor add/replace exists; vendor removal is absent")
print("Conclusion: the four clients cannot share an unqualified one-entry removal contract")
PYRepository: lidge-jun/opencodex Length of output: 245 Split the additive classification by client. cc-switch proves entry-scoped removal for Hermes and OpenClaw. Kimi Code removes the provider, dependent model aliases, and matching defaults before rewriting TOML; it is not a one-entry removal contract. Gajae Code provides add/replace only and has no removal command. Mark Gajae Code 🤖 Prompt for AI Agents |
||
|
|
||
| ## 2. Write discipline | ||
|
|
||
| - Provider-specific writers project into native files: Claude -> | ||
| `~/.claude/settings.json`, Codex -> `~/.codex/auth.json` + `config.toml`, | ||
| OpenClaw -> `~/.openclaw/openclaw.json` (JSON5), Hermes -> | ||
| `~/.hermes/config.yaml` (YAML). | ||
| - JSON/TOML/text writes go through a temporary sibling file + rename (atomic on | ||
| Unix; Windows removes the destination first). | ||
| [provider/live.rs#L1015-L1060](https://github.com/farion1231/cc-switch/blob/main/src-tauri/src/services/provider/live.rs#L1015-L1060), | ||
| [config.rs#L273-L351](https://github.com/farion1231/cc-switch/blob/main/src-tauri/src/config.rs#L273-L351) | ||
| - Writer modules preserve unknown fields (`serde(flatten)` extra maps in | ||
| `hermes_config.rs` / `openclaw_config.rs`) and honor the client's own | ||
| config-dir overrides (`HERMES_HOME`, Windows `%LOCALAPPDATA%\hermes`). | ||
| - Health warnings are returned on write (`OpenClawWriteOutcome.warnings`). | ||
|
|
||
| ## 3. Proxy takeover: the *other* kind of toggle | ||
|
|
||
| cc-switch has a second, coarser switch — "proxy takeover" — which is | ||
| backup-and-restore, not provider-entry deletion: | ||
|
|
||
| 1. Enable: start the local proxy if needed, snapshot the app's current live | ||
| config into the DB's live-backup storage, then write proxy | ||
| endpoint/placeholder fields into the client config. | ||
| 2. Disable/stop-with-restore: write the saved snapshot back and delete the | ||
| backup rows. Missing backup -> attempt SSOT/provider reconstruction and | ||
| placeholder cleanup. | ||
| 3. Switching providers *while* takeover is active is a hot switch: the client | ||
| keeps pointing at the local proxy and only the proxy's upstream target | ||
| changes. | ||
|
|
||
| [services/proxy.rs#L730-L820](https://github.com/farion1231/cc-switch/blob/main/src-tauri/src/services/proxy.rs#L730-L820), | ||
| [services/proxy.rs#L1292-L1323](https://github.com/farion1231/cc-switch/blob/main/src-tauri/src/services/proxy.rs#L1292-L1323), | ||
| [services/proxy.rs#L1822-L1865](https://github.com/farion1231/cc-switch/blob/main/src-tauri/src/services/proxy.rs#L1822-L1865), | ||
| [provider/mod.rs#L3004-L3054](https://github.com/farion1231/cc-switch/blob/main/src-tauri/src/services/provider/mod.rs#L3004-L3054) | ||
|
|
||
| For opencodex this pattern is mostly redundant — opencodex *is* the proxy, so | ||
| the client config only ever needs the additive provider entry; there is no | ||
| upstream target to hot-switch inside the client. | ||
|
|
||
| ## 4. Universal endpoint (relay), not a management API | ||
|
|
||
| cc-switch embeds an Axum server (default `http://127.0.0.1:15721`) exposing | ||
| Claude / OpenAI Responses / Gemini routes plus health and status; tools point | ||
| their base URL at it. It is a data-plane relay, **not** a control API — the | ||
| toggle operations live in Tauri commands, and the only URL scheme is | ||
| `ccswitch://v1/import?...` for config import. | ||
| [proxy/server.rs#L100-L145](https://github.com/farion1231/cc-switch/blob/main/src-tauri/src/proxy/server.rs#L100-L145), | ||
| [proxy/server.rs#L291-L366](https://github.com/farion1231/cc-switch/blob/main/src-tauri/src/proxy/server.rs#L291-L366), | ||
| [deeplink/parser.rs#L11-L67](https://github.com/farion1231/cc-switch/blob/main/src-tauri/src/deeplink/parser.rs#L11-L67) | ||
|
|
||
| Main-agent spot-check: `proxy/server.rs` binds | ||
| `config.listen_address:listen_port` via tokio TcpListener (lines 101-145). | ||
|
|
||
| ## 5. What this means for an opencodex toggle | ||
|
|
||
| - The additive per-client writer is the pattern to copy: insert/remove exactly | ||
| one provider entry, preserve everything else, atomic write, health warnings | ||
| on read-back. | ||
| - cc-switch's "is it on?" state is *its own DB record* plus a | ||
| `live_config_managed` marker — it does not re-derive state from the client | ||
| file. An opencodex toggle has no such DB; state must be read back from the | ||
| client config itself (does our entry exist, and does it match what we would | ||
| generate now?). This is a real design divergence, explored in 003. | ||
| - Its exclusive-app machinery (backfill/overwrite) and proxy-takeover | ||
| snapshot/restore solve problems opencodex does not have; neither needs | ||
| porting. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Use the cc-switch state paths from the research result.
Line 47 names
~/.cc-switch/config.jsonas cc-switch-owned state.001_ccswitch_toggle_analysis.mdidentifies~/.cc-switch/cc-switch.dbas the provider store and separatessettings.jsonandbackups/. Update Q1 to distinguish provider state, device settings, and backups. Otherwise, this plan can drive the wrong ownership model.🤖 Prompt for AI Agents