@hasna/skills
v0.10.83
Published
Skills library for AI coding agents
Maintainers
Readme
@hasna/skills
Skills library for AI coding agents — discover, pin, and run reusable capabilities through the Skills CLI and MCP server. Registers with Claude, Codewith, Codex, OpenCode and Cursor, and works with any MCP host.
Install The CLI
bun install -g @hasna/skillsRequires Bun 1.3+.
Private skill catalogs
The public package provides the CLI, API, SDK, hooks, and runtime. A skill's instructions and executable bundle belong to the organization that publishes them. API reads require authentication and use that organization's catalog, including tag filters, versions, and downloads. An empty account starts empty; neither a repository checkout nor files on the server machine supply defaults. Server startup and upgrades never import a bundled catalog.
Each operator can use their own compatible server and storage. S3 is optional: the server supports durable SQLite or PostgreSQL and database-backed bundles when no S3 bucket is configured. Publishing through an authenticated account does not publish to GitHub or npm. Keep private source documents and executable payloads outside public software repositories.
Quick Start
bun install -g @hasna/skills
skills loginskills login opens your browser to sign in to https://skills.md and stores an
API key for this machine in ~/.hasna/skills/config/credentials (owner-only),
together with the server it belongs to. On a terminal it then offers to register
Skills with your coding agents (skills setup agents). Check who you are with
skills whoami.
skills logout signs out the active profile. It deletes the key that
skills login stored, then revokes it on the server that issued it when login
minted it (a key you added with --api-key is only deleted, unless you pass
--revoke). It exits 0 only when you are signed out. It exits non-zero, naming
the reason, when revocation did not complete or is not supported (it then says
where to revoke the key by hand), when another credential is still active (an
environment variable, the Keychain or another selected profile, which it never
changes), when the profile holds a credential skills login did not store
(left in place), or when the local deletion failed.
- No browser on this machine:
skills login --deviceprints a code to approve on another device, thenskills login --pollfinishes the same sign-in. - An API key you already have:
printenv MY_SKILLS_KEY | skills login --api-keyreads it from stdin, verifies it and stores it. Nothing is echoed. - An email code instead of the browser:
skills login --email [email protected]. Interactive code input is masked. For an agent or headless terminal, first request a code withskills login --email [email protected] --json, then send the fresh code through stdin toskills login --email [email protected] --code-stdin --json. This finishes the same sign-in without requesting another code. Keep the code out of shell commands, arguments and logs. - Running
skillsin a terminal opens the interactive browser. It also works signed out and has the same account commands:/login,/logout,/whoami.
Your own server
The software is open source and every command works against your own compatible
Skills server. Sign in to it with
skills login --url https://skills.example.com; the URL is stored with the key,
so later commands use that server without flags. HASNA_SKILLS_API_URL selects
a server for one shell. skills setup --api-url <origin> records a server
without signing in.
Fleet stations
Stations provisioned with a fleet key keep using the internal gateway
https://api.hasna.com/skills; versioned requests use /skills/v1. A key with
no recorded URL (the Keychain item, HASNA_SKILLS_API_KEY alone, or an older
credentials file) always stays on that gateway and is never sent anywhere else.
The gateway has no interactive login service, so on such a station
skills login says so and sends nothing. A stored gateway credential or vault
reference is preserved even with --url. Use a separate credential profile for
customer sign-in: skills --profile skillsmd login. Later product commands use that
profile too, for example skills --profile skillsmd whoami --json; fleet
commands keep their original configuration.
Obtain a workspace API key through your administrator's provisioning process
and configure it using the credential resolution below. Check
the selected identity and available capabilities before syncing:
skills whoami --json
skills capabilities --jsonA workspace administrator creates a shared profile selecting published skills by
exact version and SHA-256 digest. Consumers sync that profile into a verified
Skills cache, then load instructions through the CLI. Replace default with
your assigned profile; these examples assume it selects [email protected]:
skills list --json
skills profiles show default --json
skills sync --selection-profile default --json
skills install [email protected] --selection-profile default --json
skills load [email protected] --selection-profile default
skills context 'Use $pdf-generate to create a PDF' --selection-profile default --json
# Preview retirement, then archive ordinary copies and vendor discovery files.
skills migrate native --include-unmanaged --include-vendor --json
skills migrate native --include-unmanaged --include-vendor --apply --json
# Preview the available adapters, then install one bridge plus hooks per agent.
skills hook agents --json
skills hook install --selection-profile default --json
skills hook install --selection-profile default --apply --json--include-vendor resolves configured plugin discovery, so it needs a reviewed
--discovery-inputs file when a configured plugin declares hooks. Without it,
skills migrate native --include-unmanaged archives user and project copies
only. Migration never archives Codex system skills (.codex/skills/.system),
even with --include-vendor. Codex refreshes its OpenAI marketplace plugin
caches on its own; retire those copies with a Codex [[skills.config]] rule
(name = "<plugin>:<skill>" or the exact path of the SKILL.md, with
enabled = false) rather than by archiving. The live Codex prompt hook accepts
a name rule only for a copy with no Hasna marker, its remote install receipt, a
refresh-safe plugin and no rule that enables it. Other checks (skills hook
install reusing a saved review, skills hook trust) do not accept a
hand-added name rule; for them, and for system skills, run skills hook install
--agent codex --discovery-inputs <file> --apply with a fresh discovery review
(no --discovery-inputs on an automatic binding; add a fresh
--codex-native-catalog <file> for a plugin Skills has enrolled), which writes
and records the disables. Run the same refresh after editing config.toml when
the binding's recorded configuration witness counts the edit: on automatic
bindings, after removing a rule that enables skills, and on reviewed bindings
whose witness counts disable rows. A NATIVE_SKILL_DRIFT refusal names the
step for each copy it lists, including that follow-up.
Without --agent, hook installation selects configured or detected consumers:
existing managed bridge bindings, provider-specific home configuration, or an
installed native CLI found through PATH. Detection reads metadata and never
executes a native CLI. A provider-specific directory also identifies a GUI
consumer without a CLI, such as Cursor. Shared .agents/skills or Claude
configuration alone does not identify another provider. No detected consumers
is an error; use --agent <agent> to configure a new consumer explicitly.
Every selected adapter still validates its configuration and prerequisites;
errors never silently drop a detected consumer. Explicit --agent all selects
all maintained adapters and requires every adapter's discovery capability,
including Sumi's installed read-only sumi-paths command. Sumi is selected by
its managed binding, native sumi or sumi-paths executable, existing legacy
provider home or ~/.config/sumi configuration, a Sumi directory beneath
XDG_CONFIG_HOME, or any set SUMI_HOME, SUMI_CONFIG_DIR, SUMI_CONFIG or
SUMI_CONFIG_CONTENT selector (even empty or malformed). It then uses the
unchanged Sumi path protocol and fails closed on unsupported configuration or
a missing helper. Generic XDG configuration alone does not select Sumi; its
provider directory must be present. Relative XDG paths resolve against the
working directory, and home shorthand expands as in the native path protocol.
Dangling or inaccessible provider roots never silently drop Sumi. Provider-defined
roots outside these published presence locations cannot be detected without a
binding, selector or executable; specify --agent sumi for that case. This is
a detection limit, not proof that Sumi is absent.
Native migration includes the current directory, every ancestor, and the global
agent directories. Use --project /path/to/project to include another project
and its ancestors. This matches the prompt hook's project discovery, including
skills inherited from a parent workspace. Preview the JSON inventory before
applying it; archived copies retain recovery receipts. A drift refusal reports
the affected paths without printing their skill documents.
Claude hook installation sets syncClaudeAiSkills: false in user settings to
stop account skill synchronization
from recreating native copies. The prompt hook checks that setting. Vendor
migration also inventories ~/.claude/plugins/synced/ and archives its skill
documents while preserving other plugin files. Whole-plugin synchronization
remains unchanged because synced plugins can also provide hooks, MCP servers,
and language servers. A later plugin download that restores a skill document
will trigger another drift refusal and require review.
A patched Codex that enforces an exact native host-path allowlist reports its
effective policy to the Skills SessionStart and UserPromptSubmit hooks as
native_skill_policy. The guard's adapter parses that envelope strictly
(capability host-path-allowlist-v1, restricted mode, non-host sources disabled,
the sole allowed path equal to the Skills bridge document, a lowercase SHA-256
effectiveConfigDigest, the consumer's processId, session_id, and turn_id
on UserPromptSubmit only), re-verifies the bridge document on every hook, walks
the hook's real parent chain to find the claimed consumer, binds its start time
and the digest of its executable to the reviewed digests stored under
bridge.codexNativePolicy.executableDigests in the managed policy (an absent set
refuses; Linux has no reviewed digest by default, so the adapter refuses there
unless an operator pins one after its own review; only the file's identity to
digest mapping is cached, in agent-hooks/codex-native-policy-executable-cache.json).
The Skills data directory is the operator trust root: the managed policy and the
cache file must be regular files reached through no symlink, owned by the current
user or root and writable by neither group nor world, or the adapter fails closed;
a writer with the same uid is outside this boundary. The adapter then requires
the authenticated channel binding of the native hook-policy peer contract
(native-hook-policy-peer-v1): Codex passes
the read end of a per-hook socketpair in CODEX_NATIVE_SKILL_POLICY_FD; the hook
forwards it as fd 3 to the qualified ancestor's own executable, debug
verify-hook-policy --fd 3 --expected-process-id <pid> --input-sha256 <raw stdin
SHA-256>, which sends a fresh challenge, verifies the actual writer and prints
one native-hook-policy-peer-v1 attestation that must name that pid, that raw
stdin digest and exactly the emitted policy; it runs once per invocation and is
never cached. The managed trust default is empty, so no envelope is accepted
until an operator records reviewed executable digests; with none, the helper is
never run, and the hook's remaining deadline bounds both the first-use executable
hash and the helper. Operators bind those digests through the package, never by
editing the policy by hand:
skills hook trust-native --platform darwin-arm64 --digest <sha256> --expected-policy-sha256 <sha256> --json
skills hook trust-native --platform darwin-arm64 --digest <sha256> --expected-policy-sha256 <sha256> --apply --jsonPreview comes first and writes nothing. Each --digest must be the SHA-256 of an
independently verified final native artifact, taken from its own review, never
from a fetch; the command accepts digests only from its arguments. --apply
requires the exact current policy SHA-256, re-checks it immediately before the
atomic 0600 replace, preserves the pre-change bytes in the usual migration backup
and reads the backup and the result back before it reports; it sets exactly the
given set for that one platform and preserves every other field (values
identical; the file is re-serialized with the package formatter).
A pre-existing group- or world-writable data directory (for example 0775) refuses
both this command and the adapter until its mode is corrected. Inertness rests on that authenticated restricted policy;
plugin classification proves nothing by itself and only narrows the scope to
installed-plugin documents under ~/.codex/plugins/cache that the verified policy
cannot load. Those are checked before any hash or helper run, and the acceptance
is recorded at agent-hooks/codex-native-policy-acceptance.json; user,
repository and project copies still refuse, and format or digest checks never
prove the runtime policy on their own.
A Codex plugin refresh can deposit a new vendor skill in ~/.codex/plugins/cache
(for example openai-curated-remote/sites/1.0.2-remix-b.1/skills/sites-remix).
Skill payloads still reach agents only through the Skills CLI, so an enabled
vendor copy keeps blocking the Codex prompt hook. Retire it by disabling it in
~/.codex/config.toml. The plugin-qualified name survives later version
directories, so prefer it:
[[skills.config]]
name = "sites:sites-remix"
enabled = falseAn exact path = ".../sites/1.0.2-remix-b.1/skills/sites-remix/SKILL.md" rule
also works, but only for that version. On the live Codex prompt hook only, a
copy is then exempt when every condition holds:
- it is package-classified plugin content in
openai-bundled,openai-curatedoropenai-curated-remote(exact names), with Codex's remote install receipt for the remote marketplace; - it carries no Skills or Hasna marker;
- every cached version of its plugin passes the vendor refresh check described below for membership changes, so the plugin can load nothing that the inventory and this rule do not account for, and no version is a link;
- a
[[skills.config]]rule names its exact path or its plugin-qualified name withenabled = false, and no matching rule enables it.
A whole-plugin [plugins."sites@openai-curated-remote"] enabled = false table
is not enough on its own: remote state can enable a locally disabled remote
plugin, and a cache copy carries no proof that its plugin source is
configuration-controlled, so the copy keeps blocking until a path or name rule
retires it. This exemption only adds to the guard's existing ones; every copy
that the guard already accepts, such as an exact-path disable in any plugin-cache
marketplace or a reviewed plugin control, stays accepted on the live hook. Once
the hook tolerates one of the witness changes below, a state the strict guard
refuses outright, plugin-cache copies are exempt only through this vendor rule.
Instead of editing by hand, skills hook native-catalog followed by
skills hook install --agent codex --codex-native-catalog <file> --apply writes
the same rules through the guarded install path.
The hook also tolerates, with a visible systemMessage warning, only the
discovery-witness changes such a refresh provably makes:
- appended vendor disable rules or vendor plugin disables in
config.toml, accepted when removing exactly those entries or restoring a formerly enabled vendor flag reproduces the reviewed digest. Candidates are tried smallest edit first, at most 128; with a typed settings witness that covers any change to up to two of at most eight vendor plugin tables. A change beyond the bound refuses; - directory membership changes under an allowlisted vendor marketplace that
passes the vendor refresh check: every plugin version has exactly one
manifest,
.codex-plugin/plugin.json, alone in its directory, whose keys are onlyname,version,description,author,homepage,repository,license,keywords,interface,skills(the default./skills/only) andapps. So hooks in any form, commands, agents, extensions, MCP servers and unknown keys refuse. There is nohooks,commandsoragentsdirectory, nohooks.jsonor.mcp.json(names compared without regard to case), no root,.claude-pluginor.cursor-pluginmanifest, no link and noSKILL.mdbelow a dot-named ornode_modulesdirectory, or nested in another skill. One exception keeps today's vendor plugins working: every current OpenAI vendor plugin declares its connector asapps = "./.app.json", so exactly that declaration is allowed when.app.jsonis a regular file of at most 1 MiB, strict UTF-8, that passes the same connector validation reviewed plugin controls use (oneappsobject; app entries with onlyid,categoryandrequired, of the right types; no duplicate keys). Any other connector path, a file that fails that validation, or the file without the declaration refuses.
Every other copy and change still refuses with NATIVE_SKILL_DRIFT, including:
- user, project,
.systemand Hasna-marketplace copies that the guard does not already exempt; - an enabled vendor copy whose plugin is only disabled by a whole-plugin table;
- capability-control changes and whole-cache membership changes;
- plugin activation, including a vendor plugin gaining
enabled = true; - missing coverage and changed roots;
- every install, trust, migrate and sync check.
Native hook invocations must use their installed adapter's selection profile.
An old client command or environment override naming another profile refuses
before synchronization or context loading. Review the hook installation and
restart the native client to load its current commands. Explicit skills load,
skills context, and skills sync commands can still select other profiles.
Reinstalling hooks without --command or --selection-profile preserves each
agent's existing executable and profile independently, including when using
--agent all. New agents use skills and default. Either explicit flag
overrides that choice for the requested agents. The policy's shared default
profile changes only when --selection-profile is supplied; older managed
agents without a per-agent profile retain that shared default.
The hook install --include-vendor option is retained for compatibility with
older scripts. Hook planning always inventories and disables discovered vendor
system skills; use migrate native --include-vendor when retiring their
discovery files.
Restart the agent after applying the hooks. In Codex, review and grant normal
trust to the installed hook definitions before starting a new session. Then
request a selected skill in a prompt, for example Use $pdf-generate to create
a PDF. The hooks supply instructions; executing the skill remains a separate
explicit action.
For Codex 0.153.0, 0.154.0, and 0.155.0, the normal installed Skills CLI can plan native trust for its three exact managed hook definitions:
skills hook trust --agent codex --json
skills hook trust --agent codex --apply --plan-digest <reviewed-plan-digest> --jsonReview the commands, current hashes, and existing trust/enable state in the
plan. Apply refuses if the plan, package, declarations, or configuration changed.
The plan preserves the native CODEX_HOME choice. When unset, Codex uses
the lexical ~/.codex path; an explicit CODEX_HOME resolves canonically.
Only the home root and an explicitly admitted canonical root-alias target
are accepted. Those views have separate hook identities even when they reach
the same files; enrolling one preserves the other's trust entries. Keep the
same CODEX_HOME choice for enrollment and the consuming agent.
It enrolls the current exact definitions, including reviewed modified hooks,
and preserves unrelated trust, settings, and comments. A private journal keeps
the pre-write configuration; a failed write or verification requires journal
reconciliation before retry. Unsupported versions or configuration layouts
refuse without a configuration write. Enrollment uses a short-lived native
app-server and makes hooks eligible for new Codex processes. Existing sessions
retain their own configuration; use their native hook controls to refresh them.
When an explicit discovery review includes the full Codex configuration file,
the exact native trust writes change that file's byte hash. Enrollment verifies
those writes and completes its journal with bindingRefreshRequired: true.
This reports native trust eligibility only: ordinary managed context remains
blocked, and the discovery policy is unchanged. Review the current full file
again and plan skills hook install --agent codex --discovery-inputs <review>
--command <same-absolute-command> --json. Verify that the plan changes only the
discovery policy, then repeat with --apply. Keep the same command and native
home. The ordinary bridge must then pass, and a fresh skills hook trust
--agent codex --json must report zero planned changes and
bindingRefreshRequired: false. Verify context in a new native session after
these checks; an enrollment receipt does not prove context was consumed.
If an interrupted journal's policy later changed only in reviewed Claude
discovery roots/sources, skills hook trust reconcile --agent codex --journal
<path> --review-claude-discovery <evidence-reference> --json can preview that
specific recovery. Supply all five package provenance flags shown by
skills hook trust reconcile --help for the current running Skills release.
The old absolute hook command remains bound to its original package bytes;
recovery reads that package as evidence without executing it. Review the full
policy hashes, exact discovery additions/removals, journal, current package,
configuration and complete native inventory in the private preview. Repeat
the same command with --recovery-plan-digest <reviewed-digest> to record the
receipt. Any unreviewed change refuses. This mode preserves the policy and
native configuration and cannot be combined with --supersede-binding.
If another reviewed producer appended a user hook after the interrupted write,
add --review-native-hook-additions <private-review.json>. This is a separate
explicit review; a producer receipt alone never authorizes recovery. The review
must be an absolute, owner-only regular file with these exact fields:
version: 1,kind: "native-hook-additions", a nonemptyreason, and aproducerEvidencereference to the independently reviewed producer operation.journalIntentSha256,policySha256,configCurrentSha256, andhooksCurrentSha256pin the complete current inputs and immutable intent.producerBeforecontainsconfigPath,configSha256,hooksPath, andhooksSha256. These owner-only backup files must reproduce exactly the completed original trust write and the original hook declarations.additionscontains one or more{ event, nativeHook }records.eventisUserPromptSubmit,SessionStart, orSubagentStart.nativeHookcontains exactly the native inventory fieldskey,eventName,handlerType,command,matcher,timeoutSec,async,statusMessage,additionalContextLimit,sourcePath,source,pluginId,isManaged,currentHash,enabled, andtrustStatus.
Only appended single-command groups from the same user hook file are supported:
no matcher, asynchronous handler, custom status/context limit, plugin source,
duplicate command, replacement or reordering. The added hooks must already be
enabled and trusted in the actual native inventory. Every original hook and
unrelated configuration byte remains verified. Combine this flag with
--review-claude-discovery only when that independent policy transition is also
present. The package provenance flags, private preview, exact
--recovery-plan-digest, and subsequent explicit binding refresh are still
required. Reconciliation writes only its journal receipt.
When updating the Codex binding afterward, Skills replaces its single hook group in place so neighboring hooks retain their native indexes and trust identities. Ambiguous duplicate or mixed Skills groups refuse installation.
Each supported agent gets one small skills-cli native skill containing CLI
instructions, without a copied catalogue. Claude's native Skill tool admits
that bridge after other copies are retired. Prompt guards verify the owned
bridge bytes, required native configuration, and discovered home/project skill
paths before loading context. A missing or changed bridge, newly discovered
copy, stale plugin registration, or incomplete scan reports repair guidance and
refuses loading. Most adapters also block the prompt; Hermes has the native
non-blocking prompt-hook limitation described below. These are checks on configured native discovery, not
an operating-system restriction on arbitrary file reads.
Agent policies support up to 1 MiB of serialized UTF-8 JSON, with bounded agent and discovery collections (2,048 sources and 512 roots per agent). Installation validates the complete resulting policy before writing configuration or backups; the same limits apply when reading and guarding native context. A rejected plan leaves the previous policy intact.
Sumi uses its native V2 plugin API, independently of OpenCode. Its managed
plugins/skills-cli.js plugin validates prompt admission and adds selected
instructions to transient request context. Real native session IDs and parent
IDs bind exact inherited pins; native agent definitions are not Hasna identities.
Prompt matching uses the native prompt-admission event. Request context restores
verified loaded Skills and never treats model history, attachments or compaction
checkpoints as a new owner prompt. The complete native model context is unchanged;
the hook's input limits and native/integrity refusals remain strict. Adapter
refusals retain only fixed reason codes, never child diagnostic prose. Both older
managed plugin forms remain recognized for a reviewed hook-install upgrade.
Native payload tool calls and prompt attachments are refused except for the
skills-cli bridge. The supported configuration resolver honors SUMI_CONFIG_DIR,
XDG_CONFIG_HOME and SUMI_HOME without performing native home adoption.
Sumi integration refuses unresolved JSONC, inline/additional config, remote or relative skill sources, flat Markdown skills and foreign plugin packages. Resolve or review these sources before applying integration. The adapter was checked against Sumi 0.2.52. That release watches plugin sources for hot reload; installation alone does not prove an existing session adopted the plugin. Verify actual prompt consumption on each target after installation.
Hermes 0.20.5 uses pre_llm_call to add selected context and pre_tool_call
with fail_closed: true and a small owned supervisor to guard tool calls. The
supervisor maps Skills child failures, timeouts and missing/invalid directives
to the native explicit block response and exit code 2. Installation edits config.yaml
while preserving unrelated values/comments and creates the native
.no-bundled-skills opt-out marker to prevent bundled payloads from reappearing.
The supervisor stays in the Skills data directory and its bytes/command are
checked before native loading. Installation leaves the native shell-hook
allowlist unchanged: approve the two exact
managed event/command pairs through Hermes normal hook trust and restart.
The adapter refuses unreviewed installed plugin sources and custom Hermes
homes/profiles, user-specific tilde expansion, and TERMINAL_CWD overrides.
Nonempty HERMES_BUNDLED_PLUGINS and HERMES_BUNDLED_SKILLS overrides are
also refused during discovery and hook checks; unset them to use the reviewed
default source paths. Custom bundle locations need a dedicated discovery adapter.
Retire native payloads before use. Legacy skills-cli.md files can shadow the
bridge and must also be preserved and retired before proceeding. Only skill_view(name:
"skills-cli") is allowed natively; author payloads with Skills CLI commands.
Hermes itself fails open on pre_llm_call errors. A returned refusal is visible
context, and the trusted pre-tool guard blocks drift and native skill fallback;
this is not a claim that Hermes can prevent every model call after a failed
prompt hook or guarantee refusal if the native host/supervisor itself dies. Arbitrary project/plugin paths still require a discovery audit.
Reviewed discovery can also bind directories: [{ path, sha256 }] alongside
its full source-file hashes. The public SDK's captureDiscoveryDirectories(paths)
captures recursive, sorted path/type membership without reading plugin payloads.
Include every directory the reviewed loader scans, including plugin version
selection parents and Python entrypoint discovery directories. Membership hashes
detect added, removed or changed file types; keep source hashes for reviewed bytes.
Missing directories bind as sha256: null. Symlinks and special nodes refuse.
The bounds are 64 roots, 20,000 total entries, 8 MiB of path/type metadata and
64 levels of recursion. Capture and checks require stable directory identities;
quiesce source writers for installation because these checks are not atomic with
a later native import.
For full binary or source-byte coverage, use the public SDK's
captureDiscoveryByteSources(paths) and retain its explicit hashMode: "bytes"
on each source witness. It hashes the exact file bytes, including invalid UTF-8,
with limits of 64 MiB per file and 256 MiB across one capture or verification.
Missing files bind as sha256: null; symlinks, special files and changing file
identities refuse. Raw witnesses cannot use configuration field projections.
Existing witnesses without hashMode retain their original UTF-8 decoding
contract and 16 MiB file limit; they are not silently converted into byte hashes.
Directory membership and file bytes are separate witnesses. Neither substitutes
for reviewing the actual executable, import paths or loader behavior.
For reviewed Claude user settings, captureClaudeSettings(canonicalSettingsPath)
emits an opt-in claude-settings-v1 witness. It permits a fixed set of typed
terminal display preferences and recognized built-in model selections to change
while binding hooks, permissions, native skill protections, plugins,
marketplaces, environment and every unknown field. Provider mappings, custom
model values and instruction settings remain bound. Replace the settings source
in an explicitly reviewed discovery input, then use the normal skills hook install
--discovery-inputs <file> plan/apply flow; existing raw witnesses are never
automatically converted or refreshed. See settings witness scope and migration.
For an explicitly reviewed launcher or interpreter reached through symlinks,
use captureDiscoveryPathSources(paths) and retain hashMode: "path-bytes".
Its digest binds the canonical input, directory identities, each link's identity
and target, and the resolved regular file's identity and exact bytes. Relative
link targets resolve component by component, including .. after an alias.
Missing targets also receive a digest that binds the path leading to their
absence. Retargeting to identical bytes, replacing a link or an ancestor, or
changing a file's metadata requires a fresh review. Unrelated sibling writes
do not change directory identity witnesses.
Path witnesses share the 64 MiB file and 256 MiB aggregate byte limits. Each
path allows at most 40 links, 256 traversal steps and 64 KiB of metadata; one
capture or verification permits 8 MiB of path metadata. Special nodes, cycles,
oversized inputs and changes during capture refuse. Native hook checks repeat
the witness verification; this does not make a later native execution atomic
with external writers. Keep source writers quiescent during activation.
Use bytes mode for configuration that hook installation will replace: path
witnesses cannot predict the future identity of a planned write. Existing raw
byte and directory witnesses still refuse links. Older clients reject the new
mode; upgrade the CLI before installing a policy that uses it.
Hermes requires directory witnesses, including when upgrading an older policy.
For an automatic bridge with no runtime installed, rerun normal skills hook install
to review and apply the new bindings. Existing native trust is preserved.
Reviewed Hermes installations need fresh source and directory coverage in their
--discovery-inputs file. Other agents may add directory witnesses to their
reviewed bindings without changing existing source-only reviews.
Hook installation preserves unrelated configuration, hooks, and plugin assets.
For Codex it sets skills.bundled.enabled = false in user configuration, preserving
the skills-cli bridge and disabling discovered native skill paths. This prevents
supported Codex clients from installing or loading their bundled .system skills.
The setting and its discovery witness are enrolled in the same configuration
transaction; existing installations must rerun skills hook install. Missing or
re-enabled bundled protection fails skills hook check before context loads.
Ordinary [skills.bundled] and legacy [[skills.config]] tables are supported;
inline or dotted target definitions that require rewriting refuse before changes.
Convert those definitions to ordinary tables while preserving their values, then
rerun installation. The control has been verified with Codex 0.153.0, 0.153.4 and
0.154.0; this is not a claim that every older build supports it. Use a client that
supports skills.bundled.enabled; Skills does not infer support from version text
or silently substitute path-only protection. Existing exact system-skill trees can
remain only with their hash-bound disabled paths; migration preserves these package
files. A client that restores or changes packaged skills requires a fresh inventory
and disable plan. Native exports are
refused while managed CLI loading is active. Migration preserves ordinary skill
directories in private archives; --include-unmanaged includes user-authored
copies, and --include-vendor retires vendor SKILL.md discovery files while
preserving shared scripts and assets. Archive receipts and configuration backups
live under the Skills data directory.
After vendor documents are archived, inventory still scans their retained asset directories for newly introduced skills. Vendor container traversal allows 32 directory levels; the ordinary native-root limit remains unchanged. Each inventory is bounded to 20,000 discovery entries and 4 MiB of UTF-8 path metadata before directory entries are retained or sorted. Unsupported special files and unsafe directory links are refused.
Codex 0.162.1 loads SKILL.md files below node_modules inside its skill
roots, so Codex inventory and the prompt guard walk node_modules in
~/.codex/skills, ~/.agents/skills, each project's .codex/skills and
.agents/skills and configured plugin skill roots. In ~/.codex/plugins/cache
they walk it only where it can lie in a plugin skill root: below a version's
default skills directory or a manifest-declared skills path, or as a
marketplace, plugin or version directory named node_modules; an unreadable
manifest walks every node_modules in its version. Dot-named directories such
as node_modules/.pnpm, a plugin version's own dependencies and any
node_modules outside a skill root stay unscanned, because Codex does not load
them; other agents' roots keep skipping node_modules. Depth limits are
unchanged: Codex reads six directory levels below a root, and an ordinary root
records a skill four levels down and refuses anything deeper.
Native archives persist a version 2 recovery journal before moving payloads;
migrate native --json --apply returns its receiptPath. The journal records
every source, archive path, expected hash, and move status, then marks successful
completion. Interrupted operations can be inspected against that durable intent.
On failure, recovery restores verified archives only when the original path is
still absent. It preserves occupied paths or unverified archives, records that
they require recovery, and continues compensating other unchanged entries.
Keep native agents and other skill writers stopped throughout migration and
recovery: portable directory rename cannot atomically reserve an absent target.
Vendor file restoration uses an exclusive hard link to preserve concurrent files.
Do not retry an interrupted operation until its journal and both paths have been
reconciled; a failed final journal write may leave the earlier durable intent.
For a reviewed migration that must retire one exact native copy, pass
--target-manifest <file>. The JSON manifest uses schema
hasna.skills-native-migration-targets.v1 and binds each target to an agent,
an existing absolute projectRoot, a normalized project-relative path, and
the complete directory treeSha256. Exact-target mode refuses broad selector
flags, protected or vendor entries, missing or ambiguous paths, symlinks,
digest drift, and writes a manifest digest into the recovery journal. Every
inventory entry outside the manifest remains untouched.
skills hook agents --json reports the supported adapters and coverage limits.
Claude and Codex have lifecycle context hooks; Gemini uses BeforeAgent, and
OpenCode uses its awaited message plugin. Cursor receives selected context at
session start and gates later prompt submission; its prompt hook does not
inject context on the supported installed path. Other inventoried clients do
not automatically gain a working prompt adapter.
Gemini's BeforeAgent prompt can include the Skills policy emitted at session
start. The hook excludes that exact leading policy from skill selection, so it
does not displace the user's requested skill. Other hook context and user text
remain part of the selection input.
Gemini discovery also covers the installed @google/gemini-cli package and its
bundled builtin skills. skills hook install finds the package through the
gemini command on its PATH and records the resolved executable and its
realpath target in the managed policy (bridge.discoveryExecutables.gemini).
Later checks always verify that recorded path, and also look gemini up on the
caller's PATH, because what PATH resolves is what that process would run:
- If PATH resolves a
geminiwhose realpath differs from the recorded target, that runtime shadows the reviewed one, and the check refuses withNATIVE_SKILL_DRIFT, naming both targets. Another launcher for the same target is not a shadow. - If PATH resolves no
geminiat all (a narrower PATH such asenv -i PATH=/usr/bin:/binor a launchd unit), the recorded path is the only witness, so a Claude hook update or a Gemini hook still verifies the reviewed runtime. - A changed recorded target, package or builtin set refuses with
NATIVE_SKILL_DRIFT. - When the recorded executable no longer resolves, or a policy written before
this record cannot find
geminion the caller's PATH, and nothing else in the reviewed discovery changed, the refusal isDISCOVERY_ROOT_UNRESOLVED, naming the agent and the command. That is an environment gap rather than drift, and it still blocks. Any other change is stillNATIVE_SKILL_DRIFT.
An install treats a recorded executable that no longer resolves as no record.
Run skills hook install from the reviewing environment to record or refresh
the path. The SDK exports DISCOVERY_ROOT_UNRESOLVED and
isDiscoveryRootUnresolved for callers that classify refusals.
Known local plugin registrations are resolved automatically. Plugins with
instruction-injecting hooks, unresolved runtime registrations, unsupported
legacy command formats, and higher-precedence project discovery settings need
separate review; a cache-only scan does not establish complete coverage. The
advanced --discovery-inputs <file> option on hook installation and migration
accepts reviewed active roots and full source-file SHA-256 witnesses. Its
version-1 document has an agents array; each entry names agent, absolute
roots, sources (path and sha256, or null for an absent file), and
pluginHooks: "reviewed-no-skill-injection". Include the agent configuration
and every input establishing the active roots and plugin-hook behavior. A
changed witness requires a new review. This option does not add support for an
unknown native file format or make unreviewed plugin behavior safe. Managed
system configuration, process-specific overrides, and alternate agent home
directories are outside automatic coverage and require their own integration
review before declaring a station migrated.
The pluginHooks attestation is the reviewer's point-in-time statement; Skills
does not inspect hook behavior. When a Claude .claude-plugin/plugin.json is
listed as a plain byte witness (hashMode omitted or "bytes") with a
non-null sha256, Skills also requires plain byte witnesses for that plugin's
hooks/hooks.json (when present) and any string hooks target in the
manifest. A manifest listed as claude-plugin-manifest-v1 (the form Skills
writes into the stored policy) or as path-bytes triggers no such requirement.
A source that the absent-retired-claude-version rule retains (see
discovery-binding)
is stored exactly as listed: Skills does not project its manifest, require its
hook files or convert its marker, because the file no longer exists.
The version-root .orphaned_at timestamp that Claude rewrites at startup is
bound by presence only, as claude-plugin-orphaned-at-v1, and is still
strictly validated; see
the full scope.
For plugins outside receipt-backed admission (a claude-plugin-registry
witness, see the
discovery transition contract),
other plugin files such as hook modules, bin/ files and package.json are
bound only if the review lists them (a reviewed directories membership witness
detects only added or removed files, not content changes), and the review is not
checked against the roots registered in
~/.claude/plugins/installed_plugins.json. Later checks
re-hash the stored sources, and drift makes the Skills hooks refuse with
NATIVE_SKILL_DRIFT; this detects a change but does not stop plugin code from
running. A process running as the same user can rewrite the plugin files and
the managed policy, so the witness is a tripwire, not a security boundary. See
the full scope.
A stronger witness for plugins outside receipt-backed admission is planned and
not yet implemented.
Captured review catalogs are immutable evidence, while configuration and plugin
files remain live discovery inputs. To retain a captured Codex native catalog,
explicitly add reviewArtifacts to its Codex entry in --discovery-inputs:
"reviewArtifacts": [{
"kind": "codex-native-catalog",
"path": "/absolute/private/reviewed-catalog.json",
"sha256": "<exact original file SHA-256>"
}]The same path and digest must already be a full byte witness in sources.
The normal read-only install plan validates the catalog using its owning schema;
apply retains its exact bytes privately under the resolved Skills data directory
at agent-discovery/artifacts/<sha256>/catalog.json before changing the policy.
The stored witness includes the original path, byte digest and projected catalog
digest. Later hooks verify the retained bytes and permissions, so removal of the
original scratch copy cannot break discovery. Live native roots, configuration,
plugin files and trust still require their original witnesses; retention does
not refresh or exempt them. No artifact is inferred from a filename.
For an existing reviewed policy, plan one exact legacy witness migration:
skills hook retain-review-artifact --kind codex-native-catalog \
--source /absolute/private/reviewed-catalog.json \
--expected-policy-sha256 <current-policy-byte-sha256> \
--expected-source-sha256 <original-reviewed-byte-sha256> --jsonRun from the same reviewed project directory; add --apply to execute that
guarded transaction. It requires the original bytes to exist and all current
bridge, discovery and trust checks to pass. Missing originals need exact recovery
first; this command never captures a replacement catalog or rehashes a changed
source. Apply preserves and reads back the old policy, leaves the original source
and session pins intact, and records retention lineage in the transaction
receipt. Existing sources without an explicit declaration keep their live-path
semantics. Immutable files left by a compensated transaction are retained and
may be reused only after exact verification.
When hook install omits --discovery-inputs, it reuses an existing reviewed
binding only after rechecking its sources, directory membership, configuration
coverage, managed bridge and native trust. Unchanged reviews need no new input
file; drift still requires a fresh explicit review. Explicit discovery inputs
take precedence, including when their agents array omits a previously reviewed
agent. The default --agent all still includes every supported adapter.
That recheck has two halves, and only one of them gates reuse. BINDING CUSTODY — the same managed bridge, home, alias set, agent, command/profile binding and reviewed discovery — must hold before a saved review is reused, or the plan refuses and names a fresh explicit review. Bridge PROTECTION — the native plugin bytes, the permission and hook rules and the bundled-skill switches — is written by the same plan, so it is asserted in full after the writes instead of gating the repair that fixes it; a plan that does not repair it is refused before the receipt is written. Hermes native shell-hook trust is the exception: it is the user's own consent and no Skills write creates it, so it stays a pre-write condition. One implementation serves both halves, so they cannot drift apart.
Because that recheck includes the managed bridge, hook install cannot reuse a
saved review on a host whose bridge has since broken, and in that form it cannot
repair its own precondition. It refuses and names the reachable form,
skills hook install --agent <agent> --discovery-inputs <review> --apply, which
skips the retained-review precheck and rebuilds the bridge from the review in the
same transaction. A reviewed binding always carries a whole-file witness for the
agent configuration beside its projected fields, so unchanged projected fields do
not excuse a change outside them: a fresh explicit discovery review, not a
witness refresh, is the supported route.
For reviewed Claude plugins, skills integration plugin plan, admit and
resolve provide a command-source admission boundary before native discovery.
Original packages and migrated skill/command prompts remain in private versioned
Skills storage. Native projections retain ordinary components, and a typed
receipt permits only verified registry/cache transitions. See
plugin admission for the package, review and runtime
contracts; these commands do not change live agent registrations or settings.
The read-only skills hook review-claude-candidate check requires its reviewed
discovery inputs to bind the user settings, both project settings files and
both plugin registries. A project .claude/settings.json or
.claude/settings.local.json that the review omits is exempt only when no other
expected source shares its path and it is either absent, or present with exact
preimage bytes that parse strictly as one JSON object (strict UTF-8, no
byte-order mark, comments, trailing content or duplicate keys) and carry only
allowlisted settings: permissions with allow, deny, ask and
defaultMode, plus outputStyle, model, theme, effortLevel, verbose
and spinnerTipsEnabled. Any discovery key (enabledPlugins,
extraKnownMarketplaces, additionalMarketplaces, skillOverrides), env,
hooks, permissions.additionalDirectories or unknown key keeps the file
required. The allowlist is a reviewed list of settings, not a proof that Claude
cannot discover anything from the file. This admits the permissions-only
~/.claude/settings.local.json that Claude writes when it saves a permission
rule. Each exempt file is re-checked against its exact preimage until the
result; user settings and the registries are never exempt. See
prospective Claude candidate review.
If your home .claude or .codex directory intentionally links to another
directory within your home, add --allow-root-aliases to hook installation and
native migration. The plan records and rechecks the exact link and target;
links inside skill contents or configuration files remain refused.
On macOS, the OS-owned /var, /tmp and /etc aliases into /private are
accepted only while their exact targets and protected parent directories verify.
The protection check refuses extended ACLs and unavailable native ACL inspection.
Inventory reports canonical paths and deduplicates their alias spellings. This
does not permit other root-owned links or user-controlled ancestor links.
Cooperating installers can use the root package's
planClaudeStopHookUpdate({ expectedSettingsSha256, replacement }), then
applyAgentIntegration(plan), to write an explicitly authorized Claude settings
replacement changing only hooks.Stop, together with every existing discovery
witness for that file. Every other field and hook must retain the same value;
this includes discovery configuration and display/model preferences.
The caller must authorize its own exact change; this API does not grant approval
to change another owner's hooks. It checks the current native bridge, inventory,
policy, executable witnesses and root aliases, preserves each witness mode, and
verifies the consumer guard after applying. A concurrent edit or pre-existing
drift refuses renewal. Failed post-write checks compensate only unchanged writes,
retaining private backups. A null plan means no Skills policy exists; malformed
or untrusted policy throws instead. This local integration operation requires no
hosted credential, does not reload an existing agent, and cannot adopt a stale
policy after another installer has already changed settings.
Settings and policy are separate files: this is a guarded sequence with
compensation, not a cross-file atomic commit. A concurrent hook can fail closed
during installation. A successful update does not reload an existing session.
Legacy full-file settings witnesses remain strict until explicitly upgraded:
skills hook rebind-settings --agent codex \
--reviewed-preimage /private/preserved/config.toml \
--expected-policy-sha256 <current-policy-sha256> \
--expected-settings-sha256 <current-settings-sha256> --jsonFor Sumi, use --agent sumi and the exact preserved sumi.json. A fresh
review can capture skills hook witness --kind sumi-settings-v1 --path
<absolute-sumi.json> --json and include that witness in its discovery inputs.
The versioned witness permits JSON whitespace and changes to $schema,
username, experimental.statusline and experimental.compact_tools only.
All other fields, unknown controls, nested plugin options, permission-map order
and array order remain protected. Foreign plugin source witnesses and the
explicit hook review remain required. Missing preserved bytes require a fresh
review; the runtime never upgrades a stale review automatically.
The Sumi plugin emits a fixed SkillsHookRefusal error with the own data property
skillsHookRefusal: { version: 1, code: "SKILLS_HOOK_REFUSED" }. Its remediation
is fixed; child stderr and arbitrary hook reasons are never copied into the
error. A compatible Sumi adapter can present this refusal without turning it
into an untyped server error. Regenerate the managed plugin with the normal
guarded skills hook install --agent sumi flow after updating Skills.
The plan proves the preserved original matches every witness being replaced,
permits only the documented non-discovery differences, and labels the replacement
witness (the JSON receipt lists them under replacedWitnesses). --apply
preserves and reads back the original policy before writing, and never writes the
native configuration. Claude upgrades to claude-settings-v3, or to
claude-settings-v4 with --claude-witness-version 4; Codex uses
codex-settings-v2, which also replaces the narrower automatic
plugins/marketplaces/skills projection of the same file once the preserved
original is proved to explain it. That projection is order-sensitive, so it keeps
failing after Codex re-serializes the file it owns.
Existing codex-settings-v1 witnesses retain their original verifier. New reviews
use skills hook witness --kind codex-settings-v2 --path <config.toml> --json.
The guarded rebind accepts a raw or v1 witness only when the exact preserved
configuration proves its original digest and any automatic projection. Without
that preimage, capture a fresh native catalog and explicitly review all discovery
inputs before installing a v2 binding; runtime never adopts drift automatically.
The Codex v2 witness binds the whole configuration apart from native-owned state
that is not a discovery input: the hooks.state trust ledger Codex rewrites when
it trusts a hook, table order and other serialization-only differences, retired
[[skills.config]] entries that explicitly disable one skill, and model,
model_reasoning_effort and model_verbosity at the root or in [profiles.*].
Every hook declaration, provider mapping, plugin, skill source or enablement,
project-trust entry, environment setting and unknown field stays bound, and a
malformed inference selection refuses instead of being adopted. Runtime hooks
never silently upgrade a witness.
A supported Codex native skill and installed-plugin receipt can be captured through the
package-owned client into a new private file, then reviewed and passed to
hook install with --codex-native-catalog <file>:
skills hook native-catalog --cwd /absolute/project --output /private/catalog.json --json
skills hook install --agent codex --codex-native-catalog /private/catalog.json --jsonCodex 0.159.2, 0.160.0, 0.160.1 and 0.161.0 have measured qualified-name catalog support.
Native transport, capture and review use one capability registry of exact
releases. Unmeasured releases, including 0.160.2 and 0.161.1, refuse until the
native catalog/name-denial and hook-dispatch acceptance tests pass; an RPC
handshake alone does not establish those semantics. Admitting a release does not
admit its corpus: the transport still requires the existing native corpus
admission (see docs/codex-corpus-writers.md).
Upstream Codex builds that lack corpus-admission-inspect, such as 0.160.0 and
0.162.1, use an interim fallback instead: an exclusive Skills-owned lock at
<realpath(dirname(codex home))>/.hasna/skills/codex-corpus-locks/, outside the
Codex home and independent of data-root overrides, recorded as
nativeAdmission: "unavailable" with the probe record in every receipt. The
probe record identifies the selected executable file (for npm installs, the
launcher script), not the vendor binary it starts. Its guarantee is weaker.
Upstream Codex's own refresh writes are not coordinated with that lock, only
Skills writers exclude each other, and preimage checks refuse only the races they
detect. For a project-level .codex, or a symlinked ~/.codex, the lock lives
under the target's parent, such as <project>/.hasna/skills/codex-corpus-locks/;
ignore that folder there. Probes run with a fresh, Skills-created CODEX_HOME in
<Skills data root>/codex-probe-homes/, removed after each probe.
The fallback is retired in the first release after the Harnesses
enrollment/inspect route is live for that build line.
The capture refuses an existing output file, writes mode 0600, verifies the
exact bytes, and reports only version, directory, count, file path and SHA-256,
plus the admission record when the interim fallback applies.
Its safe catalog shape is {version,cwd,skills,plugins}; skills have
{name,path,enabled,pluginId} and plugins have
{id,name,installed,enabled,localVersion}. Older reviewed catalogs without
plugins remain valid for skills present in skills/list. The installer matches the native
qualified name against bounded frontmatter and the owning plugin manifest.
If Codex omits a skill from skills/list because its exact path is already
disabled, the installer derives that identity only when the exact installed
and enabled plugin row matches the cache marketplace, manifest name and
local version. It preserves path disables and adds exact qualified name disables.
For a newly named remote materialization omitted from the native list, use
--codex-skill-denials <file> together with a fresh native catalog and explicit
--discovery-inputs. The denial file is an array of exact
{name,path,sha256} document reviews. The discovery review must also bind the
current full plugin manifest and each declared app/MCP control file. This plans
only exact false path/name rules;
it requires the real installed remote identity and receipt, rejects conflicting
enables, and rechecks consulted files and configuration before application.
It never synthesizes a native catalog row or enables a capability.
A wholly absent remote skills-only parent with retained qualified-name denies
keeps its reviewed fingerprints. A returning parent must satisfy the same
identity and capability checks. App/MCP declarations and active hooks do not
receive this absence exception; the saved review must explicitly establish the
skills-only role. The planner can also retain an already body-free historical
remote version whose capabilities match the reviewed disabled identity. It
records bounded membership rows matching their original directory fingerprints.
Only exact reviewed inactive roots or wholly absent disabled skills-only parents
are projected out; surviving versions, receipts and unrelated members stay bound.
Direct user hook references, returning skill bodies and capability changes
still refuse. Older directory witnesses without this projection need a fresh
review; their historical hashes are never silently weakened.
Updating the binary preserves existing policy and does not enroll this proof.
Preview skills hook install with fresh --discovery-inputs and the genuine
--codex-native-catalog, then apply the same reviewed inputs with --apply.
Preserve the exact policy/configuration/hook preimages and compare them before
application. The apply invocation replans and checks its observed preconditions;
the preview is not an apply token. Keep typed V3 settings witnesses, existing
disables, command/profile choices and session pins unchanged.
A retired Claude cache version may likewise
remain absent only while unchanged native settings and registrations select a
different extant, witnessed user version. Individual missing files, current
registered roots, aliases and registration changes still refuse; historical
source hashes and typed settings witnesses remain intact.
An explicit Claude discovery review must cover every registered active cache
manifest, skill root and hook source. Installation refuses an incomplete review
that covers only an older cache, before retirement of that cache can break prompt
delivery. Hook behavior still requires the existing no-skill-injection review.
For a Codex 0.160.0, 0.160.1 or 0.161.0 remote refresh omitted by an existing qualified-name disable,
a fresh native catalog and discovery review can plan the new exact path disable
in the same transaction. The remote installation receipt, namespace and capability
controls must match; conflicting enable rules, unknown names and ambiguous
materializations refuse. Changed plugin capability controls require a fresh
native catalog even when a new discovery review is supplied.
Known skill identities remain disabled across versioned plugin cache relocation,
even when their disabled bodies change. Unknown names, conflicting enables,
changed plugin controls, native hooks and unsupported name syntax still refuse.
Only manifest version metadata may vary. Reviewed app declarations use the implicit
.app.json or explicit ./.app.json, with a bounded apps map containing connector
id, optional category, and optional boolean required. The entire canonical app
file and its presence stay bound; it preserves existing connector availability and
native capability hints. Changed or unknown app fields, custom references, native
hooks, commands and unsupported MCP controls refuse. Referenced own-root
./.mcp.json declarations may preserve local stdio servers with Codex's typed
tool, approval, timeout and environment metadata. Their complete fingerprints
and presence remain bound; review never executes commands or resolves environment
values. Name controls suppress Skills, not every plugin capability.
A Codex 0.160 catalog may also prove a nonremote plugin is installed but disabled.
With an exact current path deny and explicit witnessed plugin disable, its cache
can remain inert across versions; re-enable, ambiguous identity, conflicting
controls and unsafe paths refuse. This does not approve its hook declarations.
Remote-controlled, missing or unknown source identities do not qualify.
The catalog retains local source paths separately from installed cache identities. When a reviewed discovery witness binds a positively mapped installation input, runtime checks omit that input from plugin skill loading. Default home/project roots and installed caches are still checked, and migration inventory remains complete. Overlapping, linked, missing or contradictory mappings refuse. No prompt hook starts an app server to obtain this receipt: native startup can maintain caches. The explicit capture starts and closes only its own bounded native client; it does not reload an existing agent session. Neither a receipt nor a config write proves an existing session adopted new rules; use the actual native session's supported acceptance path separately.
At session start, the hook authenticates and refreshes the profile. Prompt hooks
select complete skill instructions from that verified cache using explicit
$skill references, profile keywords, paths and always-required selections.
A session retains its loaded selections; compaction restores loaded instructions,
and subagents inherit the parent's selection. Instructions that exceed the
context budget produce an explicit skills load command. A hook never executes
a skill. Cached use is explicit and expires after 24 hours. When a session
receipt expires, the hook authenticates the current profile. If every loaded
selection still has identical metadata and bundle digest, it archives the old
receipt and advances that session to the current profile under an exact receipt
precondition. Unloaded selections may be added or removed. If renewal is refused
because the same profile moved on (a loaded selection changed or disappeared, or
another pinned selection's policy, membership or lifecycle changed), the managed
hook applies the explicit reconciliation planner and applier below to the
authenticated current revision: it archives the old receipt, retains unchanged
loaded bundles, retires changed or removed ones and delivers context for the
prompt. The first hook context that succeeds and reaches the agent afterwards
names each retired loaded skill once and how to reload its replacement; earlier
instructions from those skills must not be relied on. Identity, integrity and receipt failures, an
unavailable authority and anything the planner refuses keep their refusal;
session write-lock contention keeps SESSION_WRITE_BUSY. A
session created from a project lock (.skills/selection.lock.json) records
that lock in its receipt and is never migrated automatically, whatever
directory it
