返回 CodeWhale
SKILLS.md
根目录 / docs / SKILLS.md
1 # Skills Manager
2
3 Skills are reusable `SKILL.md` instruction packs. Codewhale discovers them from
4 several roots, but **only CodeWhale-owned directories are writable**. The unified
5 `/skills` manager is the interactive surface for audit and mutation; slash
6 aliases share the same write path.
7
8 For Claude Code plugin boundaries, see [CLAUDE_PLUGIN_COMPAT.md](CLAUDE_PLUGIN_COMPAT.md).
9 For `skills_dir` and `[skills]` config keys, see [CONFIGURATION.md](CONFIGURATION.md).
10
11 ## Architecture (four layers)
12
13 | Layer | Role |
14 | --- | --- |
15 | **Root catalog** | Single source of precedence and ownership (`SkillRootCatalog`). |
16 | **Audit** | Read-only, unmerged on-disk inventory (status, digest, actions). |
17 | **Mutation controller** | Only writer for install / import / update / remove / trust. |
18 | **Skills manager view** | TUI: emits events only; never writes files itself. |
19
20 Runtime discovery (`SkillRegistry`) still merges skills for the model. Audit
21 intentionally does **not** merge — it shows every on-disk copy so conflicts and
22 shadowing stay visible.
23
24 ## Ownership and roots
25
26 **Writable (CodeWhale-owned)**
27
28 | Scope | Path |
29 | --- | --- |
30 | Project | `<workspace>/.codewhale/skills/` |
31 | Global | `~/.codewhale/skills/` |
32
33 **Read-only compatible** (discover / import source only — never mutated in place)
34
35 Examples: `<workspace>/.agents/skills`, `./skills`, `.claude/skills`,
36 `.cursor/skills`, `.opencode/skills`, `~/.agents/skills`, `~/.claude/skills`,
37 and similar harness layouts.
38
39 **Audit-only (not runtime-active)**
40
41 - `.codex/skills` appears in **compatible** audit scans so operators can see it.
42 It does **not** join the runtime discovery set.
43
44 Configured `skills_dir` that is not one of the owned CodeWhale roots stays
45 read-only. Discovery and the manager can list it; mutations still target owned
46 project/global roots only.
47
48 ## Slash commands
49
50 | Command | Behavior |
51 | --- | --- |
52 | `/skills` | Opens the Skills Manager (owned-only scan, **no network**). |
53 | `/skills <prefix>` | Text list filtered by name prefix. |
54 | `/skills inspect` | Text discovery mode, searched directories, and source paths. |
55 | `/skills --remote` | Explicit registry listing (network). |
56 | `/skills suggest <task>` | Rank up to three remote skills for a task, with matching evidence and an explicit install command (network; no install). |
57 | `/skills sync` | Explicit registry → local cache sync (network). |
58 | `/skill <name>` | Activate a skill for the next turn. |
59 | `/skill install [--project\|--global] <spec>` | Install via mutation controller. |
60 | `/skill update [--project\|--global] <name>` | Update a managed skill from its registry provenance. |
61 | `/skill uninstall [--project\|--global] <name>` | Remove a managed skill. |
62 | `/skill trust [--project\|--global] <name>` | Write digest-bound advisory trust. |
63
64 Notes:
65
66 - There is **no** `/skills audit` subcommand. Use the manager (and `c` to toggle
67 compatible roots) or `/skills inspect` for discovery details.
68 - Bare `/skill install <spec>` (no scope flag) installs into the CodeWhale
69 **global** owned root.
70 - `/skills suggest` only reads the curated registry through the existing
71 network policy. It never downloads, trusts, enables, or activates a skill;
72 each result gives a separate `/skill install <name>` command for the user to
73 choose.
74 - If the same name exists in both project and global owned roots, update /
75 uninstall / trust require `--project` or `--global`.
76 - If a name exists only under a compatible external root, writes are refused;
77 import it through `/skills` instead of editing harness directories.
78
79 ## Skills Manager (TUI)
80
81 Default open path: type `/skills` and confirm. The surface is zero-network on
82 open (owned-only audit).
83
84 | Key | Action |
85 | --- | --- |
86 | `↑`/`↓` or `j`/`k` | Move selection |
87 | `Enter` | Primary available action / confirm pending prompt |
88 | `i` | Import (external → owned) |
89 | `u` | Update (managed + registry provenance) |
90 | `r` | Remove (managed; confirms first) |
91 | `t` | Trust (managed; digest-bound) |
92 | `s` | Toggle import target: project ↔ global |
93 | `c` | Toggle scan: owned-only ↔ compatible (still local disk only) |
94 | `Esc` | Cancel confirm, or close the manager |
95
96 The view never calls install helpers or touches the filesystem. It emits a
97 mutation request; the host runs the controller, shows a receipt, and rebuilds
98 the inventory.
99
100 ## Bundled catalog tiers
101
102 Codewhale presents its shipped skills in two compact tiers so agentic workflows
103 are not buried under document and integration helpers:
104
105 - **Core agentic** — planning, implementation, debugging, review, verification,
106 delegation, Fleet, release, and `best-of-n` comparison workflows.
107 - **Format & tooling** — document formats, data visualization, frontend and web
108 testing, and skill/plugin/MCP authoring helpers.
109
110 Workspace, user, and compatible-harness skills stay labeled **custom**; Codewhale
111 does not guess their intent from their name. The shipped pack also does not
112 advertise capabilities the runtime lacks. In particular, image understanding
113 is available, but an image-generation skill is not bundled until a real
114 image-generation tool exists.
115
116 Repository-maintenance and release-operator helpers (the `gh-*` skills and
117 `codew-release-qa-sweep` under [`skills/`](skills/README.md)) are **not** part
118 of the end-user starter pack and are never auto-installed; a catalog-matrix
119 test pins that boundary. Shipping them as an optional bundle is plugin-delivery
120 work tracked separately in
121 [#4836](https://github.com/Hmbown/CodeWhale/issues/4836).
122
123 ### Invocation and alias metadata
124
125 Bundled and user skills may declare two runtime-routing fields in frontmatter:
126
127 | Field | Meaning |
128 | --- | --- |
129 | `invocation: model+user` | The default; the skill appears in the model's compact catalogue and can be loaded by the model or user. |
130 | `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. |
131 | `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. |
132
133 Missing or unknown invocation values retain the historical `model+user`
134 behavior. Canonical names win over aliases when a collision exists. Loading a
135 skill reports its canonical invocation and aliases so receipts remain
136 inspectable.
137
138 ### Starter-pack parity decisions
139
140 The v0.9.2 parity audit in [#4698](https://github.com/Hmbown/CodeWhale/issues/4698)
141 compared the five `xai-grok-memory` / `xai-grok-shell` reference skills with
142 the actual Codewhale bundle. This is a decision matrix, not a request to copy
143 reference text or advertise unsupported tools:
144
145 | Reference skill | Codewhale decision | Runtime grounding |
146 | --- | --- | --- |
147 | `check-work` | Canonical alias/compatibility mapping to `verify` | `verify` is the shipped evidence-collection workflow. |
148 | `code-review` | Canonical alias/compatibility mapping to `review` | `review` is the shipped read-only correctness workflow. |
149 | `create-skill` | Canonical alias/compatibility mapping to `skill-creator` | `skill-creator` is the shipped authoring workflow. |
150 | `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. |
151 | `imagine` | Intentionally out of scope | Codewhale has no image-generation/edit tool, so the starter pack must not advertise one. |
152
153 Notes on the two non-alias decisions:
154
155 - **`help`** ships as a bundled skill (generation 7) but is `explicit-only`, so
156 it never appears in the model catalogue and costs zero ambient prompt budget.
157 Its body is a routing card — which surface owns which fact — and explicitly
158 forbids pasting a command list or settings table into context. A checked
159 invariant keeps it under 80 lines and requires it to name the `/help`,
160 `/skills`, `/config`, and `doctor` surfaces.
161 - **`imagine`** stays out. The shipped runtime exposes image *understanding*,
162 not image generation or edit, so no bundled skill may advertise it. The
163 catalog matrix asserts that `imagine`, `image`, and `image-gen` are absent
164 from the bundle and resolve to nothing.
165
166 No reference skill body is copied by this compatibility slice. The explicit
167 aliases and invocation metadata are bounded routing facts; the full skill body
168 still enters context only through `load_skill`.
169
170 ### Catalog fixture matrix (provider-free)
171
172 [`crates/tui/assets/skills-catalog-matrix.json`](../crates/tui/assets/skills-catalog-matrix.json)
173 is an **authored** expectation table covering every bundled skill: canonical
174 name, tier, invocation, aliases, whether it renders as an ambient catalogue
175 entry, and which of its aliases are shadowed by another canonical name. The
176 tests in `crates/tui/src/skills/catalog_matrix.rs` assert a bijection between
177 that fixture and `BUNDLED_SKILLS`, so the shipped pack cannot change without an
178 explicit fixture update.
179
180 What those tests do and do not claim:
181
182 - They validate **deterministic registry / catalog / resolver behavior**:
183 install, parse, eligibility, explicit load, non-activation, alias resolution,
184 explicit-only exclusion, collision precedence, and prompt budget.
185 - They validate **nothing about semantic LLM routing**. Whether a model chooses
186 `debug` for a stack trace is a live-provider question; see
187 [LIVE_SMOKE.md](LIVE_SMOKE.md).
188
189 Collision and prompt-budget invariants asserted today:
190
191 | Invariant | Meaning |
192 | --- | --- |
193 | Canonical wins | A canonical bundled name always beats another skill's alias (`docx` → `docx`, never `documents`). |
194 | Single alias owner | No two bundled skills may claim the same alias. |
195 | No duplicate entries | Each canonical name renders at most one catalogue line; aliases render zero. |
196 | Budget headroom | The shipped pack alone renders under `MAX_AVAILABLE_SKILLS_CHARS` (12 000 chars) with **no** "additional skills omitted" line, so user skills are never silently displaced. |
197 | No context poisoning | Descriptions stay single-line and are truncated to `MAX_SKILL_DESCRIPTION_CHARS` (280) before entering the prompt. |
198
199 ### Locale-aware routing metadata
200
201 `description_<tag>` frontmatter is supported (exact tag, then primary subtag,
202 then the canonical description — with Traditional Chinese excluded from the
203 Simplified `zh` fallback). **No bundled skill ships a localized routing
204 description**, and none is fabricated. The shipped contract is therefore an
205 explicit, tested fallback:
206
207 - For every skill in the bundle × every locale in `Locale::shipped()` — all 15
208 of `en`, `ja`, `zh-Hans`, `zh-Hant`, `pt-BR`, `es-419`, `vi`, `ko`, `ca`,
209 `de`, `fr`, `id`, `hi`, `ru`, `uk` (`crates/tui/src/localization.rs:70-88`) —
210 `description_for_locale` returns the canonical English description.
211 - The rendered catalogue block is byte-identical across all shipped locales.
212 - Exact-tag match, primary-subtag fallback (`pt-BR` → `description_pt`), and
213 English fallback are covered against a synthetic authored fixture, so the
214 resolution paths stay tested even while the bundle itself is English-only.
215
216 If a bundled skill later ships localized routing metadata, the parity test
217 fails until source-backed coverage is added for it — the fallback contract
218 cannot silently absorb a translation.
219
220 ## Audit statuses
221
222 Each audited row carries precedence and relationship flags:
223
224 | Status | Meaning |
225 | --- | --- |
226 | **Active** | Highest-precedence copy for that canonical name in the scan. |
227 | **Shadowed** | Same name exists at a higher-precedence root. |
228 | **Duplicate** | Same canonical name and same package digest as another copy. |
229 | **Conflict** | Same canonical name, different package digest. |
230
231 External skills with no owned peer (and a valid digest) are **import
232 candidates**. Externals that conflict with or exactly duplicate an owned copy
233 can still offer Import — duplicate → already present; conflict → confirm replace
234 in the selected import scope.
235
236 ## Provenance and markers
237
238 Managed installs write schema **v2** metadata under the skill directory:
239
240 **`.installed-from` (v2)** — written last on successful install/import:
241
242 ```json
243 {
244 "schema_version": 2,
245 "spec": "github:owner/repo",
246 "url": "https://…",
247 "source_checksum": "…",
248 "content_digest": "…",
249 "installed_name": "my-skill",
250 "registry_version": null
251 }
252 ```
253
254 - `content_digest` is a bounded package tree hash (not SKILL.md alone).
255 - Display of URLs strips userinfo, query, and fragment.
256 - Imports use a local `import:…` provenance and **cannot** be updated from a
257 registry; re-import or remove them instead.
258 - Legacy v1 markers are recognized as managed with
259 `LegacyMetadataUnknown` integrity until refreshed.
260
261 **`.trusted` (v2)** — advisory, digest-bound:
262
263 ```json
264 {
265 "schema_version": 2,
266 "content_digest": "…"
267 }
268 ```
269
270 Trust records review intent. It does **not** sandbox the skill or auto-approve
271 tools. Content updates clear trust so a stale marker cannot outlive the bytes.
272
273 Manual skills (owned root, no managed marker) are visible but not
274 update/remove/trust through the managed actions.
275
276 ## Package digest and safety
277
278 Audit and mutation share a bounded package digest:
279
280 - Regular files only; symlinks that escape the skill root or cycle → fail closed.
281 - Caps on total size, file count, and depth.
282 - Mutations re-check an expected digest before write (TOCTOU).
283 - Import/replace keeps a `.bak` until digest + marker finalize succeed; failure
284 restores the previous owned package.
285
286 ## Readiness
287
288 The audit model has a readiness field and optional provider hook for a future
289 readiness cache ([#4407](https://github.com/Hmbown/CodeWhale/issues/4407)).
290 Today, when no cache is wired, readiness is always **`Unknown`**. The manager
291 does not run readiness probes and does not block mutations on readiness.
292
293 ## Config knobs
294
295 ```toml
296 # Optional override for discovery preference (not automatically a write target
297 # unless it is the CodeWhale project/global owned path).
298 skills_dir = "/path/to/skills"
299
300 [skills]
301 # When true, runtime discovery skips cross-tool roots (.claude, .agents, …).
302 # Owned CodeWhale roots and an explicit skills_dir override still apply.
303 scan_codewhale_only = false
304
305 # Optional registry / install size overrides used by --remote, sync, and install.
306 # registry_url = "https://…"
307 # max_install_size_bytes = 5242880
308 ```
309
310 See [CONFIGURATION.md](CONFIGURATION.md) for the full config surface.
311
312 ## Operator checklist
313
314 1. Prefer `/skills` for day-to-day management; keep `--remote` / `sync` explicit.
315 2. Never hand-edit `.claude` / `.agents` / `.cursor` trees to “install” for
316 Codewhale — import into `.codewhale/skills` instead.
317 3. Treat `.trusted` as advisory documentation of review, not a security boundary.
318 4. After registry updates that change content, re-trust if you still want the
319 advisory marker.
320 5. Dual project+global copies of the same name need an explicit scope flag on
321 CLI mutations.
322
322 lines MARKDOWN