@hasna/skills 0.10.70 → 0.10.72

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 CHANGED
@@ -207,6 +207,82 @@ is recorded at `agent-hooks/codex-native-policy-acceptance.json`; user,
207
207
  repository and project copies still refuse, and format or digest checks never
208
208
  prove the runtime policy on their own.
209
209
 
210
+ A Codex plugin refresh can deposit a new vendor skill in `~/.codex/plugins/cache`
211
+ (for example `openai-curated-remote/sites/1.0.2-remix-b.1/skills/sites-remix`).
212
+ Skill payloads still reach agents only through the Skills CLI, so an enabled
213
+ vendor copy keeps blocking the Codex prompt hook. Retire it by disabling it in
214
+ `~/.codex/config.toml`. The plugin-qualified name survives later version
215
+ directories, so prefer it:
216
+
217
+ ```toml
218
+ [[skills.config]]
219
+ name = "sites:sites-remix"
220
+ enabled = false
221
+ ```
222
+
223
+ An exact `path = ".../sites/1.0.2-remix-b.1/skills/sites-remix/SKILL.md"` rule
224
+ also works, but only for that version. On the live Codex prompt hook only, a
225
+ copy is then exempt when every condition holds:
226
+
227
+ - it is package-classified plugin content in `openai-bundled`, `openai-curated`
228
+ or `openai-curated-remote` (exact names), with Codex's remote install receipt
229
+ for the remote marketplace;
230
+ - it carries no Skills or Hasna marker;
231
+ - every cached version of its plugin passes the vendor refresh check described
232
+ below for membership changes, so the plugin can load nothing that the
233
+ inventory and this rule do not account for, and no version is a link;
234
+ - a `[[skills.config]]` rule names its exact path or its plugin-qualified name
235
+ with `enabled = false`, and no matching rule enables it.
236
+
237
+ A whole-plugin `[plugins."sites@openai-curated-remote"] enabled = false` table
238
+ is not enough on its own: remote state can enable a locally disabled remote
239
+ plugin, and a cache copy carries no proof that its plugin source is
240
+ configuration-controlled, so the copy keeps blocking until a path or name rule
241
+ retires it. This exemption only adds to the guard's existing ones; every copy
242
+ that the guard already accepts, such as an exact-path disable in any plugin-cache
243
+ marketplace or a reviewed plugin control, stays accepted on the live hook. Once
244
+ the hook tolerates one of the witness changes below, a state the strict guard
245
+ refuses outright, plugin-cache copies are exempt only through this vendor rule.
246
+
247
+ Instead of editing by hand, `skills hook native-catalog` followed by
248
+ `skills hook install --agent codex --codex-native-catalog <file> --apply` writes
249
+ the same rules through the guarded install path.
250
+
251
+ The hook also tolerates, with a visible `systemMessage` warning, only the
252
+ discovery-witness changes such a refresh provably makes:
253
+ - appended vendor disable rules or vendor plugin disables in `config.toml`,
254
+ accepted when removing exactly those entries or restoring a formerly enabled
255
+ vendor flag reproduces the reviewed digest. Candidates are tried smallest edit
256
+ first, at most 128; with a typed settings witness that covers any change to up
257
+ to two of at most eight vendor plugin tables. A change beyond the bound refuses;
258
+ - directory membership changes under an allowlisted vendor marketplace that
259
+ passes the vendor refresh check: every plugin version has exactly one
260
+ manifest, `.codex-plugin/plugin.json`, alone in its directory, whose keys are
261
+ only `name`, `version`, `description`, `author`, `homepage`, `repository`,
262
+ `license`, `keywords`, `interface`, `skills` (the default `./skills/` only) and
263
+ `apps`. So hooks in any form, commands, agents, extensions, MCP servers and
264
+ unknown keys refuse. There is no `hooks`, `commands` or `agents` directory, no
265
+ `hooks.json` or `.mcp.json` (names compared without regard to case), no root,
266
+ `.claude-plugin` or `.cursor-plugin` manifest, no link
267
+ and no `SKILL.md` that the inventory cannot see (below a dot-named or
268
+ `node_modules` directory, or nested in another skill). One exception keeps
269
+ today's vendor plugins working: every current OpenAI vendor plugin declares
270
+ its connector as `apps = "./.app.json"`, so exactly that declaration is
271
+ allowed when `.app.json` is a regular file of at most 1 MiB, strict UTF-8, that
272
+ passes the same connector validation reviewed plugin controls use (one `apps`
273
+ object; app entries with only `id`, `category` and `required`, of the right
274
+ types; no duplicate keys). Any other connector path, a file that fails that
275
+ validation, or the file without the declaration refuses.
276
+
277
+ Every other copy and change still refuses with `NATIVE_SKILL_DRIFT`, including:
278
+ - user, project, `.system` and Hasna-marketplace copies that the guard does not
279
+ already exempt;
280
+ - an enabled vendor copy whose plugin is only disabled by a whole-plugin table;
281
+ - capability-control changes and whole-cache membership changes;
282
+ - plugin activation, including a vendor plugin gaining `enabled = true`;
283
+ - missing coverage and changed roots;
284
+ - every install, trust, migrate and sync check.
285
+
210
286
  Native hook invocations must use their installed adapter's selection profile.
211
287
  An old client command or environment override naming another profile refuses
212
288
  before synchronization or context loading. Review the hook installation and
@@ -550,6 +626,10 @@ non-null `sha256`, Skills also requires plain byte witnesses for that plugin's
550
626
  `hooks/hooks.json` (when present) and any string `hooks` target in the
551
627
  manifest. A manifest listed as `claude-plugin-manifest-v1` (the form Skills
552
628
  writes into the stored policy) or as `path-bytes` triggers no such requirement.
629
+ The version-root `.orphaned_at` timestamp that Claude rewrites at startup is
630
+ bound by presence only, as `claude-plugin-orphaned-at-v1`, and is still
631
+ strictly validated; see
632
+ [the full scope](docs/plugin-admission.md#reviewed-plugin-hook-attestation-scope).
553
633
  For plugins outside receipt-backed admission (a `claude-plugin-registry`
554
634
  witness, see the
555
635
  [discovery transition contract](docs/plugin-admission.md#discovery-transition-contract)),
@@ -819,16 +899,37 @@ a skill. Cached use is explicit and expires after 24 hours. When a session
819
899
  receipt expires, the hook authenticates the current profile. If every loaded
820
900
  selection still has identical metadata and bundle digest, it archives the old
821
901
  receipt and advances that session to the current profile under an exact receipt
822
- precondition. Unloaded selections may be added or removed. If a loaded selection
823
- changed or disappeared, no instructions are delivered until the explicit
824
- reconciliation below. A missing cache may be recovered through authenticated context.
902
+ precondition. Unloaded selections may be added or removed. If renewal is refused
903
+ because the same profile moved on (a loaded selection changed or disappeared, or
904
+ another pinned selection's policy, membership or lifecycle changed), the managed
905
+ hook applies the explicit reconciliation planner and applier below to the
906
+ authenticated current revision: it archives the old receipt, retains unchanged
907
+ loaded bundles, retires changed or removed ones and delivers context for the
908
+ prompt. The first hook context that succeeds and reaches the agent afterwards
909
+ names each retired loaded skill once and how to reload its replacement; earlier
910
+ instructions from those skills must not be relied on. Identity, integrity and receipt failures, an
911
+ unavailable authority and anything the planner refuses keep their refusal;
912
+ session write-lock contention keeps `SESSION_WRITE_BUSY`. A
913
+ session created from a project lock (`.skills/selection.lock.json`) records
914
+ that lock in its receipt and is never migrated automatically, whatever
915
+ directory it later prompts from. A session without that record is not migrated
916
+ while a lock sits in the prompt's working directory or any ancestor. A loaded
917
+ skill whose lifecycle epoch rotated while its bytes stayed the same also keeps
918
+ the refusal. If the migration cannot finish within the four-second renewal window,
919
+ the hook reports `SESSION_RECONCILIATION_REQUIRED` with that reason and the next
920
+ prompt retries. Turn this off station-wide with `skills config set
921
+ sessionPinMigration off --global` (the key is refused without `--global`, and a
922
+ global configuration that is a symlink, cannot be read or cannot be parsed also
923
+ turns it off); the hook
924
+ then keeps today's refusal until the explicit reconciliation below. A missing
925
+ cache may be recovered through authenticated context.
825
926
 
826
927
  After verifying the native bridge and input, ordinary lifecycle hooks continue
827
928
  without skill payload on typed hosted authentication/refusal/availability failures,
828
929
  context timeouts, valid concurrent writers, context CAS conflicts, or required
829
930
  session reconciliation. They emit a fixed warning that Skills-dependent actions
830
931
  are unavailable; previously loaded instructions are not an authorization fallback.
831
- The hook does not rewrite a session pin or remove another writer’s lock to bypass these refusals. Explicit `skills
932
+ Apart from the automatic migration above, the hook does not rewrite a session pin or remove another writer’s lock to bypass these refusals. Explicit `skills
832
933
  load`, `skills context`, and `skills run` still refuse unavailable or unauthorized
833
934
  instructions. Native skill tool guards still deny unmanaged payloads. Invalid
834
935
  input/receipts, integrity or authority mismatches, unknown failures, and native
@@ -1009,7 +1110,10 @@ hosted publication access.
1009
1110
  `--profile` option chooses an isolated credential file; these are separate
1010
1111
  settings. `HASNA_SKILLS_SELECTION_PROFILE` overrides the installed selection
1011
1112
  profile. A project lock and an existing session keep exact versions until they
1012
- are explicitly changed or a new session starts.
1113
+ are explicitly changed or a new session starts. The one exception is the
1114
+ managed hook's automatic migration of an expired session pin described above.
1115
+ It never applies to a session created from a project lock, and never while a
1116
+ lock sits in the prompt's working directory or an ancestor.
1013
1117
 
1014
1118
  ## Executable skills
1015
1119
 
@@ -1367,7 +1471,7 @@ of app folders, and `XDG_CONFIG_HOME` is not consulted at all.
1367
1471
  | `skills setup-info` | | Version, pinned skills, agent configs, paths |
1368
1472
  | `skills export` | | Export pinned skills as JSON |
1369
1473
  | `skills import <file>` | | Pin skills from a JSON export |
1370
- | `skills config set <key> <value>` | | Set default agent, scope, output format, or API origin |
1474
+ | `skills config set <key> <value>` | | Set default agent, scope, output format, or API origin; `sessionPinMigration off --global` keeps managed hooks from migrating refused session pins (global scope only) |
1371
1475
  | `skills config unset <key>` | | Remove a configuration value (`skills config unset apiUrl` clears the stored service address and returns to running on this machine) |
1372
1476
  | `skills new <name>` | `scaffold` | Scaffold a portable skill under `~/.hasna/skills/installed/<name>` |
1373
1477
  | `skills port <path>` | `add` | Import an existing skill folder into the portable standard |