Install and update both download from the registry, so they share the same
--repo/--quiet rules, blocked-download (403 / Xray) handling, and
verify-landed check.
- When evidence verification fails
- Handling a blocked download (403 / Xray-gated)
- Verify the install landed
- Update an installed skill
Install by slug (the registry slug/name, never a display name). Latest
version is used by default, and the user may pass an explicit version.
The jf skills install command takes no project. Resolving which repo hosts
the slug uses --list-skill-versions (below), which does require --project, so
use <PROJECT> resolved at session start (see SKILL.md Prerequisites).
jf skills install "<slug>" \
--server-id "<SID>" \
--version "latest" \
--repo "<repo>" \
--harness "<harness>" \
--quietIf the download returns HTTP 403, the archive is Xray-gated, not a permissions or "not found" problem. See Handling a blocked download (403 / Xray-gated) below.
Always pass --quiet. jf skills install/update opens an interactive
prompt by default, and an agent's shell has no TTY, so without --quiet the
prompt fails (it can abort with panic: device not configured). --quiet also
defaults to $CI, so exporting CI=true has the same effect if the flag is ever
unavailable. Run non-interactively and resolve every choice (--repo, target)
up front.
Resolve <harness> from the environment check script — never from your model
name. If <UA> is not already known from this session, run
bash <skill_path>/../jfrog/scripts/check-environment.sh <model-slug> now and capture
its stdout as <UA>. Parse the tool=<h> field from <UA> and map it to a
jf harness name:
tool= value in <UA> |
--harness for jf skills |
|---|---|
claude |
claude-code |
cursor |
cursor |
copilot |
github-copilot |
unknown, empty, or any other |
Ask the user |
If tool is unknown, empty, or not in the table — do not guess. Ask
the user for the desired install path and use --path <dir> instead.
Choose exactly one install target (these are mutually exclusive):
| Flag | Installs into |
|---|---|
--harness <name> |
The current agent's resolved skills dir (resolve per above, e.g. cursor, claude-code). |
--global |
Each agent's global directory from config. |
--project-dir <dir> |
Project root combined with the agent's project path. |
--path <dir> |
Direct: files go under <dir>/<slug>. |
Always resolve and pass --repo. When the platform has more than one skills
repository (the common case), jf skills install errors with multiple skills repositories found … specify --repo if you omit it, even when the skill lives
in only one repo. So the first install step is always to look up where the
slug is hosted with the Agent Guard:
npx --yes --registry <REGISTRY_URL> @jfrog/agent-guard \
--list-skill-versions --project "<PROJECT>" --skill "<slug>" [--server "<SID>"] --format json
# read versions[].version and versions[].locations[].repoKeyResolve the repo and version only via --list-skill-versions. The catalog
listing (--list-skills, even with --name) returns just names, not repos or
versions, so use the versions call above to pick the repo, never a name listing.
- One repo hosts the slug. Use it as
--repo <repoKey>directly. Don't ask. - Multiple repos host the slug. Do not pick silently. Naming a project is not
a repo choice, so ask even when one repo is project-scoped. List the repos (and
the version each holds), ask the user which to install from, then pass
--repo <chosen>. The newest version may only exist in one of them, so surface that to avoid giving the user a stale version.
If install fails with evidence verification failed … no evidence found, the
skill has no signed evidence/attestation (proof it's genuine and scanned).
This is a security control. Do not silently bypass it. Stop and ask using
this exact template:
<slug>@<version>has no signed evidence (proof it is genuine and scanned). Installing it skips that security check. Do you want to install it anyway?
Only if the user explicitly agrees, re-run with
JFROG_SKILLS_DISABLE_QUIET_FAILURE=true. Never set that flag on your own.
A jf skills install/update download can return HTTP 403 even when the
slug, version, and repo are all correct, because the skill archive is gated by Xray
and Artifactory will not serve it until the scan resolves. Do not report
this as a permissions or "not found" problem. Query the skill's Xray status to
find out why (the path is the archive <slug>/<version>/<slug>-<version>.zip,
URL-encoded):
jf api --server-id "<SID>" \
'/artifactory/api/skills/<repo>/xrayStatus?path=<slug>%2F<version>%2F<slug>-<version>.zip'Interpret the status field in the response:
-
SCAN_IN_PROGRESS. Xray is still scanning the archive. The download is temporarily gated, not blocked. Do not retry in a tight loop. Reply using this exact template:<slug>@<version>is still being scanned by Xray and isn't available to download yet. I can retry in a moment if you'd like.If it stays
SCAN_IN_PROGRESSafter a couple of polls, switch to this exact template instead:<slug>@<version>is still being scanned by Xray and is taking longer than expected. Try again later, or check with your JFrog administrator if it never clears. -
Blocked by a policy (a blocked/violating status, with the offending policy in the response body). The skill is blocked by an Xray policy. Stop. Do not retry. Reply using this exact template, filling the placeholders:
<slug>@<version>is blocked by the Xray policy<policy-name>and cannot be installed. Contact your JFrog administrator to review or resolve the policy. -
Any other status, or a non-zero
jf apiexit (jf apisignals a non-2xx response via its exit code plus a stderr[Warn] … returned NNNline — see the basejfrogskill's CLI andjf apigotchas). Treat as an operational failure (auth, endpoint disabled): the deliberate free-form case — report the CLI error verbatim (no template), but still strip theTrace ID.
After install, confirm the SKILL.md exists at the resolved install location
before reporting success:
test -f "<install-dir>/<slug>/SKILL.md" && echo "installed" || echo "MISSING SKILL.md"If the file is missing, report the failure. Do not claim success.
On success, reply using this exact template:
Installed
<slug>@<version>from<repo>into<harness>. Restart your agent session to load it.
To upgrade an installed skill to a newer version, use the CLI (it re-downloads and reinstalls in place):
jf skills update "<slug>" --server-id "<SID>" --harness "<harness>" --version "latest" --quiet
# Preview without touching Artifactory:
jf skills update "<slug>" --server-id "<SID>" --harness "<harness>" --dry-run
# Reinstall even if already at the target version:
jf skills update "<slug>" --server-id "<SID>" --harness "<harness>" --force --quietUse the same install-target flag (--harness/--global/--project-dir/
--path) the skill was installed with. After updating, re-verify the SKILL.md
(see Verify the install landed above). If the update download 403s, handle it
as in Handling a blocked download above.
On success, reply using this exact template:
Updated
<slug>to<version>(<harness>). Restart your agent session to load it.
If the skill was already current:
<slug>is already at the latest version (<version>). Nothing to update.