Skills
The full skill protocol: agentskills.io-aligned SKILL.md, Neuralis frontmatter extensions, activation, and scripts.
A skill is a directory with a SKILL.md file — YAML frontmatter plus a
markdown body — and optional scripts/, references/, and assets/ siblings.
The format is aligned with agentskills.io, and the
frontmatter parser is whitelist-policy: unknown fields are dropped
silently, which is what lets skills written for other agent platforms load in
Neuralis unchanged.
skills/
deploy-checklist/
SKILL.md
scripts/
verify.sh
references/
runbook.mdThe skill's scope is the whole directory, enumerated at discovery into the
contribution's files[] list (see the
directory contract). A bare skill
folder — SKILL.md plus scripts/, no package.json — also loads as a
single-skill package whose root is the skill.
Frontmatter
---
name: deploy-checklist
description: One-line trigger sentence the model matches on to activate this skill.
disable-model-invocation: true
allowed-tools: [fs_list, fs_read]
credentials: [OPENAI_API_KEY]
maxSteps: 12
requiredFeatures: [platform.config]
---
# Title
Body. Use ${SKILL_DIR} / ${SKILL_URI} / ${SESSION_ID} / ${NEURALIS_API}.
Run scripts as `bash ${SKILL_DIR}/scripts/verify.sh`.Standard fields:
| Field | Meaning |
|---|---|
name | Skill id (falls back to the folder name). |
description | The always-visible routing contract advertised in the per-agent package overview: state the outcome, natural request/failure trigger, and decisive distinction from neighboring skills. The detailed procedure stays in the activated body. |
allowed-tools | Tool allowlist — a YAML list (- name lines may sit at the key's own indent), or one line of names separated by commas or spaces (the Claude Code and the agentskills.io forms both read); a trailing # comment is never read as a name. A CEILING on agents/*.md delegate personas; advisory on a skill. On a persona a delegate call's own tools is intersected with this list and can only narrow it. On a skill it is recorded and displayed, but activating a skill does not restrict the parent run's tool set — which matches the ecosystem, where the key is an approval easement rather than a restriction. Use it to state intent; do not rely on it as a control. On a persona, leaving the field out is what means "inherit everything the caller can reach", and an explicitly empty list (allowed-tools: []) means the opposite: the child gets no tools at all. |
disable-model-invocation | Marks the file manual-invocation-only. On a SKILL.md this gates nothing — it is recorded and displayed in the package overview and the files catalog, but the model can still activate the skill, and the skill is still listed. It is load-bearing only on instruction / rule files and on any file that opts into the prompt with activation.pinned or activation.target: "prompt-context", where a manual file is excluded from injection. |
arguments | Declared activation arguments: a list of { name, description?, required? }. |
context | inline (default — the body is returned into the conversation) or fork. Load-bearing: a fork skill also registers as an agent contribution and becomes summonable as a delegate persona. |
model, agent, argument-hint, compatibility, license, user-invocable | Recognized and carried as metadata for cross-platform compatibility. |
Neuralis extensions — all optional and additive:
| Field | Meaning |
|---|---|
credentials | List of credential-store ids. Each id doubles as the env-var name projected into skill-script child processes. The model never sees resolved values. |
hooks | Reserved for skill-scoped lifecycle hooks. The skill frontmatter parser does not accept the key yet, so declaring it changes nothing today. |
requiredFeatures | Visibility gate — see below. This is the only frontmatter key that actually withholds a skill from a caller. |
Accepted but inert. contextMode, agentType, preferredModel, maxSteps
and manualOnly are parsed without complaint and carried as metadata, but no
runtime reads them — writing one changes nothing. In particular contextMode
does not fork a skill; context: fork is the key that does, and it is in
the table above. Reach for requiredFeatures when you need a real gate, and set
step ceilings on the agent rather than in a skill's frontmatter.
Three authoring rules matter:
requiredFeaturesmust be a flat flow array —requiredFeatures: [platform.config]. A nestedrequires:block with afeatures:child is not parsed by the discovery frontmatter parser; it warns and ignores the declaration.- A skill that declares
context: forkregisters as an agent contribution (a delegate persona) instead of a skill — see Contributions. - An explicit
activation:block overrides everything else. Discovery readsactivation.target,activation.pinned, andactivation.invocationwhen the block is present, and skips thedisable-model-invocationinference entirely.activation.pinned: trueoractivation.target: "prompt-context"pins the whole skill body into every turn's system prompt — the symptom is a context window that grows by the size of the skill for every conversation, whether or not the skill is ever used. Leave the block off unless you mean it;activation.targethas exactly two values,prompt-contextandworkspace.
Activation flow
A skill activates through the platform's execution tool
(execute action="skill"), looked up by id, title, or frontmatter name. The
activation does five things in order:
- Argument injection. Declared
argumentsvalues are substituted into the body. - Credential resolution. Each
credentials:id is resolved against the encrypted credential store with the caller's real scope (agent → project → user → platform, most-specific wins). Missing credentials are non-fatal: the body renders a(missing: <id>)sentinel and the id is reported in the structured result. - Session ticket mint. Every activation mints a per-stream session ticket
(
NEURALIS_SESSION_TOKEN, an opaquenrs1.<requestId>.<secret>) carrying the caller's real identity. Skill scripts use it to authenticate host API calls — there is no long-lived token and no synthetic skill identity, and a synthetic session cannot activate skills at all. See Sessions. - Placeholder substitution. The body is rendered with
${SKILL_DIR}(container path of the skill directory),${SKILL_URI},${SKILL_CONNECTOR},${SKILL_NAME},${SESSION_ID},${NEURALIS_API}(the host API base), and${SKILL_CREDENTIALS_RESOLVED}/${SKILL_CREDENTIALS_MISSING}. A placeholder whose coordinate is unavailable becomes a human-readable sentinel so the model picks another path.${MISSING:<id>}renders per-credential presence. - Credential layer push. Resolved secrets and the env-projectable
substitutions are pushed onto the stream's active-skill stack for subsequent
shell calls. The layer pops on explicit deactivation
(
args.deactivate: true) or at stream end; re-activation replaces the layer idempotently.
The activation envelope returned to the model carries a
[Skill directory: …] line so imported skills' relative
bash scripts/foo.sh forms work — the model passes cwd: "${SKILL_DIR}" on
the shell call and the placeholder expands server-side. With several skills
active at once, a shell call can pass skill: "<id>" to select which active
skill's directory (and ${SKILL_*} substitutions) bind for that call — the
default stays the most recently activated skill.
How scripts run
There is no separate script runner: skill scripts run through the platform's
sandboxed shell, from the model's perspective simply
bash ${SKILL_DIR}/scripts/verify.sh. Each shell call gets:
- a freshly re-minted session ticket, so multi-turn skill scripts keep a live authenticated identity,
- of the platform's own secrets, only the ones an active skill declared in
credentials:(the projection is conversation-scoped: a command receives the union of every skill still active, not just the most recent one — see credentials) — the shell env sanitizer deny-lists secret-shaped names (theSECRET/TOKEN/PASSWORD/CREDENTIAL/API_KEYname families, and more), known provider prefixes (OPENAI_*,AWS_*,GITHUB_*, …), and an exact list of infrastructure keys, passing through only the declared allowlist. It is a deny-list over the host environment, not a whitelist: a host variable whose name matches no pattern still reaches the script, so secrets belong in the credential store rather than in ambient env vars (see credentials), - URI-policy enforcement on the working directory and path arguments, with the active skill directory readable for the duration of the activation (see URI policies).
A package may advertise its script posture with the manifest's
runtime.skillScripts key (host | wasm-only | none). It is a
declaration, checked at manifest load — an untrusted package that declares
anything but none fails validation (omitting the key is also fine) — and it is
rendered as a tag in the agent's package overview. It does not itself refuse a
spawn: what actually stops a script is the shell's URI-policy gate and the
sandbox. See Manifest.
${SKILL_DIR} resolves to a sentinel string only when the skill has no
host-side directory at all — a skill contributed by a synced source whose
connector exposes no container path. An installed package and a project
_packages/ drop both resolve a real directory, so bash ${SKILL_DIR}/scripts/…
works for both.
Visibility follows the caller
Skills inherit both their package's enable/disable state and the caller's
role/feature grants, deny-by-default. A skill gated by requiredFeatures that
the caller does not hold is hidden entirely — not injected, not listed in the
package overview, not present in the files catalog — and an activation attempt
returns the same not-found result as a skill that never existed. Annotate a
skill with the strongest route feature its scripts call; leave it off for
public skills, since execution stays independently gated by route features,
shell URI policy, and credentials regardless.
Building your own first-party package
Develop a Neuralis package in its own repository: administrator-assigned first-party trust, sandboxed alternatives, build requirements and kernel peers.
Source packages
How synced filesystem sources contribute markdown packages — recognized layouts, defaults, per-file control, and the security model.