kimi-oauth-bridgeOpenCode plugin that brings the official Kimi OAuth device flow and Kimi-specific coding request fields to opencode, matching upstream kimi-cli.
0
46
46 in 7 days
30.3
Multi-signal model
5 days ago
2026-08-14
Install and configure
opencode.jsonWrites to this project's opencode.json — applies to this repository only.
opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["kimi-oauth-bridge@1.4.4"]
}Writes to ~/.config/opencode/opencode.json — applies to every project.
~/.config/opencode/opencode.json
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["kimi-oauth-bridge@1.4.4"]
}If you want to modify the plugin locally, install it into the project and reference the local path.
shell
pnpm add -D kimi-oauth-bridgeopencode loads npm dependencies through its embedded runtime on startup and caches them locally — no manual global install needed.
kimi-oauth-bridge
An opencode plugin that makes the Kimi Code path in opencode work like the official kimi-cli, using Kimi-specific extensions instead of just a generic OpenAI-compatible provider.
Note: This is an unofficial community plugin. It is not affiliated with or endorsed by Moonshot AI.
Compared with stock opencode Kimi setups, this plugin:
- uses the official Kimi device-flow OAuth against
https://auth.kimi.com - talks to
https://api.kimi.com/coding/v1through@ai-sdk/openai-compatible - sends the same
User-Agent/X-Msh-*fingerprint headers askimi-cli - reuses
~/.kimi/device_idforX-Msh-Device-Id - adds
prompt_cache_key,thinking, andreasoning_effortonly when the selected Kimi Code model's discovered capabilities permit them - discovers the authoritative, account-specific Kimi Code catalog from
/coding/v1/models, including exact ids, display names, context lengths, tools, media, and thinking capabilities - keeps tokens in opencode's auth store while mirroring
kimi-cli's refresh / retry behavior - provides a
/kimi:usageTUI command to check subscription usage
Contributor and agent documentation lives in AGENTS.md.
Quick Start
- Install the plugin globally:
opencode plugin kimi-oauth-bridge --global - If you are testing a local checkout instead of the published package, install the checkout path instead:
opencode plugin /absolute/path/to/kimi-oauth-bridge --global - Run
opencode auth login -p kimi-oauth-bridgeand approve the device flow in your browser. - Paste the provider block from Configure into your opencode config.
- Select any model shown in the account-specific Kimi Code catalog that login prints.
Requirements
opencode>= 1.4.6- A Kimi account with an active Kimi For Coding subscription (the same plan that works with kimi-cli)
Install
Recommended:
opencode plugin kimi-oauth-bridge --global
That installs the published package and adds the plugin to your global opencode config, so opencode auth login -p kimi-oauth-bridge works from any directory.
From a local checkout:
opencode plugin /absolute/path/to/kimi-oauth-bridge --global
That is the command you want when you are editing this repo and want opencode to load your working tree. Changing files in a checkout does nothing unless opencode is pointed at that checkout path.
If you prefer managing plugin registration manually, add the plugin to the plugin list in ~/.config/opencode/opencode.json or a project-local .opencode/opencode.json:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["kimi-oauth-bridge"]
}
For a local checkout, point the plugin entry at the repo root instead of the npm package name:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["/absolute/path/to/kimi-oauth-bridge"]
}
If you use a project-local .opencode/opencode.json, the plugin only exists when you run opencode inside that project tree. If you want opencode auth login to work from anywhere, use the --global install above.
Configure
After login, the plugin projects the authenticated catalog before OpenCode initializes the provider and prints a ready-to-paste provider block. Use that generated block when possible: its model ids and variants come directly from Kimi.
If you need a pre-login bootstrap entry, use only the canonical fallback below. It is not an entitlement list; discovery replaces it with the authenticated catalog at runtime:
{
"$schema": "https://opencode.ai/config.json",
"provider": {
"kimi-oauth-bridge": {
"name": "Kimi For Coding (OAuth)",
"npm": "@ai-sdk/openai-compatible",
"options": {
"baseURL": "https://api.kimi.com/coding/v1"
},
"models": {
"kimi-for-coding": {
"name": "Kimi For Coding"
}
}
}
}
}
Important: Do not predeclare entitlement-gated models or static thinking levels. The authenticated catalog supplies media support and variants per model, and the plugin backfills that runtime metadata before opencode transforms the request.
This block is for using the model after login. It does not register the auth provider by itself. What makes opencode auth login -p kimi-oauth-bridge work is the plugin being loaded via opencode plugin ... or the plugin array above.
Use these ids exactly as written:
- provider id
kimi-oauth-bridge-- the plugin'sauthandchat.paramshooks match on it. - bootstrap model id
kimi-for-coding-- retained only as the cold fallback before a successful authenticated discovery.
After discovery, select one of these exact wire ids; the labels are what OpenCode displays:
| Wire id | Label |
|---|---|
kimi-for-coding |
K2.7 |
kimi-for-coding-highspeed |
K2.7 HighSpeed |
k3 |
K3 (1M) |
k3-256k |
K3 (256K) |
K2.7 has one visible always-on on variant, not synthetic low, medium, or high effort levels. Do not substitute Moonshot Platform ids.
Note. The provider id is intentionally not
kimi-for-coding. That id is already published by models.dev and points at a static-API-key flow using a different SDK and auth shape. Using a distinct id keeps the two paths from colliding under a singleopencode auth loginentry.
Log in
opencode auth login -p kimi-oauth-bridge
Then complete the device-flow approval in your browser.
During login the plugin:
- shows a verification URL and user code
- stores the OAuth token in opencode's auth store
- discovers every Kimi Code model your account is entitled to, with its exact id, display name, context length, tools, media, and thinking capabilities
- projects that full catalog before provider initialization and prints a config hint with variants at each model's top level
Access tokens refresh automatically while you use the model.
Troubleshooting: Unknown provider "kimi-oauth-bridge"
That error means opencode did not load this plugin at all. The Kimi OAuth flow has not started yet.
The usual causes are:
- You skipped
opencode plugin kimi-oauth-bridge --globaloropencode plugin /absolute/path/to/kimi-oauth-bridge --global. - You edited a local checkout, but opencode is not pointed at that checkout path.
- You put the plugin in a project-local
.opencode/opencode.json, but ranopencode auth loginfrom another directory. - You added the
providerblock, but not thepluginentry or plugin install.
Fastest fix:
- Install the plugin globally with
opencode plugin kimi-oauth-bridge --global, oropencode plugin /absolute/path/to/kimi-oauth-bridge --globalfor a checkout. - Confirm your opencode config now contains the plugin entry.
- Run
opencode auth login -p kimi-oauth-bridgeagain.
Troubleshooting: Images not working / "this model does not support image input"
opencode gates image input on model metadata. The plugin applies attachment, modalities, and input capabilities from the authenticated model entry before opencode transforms the request.
Fix: log in again or refresh the model list, then select a catalog model whose discovered metadata includes image input. Do not force image support into a bootstrap entry for a model Kimi has not confirmed for your account.
If a generated config block is stale after an entitlement change, replace it with the newest login hint.
Login and refresh details
- The plugin queries
/coding/v1/modelsduring login and on refresh to discover the complete current account catalog. In OpenCode 1.18.5, non-Models.dev providers skip the genericprovider.modelshook, so the plugin eagerly projects the authenticated catalog through its asyncconfighook before provider initialization;provider.modelsremains for compatible hosts. A successful nonempty response removes stale configured ids; a failed or empty response leaves the cold fallback or last known-good catalog intact. - The plugin uses each model's discovery response to backfill context, tool use, image/video support, and thinking variants into opencode's runtime metadata, so pasted or dropped images reach Kimi instead of being downgraded into local error text.
- Each generated model uses
limit: { context: context_length, output: 0 };output: 0uses OpenCode's default output ceiling rather than asserting a Kimi output limit. When Kimi metadata lackslow,medium, orhigh, the generated config adds a{ disabled: true }sentinel so OpenCode does not offer that synthetic effort level. - Model discovery runs again on every token refresh, and a fresh loader instance can re-query
/coding/v1/modelson first use. Catalog metadata stays in memory only and is never persisted into opencode'sauth.json. - On a
401, the loader refreshes the access token once and retries the request once. - Refreshes are coordinated through opencode's live auth store so concurrent workspaces do not keep using an older refresh-token chain from a stale
OPENCODE_AUTH_CONTENTsnapshot.
Debug logging
Set KIMI_OAUTH_BRIDGE_DEBUG_LOG=1 when launching opencode to append each Kimi-bound request's timestamp, source, method, URL, and User-Agent to ~/.kimi/kimi-oauth-bridge-debug.log; Authorization, cookies, and request bodies are never logged. Values 1 and true use that default path, while any other non-empty value except 0 or false is treated as a custom log path. An unset value, an empty value, 0, or false disables logging without touching a file.
KIMI_OAUTH_BRIDGE_DEBUG_LOG=1 opencode serve ...
Use
Select kimi-oauth-bridge/<exact-discovered-id> in opencode. The id in the request body remains exactly the selected catalog id; the plugin never aliases a dynamic selection to another discovered model.
OpenClaw
This plugin also ships as an OpenClaw provider plugin. The same host-neutral core drives both hosts, so the OAuth device flow, the 7 X-Msh-* fingerprint headers, the catalog discovery, and the thinking/prompt_cache_key body fields are identical across hosts.
Install (OpenClaw)
From a local checkout:
openclaw plugins install --link /absolute/path/to/kimi-oauth-bridge
This registers the plugin via package.json#openclaw.extensions, pointing at src/adapters/openclaw/index.ts. For production use, the built bundle (dist/openclaw.js, with openclaw externalized) is referenced via package.json#openclaw.runtimeExtensions.
Log in (OpenClaw)
openclaw models auth login --provider kimi-oauth-bridge --method device-code
Open the verification URL, enter the device code, and approve in your browser. The token enters OpenClaw's auth-profile store (the plugin never persists tokens itself).
Use (OpenClaw)
openclaw models
Lists every Kimi Code model your account is entitled to. Select one and start chatting. The OpenClaw openai-completions transport handles streaming; wrapStreamFn injects the fingerprint headers and the Kimi thinking body field; prepareExtraParams resolves the declarative reasoning_effort/thinking pair from the catalog model's metadata.
Behavior notes (OpenClaw)
- OAuth-only: the plugin enforces the OAuth-only contract — a static
KIMI_API_KEYis never used for discovery or runtime. If no OAuth profile is configured, the catalog falls back to the coldkimi-for-codingmodel. - Scoped catalog cache: discovery is scoped per
(agentDir, workspaceDir), so a profile or agent switch does not inherit another scope's discovered models. - Refresh:
refreshOAuthis the single refresh path; OpenClaw calls it on token expiry. Same-request 401 retry is host-dependent and treated as a live-integration probe item (see AGENTS.md).
Use (OpenCode)
The default variant-cycle keybind is Ctrl+T. Available variants are capability-derived for the selected model:
- Models with no reasoning support, or
supports_thinking_type: "no", expose no thinking fields or thinking variants. supports_thinking_type: "only"stays enabled and exposes one visibleonvariant, never an off or fake effort-level variant. This is how the standard and highspeed K2.7 Kimi Code entries avoid routing a disabled-thinking selection away from the selected model.supports_thinking_type: "both"without effort support exposesoffandonmodes.- When
think_efforts.supportis true, variants are exactly the server-providedvalid_efforts; the server-provideddefault_effortis used by default. For example, an entitled K3maxvariant sendsreasoning_effort: "max"unchanged.
These variants only affect Kimi's reasoning request fields. They do not switch models or auth paths.
Every currently managed Kimi Code catalog request gets prompt_cache_key set to opencode's session id. That mirrors kimi-cli's cache hint so follow-up turns in the same session can reuse Kimi's prompt cache. Other providers never receive it.
Usage command
The plugin registers a /kimi:usage TUI slash command that shows your Kimi Code subscription usage (weekly and rolling-window limits) in a compact dialog. Run it from the opencode command palette.
Why this plugin exists
Stock opencode can already talk to generic Moonshot and OpenAI-compatible endpoints. This plugin exists for the Kimi Code path specifically: it brings the official Kimi OAuth flow and Kimi-specific request behavior into opencode without sharing kimi-cli's credential files.
What it adds over the generic route.
- OAuth device flow against
https://auth.kimi.com. @ai-sdk/openai-compatiblepointed athttps://api.kimi.com/coding/v1.prompt_cache_keyset to opencode's session id for every managed catalog model, for session-scoped cache reuse.- Per-model
thinking+reasoning_effortfields derived from Kimi's current capability metadata, without invented effort levels or clamping an official value such asmax. - The seven
X-Msh-*headers and a kimi-cli-shapedUser-Agent. ~/.kimi/device_idshared with a locally-installed kimi-cli.- Runtime model discovery from
/coding/v1/models, including every entitled exact id plusdisplay_name,context_length, protocol, tool use, media-input, and thinking capabilities. - Tokens stored in opencode's auth store under a dedicated provider id, so the plugin and kimi-cli keep independent refresh-token chains and do not invalidate each other.
- Live auth-store rereads plus a provider-scoped refresh lock, so concurrent opencode workspaces converge on the latest refresh-token chain instead of tripping
invalid_grant. - Streaming,
reasoning_contentdeltas, and tool-call schemas are handled upstream by@ai-sdk/openai-compatible-- not reimplemented here.
Request fields in detail
| Field | Wire shape | Purpose |
|---|---|---|
prompt_cache_key |
top-level body, snake_case, set to opencode's sessionID |
Added only for models in this provider's current catalog; enables session-scoped cache reuse. |
thinking + reasoning_effort |
thinking: { type: "enabled" | "disabled" } with optional sibling reasoning_effort |
Derived from supports_reasoning, supports_thinking_type, and think_efforts; official effort values are preserved exactly. |
Seven X-Msh-* headers + UA |
User-Agent, X-Msh-Platform, X-Msh-Version, X-Msh-Device-Name, X-Msh-Device-Model, X-Msh-Device-Id, X-Msh-Os-Version |
Matches kimi-cli's _common_headers() at the pinned KIMI_CLI_VERSION. |
/coding/v1/models discovery |
id, display_name, context_length, protocol, tool/media/thinking capability fields |
Supplies the authoritative, in-memory model catalog and runtime metadata. |
~/.kimi/device_id |
UUID persisted on disk, embedded in X-Msh-Device-Id |
Sends the same X-Msh-Device-Id as a locally-installed kimi-cli. |
Thinking-field mapping is model-specific rather than a global effort table. A selected effort is sent only when that model's valid_efforts includes it; always-thinking models send enabled thinking and no off variant; no-reasoning models send neither thinking field.
Files the plugin touches
| Path | Purpose |
|---|---|
~/.kimi/device_id |
Stable UUID used in X-Msh-Device-Id. Shared with kimi-cli. |
opencode auth store (auth.json in opencode's XDG data dir; on Linux typically ~/.local/share/opencode/auth.json) |
Token storage, managed by opencode through client.auth.*; the plugin also live-reads this entry to avoid stale workspace auth snapshots during refresh. |
No other state is persisted. Credentials are never written to ~/.kimi/credentials/; that path belongs to kimi-cli, and sharing it would cause refresh-token races between the two clients.
Architecture at a glance
opencode core
──────────────────────────────────────────────────
auth.login ──> plugin.auth.authorize() device-code flow, poll
└──> oauth.ts
chat ────────> plugin.loader() custom fetch that:
├──> ensureFresh() proactive refresh
└──> kimiHeaders() 7 X-Msh-* headers
/models catalog discovery
401 -> force-refresh + retry
chat.params ─> plugin "chat.params" thinking / reasoning_effort /
prompt_cache_key
/kimi:usage ─> tui.tsx subscription usage dialog
└──> usage.ts
A full description of the invariants that keep this working is in AGENTS.md, under "Architecture" and "Contracts to keep intact".
License
MIT.