@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.
- package/README.md +347 -2
- package/bin/index.js +2197 -1277
- package/bin/mcp.js +194 -46
- package/bin/migrate.js +1 -1
- package/bin/server.js +1 -1
- package/bin/worker.js +1 -1
- package/dist/cli/commands/provenance.d.ts +18 -0
- package/dist/index.js +1016 -713
- package/dist/lib/agent-discovery.d.ts +36 -0
- package/dist/lib/claude-installer-binding.d.ts +65 -0
- package/dist/lib/codex-node-modules.d.ts +11 -0
- package/dist/lib/codex-settings-witness-v1.d.ts +9 -0
- package/dist/lib/codex-settings-witness.d.ts +18 -0
- package/dist/lib/portable-skills-files.d.ts +10 -0
- package/dist/lib/selected-run.d.ts +45 -0
- package/dist/lib/selection-provenance.d.ts +108 -0
- package/dist/runtime-prerequisites.js +1 -1
- package/dist/sdk/index.js +1174 -842
- package/docs/plugin-admission.md +63 -12
- package/docs/skill-standard.md +18 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -113,6 +113,27 @@ skills hook install --selection-profile default --json
|
|
|
113
113
|
skills hook install --selection-profile default --apply --json
|
|
114
114
|
```
|
|
115
115
|
|
|
116
|
+
`--include-vendor` resolves configured plugin discovery, so it needs a reviewed
|
|
117
|
+
`--discovery-inputs` file when a configured plugin declares hooks. Without it,
|
|
118
|
+
`skills migrate native --include-unmanaged` archives user and project copies
|
|
119
|
+
only. Migration never archives Codex system skills (`.codex/skills/.system`),
|
|
120
|
+
even with `--include-vendor`. Codex refreshes its OpenAI marketplace plugin
|
|
121
|
+
caches on its own; retire those copies with a Codex `[[skills.config]]` rule
|
|
122
|
+
(`name = "<plugin>:<skill>"` or the exact `path` of the `SKILL.md`, with
|
|
123
|
+
`enabled = false`) rather than by archiving. The live Codex prompt hook accepts
|
|
124
|
+
a name rule only for a copy with no Hasna marker, its remote install receipt, a
|
|
125
|
+
refresh-safe plugin and no rule that enables it. Other checks (`skills hook
|
|
126
|
+
install` reusing a saved review, `skills hook trust`) do not accept a
|
|
127
|
+
hand-added name rule; for them, and for system skills, run `skills hook install
|
|
128
|
+
--agent codex --discovery-inputs <file> --apply` with a fresh discovery review
|
|
129
|
+
(no `--discovery-inputs` on an automatic binding; add a fresh
|
|
130
|
+
`--codex-native-catalog <file>` for a plugin Skills has enrolled), which writes
|
|
131
|
+
and records the disables. Run the same refresh after editing `config.toml` when
|
|
132
|
+
the binding's recorded configuration witness counts the edit: on automatic
|
|
133
|
+
bindings, after removing a rule that enables skills, and on reviewed bindings
|
|
134
|
+
whose witness counts disable rows. A `NATIVE_SKILL_DRIFT` refusal names the
|
|
135
|
+
step for each copy it lists, including that follow-up.
|
|
136
|
+
|
|
116
137
|
Without `--agent`, hook installation selects configured or detected consumers:
|
|
117
138
|
existing managed bridge bindings, provider-specific home configuration, or an
|
|
118
139
|
installed native CLI found through PATH. Detection reads metadata and never
|
|
@@ -264,8 +285,8 @@ discovery-witness changes such a refresh provably makes:
|
|
|
264
285
|
unknown keys refuse. There is no `hooks`, `commands` or `agents` directory, no
|
|
265
286
|
`hooks.json` or `.mcp.json` (names compared without regard to case), no root,
|
|
266
287
|
`.claude-plugin` or `.cursor-plugin` manifest, no link
|
|
267
|
-
and no `SKILL.md`
|
|
268
|
-
|
|
288
|
+
and no `SKILL.md` below a dot-named or `node_modules` directory, or nested
|
|
289
|
+
in another skill. One exception keeps
|
|
269
290
|
today's vendor plugins working: every current OpenAI vendor plugin declares
|
|
270
291
|
its connector as `apps = "./.app.json"`, so exactly that declaration is
|
|
271
292
|
allowed when `.app.json` is a regular file of at most 1 MiB, strict UTF-8, that
|
|
@@ -541,6 +562,20 @@ is bounded to 20,000 discovery entries and 4 MiB of UTF-8 path metadata before
|
|
|
541
562
|
directory entries are retained or sorted. Unsupported special files and unsafe
|
|
542
563
|
directory links are refused.
|
|
543
564
|
|
|
565
|
+
Codex 0.162.1 loads `SKILL.md` files below `node_modules` inside its skill
|
|
566
|
+
roots, so Codex inventory and the prompt guard walk `node_modules` in
|
|
567
|
+
`~/.codex/skills`, `~/.agents/skills`, each project's `.codex/skills` and
|
|
568
|
+
`.agents/skills` and configured plugin skill roots. In `~/.codex/plugins/cache`
|
|
569
|
+
they walk it only where it can lie in a plugin skill root: below a version's
|
|
570
|
+
default `skills` directory or a manifest-declared skills path, or as a
|
|
571
|
+
marketplace, plugin or version directory named `node_modules`; an unreadable
|
|
572
|
+
manifest walks every `node_modules` in its version. Dot-named directories such
|
|
573
|
+
as `node_modules/.pnpm`, a plugin version's own dependencies and any
|
|
574
|
+
`node_modules` outside a skill root stay unscanned, because Codex does not load
|
|
575
|
+
them; other agents' roots keep skipping `node_modules`. Depth limits are
|
|
576
|
+
unchanged: Codex reads six directory levels below a root, and an ordinary root
|
|
577
|
+
records a skill four levels down and refuses anything deeper.
|
|
578
|
+
|
|
544
579
|
Native archives persist a version 2 recovery journal before moving payloads;
|
|
545
580
|
`migrate native --json --apply` returns its `receiptPath`. The journal records
|
|
546
581
|
every source, archive path, expected hash, and move status, then marks successful
|
|
@@ -626,6 +661,10 @@ non-null `sha256`, Skills also requires plain byte witnesses for that plugin's
|
|
|
626
661
|
`hooks/hooks.json` (when present) and any string `hooks` target in the
|
|
627
662
|
manifest. A manifest listed as `claude-plugin-manifest-v1` (the form Skills
|
|
628
663
|
writes into the stored policy) or as `path-bytes` triggers no such requirement.
|
|
664
|
+
A source that the `absent-retired-claude-version` rule retains (see
|
|
665
|
+
[`discovery-binding`](#verify-the-stored-claude-discovery-binding-discovery-binding))
|
|
666
|
+
is stored exactly as listed: Skills does not project its manifest, require its
|
|
667
|
+
hook files or convert its marker, because the file no longer exists.
|
|
629
668
|
The version-root `.orphaned_at` timestamp that Claude rewrites at startup is
|
|
630
669
|
bound by presence only, as `claude-plugin-orphaned-at-v1`, and is still
|
|
631
670
|
strictly validated; see
|
|
@@ -694,6 +733,27 @@ file; drift still requires a fresh explicit review. Explicit discovery inputs
|
|
|
694
733
|
take precedence, including when their `agents` array omits a previously reviewed
|
|
695
734
|
agent. The default `--agent all` still includes every supported adapter.
|
|
696
735
|
|
|
736
|
+
That recheck has two halves, and only one of them gates reuse. BINDING CUSTODY —
|
|
737
|
+
the same managed bridge, home, alias set, agent, command/profile binding and
|
|
738
|
+
reviewed discovery — must hold before a saved review is reused, or the plan
|
|
739
|
+
refuses and names a fresh explicit review. Bridge PROTECTION — the native plugin
|
|
740
|
+
bytes, the permission and hook rules and the bundled-skill switches — is written
|
|
741
|
+
by the same plan, so it is asserted in full after the writes instead of gating
|
|
742
|
+
the repair that fixes it; a plan that does not repair it is refused before the
|
|
743
|
+
receipt is written. Hermes native shell-hook trust is the exception: it is the
|
|
744
|
+
user's own consent and no Skills write creates it, so it stays a pre-write
|
|
745
|
+
condition. One implementation serves both halves, so they cannot drift apart.
|
|
746
|
+
|
|
747
|
+
Because that recheck includes the managed bridge, `hook install` cannot reuse a
|
|
748
|
+
saved review on a host whose bridge has since broken, and in that form it cannot
|
|
749
|
+
repair its own precondition. It refuses and names the reachable form,
|
|
750
|
+
`skills hook install --agent <agent> --discovery-inputs <review> --apply`, which
|
|
751
|
+
skips the retained-review precheck and rebuilds the bridge from the review in the
|
|
752
|
+
same transaction. A reviewed binding always carries a whole-file witness for the
|
|
753
|
+
agent configuration beside its projected fields, so unchanged projected fields do
|
|
754
|
+
not excuse a change outside them: a fresh explicit discovery review, not a
|
|
755
|
+
witness refresh, is the supported route.
|
|
756
|
+
|
|
697
757
|
For reviewed Claude plugins, `skills integration plugin plan`, `admit` and
|
|
698
758
|
`resolve` provide a command-source admission boundary before native discovery.
|
|
699
759
|
Original packages and migrated skill/command prompts remain in private versioned
|
|
@@ -702,6 +762,25 @@ receipt permits only verified registry/cache transitions. See
|
|
|
702
762
|
[plugin admission](docs/plugin-admission.md) for the package, review and runtime
|
|
703
763
|
contracts; these commands do not change live agent registrations or settings.
|
|
704
764
|
|
|
765
|
+
The read-only `skills hook review-claude-candidate` check requires its reviewed
|
|
766
|
+
discovery inputs to bind the user settings, both project settings files and
|
|
767
|
+
both plugin registries. A project `.claude/settings.json` or
|
|
768
|
+
`.claude/settings.local.json` that the review omits is exempt only when no other
|
|
769
|
+
expected source shares its path and it is either absent, or present with exact
|
|
770
|
+
preimage bytes that parse strictly as one JSON object (strict UTF-8, no
|
|
771
|
+
byte-order mark, comments, trailing content or duplicate keys) and carry only
|
|
772
|
+
allowlisted settings: `permissions` with `allow`, `deny`, `ask` and
|
|
773
|
+
`defaultMode`, plus `outputStyle`, `model`, `theme`, `effortLevel`, `verbose`
|
|
774
|
+
and `spinnerTipsEnabled`. Any discovery key (`enabledPlugins`,
|
|
775
|
+
`extraKnownMarketplaces`, `additionalMarketplaces`, `skillOverrides`), `env`,
|
|
776
|
+
`hooks`, `permissions.additionalDirectories` or unknown key keeps the file
|
|
777
|
+
required. The allowlist is a reviewed list of settings, not a proof that Claude
|
|
778
|
+
cannot discover anything from the file. This admits the permissions-only
|
|
779
|
+
`~/.claude/settings.local.json` that Claude writes when it saves a permission
|
|
780
|
+
rule. Each exempt file is re-checked against its exact preimage until the
|
|
781
|
+
result; user settings and the registries are never exempt. See
|
|
782
|
+
[prospective Claude candidate review](docs/plugin-admission.md#prospective-claude-candidate-review).
|
|
783
|
+
|
|
705
784
|
If your home `.claude` or `.codex` directory intentionally links to another
|
|
706
785
|
directory within your home, add `--allow-root-aliases` to hook installation and
|
|
707
786
|
native migration. The plan records and rechecks the exact link and target;
|
|
@@ -1009,6 +1088,216 @@ reports an incomplete outcome, inspect `sessions show` and the preserved
|
|
|
1009
1088
|
operation receipt before retrying. The archive contains both original and
|
|
1010
1089
|
prepared bytes even if the final receipt write fails.
|
|
1011
1090
|
|
|
1091
|
+
### Claude installer witness CLI (`capture-claude-installer`)
|
|
1092
|
+
|
|
1093
|
+
```text
|
|
1094
|
+
skills hook capture-claude-installer --request /absolute/request.json --json
|
|
1095
|
+
```
|
|
1096
|
+
|
|
1097
|
+
Installers obtain Skills-owned witnesses through the configured Skills command
|
|
1098
|
+
instead of reimplementing them. Every request is a JSON object of at most
|
|
1099
|
+
64 KiB with exactly the keys of one operation: `schema`
|
|
1100
|
+
(`skills.claude-installer-capture/v1`), `commandPath` (the normalized absolute
|
|
1101
|
+
path of the configured Skills command), `operation`, and that operation's
|
|
1102
|
+
inputs. The command checks that `commandPath` resolves to this installed
|
|
1103
|
+
`@hasna/skills` CLI and runtime, before and after the operation, and prints
|
|
1104
|
+
one receipt on stdout with exit status 0:
|
|
1105
|
+
|
|
1106
|
+
```json
|
|
1107
|
+
{
|
|
1108
|
+
"schema": "skills.claude-installer-capture-result/v1",
|
|
1109
|
+
"producer": {
|
|
1110
|
+
"schema": "skills.cli-producer-identity/v1",
|
|
1111
|
+
"configuredCommandPath": "<commandPath>",
|
|
1112
|
+
"physicalLauncher": { "path": "<absolute>", "sha256": "<64 hex>" },
|
|
1113
|
+
"runtimeEntry": { "path": "<absolute>", "sha256": "<64 hex>" },
|
|
1114
|
+
"runtime": { "path": "<absolute>", "sha256": "<64 hex>" },
|
|
1115
|
+
"package": { "name": "@hasna/skills", "version": "<x.y.z>", "manifestSha256": "<64 hex>" }
|
|
1116
|
+
},
|
|
1117
|
+
"operation": "<operation>",
|
|
1118
|
+
"result": {}
|
|
1119
|
+
}
|
|
1120
|
+
```
|
|
1121
|
+
|
|
1122
|
+
A refusal prints nothing on stdout, exits 1 and writes one line to stderr,
|
|
1123
|
+
`CODE: fixed text`, which never echoes request or file contents. The
|
|
1124
|
+
per-file operations (`settings`, `marketplace-registry`,
|
|
1125
|
+
`managed-plugin-registry`, `path-bytes`, `discovery-directories`,
|
|
1126
|
+
`plugin-manifest` and `candidate`) are described in
|
|
1127
|
+
[docs/plugin-admission.md](docs/plugin-admission.md#claude-installer-witness-cli).
|
|
1128
|
+
|
|
1129
|
+
#### Verify the stored Claude discovery binding (`discovery-binding`)
|
|
1130
|
+
|
|
1131
|
+
`discovery-binding` checks the Claude discovery binding stored in the Skills
|
|
1132
|
+
policy (`bridge.discovery.claude` in `agent-policy.json`) with the discovery
|
|
1133
|
+
verification the managed prompt hook runs on it: the root alias recheck,
|
|
1134
|
+
`verifyAgentDiscovery` and, for an automatic binding, the automatic closure
|
|
1135
|
+
check. It then reports every stored witness. An installer calls it once
|
|
1136
|
+
instead of re-capturing each stored witness. Per-file capture requires every
|
|
1137
|
+
file to exist, so it refuses witnesses that Skills keeps on purpose after
|
|
1138
|
+
Claude deletes a retired plugin-cache version; this operation reports those as
|
|
1139
|
+
`retained-absent`. It does not check the bridge files, hook commands or
|
|
1140
|
+
project-directory settings, which the hook checks separately.
|
|
1141
|
+
|
|
1142
|
+
The request has exactly these keys:
|
|
1143
|
+
|
|
1144
|
+
```json
|
|
1145
|
+
{
|
|
1146
|
+
"schema": "skills.claude-installer-capture/v1",
|
|
1147
|
+
"commandPath": "/home/me/.local/bin/skills",
|
|
1148
|
+
"operation": "discovery-binding",
|
|
1149
|
+
"policyPath": "/home/me/.hasna/skills/agent-policy.json"
|
|
1150
|
+
}
|
|
1151
|
+
```
|
|
1152
|
+
|
|
1153
|
+
`policyPath` must equal `agent-policy.json` in the data directory the installed
|
|
1154
|
+
package resolves (`$HASNA_SKILLS_DIR`, default `~/.hasna/skills`), as for the
|
|
1155
|
+
`candidate` operation.
|
|
1156
|
+
|
|
1157
|
+
The receipt's `result`:
|
|
1158
|
+
|
|
1159
|
+
```json
|
|
1160
|
+
{
|
|
1161
|
+
"schema": "skills.claude-discovery-binding-verification/v1",
|
|
1162
|
+
"ok": true,
|
|
1163
|
+
"policySha256": "<64 hex>",
|
|
1164
|
+
"discoverySha256": "<64 hex>",
|
|
1165
|
+
"agent": "claude",
|
|
1166
|
+
"method": "reviewed",
|
|
1167
|
+
"rootCount": 2,
|
|
1168
|
+
"sources": [
|
|
1169
|
+
{ "index": 0, "path": "/home/me/.claude/settings.json", "hashMode": "claude-settings-v4", "format": null, "sha256": "<64 hex>", "status": "current" },
|
|
1170
|
+
{ "index": 3, "path": "/home/me/.claude/plugins/cache/market/plugin/1.0.0/.claude-plugin/plugin.json", "hashMode": "claude-plugin-manifest-v1", "format": null, "sha256": "<64 hex>",
|
|
1171
|
+
"status": "retained-absent", "retention": { "rule": "absent-retired-claude-version", "root": "/home/me/.claude/plugins/cache/market/plugin/1.0.0", "witness": "claude-plugin-manifest-v1" } }
|
|
1172
|
+
],
|
|
1173
|
+
"directories": [ { "index": 0, "path": "/home/me/.claude/plugins/cache/market/plugin/2.0.0", "status": "current" } ],
|
|
1174
|
+
"failures": []
|
|
1175
|
+
}
|
|
1176
|
+
```
|
|
1177
|
+
|
|
1178
|
+
- `policySha256` is the SHA-256 of the exact policy file bytes that were
|
|
1179
|
+
verified. It is the value a prospective review request passes as
|
|
1180
|
+
`skills.policySha256`. The policy is read again before the result is
|
|
1181
|
+
returned; if it changed, the request is refused.
|
|
1182
|
+
- `discoverySha256` is `hashClaudeDiscoveryBinding` of the stored binding, the
|
|
1183
|
+
same digest the `candidate` operation returns.
|
|
1184
|
+
- `agent`, `method` (`reviewed` or `automatic`) and `rootCount` (the number of
|
|
1185
|
+
stored discovery roots) come from the stored binding.
|
|
1186
|
+
- `sources` has one row per stored source, in stored order. `index` is the
|
|
1187
|
+
position in `bridge.discovery.claude.sources`. `path`, `hashMode`, `format`
|
|
1188
|
+
and `sha256` repeat the stored values: `hashMode` is `null` for a legacy
|
|
1189
|
+
full-file witness without a mode, `format` is `null` unless the source is a
|
|
1190
|
+
field projection (Claude reviews also keep the automatic `json` projection of
|
|
1191
|
+
`settings.json`), and a `null` `sha256` pins absence. `status` is one of:
|
|
1192
|
+
- `current`: the source's own witness reproduces the stored digest now.
|
|
1193
|
+
- `retained-absent`: the file was not read, because the
|
|
1194
|
+
`absent-retired-claude-version` rule keeps its stored digest. The rule
|
|
1195
|
+
holds when the whole version directory `retention.root`
|
|
1196
|
+
(`<...>/.claude/plugins/cache/<marketplace>/<plugin>/<version>`) is absent,
|
|
1197
|
+
the reviewed witnesses of `settings.json` and
|
|
1198
|
+
`plugins/installed_plugins.json` are current, settings enable the plugin
|
|
1199
|
+
and no settings hook names that directory, every registration of the
|
|
1200
|
+
plugin is a valid user or project row for one existing sibling version in
|
|
1201
|
+
the same plugin directory (with a user row among them), no registration of
|
|
1202
|
+
any plugin points into or contains the absent directory, and the sibling's
|
|
1203
|
+
`.claude-plugin/plugin.json` is bound and current. It applies only to
|
|
1204
|
+
reviewed bindings. `retention.witness` names the retained witness class:
|
|
1205
|
+
`bytes` (a full byte witness, `hashMode` `null` or `bytes`),
|
|
1206
|
+
`claude-plugin-manifest-v1` or `claude-plugin-orphaned-at-v1` (the typed
|
|
1207
|
+
presence witness of a version-root `.orphaned_at` marker). No other
|
|
1208
|
+
witness is retained: `path-bytes`, field projections and typed settings
|
|
1209
|
+
or registry witnesses stay checked. Settings and registry files are
|
|
1210
|
+
never retained.
|
|
1211
|
+
- `drift`, with `reason`: `MISSING` (the path is absent and the rule does
|
|
1212
|
+
not retain it), `APPEARED` (the stored witness pins absence and the path
|
|
1213
|
+
now exists), `CHANGED` (the path exists but its witness does not
|
|
1214
|
+
reproduce the stored digest or refuses the current file, for example
|
|
1215
|
+
edited settings or a symlink), `MARKER_INVALID` (a
|
|
1216
|
+
`claude-plugin-orphaned-at-v1` marker exists but is not a valid Claude
|
|
1217
|
+
marker; see below) or `REFUSED` (the path's presence could not be
|
|
1218
|
+
determined).
|
|
1219
|
+
- `directories` has one row per stored directory membership witness, with
|
|
1220
|
+
`status` `current`, or `drift` with `reason` `MEMBERSHIP_CHANGED` or
|
|
1221
|
+
`REFUSED`.
|
|
1222
|
+
- `failures` lists every drifted source and directory as
|
|
1223
|
+
`{ "kind": "source" | "directory", "index", "path", "reason" }`, followed by
|
|
1224
|
+
`{ "kind": "binding", "reason": "DISCOVERY_REFUSED" }` whenever the hook's
|
|
1225
|
+
own discovery verification refuses the binding. That covers checks no single
|
|
1226
|
+
row shows, such as a changed root alias, a retired directory that reappeared
|
|
1227
|
+
during verification or an invalid witness combination.
|
|
1228
|
+
- `ok` is `true` only when `failures` is empty: the hook's verification
|
|
1229
|
+
accepts the binding, every source is `current` or `retained-absent` and
|
|
1230
|
+
every directory is `current`.
|
|
1231
|
+
|
|
1232
|
+
`ok: false` is a completed verification and still exits 0, so the caller
|
|
1233
|
+
reads which witnesses drifted and why. Installers must require `ok === true`.
|
|
1234
|
+
To bind the result, compare each `sources` row (`index`, `path`, `hashMode`,
|
|
1235
|
+
`format`, `sha256`) with the binding they read themselves, compare
|
|
1236
|
+
`discoverySha256` with the `candidate` capture and `policySha256` with the
|
|
1237
|
+
policy bytes they review, and repeat the call immediately before the first
|
|
1238
|
+
native change, because the verdict describes one moment.
|
|
1239
|
+
|
|
1240
|
+
An installer that then passes the stored full-file sources (rows with `format`
|
|
1241
|
+
`null`), roots and directory witnesses back to `skills hook install --agent
|
|
1242
|
+
claude --discovery-inputs <file>` gets the same retention: `hook install`
|
|
1243
|
+
retains each `retained-absent` source with the same rule and stores it
|
|
1244
|
+
unchanged, so a historical `bytes` witness keeps its meaning. Every other
|
|
1245
|
+
source is checked and, for a fresh review, typed as usual.
|
|
1246
|
+
|
|
1247
|
+
Claude writes `.orphaned_at` at the root of a plugin-cache version it plans to
|
|
1248
|
+
delete (`<...>/.claude/plugins/cache/<marketplace>/<plugin>/<version>/.orphaned_at`),
|
|
1249
|
+
rewrites its timestamp at each start, may replace the file, and later deletes
|
|
1250
|
+
the marker or the whole version. A fresh Skills discovery review binds such a
|
|
1251
|
+
marker as `claude-plugin-orphaned-at-v1`, a witness of its presence only, and
|
|
1252
|
+
`discovery-binding` reports it with that witness's own check, exactly as the
|
|
1253
|
+
hook does:
|
|
1254
|
+
|
|
1255
|
+
- A rewritten timestamp or a replaced file (new inode) is `current`, provided
|
|
1256
|
+
the marker is a regular, non-symlink file owned by the current user whose
|
|
1257
|
+
content is exactly 13 ASCII digits without a leading zero (no byte-order
|
|
1258
|
+
mark, no newline).
|
|
1259
|
+
- Any other content, a symlink or another owner is `drift` with
|
|
1260
|
+
`MARKER_INVALID`.
|
|
1261
|
+
- A deleted marker whose version directory still exists is `drift` with
|
|
1262
|
+
`MISSING`; the hook refuses this state too.
|
|
1263
|
+
- When Claude deletes the whole version directory and the registered sibling
|
|
1264
|
+
version stays bound and current, the marker and every other retainable
|
|
1265
|
+
witness below that directory are `retained-absent` under
|
|
1266
|
+
`absent-retired-claude-version`.
|
|
1267
|
+
- A recreated version directory is no longer absent, so each of its witnesses
|
|
1268
|
+
is checked again: a valid marker and an unchanged manifest are `current`,
|
|
1269
|
+
and a missing marker is `drift` with `MISSING`.
|
|
1270
|
+
- Marker witnesses stored by an older review as `bytes` or `path-bytes` keep
|
|
1271
|
+
their exact meaning and report `CHANGED` once Claude rewrites the marker,
|
|
1272
|
+
until a fresh discovery review rebinds them as typed witnesses.
|
|
1273
|
+
|
|
1274
|
+
Installers must not restore, copy back or rewrite `.orphaned_at` files, or any
|
|
1275
|
+
other witness file, to make a binding verify. A restored file has a new inode,
|
|
1276
|
+
which a `path-bytes` witness rejects, and it can hide a change Claude made. Act
|
|
1277
|
+
on the `discovery-binding` result instead. When it reports drift, the binding
|
|
1278
|
+
needs a fresh Skills discovery review (`skills hook install` with fresh
|
|
1279
|
+
`--discovery-inputs`), not a file repair.
|
|
1280
|
+
|
|
1281
|
+
Refusal codes for this operation, besides the shared request and producer
|
|
1282
|
+
codes (`INVALID_REQUEST_FILE`, `INVALID_REQUEST_JSON`, `INVALID_REQUEST`,
|
|
1283
|
+
`INVALID_SCHEMA`, `INVALID_REQUEST_FIELDS`, `INVALID_PATH`,
|
|
1284
|
+
`PRODUCER_UNVERIFIED`, `PRODUCER_CHANGED` and `CAPTURE_REJECTED`):
|
|
1285
|
+
|
|
1286
|
+
- `POLICY_PATH_MISMATCH`: `policyPath` is not the package-owned policy path.
|
|
1287
|
+
- `POLICY_UNAVAILABLE`: the policy file is absent.
|
|
1288
|
+
- `POLICY_UNREADABLE`: the policy is not a regular, bounded, valid managed
|
|
1289
|
+
policy file.
|
|
1290
|
+
- `BINDING_UNAVAILABLE`: the policy stores no Claude discovery binding.
|
|
1291
|
+
- `BINDING_INVALID`: the stored binding is not a Claude binding with a
|
|
1292
|
+
`reviewed` or `automatic` method, or its sources, directories or root
|
|
1293
|
+
aliases do not match the binding schema.
|
|
1294
|
+
- `POLICY_CHANGED`: the policy changed while it was being verified.
|
|
1295
|
+
- `DISCOVERY_BINDING_REJECTED`: any other failure.
|
|
1296
|
+
|
|
1297
|
+
The operation is read-only. It reads the policy and the stored witness paths
|
|
1298
|
+
and directories. It writes no file, cache, selection pin or policy, and it does
|
|
1299
|
+
not start Claude or change native state.
|
|
1300
|
+
|
|
1012
1301
|
## Profiles, station sync and rollback
|
|
1013
1302
|
|
|
1014
1303
|
```bash
|
|
@@ -1034,6 +1323,50 @@ for the named station; it is not a native-folder snapshot in this mode.
|
|
|
1034
1323
|
`skills install --selection-profile default` without skill names also syncs the
|
|
1035
1324
|
whole selection.
|
|
1036
1325
|
|
|
1326
|
+
### Reading provenance instead of trusting one record
|
|
1327
|
+
|
|
1328
|
+
Applying a record is not adoption, and the four facts below are different. Only
|
|
1329
|
+
`skills provenance` reports them together, read-only:
|
|
1330
|
+
|
|
1331
|
+
- `selected` — the shared profile the authority serves right now;
|
|
1332
|
+
- `activated` — the snapshot this machine last verified and activated, which is
|
|
1333
|
+
what its hooks, `skills context` and `skills load` resolve from;
|
|
1334
|
+
- `applied` — the station receipt the authority holds. Only an explicit
|
|
1335
|
+
`skills sync` writes it; the managed hook keeps station reporting off its
|
|
1336
|
+
blocking lifecycle path on purpose, so this record legitimately lags the
|
|
1337
|
+
activation and is not by itself evidence that a machine is adrift;
|
|
1338
|
+
- `pinned` — the exact immutable profile revision one live session holds. A
|
|
1339
|
+
session keeps its revision when the profile moves on, so an older pin is
|
|
1340
|
+
custody by design, not drift;
|
|
1341
|
+
- `consumed` — the skills that session actually loaded, at their exact versions.
|
|
1342
|
+
|
|
1343
|
+
```bash
|
|
1344
|
+
skills provenance --json
|
|
1345
|
+
skills provenance --session <session-id> --json
|
|
1346
|
+
skills provenance --station station-example --json
|
|
1347
|
+
```
|
|
1348
|
+
|
|
1349
|
+
Every consumer is classified `current`, `behind`, `pinned` or `unverified`, and
|
|
1350
|
+
always carries a stable `reasonCode` and its reason. Identity is part of the
|
|
1351
|
+
comparison: a revision that matches under a different authority, workspace or
|
|
1352
|
+
profile is `IDENTITY_MISMATCH`, not `current`, so a foreign pin is never
|
|
1353
|
+
reported as adopted and is never diffed. Each receipt source declares the
|
|
1354
|
+
identity fields it must record, so a receipt that omits one — or carries `null` or
|
|
1355
|
+
an empty string where a nonempty string is required, which the HTTP reader also
|
|
1356
|
+
passes through — is `INCOMPLETE_RECEIPT`, not `current` and not `behind`: an
|
|
1357
|
+
absent revision is not an older revision. The local activation is named as this
|
|
1358
|
+
machine and the authority receipt as the station named on the command line; the
|
|
1359
|
+
two are never collapsed into one id. The receipt also states what it does not
|
|
1360
|
+
attest — published version and digest evidence, native discovery and locks, and
|
|
1361
|
+
live consumer adoption — rather than letting a clean-looking result imply them.
|
|
1362
|
+
`drift` lists the bundles whose exact versions differ. The command reads and
|
|
1363
|
+
never writes a pin, receipt, cache entry or station record, and it renders no
|
|
1364
|
+
skill payload and no credential: a reader's exception text is never carried,
|
|
1365
|
+
only a fixed diagnostic code, because bounding foreign text is not redacting it.
|
|
1366
|
+
With `--cached`, or when the authority cannot be read, the reference is the
|
|
1367
|
+
locally synced snapshot and every consumer is reported `unverified` rather than
|
|
1368
|
+
`current` — a local snapshot cannot establish adoption.
|
|
1369
|
+
|
|
1037
1370
|
After hook installation has enabled CLI loading, pull operations obey the same
|
|
1038
1371
|
profile. `--all` refreshes its selected versions rather than the full catalog,
|
|
1039
1372
|
and a named pull must belong to that profile:
|
|
@@ -1438,6 +1771,7 @@ of app folders, and `XDG_CONFIG_HOME` is not consulted at all.
|
|
|
1438
1771
|
| `skills context <prompt> --selection-profile <id>` | | Resolve instructions matching the prompt and profile triggers |
|
|
1439
1772
|
| `skills hook install --selection-profile <id>` | | Plan bridges and hooks for configured/detected consumers; `--agent <agent>` selects one, explicit `--agent all` requires every adapter; `--apply` installs them, then restart and trust the hooks |
|
|
1440
1773
|
| `skills sessions show <id> --json` | | Inspect one session's exact profile revision and receipt hash without loading payloads |
|
|
1774
|
+
| `skills provenance [--session <id>] [--station <id>] --json` | `--cached` | Read-only receipt of the selected, activated, applied, pinned and actually loaded skill versions, each with its status and reason; writes nothing |
|
|
1441
1775
|
| `skills sessions reconcile <id> --from-profile <id> --from-revision <rev> --receipt-sha256 <sha> --selection-profile <id> --profile-revision <rev>` | | Plan an explicit migration of one live session; `--apply --plan-digest <digest> --plan-issued-at <time> --plan-expires-at <time>` (within five minutes) preserves its old receipt and applies the reviewed replacement |
|
|
1442
1776
|
| `skills hook agents --json` | | Report maintained adapters and explicit coverage limits |
|
|
1443
1777
|
| `skills migrate native` | | Inventory native copies; `--apply` archives managed copies, with explicit `--include-unmanaged`, `--include-vendor`, or reviewed `--target-manifest` selection |
|
|
@@ -2850,6 +3184,17 @@ Review the plan before adding `--apply`; the original review preimage must match
|
|
|
2850
3184
|
its original mode, and unrelated changes refuse. This preserves the native
|
|
2851
3185
|
configuration, root aliases, other witnesses and active session pins.
|
|
2852
3186
|
|
|
3187
|
+
Verifying a typed Codex settings witness from `codex-settings-v1` to
|
|
3188
|
+
`codex-settings-v5` also accepts the one write Codex 0.162.1 makes on its own
|
|
3189
|
+
first TUI or desktop launch: the boolean `tui.screen_reader_detection_done`
|
|
3190
|
+
receipt, added, removed or flipped (V6 already omits it). No digest changes
|
|
3191
|
+
meaning, and verification alone records or rebinds nothing. A non-boolean receipt, any other TUI key
|
|
3192
|
+
(including the `animations = false` Codex adds when it detects a screen
|
|
3193
|
+
reader) and every other change still drift, including Codex's
|
|
3194
|
+
`[projects."<dir>"]` trust entries. A planned Skills write to `config.toml`
|
|
3195
|
+
rebinds the witness to the written document, which adopts at most that
|
|
3196
|
+
receipt.
|
|
3197
|
+
|
|
2853
3198
|
`claude-settings-v4` is an explicit successor to `claude-settings-v3`. It
|
|
2854
3199
|
additionally ignores only a top-level `theme` whose value is exactly one of the
|
|
2855
3200
|
documented built-in values (`auto`, `dark`, `light`, `dark-daltonized`,
|