Перейти к содержимому

Install

Это содержимое пока не доступно на вашем языке.

Four ways in. They produce the same working tool — pick by how much machinery you want between you and the files.

# Method Needs Updating Best for
1 Claude Code plugin Claude Code, git access one command (update_check.py --apply), or Claude Code's own auto-update once you switch it on most people
2 Installer script PowerShell or bash one command no plugin system, or an offline zip
3 Manual copy nothing at all one command locked-down machines, air-gapped, "just give me the files"
4 Run in place nothing git pull trying it once without installing

Everything is plain Python using only the standard library. There is nothing to pip install, nothing is compiled and nothing runs in the background. The one thing the kit sends on its own is a version check against api.github.com, at most once a day, after a real round or at session start — so you learn about a release, and the notice names the one command that installs it. With automatic updates on, a script install also downloads that release from github.com at session start. python update_check.py --show-what-would-be-sent prints that request verbatim; MODEL_ORCH_UPDATE_CHECK=0 switches it off. Everything else leaves your machine only when you run a review, to the channels you chose.


python --version

If that fails, install Python from python.org and tick "Add Python to PATH" during setup. On macOS and most Linux systems it is already there, sometimes as python3.


Section titled “Method 1 — Claude Code plugin (recommended)”

This repository is itself a plugin marketplace. In Claude Code:

/plugin marketplace add igorsaevets/ai-second-opinion
/plugin install model-orchestration@review-channels

Then restart the session, or run /reload-plugins.

Updates. Switch them to automatic once — python <plugin folder>/update_check.py --auto-update on, or /plugin → Marketplaces → review-channels → Enable auto-update (details: Automatic updates). Until then, once a day the kit checks GitHub and, when a release is out, tells you at session start (you and the assistant both see it) with the one command that installs it:

python <plugin folder>/update_check.py --apply

On this install path that command runs claude plugin update model-orchestration@review-channels for you — the same thing as typing /plugin update model-orchestration@review-channels inside Claude Code — and asks you to restart the session. Claude Code can also update the plugin by itself, but for a third-party marketplace like this one its auto-update is off by default (measured 2026-09-11 on claude 2.1.268: a stale install stayed stale until plugin update was run). To switch it on: /plugin → Marketplaces → review-channels → Enable auto-update. DISABLE_AUTOUPDATER=1 in your environment also disables plugin auto-updates unless FORCE_AUTOUPDATE_PLUGINS=1 is set. A private repository works exactly the same way — you only need normal git access to it.

Put this in your team repository's .claude/settings.json and anyone who clones it is offered the plugin automatically:

{
"extraKnownMarketplaces": {
"review-channels": {
"source": { "source": "github", "repo": "igorsaevets/ai-second-opinion" },
"autoUpdate": true
}
},
"enabledPlugins": { "model-orchestration@review-channels": true }
}

Download the repository (green Code button → Download ZIP, or git clone), unpack it, and from the root of it:

Windows (PowerShell):

Terminal window
.\install.ps1

macOS / Linux:

Terminal window
./install.sh

It copies the skill into your home directory and runs the doctor. If an install is already there, it hands the whole job to upgrade.py — see Updating — so "install" and "update" are the same command and the same tested code path.

If PowerShell refuses to run the script, it is the execution policy, not the script:

Terminal window
powershell -ExecutionPolicy Bypass -File .\install.ps1

No git, no plugin system, no installer, no elevated permissions. This is the whole procedure:

Copy this folder from the repository:

plugins/model-orchestration/skills/model-orchestration/

To this location on your machine:

Agent / system Destination
Claude Code (Windows) %USERPROFILE%\.claude\skills\model-orchestration\
Claude Code (macOS/Linux) ~/.claude/skills/model-orchestration/
Any agentskills.io agent (Cursor, Codex, Gemini CLI, Kimi, Qwen, etc.) ~/.agents/skills/model-orchestration/
opencode (Windows) %USERPROFILE%\.config\opencode\skills\model-orchestration\
opencode (macOS/Linux) ~/.config/opencode/skills/model-orchestration/

Create the parent skills folders if they do not exist. When you are done, the destination should contain SKILL.md, orchestrate.py, doctor.py and the references/ and systems/ folders — not another folder containing those. Copying to one of the rows is enough for the agent that reads that path; copying to all rows makes the same install work for every agent on the machine.

Copy-paste commands, if you prefer

Windows PowerShell, run from the unpacked repository root:

Terminal window
# Claude Code
$dst = "$env:USERPROFILE\.claude\skills\model-orchestration"
New-Item -ItemType Directory -Force (Split-Path $dst) | Out-Null
Copy-Item "plugins\model-orchestration\skills\model-orchestration" $dst -Recurse -Force
python "$dst\doctor.py"
# Any agentskills.io agent (Cursor / Codex / Gemini / etc.)
$dst2 = "$env:USERPROFILE\.agents\skills\model-orchestration"
New-Item -ItemType Directory -Force (Split-Path $dst2) | Out-Null
Copy-Item "plugins\model-orchestration\skills\model-orchestration" $dst2 -Recurse -Force
# opencode
$dst3 = "$env:USERPROFILE\.config\opencode\skills\model-orchestration"
New-Item -ItemType Directory -Force (Split-Path $dst3) | Out-Null
Copy-Item "plugins\model-orchestration\skills\model-orchestration" $dst3 -Recurse -Force
python "$dst3\doctor.py"

macOS / Linux, from the repository root:

Terminal window
dst="$HOME/.claude/skills/model-orchestration"
mkdir -p "$(dirname "$dst")"
cp -R plugins/model-orchestration/skills/model-orchestration "$dst"
python3 "$dst/doctor.py"
# agentskills.io
dst2="$HOME/.agents/skills/model-orchestration"
mkdir -p "$(dirname "$dst2")"
cp -R plugins/model-orchestration/skills/model-orchestration "$dst2"
# opencode
dst3="$HOME/.config/opencode/skills/model-orchestration"
mkdir -p "$(dirname "$dst3")"
cp -R plugins/model-orchestration/skills/model-orchestration "$dst3"
python3 "$dst3/doctor.py"

Agent did not auto-discover the skill? Use the absolute path — it always works:

Terminal window
python "$HOME/.claude/skills/model-orchestration/orchestrate.py" --ask "your question"
# opencode alt: python "$HOME/.config/opencode/skills/model-orchestration/orchestrate.py" --ask "..."

Getting one folder onto a machine with no internet access: copy it on a USB stick. It is a few hundred kilobytes of text files. That is the entire deployment story.


You can run the scripts straight out of the unpacked repository:

python plugins/model-orchestration/skills/model-orchestration/doctor.py

Everything works — the scripts resolve their own location and find their presets and reference files relative to themselves. The only thing you lose is that Claude Code will not know the skill exists, so you have to invoke the commands yourself rather than asking for a second opinion in plain language.


One command, run from the copy you have. It looks up the newest release on GitHub, downloads the archive pinned to that release's commit, verifies it, backs up your folder, carries your settings across and runs the doctor:

python ~/.claude/skills/model-orchestration/update_check.py --apply # --dry-run to preview

(Windows: %USERPROFILE%\.claude\skills\model-orchestration\update_check.py.) You do not have to remember it: once a day the kit checks for a release — at session start and after a real round — and prints exactly that command when there is one.

1.119.0 adds no new install step and no new environment surface. The free-voice in-round rule reads optional integer env overrides (ORCH_FREE_INROUND_WINDOW, ORCH_FREE_INROUND_RETRY_429, ORCH_FREE_INROUND_RETRY_5XX) if present; nothing changes if they are not set. The four chat panel channels (claudeaiseat, cldesktopseat, cgptseat, cgptdeskseat) ship with enabled: false — they do nothing until an overlay turns them on, and their drivers are the author's local-only tooling.

--apply, the installer and upgrade.py switch automatic updates on — unless you switched them off before (that choice is kept), or you pass --no-auto-update. From then on:

  • Installer / manual copy: a SessionStart hook in ~/.claude/settings.json (it runs the Python that installed it, by absolute path) checks once a day and, when a release is out, installs it at session start — download, verify, back up, keep your settings — and says updated automatically: X -> Y. A failure is reported once and retried the next day; the log is ~/.claude/model-orchestration.updates/auto-update.log.
  • Plugin install: Claude Code's own auto-update for the review-channels marketplace — the autoUpdate flag on its entry in Claude Code's settings.json, the same switch as /plugin → Marketplaces → review-channels → Enable auto-update. Claude Code installs a release during a session (after your first message, within ~10 minutes) and shows Plugin updated; the next session runs it. DISABLE_AUTOUPDATER=1, DISABLE_UPDATES=1 or CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 switch that pass off unless FORCE_AUTOUPDATE_PLUGINS=1 is also set.
python <your install>/update_check.py --status # one VERDICT: OK or FAIL, each FAIL with its fix
python <your install>/update_check.py --auto-update off # or on

Backups of a script install no longer sit next to it in ~/.claude/skills/ (Claude Code loaded each one as another copy of the skill): they go to ~/.claude/model-orchestration.backups/, newest three kept. --dry-run downloads and verifies, then shows the full upgrade report without changing anything; --tag v1.62.0 picks a specific release. For a plugin install the same command goes through claude plugin update (restart the session after); for a git checkout it prints the git pull instead of overwriting anything.

What it trusts, stated plainly: the archive comes over TLS from github.com, pinned to the commit the GitHub API named for the tag, and is refused unless it holds one top-level folder, the skill subtree, every required file, a VERSION equal to the tag, and no path that escapes the folder. There is no signature — the same trust as git clone.

The manual way still works: download the new version (git pull, or the Code → Download ZIP button) and run its upgrade.py from the unpacked folder:

python plugins/model-orchestration/skills/model-orchestration/upgrade.py --dry-run # preview
python plugins/model-orchestration/skills/model-orchestration/upgrade.py # apply

Either way the report names the version you had and the version you are getting, which channels are new and which are gone, and which of your settings it carried across; the old folder is copied to ~/.claude/model-orchestration.backups/<folder>.bak.<timestamp> (outside skills, see above; a non-default folder keeps <folder>.bak.<timestamp> beside it) before anything is written, and the doctor runs at the end.

A plugin install that Claude Code updates by itself (auto-update switched on) needs none of this from 1.7.0 onward — your settings live outside the folder it replaces.

🔴 If you are still on 1.6.x, read this before you update. Your channel settings are in channels.json, inside the folder an update replaces, and an auto-updating plugin replaces it with nobody running anything — so nothing can carry them across on that path. Claude Code keeps the previous plugin version in its cache for 14 days after an update, so the rescue is real but not permanent: run upgrade.py once (it scans that cache and offers to bring the settings over), or simply write the one line of JSON into your settings file yourself. After that, updates stop being able to lose anything.

To an AI assistant asked to "update this to the new version" (or «обнови kit»): run update_check.py --apply from the installed folder, and report the version line it prints. Do not copy files over the old folder, and do not install fresh. If the install has no VERSION file it is older than 1.7.0, which is expected — that release is where a version string first reached an installed copy at all.

Everything you configure — which channels are on — used to live in channels.json, inside the folder that an update replaces. So the documented workflow was: read this file, edit channels.json to enable a channel, and then lose that edit at the next update, silently, whether you used the installer, copied the files by hand, or let the plugin update itself.

From 1.7.0 your settings live in a file outside the skill folder, which nothing can overwrite:

Your system Your settings file
Windows %USERPROFILE%\.claude\model-orchestration.local.json
macOS / Linux ~/.claude/model-orchestration.local.json
{
"channels": {
"goog36flash": { "enabled": true },
"ornemotron3ultra": { "enabled": false }
}
}

What it may change (1.8.0 widened this a lot)

Section titled “What it may change (1.8.0 widened this a lot)”

At the path in the table above — your own home directory — it may change anything a channel or a tier has, and it may add whole new ones. Repoint a model, add a vendor, define your own tier:

{
"channels": {
"mylocal": {
"_new": true,
"kind": "openrouter", "label": "My Channel", "cost": "metered",
"model": "vendor/model-id",
"models": { "vendor/model-id": { "label": "My Model", "data_policy": "metered API" } },
"enabled": true
}
},
"tiers": { "max": { "gemini_thinking_level": "low" } }
}

"_new": true is required when you are adding something, so that a misspelt name fails loudly instead of quietly becoming a second channel.

Since 1.65.0 you no longer have to hand-edit the JSON to add a channel — one command does it:

Terminal window
python orchestrate.py --new-channel codex59nova:codex:gpt-5.9-nova-ultra

NAME:KIND:SLUG. Writes an atomically-renamed block to the file above with _new: true, enabled: true, a models table keyed on the slug, and a [HYPOTHESIS] label so the plan shows the vendor terms are UNKNOWN until you replace them. Refused when the NAME collides with a shipped channel (pick another), when the KIND is unknown to the router, or when your overlay is redirected via MODEL_ORCH_LOCAL (adding a channel needs the home path — same rule the router enforces when it reads the file). The block is a normal overlay entry; edit it by hand afterwards to change label, data_policy, or to add fields the vendor needs (endpoint, provider, etc). For a one-off try of an unlisted slug on an existing channel — no overlay write — use --set <chan>=<slug> instead: accepted for network-API kinds as a HYPOTHESIS (paid 4xx is the honest test); refused for CLI-fixed kinds (agy/opencode/hermes) with the alternative named.

1.7.0 refused all of that, and it was wrong to. Your settings file and channels.json have the same write permissions — anything able to change one can change the other — and channels.json was the file nothing announced at run time. Refusing model here never stopped anybody; it pushed the change into the quieter file. Both are now reported, in the plan, before a penny is spent.

Two conditions, and neither is about trusting you less.

1. A transport change has to be accepted once. Repointing a model, changing provider or kind, adding a channel — anything that decides where a document goes — is applied, printed in the plan with a 🔴, and then a paid round refuses to run until you have said once:

python routing.py --accept-settings

It prints exactly what you are accepting and records it. Change any of it later and the refusal comes back. Why: this file survives every update, so a single write to it — by a mistyped command, or by an AI assistant acting on a poisoned instruction — would otherwise redirect a channel forever, silently. Quiet settings (enabled, how hard it thinks, how much it may read) never need this. If you want a permanent transport change without the step, put it in channels.json: that is now reported field by field in the plan on every run, and an update will replace it, which is the right property for that class.

2. A relocated settings file may only set the quiet knobs. If you point MODEL_ORCH_LOCAL at a different path, only these are accepted from it: enabled, effort, reasoning, thinking_level, max_tokens, fetch_tool, web, timeout, label, notes. A project's own .claude/settings.json can set environment variables for the sessions run inside it, so a repository you cloned can choose that path. Your home directory is yours. Move the file to the default path and everything is accepted, subject to condition 1.

(cost is not on that list, though it looks cosmetic. It decides whether the plan warns you that a channel is expensive, and which channels --ask fans out to.)

Five things make it hard to shoot yourself with:

  • Every run prints the file's path and each value it changed, in the resolved plan, whether or not you were thinking about it. Changes to a transport are marked 🔴. A settings file you forget you wrote is worse than none.
  • The plan also reports edits you made to channels.json, by field, for the same reason — and reminds you that the next update will take them.
  • A name that is not a channel is refused, loudly, with the list of real ones. A typo in a config file otherwise looks exactly like a channel that is off for some other reason.
  • A channel that was renamed still resolves, through the same alias table --only uses. A strict "unknown name" refusal plus a rename upstream would otherwise stop the tool starting, on upgrade day, for people who did nothing wrong.
  • doctor.py names the fields you edited in channels.json, and points at python upgrade.py --migrate, which moves those edits out for you and changes nothing else.

python ~/.claude/skills/model-orchestration/doctor.py

On Windows use %USERPROFILE%\.claude\skills\model-orchestration\doctor.py.

It checks Python, every file, whether each script compiles, the model registry, whether your API key is present (it reports presence and length only, never the value), both command-line tools and their live versions, permissions, and the privacy gate.

Its last line is your exact run command with the real path already filled in. Do not copy a path out of any document, including this one — ask the doctor. Paths in documentation go stale; a probe cannot.

Verifying the behaviour, not just the install

Section titled “Verifying the behaviour, not just the install”
python ~/.claude/skills/model-orchestration/selftest.py

Runs about fifty behavioural checks — partial installs degrade instead of crashing, channel selection is obeyed exactly, and nothing secret-shaped can reach a log or a console. Costs nothing and contacts no vendor. Worth running after any upgrade, and after any change an AI assistant makes for you.


You need at least one channel — the tool runs whatever is available and tells you exactly what it skipped and why. A missing key or a missing CLI is a normal, non-fatal condition, not an error.

No key at all gets you --ask. The opencode CLI runs two free voices (and a free fallback) with no API key and no account — npm install -g @opencode/cli and you are done. (The free Spark 1.3 voice it used to give is gone since 2026-10-17.) For a full review panel, OPENROUTER_API_KEY alone reaches most of the model families here, which is enough for the disagreement this tool exists to produce. Everything else is optional.

what it needs what that unlocks cost
the opencode CLI v2 (npm install -g @opencode/cli) one free voice, in the cheap panel and in --ask (not on a day the free allowance was refused): ocmimo26flashfree (MiMo v2.6 Flash). ocglm53flashfree (GLM 5.3 Flash) and ocdeepseekv41flashfree (DeepSeek V4.1 Flash) start only when named; the Nemotron copy retired in 1.116.1, and ocstep5previewnv (Step 5 Preview on your NVIDIA key) runs only when named since 1.118.0. The free Spark 1.3 (ocspark13free) is gone since 2026-10-17. With an OpenCode Go plan, since 1.120.0, opencode also runs both Muse Spark Contributor voices (ocspark12go, ocspark13go) on the plan, once a workspace owner or admin turns on «Allow paid endpoints that train on request data» in the OpenCode Console, Settings › Privacy (README, «Spark on an OpenCode Go plan») free; the Go plan is an opencode subscription
NVIDIA_NIM_API_KEY (free, below) two free voices on NVIDIA's own endpoint: DeepSeek V4.1 Flash (nvdeepseekv41flash, since 1.118.0; GLM 5.3 Flash, nvglm53flash, is its fallback) and Nemotron 3 Ultra (nvnemotron3ultra); Step 5 Preview, the voice of 1.114.0–1.117.2, by name only free
the Kimi Code CLI — not needed since 1.112.0 (why) nvkimik3 ships switched off: NVIDIA retired its free Kimi K3 on 2026-10-15. Kimi K3 answers in the standard panel through OPENROUTER_API_KEY (kimik3) —
OPENROUTER_API_KEY the largest group — Kimi, Qwen, Gemini, MiMo, Grok, GLM, DeepSeek, the Muse Spark voices where opencode has no Go plan and a free NVIDIA Nemotron, all on one account metered per token, plus per web search; the Nemotron model itself is free
MODEL_API_KEY the Muse Spark voices reached directly from Meta metered API
the Codex CLI, signed in codex your existing subscription
the Claude Code CLI, signed in cclopus46 — Claude Opus, off by default; runs with permission prompts bypassed, see its section below your existing subscription
the Antigravity CLI, signed in the agy Gemini channels free on a personal Google account, with weekly limits; Google AI plans raise them
the Grok Build CLI, signed in grokbuild — Grok, and it opens pages itself an xAI account; SuperGrok plans raise the limits
GEMINI_API_KEY Gemini on Google's own API — the best-grounded channel here, and the only one whose citations carry character spans. Off by default, see below metered, free tier available
XAI_API_KEY Grok on xAI's own API — adds X/Twitter search and reports the dollar cost of each call. Off by default metered
MIMO_API_KEY MiMo on Xiaomi's own API — its search opens whole pages instead of returning excerpts. Off by default metered

🔴 Do not count the channels from this file. The number is whatever channels.json enables, and it has changed most weeks. Run python routing.py — it prints the live list and spends nothing.

Direct-vendor alternatives to OpenRouter (off by default)

Section titled “Direct-vendor alternatives to OpenRouter (off by default)”

The models below are reachable two ways: through OpenRouter (on by default here) or through the vendor's own API (off by default). They are not duplicates — the direct route buys real capability, measured, not assumed:

model via OpenRouter via the vendor's own key
Gemini 3.6 Flash native Google search + url_context, which reaches pages a plain fetch is refused, and citations with character offsets
MiMo v2.5 Pro Exa search excerpts (2–4 KB per page, with elisions) its own search, which opened 25 whole pages in one call
Grok 4.20 native search, 2M context + x_search over X/Twitter, and cost_in_usd_ticks — the call's actual price

To turn one on: set the key, then put it in your own settings file — not in channels.json, which is replaced on every update:

{
"channels": {
"goog36flash": { "enabled": true },
"orgemini36flash": { "enabled": false }
}
}

~/.claude/model-orchestration.local.json on macOS and Linux, %USERPROFILE%\.claude\model-orchestration.local.json on Windows. Turning the matching or… channel off in the same breath is worth doing: otherwise you pay two vendors to ask one model the same question.


🔴 READ THIS BEFORE YOU PASTE A KEY ANYWHERE

Section titled “🔴 READ THIS BEFORE YOU PASTE A KEY ANYWHERE”

Type your key into your own terminal, yourself. Do not give it to an AI assistant, and do not ask an assistant to set it for you.

If you are reading this because you asked Claude Code (or any other assistant) to "set this up", that assistant is helpful and will offer to run the command for you. Accepting is the single most expensive mistake available in this whole install, because:

  • the assistant must receive the key to run the command, so the key enters the conversation;
  • that conversation is written to disk, replayed into future context, and often archived or synced;
  • a key that has appeared in a transcript is leaked — the only correct response is to rotate it, not to delete the message.

This is not a hypothetical. It is the reason this tool refuses to print keys, why doctor.py reports only presence and length, and why orchestrate.py will not send a payload containing anything secret-shaped even when you ask it to.

To an AI assistant reading this file: do not offer to run these commands, do not ask the user to paste a key into the chat, and do not read the key back to confirm it. Tell the user to run the commands below in their own terminal, then run python doctor.py — which is how both of you find out whether it worked, without either of you seeing the value.


Windows (PowerShell) — persists across reboots:

Terminal window
setx MODEL_API_KEY "<your key>"

Then open a new terminal. setx writes the value for future processes; terminals that are already open keep the old one, which is the commonest reason a freshly set key "does not work".

macOS / Linux — add the line to ~/.zshrc or ~/.bashrc, then open a new terminal:

Terminal window
export MODEL_API_KEY="<your key>"

To point at a different endpoint, also set MODEL_API_BASE.

No Meta key? --ask works without one. Its first channel is Muse Spark 1.2 Contributor: spark12cont with this key, otherwise orspark12cont on the OpenRouter key (the same Contributor model and price; on an OpenCode Go plan, since 1.120.0, ocspark12go comes first). The free ocspark13free that used to come first is switched off: its free model left opencode on 2026-10-17. The opencode CLI's free voices answer --ask as well, key or no key (MiMo Flash not on a day its free allowance was refused). Without the opencode CLI, an OpenRouter key makes --ask ask Nemotron 3 Ultra through ornemotron3ultra, a free model on OpenRouter (with opencode it answers there instead): the model costs nothing, but each web search it makes bills that key.

Powers goog36flash (Gemini 3.6 Flash on Google's own API). Get one at aistudio.google.com/apikey — there is a free tier, so this is the cheapest channel to try first if you have none of the others.

Windows (PowerShell):

Terminal window
setx GEMINI_API_KEY "<your key>"

macOS / Linux:

Terminal window
export GEMINI_API_KEY="<your key>" # add to ~/.zshrc or ~/.bashrc to persist

Close and reopen the terminal afterwards — setx and shell profiles only affect new sessions.

This channel is worth having even beside the OpenRouter one that runs the same model: it uses Google's own retrieval (google_search + url_context), which reaches pages a plain HTTP fetch is refused, and its citations carry start_index/end_index into the answer text — so "which sentence does this source support" is a lookup rather than a judgement. One caveat measured: citations produced by google_search come back as vertexaisearch.../grounding-api-redirect/... wrappers rather than the publisher's URL; only url_context citations are the real address. Each wrapper does carry the publisher domain in its title, and the citation audit follows the wrapper's redirect to recover the full URL — so these citations are checkable, which is not what this paragraph said before 2026-08-08. Note the documentation's own example shows publisher URLs in that field; the live endpoint does not. A response example in vendor docs is an illustration, not a schema.

Optional and free, since 1.114.0. One key gives two voices on NVIDIA's own free endpoint, both API calls: DeepSeek V4.1 Flash (nvdeepseekv41flash, since 1.118.0; Step 5 Preview held this seat until 1.117.2) and Nemotron 3 Ultra (nvnemotron3ultra). GLM 5.3 Flash on the same key (nvglm53flash) answers once, after the round, when DeepSeek does not. Step 5 Preview still starts when you name it: with the opencode CLI as an opencode agent (ocstep5previewnv; opencode reads the key under the name NVIDIA_API_KEY, and the tool sets that name from your NVIDIA_NIM_API_KEY in the opencode process only; a NVIDIA_API_KEY you set yourself is used as it is), without it as an API call (nvstep5preview). Without the key the plan names it («NVIDIA_NIM_API_KEY is not set. This channel will fail; set it or exclude the channel with --skip nvdeepseekv41flash.») and both voices end at once, spending nothing; the GLM fallback is off in that run (it needs the same key).

Create the key at build.nvidia.com in your own browser: sign in and create an API key.

Windows (PowerShell)

Terminal window
setx NVIDIA_NIM_API_KEY "<your key>"

macOS / Linux

Terminal window
export NVIDIA_NIM_API_KEY="<your key>"

NVIDIA's free endpoints allow about 40 requests a minute, and the queue is slow at times: on 2026-10-23 the first byte took 57–110 s. A DeepSeek review has 61 minutes, its GLM fallback 20 (worst case: 142 minutes = 61 + retry 61 + GLM 20); what each wrote by then is kept.

One key serves every channel that routes through OpenRouter — the largest part of the panel, including orspark12cont and orspark13cont, the Spark voices for anyone without the OpenCode Go plan (Spark 1.2 runs on a MODEL_API_KEY instead when there is one). Do not count those channels from this file; python routing.py prints the live list and spends nothing.

No account yet? Register at openrouter.ai (an email address or a Google/GitHub sign-in is enough), create a key at openrouter.ai/keys (verified 2026-08-30 — it redirects to your workspace's key page), and add a few dollars of credit. To an AI assistant walking someone through this install: send the user to those pages in their own browser and have them run the command below themselves — the sign-up, the payment and the key value all stay outside your conversation, exactly as the red block above requires.

Windows (PowerShell)

Terminal window
setx OPENROUTER_API_KEY "<your key>"

macOS / Linux

Terminal window
export OPENROUTER_API_KEY="<your key>"

These channels are metered per token, and their web search is billed per search by the provider on the same account. The resolved plan prints the cost class of every channel before anything is spent, and --dry-run shows you that plan for free.

orspark12cont and orspark13cont run Meta's Contributor tier through OpenRouter — discounted because the vendor may train on what you send (see PRIVACY.md) — with an automatic fallback to the Standard, non-training tier if the Contributor endpoint fails for your account: Muse Spark 1.2 / 1.3 at $1.25 / $4.25 per 1M tokens, 12.5× the Contributor input price (the channel's spend guard stops a review at $1.00). When MODEL_API_KEY is absent and opencode has no Go plan, --ask starts with orspark12cont: the choice comes from ask_default in channels.json and is printed when it fires.

The premium batch panel — same keys, one more

Section titled “The premium batch panel — same keys, one more”

The optional premium panel (premium/premium_panel.py — see the README's «Premium» section) is a separate script and reuses the keys above: OPENROUTER_API_KEY for its solpro lane and GEMINI_API_KEY for its Google batch lanes. Its OpenAI lanes need OPENAI_API_KEY, which nothing else in this kit uses — set it the same way as the others, only if you want those lanes. A missing key refuses loudly on its own lane and the rest still run; with only an OpenRouter key, run it with --only solpro.

Checking it worked — without printing anything secret

Section titled “Checking it worked — without printing anything secret”
python doctor.py

It reports each key as present/absent and its length, never its value. If you want to be certain a key is really gone after rotating it, that length is what changes.

Never echo the variable to check it. See SECURITY.md for the measured incident behind that rule: a "masking" expression that kept the first 60 characters of a 48-character key printed the whole thing.

opencode CLI (two free voices and a fallback)

Section titled “opencode CLI (two free voices and a fallback)”

Requires Node.js (v18 or newer). If npm is not on your PATH, install Node.js from nodejs.org first — tick "Add to PATH" on Windows; on macOS brew install node; on Linux use your package manager.

npm uninstall -g opencode-ai # only if you have the old package: it is opencode v1
npm install -g @opencode/cli
opencode --version # must print 2.x

The package opencode-ai is the v1 line (1.19.2 on 2026-10-16). The harness speaks v2 (model#variant, run --standalone); on v1 those calls fail at once and the harness says so.

No key, no account, no sign-in for the opencode/ models whose names end in -free. This installs the opencode CLI from opencode.ai; the cheap panel's two free voices run through it: MiMo v2.6 Flash (ocmimo26flashfree) and Nemotron 3 Ultra (ocnemotron3ultrafree). GLM 5.3 Flash (ocglm53flashfree) is MiMo Flash's fallback and DeepSeek V4.1 Flash (ocdeepseekv41flashfree) starts only when named; all four ran live on 2026-10-18. They are free relays: one can disappear — opencode stopped serving its free Muse Spark 1.3 on 2026-10-17 (provider.no-route) — and MiMo, GLM and DeepSeek draw on one daily allowance of requests per network address, refused with provider.quota once it is used up, until 00:00 UTC (the README's cheap panel section says what the harness then does). The run says so for that voice and what to do; opencode models is the live list.

--ask goes to the free voices too, except one whose free allowance was refused earlier this UTC day; with every key and CLI it asks 4 channels (Muse Spark, MiMo v2.6 Flash, Nemotron 3 Ultra, DeepSeek V4.1 Flash), 3 on such a day. Since 1.115.1 its line «--ask goes to N channel(s): …» is read off the final plan: it names who starts, and after «not started:» who does not and why («quota group «opencode-free» refused earlier today», «one voice with »). Nemotron 3 Ultra runs, but its answer is not printed: channels.json marks every Nemotron channel never_read, and --ask prints one line «ANSWER [] … NOT PRINTED … its file: » in its place. Its first channel is Muse Spark: ocspark12go on an OpenCode Go plan (since 1.120.0), otherwise one that needs a key: spark12cont (MODEL_API_KEY) or orspark12cont (OPENROUTER_API_KEY), both paid. On a machine with neither, that line fails with «MODEL_API_KEY not set»; that is not fatal, and the free voices still answer.

If the CLI is absent, the others work the same as before. The two free voices stay in the plan as [RUN ] and each fails at dispatch with «binary not found», spending nothing (MiMo Flash's fallback is OFF in that run; say "without opencode" to leave them out), and Nemotron 3 Ultra then answers the standard panel through OpenRouter (ornemotron3ultra). doctor.py reports whether the CLI is found and where. If yours is installed in an unusual location, set OPENCODE_BIN to the full path.

Kimi Code CLI (retired: free Kimi K3 through NVIDIA)

Section titled “Kimi Code CLI (retired: free Kimi K3 through NVIDIA)”

Not needed since 1.112.0. From 1.106.0 to 1.111.5 the cheap panel had a free Kimi K3 voice, nvkimik3: the Kimi Code CLI (github.com/MoonshotAI/kimi-code) talking to NVIDIA's free endpoint with an NVIDIA_NIM_API_KEY. NVIDIA retired that model on 2026-10-15 at 08:00 UTC: the endpoint answers HTTP 410 «end of life», on every key.

Since 1.112.0 nvkimik3 ships switched off and the cheap panel has no Kimi voice. Kimi K3 answers in the standard panel through OpenRouter (kimik3, about $1.38 a run), and «only kimi» / --only kimi starts that channel alone. If you installed the CLI for the free route, nothing uses it any more; keep the NVIDIA_NIM_API_KEY: DeepSeek V4.1 Flash (Step 5 Preview until 1.117.2) and Nemotron 3 Ultra use it (NVIDIA). If you start nvkimik3 by name anyway, the run ends with the 410 and names the cause: the vendor has retired the model.

Muse Code CLI (Muse Wonder on a Muse Code subscription)

Section titled “Muse Code CLI (Muse Wonder on a Muse Code subscription)”

Optional, since 1.111.0. With it, Muse Wonder (mcwonder10cont) runs on your Muse Code subscription instead of a per-token key. Since 1.113.0 Wonder is in no panel: it starts only when you name it ("only wonder", "add wonder", «вондер», or a channel's own name).

  1. The CLI and a sign-in. Install Muse Code from Meta's documentation (dev.meta.ai/docs/muse-code) and sign in once with the account that holds the subscription: muse login. The plan must include Muse Wonder.
  2. Check it with one real call (it uses a little of your plan): python ~/.claude/skills/model-orchestration/orchestrate.py --ask "Reply with the word OK" --only mcwonder10cont (a plugin install has the same file in its plugin folder). It prints the answer, OK; if Muse Code is not signed in, the run says so and how to fix it. A command that only resolves the model name proves nothing: muse model-profile show prints a profile for any id, an invented one too. On Windows, muse sandbox windows check should print status=ready (the CLI's shell sandbox); if not, muse sandbox windows setup.

The harness finds the binary through MUSE_BIN, then (Windows) the muse-bin-<version>.exe named in %LOCALAPPDATA%\Programs\muse\.muse-version, then muse on PATH. It never passes an API key to this CLI: with META_API_KEY set, Muse Code bills that key instead of the plan, so the harness keeps it out of the CLI's environment. The run has no file writes, no shell and no approval prompts (--disable-approval --disable-write --disable-shell); it is offered only the built-in web_search and web_fetch (-c run.toolset): the MCP servers in your Muse Code settings still start, but the reviewer cannot call them. Without Muse Code, "only wonder" / «вондер» stops before paying and names the paid Wonders: wonder10 (MODEL_API_KEY, pay-as-you-go) and orwonder (OpenRouter, stops at $5 a run); name one to run it. To seat Wonder in the standard panel again on your subscription, as before 1.113.0, put this in ~/.claude/model-orchestration.local.json:

{ "channels": { "mcwonder10cont": { "explicit_only": false } } }

The registry also holds Muse Code channels for Muse Spark 1.3 (mcspark13, its fallback mcspark12) and Wonder Standard (mcwonder10). They ship switched off (the kit's Spark voices run through opencode's Go plan or an API) and start when you name one or switch it on in your settings file; musecode / «muse code» is a group word, and like every group it runs only the members that are on. Since 1.113.8 every Muse Code call passes --contributor-mode from the channel's model id: with contributor mode on in Muse Code's own settings, a request for the Standard muse-spark-1.3 was answered by the Contributor model (measured 2026-10-22).

Install the Codex CLI and sign in with an account whose plan includes it:

codex --version
codex login

No key needed — it uses your subscription. If you do not have one, run with --skip codex.

Claude Code CLI (Claude Opus — off by default)

Section titled “Claude Code CLI (Claude Opus — off by default)”

Install the Claude Code CLI and sign in with a Claude subscription:

npm install -g @anthropic-ai/claude-code
claude auth login
claude auth status

The channel is cclopus46 and it ships disabled. Run it for one round with --only cclopus46, or set "enabled": true on it in channels.json. No key is used: the channel removes ANTHROPIC_API_KEY and ANTHROPIC_AUTH_TOKEN from the CLI's environment on purpose, because with either set the CLI bills that key instead of your subscription.

🔴 Read before enabling. The CLI is launched with --permission-mode bypassPermissions: every built-in tool — shell, file edits anywhere on your machine, web — and every MCP server configured in your Claude Code run without a permission prompt, on a brief that is untrusted input. A headless run cannot prompt, and without that mode the reviewer's fetches and commands were silently denied (measured 2026-09-11). Your permissions.deny rules and hooks still apply in this mode; SECURITY.md has the full picture. If that is not acceptable on the machine you run this from, leave the channel off — the panel does not need it.

grok --version # expect: grok 1.0.4 (…) [stable] or newer
grok login

No key needed — it authenticates with a subscription session, and the channel carries no API key at all. If you do not have a Grok subscription, run with --skip grokbuild; a missing CLI is reported and skipped, not fatal.

🔴 The binary is not on PATH on Windows. The harness looks in %USERPROFILE%\.grok\bin before giving up, so a default install is usually found without configuration. If yours is elsewhere, set GROK_BIN to the full path. python doctor.py prints which CLIs it found and where.

What this channel is, and what it is not. It is an agentic coding CLI pointed at a review brief, and that is the whole difficulty: it runs the tool loop itself, opens pages itself, and takes several minutes. In exchange it produced the longest and most-cited answer of any channel in the panel it was first enabled for. Three things are configured for you and should not be undone:

  • --allow WebFetch. Without it the CLI silently denies any page fetch outside its own vendor's domain, and one denied tool discards the whole turn — you get a couple of hundred bytes of planning narration and stopReason: cancelled, with nothing saying why. Note the spelling: --allow wants WebFetch, --tools wants web_fetch, and the wrong one is accepted while granting nothing.
  • --disallowed-tools search_tool,use_tool. These are the CLI's gateway to whatever MCP servers you have configured, and --tools does not bound them. They are removed rather than granted because a review brief is untrusted input and your MCP servers may hold credentials. Web search and page fetching are unaffected — they are built in, not MCP.
  • No file tools. --cwd bounds where the agent starts, not what read_file can open, so the read tools are not granted at all.

Imports from Claude Code, Cursor and Codex switched off (since 1.111.2) — plugins excepted. Out of the box Grok Build loads the MCP servers in your ~/.claude.json, your Claude Code skills, rules (your global CLAUDE.md), agents and hooks, and the same parts of Cursor and Codex. For a review that meant your own instructions went to xAI with every brief, and on 2026-10-13 one MCP server imported from ~/.claude.json hung every run until the 40-minute timeout. The harness starts Grok with GROK_CLAUDE_MCPS_ENABLED=0 and the 17 sibling switches (GROK_<CLAUDE|CURSOR|CODEX>_<SKILLS|RULES|AGENTS|MCPS|HOOKS|SESSIONS>_ENABLED=0). Ten of them are in xAI's settings reference; the SESSIONS and CODEX ones exist only in the binary (measured on grok 1.0.52). Since 1.111.3 every run first asks grok inspect --json (no model call, under half a second) whether this grok honoured them, and the run log says «imports verified off». Since 1.111.4, if a newer grok ignores a switch and would load an imported item, Grok is not started and the brief is not sent: the error names the surfaces, and [compat.claude] / [compat.cursor] in ~/.grok/config.toml turn them off. A switch that is on with nothing behind it is a 🔴 note on the run. Still loaded, because Grok has no switch for them: Claude Code plugins (with any skills, hooks or MCP servers they bring) and the files in ~/.grok/rules/ (the preflight lists them). A reviewer keeps Grok's own config: the MCP servers in ~/.grok/config.toml, your shell logins, Grok's own skills. In --task mode Grok works in the task folder and reads that project's AGENTS.md, as it would for you. If a run still times out, the error quotes Grok's own session record (found by the --session-id the harness gives each run): the tool that started and never finished, and the MCP servers that failed at start. Your own grok sessions are unaffected; to keep them from importing too, set GROK_CLAUDE_MCPS_ENABLED=0 (and any of the others) in your user environment, or mcps = false under [compat.claude] in ~/.grok/config.toml.

agy --version

Then the one post-install step that is not optional:

python ~/.claude/skills/model-orchestration/patch_agy_permissions.py --dry-run # preview
python ~/.claude/skills/model-orchestration/patch_agy_permissions.py # apply

Why this is mandatory, measured 5 runs out of 5: running headless, this CLI cannot show a permission prompt, so any tool still set to "ask" is auto-denied — and one denial silently throws the entire run away. You get an empty answer, a status of SUCCESS, and exit code 0, after dozens of successful tool calls. Nothing in the exit code, the status field or the elapsed time reveals it. With the patch applied, the same document went from an empty answer to 49 tool calls.

The script edits one settings file, is additive and idempotent, backs up before writing, and has --revert. It also blocks metered crawling tools that bill per page with no ceiling — which is why, for this CLI, the answer to a permissions problem is never --dangerously-skip-permissions. (The Claude Code CLI channel is the deliberate exception — its own section above says what that costs.)

doctor.py re-checks this on every run and tells you if it has been reverted.

The plain gemini CLI is not a substitute — on a personal-tier account it fails with an ineligible-tier error.


Delete the folder:

Your system Delete
Windows %USERPROFILE%\.claude\skills\model-orchestration\
macOS / Linux ~/.claude/skills/model-orchestration/

If you installed as a plugin, /plugin uninstall model-orchestration@review-channels.

Nothing is written anywhere else — no registry keys, no services, no scheduled tasks. The only other thing it creates is the output folder for each review, wherever you pointed --out.

If you ran patch_agy_permissions.py, it left a timestamped backup of the file it changed alongside the original, and --revert restores it.