* feat(plugin): install plugins from a GitHub repository URL Allow `/plugins install <github-url>` (and marketplace `source` entries) to take a GitHub repo URL directly. A new `github` source kind joins the existing `local-path` and `zip-url` kinds. Recognized URL forms (parsing in source.ts): - `https://github.com/<o>/<r>` — bare; resolves to latest release tag, falling back to default branch HEAD. - `https://github.com/<o>/<r>/tree/<ref>` — branch / tag / SHA; value passed to codeload in its short form so the backend resolves either. - `https://github.com/<o>/<r>/releases/tag/<tag>` — explicit tag, uses refs/tags/<tag> to avoid same-named-branch ambiguity. - `https://github.com/<o>/<r>/commit/<sha>` — explicit commit SHA. The resolver deliberately avoids `api.github.com`: its 60/hour anonymous quota is shared with every other tool on the egress IP (browser, gh CLI, IDE integrations) and a first-time install failing because some other tool ate the budget is unacceptable UX. Instead we: - GET `github.com/<o>/<r>/releases/latest` with manual redirect and parse the `Location` header (302 → tag URL; 404 → no own release). - Fall back to `codeload.github.com/<o>/<r>/zip/HEAD` for repos with no releases (or for forks that inherit upstream tags but have no own release page, which redirect to bare `/releases`). - Only treat the explicit 404 from `/releases/latest` as "no release" — 5xx, 403, 429, and any other non-2xx status surface a hard error rather than silently installing the default branch, so the user knows when transient GitHub issues changed the install path. UI changes in the TUI: - `/plugins install` now shows a live Braille spinner while resolving and downloading, then flips to a final status that distinguishes Installed (fresh) vs Updated (same repo identity, new version) vs Migrated (source changed, e.g. CDN zip-url → GitHub). - `/plugins list`, the `/plugins` overview, and `/plugins info` show the install provenance inline. `zip-url` installs now display the URL host (e.g. `via code.kimi.com`, `via 127.0.0.1:port`) instead of the opaque `zip-url` literal. GitHub installs show `github <owner>/<repo>@<ref>`. - Three-tier trust badge driven by the marketplace context recorded at install time: `official` (green) for `tier: official`, `curated` (blue) for `tier: curated`, `third-party` (muted) for anything not installed through the marketplace selector. CLI `/plugins install <url>` always records as third-party; the marketplace selector passes the tier through. A re-install replaces the marketplace context: switching to a third-party source clears the badge, which matches the underlying trust change. `installed.json` gains optional `github` and `marketplace` fields (back-compatible). PluginSummary surfaces `source`, `originalSource`, `github`, and `marketplace` so the TUI can label installs without an extra round trip to PluginInfo. The SDK's `session.installPlugin(source)` gains an optional `{ marketplace }` second argument so the marketplace selector can forward `{ id, tier }` through RPC; the CLI install path omits it. Tests: 112 plugin-suite tests (URL parser, resolver, store round-trip, manager integration). The manager integration tests assert codeload URLs shape (short form for `/tree/<ref>`, explicit `refs/tags/` for `/releases/tag/`) and verify marketplace context is persisted across reloads and cleared on a third-party re-install. * chore(changeset): plugin install from GitHub * docs(plugins): document GitHub install URLs and trust badges * fix(plugin): preserve URL-encoded characters in GitHub ref names Git permits ref characters that have special meaning in URLs — most notably `#`, which is a valid tag character (e.g. `release#1`) but the URL fragment delimiter. The resolver decoded the tag from GitHub's `/releases/latest` 302 redirect Location header and then interpolated the raw value into the codeload URL. The literal `#1` became a fragment and the HTTP request reached the server as `…/refs/tags/release` — a wrong or truncated ref, leading to install failure for a release whose URL was otherwise valid. Two symmetric changes: - The codeload URL builder now splits the ref on `/` (so multi-segment refs like `feat/foo` keep their path separators) and percent-encodes each segment. - The GitHub URL parser now percent-decodes each segment from the URL's pathname when extracting `/tree/<ref>`, `/releases/tag/<tag>`, and `/commit/<sha>`. Storage and display see the human-readable Git ref name; the resolver re-encodes on the way out. Malformed `%xx` sequences in user-typed URLs are tolerated: we keep the raw segment so the caller surfaces a normal "ref not found" error downstream instead of crashing during parse. * fix: restrict plugin trust badges * chore: remove fetch when show plugin list --------- Co-authored-by: qer <Anna_Knapprfr@mail.com>
8 KiB
Plugins
Plugins package reusable Kimi Code CLI capabilities into installable units. A plugin can add Agent Skills, load a skill at session start, and declare MCP servers for real tool access.
Use plugins when you need to share workflows, connect to external services, or install extensions from the official marketplace. Kimi Code CLI loads plugins conservatively: installing a plugin does not run Python, Node.js, shell, hook, or command scripts bundled with it.
Installing and managing plugins
Run /plugins in the TUI to open the plugin manager. From there you can install plugins, browse the official marketplace, inspect plugin details, enable or disable plugins, remove them, reload install records, and manage MCP servers.
Useful keys:
| Key | Action |
|---|---|
Enter or → |
Open the selected item, or install the selected marketplace plugin. |
Space |
Enable or disable an installed plugin; install or update a marketplace plugin. |
M |
Manage MCP servers for the selected plugin. |
← or Esc |
Go back. |
Most users only need the interactive manager. You can also use these slash commands directly:
| Command | Description |
|---|---|
/plugins |
Open the interactive plugin manager. |
/plugins list |
List installed plugins. |
/plugins install <path-or-url> |
Install from a local directory (relative paths and ~/ supported), a zip URL, or a GitHub repository URL. |
/plugins marketplace [source] |
Browse the official marketplace; optionally pass a marketplace JSON path or URL. |
/plugins info <id> |
Show plugin details and diagnostics; opens the manager when <id> is omitted. |
/plugins <id> |
Show details for a plugin; same as /plugins info <id>. |
/plugins enable <id> |
Enable a plugin; opens the manager when <id> is omitted. |
/plugins disable <id> |
Disable a plugin; opens the manager when <id> is omitted. |
/plugins remove <id> |
Remove a plugin; requires confirmation. |
/plugins reload |
Reload installed.json and each plugin manifest. |
/plugins mcp enable <id> <server> |
Enable an MCP server declared by a plugin. |
/plugins mcp disable <id> <server> |
Disable an MCP server declared by a plugin. |
For general slash command behavior, see Slash commands.
GitHub URLs accept four forms. The bare URL https://github.com/<owner>/<repo> installs the repository's latest GitHub release; if the repo has no release, the default branch is installed instead. https://github.com/<owner>/<repo>/tree/<ref> installs a specific branch, tag, or short commit SHA. https://github.com/<owner>/<repo>/releases/tag/<tag> and https://github.com/<owner>/<repo>/commit/<sha> pin to an explicit tag or commit. Network calls go to github.com redirects and codeload.github.com archive downloads only; api.github.com is not used.
The plugin manager shows each install's source and a trust badge. kimi-official marks plugin zips downloaded from https://code.kimi.com/kimi-code/plugins/official/; curated marks plugin zips downloaded from https://code.kimi.com/kimi-code/plugins/curated/. third-party marks anything else, including GitHub installs, local directories, custom marketplace sources, and other URLs.
Kimi Code CLI currently installs plugins per user. Records are stored under $KIMI_CODE_HOME/plugins/ and apply across all projects. Project-local, repository-shared, admin-managed, and --scope installs are not supported yet.
Plugin changes apply to new sessions only. After installing, enabling, disabling, removing, or reloading a plugin, or changing an MCP server toggle, start a fresh session with /new. The current session is not updated; new skills, session-start behavior, and MCP servers load only in new sessions.
Local installs are copied into $KIMI_CODE_HOME/plugins/managed/<id>/, and Kimi Code CLI always runs from that managed copy. Editing the original source directory after install has no effect until you reinstall — /plugins reload re-reads install records and manifests, not the original source. Removing a plugin deletes only its install record; the managed copy and the original source files are left on disk.
Plugin manifest
A plugin is a directory or zip file with a manifest at one of these paths:
<plugin_root>/kimi.plugin.json
<plugin_root>/.kimi-plugin/plugin.json
When both files exist, kimi.plugin.json takes precedence. Kimi Code CLI does not read root plugin.json or .codex-plugin/plugin.json.
Example:
{
"name": "kimi-finance",
"version": "1.0.0",
"description": "Finance data and analysis workflows for Kimi Code CLI",
"skills": "./skills/",
"sessionStart": {
"skill": "using-finance"
},
"interface": {
"displayName": "Kimi Finance",
"shortDescription": "Market data and financial analysis workflows"
}
}
Supported fields:
| Field | Description |
|---|---|
name |
Required plugin id. Must match [a-z0-9][a-z0-9_-]{0,63}. |
version, description, keywords, author, homepage, license |
Display metadata. |
interface |
Fields shown in /plugins, such as displayName, shortDescription, longDescription, developerName, and websiteURL. |
skills |
One or more ./ paths inside the plugin root. If omitted, a root SKILL.md is treated as a single skill root. |
sessionStart.skill |
Loads the named plugin skill into the main agent at the start of a new or resumed session. |
skillInstructions |
Extra instructions included whenever a skill from this plugin is loaded. |
mcpServers |
MCP server declarations. Enabled by default; can be disabled from /plugins. |
Unsupported runtime fields such as tools, commands, hooks, apps, inject, configFile, config_file, and bootstrap are reported as diagnostics and ignored.
Skills and session start
Plugin skills use the same SKILL.md format as ordinary Agent Skills. A common layout:
my-plugin/
kimi.plugin.json
skills/
using-my-plugin/
SKILL.md
another-workflow/
SKILL.md
sessionStart.skill loads one plugin skill into the main agent at session startup. It is useful for setup instructions, workflow rules, or mapping terminology from another tool to Kimi Code CLI. It injects text only and does not execute code.
skillInstructions is included with every skill from the plugin, whether the skill is loaded by sessionStart.skill, by /skill:<name>, or by automatic skill invocation.
MCP servers in plugins
Use mcpServers when a plugin needs real tool access, such as reading data from an external service or running a local helper process. Plugin MCP servers use the same schema as MCP.
Stdio server:
{
"mcpServers": {
"finance": {
"command": "uvx",
"args": ["kimi-finance-mcp"]
}
}
}
HTTP server:
{
"mcpServers": {
"docs": {
"url": "https://example.com/mcp"
}
}
}
For stdio servers, command may be a command on PATH or a ./ path inside the plugin root. If cwd is set, it must also start with ./ and stay inside the plugin root; other values are rejected and the server is omitted. Plugin MCP servers inherit the current process environment; values under env are literal overrides.
Plugin MCP servers start only in new sessions. To disable or re-enable one, run /plugins, select the plugin, and press M. Shortcut commands are also available:
/plugins mcp disable kimi-finance finance
/new
/plugins mcp enable kimi-finance finance
/new
Security model
Plugins expose a limited loading surface:
- Install and session startup read only plugin manifests and Markdown skill files.
- All paths must stay inside the plugin root after symlinks are resolved.
- Command-backed plugin tools, hooks, and legacy tool runtimes are not executed by the plugin loader.
- MCP servers declared by enabled plugins start only in new sessions and can be disabled from
/plugins. - Bad manifests or unsafe paths produce diagnostics in
/plugins info <id>without crashing unrelated sessions.