English | 简体中文
**kimi-tide (MoonTide) is a small plugin you install into DSH — the tool you use to work and write code together with an AI (open-sourced by DeepSeek).**
**It does one job: it swaps in a better-suited AI for you, automatically.** You usually have several AIs connected — one cheap, one smart, one that can read screenshots. Until now you had to switch by hand, and often forgot to switch back; with kimi-tide it picks for you on every turn: **everyday work goes to the cheap one first, the important work goes to the smarter one, images go to the one that can see them.**
**Three things you get:**
- **Save money** — don't pay where you don't need to. Chat, translation, copy edits and tidying up keep using your cheapest AI; **the good steel goes only where the blade is**.
- **No weak links** — the critical parts are backed by a strong model: coding, code review and math each go to the stronger one, and output that matters can be checked by a strong model first (issues by severity + advice + a pass/fail verdict) before it reaches you.
- **No more switching back** — after a screenshot, only that turn moves to a vision AI; the next turn returns to the one you were using. **The pricey AI is billed by the slice, not by the whole session.**
(In the rest of this document, "AI" and "model" mean the same thing — DSH calls them models.)
**For you if**: you use DSH with more than one model connected.
**Not for you if**: you use a single model, or haven't set up DSH yet (set up DSH first, then come back).
---
## What problem it solves
**Scenario 1: you paste a screenshot, and the model says it can't see images**
- Before: switch to a vision model by hand → paste → ask → remember to switch back.
- After: just paste. Image-bearing messages go to a model that can see; the next text-only message returns to your default model automatically.
**Scenario 2: you switched models and forgot to switch back**
- Before: one screenshot moved you to the expensive model — and the rest of the session kept burning it.
- After: kimi-tide decides **per step**, not per session — once the image is handled, your next message is back on the default model.
**Scenario 3: your quota burns faster than expected**
- Before: every message — including "hello" and "translate this" — runs on the most expensive model.
- After: pick the "saving" preset (a ready-made bundle of default model + rules) — small talk, translation, and daily chores go to the cheap model; only code and images touch the expensive ones. The panel shows your plan's remaining quota in real time (Kimi/GLM plans; models without a plan stay greyed out).
---
## Routing logic in 30 seconds
When a message arrives, kimi-tide decides in this order:
1. **Explicit pick**: the message says `@kimi` (provider level: the model you configured in the preset) or `@kimi/k3` (pins that exact model) → highest priority.
2. **Rule hit**: score the preset's rules — has an image? how many keyword-group words matched? → rules are sorted by **specificity** (more matched words first, image always first, ties keep list order) and the **first rule with an available target** wins (unavailable targets fall through to the next rule).
3. **Baseline**: nothing fires → use the preset's default model.
4. **Image guard**: even if a text-only model was picked, an image-bearing message is rerouted to a model that can see — no crashes.
```mermaid
flowchart LR
A["💬 Your message
(new this turn)"] --> B{"Explicit @model?"}
B -- "@kimi etc." --> H["🎯 Explicit directive
highest priority"]
B -- no --> C["📏 Preset rule chain
image / keyword groups
sorted by specificity · first available wins"]
C -- hit --> D["🌙 Rule target: model | flow
(skipped if unavailable)"]
C -- miss --> E["💰 Preset default
(baseline)"]
H --> J
D -- "target = flow" --> T["🌊 Transcribe flow
vision model turns images into text"]
D -- "target = model" --> F
E --> F{"Image on a
text-only target?"}
T --> K["✍️ Transcribed text
text model takes over"]
F -- yes --> G["🖼️ Image guard
reroute to a vision model"]
F -- no --> J["📋 dock trail
who + why"]
G --> J
K --> J
```
> A "flow" is a small automation pipeline (e.g.: images are turned into text first, then a cheap text model takes over); "vision" means a model that can read images; the "dock panel" is the "🌙 MoonTide" panel below the input box.
## What it looks like
[](docs/assets/readme/kimi-tide-architecture.html)
*Click for full size; download the linked HTML and open it in a browser for the interactive diagram (pan/zoom/search, light & dark themes).*
---
## Quick Start
### 1. Prerequisites
- Node.js ≥ 22
- DSH `@deepseek-ai/dsh@0.1.2-rc.1` or newer (this release is verified on `0.1.5-rc.1`)
- The models you want to route among are connected in DSH — **any provider works**. To use Kimi, grab a **Kimi Code Console API key** (the quota panel rides the same key)
### 2. Connect candidate models (DSH "Settings → Models" page)
Add a model source (example: **`kimi-coding`** with `apiKeyEnv` set to `KIMI_API_KEY`, then paste your key in the credential area — the 4 Kimi models appear in the catalog automatically). **Mount as many providers as you like**: kimi-tide's candidate pool is the full Models-page catalog. Keys live in DSH's managed credential store, **never in any plugin config file**.
### 3. Install the plugin
```bash
cd packages/dsh-kimi-tide
npm install && npm run build && npm pack
dsh plugin --profile web add ./dsh-kimi-tide-.tgz
```
### 4. Use it
Restart `dsh web`:
- **Settings → 月汐**: pick the "saving" or "capability" preset — the router is on duty;
- Type **`@kimi`** for an explicit pick, or let the built-in keyword groups reroute automatically (a message mentioning "code" goes to the coding model);
- The "🌙 MoonTide" dock panel below the input box shows who was picked and why, for every step;
- ✅ **30-second smoke check**: send "write a function for me" — the panel should show the code rule firing and rerouting to the coding model. No reason chip = the router isn't on duty; go back to "Settings → 月汐" and confirm a preset is selected.
---
## Presets & Rules
A preset is a bundle of "default model + rules" you can switch globally in one click. Two ship built in:
| Preset | Default model (used when no rule fires) | Rules | Best for |
|---|---|---|---|
| Off | — | — | full manual control |
| Saving (省钱) | `deepseek-v4-flash` | image → `k3`; code keywords → `kimi-for-coding`; translate keywords → `deepseek-v4-flash` | quota-sensitive daily work |
| Capability (能力) | `k3` | image → `k3`; review → `k3`; code → `kimi-for-coding`; math → `deepseek-v4-pro`; longdoc → `k3`; writing → `deepseek-v4-pro`; translate → `deepseek-v4-flash`; chitchat → `deepseek-v4-flash` | best output quality |
Seven built-in keyword groups (word lists editable, custom groups allowed):
| Group | Direction | Built-in word list (editable) |
|---|---|---|
| `code` | coding | 代码, code, bug, 重构, refactor, 实现, 函数, 测试, 接口, 联调, 部署, 性能, 报错, 日志, 编译, 命令, 脚本 |
| `review` | review | 审查, review, 评审, 挑毛病, 复检, 检查, audit, 意见, 打分 |
| `writing` | writing | 写作, 文案, 润色, 改写, 扩写, 标题, 推文, 周报, 演讲稿, 总结 |
| `translate` | translation | 翻译, 译成, 中译英, 英译中, translate, 本地化 |
| `longdoc` | long documents | 长文档, 通读, 逐段, 全文, 上万字, 大文档 |
| `math` | math | 数学, 证明, 推导, 求解, 公式, 数论, 概率, 逻辑题 |
| `chitchat` | small talk | 你好, 谢谢, 怎么样, 随便, 聊聊, 天气 |
> The `review` group serves the **collaborative review flow** by default (a strong model reviews this turn's output) — see "Multi-model collaborative review" below for the mechanism, the three switches and today's limits.
Two common tweaks (a few clicks in "Settings → 月汐"):
- **Minimum keyword hits**: set a threshold (e.g. 2) so a rule fires only when at least 2 distinct words from the group appear — "make a plan" no longer trips the plan-related words by accident.
- **Reasoning effort**: give a rule target or the default model a "thinking depth" tier (deeper is slower and pricier); unsupported tiers are dropped automatically — no errors.
### Usage & balance (follows the model that actually got picked)
The quota slots on the panel's second row **follow the current routed target** and adapt their shape: subscription plans (code plans) show usage windows (weekly / 5h — the bar draws the **remaining** share), while API-billed providers show a **balance** (with an explicit "insufficient balance" note when that is what the endpoint reports). Next to them a **Overview** button lists every registered source in one screen, including *why* a source has no data: "no public API for this plan" / "key not configured" / "fetch failed" — three distinct states, spelled out per row.
> Credentials are resolved by the **`apiKeyEnv` name configured for that provider in `settings.yaml`** (built-in aliases as fallback), so **the panel still gets data when your key name differs from the plugin's default**.
### Help tab & semantic hit confirmation
- **"Settings → 月汐 → 说明"** explains every panel element and every settings field across eight sections, with key entries carrying the **current value** (e.g. "trigger: manual ⇒ keyword hits will not fire a review"), plus a **symptom → cause** table.
- **Semantic hit confirmation** (off by default, needs config): with it enabled a keyword hit no longer reroutes immediately — the **preset's own default model** first confirms "is this really this turn's intent?", and an "omit" verdict skips that rule and keeps matching the rest. Timeout / unavailable judge / unparseable output all **fall back to the plain keyword result**; explicit `@` turns and turns where an image rule already leads make **no judge call at all**. Config knob: `preset.hitConfirm`.
- **The verdict lands in the decision reason**: omit / hit / no-verdict is prepended to the panel's decision reason (e.g. "semantic gate: no verdict 1200ms (code-kfc)"). Because an omit drops the rule from the chain and therefore lands on the default route, **default-route decisions carrying a verdict note are now surfaced too** — otherwise the omit itself, the one outcome you most need to see, would stay invisible.
- **The judge's thinking is turned off when the target allows it**: the judge is a reasoning model but this gate gives it a 64-token budget — left thinking, it spends the whole budget on reasoning, returns **not a single character of output**, and the verdict becomes unparseable (the gate then fails open and changes nothing). So when the judge target declares an "off" effort level, the plugin disables thinking explicitly; targets that do not (k3, for instance) get no effort sent at all — never an enum they would reject.
### Two ways to write an explicit @
- `@kimi` (provider level): the model is **the one you configured in the preset**, not whatever happens to be first in the catalog — and the decision reason says which basis was used.
- `@kimi/k3` (exact model): pins that model directly, regardless of pool order; if it is unavailable you are **told what it fell back to** instead of being silently switched.
- **Only a real provider counts as a directive**: if the token after `@` is not a provider this plugin knows — a workspace path reference like `@README.md`, a scoped package name like `node_modules/@deepseek-ai/...`, or an `@xxx` inside a path — it is **not treated as an explicit directive**; the turn goes through the keyword rules as usual and the decision reason says "`@x` is not a known provider (ignored)".
Matching details (word boundaries, specificity ranking, degradation), image behavior, and the full config reference: [router architecture](packages/dsh-kimi-tide/docs/router.md). The candidate pool is the full Models-page catalog — any model can be a default or a rule target.
## Multi-model collaborative review (a strong model signs off)
Routing decides *who runs this step*; review decides *whether this step is good enough*. They work separately or together.
**What it does**: when a turn closes, kimi-tide sends "your request for this turn + the main model's output" to **the reviewer you configured** (usually the stronger, pricier one) and gets back a structured review — issues graded by severity (blocking / suggested / optional) → improvement advice → a verdict (pass / conditional pass / fail) — rendered as a **review card** under that turn.
**Three switches** (Settings → 月汐 → collaboration flows):
| Switch | What it actually does today |
|---|---|
| Trigger | `keywords`: review only when the message hits the chosen keyword group; `manual`: run `/kimi-tide review` on the last turn at any time |
| Rounds | 1–3, bounding how many review passes happen |
| Auto-revise | **Not implemented yet** — ticking it changes nothing (the field is kept; implementation is on the roadmap) |
**What it does not do today**: it does not send a failing turn back for rework, and it does not edit your code. When the verdict is "fail", the next move is yours — a deliberate trade-off: no strong-model quota burned by default, and no silent rewrite of output you were happy with.
**Cost**: review only runs on **matching turns**, and only this turn's output slice is sent to the reviewer (12,000 characters per section, 60-second timeout, failures never interrupt the turn). In the industry data the research repo cites, adversarial review loops commonly cost 2–3× a single model's tokens — **this plugin has not measured its own numbers yet**.
**Evidence grade**: the mechanism and the three rounds of practice are documented in [kimi-tide-research](https://github.com/tafcear/kimi-tide-research). Whether review actually *improves a weaker model's output* is **not measured yet** (no acceptance rate, no baseline against the strong model working alone, no regression rate), so this section quotes no effect numbers; the transfer-efficiency experiment is scheduled as pre-release evidence for v1.4.0.
---
## FAQ
**Q: Where did the old OAuth access go?**
A: Retired. The official DSH ecosystem natively supports Kimi now, so the self-built layer was removed wholesale. Archive: [`docs/legacy-setup.md`](docs/legacy-setup.md).
**Q: Do I still need the Kimi CLI and `kimi login`?**
A: No. One Console API key + the official Models page.
**Q: Any limitations with image sessions?**
A: With the default "latch" behavior, a session that has seen an image stays locked to the vision-capable model — if its quota fails, that session can't fall back to text; open a new one. To avoid this: set the preset's image fallback to "lazy transcribe" (images become text, the text model takes over) or "blind" (treat images as absent). Transcriptions are cached and never retried.
**Q: I heard about a "capability scoring engine"?**
A: Retired. Scoring by machine was a black box; routing now follows rules you can read and edit — a hit routes, a miss falls to the baseline. Old scoring configs migrate into presets automatically on upgrade.
**Q: Where is the router config stored? Will upgrades lose it?**
A: In DSH settings (edited via "Settings → 月汐", restart-safe). Upgrades migrate automatically and archive the old config; details in the "migration chain" section of the [router architecture](packages/dsh-kimi-tide/docs/router.md).
---
## Version & Roadmap
> Current version: **v1.3.0 (2026-09-15)**
- What every version gives you: [CHANGELOG.md](CHANGELOG.md)
- Maintainer evidence chain (commit anchors / acceptance records): [docs/release-evidence.md](docs/release-evidence.md)
- Planned: subagent transcription, the 0.8.5 "hardening & packaging" release — tracked in the [evidence doc](docs/release-evidence.md).
---
## Documentation Index
> Three principles of this project: **official first · transparent rules · observable decisions** — routing follows rules you can write, and every automatic pick has a reason and a trail.
**I just want to use it**
- Quick Start (this page)
- FAQ (this page)
- [Changelog](CHANGELOG.md)
**I want to dig deeper**
- [Router architecture](packages/dsh-kimi-tide/docs/router.md): presets / rules / degradation / migration chain / full config reference
- [Interactive architecture diagram](docs/assets/readme/kimi-tide-architecture.html) (open in a browser after download; static version above)
- [DSH host-platform contract research](docs/host-platform-map.md)
- [Project positioning & maintenance strategy](docs/positioning.md)
- [The dual-model collaboration loop](docs/agent-collaboration-loop.md) (how this project itself is built; independent study: [kimi-tide-research](https://github.com/tafcear/kimi-tide-research))
**I want to contribute**
- Report issues, send fixes, or say hi in [Discussions](https://github.com/tafcear/kimi-tide/discussions)
---
## Development & Testing
```bash
cd packages/dsh-kimi-tide
npm install
npm run typecheck # tsc --noEmit
npm test # vitest
npm run build # tsc host build + esbuild browser bundle
```
Quality bar: full test suite green + zero typecheck errors + successful build before committing. This repository practices an "implement → independent review → fix → re-check" dual-model loop (see [`docs/agent-collaboration-loop.md`](docs/agent-collaboration-loop.md)).
**Doc gates**: `npm run check` runs three machine gates — CHANGELOG / README / package version consistency, no broken doc links, and README pair parity (version line / section skeleton / badges / local doc-link set; rules: [`docs/agents/readme-pair.md`](docs/agents/readme-pair.md)). Any user-visible change must update both READMEs (Chinese and English) in the same commit.
**Bilingual four-section release page**: every new version's Release body (= the annotated tag message) must be **bilingual** — a 简体中文 block first, an English block below — with four sections inside each language: ① one-line positioning ② `本次更新` / `What's new` ③ `安装与升级` / `Install & upgrade` ④ `验证与验收` / `Verification & acceptance`. Self-check with `node scripts/check-release-notes.mjs --file ` before tagging; Actions enforces it again before `gh release create` (template and rules: [`docs/agents/release-notes.md`](docs/agents/release-notes.md)).
**Release gate**: before any release (tagging / triggering the Actions release), that version's live-acceptance checklist must pass in full on the real host, and the maintainer approves the tag — "unit tests green" is not "runs in the host". Per-version acceptance records: [docs/release-evidence.md](docs/release-evidence.md).
> **Release rule (maintainers)**: a DSH plugin must declare `dsh.bundle.patch` (pointing at `cordis.patch.yml`) to load as a profile layer. This plugin follows the official spec — do not remove the field when bumping versions.
---
## Contributors
- Thanks to [@dracpet](https://github.com/dracpet) for live-verified diagnosis and community contributions: [PR #1](https://github.com/tafcear/kimi-tide/pull/1) (OAuth expiry refresh), [PR #2](https://github.com/tafcear/kimi-tide/pull/2) (`commands/execute` across host contract versions), [PR #3](https://github.com/tafcear/kimi-tide/pull/3) (YAML-null config normalization), and [Issue #4](https://github.com/tafcear/kimi-tide/issues/4) (rc.2 projection wire-contract diagnosis).
- Thanks to [@pandashere](https://github.com/pandashere) for [dsh-kimi-bridge](https://github.com/pandashere/dsh-kimi-bridge) (MIT): it bootstrapped the early Kimi CLI bridging and validated the panel path kimi-tide later took; retired and archived (history preserved in git) as the official integration matured — thank you.
- Contributions of any form are welcome: report issues, send fixes, or share how you use it in [Discussions](https://github.com/tafcear/kimi-tide/discussions).
---
## License & Compliance
- **kimi-tide itself**: [MIT](LICENSE) (Copyright 2026 kimi-tide contributors)
- **Third-party components**: `@earendil-works/pi-ai` (MIT), `@deepseek-ai/dsh-llm-pi-ai` (MIT, DeepSeek), `schemastery` (MIT), `zod` (MIT), `yaml` (MIT), `dsh-kimi-bridge` (MIT, historical credit — archived)
- **Compliance**: the default path is the **official Console API key**, safe for personal use; Kimi Code subscription terms still apply as officially stated — no high-frequency batch calls or key sharing.
- This repository contains **no credentials**; never commit `~/.dsh/.credentials.yaml` or any key from your environment.