Importing and reviewing skill sources
Source types
Imported sources have three types; local backend authoring is the fourth way to create a skill and does not require a source:
single_file - One
SKILL.at a fixed path in a repository. A single, explicit admin act — its skill may default to enabled.md repo- A whole repository. Every
SKILL.under the repo root,md skills/<name>/,.claude/orskills/<name>/ <plugin>/is discovered. Discovered skills arrive disabled for review.skills/<name>/ marketplace-
An Anthropic
marketplace.index that lists plugins pointing at further repositories. Each entry is expanded with thejson repoflow. All discovered skills arrive disabled.The parser accepts a
pluginsarray. A plugin source can be anowner/string, an object with a stringrepository repoof that form, or an object with a GitHuburl. A stringrepotakes precedence overurl. GitHub URL host matching is case-insensitive; the first two path segments identify the repository and a trailing.gitsuffix is removed. Unsupported entries are skipped while later supported entries are still processed. A plugin's stringrefis passed to its repository sync; an absent or non-stringrefusesHEAD. An empty string is normalized toHEADby that sync.
Adding a source
- Navigate to AI > Authoring > 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.URL, the repository URL, or themd marketplace.URL). For a marketplace, a plain repository URL usesjson .claude-atplugin/ marketplace. json HEAD; a raw or blob index URL specifies its own path and ref. - Ref
-
For
single_andfile repo, a branch, tag or commit (for examplemainorv1.); an empty value uses2. 0 HEAD. It is resolved once to an immutable commit SHA, and the skill bodies are fetched by that SHA.A
marketplacesource does not use this field. A raw or blob index URL is fetched at the URL's ref. A plain repository URL instead resolvesHEADand fetches the conventional index path by that commit. Each plugin repository is resolved separately from that plugin'sreforHEAD, and its skill bodies use the resulting commit.
- Click Save.
The pinned_, sync_, sync_ and last_
fields are managed by the sync run and shown read-only.
Sync errors shown by the module and stored on the source mask credential query parameters and URL userinfo passwords. Fatal-error diagnostics retain the exception class, source uid and sanitized message and source URL; they do not retain the raw exception object.
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. The source stores a vault reference; nr-vault stores the token with envelope encryption. The plaintext token is never stored in the source record.
- When a sync hits the rate limit (HTTP 403 with no remaining quota), the
source is set to
sync_carrying the reset time; state is not partially corrupted. Add a token and re-sync.status = error
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.,
raw., api. or
codeload.. This is separate from, and in
addition to, the nr-vault SSRF guard.
On hardened instances that restrict outbound HTTP through the global
HTTP/ 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
The Skills module — the Sources table (type, sync status,
last synced, per-source actions) above the discovered Skills
with their partial / full support badge and enabled state.
- On a source, click Sync. The source moves through
never_→synced syncing→ok/partial/error. Synchronization requires a saved, non-deleted source. The database row carries an opaque lease owner, so a second caller is refused even when its loaded source still has an older status. A missing or soft-deleted source returnserrorbefore remote requests or skill writes. 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
brings a different version of an enabled skill, nr-llm auto-disables
it so you re-confirm before it is used again. A version is the body
and the frontmatter fields the model reads — name, description,
support status,
allowed-and thetools processmarker — so a frontmatter-only change upstream, such as a widenedallowed-, disables the skill as well (ADR-214). Thetools pagekey is not part of the version: a change of it alone is stored and disables nothing (Whether a skill works on a page). - A skill that disappeared upstream is marked orphaned and disabled, never silently dropped, so attachments do not vanish.
The source, skill and skill-audit tables must use the same database connection.
Remote collection runs outside the publication transaction. A conditional
ownership check then fences skill changes, orphaning, audit writes and source
completion in one short transaction. Losing the lease during a slow remote
fetch returns error and publishes none of the collected changes; an older
worker cannot clear a replacement owner's lease. A publication failure rolls
back its changes and reports zero change counters.
A syncing row is interrupted when its heartbeat is zero or differs from
the current time by more than 180 seconds, including excessive future clock
skew. The exact 180-second boundary is still live. Opening the source list
rechecks the persisted row and changes an interrupted lease to retryable
error; a renewed or completed row is preserved. Trigger Sync
again to retry. Lease ownership fields stay internal and are not editable in
FormEngine (ADR-221).
GitHub may mark an oversized recursive tree response as truncated.
Such a listing is rejected before any skill file is fetched: it cannot prove
that omitted paths were removed. A repo source reports error and
preserves its existing skills and pinned SHA. For a marketplace source,
the affected child repository reports a partial sync; its existing skills
remain unchanged, and other reachable child repositories can still sync.
Malformed GitHub JSON responses are refused with the client's typed response error. Diagnostic logging is best effort and cannot replace that refusal.
Deleting a source cascade-deletes its skills.