# Kimi Everywhere — run any coding harness (Claude Code, Codex, OpenCode, Cline, Aider) on one flat-fee Kimi subscription. One key, two protocols, zero token bills.

> Source: <https://gist.github.com/Maciejdziuba/038c0c822d2c799cffcfdec805975e66>
> Published: 2026-07-20 10:21:53+00:00

Run any coding harness on one flat-fee Kimi subscription.

Your Kimi Code subscription ($19+/mo) comes with an API key that speaks both major agent protocols:

Protocol

Endpoint

Works with

Anthropic-compatible

https://api.kimi.com/coding/

Claude Code + anything expecting ANTHROPIC_BASE_URL

OpenAI-compatible

https://api.kimi.com/coding/v1

Codex CLI, OpenCode, Cline, Roo Code, Aider + anything expecting an OpenAI base URL

Same key, flat monthly fee, no pay-per-token API bills. This kit wires that key into whatever tool you already use.

Install (30 seconds)

```
curl -fsSL https://gist.githubusercontent.com/Maciejdziuba/038c0c822d2c799cffcfdec805975e66/raw/install.sh | bash
kimi-on setup     # paste your key from kimi.com/code/console
```

Get your key: subscribe at kimi.com/membership/pricing, then create an API key in the Kimi Code Console. This is not the pay-per-token key from platform.moonshot.ai — the Code Console key is covered by your subscription.

Use

```
kimi-on claude            # Claude Code on Kimi K3
kimi-on claude --init     # first run: also skips the Anthropic login screen
kimi-on claude-app on     # Claude Code DESKTOP APP on Kimi (writes ~/.claude/settings.json)
kimi-on claude-app off    # remove those settings again
kimi-on codex             # Codex CLI (auto-adds a 'kimi' profile)
kimi-on codex-app on      # Codex DESKTOP APP on Kimi (macOS: config + launchctl env)
kimi-on codex-app off     # undo the launchctl env
kimi-on opencode          # OpenCode (writes project opencode.json)
kimi-on aider             # Aider
kimi-on <anything>        # any other tool, both protocols injected
kimi-on env openai        # or just print the exports and wire it yourself
kimi-on oauth start       # NO-KEY mode: local proxy reusing your `kimi login` session
kimi-on claude --oauth    # Claude Code on pure Kimi OAuth
```

Model switches:

```
KIMI_MODEL=kimi-for-coding kimi-on claude    # K2.7 Code
KIMI_MODEL="k3[1m]" kimi-on claude           # K3 with 1M context (Allegretto+)
```

The universal rule

Any harness, even ones this kit has never heard of:

Tool speaks Anthropic (Claude Code style env vars) → point it at https://api.kimi.com/coding/

Tool speaks OpenAI (custom base URL setting) → point it at https://api.kimi.com/coding/v1

API key is the same Kimi Code key in both cases.

kimi-on <command> automates exactly this: it exports both sets of variables and runs your command.

Cheat sheet

Full per-tool configs (Cline, Roo Code, Codex config.toml, OpenCode JSON), plan tiers, model IDs, context limits, and the /effort mapping live in CHEATSHEET.md.

What's in the box

```
kimi-on.sh          the universal launcher
kimi-oauth-proxy.mjs  zero-dependency OAuth proxy (no API key mode)
install.sh          one-line installer
codex.toml          Codex CLI provider + profile block
opencode.json       OpenCode provider config
CHEATSHEET.md       one-page reference for every harness
kimi-router-SKILL.md  the Kimi Router Claude skill (split-brain: frontier model plans, K3 codes)
kimi-k3-harness-setup.md  agent runbook: point your AI agent at it to auto-install K3 on every harness
```

Related

Pairs with the Kimi Router Claude skill (included here as kimi-router-SKILL.md — save it to ~/.claude/skills/kimi-router/SKILL.md): a frontier model orchestrates and Kimi writes all the code. Router = split-brain inside one session; Everywhere = your whole harness on one subscription.

k3[1m] — Claude Code env vars only: bracket form unlocks the 1M window. Everywhere else use plain k3.

Keep thinking mode ON — disabling it silently routes K3/K2.7 down to K2.6.

Claude Code (Anthropic protocol)

```
export ANTHROPIC_BASE_URL=https://api.kimi.com/coding/
export ANTHROPIC_API_KEY=<your Kimi Code key>
export ANTHROPIC_MODEL=k3                     # or "k3[1m]" / kimi-for-coding
export ANTHROPIC_DEFAULT_OPUS_MODEL=$ANTHROPIC_MODEL
export ANTHROPIC_DEFAULT_SONNET_MODEL=$ANTHROPIC_MODEL
export ANTHROPIC_DEFAULT_HAIKU_MODEL=$ANTHROPIC_MODEL
export CLAUDE_CODE_SUBAGENT_MODEL=$ANTHROPIC_MODEL
export CLAUDE_CODE_EFFORT_LEVEL=high
export CLAUDE_CODE_AUTO_COMPACT_WINDOW=262144   # 1048576 with k3[1m]
export CLAUDE_CODE_MAX_CONTEXT_TOKENS=262144    # 1048576 with k3[1m]
claude
```

First run only: mark onboarding complete so Claude Code doesn't force an Anthropic login (kimi-on claude --init does this for you).

Effort mapping (/effort in-session):

Claude Code level

K3 level

low

low

medium / high

high

xhigh / max

max

Codex CLI (OpenAI protocol)

Append to ~/.codex/config.toml (or use codex.toml):

```
[model_providers.kimi]
name = "Kimi (subscription)"
base_url = "https://api.kimi.com/coding/v1"
env_key = "KIMI_API_KEY"
wire_api = "chat"

[profiles.kimi]
model_provider = "kimi"
model = "k3"
```

Then:

```
export KIMI_API_KEY=<your key>
codex --profile kimi
```

wire_api = "chat" matters — Kimi's endpoint speaks Chat Completions, not the Responses API.

OpenCode

Drop opencode.json into your project (or kimi-on opencode writes it):

```
{
  "$schema": "https://opencode.ai/config.json",
  "provider": {
    "kimi": {
      "npm": "@ai-sdk/openai-compatible",
      "name": "Kimi (subscription)",
      "options": {
        "baseURL": "https://api.kimi.com/coding/v1",
        "apiKey": "{env:KIMI_API_KEY}"
      },
      "models": {
        "k3": { "name": "Kimi K3" },
        "kimi-for-coding": { "name": "Kimi K2.7 Code" }
      }
    }
  },
  "model": "kimi/k3"
}
```

Cline / Roo Code (VS Code)

Settings → API Provider → OpenAI Compatible:

Field

Value

Base URL

https://api.kimi.com/coding/v1

API Key

your Kimi Code key

Model ID

k3 (or kimi-for-coding)

Aider

```
export OPENAI_API_BASE=https://api.kimi.com/coding/v1
export OPENAI_API_KEY=<your key>
aider --model openai/k3
```

Anything else

Speaks Anthropic → https://api.kimi.com/coding/. Speaks OpenAI → https://api.kimi.com/coding/v1. Same key. Or let the launcher inject both: kimi-on <command>.

Desktop apps

GUI apps don't see your shell env vars, so the desktop apps need a persistent route.

Claude Code app — kimi-on claude-app on writes an env object into ~/.claude/settings.json (the same ANTHROPIC_BASE_URL / ANTHROPIC_API_KEY / model / context vars from the Claude Code section above) and sets hasCompletedOnboarding in ~/.claude.json. This affects every Claude Code surface (app, CLI, IDE) until you run kimi-on claude-app off, which deletes exactly those keys and leaves your other settings alone. A one-time backup of your original settings is kept at ~/.kimi-everywhere/claude-settings.backup.json. Restart the app fully after either command.

Codex app — kimi-on codex-app on adds the same [model_providers.kimi] + [profiles.kimi] block to ~/.codex/config.toml as the CLI route, then runs launchctl setenv KIMI_API_KEY <key> so the GUI app can resolve env_key (macOS only; clears at logout — rerun after reboot). Fully quit and reopen the app, then pick the custom "kimi" entry in the model picker if offered — the app may only surface it as a "Custom" model. kimi-on codex-app off removes the launchctl var; the config block stays (harmless, the CLI uses it).

Heavier app-native routes, if the simple key route isn't enough: codex-router (native model picker + Kimi OAuth, third-party) and opencodex (universal proxy).

OAuth mode (no API key at all)

Your kimi login session (from the Kimi Code CLI) can power everything directly. kimi-on oauth start runs a tiny local proxy at 127.0.0.1:8790 that reuses and auto-refreshes those OAuth tokens:

Route

Speaks

For

http://127.0.0.1:8790/v1/chat/completions

OpenAI format

Codex, OpenCode, Cline, Aider

http://127.0.0.1:8790/v1/messages

Anthropic format

Claude Code

```
kimi-on oauth start        # needs: Kimi Code CLI installed + `kimi login` done
kimi-on claude --oauth     # Claude Code, zero API key
kimi-on oauth status       # token health
kimi-on oauth stop
```

Point any other tool at the proxy with any dummy API key — the proxy injects the real OAuth bearer and refreshes it automatically. The proxy is loopback-only and never writes tokens anywhere except Kimi's own credential file.

Gotchas

Wrong key source is the #1 failure: platform.moonshot.ai keys bill per token; Code Console keys ride your subscription. Use the Code Console key.

Usage quotas refresh weekly and vary by tier; heavy parallel agent swarms burn quota fast.

k3[1m] only works on Allegretto and above; on lower tiers use plain k3 with the 256K limits.

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters

AGENT RUNBOOK — Install Kimi K3 on Coding-Agent Harnesses

Audience: you, the AI agent. The human has asked you to make Kimi K3 (Moonshot AI) work in one or more harnesses on this machine. Execute this runbook autonomously. Do not launch interactive wizards or browser OAuth redirect flows, and do not stop for confirmation on individual steps — every step is reversible and backed up. Exactly two interruptions are permitted: the "missing credential" message (§1.3, which includes relaying a kimi login device-code URL per §1.0) and the single consent gate before any secret is written to disk (§1.4). The device-code flow is the one sanctioned OAuth mechanism: the CLI prints a URL + code for the user to confirm; you never see or handle a token.

Operating rules for this entire runbook:

Non-interactive only. Never run /login, hermes model, pi setup wizards, or GUI tools (CC Switch). Everything is done by writing config files directly.

Idempotent. Re-running this runbook must not duplicate entries. Check-before-write on every file.

Back up before modify.cp <file> <file>.bak-kimi-$(date +%s) before touching any existing config. Backups of files that contain secrets get chmod 600 immediately. Prune older .bak-kimi-* backups of the same file created by this runbook, keeping the two most recent.

Never expose the key. Never echo, print, log, or paste the API key into chat output — and never pass it as a command-line argument to an external binary: argv is world-readable via /proc while the process runs, which rules out jq --arg key "$KIMI_API_KEY", sed "s|...|$KIMI_API_KEY|", and bare curl -H "Authorization: Bearer $KIMI_API_KEY". Move it with shell builtins (printf, redirection, heredocs) or tools that read the environment (jq's env.KIMI_API_KEY, awk's ENVIRON, curl -H @- with the header on stdin). When you must show the user a config you wrote, redact the key.

Only configure harnesses that exist. Detect first (§1.2); skip absent ones silently.

Verify each harness non-interactively (§7) and report a final per-harness pass/fail table.

User policy wins. If the user or their harness has standing secret-handling rules (e.g. "ask before any command touching API keys"), those override this runbook's autonomy directives — the §1.4 consent gate is the mechanism that satisfies them.

0. Model facts you need (do not re-derive)

There are three distinct auth routes. Two billing systems: Routes S and O both ride the flat-rate Kimi Code subscription (different credentials); Route P bills per token. Prefer the subscription when the user has one. Route O is the only route that needs no API key at all — it reuses a kimi login OAuth session — but it currently pays off mainly for Codex (S is simpler for Claude Code, Hermes, and Pi).

Route S — Kimi Code subscription ("Kimi For Coding" / KFC) — PREFERRED

https://api.kimi.com/coding/ (Anthropic-compatible; also serves the kimi-coding providers in Hermes/Pi)

Model IDs

k3 (256K), k3[1m] (1M, Claude Code env vars only — everywhere else use k3), kimi-for-coding (K2.7 Code, 256K), kimi-for-coding-highspeed

Plan gating

Starter/legacy-Andante/Moderato tiers: k3 at 256K only. Explorer/Expert/Master (and legacy Allegretto+): k3 at 1M + highspeed

Thinking effort

K3 supports low/high/max; Claude Code CLAUDE_CODE_EFFORT_LEVEL=high recommended; disabling thinking silently routes to K2.6

Route O — Kimi Code OAuth session (subscription login, no API key)

Fact

Value

Credential

An OAuth session created by kimi login (official Kimi Code CLI, kimi-code) — device-code flow: the CLI prints a URL + code, the user confirms in a browser. No key material passes through you.

Session owner

The Kimi Code CLI stores and refreshes the session itself (~/.kimi-code/). Never read, print, or copy its credential files — bridges reuse the session, they don't extract it.

Bridge for Codex

duolahypercho/codex-router — purpose-built router that puts kimi-oauth/k3 in the Codex model picker (App + CLI) next to native GPT models, preserving the ChatGPT login. Ships an agent runbook (AGENTS.md) and a non-interactive installer: ./install.sh --auto --providers kimi-oauth --migrate-known. Listens on 127.0.0.1 ports 4100–4103.

Bridge (alternative)

lidge-jun/opencodex (npm @bitkyc08/opencodex, proxy on localhost:10100) — universal provider proxy for Codex and Claude Code with Kimi OAuth support. Its ocx init setup is interactive, so under this runbook use it only if codex-router fails and configure ~/.opencodex/config.json directly per its docs.

Plan gating

Same subscription tiers as Route S (§1.3 tier heuristic applies).

Route P — Moonshot/Kimi Open Platform (pay-per-token)

(OpenRouter — moonshotai/kimi-k3, ~$3/M in, ~$15/M out — is a last-resort fallback only; do not configure it unless the user explicitly has an OpenRouter key and no Kimi key.)

Shared facts (both routes)

Fact

Value

K3 context window

1048576 (1M) where the plan allows, else 262144

Thinking

Always on for K3; never send the K2.x thinking param

Sampling params

temperature, top_p, n, presence_penalty, frequency_penalty are fixed — never send them

Vision

base64 or ms://<file-id> only; content must be an array of objects

Open weights

Released by 2026-07-27; until confirmed available, self-hosting is out of scope — use the API

1. Preflight

1.0 Detect a Kimi Code OAuth session (Route O; check before hunting keys)

Find the Kimi Code CLI: command -v kimi, else ~/.kimi-code/bin/kimi. Absent → Route O unavailable; continue with §1.1.

If present, test for a valid session with one cheap non-interactive call: kimi -p 'Reply with exactly: OK' (timeout ~60s). Success → a live OAuth session exists; record Route O available. An auth/login error → CLI installed but not logged in.

Installed-but-not-logged-in and Codex is a target: kimi login is a device-code flow, not a browser wizard — you may run it, relay the printed URL + code to the user verbatim, and wait for completion. This counts as part of the §1.3 "missing credential" interruption, not an extra one. If the user is unreachable or declines, drop Route O and fall back to §1.1.

Route O only covers harnesses bridged in §3 Rung O. Even when Route O is available, still run §1.1–1.3 if other harnesses (Claude Code, Hermes, Pi) are targets — they need a key route (S/P). If no key exists anywhere but a Route O session does, configure Codex via Rung O and report the other harnesses as needing a key (§1.3 message), rather than stopping everything.

1.1 Locate a Moonshot API key (in order; stop at first hit)

Check without printing values (test emptiness only, e.g. [ -n "$VAR" ]):

Normalize: export the found key as KIMI_API_KEY for the rest of this runbook (source the file or export from the found location — never echo it). It must be exported, not just a shell variable: later steps read it from the environment (jq's env, LiteLLM's os.environ/).

1.2 Detect installed harnesses

Harness

Present if

Claude Code

command -v claude

Codex CLI

command -v codex

Hermes Agent

command -v hermes or ~/.hermes/ exists

Pi

command -v pi or ~/.pi/ exists

If the user named specific harnesses, configure exactly those (and report if one isn't installed). Otherwise configure every detected harness.

1.3 Classify and validate the key (the only potentially blocking step)

You must determine whether the key is a subscription (Route S) or platform (Route P) key. Probe in this order and stop at the first 200; the winning probe determines the route used for every section below.

```
CHECK=$(mktemp)   # never a fixed /tmp path — mktemp gives an unpredictable name with 0600 perms

# Probe S — subscription (Anthropic-style endpoint); auth header via stdin (-H @-), not argv
HTTP_S=$(curl -s -o "$CHECK" -w '%{http_code}' \
  https://api.kimi.com/coding/v1/messages \
  -H @- -H "anthropic-version: 2023-06-01" -H "Content-Type: application/json" \
  -d '{"model":"k3","max_tokens":16,"messages":[{"role":"user","content":"ping"}]}' \
  <<< "x-api-key: $KIMI_API_KEY")

# Probe P — platform (OpenAI-style endpoint), only if Probe S failed
HTTP_P=$(curl -s -o "$CHECK" -w '%{http_code}' \
  https://api.moonshot.ai/v1/chat/completions \
  -H @- -H "Content-Type: application/json" \
  -d '{"model":"kimi-k3","messages":[{"role":"user","content":"ping"}],"max_completion_tokens":16}' \
  <<< "Authorization: Bearer $KIMI_API_KEY")
```

Probe S returns 200 → Route S (subscription). Then detect the plan tier: attempt Probe S again with model kimi-for-coding-highspeed. A 200 implies an Explorer+/Allegretto+ tier → use the 1M config (k3[1m], window 1048576); a 4xx implies a base tier → use the 256K config (k3, window 262144). Record the tier. This is a heuristic — it assumes highspeed access and 1M K3 remain gated on the same tiers. If k3[1m] is later rejected during verification, downgrade to the 256K config (§8) instead of debugging the endpoint.

Probe S fails, Probe P returns 200 → Route P (platform).

Probe P 401 on .ai → retry against https://api.moonshot.cn/v1/...; a 200 means a China-platform key: Route P with .cn endpoints.

If multiple keys were found in §1.1, classify each and prefer any Route S key.

Nothing validates → check §1.0's result before stopping. A live Route O session + Codex-only target → proceed OAuth-only (§1.0 step 4). Otherwise stop and send the user this single message, then end your turn:

I need a Kimi credential to finish the K3 setup. If you have a Kimi Code subscription, either (a) create a key at https://www.kimi.com/code/console (flat-rate; every paid tier can mint one), or (b) for a Codex-only setup I can use OAuth instead — install the Kimi Code CLI and I'll run kimi login and give you a URL to confirm, no key to paste. Otherwise create a pay-per-token key at https://platform.kimi.ai/console/api-keys. Then run export KIMI_API_KEY=<key> in this shell (or say "use oauth"), and say "continue" — I'll finish without further questions.

rm -f "$CHECK" afterward — probe responses can include account metadata.

1.4 Consent gate — one message before any secret is written

Before the first write of key material to disk, send the user one message listing:

Every file that will receive the key, plaintext or env-reference — e.g. ~/.claude/settings.json, ~/.zshrc, ~/.hermes/.env, ~/.config/litellm/.kimi-key, ~/.pi/agent/auth.json.

For each harness already routed to another provider: whether you will take over the default in place or create an isolated profile (decision rules in §2/§3).

If §3 Rung O will run: that codex-router will be checked out to ~/.local/share/codex-router, add a marked managed block (openai_base_url + model_catalog_json) to ~/.codex/config.toml, and install a user-level background service on ports 4100–4103. Rung O writes no key material, but it modifies config.toml, so it belongs in this gate.

Proceed on confirmation; apply any adjustments the user makes. Skip this gate only when the user's request already granted it explicitly (e.g. "set up Kimi everywhere, overwrite what you need, don't ask"). After the gate, do not ask again — the remaining steps run uninterrupted.

Throughout §2–§6: SUB blocks apply on Route S, PLAT blocks on Route P. Route O has no per-harness blocks — it applies only as §3 Rung O (Codex); every other harness uses SUB or PLAT.

2. Claude Code

Target file: ~/.claude/settings.json. Back it up, then merge (never overwrite the whole file — preserve permissions, theme, hooks, etc.) the route-appropriate env block into .env.

SUB (Route S) — per the official Kimi Code docs. MODEL is k3[1m] on 1M-tier plans, k3 on 256K tiers (from §1.3); WINDOW is 1048576 or 262144 accordingly. Note the subscription uses ANTHROPIC_API_KEY (not AUTH_TOKEN) and effort high (not max):

```
cp ~/.claude/settings.json ~/.claude/settings.json.bak-kimi-$(date +%s) 2>/dev/null
chmod 600 ~/.claude/settings.json.bak-kimi-* 2>/dev/null
MODEL='k3[1m]'; WINDOW='1048576'   # or k3 / 262144 for 256K tiers
TMP=$(mktemp)
# key read via jq's env (exported in §1.1) — never via --arg, which exposes it in argv
jq --arg m "$MODEL" --arg w "$WINDOW" '.env = (.env // {}) + {
  "ANTHROPIC_BASE_URL":"https://api.kimi.com/coding/",
  "ANTHROPIC_API_KEY":env.KIMI_API_KEY,
  "ANTHROPIC_MODEL":$m,
  "ANTHROPIC_DEFAULT_FABLE_MODEL":$m,
  "ANTHROPIC_DEFAULT_OPUS_MODEL":$m,
  "ANTHROPIC_DEFAULT_SONNET_MODEL":$m,
  "ANTHROPIC_DEFAULT_HAIKU_MODEL":$m,
  "CLAUDE_CODE_SUBAGENT_MODEL":$m,
  "ENABLE_TOOL_SEARCH":"false",
  "CLAUDE_CODE_EFFORT_LEVEL":"high",
  "CLAUDE_CODE_AUTO_COMPACT_WINDOW":$w,
  "CLAUDE_CODE_MAX_CONTEXT_TOKENS":$w
}' ~/.claude/settings.json > "$TMP" && mv "$TMP" ~/.claude/settings.json && chmod 600 ~/.claude/settings.json
```

If Claude Code has never been onboarded on this machine, also set hasCompletedOnboarding: true (and penguinModeOrgEnabled: true) in ~/.claude.json so the user isn't dropped into the Anthropic login flow — merge, don't overwrite. Verify these keys against the installed Claude Code version first (an existing ~/.claude.json on this or another machine, or the docs); skip any key you cannot confirm rather than inventing settings.

PLAT (Route P) — platform pay-per-token:

```
cp ~/.claude/settings.json ~/.claude/settings.json.bak-kimi-$(date +%s) 2>/dev/null
chmod 600 ~/.claude/settings.json.bak-kimi-* 2>/dev/null
TMP=$(mktemp)
jq '.env = (.env // {}) + {
  "ANTHROPIC_BASE_URL":"https://api.moonshot.ai/anthropic",
  "ANTHROPIC_AUTH_TOKEN":env.KIMI_API_KEY,
  "ANTHROPIC_MODEL":"kimi-k3",
  "ANTHROPIC_DEFAULT_OPUS_MODEL":"kimi-k3",
  "ANTHROPIC_DEFAULT_SONNET_MODEL":"kimi-k3",
  "ANTHROPIC_DEFAULT_HAIKU_MODEL":"kimi-k3",
  "CLAUDE_CODE_SUBAGENT_MODEL":"kimi-k3",
  "ENABLE_TOOL_SEARCH":"false",
  "CLAUDE_CODE_AUTO_COMPACT_WINDOW":"1048576",
  "CLAUDE_CODE_EFFORT_LEVEL":"max"
}' ~/.claude/settings.json > "$TMP" && mv "$TMP" ~/.claude/settings.json && chmod 600 ~/.claude/settings.json
```

(Either route: if the file doesn't exist, create it as {"env": {...}} the same way, seeding from {}. If switching routes over a previous Kimi setup, first delete the other route's stale keys — e.g. remove ANTHROPIC_AUTH_TOKEN when writing SUB, remove ANTHROPIC_API_KEY when writing PLAT.)

Then remove conflicts — settings.jsonenvoverrides shell exports, but stale rc-file exports of ANTHROPIC_* pointing at other providers still confuse diagnosis. Grep ~/.zshrc/~/.bashrc for ANTHROPIC_BASE_URL/ANTHROPIC_AUTH_TOKEN exports; if any point to a non-moonshot provider, comment them out (with a # disabled by kimi-k3 setup marker), noting this in your final report.

Every model-tier variable above is required. Missing ones make subagents and background tasks (titles, summarization) fail silently with unknown-model errors. The exact ANTHROPIC_DEFAULT_* roster tracks Claude Code releases — confirm against the installed version's docs; an unrecognized variable is ignored harmlessly, but a missing recognized one is not.

Preserve-existing-setup variant: if settings.json already routes to another provider the user actively uses (e.g. a real Anthropic subscription), do not clobber it. Instead create an isolated profile: write the full config to ~/kimi-home/.claude/settings.json and append to the user's rc file:

```
alias kimi-claude='CLAUDE_CONFIG_DIR=$HOME/kimi-home/.claude claude'
```

Decision rule: existing env.ANTHROPIC_BASE_URL already moonshot → in-place merge. Existing non-moonshot base URL, or OAuth login in active use → isolated profile. "OAuth login in active use" is concrete: on Linux, ~/.claude/.credentials.json exists and is non-empty; on macOS, security find-generic-password -s "Claude Code-credentials" succeeds. Base URL absent and no OAuth credentials → in-place merge. State the choice in the §1.4 consent message and repeat it in the final report.

3. Codex CLI

Protocol constraint (verified by deep research, 2026-07): Codex CLI speaks only the OpenAI Responses API for custom providers — wire_api = "chat" was removed from Codex in early 2026. Kimi's endpoints (platform api.moonshot.ai/v1 and subscription api.kimi.com/coding/v1) are Chat Completions, so on a current Codex a direct wiring fails and a local translation bridge is required. Moonshot's official answer is the CC Switch GUI router — which you must NOT use (interactive). Attempt the ladder below in order; stop at the first rung whose §7 verification passes. Rung O first when Route O is available (§1.0) — it is the only rung that surfaces Kimi in the Codex App model picker alongside native GPT models and needs no key; Rungs A/B are the key-based (S/P) fallbacks.

Rung O — codex-router with the Kimi OAuth session (preferred; Route O)

Requires: a valid kimi login session (§1.0), Git, Node.js ≥22.19, and uv or Python 3.10+. Missing runtime → do not install system packages without consent; skip to Rung A/B.

Install per the repo's own agent runbook (AGENTS.md in duolahypercho/codex-router — read it first and follow it where it is stricter than this section):

```
# 1. Stable checkout — never install the service from a temp clone
git clone https://github.com/duolahypercho/codex-router ~/.local/share/codex-router \
  || git -C ~/.local/share/codex-router pull --ff-only
cd ~/.local/share/codex-router

# 2. Non-interactive install, OAuth provider only.
#    --migrate-known is safe: it only snapshots/migrates router installs the repo itself recognizes.
./install.sh --auto --providers kimi-oauth --migrate-known

# 3. Health — every core line must be OK (unselected credentials may WARN)
./bin/doctor || ./bin/doctor --fix
./bin/providers        # expect: kimi-oauth SHOW + ready
```

What it changes: only a marked # BEGIN codex-router-managed … # END block in ~/.codex/config.toml (openai_base_url → local router on 127.0.0.1:4102, plus model_catalog_json), first backup kept as config.toml.pre-codex-router. It does not touch model, model_provider, profiles, MCP config, or the ChatGPT login — native GPT models keep working; kimi-oauth/k3 appears as an additional picker entry. Internally: router :4102 → LiteLLM Responses↔Chat-Completions adapter :4100 → OAuth forwarder :4101 → Kimi Code API; all listeners on 127.0.0.1.

Rung O safety boundaries (from the repo's AGENTS.md; they override your defaults):

Never print, read, or copy credential files or the generated /_codex-router/<capability>/v1 base URL — treat the managed URL as a local secret; show it only redacted.

Never kill unknown processes on ports 4100–4103; never migrate/stop an unrecognized router — --migrate-known handles recognized ones only.

Do not restart or quit the Codex App yourself; the catalog loads at app startup, so the final step is the user's: fully quit Codex (not just the window) and reopen. Say this in the report. CLI verification (§7) works without the app restart.

If doctor still fails after --fix, run ./bin/support-bundle and report its path; do not upload it.

Rollback: cd ~/.local/share/codex-router && ./bin/rollback (or ./bin/migrate rollback for a migrated older install); the managed config block is removable by deleting the marked lines and restoring config.toml.pre-codex-router.

On success, skip Rungs A/B entirely (no LiteLLM service needed — codex-router embeds its own adapter). If the user also wants a key-based Codex profile as backup, that is out of scope unless requested.

Rung A — direct config (works only on older Codex builds that still accept wire_api = "chat")

Back up ~/.codex/config.toml, then write (update in place if a [model_providers.kimi] block exists; replace, don't duplicate, top-level keys):

```
model = "k3"                     # Route S; "kimi-k3" on Route P
model_provider = "kimi"
model_reasoning_effort = "high"

[model_providers.kimi]
name = "Kimi"
base_url = "https://api.kimi.com/coding/v1"   # Route S; https://api.moonshot.ai/v1 on Route P
env_key = "KIMI_API_KEY"
wire_api = "chat"
```

If codex exec errors on the config (unknown/invalid wire_api value) or requests 404, move straight to Rung B — do not debug Rung A further. (There is no direct Responses wiring: api.moonshot.ai/v1/responses returns 404 — the platform endpoint is Chat Completions only.)

Rung B — LiteLLM translation proxy (the non-interactive bridge; fallback on current Codex)

LiteLLM exposes a Responses-API facade locally and translates to Kimi's Chat Completions upstream.

```
# 1. Install (prefer uv; fall back to pipx/pip)
uv tool install "litellm[proxy]" || pipx install "litellm[proxy]" || pip install --user "litellm[proxy]"

# 2. Config — ~/.config/litellm/kimi.yaml (create dir; key via env reference, not plaintext)
mkdir -p ~/.config/litellm
cat > ~/.config/litellm/kimi.yaml <<'EOF'
model_list:
  - model_name: kimi-k3
    litellm_params:
      model: moonshot/k3                    # Route S; moonshot/kimi-k3 on Route P
      # Must be the moonshot/ prefix. openai/... passes requests through untranslated
      # and every request fails; moonshot/ engages LiteLLM's Moonshot translation.
      api_base: https://api.kimi.com/coding/v1   # Route S; https://api.moonshot.ai/v1 on Route P
      api_key: os.environ/KIMI_API_KEY
EOF

# 3. Key file the unit reads — written via shell builtins only (umask 077 → 0600); never inline the key in the unit
( umask 077; printf 'KIMI_API_KEY=%s\n' "$KIMI_API_KEY" > ~/.config/litellm/.kimi-key )

# 4a. Linux — run as a persistent background service (user-level systemd; survives reboots)
mkdir -p ~/.config/systemd/user
cat > ~/.config/systemd/user/litellm-kimi.service <<EOF
[Unit]
Description=LiteLLM proxy for Kimi (Codex bridge)
[Service]
EnvironmentFile=%h/.config/litellm/.kimi-key
ExecStart=$(command -v litellm) --config %h/.config/litellm/kimi.yaml --port 4141
Restart=on-failure
[Install]
WantedBy=default.target
EOF
systemctl --user daemon-reload && systemctl --user enable --now litellm-kimi
```

(EnvironmentFile= reads KIMI_API_KEY=... lines from the file — do not use Environment=KIMI_API_KEY=<path>, which would set the variable's value to the file path itself and 401 every request.)

```
# 4b. macOS — no systemd; use a user-level launchd agent instead.
# launchd has no EnvironmentFile equivalent, so a /bin/sh wrapper sources the 0600
# key file at start — the key itself never appears in the plist.
mkdir -p ~/Library/LaunchAgents
cat > ~/Library/LaunchAgents/com.kimi.litellm.plist <<EOF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key><string>com.kimi.litellm</string>
  <key>ProgramArguments</key>
  <array>
    <string>/bin/sh</string>
    <string>-c</string>
    <string>set -a; . "\$HOME/.config/litellm/.kimi-key"; exec $(command -v litellm) --config "\$HOME/.config/litellm/kimi.yaml" --port 4141</string>
  </array>
  <key>RunAtLoad</key><true/>
  <key>KeepAlive</key><dict><key>SuccessfulExit</key><false/></dict>
</dict>
</plist>
EOF
launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/com.kimi.litellm.plist 2>/dev/null \
  || launchctl load ~/Library/LaunchAgents/com.kimi.litellm.plist   # older macOS fallback
```

(On hosts with neither systemd nor launchd, use the harness's tracked background-job facility to run litellm --config ... --port 4141 with KIMI_API_KEY exported, and note in the report that it must be relaunched after reboot.)

Then point Codex at the proxy:

```
model = "kimi-k3"
model_provider = "kimi"
model_reasoning_effort = "high"

[model_providers.kimi]
name = "Kimi via LiteLLM"
base_url = "http://localhost:4141/v1"
env_key = "KIMI_API_KEY"        # value irrelevant to the proxy hop but must be set
wire_api = "responses"
```

Sanity-check the proxy itself before blaming Codex: curl -s http://localhost:4141/v1/models should list kimi-k3.

Rung C — report-only fallback

If Rung O prerequisites are missing and LiteLLM cannot be installed (no network/python tooling), configure nothing, and in the final report tell the user their manual options: Moonshot's CC Switch GUI routing guide (https://platform.kimi.ai/docs/guide/codex-kimi), or the interactive ocx init of opencodex (https://github.com/lidge-jun/opencodex, npm i -g @bitkyc08/opencodex) which supports Kimi OAuth for Codex and Claude Code. Do not attempt to drive either interactive flow yourself.

Preserving an existing OpenAI setup

Keep the user's ChatGPT/OpenAI Codex auth usable: instead of overwriting top-level model/model_provider, you may define the Kimi rung under a profile. Current Codex versions reject [profiles.kimi] blocks inside config.toml — profiles must live in their own file. Write the profile to ~/.codex/kimi.config.toml:

```
# ~/.codex/kimi.config.toml — do NOT put this in config.toml (current Codex rejects it there)
model = "kimi-k3"
model_provider = "kimi"
model_reasoning_effort = "high"
```

(The [model_providers.kimi] block from the winning rung stays in ~/.codex/config.toml as before — only the profile moves.) Verify with codex exec --profile kimi .... Same decision rule as §2: take over the default only if no other provider is actively configured; otherwise use the profile and say so in the report.

Top-level model/model_provider keys: replace existing values rather than appending duplicates (TOML rejects duplicate keys).

Codex reads the key from the environment (env_key), so persist it: if KIMI_API_KEY isn't already exported in a shell rc file, append it to ~/.zshrc with the printfbuiltin (printf 'export KIMI_API_KEY=%s\n' "$KIMI_API_KEY" >> ~/.zshrc — builtins don't expose argv; do not display the key). This puts the key in plaintext in the rc file, so ~/.zshrc must be listed in the §1.4 consent message.

If the user's Codex is authenticated with a ChatGPT subscription they use, keep that usable: add the Kimi block but note in your report that codex --profile/model_provider switching applies; optionally define the profile in ~/.codex/kimi.config.toml (as above) instead of changing the top-level default — same decision rule as §2 (clobber only if nothing else is actively configured).

4. Hermes Agent

Kimi is a first-class Hermes provider; config is file-based, no wizard needed. Hermes' kimi-coding provider is built for the Kimi coding key — both routes use the same provider name and KIMI_API_KEY variable, so the steps below are route-independent except for the model ID (SUB: k3; PLAT: kimi-k3) and one override: on Route S, if requests fail against the provider's default endpoint, set KIMI_BASE_URL=https://api.kimi.com/coding/v1 in ~/.hermes/.env.

```
# 1. Key into ~/.hermes/.env (create file if missing; replace existing KIMI_API_KEY line, don't append a duplicate).
# No sed: the key in sed's argv is world-readable via /proc, and |/& in a key break the replacement.
mkdir -p ~/.hermes && touch ~/.hermes/.env && chmod 600 ~/.hermes/.env
TMP=$(mktemp)
grep -v '^KIMI_API_KEY=' ~/.hermes/.env > "$TMP" || true
printf 'KIMI_API_KEY=%s\n' "$KIMI_API_KEY" >> "$TMP"
mv "$TMP" ~/.hermes/.env && chmod 600 ~/.hermes/.env
```

Set the default model in ~/.hermes/config.yaml (back up first; merge into the existing model: block if present):

```
model:
  provider: "kimi-coding"
  default: "k3"        # Route S; use "kimi-k3" on Route P
```

China-platform key (from §1.3): use provider kimi-coding-cn and put the key in KIMI_CN_API_KEY instead.

If config.yaml already has a provider the user actively uses, leave model: alone and just install the key — the user can switch with /model in-session; say so in the report. Same decision rule as §2.

Usage (for your verification and your report): hermes chat --provider kimi-coding --model k3 (or kimi-k3 on Route P).

5. Pi

Config is file-based. The two routes diverge here — Pi's built-in kimi-coding provider only accepts subscription (Route S) keys; a platform pay-per-token key gets a 401 from it. Route P needs a custom provider in ~/.pi/agent/models.json instead.

SUB (Route S) — use the built-in provider, literally named "Kimi For Coding" (kimi-coding), via ~/.pi/agent/auth.json. Pi's auth.json supports env interpolation, so prefer the no-plaintext form: since you persisted export KIMI_API_KEY in §3 (do it even if Codex is absent, when Pi is present), write:

```
mkdir -p ~/.pi/agent
[ -f ~/.pi/agent/auth.json ] && cp ~/.pi/agent/auth.json ~/.pi/agent/auth.json.bak-kimi-$(date +%s)
# merge, preserving other providers' credentials
[ -f ~/.pi/agent/auth.json ] || echo '{}' > ~/.pi/agent/auth.json
TMP=$(mktemp)
jq '. + {"kimi-coding": {"type": "api_key", "key": "$KIMI_API_KEY"}}' \
  ~/.pi/agent/auth.json > "$TMP" && mv "$TMP" ~/.pi/agent/auth.json
chmod 600 ~/.pi/agent/auth.json
```

Note: "$KIMI_API_KEY" here is a literal string — Pi interpolates it at runtime. Do not substitute the real key into this file. auth.json beats env vars in Pi's resolution order, so this entry wins cleanly.

PLAT (Route P) — do not write the key under kimi-coding (401). Define a custom Moonshot provider in ~/.pi/agent/models.json (back up first; merge if the file exists, preserving other custom providers):

```
mkdir -p ~/.pi/agent
[ -f ~/.pi/agent/models.json ] && cp ~/.pi/agent/models.json ~/.pi/agent/models.json.bak-kimi-$(date +%s)
[ -f ~/.pi/agent/models.json ] || echo '{}' > ~/.pi/agent/models.json
TMP=$(mktemp)
jq '.providers = (.providers // {}) + {
  "moonshot": {
    "name": "Moonshot (Kimi Platform)",
    "baseUrl": "https://api.moonshot.ai/v1",
    "api": "openai-completions",
    "apiKey": "KIMI_API_KEY",
    "models": [
      {"id": "kimi-k3", "name": "Kimi K3", "reasoning": true, "contextWindow": 1048576, "maxTokens": 16384}
    ]
  }
}' ~/.pi/agent/models.json > "$TMP" && mv "$TMP" ~/.pi/agent/models.json
chmod 600 ~/.pi/agent/models.json
```

"apiKey": "KIMI_API_KEY" names the env var Pi reads at runtime — no plaintext key lands in this file, but the §3 rc-file export must exist. Verify the field names against the installed Pi version's custom-provider docs before writing; if they differ, adapt rather than guessing. Use China endpoint https://api.moonshot.cn/v1 for a .cn key.

Model selection in Pi is per-session (/model) — no default-model file edit is needed or safe to guess. In the report, tell the user: "In Pi, pick Kimi K3 via /model (provider: Kimi For Coding on Route S; Moonshot on Route P)."

6. Other OpenAI-compatible harnesses (OpenCode, Cline, Aider, Zed, ...)

If the user asked for a harness not covered above and it supports custom OpenAI-compatible providers, configure its provider file with:

Base URL https://api.moonshot.ai/v1, model kimi-k3, key from $KIMI_API_KEY

Context window 1048576 if the harness has such a field

Do not configure sampling parameters (they're fixed server-side)

Find that harness's non-interactive config file yourself (docs or --help); apply the same rules: backup, merge, no wizards, no plaintext key in chat.

7. Verification (all non-interactive)

Run for each configured harness; collect results for the final report.

Use MODEL=k3 on Route S (never k3[1m] outside Claude Code env vars) and MODEL=kimi-k3 on Route P.

Harness

Command

Pass criterion

API direct

winning probe from §1.3

HTTP 200

Claude Code

claude -p 'Reply with exactly: KIMI-OK' (with the profile's env active; model comes from settings.json)

Output contains KIMI-OK

Codex CLI (Rung A/B)

codex exec 'Reply with exactly: KIMI-OK'

Output contains KIMI-OK; startup banner shows the Kimi model

Codex CLI (Rung O)

~/.local/share/codex-router/bin/doctor, then codex exec -m kimi-oauth/k3 'Reply with exactly: KIMI-OK'

Doctor all-OK on core lines; output contains KIMI-OK. App picker entry only verifiable by the user after a full app restart — state it in the report, don't fail on it

Hermes

hermes chat --provider kimi-coding --model $MODEL -p 'Reply with exactly: KIMI-OK' (use --print/non-interactive flag per hermes chat --help)

Output contains KIMI-OK

Pi

pi --provider kimi-coding --model k3 -p 'Reply with exactly: KIMI-OK' on Route S; pi --provider moonshot --model kimi-k3 -p '...' on Route P (check pi --help for the print flag)

Output contains KIMI-OK

If a harness's non-interactive flag differs from the above, discover it via --help rather than skipping verification. A verification failure is yours to debug (see §8) — do not hand it back to the user until you've worked through §8.

8. Failure playbook (work through before reporting failure)

Symptom

Cause

Fix

401 (Claude Code)

Stale env entries in settings.json overriding your merge; or wrong-region key

Re-read the file you wrote; try .cn endpoints

"model not found"

A model-tier variable still points at a Claude/GPT default

Re-check all 7 model vars in §2

400 invalid thinking

K2.x thinking param sent, or thinking disabled

K3: remove thinking, use reasoning_effort; never disable thinking

Tool calls misbehave (Claude Code)

Tool Search enabled

ENABLE_TOOL_SEARCH must be the string "false"

Premature compaction / context errors

Wrong compact window

CLAUDE_CODE_AUTO_COMPACT_WINDOW=1048576

Codex ignores provider

Duplicate top-level model/model_provider keys, or TOML parse error

codex exec surfaces parse errors; validate the TOML

Codex rejects wire_api = "chat"

Current Codex builds only support responses

Expected — move to §3 Rung B (LiteLLM proxy); there is no direct Responses wiring (api.moonshot.ai/v1/responses is 404)

Codex hangs 15+ min before first output

Hooks or MCP servers in ~/.codex/config.toml stall startup when combined with a custom provider

Temporarily comment out mcp_servers/hook blocks, retry, then re-enable one at a time to find the culprit

Codex rejects config: unknown [profiles.*]

Profile block placed in config.toml; current Codex requires profiles in their own file

Move the block to ~/.codex/kimi.config.toml (§3)

Every request via proxy fails / passthrough errors

LiteLLM model uses the openai/ prefix, which doesn't translate

Use moonshot/k3 (Route S) / moonshot/kimi-k3 (Route P) in kimi.yaml; restart the service

Codex 404/protocol errors via proxy

LiteLLM not running, wrong port, or upstream mapping wrong

curl http://localhost:4141/v1/models; check systemctl --user status litellm-kimi (Linux) or launchctl list | grep com.kimi.litellm (macOS); verify api_base/model in kimi.yaml

Codex 401 via proxy

Unit uses Environment=KIMI_API_KEY=<path> (value = the file path) instead of EnvironmentFile=

EnvironmentFile=%h/.config/litellm/.kimi-key with a KIMI_API_KEY=... line inside (0600); restart the unit

Hermes uses wrong model

config.yamlmodel: block not merged / overridden by CLI flags

Literal $KIMI_API_KEY written but env var not exported in the shell Pi runs from

Confirm the rc-file export from §3; restart shell context

Pi 401 on Route P

Platform pay-per-token key written under the kimi-coding provider, which only accepts subscription keys

Remove the kimi-coding auth.json entry; use the custom moonshot provider in models.json (§5 PLAT)

Sampling-param rejection

Harness injects temperature etc.

Remove from harness config; K3 fixes these server-side

401 with a valid subscription

Route mix-up: subscription key sent to api.moonshot.ai, or platform key sent to api.kimi.com/coding/

Re-run §1.3 classification; the two consoles issue different keys

Rung O: auth errors after previously working

kimi login OAuth session expired or revoked

Re-run §1.0 step 2; if dead, relay a fresh kimi login device-code URL to the user, then ./bin/doctor

Rung O: Kimi missing from the App picker but CLI works

Catalog loads only at app startup, or stale catalog

User must fully quit Codex (not just the window) and reopen; if still missing, ./bin/refresh-catalog then quit/reopen again

Rung O: doctor FAIL on service/router health

Port 4100–4103 conflict or service not started

systemctl --user status the router unit; if a foreign process owns the port, report it — never kill unknown processes on those ports

Rung O: codex exec ignores the router

Managed block removed/mangled in config.toml, or another tool overwrote openai_base_url

Check the marked codex-router-managed block; ./bin/doctor --fix rebuilds it

"model not found: kimi-k3" on Route S

Platform model ID used against the subscription endpoint

Subscription model IDs are k3 / kimi-for-coding, not kimi-k3

k3[1m] rejected

1M form used outside Claude Code env vars, or plan is a 256K tier

Use k3 everywhere else; downgrade to 256K config per §1.3 tier check

9. Final report to the user (required format)

End with a short message containing:

Which auth route was used per harness (S subscription key / O OAuth session / P platform pay-per-token) and, on Route S, which plan tier was detected (1M vs 256K).

The 1–2 things the user must know: e.g. kimi-claude alias if you made an isolated profile; /model selection note for Pi; restart open harness sessions to pick up new config; on Rung O, fully quit and reopen the Codex App to load the new model catalog.

Rollback one-liner: "To undo, restore the .bak-kimi-* files listed above."

No secrets in the report. No questions in the report.

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters

Split-brain coding mode — the session model (e.g. Claude Fable) acts as orchestrator only, and ALL code writing is delegated to a Kimi worker running headless Claude Code against Moonshot's Anthropic-compatible API. Use when the user invokes /kimi-router or asks to route coding work to Kimi.

Kimi Router

You are now the orchestrator. Kimi is the executor. This mode stays on for the rest of the session.

The one rule

You never write or edit code. Not one line, not a "quick fix". Every code change — new files, edits, refactors, config, tests — is delegated to a Kimi worker. Your job is direction: understand the task, write the brief, review the result.

You MAY still directly: read files, search, run tests/builds, run git commands, answer questions, and edit non-code documents the user asks you for (e.g. this brief, notes).

Setup (once)

The worker needs these env vars (put them in ~/.kimi/env or similar, never commit them):

```
export KIMI_API_KEY="sk-..."                                # Moonshot platform key
export KIMI_BASE_URL="https://api.moonshot.ai/anthropic"    # Anthropic-compatible endpoint
export KIMI_MODEL="kimi-k3"                                 # exact model name from Moonshot docs
```

If KIMI_API_KEY is not set in the environment, try source ~/.kimi/env first; if still missing, stop and ask the user for the key.

The loop (per coding task)

Understand — read the relevant files and any AGENTS.md/CLAUDE.md yourself. Decide what should change and where.

Brief — write a self-contained task brief. The worker has zero conversation context, so the brief must include:

Goal in one sentence, then exact requirements.

Absolute paths of files to change (and files to read for context/conventions).

Constraints (style, patterns to follow, what NOT to touch).

Acceptance criteria (what must pass/work when done).

Delegate — spawn one worker (serial, never parallel):

```
env ANTHROPIC_BASE_URL="$KIMI_BASE_URL" \
    ANTHROPIC_AUTH_TOKEN="$KIMI_API_KEY" \
    ANTHROPIC_MODEL="$KIMI_MODEL" \
    ANTHROPIC_SMALL_FAST_MODEL="$KIMI_MODEL" \
    claude -p "<brief>" \
    --model "$KIMI_MODEL" \
    --permission-mode acceptEdits \
    --settings '{"disableAllHooks": true}' \
    --output-format stream-json --verbose \
    --add-dir <project-root>
```

--model is required: without it, headless Claude Code uses the user's saved default model (an Anthropic model), which the Kimi endpoint rejects. The env vars alone are not enough.

--settings '{"disableAllHooks": true}' stops the user's global hooks (e.g. an autogit Stop hook) from firing inside the worker — otherwise the worker's changes can get auto-committed and even auto-pushed with the brief as the commit message before the orchestrator has reviewed them. The orchestrator owns git; workers must not commit. (Trade-off: guardrail hooks are also skipped, so never combine this with a broad Bash allowlist.)

--output-format stream-json --verbose makes the worker emit one JSON line per step (tool calls, edits, messages) instead of staying silent until the end. Run the worker in the background, poll its output file every ~30s, and report progress to the user in plain English (e.g. "Kimi is editing index.js now"). The final result JSON line is the worker's report.

Run it from the project root. For anything non-trivial, run it in the background (it can take minutes) and poll the output instead of blocking.

Review — after the worker exits:

Read the full diff (git diff).

Check it against the acceptance criteria.

Run the relevant tests/build.

Iterate — if something is wrong or missing, do NOT fix it yourself. Write a new fix-it brief (quote the failing test output / the specific defect and file:line) and spawn another worker. Repeat until the acceptance criteria pass.

Report — tell the user what Kimi changed, what you verified, and anything still open.

Brief-writing tips

One task per worker. Split big features into sequential briefs; each builds on the reviewed result of the last.

Over-specify. Vague briefs produce vague code. Name functions, name files, paste relevant snippets.

Tell the worker to follow existing patterns in named files rather than inventing new abstractions.

Tell the worker its stdout is a report, not a chat: end with a summary of files changed.

Failure handling

Worker returns an API/auth error → surface it to the user; it's a setup problem, not a coding problem.

Worker produces wrong code → fix-it brief (step 5). There is no "orchestrator takes over" fallback.

This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
