@hasna/skills 0.10.72 → 0.10.74

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.
@@ -195,7 +195,7 @@ plugin dependency declarations refuse because this validator does not resolve
195
195
  or review unselected external plugins.
196
196
  The request may declare `functionHooksEnv: "1"`; without that declaration the
197
197
  environment document is preserved unchanged. For a measured Claude 2.1.276,
198
- 2.1.278, 2.1.282, 2.1.287, 2.1.293, 2.1.296 or 2.1.299 user-scoped install,
198
+ 2.1.278, 2.1.282, 2.1.287, 2.1.293, 2.1.296, 2.1.299 or 2.1.300 user-scoped install,
199
199
  `candidate.settingsMarketplaceSource: "directory"`
200
200
  explicitly declares the native settings registration. Skills derives
201
201
  `extraKnownMarketplaces[candidate.marketplace].source` from the exact frozen
@@ -249,6 +249,49 @@ structural refusal checks do not prove hook behavior. Recheck all preimages and
249
249
  candidate closure immediately before the first native mutation. The validator
250
250
  does not claim native install atomicity or crash recovery.
251
251
 
252
+ The reviewed discovery inputs must bind every current Claude settings and
253
+ registration source: the user settings, both project settings files,
254
+ `known_marketplaces.json` and `installed_plugins.json`. A project
255
+ `.claude/settings.json` or `.claude/settings.local.json` that the reviewed
256
+ sources omit is exempt only when no other expected source (the target settings
257
+ or the user settings) shares its path, and it is either:
258
+
259
+ - absent, with a null preimage; or
260
+ - present, and all of the following hold:
261
+ - its current bytes match its preimage SHA-256; a mismatch refuses with
262
+ `<name> preimage changed`;
263
+ - those exact bytes are strict UTF-8 without a byte-order mark and parse as
264
+ one JSON object within the native JSON witness limits (no comments,
265
+ trailing commas, trailing content or duplicate keys at any depth);
266
+ - none of `enabledPlugins`, `extraKnownMarketplaces`,
267
+ `additionalMarketplaces` or `skillOverrides` is present at any value,
268
+ including `null`, `{}` and `[]`;
269
+ - every top-level key is on the exemption allowlist with its type:
270
+ `permissions` (an object), `outputStyle`, `model`, `theme` and
271
+ `effortLevel` (strings), and `verbose` and `spinnerTipsEnabled` (booleans);
272
+ - `permissions` holds only `allow`, `deny` and `ask` (arrays of strings) and
273
+ `defaultMode` (a string).
274
+
275
+ Anything else keeps the file required, including `env` (Claude reads
276
+ `CLAUDE_CODE_PLUGIN_DIRS` from it), `hooks`, `permissions.additionalDirectories`
277
+ (Claude loads skills, commands and agents from those directories), `__proto__`
278
+ and unknown keys. The allowlist names settings reviewed as not configuring
279
+ plugins, marketplaces, skills, hooks, extra directories or the environment. It
280
+ does not prove that Claude cannot discover anything from the file; a setting
281
+ joins it only after that review.
282
+
283
+ This covers the permissions-only `~/.claude/settings.local.json` that Claude
284
+ writes when it saves a permission rule during a user-scope install, whose
285
+ project path is the Claude home. A present unreviewed file that fails the parse,
286
+ discovery-key or allowlist checks refuses and names the reason. Each exempt file
287
+ is re-checked against its exact preimage (still absent, or the same bytes) after
288
+ discovery and again before the result, so a change, creation or removal in
289
+ between refuses. The live hooks' project check still runs on top; it refuses
290
+ any of the four discovery keys (`additionalMarketplaces` included, because
291
+ Claude 2.1.300 rewrites it into `extraKnownMarketplaces` on every settings read)
292
+ and its other project skill and hook settings. The user settings and both
293
+ registries are never exempt.
294
+
252
295
  The optional release manifest witness binds the complete supplied release.json
253
296
  file bytes, path and SHA-256 in the request/receipt. Harnesses remains
254
297
  responsible for verifying that its release options correspond to every
@@ -270,8 +313,12 @@ skills hook capture-claude-installer --request /absolute/request.json --json
270
313
  The UTF-8 request is a bounded JSON object with schema
271
314
  `skills.claude-installer-capture/v1`, the exact configured `commandPath`, one
272
315
  fixed `operation` (`settings`, `marketplace-registry`, `managed-plugin-registry`,
273
- `path-bytes`, `discovery-directories`, `plugin-manifest`, or `candidate`), and
274
- only that operation's documented inputs. The result uses
316
+ `path-bytes`, `discovery-directories`, `plugin-manifest`, `candidate`, or
317
+ `discovery-binding`), and only that operation's documented inputs. The
318
+ `discovery-binding` operation verifies the stored Claude discovery binding as a
319
+ whole, including witnesses retained under an absent retired plugin-cache
320
+ version; its request and result contract is in the README section
321
+ "Claude installer witness CLI". The result uses
275
322
  `skills.claude-installer-capture-result/v1` and contains a Skills producer
276
323
  receipt plus the selected existing witness result. Candidate manifests include
277
324
  their plugin name, canonical path, `hashMode: "claude-plugin-manifest-v1"`, and
@@ -307,7 +354,8 @@ What the software currently enforces is narrower:
307
354
  non-null hash. A non-string `hooks` value and a `hooks` target outside the
308
355
  plugin root are refused. A manifest listed as `claude-plugin-manifest-v1`
309
356
  (the form Skills writes into the stored policy) or as `path-bytes` triggers
310
- no hook-file requirement. Nothing else is required.
357
+ no hook-file requirement, and neither does a manifest the absent retired
358
+ version rule below retains. Nothing else is required.
311
359
  - A `hooks/hooks.json` that is absent at review time and appears later is
312
360
  detected if the review pins it with `sha256: null` or covers it with a
313
361
  reviewed `directories` membership witness on the plugin root or its `hooks/`
@@ -336,7 +384,7 @@ What the software currently enforces is narrower:
336
384
  `captureDiscoveryPathSources` (including the installer `path-bytes`
337
385
  operation) produces a `claude-plugin-orphaned-at-v1` witness, and a fresh
338
386
  explicit review converts a plain byte or `path-bytes` witness of it to that
339
- form. The witness binds the marker's presence or absence, not its bytes or
387
+ form, unless the absent retired version rule below retains it. The witness binds the marker's presence or absence, not its bytes or
340
388
  inode. Every capture and check still requires a regular, non-symlink file
341
389
  owned by the current user, at most 32 bytes, matching `^[1-9][0-9]{12}$`.
342
390
  The name stays in `directories` membership, so other added or removed names
@@ -345,17 +393,20 @@ What the software currently enforces is narrower:
345
393
  that binds the marker's bytes keeps that meaning and needs one fresh review.
346
394
  - An entirely absent retired Claude version root exempts only its plain byte
347
395
  sources (`hashMode` omitted or `"bytes"`, with no `format`, `fields` or
348
- `managedPlugins`) and a present `claude-plugin-orphaned-at-v1` marker. Such a
349
- source with a non-null `sha256` is also the only
396
+ `managedPlugins`), its `.claude-plugin/plugin.json` as a
397
+ `claude-plugin-manifest-v1` witness and a present
398
+ `claude-plugin-orphaned-at-v1` marker. Such a source with a non-null
399
+ `sha256` is also the only
350
400
  thing that identifies the root, and the root qualifies only while it stays
351
401
  entirely absent and the reviewed settings and registry select a different,
352
402
  verified version. Every other source under that root is re-hashed as usual,
353
403
  and one whose file existed at review no longer matches its hash, so the
354
- check refuses. That includes the plugin manifest in the
355
- `claude-plugin-manifest-v1` form Skills stores, so a stored review that lists
356
- the retired version's manifest refuses until a fresh review replaces it. A
357
- `directories` witness that covers the retired root is not exempt either. If
358
- the root reappears, its sources are checked again.
404
+ check refuses. A `directories` witness that covers the retired root is not
405
+ exempt either. An explicit review (`--discovery-inputs`) keeps each exempt
406
+ source exactly as listed: it does not project a byte-witnessed manifest,
407
+ require its hook files or convert a byte-witnessed marker, so a historical
408
+ byte witness keeps its meaning. If the root reappears, its sources are
409
+ checked again.
359
410
  - It is detection-only. Later checks re-hash the stored sources and re-walk any
360
411
  reviewed `directories` witnesses. Drift makes the
361
412
  Skills hooks refuse with `NATIVE_SKILL_DRIFT`; it does not stop, unload or
@@ -91,10 +91,24 @@ existing Codewith conventions):
91
91
  `package.json`, a non-empty `bin`, and `src/index.ts`. `skills run` executes it.
92
92
  - `kind: instruction` — a `SKILL.md`-primary prose skill for coding agents.
93
93
  `package.json`, `bin`, and `src/` are all optional. Instruction skills may still
94
- bundle optional helper scripts (a `bin`/`src` is permitted, not forbidden), but
95
- they are consumed by agents via `SKILL.md`, not executed. `skills run` on an
96
- instruction skill returns a clear "not runnable — instruction skill" error
97
- instead of executing a stub.
94
+ bundle optional helper scripts (a `bin`/`src` is permitted, not forbidden) and
95
+ are consumed by agents via `SKILL.md`. `skills run` refuses a prose-only
96
+ instruction skill with a clear "not runnable — instruction skill" error instead
97
+ of executing a stub.
98
+ - An instruction skill may instead declare the one operation it ships: the first
99
+ `commands` entry, naming its helper, together with an explicit `runtime`
100
+ contract. `skills run` then executes exactly that declared entrypoint from the
101
+ selected bundle — the same immutable object, digest receipt, argument,
102
+ timeout, output and no-ambient-credential contract an executable skill gets —
103
+ and still refuses the skill when it declares no operation or no runtime. The
104
+ declared command entry is the authority: it must be a regular file in the
105
+ selected bundle, and a `runtime.entrypoint` that disagrees with it is an
106
+ inconsistent declaration that refuses (`LOCAL_ENTRYPOINT_MISMATCH`) rather than
107
+ running the other file. A declared entry missing from the bundle refuses
108
+ (`LOCAL_ENTRYPOINT_MISSING`) and is never substituted, and the mutable
109
+ authoring corpus is never executed. Executable skills keep their own
110
+ precedence (`runtime.entrypoint`, then `package.json` bin) unchanged, and cloud
111
+ execution keeps requiring an executable skill version.
98
112
 
99
113
  New scaffolds always record their selected kind. Legacy local readers retain
100
114
  their executable fallback, while the legacy publication API retains its
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/skills",
3
- "version": "0.10.72",
3
+ "version": "0.10.74",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {