返回 CodeWhale
SKILLS.md
根目录 / docs / SKILLS.md
1 # Skills Manager
2
3 In the terminal, `/skills` opens **Extensions → Skills**. Enter on a skill opens the dedicated manager, also available directly through `/skills manage`, for existing install, update, remove, and trust operations. `/skill <name>` still activates a skill, and the explicit inspection, remote, sync, and suggestion subcommands remain available.
4
5
6 > 阅读简体中文版:[zh_hans/SKILLS.md](zh_hans/SKILLS.md)
7
8 Skills are reusable `SKILL.md` instruction packs. Codewhale discovers them from
9 several roots, but **only Codewhale-owned directories are writable**. The unified
10 `/skills manage` manager is the interactive surface for audit and mutation; slash
11 aliases share the same write path.
12
13 For Claude Code plugin boundaries, see [CLAUDE_PLUGIN_COMPAT.md](CLAUDE_PLUGIN_COMPAT.md).
14 For `skills_dir` and `[skills]` config keys, see [CONFIGURATION.md](CONFIGURATION.md).
15
16 ## Architecture (four layers)
17
18 | Layer | Role |
19 | --- | --- |
20 | **Root catalog** | Single source of precedence and ownership (`SkillRootCatalog`). |
21 | **Audit** | Read-only, unmerged on-disk inventory (status, digest, actions). |
22 | **Mutation controller** | Only writer for install / import / update / remove / trust. |
23 | **Skills manager view** | TUI: emits events only; never writes files itself. |
24
25 Runtime discovery (`SkillRegistry`) still merges skills for the model. Audit
26 intentionally does **not** merge — it shows every on-disk copy so conflicts and
27 shadowing stay visible.
28
29 ## Ownership and roots
30
31 **Writable (Codewhale-owned)**
32
33 | Scope | Path |
34 | --- | --- |
35 | Project | `<workspace>/.codewhale/skills/` |
36 | Global | `~/.codewhale/skills/` |
37
38 **Read-only compatible** (discover / import source only — never mutated in place)
39
40 Examples: `<workspace>/.agents/skills`, `./skills`, `.claude/skills`,
41 `.cursor/skills`, `.opencode/skills`, `~/.agents/skills`, `~/.claude/skills`,
42 and similar harness layouts.
43
44 **Audit-only (not runtime-active)**
45
46 - Flat `<workspace>/skills` is an audit candidate until `[skills] flat_workspace_root = true`; an explicit `skills_dir` can also select it.
47 - `.codex/skills` appears in **compatible** audit scans so operators can see it.
48 It does **not** join the runtime discovery set.
49
50 Configured `skills_dir` that is not one of the owned Codewhale roots stays
51 read-only. Discovery and the manager can list it; mutations still target owned
52 project/global roots only.
53
54 Within each scope, the owned `.codewhale/skills` root wins name collisions.
55 Project order is `.codewhale`, `.agents`, `.claude`, `.opencode`, `.cursor`, then
56 an opted-in flat `skills` root. Global order is `.codewhale`, `.agents`, `.claude`,
57 then legacy `.deepseek`. Project roots precede global roots. Shadowing warnings
58 name both copies, so install and update select the owned copy in that scope.
59
60 Every root inside the workspace — owned, compatible, or a configured
61 `skills_dir` that resolves there — loads only once the workspace is trusted
62 (`/trust on --save`). Until then discovery names the skipped directories in its
63 warning, and the session's skills directory falls back to the global one.
64
65 ## Slash commands
66
67 | Command | Behavior |
68 | --- | --- |
69 | `/skills` | Opens Extensions → Skills (owned-only scan, **no network**). |
70 | `/skills manage` | Opens the dedicated Skills Manager for audit and mutation. |
71 | `/skills <prefix>` | Text list filtered by name prefix. |
72 | `/skills inspect` | Text discovery mode, searched directories, and source paths. |
73 | `/skills --remote` | Explicit registry listing (network). |
74 | `/skills suggest <task>` | Rank up to three remote skills for a task, with matching evidence and an explicit install command (network; no install). |
75 | `/skills sync` | Explicit registry → local cache sync (network). |
76 | `/skill <name>` | Activate a skill for the next turn. |
77 | `/skill install [--project\|--global] <spec>` | Install via mutation controller. |
78 | `/skill update [--project\|--global] <name>` | Update a managed skill from its registry provenance. |
79 | `/skill uninstall [--project\|--global] <name>` | Remove a managed skill. |
80 | `/skill trust [--project\|--global] <name>` | Write digest-bound advisory trust. |
81
82 Notes:
83
84 - There is **no** `/skills audit` subcommand. Use the manager (and `c` to toggle
85 compatible roots) or `/skills inspect` for discovery details.
86 - Bare `/skill install <spec>` (no scope flag) installs into the Codewhale
87 **global** owned root.
88 - `/skills suggest` only reads the curated registry through the existing
89 network policy. It never downloads, trusts, enables, or activates a skill;
90 each result gives a separate `/skill install <name>` command for the user to
91 choose.
92 - If the same name exists in both project and global owned roots, update /
93 uninstall / trust require `--project` or `--global`.
94 - If a name exists only under a compatible external root, writes are refused;
95 import it through `/skills manage` instead of editing harness directories.
96
97 ## Skills Manager (TUI)
98
99 Direct manager path: type `/skills manage` and confirm. The surface is zero-network on
100 open (owned-only audit).
101
102 | Key | Action |
103 | --- | --- |
104 | `↑`/`↓` or `j`/`k` | Move selection |
105 | `Enter` | Primary available action / confirm pending prompt |
106 | `i` | Import (external → owned) |
107 | `u` | Update (managed + registry provenance) |
108 | `r` | Remove (managed; confirms first) |
109 | `t` | Trust (managed; digest-bound) |
110 | `s` | Toggle import target: project ↔ global |
111 | `c` | Toggle scan: owned-only ↔ compatible (still local disk only) |
112 | `Esc` | Cancel confirm, or close the manager |
113
114 The view never calls install helpers or touches the filesystem. It emits a
115 mutation request; the host runs the controller, shows a receipt, and rebuilds
116 the inventory.
117
118 ## Bundled catalog tiers
119
120 Codewhale presents its shipped skills in two compact tiers so agentic workflows
121 are not buried under document and integration helpers:
122
123 - **Core agentic** — planning, implementation, debugging, review, verification,
124 delegation, Fleet, release, and `best-of-n` comparison workflows.
125 - **Format & tooling** — document formats, data visualization, frontend and web
126 testing, and skill/plugin/MCP authoring helpers.
127
128 Workspace, user, and compatible-harness skills stay labeled **custom**; Codewhale
129 does not guess their intent from their name. The shipped pack also does not
130 advertise capabilities the runtime lacks. In particular, image understanding
131 is available, but an image-generation skill is not bundled until a real
132 image-generation tool exists.
133
134 Repository-maintenance and release-operator helpers (the `gh-*` skills and
135 `codew-release-qa-sweep` under [`skills/`](skills/README.md)) are **not** part
136 of the end-user starter pack and are never auto-installed; a catalog-matrix
137 test pins that boundary. Shipping them as an optional bundle is plugin-delivery
138 work tracked separately in
139 [#4836](https://github.com/codewhale-hq/CodeWhale/issues/4836).
140
141 ### Invocation and alias metadata
142
143 Bundled and user skills may declare two runtime-routing fields in frontmatter:
144
145 | Field | Meaning |
146 | --- | --- |
147 | `invocation: model+user` | The default; the skill appears in the model's compact catalogue and can be loaded by the model or user. |
148 | `invocation: explicit-only` | The skill remains loadable by an explicit name, but is omitted from the model catalogue so opt-in instructions do not become ambient context. |
149 | `aliases-for: name, other-name` | Additional lookup names for the same canonical skill. Aliases are not separate catalogue entries and do not duplicate prompt content. |
150
151 `disable-model-invocation: true` makes a skill explicit-only. `user-invocable:
152 false` hides it from user menus and refuses explicit activation while preserving
153 model selection. Setting both disables both paths. Boolean spellings `true/false`,
154 `yes/no`, `on/off`, and `1/0` are accepted; invalid policy booleans fail closed.
155 The model's catalog, list/query, and `load_skill` enforce model eligibility; the
156 user's slash and command palettes enforce user eligibility. `argument-hint` is
157 shown beside user-facing descriptions. `when_to_use` joins the routing description
158 as `Use when:`.
159
160 The runtime and installer share one frontmatter validator. Runtime accepts missing
161 descriptions and heading-only Markdown with warnings; installation requires a
162 frontmatter block, a nonempty description, and a path-safe name. A name/directory
163 mismatch warns without renaming the file. Nested `metadata` stays nested; flow
164 and block lists share the same interpretation. `license`, `compatibility`,
165 `metadata`, localized descriptions, and `x-*` extension keys are accepted silently.
166 Unknown keys warn once. `allowed-tools` / `disallowed-tools`, `model`, `context`,
167 and `agent` warn because they grant no tool, approval, provider, or fork authority.
168 The existing workspace-trust and reviewed-plugin byte/hash gates still apply.
169
170 Missing or unknown invocation values retain the historical `model+user`
171 behavior. Canonical names win over aliases when a collision exists. Loading a
172 skill reports its canonical invocation and aliases so receipts remain
173 inspectable.
174
175 ### Non-ASCII names and saved activation
176
177 ASCII names keep their existing command spelling. A name containing non-ASCII
178 characters gets a stable ASCII ID: a shortened old slug plus 32 hexadecimal
179 SHA-256 digits, at most 64 characters per skill-name segment. The hash uses
180 trimmed UTF-8 with ASCII case folding; it does not transliterate or merge Unicode
181 normalization forms. Unqualified raw names and those IDs select the same body.
182 Package directories stay in place. Qualified lookup requires the declared canonical
183 namespace, with ASCII case folding and no punctuation folding: `Team.Plugin:技能`
184 cannot select a skill in `team-plugin`.
185
186 Previously disabled lossy names such as `skill` or `pdf` continue to suppress
187 every corresponding renamed skill. Enabling one exact catalog ID enables only
188 that identity, including a literal ASCII skill named `skill`; it does not enable
189 its formerly colliding siblings. Toggle requests use the exact ID returned by
190 `GET /v1/skills`. Plugin bundle trust remains a separate gate.
191
192 Activation still uses one `skills_state.toml` file and its `disabled` array.
193 Reserved `!codewhale-skill-state:1:*` entries preserve legacy veto history and
194 exact enable choices through older writers, using the same lock and atomic
195 write. Listing/discovery do not rewrite the file. Unknown versions or malformed
196 reserved entries are errors and are left untouched; existing recovery behavior
197 keeps native skills available but hides reviewed plugin skills when policy
198 cannot be read.
199
200 This is **not simultaneous-version activation compatibility**. v0.10.0 readers
201 cannot enforce new per-identity disables, and their lossy or no-op toggles cannot
202 express every new choice. Upgrade every runtime sharing the state directory
203 before relying on consistent controls. Retaining marker strings through an old
204 write does not give that old binary the new identity semantics.
205
206 ### Starter-pack parity decisions
207
208 The v0.9.2 parity audit in [#4698](https://github.com/codewhale-hq/CodeWhale/issues/4698)
209 compared the five `xai-grok-memory` / `xai-grok-shell` reference skills with
210 the actual Codewhale bundle. This is a decision matrix, not a request to copy
211 reference text or advertise unsupported tools:
212
213 | Reference skill | Codewhale decision | Runtime grounding |
214 | --- | --- | --- |
215 | `check-work` | Canonical alias/compatibility mapping to `verify` | `verify` is the shipped evidence-collection workflow. |
216 | `code-review` | Canonical alias/compatibility mapping to `review` | `review` is the shipped read-only correctness workflow. |
217 | `create-skill` | Canonical alias/compatibility mapping to `skill-creator` | `skill-creator` is the shipped authoring workflow. |
218 | `help` | Bounded `invocation: explicit-only` router, not an ambient manual | Routes to `/help`, `/skills`, `/config`, `doctor`, and the installed `docs/` tree; it embeds no manual text. |
219 | `imagine` | Intentionally out of scope | Codewhale has no image-generation/edit tool, so the starter pack must not advertise one. |
220
221 Notes on the two non-alias decisions:
222
223 - **`help`** ships as a bundled skill (generation 7) but is `explicit-only`, so
224 it never appears in the model catalogue and costs zero ambient prompt budget.
225 Its body is a routing card — which surface owns which fact — and explicitly
226 forbids pasting a command list or settings table into context. A checked
227 invariant keeps it under 80 lines and requires it to name the `/help`,
228 `/skills`, `/config`, and `doctor` surfaces.
229 - **`imagine`** stays out. The shipped runtime exposes image *understanding*,
230 not image generation or edit, so no bundled skill may advertise it. The
231 catalog matrix asserts that `imagine`, `image`, and `image-gen` are absent
232 from the bundle and resolve to nothing.
233
234 No reference skill body is copied by this compatibility slice. The explicit
235 aliases and invocation metadata are bounded routing facts; the full skill body
236 still enters context only through `load_skill`.
237
238 ### Catalog fixture matrix (provider-free)
239
240 [`crates/tui/assets/skills-catalog-matrix.json`](../crates/tui/assets/skills-catalog-matrix.json)
241 is an **authored** expectation table covering every bundled skill: canonical
242 name, tier, invocation, aliases, whether it renders as an ambient catalogue
243 entry, and which of its aliases are shadowed by another canonical name. The
244 tests in `crates/tui/src/skills/catalog_matrix.rs` assert a bijection between
245 that fixture and `BUNDLED_SKILLS`, so the shipped pack cannot change without an
246 explicit fixture update.
247
248 What those tests do and do not claim:
249
250 - They validate **deterministic registry / catalog / resolver behavior**:
251 install, parse, eligibility, explicit load, non-activation, alias resolution,
252 explicit-only exclusion, collision precedence, and prompt budget.
253 - They validate **nothing about semantic LLM routing**. Whether a model chooses
254 `debug` for a stack trace is a live-provider question; see
255 [LIVE_SMOKE.md](LIVE_SMOKE.md).
256
257 Collision and prompt-budget invariants asserted today:
258
259 | Invariant | Meaning |
260 | --- | --- |
261 | Canonical wins | A canonical bundled name always beats another skill's alias (`docx` → `docx`, never `documents`). |
262 | Single alias owner | No two bundled skills may claim the same alias. |
263 | No duplicate entries | Each canonical name renders at most one catalogue line; aliases render zero. |
264 | Budget headroom | The shipped pack alone renders under the window-scaled skills budget (25 600 chars at the default 128k window; 2 400-char floor) with **no** "additional skills omitted" line, so user skills are never silently displaced. |
265 | No context poisoning | Descriptions stay single-line and are truncated to `MAX_SKILL_DESCRIPTION_CHARS` (400) before entering the prompt. |
266
267 ### Locale-aware routing metadata
268
269 `description_<tag>` frontmatter is supported (exact tag, then primary subtag,
270 then the canonical description — with Traditional Chinese excluded from the
271 Simplified `zh` fallback). **No bundled skill ships a localized routing
272 description**, and none is fabricated. The shipped contract is therefore an
273 explicit, tested fallback:
274
275 - For every skill in the bundle × every locale in `Locale::shipped()` — all 15
276 of `en`, `ja`, `zh-Hans`, `zh-Hant`, `pt-BR`, `es-419`, `vi`, `ko`, `ca`,
277 `de`, `fr`, `id`, `hi`, `ru`, `uk` (`crates/localization/src/lib.rs:70-88`) —
278 `description_for_locale` returns the canonical English description.
279 - The rendered catalogue block is byte-identical across all shipped locales.
280 - Exact-tag match, primary-subtag fallback (`pt-BR` → `description_pt`), and
281 English fallback are covered against a synthetic authored fixture, so the
282 resolution paths stay tested even while the bundle itself is English-only.
283
284 If a bundled skill later ships localized routing metadata, the parity test
285 fails until source-backed coverage is added for it — the fallback contract
286 cannot silently absorb a translation.
287
288 ## Audit statuses
289
290 Each audited row carries precedence and relationship flags:
291
292 | Status | Meaning |
293 | --- | --- |
294 | **Active** | Highest-precedence copy for that canonical name in the scan. |
295 | **Shadowed** | Same name exists at a higher-precedence root. |
296 | **Duplicate** | Same canonical name and same package digest as another copy. |
297 | **Conflict** | Same canonical name, different package digest. |
298
299 External skills with no owned peer (and a valid digest) are **import
300 candidates**. Externals that conflict with or exactly duplicate an owned copy
301 can still offer Import — duplicate → already present; conflict → confirm replace
302 in the selected import scope.
303
304 ## Provenance and markers
305
306 Managed installs write schema **v2** metadata under the skill directory:
307
308 **`.installed-from` (v2)** — written last on successful install/import:
309
310 ```json
311 {
312 "schema_version": 2,
313 "spec": "github:owner/repo",
314 "url": "https://…",
315 "source_checksum": "…",
316 "content_digest": "…",
317 "installed_name": "my-skill",
318 "registry_version": null
319 }
320 ```
321
322 - `content_digest` is a bounded package tree hash (not SKILL.md alone).
323 - Display of URLs strips userinfo, query, and fragment.
324 - Imports use a local `import:…` provenance and **cannot** be updated from a
325 registry; re-import or remove them instead.
326 - Legacy v1 markers are recognized as managed with
327 `LegacyMetadataUnknown` integrity until refreshed.
328
329 **`.trusted` (v2)** — advisory, digest-bound:
330
331 ```json
332 {
333 "schema_version": 2,
334 "content_digest": "…"
335 }
336 ```
337
338 Trust records review intent. It does **not** sandbox the skill or auto-approve
339 tools. Content updates clear trust so a stale marker cannot outlive the bytes.
340
341 Manual skills (owned root, no managed marker) are visible but not
342 update/remove/trust through the managed actions.
343
344 ## Package digest and safety
345
346 Audit and mutation share a bounded package digest:
347
348 - Regular files only; symlinks that escape the skill root or cycle → fail closed.
349 - Caps on total size, file count, and depth.
350 - Mutations re-check an expected digest before write (TOCTOU).
351 - Import/replace keeps a `.bak` until digest + marker finalize succeed; failure
352 restores the previous owned package.
353
354 ## Readiness
355
356 The audit model has a readiness field and optional provider hook for a future
357 readiness cache ([#4407](https://github.com/codewhale-hq/CodeWhale/issues/4407)).
358 Today, when no cache is wired, readiness is always **`Unknown`**. The manager
359 does not run readiness probes and does not block mutations on readiness.
360
361 ## Config knobs
362
363 ```toml
364 # Optional override for discovery preference (not automatically a write target
365 # unless it is the Codewhale project/global owned path).
366 skills_dir = "/path/to/skills"
367
368 [skills]
369 # When true, runtime discovery skips cross-tool roots (.claude, .agents, …).
370 # Owned Codewhale roots and an explicit skills_dir override still apply.
371 scan_codewhale_only = false
372
373 # Optional registry / install size overrides used by --remote, sync, and install.
374 # registry_url = "https://…"
375 # max_install_size_bytes = 5242880
376 ```
377
378 See [CONFIGURATION.md](CONFIGURATION.md) for the full config surface.
379
380 ## Operator checklist
381
382 1. Prefer `/skills manage` for day-to-day management; keep `--remote` / `sync` explicit.
383 2. Never hand-edit `.claude` / `.agents` / `.cursor` trees to “install” for
384 Codewhale — import into `.codewhale/skills` instead.
385 3. Treat `.trusted` as advisory documentation of review, not a security boundary.
386 4. After registry updates that change content, re-trust if you still want the
387 advisory marker.
388 5. Dual project+global copies of the same name need an explicit scope flag on
389 CLI mutations.
390
390 lines MARKDOWN