Managing skills
Skills are GitHub-hosted SKILL.md files — a YAML front-matter block
with a name and description plus a markdown body — that nr-llm can
ingest, review, and (from Plan 1b) inject into prompts. You add a skill
source that points at GitHub, sync it, and then enable the individual
skills you want.
Skill management is admin-only. It lives in Admin Tools > LLM > Skills and is not delegated to other backend groups: a skill body becomes prompt context, so the two skill tables are treated as a privilege-escalation surface.
Note
Ingest — adding sources, syncing and reviewing — is described by ADR-035. Attaching enabled skills to tasks and configurations and injecting them into text-generation prompts is described by ADR-036 and the Attaching skills section below.
Source types
A source has one of three types:
single_file- One
SKILL.mdat a fixed path in a repository. A single, explicit admin act — its skill may default to enabled. repo- A whole repository. Every
SKILL.mdunder the repo root,skills/<name>/,.claude/skills/<name>/or<plugin>/skills/<name>/is discovered. Discovered skills arrive disabled for review. marketplace- An Anthropic
marketplace.jsonindex that lists plugins pointing at further repositories. Each entry is expanded with therepoflow. All discovered skills arrive disabled.
Adding a source
- Navigate to Admin Tools > LLM > Skills.
- Click New Skill Source.
-
Fill in the fields:
- Title
- Display name for the source list.
- Type
single_file,repoormarketplace(see above).- URL
- The GitHub URL the type expects (the
SKILL.mdURL, the repository URL, or themarketplace.jsonURL). - Ref
- A branch or tag (for example
mainorv1.2.0). It is resolved once to an immutable commit SHA at sync time; all bodies are then fetched by that SHA, never by the moving branch.
- Click Save.
The pinned_sha, sync_status, sync_error and last_synced
fields are managed by the sync run and shown read-only.
GitHub token and rate limits
Unauthenticated GitHub API access is limited to 60 requests per hour,
which is quickly exhausted by a repo or marketplace sync. Add a
personal access token (a read-only, public-repo token is enough) to raise
the limit and to read private repositories.
- The token is set through the Set token action on a source, not typed into a FormEngine field. It is stored as an nr-vault UUID (envelope-encrypted), mirroring provider API-key storage — never as plaintext in TCA, YAML or the database.
- When a sync hits the rate limit (HTTP 403 with no remaining quota), the
source is set to
sync_status = errorcarrying the reset time; state is not partially corrupted. Add a token and re-sync.
Host-allowlist prerequisite
nr-llm enforces an app-level GitHub allowlist on every skill request:
the scheme must be https and the host must be one of github.com,
raw.githubusercontent.com, api.github.com or
codeload.github.com. This is separate from, and in
addition to, the nr-vault SSRF guard.
On hardened instances that restrict outbound HTTP through the global
HTTP/allowed_hosts SSRF setting, those four GitHub hosts must be on
that list, otherwise every sync fails closed. This is a deliberate
prerequisite — nr-llm never silently bypasses the SSRF guard.
Syncing and the review flow
- On a source, click Sync. The source moves through
never_synced→syncing→ok/partial/error. Thesyncingstate also acts as a lock: a second concurrent sync on the same source is refused. partialmeans the per-sync file-count or wall-time bound was reached (large marketplaces); the skills fetched so far are stored.- Discovered skills from
repoandmarketplacesources are created disabled by default. Review each one, then toggle it on with Enable. - Re-sync never silently changes an enabled skill. If a re-sync
recomputes a different
body_checksumfor an enabled skill, nr-llm auto-disables it and surfaces a diff (Review changes) so you re-confirm before it is used again. Accepting the diff re-pins the SHA atomically. - A skill that disappeared upstream is marked orphaned and disabled, never silently dropped, so attachments (Plan 1b) do not vanish.
Deleting a source cascade-deletes its skills.
The partial support badge
Each skill carries a support badge:
full- The skill is plain front-matter and prose.
partial- The body or front-matter references scripts,
references/,assets/or anallowed-toolsdeclaration.
Warning
partial is not a "safer content" badge. It only signals that
the referenced scripts and assets are not executed by nr-llm
(which is true for every skill in this release). The prose itself is
fully untrusted regardless of the badge. Asset references are stripped
from injected prose in a later release purely to avoid dangling
instructions, not as a security control.
See ADR-035 for the full design and security rationale.
Attaching skills and injecting them into prompts
Enabled, non-orphaned skills can be attached to a Task and/or an
LLM configuration via the Skills field on those records
(only enabled skills are offered). At execution time, for text-generation
operations only — completion, translation and task execution; never
embeddings, vision or speech — nr-llm composes the attached skills into a
delimited block and prepends it to the user prompt. The configuration
system_prompt is never modified.
Composition rules:
- Precedence. Configuration skills are the baseline, task skills are additive; the set is the union deduped by source + identifier (the configuration wins on a duplicate). The configuration block renders first.
- Budget. The block is bounded by a conservative character budget; when it is exceeded, task-additive skills are dropped before configuration-baseline skills and each drop is logged.
- Integrity. Each skill's body checksum is re-verified at injection time; a mismatch (tampering or a stale row) drops that skill — it is never injected.
- Untrusted output. Skill prose is third-party text; output produced under its influence is treated as untrusted and escaped/sanitized where it is stored or rendered. Message role is defense-in-depth, not a trust boundary.
See ADR-036 for the injection design.