@mrciphersmith/keryx 0.3.44 → 0.3.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -8
- package/dist/cli.js +132183 -128470
- package/dist/core.js +919 -516
- package/package.json +1 -1
- package/src/gdskills/bundled/rules/core/mobx-store-template.mdc +12 -2
- package/src/gdskills/bundled/rules/core/rule-management-workflow.mdc +5 -2
- package/src/gdskills/bundled/skills/core/reviewer-skill-creator/SKILL.detail.md +669 -0
- package/src/gdskills/bundled/skills/core/reviewer-skill-creator/SKILL.md +20 -20
- package/src/gdskills/bundled/skills/platform/agent-entrypoint-distiller/SKILL.md +3 -3
- package/src/gdskills/bundled/skills/platform/claude-md-management/SKILL.md +1 -1
- package/src/gdskills/bundled/skills/review/review-frontend/SKILL.md +7 -7
- package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.detail.md +208 -4
- package/src/gdskills/bundled/skills/review/review-orchestrator/SKILL.md +10 -10
- package/src/gdskills/bundled/skills/review/review-orchestrator/reviewer-input.schema.json +7 -0
|
@@ -0,0 +1,669 @@
|
|
|
1
|
+
# Reviewer Skill Creator — detail
|
|
2
|
+
|
|
3
|
+
Overflow reference for `core/reviewer-skill-creator`, linked from its SKILL.md
|
|
4
|
+
section "Bulk import of overlay reviewers". Nothing here overrides SKILL.md.
|
|
5
|
+
|
|
6
|
+
## Importing reviewers from an overlay — a worked example
|
|
7
|
+
|
|
8
|
+
The output below was produced by running the commands against this tree, kept
|
|
9
|
+
inside the project at `vendor/acme-overlay`. Lines cut for length are marked `…`.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
vendor/acme-overlay/
|
|
13
|
+
skills/
|
|
14
|
+
review-acme-api/SKILL.md reviewer; triggers and flags only in its description
|
|
15
|
+
review-acme-styling/SKILL.md reviewer; declares metadata.paths and metadata.flags
|
|
16
|
+
review-acme-naming/SKILL.md reviewer; its description names one file and no glob
|
|
17
|
+
review-acme-legacy/SKILL.md `deprecated: true` alias of review-acme-api
|
|
18
|
+
acme-review/SKILL.md the overlay's own review entry point (an orchestrator)
|
|
19
|
+
review-logic/SKILL.md the overlay's copy of a reviewer keryx ships
|
|
20
|
+
rules/core/
|
|
21
|
+
error-handling.mdc same filename as a rule keryx ships
|
|
22
|
+
acme-api.mdc a name only the overlay has
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The project already has one reviewer of its own, `review-house-api`, selected
|
|
26
|
+
by `--api` and gated on `src/api/**`. It matters in section 2.
|
|
27
|
+
|
|
28
|
+
`--from` takes that tree (a directory of packages, or a parent that contains
|
|
29
|
+
`skills/`), or one package directory. `keryx review import` is the review-shaped
|
|
30
|
+
spelling of `keryx skills import --module review`: one importer, the module
|
|
31
|
+
implied. For a non-review skill, or a GitHub `SKILL.md` URL, use
|
|
32
|
+
`keryx skills import` directly.
|
|
33
|
+
|
|
34
|
+
### 1. A tree without `--only` is refused
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
$ keryx review import --from ./vendor/acme-overlay
|
|
38
|
+
keryx review import: ./vendor/acme-overlay holds 6 packages and the import targets module review, where review-orchestrator dispatches every package it finds. Say which ones with --only <glob> (repeatable; matched against the package directory name).
|
|
39
|
+
|
|
40
|
+
Candidates:
|
|
41
|
+
- acme-review
|
|
42
|
+
- review-acme-api
|
|
43
|
+
- review-acme-legacy (deprecated — skipped in a tree import)
|
|
44
|
+
- review-acme-naming
|
|
45
|
+
- review-acme-styling
|
|
46
|
+
- review-logic (bundled keryx skill name — skipped unless --force)
|
|
47
|
+
|
|
48
|
+
Example:
|
|
49
|
+
keryx review import --from ./vendor/acme-overlay --only 'review-acme-api'
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Exit code 1, nothing written. The reason is what module `review` means:
|
|
53
|
+
`review-orchestrator` dispatches every package registered there, and a package
|
|
54
|
+
with no path gate is dispatched on every round. A tree imported whole brings its
|
|
55
|
+
entry point, its deprecated aliases and whatever else sits beside the reviewers,
|
|
56
|
+
and each of those becomes a sub-agent that runs on every review. So the
|
|
57
|
+
selection is yours to state, not something inferred from how one overlay names
|
|
58
|
+
its packages. The candidate list is the input for that decision: read it and
|
|
59
|
+
write the glob.
|
|
60
|
+
|
|
61
|
+
`--only` is a glob over the package **directory name** as it is on disk (`*`
|
|
62
|
+
any run of characters, `?` one), and it is repeatable: `--only 'review-acme-*'
|
|
63
|
+
--only 'code-acme-*'`. A glob that matches nothing is refused with the same
|
|
64
|
+
list. A single package directory, or a `SKILL.md` file, needs no `--only`.
|
|
65
|
+
|
|
66
|
+
An `--only` with no glob in it is an error, not "no selection":
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
$ keryx review import --from ./vendor/acme-overlay --only ''
|
|
70
|
+
keryx review import: --only needs a glob; an empty value selects nothing. Pass a package directory name or a glob over them (`*`, `?`), or drop --only.
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The directory name is what you select by; the **slug** of that name is what
|
|
74
|
+
gets written. A directory `review_acme_api` is matched by `--only
|
|
75
|
+
'review_acme_*'` (and by `--name review_acme_api` in `keryx skills import`),
|
|
76
|
+
and lands as `review/review-acme-api`: the destination, the "already exists"
|
|
77
|
+
and bundled-name checks, and the row the import prints all use the slug. Two
|
|
78
|
+
selected directories that slug to one destination are refused before anything
|
|
79
|
+
is written — here a tree holding both `review-dup` and `review_dup`:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
$ keryx review import --from ./dup --only 'review*' --dry-run
|
|
83
|
+
keryx review import: review-dup and review_dup both import as review/review-dup. Narrow --only to one of them, or rename one directory.
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
A directory name with no letter or digit has no slug to be written under, and
|
|
87
|
+
is refused the same way:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
$ keryx review import --from ./vendor/odd/___ --dry-run
|
|
91
|
+
keryx review import: package directory ___ has no letter or digit to name it by. Rename the directory, or import its SKILL.md under a name you choose: keryx skills import --from ./vendor/odd/___/SKILL.md --module review --name <name>
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Before the first write, every destination the import would touch — the
|
|
95
|
+
package, the registry in `.metaproject/metaproject.json`, the catalog, each
|
|
96
|
+
rule — is checked for a symlink on the way that resolves outside the project.
|
|
97
|
+
One is refused, nothing is written, and a dry run refuses it with the same
|
|
98
|
+
message. `keryx skills update` checks the same way. Here the package directory
|
|
99
|
+
had been replaced by a link to a directory outside the project:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
$ keryx review import --from ./vendor/acme-overlay/skills/review-acme-naming --dry-run
|
|
103
|
+
keryx review import: .metaproject/project-skills/review/review-acme-naming/SKILL.md: refuses to write through a symlink at .metaproject/project-skills/review/review-acme-naming that resolves outside the project root. Nothing was written.
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 2. Dry-run first
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
$ keryx review import --from ./vendor/acme-overlay --only 'review-acme-*' --dry-run
|
|
110
|
+
# skills import
|
|
111
|
+
|
|
112
|
+
from: ./vendor/acme-overlay
|
|
113
|
+
dry-run: yes
|
|
114
|
+
force: no
|
|
115
|
+
imported: 0 overwritten: 0 updated: 0 skipped: 1 would-import: 3 would-overwrite: 0
|
|
116
|
+
|
|
117
|
+
## would import (3) — dry run, nothing written
|
|
118
|
+
|
|
119
|
+
- review/review-acme-api
|
|
120
|
+
- review/review-acme-naming
|
|
121
|
+
- review/review-acme-styling
|
|
122
|
+
|
|
123
|
+
## packages
|
|
124
|
+
|
|
125
|
+
- review/review-acme-api: would-import — review-orchestrator will dispatch this after `keryx review reviewers` lists it
|
|
126
|
+
- warning: flag --api is carried by one existing project reviewer, review-house-api: it becomes a family flag for both, so --api now selects review-house-api path-gated instead of dispatching it outright.
|
|
127
|
+
- review/review-acme-legacy: skipped — deprecated
|
|
128
|
+
- review/review-acme-naming: would-import — review-orchestrator will dispatch this after `keryx review reviewers` lists it
|
|
129
|
+
- warning: paths: none — dispatched on every round. Declare `metadata.paths: "<glob>, <glob>"` in its frontmatter to gate it on the diff.
|
|
130
|
+
- review/review-acme-styling: would-import — review-orchestrator will dispatch this after `keryx review reviewers` lists it
|
|
131
|
+
- warning: metadata.flags: "--acme_css" dropped — a flag is `--` and a name of lower-case letters, digits and dashes that starts with a letter
|
|
132
|
+
|
|
133
|
+
A package whose frontmatter says `deprecated: true` is skipped in a tree import. To import one anyway, pass its own directory as --from.
|
|
134
|
+
|
|
135
|
+
## rules the skills cite
|
|
136
|
+
|
|
137
|
+
- core/acme-api.mdc: would-import — from vendor/acme-overlay/rules/core/acme-api.mdc (cited by review-acme-api)
|
|
138
|
+
- core/acme-styling.mdc: unresolved — no rules/ directory beside the source has it (cited by review-acme-styling)
|
|
139
|
+
- core/error-handling.mdc: differs — .metaproject/rules/core/error-handling.mdc is not the overlay's version; the overlay's would be written to .metaproject/rules/project/core/error-handling.mdc, which is the file the reviewer would read — from vendor/acme-overlay/rules/core/error-handling.mdc (cited by review-acme-api)
|
|
140
|
+
…
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Read three things off it before running for real:
|
|
144
|
+
|
|
145
|
+
- **The `would import` list is the whole answer to "what lands".** Here the glob
|
|
146
|
+
also matched `review-acme-legacy`, and it is skipped as `deprecated` — a tree
|
|
147
|
+
import skips a deprecated package even with `--force`. `acme-review` and
|
|
148
|
+
`review-logic` did not match the glob, so they are not rows at all.
|
|
149
|
+
- **Every `warning:` row.** There are three kinds here, and each is a decision
|
|
150
|
+
to make before the real run:
|
|
151
|
+
- `paths: none` — that reviewer will run on every round whatever the diff
|
|
152
|
+
touches. The remedy is `metadata.paths` in the overlay's frontmatter
|
|
153
|
+
(section 4).
|
|
154
|
+
- `metadata.flags: … dropped` — an entry of the declared list is not a flag
|
|
155
|
+
and will not select the reviewer. Fix the spelling in the overlay. When no
|
|
156
|
+
entry survives, a second line, `metadata.flags: no entry is a flag`, says
|
|
157
|
+
the reviewer now has no selection flags at all (section 4, `flags`).
|
|
158
|
+
- `flag … is carried by one existing project reviewer` — the import changes
|
|
159
|
+
how a reviewer the project **already has** is dispatched. Until now `--api`
|
|
160
|
+
dispatched `review-house-api` outright; once a second reviewer carries it,
|
|
161
|
+
`--api` is a family flag for both and each stays path-gated. If the
|
|
162
|
+
existing reviewer must keep its own flag, rename the flag in the overlay.
|
|
163
|
+
The warning is about reviewers that were on disk before the import and are
|
|
164
|
+
not replaced by it; packages arriving together that share a flag (`--acme`)
|
|
165
|
+
are the overlay's own family and get no warning.
|
|
166
|
+
|
|
167
|
+
A fourth kind appears only on a `--force` overwrite: `flag … is dropped by
|
|
168
|
+
this version of …, which leaves … its only carrier` — the reverse change,
|
|
169
|
+
shown under "Refresh when the origin moves".
|
|
170
|
+
- **Every rule row that is not `would-import` or `present`.** `unresolved` means
|
|
171
|
+
the reviewer will cite a rule the project will not have. `differs` means a
|
|
172
|
+
file already answers that reference with other content.
|
|
173
|
+
|
|
174
|
+
A dry-run does not run the security gate that a real run applies to every file
|
|
175
|
+
it writes, so a `would-…` status can be optimistic: the real run may still block
|
|
176
|
+
a package, or report a rule as `unresolved` with `blocked by the security gate`.
|
|
177
|
+
|
|
178
|
+
### 3. The real run, and what it writes
|
|
179
|
+
|
|
180
|
+
```
|
|
181
|
+
$ keryx review import --from ./vendor/acme-overlay --only 'review-acme-*'
|
|
182
|
+
# skills import
|
|
183
|
+
|
|
184
|
+
from: ./vendor/acme-overlay
|
|
185
|
+
dry-run: no
|
|
186
|
+
force: no
|
|
187
|
+
imported: 3 overwritten: 0 updated: 0 skipped: 1 would-import: 0 would-overwrite: 0
|
|
188
|
+
|
|
189
|
+
- review/review-acme-api: imported — review-orchestrator will dispatch this after `keryx review reviewers` lists it
|
|
190
|
+
- warning: flag --api is carried by one existing project reviewer, review-house-api: it becomes a family flag for both, so --api now selects review-house-api path-gated instead of dispatching it outright.
|
|
191
|
+
- review/review-acme-legacy: skipped — deprecated
|
|
192
|
+
- review/review-acme-naming: imported — review-orchestrator will dispatch this after `keryx review reviewers` lists it
|
|
193
|
+
- warning: paths: none — dispatched on every round. Declare `metadata.paths: "<glob>, <glob>"` in its frontmatter to gate it on the diff.
|
|
194
|
+
- review/review-acme-styling: imported — review-orchestrator will dispatch this after `keryx review reviewers` lists it
|
|
195
|
+
- warning: metadata.flags: "--acme_css" dropped — a flag is `--` and a name of lower-case letters, digits and dashes that starts with a letter
|
|
196
|
+
…
|
|
197
|
+
## rules the skills cite
|
|
198
|
+
|
|
199
|
+
- core/acme-api.mdc: imported — from vendor/acme-overlay/rules/core/acme-api.mdc (cited by review-acme-api)
|
|
200
|
+
- core/acme-styling.mdc: unresolved — no rules/ directory beside the source has it (cited by review-acme-styling)
|
|
201
|
+
- core/error-handling.mdc: differs — .metaproject/rules/core/error-handling.mdc is not the overlay's version; the overlay's was written to .metaproject/rules/project/core/error-handling.mdc, which is the file the reviewer reads — from vendor/acme-overlay/rules/core/error-handling.mdc (cited by review-acme-api)
|
|
202
|
+
|
|
203
|
+
A reviewer that cites `<dir>/<name>.mdc` reads `.metaproject/rules/project/<dir>/<name>.mdc` when that file exists,
|
|
204
|
+
and `.metaproject/rules/<dir>/<name>.mdc` otherwise. `keryx init`, `keryx update` and `keryx skills install` overwrite
|
|
205
|
+
rules/core with keryx's own rules and leave rules/project alone. `keryx review reviewers` lists each such reference
|
|
206
|
+
under `shadowedRules`.
|
|
207
|
+
|
|
208
|
+
Reviewers: `keryx review reviewers` must list every imported review/* name. That is the same call review-orchestrator makes.
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
The note's "`keryx skills install` overwrite rules/core" is true of one of its
|
|
212
|
+
two forms. **`keryx init`, `keryx update` and the legacy-profile form of
|
|
213
|
+
`keryx skills install`** (`--profile minimal|recommended|full|custom` with no
|
|
214
|
+
manifest flag) copy keryx's rules over `rules/core`. The manifest form with
|
|
215
|
+
`--target keryx-shell` also writes `rules/core`, but skips an existing file its
|
|
216
|
+
install-state did not record (or that drifted from it) unless `--force`;
|
|
217
|
+
`--target claude` writes `.claude/rules/` and leaves `rules/core` alone. None
|
|
218
|
+
of them writes or cleans `rules/project`. The other mentions below mean this.
|
|
219
|
+
|
|
220
|
+
Per imported package, four things now exist:
|
|
221
|
+
|
|
222
|
+
- **The package directory** `.metaproject/project-skills/review/<name>/`, holding
|
|
223
|
+
`SKILL.md` and `skill-changelog.md`. The import copies `SKILL.md` and the rules
|
|
224
|
+
it cites, nothing else: a checklist, template or script the reviewer points at
|
|
225
|
+
is not brought along (section 4, `unresolvedReferences`).
|
|
226
|
+
- **A header stamped into `SKILL.md`**, directly after the frontmatter. The body
|
|
227
|
+
below it is the source's, unchanged:
|
|
228
|
+
|
|
229
|
+
```
|
|
230
|
+
Version: 1.2.0
|
|
231
|
+
Target: review-acme-api
|
|
232
|
+
Module: review
|
|
233
|
+
Origin: vendor/acme-overlay/skills/review-acme-api/SKILL.md
|
|
234
|
+
Origin Hash: sha256:d6cfb23a47093ac46c5b1788bd1325cbba0c08b76e749c40f371f474589eef2f
|
|
235
|
+
Imported At: 2026-09-30T15:49:48.204Z
|
|
236
|
+
Status: active
|
|
237
|
+
Last Verified: never
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
`Origin`, `Origin Hash` and `Imported At` are what drift is computed from.
|
|
241
|
+
`Origin` is recorded project-relative when the source is inside the project,
|
|
242
|
+
as `~/…` when it is under the home directory, and absolute only otherwise — an
|
|
243
|
+
absolute origin is true on one machine and reads as drift `missing` on every
|
|
244
|
+
other.
|
|
245
|
+
- **A `projectSkillRegistry` entry** in `.metaproject/metaproject.json`
|
|
246
|
+
(`modules.gdskills.projectSkillRegistry`):
|
|
247
|
+
|
|
248
|
+
```json
|
|
249
|
+
{
|
|
250
|
+
"module": "review",
|
|
251
|
+
"name": "review-acme-api",
|
|
252
|
+
"target": "review-acme-api",
|
|
253
|
+
"path": ".metaproject/project-skills/review/review-acme-api",
|
|
254
|
+
"version": "1.2.0",
|
|
255
|
+
"status": "active",
|
|
256
|
+
"updatedAt": "2026-09-30T15:49:48.246Z"
|
|
257
|
+
}
|
|
258
|
+
```
|
|
259
|
+
- **A catalog row** in the Project Skills section of `.metaproject/skills/catalog.md`:
|
|
260
|
+
|
|
261
|
+
```
|
|
262
|
+
| review | review-acme-api | `review-acme-api` | .metaproject/project-skills/review/review-acme-api/SKILL.md |
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
**Rules.** For each backticked `.mdc` rule a selected package cites, the import
|
|
266
|
+
looks for the file in a `rules/` directory beside the overlay's skills and
|
|
267
|
+
reports one status:
|
|
268
|
+
|
|
269
|
+
- `imported` — the project did not have it; copied to `.metaproject/rules/<ref>`
|
|
270
|
+
(here `acme-api.mdc`, into the project's `rules/core`).
|
|
271
|
+
- `present` — the project already has it, identical to the overlay's, or the
|
|
272
|
+
overlay has no version to compare with.
|
|
273
|
+
- `differs` — a file already answers that reference with other content. The
|
|
274
|
+
overlay's version is written to the reference's project slot,
|
|
275
|
+
`.metaproject/rules/project/<dir>/<name>.mdc`, and the existing file is left
|
|
276
|
+
untouched. This is the ordinary case for a filename keryx also ships
|
|
277
|
+
(`error-handling.mdc` above, written to `rules/project/core/`): the file in
|
|
278
|
+
`rules/core` is keryx's generic rule, not the overlay's.
|
|
279
|
+
- `imported-project` — a `core/<name>.mdc` that keryx ships under the same name
|
|
280
|
+
and the project has no file for yet; the overlay's goes to
|
|
281
|
+
`.metaproject/rules/project/core/<name>.mdc` rather than to `rules/core`,
|
|
282
|
+
because `keryx init`, `keryx update` and the legacy-profile
|
|
283
|
+
`keryx skills install` overwrite `rules/core` with keryx's own rules.
|
|
284
|
+
- `unresolved` — no `rules/` directory beside the source has it. Add the file by
|
|
285
|
+
hand, or the reviewer keeps citing a rule the project lacks.
|
|
286
|
+
|
|
287
|
+
The project slot keeps the whole reference, directory included:
|
|
288
|
+
`core/error-handling.mdc` resolves to
|
|
289
|
+
`.metaproject/rules/project/core/error-handling.mdc` first and to
|
|
290
|
+
`.metaproject/rules/core/error-handling.mdc` second, and a
|
|
291
|
+
`house/error-handling.mdc` would resolve to
|
|
292
|
+
`.metaproject/rules/project/house/error-handling.mdc` first — two rules with
|
|
293
|
+
one filename never share a slot. A file lying directly in `rules/project/` is nobody's slot:
|
|
294
|
+
it is read only by a reviewer whose text cites it literally, as
|
|
295
|
+
`project/<name>.mdc`. Nothing loads rules for a reviewer, so the order takes
|
|
296
|
+
effect in one place: `review-orchestrator` reads `shadowedRules` from the
|
|
297
|
+
inventory and tells the reviewer, in its dispatch prompt, which file to read. A
|
|
298
|
+
reviewer run outside the orchestrator reads what its text names. An existing
|
|
299
|
+
project-slot copy that differs from the overlay's is left as it is — it may be
|
|
300
|
+
a hand edit — unless `--force` is passed.
|
|
301
|
+
|
|
302
|
+
Running the same command again is safe and is how rules are fetched for an
|
|
303
|
+
import made earlier: packages come back `skipped — already exists; pass --force
|
|
304
|
+
to overwrite`, and the rule rows are re-resolved — `present` for both files
|
|
305
|
+
written above, the second with `the reviewer reads
|
|
306
|
+
.metaproject/rules/project/core/error-handling.mdc`.
|
|
307
|
+
|
|
308
|
+
### 4. Reading `keryx review reviewers`
|
|
309
|
+
|
|
310
|
+
```
|
|
311
|
+
$ keryx review reviewers
|
|
312
|
+
…
|
|
313
|
+
## project-local
|
|
314
|
+
|
|
315
|
+
- review-acme-api (vendor/acme-overlay/skills/review-acme-api/SKILL.md — clean)
|
|
316
|
+
- paths: src/api/**, src/server/routes.ts [description]
|
|
317
|
+
- flags: --acme, --acme-api, --api
|
|
318
|
+
- family flags: --acme, --api — shared with another project reviewer: selects it, stays path-gated
|
|
319
|
+
- review-acme-naming (vendor/acme-overlay/skills/review-acme-naming/SKILL.md — clean)
|
|
320
|
+
- paths: none — dispatched on every round [none]
|
|
321
|
+
- flags: --acme-naming
|
|
322
|
+
- review-acme-styling (vendor/acme-overlay/skills/review-acme-styling/SKILL.md — clean)
|
|
323
|
+
- paths: src/**/*.css, src/theme/** [metadata]
|
|
324
|
+
- flags: --acme, --acme-styling
|
|
325
|
+
- family flags: --acme — shared with another project reviewer: selects it, stays path-gated
|
|
326
|
+
- warning: metadata.flags: "--acme_css" dropped — a flag is `--` and a name of lower-case letters, digits and dashes that starts with a letter
|
|
327
|
+
- review-house-api (house/review-house-api/SKILL.md — clean)
|
|
328
|
+
- paths: src/api/** [description]
|
|
329
|
+
- flags: --api
|
|
330
|
+
- family flags: --api — shared with another project reviewer: selects it, stays path-gated
|
|
331
|
+
|
|
332
|
+
## rules cited but not in .metaproject/rules
|
|
333
|
+
|
|
334
|
+
- review-acme-styling: core/acme-styling.mdc
|
|
335
|
+
…
|
|
336
|
+
## rules read from .metaproject/rules/project
|
|
337
|
+
|
|
338
|
+
- review-acme-api: `core/error-handling.mdc` → .metaproject/rules/project/core/error-handling.mdc
|
|
339
|
+
…
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
This is the call `review-orchestrator` makes (with `--json`), so what it prints
|
|
343
|
+
is what a round will do. `review-house-api`'s last row is what the import
|
|
344
|
+
warned about: `--api` is now a family flag for it. The frontmatter the three
|
|
345
|
+
imported rows were derived from:
|
|
346
|
+
|
|
347
|
+
```yaml
|
|
348
|
+
# review-acme-api — nothing declared; everything is read out of the description
|
|
349
|
+
description: |
|
|
350
|
+
Use when reviewing Acme API handlers against the Acme error contract.
|
|
351
|
+
Dispatched for --acme, --acme-api, --api, --all, or changes under src/api/** and
|
|
352
|
+
src/server/routes.ts. NOT for styling.
|
|
353
|
+
metadata:
|
|
354
|
+
stack_requires: "http-server"
|
|
355
|
+
|
|
356
|
+
# review-acme-styling — declared; the description is not consulted for these
|
|
357
|
+
metadata:
|
|
358
|
+
paths: "src/**/*.css, src/theme/**"
|
|
359
|
+
flags:
|
|
360
|
+
- acme
|
|
361
|
+
- --Acme-Styling
|
|
362
|
+
- --acme_css
|
|
363
|
+
|
|
364
|
+
# review-acme-naming — a file path in prose, and no glob anywhere
|
|
365
|
+
description: |
|
|
366
|
+
Use when reviewing names against the Acme naming guide. Dispatched for
|
|
367
|
+
--acme-naming or --all. The pattern to follow is in src/app/names.ts.
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
The frontmatter is read by one reader, shared by the import, this inventory,
|
|
371
|
+
`keryx review jev-rules` and the stack gate. It reads a subset of YAML, and a
|
|
372
|
+
shape outside the subset reads as not declared — the same as an absent key:
|
|
373
|
+
|
|
374
|
+
- the block opens with `---` on the first line; a leading BOM is ignored and
|
|
375
|
+
CRLF line endings read as LF;
|
|
376
|
+
- a `# comment` after whitespace, outside quotes, is dropped;
|
|
377
|
+
- `metadata.paths` and `metadata.flags` may be a comma-separated string, a flow
|
|
378
|
+
list (`[a, b]`) or a block list of `- item` lines; empty items are skipped.
|
|
379
|
+
`metadata.stack_requires` is read as a string only;
|
|
380
|
+
- only keys directly under `metadata:` are its fields — a `paths:` nested a
|
|
381
|
+
level deeper is not `metadata.paths`;
|
|
382
|
+
- a flow mapping, an anchor, a nested list or a multi-line quoted scalar is
|
|
383
|
+
outside the subset;
|
|
384
|
+
- `deprecated: true` and `category` count at the top level or under
|
|
385
|
+
`metadata:`.
|
|
386
|
+
|
|
387
|
+
How each field of a `project` entry in `--json` is derived:
|
|
388
|
+
|
|
389
|
+
- **`flags`** — `metadata.flags` when it has at least one non-empty entry;
|
|
390
|
+
otherwise every `--flag` the description names. So `flags: []` and
|
|
391
|
+
`flags: ''` leave the description's flags in force — they do not switch them
|
|
392
|
+
off. A declared flag entry is normalised before anything compares it: split
|
|
393
|
+
on commas and whitespace, trimmed, lower-cased, and given `--` when it has no
|
|
394
|
+
leading dash — so `acme` and `--Acme-Styling` above became `--acme` and
|
|
395
|
+
`--acme-styling`. `--all` is excluded either way: it selects every reviewer
|
|
396
|
+
already. A list with entries replaces the description even when none of them
|
|
397
|
+
survives: a list of only non-flags (`[--acme_css]`) and a list of only
|
|
398
|
+
`--all` both leave the reviewer with no flags, selected by its paths or by
|
|
399
|
+
`--all`.
|
|
400
|
+
- **`flagWarnings`** — one line per `metadata.flags` entry that is still not
|
|
401
|
+
`--` plus a lower-case name after normalising (`--acme_css` above). The entry
|
|
402
|
+
is dropped from `flags`, and the line is printed as a `warning:` row here and
|
|
403
|
+
on the import row. When dropping left no flag, a second line says so. A list
|
|
404
|
+
of only `--all` gets no warning. Empty when there is nothing to say.
|
|
405
|
+
- **`familyFlags`** — the subset of `flags` that at least one other project
|
|
406
|
+
reviewer also carries (`--acme` and `--api` above). A passed family flag
|
|
407
|
+
selects the reviewer and leaves it path-gated; a passed flag only this
|
|
408
|
+
reviewer carries (`--acme-styling`) selects it explicitly, with no path gate.
|
|
409
|
+
- **`paths` and `pathsSource`** — `metadata.paths` when declared
|
|
410
|
+
(`pathsSource: metadata`); it wins. Otherwise the triggers found in the
|
|
411
|
+
description (`pathsSource: description`): any token with a `*` that looks like
|
|
412
|
+
a path, and — only in a description that has at least one such glob — any
|
|
413
|
+
literal repo-relative file path beside it, such as `src/server/routes.ts`;
|
|
414
|
+
`src/**/*.ts(x)` expands to both spellings. A cited document (`.md`, `.mdc`)
|
|
415
|
+
and a path under `.metaproject/` are never triggers, and neither is prose
|
|
416
|
+
without a glob or an extension (`date/temporal utils`). A description with no
|
|
417
|
+
glob yields no trigger at all, whatever file paths it names: prose is full of
|
|
418
|
+
things shaped like one (`React/Next.js`), and a trigger that matches no file
|
|
419
|
+
would gate the reviewer off every round. That is `review-acme-naming` above —
|
|
420
|
+
`src/app/names.ts` is not a trigger, the entry has `paths: []` and
|
|
421
|
+
`pathsSource: none`, and the reviewer is dispatched on every round, with the
|
|
422
|
+
import warning.
|
|
423
|
+
|
|
424
|
+
The description reader works on prose, so it can be wrong in both directions:
|
|
425
|
+
beside a glob, a file the description merely mentions ("see src/app/main.ts
|
|
426
|
+
for the pattern") becomes a trigger, and a directory named without a glob
|
|
427
|
+
yields nothing. When the printed `paths` are not what the reviewer should be
|
|
428
|
+
gated on, declare `metadata.paths` in the overlay's frontmatter and refresh
|
|
429
|
+
the import — do not reword the description until the guess comes out right.
|
|
430
|
+
- **`stackRequires`** — `metadata.stack_requires`, a comma-separated string of the
|
|
431
|
+
tags `keryx review stack` knows (`nestjs`, `react`, `mobx`, `prisma`,
|
|
432
|
+
`playwright`, `sql`, `http-server`). An unknown tag is dropped, which leaves
|
|
433
|
+
the reviewer unscoped rather than excluded.
|
|
434
|
+
- **`unresolvedRules`** — backticked `.mdc` rules the text cites that exist
|
|
435
|
+
neither at `.metaproject/rules/project/<ref>` nor at `.metaproject/rules/<ref>`.
|
|
436
|
+
Printed under "rules cited but not in .metaproject/rules". The reviewer is
|
|
437
|
+
still dispatched; add the rule, or accept that it reviews without it.
|
|
438
|
+
- **`shadowedRules`** — `[{ ref, resolved }]`: rules the text cites as
|
|
439
|
+
`<dir>/<name>.mdc` that the project-slot copy answers first — above,
|
|
440
|
+
`{ "ref": "core/error-handling.mdc", "resolved":
|
|
441
|
+
".metaproject/rules/project/core/error-handling.mdc" }`. Printed under
|
|
442
|
+
"rules read from .metaproject/rules/project". Expected after a `differs` or
|
|
443
|
+
`imported-project` row; it is a fact to check, not a defect.
|
|
444
|
+
- **`unresolvedReferences`** — `[{ ref, reason }]`, printed under "references
|
|
445
|
+
that do not resolve". `missing`: a backticked path starting `skills/` or
|
|
446
|
+
`rules/` and ending `.md` or `.json` with no file at that path under
|
|
447
|
+
`.metaproject/` — the import did not bring it; copy it there or edit the
|
|
448
|
+
reference out. `non-portable`: a rule cited by an absolute or `~` path, which
|
|
449
|
+
exists on one machine at most; cite it as `core/<name>.mdc` instead.
|
|
450
|
+
- **`drift`** — `clean`, `changed` or `missing`, from re-hashing the file
|
|
451
|
+
`Origin` names against `Origin Hash`. It is the word after the dash on the
|
|
452
|
+
reviewer's row. `none` means no origin was recorded — a reviewer made with
|
|
453
|
+
`keryx skills create` and no `--origin` — and its row reads
|
|
454
|
+
`- <name> (no recorded origin)`, with no dash. A remote (`https://`) origin
|
|
455
|
+
always lists as `clean`: listing opens no connection, and `keryx skills
|
|
456
|
+
update` is what re-reads it.
|
|
457
|
+
|
|
458
|
+
## What is not a reviewer
|
|
459
|
+
|
|
460
|
+
Module `review` is a dispatch list, not a folder for review-adjacent skills. A
|
|
461
|
+
package belongs there only if it can be handed a bounded diff and return
|
|
462
|
+
`REVIEW_RESULT` under the orchestrated review contract. Leave these out of
|
|
463
|
+
`--only`:
|
|
464
|
+
|
|
465
|
+
- **An orchestrator, facade or entry point** (`acme-review` above). Registered
|
|
466
|
+
as a reviewer it is dispatched as a sub-agent of the round it was written to
|
|
467
|
+
run.
|
|
468
|
+
- **A deprecated alias.** The tree import skips a package whose frontmatter says
|
|
469
|
+
`deprecated: true`; one whose deprecation is only stated in prose is yours to
|
|
470
|
+
exclude.
|
|
471
|
+
- **A report generator, comment interpreter or other post-processing skill.** It
|
|
472
|
+
consumes findings; it does not produce them.
|
|
473
|
+
- **Anything with no review contract** — a rule digest, a style guide, a
|
|
474
|
+
checklist with no output schema.
|
|
475
|
+
- **A copy of a reviewer keryx ships** (`review-logic` above). It is skipped
|
|
476
|
+
unless `--force`, and forcing it shadows the bundled one.
|
|
477
|
+
|
|
478
|
+
Naming a package by its own directory is the operator asking for it, so none of
|
|
479
|
+
the tree protections apply: a deprecated package is imported, with a warning.
|
|
480
|
+
If one of these is worth having in the project, import it under another module
|
|
481
|
+
(`keryx skills import --from <package-dir> --module orchestration`): it is
|
|
482
|
+
registered for `keryx skills route` and is not dispatched by review rounds.
|
|
483
|
+
|
|
484
|
+
## Undo
|
|
485
|
+
|
|
486
|
+
```
|
|
487
|
+
$ keryx skills remove review/review-acme-naming --dry-run
|
|
488
|
+
Would remove project skill: review/review-acme-naming
|
|
489
|
+
- absent: verification report — .metaproject/data/gdskills/reports/review-review-acme-naming-verification.json
|
|
490
|
+
- would remove: catalog row — .metaproject/skills/catalog.md
|
|
491
|
+
- would remove: package directory — .metaproject/project-skills/review/review-acme-naming
|
|
492
|
+
- would remove: registry entry — .metaproject/metaproject.json
|
|
493
|
+
Dry run: nothing was changed.
|
|
494
|
+
|
|
495
|
+
$ keryx skills remove review/review-acme-naming
|
|
496
|
+
Removed project skill: review/review-acme-naming
|
|
497
|
+
- absent: verification report — .metaproject/data/gdskills/reports/review-review-acme-naming-verification.json
|
|
498
|
+
- removed: catalog row — .metaproject/skills/catalog.md
|
|
499
|
+
- removed: package directory — .metaproject/project-skills/review/review-acme-naming
|
|
500
|
+
- removed: registry entry — .metaproject/metaproject.json
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
One skill per call, named exactly as registered. It removes the four things an
|
|
504
|
+
import registered, plus the `review/` directory when that was the last skill in
|
|
505
|
+
it, in the order printed: the verification report, the catalog row, the
|
|
506
|
+
package directory, the module directory, and the registry entry last. `absent`
|
|
507
|
+
means the part was already gone and is not an error.
|
|
508
|
+
|
|
509
|
+
If a step fails — a read-only directory, say — the error names the part that
|
|
510
|
+
failed, what is already gone and what is still in place; a package directory
|
|
511
|
+
whose recursive delete failed part-way is listed as `(may be partly removed)`,
|
|
512
|
+
since some of its files may already be gone. The registry entry is
|
|
513
|
+
still there, so running the same command again once the cause is fixed
|
|
514
|
+
finishes the removal. A skill whose entry and package are already gone is
|
|
515
|
+
still found by a leftover catalog row or verification report, so a removal
|
|
516
|
+
half-done by hand is finished the same way.
|
|
517
|
+
|
|
518
|
+
Names are case-sensitive, on every filesystem. A spelling that differs from the
|
|
519
|
+
registered one only in case is refused and names the registered spelling:
|
|
520
|
+
|
|
521
|
+
```
|
|
522
|
+
$ keryx skills remove Review/review-acme-naming --dry-run
|
|
523
|
+
keryx skills remove: Review/review-acme-naming is not registered under that spelling; the registered spelling is review/review-acme-naming. Skill names are case-sensitive: run `keryx skills remove review/review-acme-naming`. Nothing was changed.
|
|
524
|
+
```
|
|
525
|
+
|
|
526
|
+
The command deletes a directory recursively and takes its target from a
|
|
527
|
+
registry anyone can edit, so it checks where it is about to reach and refuses
|
|
528
|
+
(exit 1) before changing anything — a refused run leaves the registry, the
|
|
529
|
+
catalog and the disk as they were:
|
|
530
|
+
|
|
531
|
+
- a bundled skill, or a name that is not a project skill;
|
|
532
|
+
- a skill whose package directory is on disk only under another spelling
|
|
533
|
+
(`review/Alpha/` for `review/alpha`). On a filesystem that ignores case the
|
|
534
|
+
two are one directory, so removing the entry and row would leave that package
|
|
535
|
+
in place and still found as a skill. The refusal names the on-disk spelling;
|
|
536
|
+
rename the directory to `.metaproject/project-skills/<module>/<name>` and
|
|
537
|
+
retry;
|
|
538
|
+
- a symlink where something would be deleted: `.metaproject/project-skills`
|
|
539
|
+
itself, the module directory, the package, or the reports directory
|
|
540
|
+
`.metaproject/data/gdskills/reports`. It does not delete through the link and
|
|
541
|
+
does not unlink it; remove the link by hand if that is the intent;
|
|
542
|
+
- a `.metaproject/metaproject.json` or `.metaproject/skills/catalog.md` that
|
|
543
|
+
resolves outside the project. One reached through a symlink to a file inside
|
|
544
|
+
the project is rewritten in place, and the row names where the write lands;
|
|
545
|
+
- a registry entry whose `path` is not its own
|
|
546
|
+
`.metaproject/project-skills/<module>/<name>` — an entry pointing at the
|
|
547
|
+
module directory or at another skill's package would otherwise delete that;
|
|
548
|
+
- a registry entry whose key is not two plain path segments.
|
|
549
|
+
|
|
550
|
+
A verification report is removed only when it is this skill's: a report whose
|
|
551
|
+
body names another package (`skillPath`) is left alone even if its file name
|
|
552
|
+
matches.
|
|
553
|
+
|
|
554
|
+
It leaves in place, deliberately: the rules the import copied into
|
|
555
|
+
`.metaproject/rules/` — `rules/project` included — because other skills may
|
|
556
|
+
cite them; runtime exports under `.metaproject/runtime/skills/`; and learning
|
|
557
|
+
proposals under `.metaproject/data/gdskills/proposals/`. Delete a rule by hand
|
|
558
|
+
once nothing cites it, and check with `keryx review reviewers` that no reviewer
|
|
559
|
+
lists it as unresolved afterwards.
|
|
560
|
+
|
|
561
|
+
## Refresh when the origin moves
|
|
562
|
+
|
|
563
|
+
After the overlay's `review-acme-api/SKILL.md` was edited:
|
|
564
|
+
|
|
565
|
+
```
|
|
566
|
+
$ keryx review reviewers
|
|
567
|
+
…
|
|
568
|
+
- review-acme-api (vendor/acme-overlay/skills/review-acme-api/SKILL.md — changed)
|
|
569
|
+
…
|
|
570
|
+
## origins that moved on
|
|
571
|
+
|
|
572
|
+
- review-acme-api: `vendor/acme-overlay/skills/review-acme-api/SKILL.md` changed since 2026-09-30T15:49:48.204Z
|
|
573
|
+
…
|
|
574
|
+
$ keryx skills update review/review-acme-api --dry-run
|
|
575
|
+
…
|
|
576
|
+
## would import (1) — dry run, nothing written
|
|
577
|
+
|
|
578
|
+
- review/review-acme-api (overwrites the existing one)
|
|
579
|
+
…
|
|
580
|
+
$ keryx skills update review/review-acme-api
|
|
581
|
+
…
|
|
582
|
+
- review/review-acme-api: updated — review-orchestrator will dispatch this after `keryx review reviewers` lists it
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
`changed` does not mean the reviewer is wrong; it still runs, from the older
|
|
586
|
+
text. `keryx skills update <module>/<name>` (or `--all`) re-reads each `Origin`
|
|
587
|
+
and overwrites the project's `SKILL.md`, re-stamping the hash — so an edit made
|
|
588
|
+
to the imported copy is lost. If the project deliberately differs from the
|
|
589
|
+
overlay, make the change in the overlay, or record the divergence and leave the
|
|
590
|
+
row `changed`.
|
|
591
|
+
|
|
592
|
+
`keryx skills update` refreshes `SKILL.md` only; it reports no rule rows. When
|
|
593
|
+
the overlay's rules moved too, re-run the import. `--force` on the import
|
|
594
|
+
overwrites packages that already exist and replaces a project-slot copy
|
|
595
|
+
(`rules/project/<dir>/<name>.mdc`) that differs from the overlay's:
|
|
596
|
+
|
|
597
|
+
```
|
|
598
|
+
$ keryx review import --from ./vendor/acme-overlay/skills/review-acme-styling --force
|
|
599
|
+
…
|
|
600
|
+
- review/review-acme-styling: overwritten — review-orchestrator will dispatch this after `keryx review reviewers` lists it
|
|
601
|
+
- warning: metadata.flags: "--acme_css" dropped — a flag is `--` and a name of lower-case letters, digits and dashes that starts with a letter
|
|
602
|
+
…
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
An overwrite can also change how a reviewer it leaves alone is dispatched.
|
|
606
|
+
When the new version drops a family flag and one other project reviewer is left
|
|
607
|
+
carrying it, that flag becomes the other reviewer's own and dispatches it past
|
|
608
|
+
its path gate — here the overlay dropped `--api` from `review-acme-api`:
|
|
609
|
+
|
|
610
|
+
```
|
|
611
|
+
$ keryx review import --from ./vendor/acme-overlay/skills/review-acme-api --force --dry-run
|
|
612
|
+
…
|
|
613
|
+
- review/review-acme-api: would-overwrite — review-orchestrator will dispatch this after `keryx review reviewers` lists it
|
|
614
|
+
- warning: flag --api is dropped by this version of review-acme-api, which leaves review-house-api its only carrier: --api now dispatches review-house-api outright instead of selecting it path-gated.
|
|
615
|
+
…
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
An origin that reads `missing` cannot be updated from: pass the new location
|
|
619
|
+
with `keryx skills update <module>/<name> --from <new-origin>`.
|
|
620
|
+
|
|
621
|
+
## Registration is per clone where `.metaproject/` is ignored
|
|
622
|
+
|
|
623
|
+
Everything above lives under `.metaproject/`. Many projects git-ignore that
|
|
624
|
+
directory, and then an import registers reviewers in the clone it ran in and
|
|
625
|
+
nowhere else: a teammate, a fresh worktree and CI see none of them until the
|
|
626
|
+
import is run there too. Check with `git check-ignore .metaproject` before
|
|
627
|
+
telling anyone the reviewers are wired for the team.
|
|
628
|
+
|
|
629
|
+
Where `.metaproject/` is tracked, commit what the import wrote:
|
|
630
|
+
`.metaproject/project-skills/review/`, the registry entry in
|
|
631
|
+
`.metaproject/metaproject.json`, the catalog row, and the rules — including
|
|
632
|
+
`.metaproject/rules/project/`, which `keryx init`, `keryx update` and
|
|
633
|
+
`keryx skills install` (either form) never write or clean, so a clone that lacks it
|
|
634
|
+
silently reads keryx's generic rule under the same name. Keep the overlay at a path that resolves for everyone
|
|
635
|
+
(inside the repository, or the same `~/…` location), or `drift` reads `missing`
|
|
636
|
+
on every machine but the importer's.
|
|
637
|
+
|
|
638
|
+
## `review-learning.config.json`
|
|
639
|
+
|
|
640
|
+
Optional, and separate from importing: it names which pull-request comment
|
|
641
|
+
authors `keryx review learn` may turn into lessons for one project skill. The
|
|
642
|
+
file is `.metaproject/review-learning.config.json`:
|
|
643
|
+
|
|
644
|
+
```json
|
|
645
|
+
{
|
|
646
|
+
"schemaVersion": 1,
|
|
647
|
+
"skill": "review/review-acme-api",
|
|
648
|
+
"repo": "acme/shop",
|
|
649
|
+
"authors": ["alice", "bob"],
|
|
650
|
+
"reviewerProfiles": ["alice"]
|
|
651
|
+
}
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
- `schemaVersion` — required, exactly `1`.
|
|
655
|
+
- `skill` — required, `<module>/<skill>` naming a project skill under
|
|
656
|
+
`.metaproject/project-skills/`: one `/`, no whitespace. The loader checks the
|
|
657
|
+
shape only.
|
|
658
|
+
- `repo` — required, `owner/repo`: the repository whose collected comments
|
|
659
|
+
teach that skill.
|
|
660
|
+
- `authors` — required, at least one GitHub login. Matching is
|
|
661
|
+
case-insensitive and otherwise exact. A present file with no authors is an
|
|
662
|
+
error rather than a pass that teaches nothing.
|
|
663
|
+
- `reviewerProfiles` — optional array of logins that also get a per-reviewer
|
|
664
|
+
profile rule. Every entry must be one of `authors` (case-insensitive);
|
|
665
|
+
omitted means nobody gets a profile.
|
|
666
|
+
|
|
667
|
+
There are no defaults: every required field must be present. No file at all is
|
|
668
|
+
the supported "this project does not learn" state and is not an error; a file
|
|
669
|
+
that is present and malformed is refused with the field named.
|