Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .cursor-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
},
"metadata": {
"description": "JFrog Platform plugins for Cursor",
"version": "0.5.4",
"version": "0.5.5",
"pluginRoot": "plugins"
},
"plugins": [
Expand Down
2 changes: 1 addition & 1 deletion plugins/jfrog/.cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "jfrog",
"displayName": "JFrog Platform",
"version": "0.5.4",
"version": "0.5.5",
"description": "JFrog Platform integration with MCP, security skills, supply-chain best practices, and JFrog Agent Guard governance for adding, removing, and listing MCP servers.",
"author": {
"name": "JFrog",
Expand Down
105 changes: 105 additions & 0 deletions plugins/jfrog/skills/jfrog-ai-catalog-skills/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
---
name: jfrog-ai-catalog-skills

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don’t merge the PR until the new jfrog-ai-catalog-skills skill is fully tested with this plugin.

description: >-
Discover, install, manage, and publish agent skills hosted in the JFrog AI
Catalog (Artifactory skills repositories) using the JFrog CLI (`jf skills`)
and the JFrog Agent Guard. Lists and searches available skills (catalog-wide
or scoped to a project), shows a skill's versions and which repos host it,
installs the latest or a pinned version, verifies the install, lists
installed skills, updates and removes them, and publishes (uploads) a local
skill bundle and releases new versions.
Use when the user asks what skills are available or installed, to
search/browse the catalog, to install/update/uninstall a skill, to see a
skill's versions, or to publish/upload/release a skill to JFrog /
Artifactory / the AI Catalog.
metadata:
role: workflow
---

# JFrog AI Catalog Skills

Discover, install, and manage agent skills from the JFrog AI Catalog
(Artifactory skills repositories), and publish your own skills back to it, all
through the JFrog CLI (`jf skills`) and the JFrog Agent Guard.

## Choose a reference file

Pick the row matching the user's intent and read that reference file.

| Intent | Read |
|--------|------|
| "What skills are available?" / browse the catalog / list versions / search by name | [references/discovering-skills.md](references/discovering-skills.md) |
| Install or update a skill (latest or a pinned version), or a download is blocked | [references/installing-skills.md](references/installing-skills.md) |
| "What's installed?" / remove an installed skill | [references/managing-installed-skills.md](references/managing-installed-skills.md) |
| Publish / upload / release a skill to the catalog | [references/publishing-skills.md](references/publishing-skills.md) |

## Prerequisites

- **Read the base `jfrog` skill first.** [`../jfrog/SKILL.md`](../jfrog/SKILL.md)
owns the shared guards this skill depends on, so this skill does **not** repeat
them — follow them there:
- The [environment check](../jfrog/SKILL.md#environment-check) — confirm `jf`
is installed before the first `jf` call, and install it if missing.
- The [server selection rules](../jfrog/SKILL.md#server-selection-rules-mandatory)
— resolve the default `<SID>` once and reuse it, pass `--server-id <SID>`
after the subcommand on every `jf` call, and use one server per request.
- The stop-on-error rule — on any `jf` failure, stop and never switch servers.

One addition specific to this skill: never `cat` or parse
`~/.jfrog/jfrog-cli.conf.v6` (it can hold access tokens); list servers only
with `jf config show`, which redacts secrets.
- **Agent Guard registry.** Catalog discovery and repo provisioning run through
`npx --yes @jfrog/agent-guard`. `<REGISTRY_URL>` is the npm registry that
provides the `@jfrog/agent-guard` package itself: use `JFROG_AGENT_GUARD_REPO`
if set, otherwise
`https://releases.jfrog.io/artifactory/api/npm/coding-agents-npm/`. Pass the
same `<SID>` to Agent Guard as `--server "<SID>"` so it targets the same server
as your `jf` calls. Agent Guard also reads `JFROG_URL` / `JF_URL` directly when
set, so make sure the `<SID>` you resolved points at that same host.
- **Resolve the project (`<PROJECT>`) only when needed, and always to a key.**
`<PROJECT>` must be the JFrog **project key**, not the display name. It is
required for `--list-skills`, `--list-skill-versions`, and
`--provision-skills-repository`. Take the value from `JF_PROJECT` or the user,
then resolve it to a key against the projects list (see *List all projects* in
the base `jfrog` skill's [`references/projects-api.md`](../jfrog/references/projects-api.md)):
```bash
jf api '/access/api/v1/projects' --server-id "<SID>" \
| jq -r '.[] | select(.project_key=="<value>" or .display_name=="<value>") | .project_key'
```
Use the printed key. If it prints nothing, ask the user for the key. Never
assume `default`, never invent one. Install, update, remove, and publishing to
an explicit `--repo` are keyed by skill **name** and/or **repo**, not a
project.

## Workflow overview

```mermaid
flowchart TD
A[User request] --> B{jf CLI installed?}
B -->|No| C[Ask user to install jf CLI, then continue]
B -->|Yes| D{Intent}
C --> D
D -->|List all / versions| E[npx @jfrog/agent-guard --list-skills]
D -->|Install / update| F[Resolve slug + version, then jf skills install/update]
D -->|List installed / remove| G[jf skills list / rm -rf install dir]
D -->|Publish| H[Resolve/provision repo, validate bundle, jf skills publish]
```

## Gotchas

Catalog-specific rules only. The shared `jf` guards — single server per request,
stop-on-error, and cautious mutation — live in the base
[`jfrog` skill](../jfrog/SKILL.md); follow those too. Flow-specific rules live in
the reference files above.

- **Which operations mutate**: install and list are read-mostly; remove, registry
delete, and publish mutate state — the base skill's cautious-mutation rule
applies to those three.
- **Session pickup**: installs, updates, and removals usually take effect only at
the next agent session start, so tell the user to restart.
- **Don't leak the plumbing**: present skills/versions/repos to the user, never
the `npx`/Agent Guard commands, `--registry`, flags, or cursors. Run follow-ups
yourself.
- **Use the response templates verbatim**: where a reference file gives a "reply
using this exact template" block, fill the placeholders and send exactly that,
with the same wording every time and no extra preamble or commentary.
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
# Discovering skills

List-all and versions go through the **Agent Guard**.

## List skills (page through the catalog)

```bash
npx --yes --registry <REGISTRY_URL> @jfrog/agent-guard \
--list-skills --project "<PROJECT>" [--name <PATTERN>] [--server "<SID>"] [--page-size <N>] [--cursor <C>] [--format json]
```

| Flag | Required | Purpose |
|------|----------|---------|
| `--project <PROJECT>` | **Yes** | AI Catalog project to list. |
| `--name <PATTERN>` | No | Find skills by name: server-side, case-insensitive substring, scoped to the project. |
| `--server <SID>` | No | jf CLI config entry to authenticate with (defaults to the resolved single server). |
| `--page-size <N>` | No | Results per page. Pass `50` to stay bounded. The Agent Guard defaults to 500 if omitted. |
| `--cursor <C>` | No | Continuation cursor from a previous page's JSON, to fetch the next page. |
| `--format json` | No | Raw page JSON instead of the default compact TSV (name + last-updated). |

Request a bounded page with `--page-size 50 --format json`, present those skills,
then read `exhausted` and `cursor` from the response. If `exhausted` is `false`
there are more. Tell the user and offer to fetch the next page with
`--cursor <cursor>`. Do not silently page through the whole catalog.

**Presenting results (use this exact format).** Render the skills as this table,
sorted by name, and nothing else (no commands, URLs, flags, or cursors):

| Skill | Last updated |
|-------|-------------|
| `<name>` | `<lastUpdated>` |

For a `--name` search with no matches, reply with one line instead:

> No skills match "`<query>`".
To offer a follow-up (a skill's versions or repos), ask in plain language
("want the versions for one of these?") and run the command yourself.

## List a repo's skills

To see what is published in one specific skills repository (for example, to check
a repo before or after publishing to it), list it directly with the CLI. This is
repo-scoped (Artifactory registry contents), unlike `--list-skills`, which is
project-scoped:

```bash
jf skills list --repo "<repo>" --server-id "<SID>" --format json
```

Never run a bare `jf skills list` (it errors): always pass `--repo <key>` here, or
`--harness <h>` for installed skills (see `managing-installed-skills.md`).

**Presenting results (use this exact format).** Render the skills as this table,
sorted by name, and nothing else (no commands, URLs, or flags):

Skills in `<repo>`:

| Skill | Version | Description |
|-------|---------|-------------|
| `<name>` | `<version>` | `<description>` |

Include the **Description** column only when the listing provides one (drop it if
every skill's description is empty). If the repo holds no skills, reply with one
line instead:

> No skills published in `<repo>`.
## A skill's versions and hosting repos

```bash
npx --yes --registry <REGISTRY_URL> @jfrog/agent-guard \
--list-skill-versions --project "<PROJECT>" --skill "<slug>" [--server "<SID>"] [--page-size <N>] [--cursor <C>] [--format json]
# JSON: versions[].version, versions[].locations[].repoKey (page through with cursor like above)
```

**Presenting versions (use this exact format).** Newest version first:

Versions of `<slug>`:

| Version | Hosted in |
|---------|-----------|
| `<version>` | `<repoKey>`[, `<repoKey>`] |
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# Installing and updating skills

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.

## Contents

- 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
resolve it (from `JF_PROJECT`, else ask the user) before that lookup.

```bash
jf skills install "<slug>" \
--server-id "<SID>" \
--version "latest" \
--repo "<repo>" \
--harness "<harness>" \
--quiet
```

If 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 host you are running in. Never take it from your
model name, and never hardcode it.** Get the valid names from the CLI: run
`jf skills list --harness '?'` to print the
`Supported agents:` table, then install into the row for your host. Identify the
host from its environment. For example, `CURSOR_*``cursor`,
`CLAUDECODE``claude-code`, VS Code / GitHub Copilot → `github-copilot`. If
nothing identifies the host, ask the user. Never assume.

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:

```bash
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[].repoKey
```

**Resolve 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.

## When evidence verification fails

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.

## Handling a blocked download (403 / Xray-gated)

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):

```bash
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_PROGRESS` after 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 api` exit** (`jf api` signals a non-2xx
response via its exit code plus a stderr `[Warn] … returned NNN` line — see the
base `jfrog` skill's *CLI and `jf api`* gotchas). Treat as an operational
failure (auth, endpoint disabled): the deliberate **free-form** case — report
the CLI error verbatim (no template), but still strip the `Trace ID`.

## Verify the install landed

After install, confirm the `SKILL.md` exists at the resolved install location
before reporting success:

```bash
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.
## Update an installed skill

To upgrade an installed skill to a newer version, use the CLI (it re-downloads
and reinstalls in place):

```bash
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 --quiet
```

Use 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.
Loading
Loading