返回 CodeWhale
PLUGINS.md
根目录 / docs / PLUGINS.md
1 # Installing plugins
2
3 To create a bundle, start with [Write your first Codewhale plugin](PLUGIN_AUTHORING.md)
4 and its runnable Skills example.
5
6 This is the walkthrough for the `/plugin install` on-ramp (v0.9.4, #5182).
7 [PLUGIN_BUNDLES.md](PLUGIN_BUNDLES.md) remains the contract for the bundle
8 format (`plugin.json`, compatible `kimi.plugin.json` or
9 `.claude-plugin/plugin.json`, or legacy `plugin.toml`), discovery, validation, and
10 the trust/enable lifecycle — this document covers how bits get onto disk in
11 the first place.
12
13 `/plugin suggest <task>` is a local, read-only companion: it ranks already
14 installed bundles (name, keywords, description, bundled skill names, declared
15 hosts) and any marketplace catalogs you have added with `/plugin marketplace add`.
16 It explains the match and gives the next review, enable, or catalog-install
17 step, but never installs, trusts, or enables a bundle on its own.
18
19 Sending a task also surfaces one quiet toast when the prompt strongly matches
20 an installed-but-idle plugin or a catalog candidate you do not have yet — for
21 example a prompt about Supabase suggesting `/plugin trust supabase` or
22 `/plugin marketplace install <catalog> supabase`. Description-only matches do
23 not toast. While you type, a one-line composer CTA (`Install {name} plugin?`)
24 offers the same review command after a short debounce; it never auto-installs,
25 hides when the plugin is already active, and stays dismissed for that name
26 this session. Matching idle or catalog plugins are also appended on send as
27 an `<recommended_plugins>` user-turn block (not the pinned system prefix);
28 the model can call `request_plugin_install` to surface review for the human
29 without changing disk. Codewhale does not invent a remote plugin URL; missing
30 plugins are suggested only from catalogs you added. On-disk bundle changes
31 still toast `/plugin reload` on send and between turns.
32
33 ## Sources
34
35 `/plugin install <spec>` accepts three source kinds:
36
37 ```text
38 /plugin install ./path/to/bundle # local directory (copied)
39 /plugin install github:owner/repo # GitHub archive of the default branch
40 /plugin install https://example.com/x.tar.gz # direct tarball URL
41 ```
42
43 There is no registry index and no `git clone` in v1 — tarball-only fetching
44 keeps the size cap and no-symlink guarantees of the installer. Downloads are
45 gated by the per-domain network policy: an unknown host returns a
46 "needs approval" error naming the host (`/network allow <host>`, then retry),
47 a denied host aborts without touching disk.
48
49 The fetched tree must contain **exactly one** bundle root — a directory
50 holding a `plugin.json`, compatible `kimi.plugin.json`,
51 `.claude-plugin/plugin.json`, or legacy `plugin.toml` manifest. Kimi bundles are accepted when they use Codewhale-compatible Skills,
52 commands, agents, and MCP declarations; unsupported Kimi runtime fields fail
53 closed instead of being silently ignored. Bundles land in
54 the user plugins root at `~/.codewhale/plugins/<name>/`, where `<name>` is the
55 manifest's plugin name.
56
57 Claude bundles keep their metadata in `.claude-plugin/plugin.json` and their
58 components at the bundle root. The importer supports skills, commands, agents,
59 and MCP servers declared inline or in root `.mcp.json` (flat server map or an
60 `mcpServers` wrapper). Claude `http` transport maps to Streamable HTTP. Relative
61 sources in a `.claude-plugin/marketplace.json` catalog resolve from the marketplace
62 repository root. The whole bundle remains subject to the same review hashes and
63 path checks as native plugins.
64
65 Remote MCP headers can name credentials without embedding them: exact
66 `Bearer ${ENV_NAME}` authorization values become `bearer_token_env_var`, and
67 exact `${ENV_NAME}` header values become `env_headers`. Import reads no credential
68 values. Literal credentials and compound templates are rejected.
69
70 This is a compatible subset: hooks, LSP declarations, custom MCP file paths, and
71 `${CLAUDE_PLUGIN_ROOT}` expansion are rejected with an explanation; no partial
72 plugin is installed. Installing a remote MCP declaration does not complete its
73 authentication. Plugin-contributed remote servers retain the existing explicit
74 credential requirements; this importer does not enable plugin OAuth.
75
76 ## The guided flow
77
78 Installing never activates anything. The command places the bits, then drops
79 you straight into the standard capability review:
80
81 ```text
82 /plugin install github:someone/neat-plugin
83 → Installed plugin 'neat-plugin' to ~/.codewhale/plugins/neat-plugin.
84 It is disabled and untrusted. Review its requested authority below…
85 <full inventory, permissions, MCP authority render>
86 /plugin trust neat-plugin <content-hash>.<capability-hash>
87
88 /plugin trust neat-plugin <paste the token> # records the hash-bound receipt
89 /plugin enable neat-plugin # activates for this workspace
90 ```
91
92 This is the same review render and confirmation token as `/plugin trust
93 <name>` — trust is the strict hash-bound receipt flow, not an advisory marker.
94 If the bundle's content or declared capabilities change, the receipt stops
95 matching and the plugin goes inactive until you review again.
96
97 ## Update and uninstall
98
99 ```text
100 /plugin update <name> # re-download, byte-compare, atomic swap if changed
101 /plugin disable <name> # required before uninstall
102 /plugin uninstall <name> # deletes the bundle and prunes its state entry
103 ```
104
105 - `update` re-downloads the recorded source. Identical bytes are a no-op; a
106 changed bundle is swapped atomically and its trust receipt is automatically
107 invalidated (the hash no longer matches), so re-review is forced before the
108 plugin can activate again. Plugins installed from a local path cannot be
109 re-downloaded. To replace their installed copy, disable and uninstall it,
110 then run `/plugin install <path>` and review the new bundle; the original
111 source directory is left intact. See the [local authoring loop](PLUGIN_AUTHORING.md#4-iterate-and-review-changes).
112 - `uninstall` refuses enabled plugins (disable first), deletes the bundle
113 directory, and removes its persisted trust/enablement entry.
114
115 ## Safety rules
116
117 - Every install carries an `.installed-from` provenance marker. The installer
118 **refuses to overwrite or delete** a bundle that lacks it — hand-placed
119 bundles under `~/.codewhale/plugins/` are never clobbered.
120 - Tarballs are size-capped and extracted into a private staging directory
121 first; path traversal (`..`, absolute paths) and symlinks/hard links inside
122 the bundle are rejected, and the destination only appears via an atomic
123 rename after every check passes.
124 - Install pre-checks the name against builtin and workspace bundles so a
125 higher-precedence bundle cannot silently shadow (or be shadowed by) the
126 install.
127 - Newly installed bits are always **disabled and untrusted**; enablement only
128 ever happens through the explicit trust review above.
129
129 lines MARKDOWN