From a83d872e0661cb9a345c746d27702bdcb8439b01 Mon Sep 17 00:00:00 2001
From: "jfrog-agentic-release-bot[bot]"
<276080306+jfrog-agentic-release-bot[bot]@users.noreply.github.com>
Date: Thu, 27 Aug 2026 10:09:03 +0000
Subject: [PATCH 1/2] [patch] chore: sync skills to v0.31.1
---
.devin-plugin/plugin.json | 2 +-
.github/scripts/sync-skills-vendor.json | 2 +-
.../SKILL.md | 63 +-
.../references/rca-procedure.md | 568 ++++++++++++++++++
skills/jfrog-reference-architecture/SKILL.md | 2 +-
skills/jfrog/SKILL.md | 2 +-
skills/jfrog/references/INDEX.md | 6 +-
7 files changed, 627 insertions(+), 18 deletions(-)
rename skills/{jfrog-package-safety-and-download => jfrog-package-curation}/SKILL.md (80%)
create mode 100644 skills/jfrog-package-curation/references/rca-procedure.md
diff --git a/.devin-plugin/plugin.json b/.devin-plugin/plugin.json
index 206d958..119e26d 100644
--- a/.devin-plugin/plugin.json
+++ b/.devin-plugin/plugin.json
@@ -1,7 +1,7 @@
{
"name": "jfrog",
"displayName": "JFrog Platform",
- "version": "0.3.2",
+ "version": "0.3.3",
"description": "Official JFrog plugin for Devin. Ships the JFrog skills bundle (platform ops, init, MCP management, AI Catalog, package safety, reference architecture, package-manager setup) and registers the JFrog Platform MCP server (remote HTTP + OAuth).",
"author": {
"name": "JFrog Ltd.",
diff --git a/.github/scripts/sync-skills-vendor.json b/.github/scripts/sync-skills-vendor.json
index acab867..bf58e43 100644
--- a/.github/scripts/sync-skills-vendor.json
+++ b/.github/scripts/sync-skills-vendor.json
@@ -1,6 +1,6 @@
{
"repo": "jfrog/jfrog-skills",
- "pin": "v0.30.0",
+ "pin": "v0.31.1",
"paths": [
"skills"
]
diff --git a/skills/jfrog-package-safety-and-download/SKILL.md b/skills/jfrog-package-curation/SKILL.md
similarity index 80%
rename from skills/jfrog-package-safety-and-download/SKILL.md
rename to skills/jfrog-package-curation/SKILL.md
index 0adb9cf..300f785 100644
--- a/skills/jfrog-package-safety-and-download/SKILL.md
+++ b/skills/jfrog-package-curation/SKILL.md
@@ -1,25 +1,61 @@
---
-name: jfrog-package-safety-and-download
+name: jfrog-package-curation
description: >-
- Check JFrog Public Catalog and stored packages for a version, interpret
- catalog security signals, and download through Artifactory (JFrog Platform
- locations, remote cache, curation-aware package managers, or repo proxy).
- Use when the user asks whether a package is safe, allowed, curated, or
- wants to download npm, Maven, PyPI, Go, or similar packages via JFrog.
- Do NOT use for pure CVE or vulnerability lookups (e.g. "details on
- CVE-2021-23337") — those are handled by the jfrog skill's Public security
- domain queries without this workflow.
+ Check/download a package (npm, Maven, PyPI, Go...) via JFrog — safe,
+ allowed, curated? Or: package op fails/blocked (ETARGET, 403, blocked by
+ curation policy, missing version, waiver) — root cause it. Checks the JFrog Public
+ Catalog and stored packages for a version, interprets catalog security
+ signals, and downloads through Artifactory (JFrog Platform locations,
+ remote cache, curation-aware package managers, or repo proxy). Do NOT use
+ for pure CVE or vulnerability lookups (e.g. "details on CVE-2021-23337")
+ — those are handled by the jfrog skill's Public security domain queries
+ without this workflow. Do NOT use for installing, listing, or approving MCP
+ servers/tools (even when named like a package, e.g. `@scope/pkg`) — that's
+ `jfrog-mcp-management`.
+compatibility: >-
+ "Check & download" needs only the JFrog CLI (`jf`). "Troubleshoot a
+ failure" needs the JFrog MCP curation tools (`jfs_curation_*`) — `jf` CLI
+ alone does not cover it; if unavailable, that section cannot run (see its
+ Preflight). Its reference file is local; outbound HTTPS is optional there
+ too (on-demand WebFetch of JFrog docs) — without it, it runs on the MCP
+ tools and local reference, degraded.
metadata:
role: workflow
---
-# JFrog Package Safety and Download
+# JFrog Package Curation
## Prerequisites
- Read `../jfrog/SKILL.md` for JFrog Platform concepts, domain model, CLI setup, and API patterns.
- **OneModel shapes drift by server version.** Before inventing GraphQL fields or `where` filters, read `../jfrog/references/onemodel-graphql.md` (schema fetch workflow) and `../jfrog/references/onemodel-query-examples.md` (**Public packages**, **Stored packages**). Regenerate or verify queries against `GET "$JFROG_URL/onemodel/api/v1/supergraph/schema"` when examples fail validation.
+## Which path do I need?
+
+- **Package hasn't been checked or downloaded yet** (is it safe / allowed / curated? download it) → go to **Check & download** below.
+- **A package operation already failed** — `ETARGET` (npm), "no matching distribution" (pip), `NU1102` (NuGet), a version missing/stripped from the registry, `403` / "blocked by curation policy", or an approved waiver not taking effect → go to **Troubleshoot a failure** below.
+
+---
+
+# Troubleshoot a failure
+
+> **Requires the JFrog MCP curation tools** (`jfs_curation_*`); no `jf` CLI
+> equivalent is used in this path. See the skill's `compatibility` note.
+
+Root-causing a curation-attributable failure (`ETARGET`, `403`, a version
+missing from the index, a waiver not taking effect) is a multi-step
+investigation — preflight checks, the two-gate model, symptom classification,
+then a full RCA procedure. It doesn't belong inline here since a plain
+download never touches it. **Open
+[references/rca-procedure.md](references/rca-procedure.md) and follow it from
+the top** — one file, covering preflight, the #1 RULE, the two-gate model,
+symptom classification (Step 0), and the RCA itself (Steps 1–4, worked
+examples, gotchas).
+
+---
+
+# Check & download
+
## Workflow overview
```mermaid
@@ -36,7 +72,7 @@ flowchart TD
I -->|Yes| J[Check curation policy via API]
I -->|No| K[Download via remote repo]
J -->|200 Allowed| K
- J -->|403 Blocked| M[Report curation blocked — stop]
+ J -->|403 Blocked| M[Report curation blocked — see Troubleshoot a failure]
```
### Parallelization opportunities
@@ -207,7 +243,10 @@ fi
download via a remote repo (same as Step 6b).
- **`returned 403` on stderr** → package is **blocked** by a curation
policy. The response body explains which policy rule blocked it. Report
- the block reason to the user and stop — do not attempt to download.
+ the block reason to the user and stop — do not attempt to download. For
+ root-cause detail beyond the block reason (why this version specifically,
+ whether a waiver applies, what to use instead), see **Troubleshoot a
+ failure** above.
- **Any other non-zero exit** → treat as an operational failure (auth, DNS,
endpoint disabled) and report.
diff --git a/skills/jfrog-package-curation/references/rca-procedure.md b/skills/jfrog-package-curation/references/rca-procedure.md
new file mode 100644
index 0000000..3a8f24b
--- /dev/null
+++ b/skills/jfrog-package-curation/references/rca-procedure.md
@@ -0,0 +1,568 @@
+# Curation RCA procedure
+
+> **Requires the JFrog MCP curation tools** (`jfs_curation_*`); no `jf` CLI
+> equivalent is used in this path. See the skill's `compatibility` note.
+
+> **#1 RULE — READ FIRST.** The **public catalog**
+> (`catalog_packages_list_versions`) is the only authority on whether a version
+> exists — quote its version list when you report existence. **Never** assert a
+> version exists or doesn't from the curated registry (`npm view` / `pip index`
+> against `/artifactory/...`, which is curation-filtered, so a CVS-blocked version
+> is simply absent) **or from your own memory**. Decide existence from the catalog,
+> and cross-check the **CVS audit** (`jfs_curation_query_cvs_audit_events`) for why a version was
+> filtered.
+
+Root-cause a curation package failure: correlate the two places Curation acts,
+then report an actionable conclusion. This file is the whole workflow —
+preflight, the two-gate model, symptom classification, evidence gathering,
+interpretation, and the conclusion — read it in order.
+
+This orchestrates the **JFrog MCP curation tools** (no `jf` CLI or raw
+HTTP) and assumes the JFrog MCP server is connected and the tenant is
+Curation-entitled. The curation tools are the **`jfs_curation_*`** family (e.g.
+`jfs_curation_query_cvs_audit_events`); `catalog_packages_list_versions`
+and `artifactory_repositories_get` are different tool families without the prefix.
+
+## Preflight
+
+**Right environment.** The MCP curation tools only ever query the
+**currently connected** JFrog tenant, and a different env has different audit data —
+an answer from the wrong tenant is worse than none. When the failing URL's host
+matches the connected tenant, you're set — proceed. **Confirm with the user only
+when it's ambiguous** (the host doesn't obviously match, or you can't tell which
+tenant is connected); on a real mismatch, **stop** until the tools point at the
+right tenant. Don't ask when it already matches.
+
+**Tools must be present.** These MCP tools are gated at registration
+by platform version + entitlement (min Xray **3.153.0** for the CVS tools and
+`jfs_curation_get_audit_event_policies`; **3.112.0** for `jfs_curation_query_audit_events`). If the tool you
+need is **not in your available tools**, split the diagnosis on what else is
+present:
+
+- **No JFrog MCP tools at all** (not even `catalog_packages_list_versions` /
+ `artifactory_repositories_get`) → the JFrog MCP server isn't connected. Say
+ so; never substitute a `jf` command or raw HTTP.
+- **Other JFrog MCP tools work but `jfs_curation_*` is absent** → the
+ platform is below the required Xray version or the tenant isn't
+ Curation-entitled. **Stop gracefully:** report that the audit-based investigation
+ can't run here and that it needs Xray ≥ 3.153.0 with Curation enabled.
+
+Either way, do **not** fabricate calls or guess results.
+
+## How Curation works
+
+A package manager does two things: **resolve** a version, then **download** it.
+Curation acts at both, with different strictness.
+
+| | **Gate 1 — Resolution** | **Gate 2 — Download** |
+|---|---|---|
+| Client action | asks Artifactory for the version list | requests the binary |
+| Curation evaluates | versions newest-first, **stops at the first approved one** (max evaluated is configurable, typically 1) | **all** policies, against the one requested version |
+| Returns | that version **plus everything older** — or `403` if none approved | the binary — or `403` |
+| Strictness | best-effort filter to reduce downstream blocks; **not a guarantee** | **hard gate** — enforcement is final here |
+
+**The list is truncated at the top, not filtered throughout.** Versions *newer*
+than the approved one are gone. Versions *older* are present but were **never
+evaluated**. Every symptom below follows from that one sentence.
+
+```mermaid
+sequenceDiagram
+ participant CLI as Package manager
+ participant RT as Artifactory
+ participant CUR as Curation
+
+ CLI->>RT: 1. list versions
+ RT->>CUR: evaluate
+ CUR-->>RT: first approved version + all older
+ alt none approved
+ RT-->>CLI: 403
+ else
+ RT-->>CLI: truncated list
+ end
+ Note over CLI: client resolves against this list only
a pin not in it fails here, in the client
+
+ CLI->>RT: 2. download resolved version
+ RT->>CUR: evaluate all policies
+ alt blocked
+ RT-->>CLI: 403
+ else
+ RT-->>CLI: binary
+ end
+```
+
+**Which audit records which gate:**
+
+- **Gate 1 — resolution** → the **CVS audit**:
+ `jfs_curation_query_cvs_audit_events` → `jfs_curation_get_cvs_audit_version_detail`.
+- **Gate 2 — download** → the **package-download audit**:
+ `jfs_curation_query_audit_events` → `jfs_curation_get_audit_event_policies`.
+- A **`403` with nothing resolvable** (gate 1, every version blocked) is recorded in
+ **both** audits — query both.
+
+**Symptom → gate:**
+
+| Symptom | Gate | Read it as |
+|---|---|---|
+| `ETARGET`, "no matching distribution", `NU1102` | 1 | pin is newer than the approved version, so it was never returned. The client failed locally — **Curation wrote no event for this failure** |
+| `403` on a version the client could see | 2 | pin is older than the approved version: passed gate 1 unevaluated, blocked at the hard gate. Expected, not a contradiction |
+| `403` with nothing resolvable | 1 | every version blocked (recorded in both audits) |
+| Visible "latest" is lower than upstream | 1 | normal truncation, not a fault |
+
+Exact error text is **manager- and command-specific** — don't assume `ETARGET`
+(npm `ETARGET`, pip "no matching distribution", NuGet `NU1102`, `E403`; `npm
+install` vs `npm ci`, `pip install ` vs `==`).
+
+Gate 1 and gate 2 disagreeing is **by design** — say so rather than reconciling it.
+
+**"CVS disabled" ≠ no gate 1.** CVS is **enabled by default** for some package types: the
+**malicious** and **immature** policies run at gate 1 even when CVS is switched off
+(npm today; the set grows as types onboard — don't assume it's only npm). So a
+gate-1 block whose `condition_name` is malicious or immature is expected despite a
+"CVS is disabled" claim; a CVE / license / ban condition means CVS is actually on.
+Treat the audit as ground truth — a gate-1 event contemporaneous with the failure
+settles it. Read the `condition_name` and explain it; don't argue with the claim.
+
+> **Don't mix timelines.** The audit tools report the **past** (timestamped
+> events). `jfs_curation_check_remote_package_compliance` returns a **live verdict now** — it
+> runs a fresh CVS evaluation under current policy and may create a new audit row.
+> Anchor the RCA on the audit timeline. Use a live compliance check only per
+> Step 2, and label its result **current** — never as evidence of the
+> failure-time state.
+
+**Docs to consult** — fetch on demand, once (if blocked/airgapped, say so and
+reason from the tool outputs; if the fetch itself fails for any other reason,
+say so and proceed on the tool outputs alone rather than stalling):
+
+- **CVS mechanism, supported types, waiver applicability, limits** — fetch at the
+ start of a gate-1 investigation:
+ `https://docs.jfrog.com/security/docs/compliant-version-selection`
+- **Per-package-manager error text** — don't assume `ETARGET`; the pattern is
+ manager- and command-specific:
+ `https://docs.jfrog.com/security/docs/behavior-by-package`
+- **Curation concepts** (what it is, features & capabilities), only to ground a
+ term you cannot otherwise resolve:
+ `https://docs.jfrog.com/security/docs/curation-intro` and
+ `https://docs.jfrog.com/security/docs/features-and-capabilities-getting-started-5`
+
+## Route by gate
+
+Classify the symptom → gate → tool using the tables above:
+
+- **Gate 1 — resolution** (not resolvable: `ETARGET`, "no matching distribution",
+ `NU1102`, missing from `npm view` / `pip index`) → **CVS audit**:
+ `jfs_curation_query_cvs_audit_events` → `jfs_curation_get_cvs_audit_version_detail`.
+- **Gate 2 — download** (`403` on a version that *is* resolvable) → **package-download
+ audit**: `jfs_curation_query_audit_events` → `jfs_curation_get_audit_event_policies`.
+ Enough to root-cause the 403 on its own — don't reach for a compliance check by reflex.
+
+A `403` with **nothing** resolvable is gate 1 and is recorded in **both** audits —
+query both. The gates can **disagree** (a resolvable version that still 403s) —
+surface it, don't reconcile.
+
+## Step 0 — Capture the symptom
+
+Collect before touching any tool. Ask the user only for what is missing:
+
+- **package type** (npm, PyPI, Maven, Go, NuGet, …) — infer it from the failing
+ URL (`/api//…`, e.g. `/api/npm/`) or the command (`npm`/`pip`/…); ask the
+ user only if neither is available. `package_type` is **required** on the CVS
+ audit call. If the first audit comes back
+ empty, suspect a casing/token mismatch instead: canonical CVS tokens are
+ `npm, PyPI, Maven, Go, NuGet, Gems, Conda, Composer, Gradle,
+ AIEditorExtensions, SBT, Alpine, Docker, Cargo` (case-sensitive, not
+ normalised server-side) — retry with the canonical casing, or ask the user
+ to confirm the ecosystem rather than guessing.
+- **package name** and the **version** in the error.
+- **repository / registry** the client resolved through (from the failing URL /
+ client config), and whether it's a JFrog **curated remote**, a **virtual** (some
+ managers — e.g. Go — require one; npm can use either), or plain public. This
+ decides how Step 1 reads a "not found" (curated vs public) and how Step 2
+ identifies the remote (the audits are keyed by the remote, never a virtual). You
+ often can't tell virtual from remote by name — capture it; if unknown, ask; do
+ not assume.
+- the **exact error text** and the **approximate date + hour** — bounds the audit
+ window (Step 2). Investigate any past failure within **retention** (default ~30 days);
+ the 168h cap limits one query's **width**, not recency. For an older failure,
+ anchor the window near the failure time (not "now") so the query actually covers it.
+
+**Pin the timeline before running any audit.** Read the failure's **date + hour**
+from the error text / log if it's there (e.g. a timestamped log line) — don't ask
+for what the provided context already shows; ask the user only if it's missing
+(and don't settle for "recently"). It bounds the audit window and anchors
+`created_at_end` to the failure, not "now". Then, within that window, if Step 2's
+survey turns up **more than one curated remote** for the package, ask which repo
+they resolved through before interpreting — see Step 2's "Identify the curated
+remote".
+
+Classify into a symptom class. This list is **open-ended** — match the closest
+row; if nothing fits, use the last row (never refuse for lack of an exact match):
+
+| Symptom | Class | Start with |
+|---|---|---|
+| A version can't be resolved/installed — e.g. `ETARGET` (npm), "no matching distribution" (pip), `NU1102` (NuGet), or absent from `npm view` / `pip index`. The exact pattern is **package-manager-specific** — see behavior-by-package | **NOT-RESOLVABLE** | Step 1's client-side-config check, then Gate 1 — CVS audit |
+| `403` / `Forbidden` / "blocked by curation policy" on a version that *is* listed | **DOWNLOAD-BLOCKED** | Gate 2 — package-download audit |
+| Every version fails because nothing resolves at all (empty/near-empty listing) | **NOT-RESOLVABLE** (package-level) | This is a resolution failure, not a download-time block — Gate 1 + both audits |
+| Every version 403s at download while the package is still listed | **PACKAGE-BLOCKED** | Gate 2; expect a package-level block |
+| The blocked name is a dependency of what you installed | **TRANSITIVE** | Gate 2 on the *blocked* name, not the top-level one |
+| Used to install, now blocked (or was blocked, now works) | **DRIFT / TIMELINE** | both audits across time; a live compliance check is the *only* "now" signal |
+| Still blocked despite an approved waiver | **WAIVER-NOT-APPLIED** | Gate 2 + `jfs_curation_query_waiver_requests` (check scope, status, expiry) |
+| "Pending Catalog update" reason, or intermittent/flaky blocks | **PENDING / TRANSIENT** | the relevant audit filtered by `reason` |
+| Anything else curation-related, or unclear | **OTHER** | gather from **both** audits + the client error text, then map via the Step 4 RCA table |
+
+## Step 1 — Rule out the non-curation cause first
+
+Don't assume curation — and for **NOT-RESOLVABLE**, decide existence per the **#1 RULE**.
+
+**Rule out client-side config first.** A resolve failure can look identical to a
+curation block while having nothing to do with curation — the package manager's
+own local filters produce the same symptom shape (`ETARGET`, no matching
+version). Before trusting the symptom table's default routing, check whether
+the client config explains it: a date/version-age filter (npm's `before` /
+`min-release-age`, surfaced via `npm config get before` and `npm config get
+min-release-age`), a registry override in `.npmrc` / `pip.conf` / `nuget.config`
+/ `GOPROXY`, or a CI-injected flag. This applies **regardless of the exact
+error string** — don't wait for a table row that matches your specific
+package manager's wording.
+
+Settle it with **two independent reads — run BOTH, and never gate one behind the
+other**:
+
+1. **Does it exist?** Use **only** `catalog_packages_list_versions` (approved MCP
+ tool). **Never** query a public/upstream registry directly, **never** the
+ curated `/artifactory/...` registry, and **never** `artifactory_packages_get_versions`
+ (curated/cached = **filtered** listing — same trap). Two coverage notes:
+ - **Name translation:** the catalog token differs for some CVS types — **Go →
+ `golang`**, **Gems → `rubygems`**. npm / PyPI / Maven / NuGet are the same.
+ - The catalog covers only some types; for an **unsupported** type it returns
+ nothing — a catalog miss there is **not** proof of non-existence. Fall back
+ to the CVS audit (read 2); if that's also empty, say the existence check is
+ unavailable rather than guessing.
+2. **What did Curation decide?** For a **NOT-RESOLVABLE** symptom, **always** query
+ the CVS audit (`jfs_curation_query_cvs_audit_events`, package + type) — do not
+ skip it because a listing looked empty. It is the authoritative record of whether
+ CVS inspected the version and blocked or approved it: it both proves the version
+ existed and gives the verdict. (For a **403 / download** symptom, the reverse
+ holds — do **not** query the CVS audit; use the download audit only. See Gate 2
+ and the 403 worked example. A **403 with nothing resolvable** is Gate 1
+ too — query **both** audits, per the two-gate model above.)
+
+Read the cross-product:
+
+- **In the catalog (or a CVS record exists) + CVS blocked it** → **curated-index
+ filtering** (the usual answer): CVS blocked the version **and** the client can't
+ resolve it. The audit proves *blocked* (a decision); the **client's ETARGET /
+ absence** is what proves it's missing from the listing — the audit does not state
+ listing membership, so don't claim omission unless the client listing actually
+ lacks the pin. Together → **Gate 1** for the policy detail and the compliant
+ version CVS selected.
+- **In the catalog + no CVS record** → not (yet) curation — remote sync / virtual
+ repo / cache config; investigate outside CVS.
+- **Not in the catalog (and the catalog supports this package type) + no CVS
+ record** → likely never existed / yanked → not curation; report the nearest
+ catalog versions (e.g. `1.18.1`, `0.19.0`) and stop. If the catalog does
+ **not** support this type, a miss is not proof of non-existence — report the
+ existence check as unavailable (Insufficient evidence) instead.
+
+A resolve-time ETARGET fails **in the client**: it mints **no** CVS or download
+audit row and there is **no** 403 to find. The CVS evidence is a
+**prior/historical** evaluation (when the package was last inspected) — never
+expect a row created by this failed install, and never read its absence as
+"curation not involved".
+
+For a **403** symptom the non-curation confounders are auth / permissions / a
+disabled repo — rule those out, then Gate 2.
+
+## Step 2 — Gather evidence
+
+Pick the branch from Step 0. When in doubt, run both; they are independent.
+
+**Identify the curated remote.** The audits are keyed by the curated **remote**,
+never a virtual — so the repo in the client URL is a lookup key, not the answer.
+Capture it as `client_repo` (from the failing URL, e.g. `/api/npm//…`); a
+virtual (some managers, e.g. Go, require one) is **never** the curated remote key,
+so do **not** pre-filter the audit on it. Read the candidate remotes from the
+returned events (`curated_repo_name` for CVS, `curated_repository_name` for the
+download audit) within the failure window.
+
+When `client_repo` is a virtual, or more than one remote has a contemporaneous
+event, resolve which remote in this order — **never infer from names**
+(`npm-virtual` does not imply `npm-remote`):
+
+1. **Artifactory join (preferred).** Call `artifactory_repositories_get(client_repo)`
+ and intersect its member repositories with the candidate remotes from the audit.
+ A single match is the remote.
+2. **Ask (fallback).** If that tool is not accessible (e.g. a 403/permission error),
+ or the intersection is empty or still more than one, **ask the user to confirm
+ the underlying remote** they resolved through. Do not guess.
+
+Until the remote is proven by (1) or (2), do **not** put a repo in the RCA
+**Repository** field — and never the virtual name — and cap that field at
+**Medium** confidence. The *what* (policy/verdict) can still be **High** when every
+candidate remote carries the same verdict, even while the Repository stays Medium.
+
+**Window to the failure time** (from Step 0), not the 7-day default — far fewer
+day-partitions scanned on a busy tenant, and required when the failure is >7 days old.
+The survey bounds `created_at_start`/`created_at_end` are **RFC3339 strings** (e.g.
+`2026-08-18T03:33:00Z`), **not** epoch — epoch ms is only for
+`jfs_curation_get_cvs_audit_version_detail.created_at` (Gate 1 step 3); don't carry that
+format into the survey or it 400s / returns empty.
+
+- **Gate 2 (403):** the block is contemporaneous with the failure, so window it
+ **as tightly as your timestamp precision allows** — with a precise time (e.g. from
+ the client log), use only a clock-skew margin (**±15 min**, at most ±1 h); widen
+ toward ±1 day **only** when the failure time is approximate ("sometime that day").
+ A tight window also avoids sweeping in unrelated contemporaneous events (e.g. a
+ second remote's block for the same package), which is what forces the
+ remote-disambiguation step — so don't widen it past what the timestamp warrants.
+- **Gate 1 (CVS):** the evaluation happens when Artifactory (re)builds the
+ **cached** curated metadata, so it can be **hours or days before** the failed
+ resolve — its timestamp has no fixed relation to the failure clock. Do **not**
+ window symmetrically or tightly: reach **back** — set `created_at_end` to just
+ after the failure, `created_at_start` to **failure − 7 days** (one 168h window),
+ `direction=desc`, and take the **latest event at or before the failure**. Cap the
+ reach-back at 7 days; do **not** page further. If that window is empty, report
+ **"no CVS record in the 7 days before the failure"** (the cached inspection is
+ older than 7 days) — not "no CVS" outright.
+
+### Gate 1 — NOT-RESOLVABLE (CVS audit)
+
+Target the **historical** CVS evaluation — the failed install created no new row.
+The pin may be **absent** from `versions[]` because resolution stopped before it
+(see **How Curation works** above), not because it was "never evaluated".
+
+1. **Survey** with `jfs_curation_query_cvs_audit_events` (do **not** set `include_versions`
+ yet). `package_name` and `package_type` are **required** (no unscoped
+ surveys). Add `inspection_results=no_compliant_versions,compliant_version_selected`
+ (comma-separated IN — both failure buckets in one call), and use `direction=desc` with a
+ small `num_of_rows` for the latest evaluation. **Never** survey
+ `all_versions_compliant` to explain a failure (~99% of the data); if you ever
+ query it, cap the window to **≤1 day**. Set `include_total` only when you need the
+ match count or an exact `next_offset` (to gauge volume or paginate) — it adds a
+ count query, so skip it for a plain latest-event lookup.
+ Read `packages[].summary`, `inspection_results`, `latest_inspected_version`.
+2. **Drill down** on the event you care about: call again with the same
+ `package_name` + `package_type` plus `event_id=`,
+ `include_versions=true`, `num_of_rows` ≤ 10. Find the target version in
+ `packages[].versions[]` and read its `action` + blocking `policies[]`.
+3. **Explain** one version with `jfs_curation_get_cvs_audit_version_detail`
+ (`version_id=versions[].id`, `created_at=` the **event's** `created_at` in
+ **epoch milliseconds** — copy it verbatim).
+
+### Gate 2 — DOWNLOAD-BLOCKED (package-download audit)
+
+1. **Search** `jfs_curation_query_audit_events` by `package_type` + `package_name`
+ (+ `package_version` if known) over the relevant window (add `include_total=true`
+ only if you want the match count).
+2. **Explain** the blocking event with `jfs_curation_get_audit_event_policies`
+ (`event_id=data[i].id`) for the `explanation` + `remediation`. These fields can
+ come back **empty** (policy/condition names and verdict only) — that does **not**
+ lower confidence: when the audit's policy/condition agrees with the client's
+ block notice, the finding is still **High**. Fall back to the Step 4 generic
+ package-blocked remediation and note "no remediation text from the API".
+
+### Optional live compliance check — only when it earns its place
+
+`jfs_curation_check_remote_package_compliance` is **not** a step in the RCA. It is a live,
+current-policy verdict that runs a fresh evaluation (see the
+timeline note above), so it does not tell you what happened at the time of the
+failure and it can muddy a clean audit-based conclusion. Call it **only** when:
+
+- the user asks "what can I install instead?" **and** the audit did not already
+ surface allowed/suggested versions (the client's own block notice often does);
+- you specifically need a **current-vs-past drift** check (e.g. confirm the block
+ still stands under today's policy); or
+- you are about to **change a dependency or recommend a pin** and must validate
+ the candidate live.
+
+Otherwise skip it. When you do call it, report `allowed_versions` and the verdict
+as **current state**, kept separate from the audit-based root cause.
+
+## Step 3 — Interpret
+
+Each tool's own description lists its traps; read them before concluding. The
+ones that most often flip an RCA:
+
+- **Empty CVS result → first rule out "curation not enabled".** The audit tools
+ are **not** feature-gated (they need only `VIEW_POLICIES`), so a disabled feature
+ writes no rows and returns `200` with empty `data` — indistinguishable from
+ "nothing blocked".
+- **For a 403, the download audit is the authority; CVS coverage is partial.**
+ Because resolution stops at the first approved version (see **How Curation
+ works** above), absence from a CVS `versions[]` does **not** mean a version
+ was unevaluated, out of the index, or approved — and it must **never** weaken
+ or override a `jfs_curation_query_audit_events` finding. Versions CVS did not
+ (re)select stay in the index and are enforced by the download flow — that is
+ the 403.
+- **Bad `inspection_results`/`reason` tokens are silently ignored** → a 200
+ **unfiltered** result. Verify returned rows carry the value you filtered on.
+- **Do not invent or generalize a mechanism.** The audit reports the *decision*
+ on a version (blocked/compliant + policy + reason), not why the client listing
+ contains or omits it. Never infer a general rule from a few events — e.g.
+ "CVE policies enforce at download, ban-label at resolve" from two rows. A
+ policy's category does not determine listing membership or enforcement stage;
+ read each event's own fields. If the behavior in question (listing/exposure,
+ enforcement stage) is not stated in the audit rows or the CVS doc, report it as
+ **not determined** — do not synthesize an explanation to fit the data points.
+
+## Before Step 4 — output gate
+
+No conclusion (even hedged) without these tool calls made and reflected in
+Evidence:
+
+- Existence in question (NOT-RESOLVABLE, or any 403 with **nothing**
+ resolvable): `catalog_packages_list_versions` (the #1 RULE).
+- A 403 on a version the client already **resolved/listed**: existence is
+ proven by that successful listing — the catalog call isn't required; go
+ straight to the download audit.
+- NOT-RESOLVABLE, or any 403 with nothing resolvable: `jfs_curation_query_cvs_audit_events`.
+- Any resolvable/listed 403 (DOWNLOAD-BLOCKED, PACKAGE-BLOCKED on a still-listed
+ name, TRANSITIVE): `jfs_curation_query_audit_events`.
+- WAIVER-NOT-APPLIED: + `jfs_curation_query_waiver_requests`.
+
+Missing/unavailable tool ≠ license to guess — use Insufficient evidence instead.
+
+## Step 4 — Conclude the RCA
+
+Map the evidence to a root cause. Report the **first** row that matches.
+
+| Evidence | Root cause | Remediation |
+|---|---|---|
+| Version not in the public catalog (for a package type the catalog supports) and no CVS record | **Not curation** — version does not exist | Correct the version; nothing to unblock. |
+| ETARGET on a curated registry; version present in the **public catalog** but absent from the **curated** listing; CVS history shows it filtered / not selected | **Curated-index filtering** — CVS omitted the version from the curated listing, so the client can't resolve it (fails at resolve, no 403, no fresh audit row) | Use a version present in the curated listing (one CVS selected / `allowed_versions`); or waiver and re-index. |
+| CVS event: target version `action=blocked` + policy P | **CVS non-compliant** — CVS found the version non-compliant under policy P (this is the decision; it does not by itself explain listing membership) | Apply the version's `remediation` from `jfs_curation_get_cvs_audit_version_detail`; pin to an `action=approved` version from the same event (or `allowed_versions`). For waiver applicability under CVS, consult the CVS doc — do not assume. |
+| CVS event: `inspection_results=no_compliant_versions` | **No compliant version found** in the audit | Check `jfs_curation_check_remote_package_compliance` for any allowed version; otherwise raise a waiver (see the CVS doc for applicability). Do not recommend changing the policy. |
+| Package-audit event: version `action=blocked` + policy P | **Download-time block** — the 403 comes from policy P at download | Apply the policy's `remediation` from `jfs_curation_get_audit_event_policies`; use an allowed version; or raise a waiver. |
+| Locked/older pin 403s at download; the recent CVS record selected a *newer* compliant version and has no (or only a stale/earlier) record for the pin | **Pin bypasses CVS selection** — CVS returned a newer compliant version and did not (re)select the pinned one, so the pin stays in the index and is enforced by the download-time policy (the 403). The CVS absence is expected, **not** evidence of anything | Use the compliant version CVS selected (or `allowed_versions`), or waiver the pin. The download audit + `jfs_curation_get_audit_event_policies` is the authority for the block. |
+| Block covers the package itself, not a single version | **Package-blocked** — a policy blocks the whole package | Use a different package, or waiver the package if policy allows (see the block's `remediation`). |
+| The blocked package name ≠ the one the user installed | **Transitive dependency block** — a dependency was blocked | Re-run the RCA on the *blocked* dependency; remediate it (pin/override the transitive) rather than the top-level package. |
+| Approved waiver exists (`jfs_curation_query_waiver_requests`) yet the block persists | **Waiver not effective** — wrong scope/repo, expired, not yet applied, or the index has not refreshed | Verify the waiver's scope, status, and expiry against the failing repo/version. If it's valid, the index likely hasn't re-evaluated — no MCP tool here can force this; tell the **user** to reindex / zap the cache on the curated remote and retry after they do. |
+| `reason = "Pending Catalog update"` | **Transient / pending** — the verdict awaits catalog data | Retry after the catalog updates; treat as not-final, not a hard block. |
+| CVS `approved` **and** a download-time block exist for the same version | **Divergence** — the version is CVS-approved yet blocked at download; causes include a policy change between evaluation and download, or a different policy set on the download path (see the CVS doc) | Confirm current status via `jfs_curation_check_remote_package_compliance`; use a curation-compliant version or raise a waiver. Do not recommend changing the policy. |
+| No CVS **and** no package-audit record, version exists upstream | **Likely not curation** (write lag, CVS disabled or not applicable, no scoped policy, unsupported type) | For the CVS audit, confirm the window already reached the full 7 days (Gate 1's cap) — do not widen past 168h or drop `package_name`/`package_type`. For the download audit, you may widen using the multi-window probe strategy and drop optional filters, but keep `package_type`. If still empty at those caps, investigate outside curation. |
+
+**Failure Reason lookup** — map the matched root cause above to the one **Failure
+Reason** you print below (several root causes map to the same label):
+
+- **Version not available — removed by curation:** Curated-index filtering; CVS
+ non-compliant; No compliant version found.
+- **Download blocked by a curation policy:** Download-time block; Pin bypasses CVS
+ selection; Divergence (CVS-approved yet blocked at download); Waiver not effective
+ (add "waiver not applied" in Failure Details).
+- **Whole package blocked by curation:** Package-blocked.
+- **Curation check still pending:** Transient / pending ("Pending Catalog update").
+- **Not caused by curation:** version does not exist; likely-not-curation (remote
+ sync / cache / no scoped policy / unsupported type); a client-side date/version
+ filter (`min-release-age` / `before`, registry override, CI flag) explains it.
+- **No curation record found:** no CVS and no package-audit record in window.
+- **Transitive** is not its own label — re-run the RCA on the *blocked dependency*
+ and use whichever Failure Reason its own root-cause row maps to.
+
+**If the root cause is "Not caused by curation" or "No curation record
+found," skip the table below — use the "Not a curation problem" block after
+Insufficient evidence instead.** The table's fields are curation-specific
+(Repository, Audit event links) and don't apply to a non-curation cause.
+
+For the other four Failure Reasons, present the conclusion as a **table** —
+render exactly these rows, in this order. Frame every value in **curation**
+terms (this is a curation RCA, not a generic one):
+
+| Field | Value |
+| --- | --- |
+| **Confidence** | **High** / **Medium** / **Low** — ``. Report **Low** when a step returned an ambiguous empty result rather than a positive record; the *what* can stay **High** while **Repository** is **Medium** until the virtual→remote join is proven (Step 2). |
+| **Package** | `` |
+| **Version** | `` (or `all` / the failing pin) |
+| **Failure Reason** | one of: **Version not available — removed by curation** · **Download blocked by a curation policy** · **Whole package blocked by curation** · **Curation check still pending** · **Not caused by curation** · **No curation record found** |
+| **Failure Details** | Failed due to curation policy `` — `` (e.g. "Failed due to curation policy `cve` — cve more than 7 and Half") |
+| **Repository** | the remote from whichever audit you used — `` (CVS) or `` (download audit) |
+| **Failure Timestamp** | the exact failure timestamp, e.g. `2026-08-18T03:33:00Z` |
+| **Audit event links** | the Curation **UI audit page** — `/ui/package-curation/audit` (`` = the platform host from the failing URL / connected tenant) — plus the event(s) that locate the record there: CVS `jfs_curation_query_cvs_audit_events` event `id=` (`created_at=`), download `jfs_curation_query_audit_events` event `id=` |
+
+Then, **below the table, as bullet points** (not table rows):
+
+- **Ruled out:** the non-curation causes you checked — auth / permissions, repo or remote config, a version that never existed.
+- **Evidence:** discrete `key=value` tokens on one line, each individually searchable/copyable — e.g. `tool=jfs_curation_query_cvs_audit_events` `event_id=1290` `created_at=1786000000000` `action=blocked` `policy=cve`. Emit only the tokens you have.
+- **Remediation** *(High confidence only — omit entirely at Medium/Low):* use a curation-**compliant** version (the one CVS selected, or an `allowed_versions` entry), or **raise a waiver** scoped to the curated remote(s) you resolve through. **Never** propose changing or loosening a curation policy (e.g. "lower the CVE threshold in policy `cve`") — a policy change is out of scope for this RCA; the waiver is the only sanctioned exception.
+
+**Insufficient evidence** *(use instead of the table above when the output
+gate stopped you)*: state **Cannot conclude** — name the missing tool call(s)
+or ambiguity (tenant, repo, tool unavailable) — and what's needed to proceed.
+Never fill the table with a guess to avoid this.
+
+**Not a curation problem** *(use instead of the table above for "Not caused
+by curation" / "No curation record found")*: state the actual cause and the
+evidence that rules out curation — e.g. `npm config get before` /
+`min-release-age` returned a value matching the error, or no CVS/download
+record exists in a widened window. No curation-specific fields — Repository
+and Audit event links don't apply here.
+
+**Consistency gate — before you finalize.** Re-check the conclusion against
+**every** event you retrieved, not just the ones that fit. If any row contradicts
+it, the conclusion is wrong — revise it to fit all the data. A conclusion that
+requires an invented mechanism to reconcile two rows is a red flag: prefer "not
+determined from the audit (see the CVS doc)" over a synthesized rule.
+
+## Worked examples (illustrative)
+
+Two end-to-end illustrations. They are **not** the supported set — apply the same
+method (Step 0 → Step 4) to any curation symptom, including the classes above
+that have no example here.
+
+### npm `ETARGET`
+
+> `No matching version found for @vitest/eslint-plugin@1.6.27`
+
+`ETARGET` → NOT-RESOLVABLE (Gate 1). **First** apply Step 1's two reads — do
+**not** trust `npm view` against the curated registry (that's the filtered
+view). (1) Existence via `catalog_packages_list_versions` (the only approved
+oracle — do not query public npm directly) — absent there → "version does not
+exist", report the nearest catalog versions, stop. (2) **Always** survey the CVS audit
+`jfs_curation_query_cvs_audit_events(package_name, package_type="npm")` with
+`direction=desc` for the latest **historical** evaluation (this failed install minted
+no row). Drill down (`event_id`, `include_versions=true`) and look for `1.6.27`:
+`action=blocked` → CVS found it non-compliant; combined with the client's ETARGET
+(the pin is absent from the curated listing), that's curated-index filtering
+— get `explanation`/`remediation` via `jfs_curation_get_cvs_audit_version_detail` and pin to
+the version CVS selected (check the CVS doc before assuming a waiver applies);
+**absent** from `versions[]` → likely CVS stopped after selecting its compliant
+version(s) and never recorded this pin (Step 3), not "never evaluated". Conclude
+per Step 4.
+
+### 403 on a version that `npm view` lists
+
+> `npm view` lists `axios@1.15.1`, but `npm install axios@1.15.1` fails with
+> 403 "blocked by JFrog Packages Curation Service" (policy: CVE). User claim:
+> "it's listed, so CVS approved it — why does download fail?"
+
+403 on a **resolvable** version → **DOWNLOAD-BLOCKED (Gate 2)**. The version
+is already listed, so resolvability — and therefore existence, for this
+purpose — is proven by the client's own successful listing; Step 1's
+catalog/CVS existence check is for when resolvability itself is in question,
+so it doesn't apply here. Then Gate 2 **alone**:
+`jfs_curation_query_audit_events(package_type="npm", package_name="axios", package_version="1.15.1")`
+returns the blocked download event with the policy and CVEs — that **is** the
+root cause. If the user wants the remediation prose, add
+`jfs_curation_get_audit_event_policies(event_id)`.
+
+Answer the misconception without a compliance call: a `npm view` listing is what
+the client resolves against, **not** a per-version CVS approval — a locked/exact
+pin to a non-compliant version is refused at download with no fallback (fetch the
+CVS doc to cite this). You do **not** need `jfs_curation_check_remote_package_compliance` to
+conclude this, and you should not query the CVS audit to "prove approval" — CVS
+audit answering `all_versions_compliant` is a *different timeline and mechanism*
+and will confuse the 403 RCA. Only if the user then asks "what should I install
+instead?" and no allowed versions are already in hand does a compliance check (or
+the client's own suggested-versions notice) earn its place.
+
+## Gotchas
+
+- **MCP tools only.** Never substitute a `jf` command or raw HTTP for any
+ `jfs_curation_*` call. If a curation tool specifically is unavailable while
+ other JFrog MCP tools work, that's a version/entitlement gap, not a
+ disconnected server — see Preflight.
+- **Disjoint id-spaces / repo-name spelling.** CVS event ids go to
+ `jfs_curation_get_cvs_audit_version_detail`, package-audit ids to
+ `jfs_curation_get_audit_event_policies` (crossing them returns nothing). CVS uses
+ `curated_repo_name`; package audit uses `curated_repository_name`.
+- **Don't over-attribute to curation.** The most common `ETARGET` cause is a
+ version that never existed, or a client-side config filter — always complete
+ Step 1 before blaming curation.
diff --git a/skills/jfrog-reference-architecture/SKILL.md b/skills/jfrog-reference-architecture/SKILL.md
index 394d000..b331b24 100644
--- a/skills/jfrog-reference-architecture/SKILL.md
+++ b/skills/jfrog-reference-architecture/SKILL.md
@@ -11,7 +11,7 @@ description: >-
Do NOT use for artifact search or download, repository or permission admin,
CVE or vulnerability lookups, live jf CLI operations against their instance,
or package curation — use the jfrog base skill or
- jfrog-package-safety-and-download instead.
+ jfrog-package-curation instead.
compatibility: >-
Requires outbound HTTPS (WebFetch or equivalent). Request full_network when
the runtime blocks fetches. No jf CLI or configured JFrog instance required
diff --git a/skills/jfrog/SKILL.md b/skills/jfrog/SKILL.md
index 902d453..460d111 100644
--- a/skills/jfrog/SKILL.md
+++ b/skills/jfrog/SKILL.md
@@ -19,7 +19,7 @@ compatibility: >-
(CLI) and Tier 3 (jf api) operations; without it, only MCP (Tier 1) is available.
metadata:
role: base
- version: "0.30.0"
+ version: "0.31.1"
---
# JFrog Skill
diff --git a/skills/jfrog/references/INDEX.md b/skills/jfrog/references/INDEX.md
index c005c53..b40a61f 100644
--- a/skills/jfrog/references/INDEX.md
+++ b/skills/jfrog/references/INDEX.md
@@ -50,7 +50,9 @@ for one operation.
- **Watches, policies, violations, components, or vulnerability scanning (concepts)**: read `references/xray-entities.md`
- **Exposures scanning results (secrets, IaC, service misconfigurations, application security risks)**: read `references/xray-entities.md` § Exposures (Advanced Security)
-- **Curation audit events (approved/blocked packages, dry-run policy evaluations, curation export)**: read `references/xray-entities.md` § Curation audit events
+- **Package install/resolve/download failure blamed on Curation — 403 from a curated remote, `ETARGET` / "no matching version", a version missing from the index, "why was package X blocked?", or a waiver after a block**: load the `jfrog-package-curation` workflow skill and follow its "Troubleshoot a failure" section (index-time CVS audit + download-time package audit → root cause + remediation, MCP only). Its "Check & download" section instead handles proactive "is this package safe to download?".
+- **Is this package safe / allowed / curated? Downloading npm, Maven, PyPI, Go, or similar packages via JFrog**: load the `jfrog-package-curation` workflow skill and follow its "Check & download" section.
+- **Curation audit events (approved/blocked packages, dry-run policy evaluations, curation export) without a failure to triage**: read `references/xray-entities.md` § Curation audit events
## Release lifecycle & distribution
@@ -60,7 +62,7 @@ for one operation.
## Catalog
- **Public or custom catalog, package metadata, vulnerability advisories, licenses, OpenSSF, or MCP services (concepts)**: if the JFrog MCP server exposes a catalog tool, prefer it for single-package lookups. For deeper queries, read `references/catalog-entities.md`
-- **CVE details, vulnerability lookup by CVE ID, or severity/affected-packages/fix-versions for a specific CVE**: prefer an MCP vulnerability-lookup tool if the JFrog MCP server exposes one. Otherwise read `references/onemodel-query-examples.md` § *Public security domain* for the `searchVulnerabilities` query shape — this is self-contained; do not load the `jfrog-package-safety-and-download` skill for pure CVE lookups
+- **CVE details, vulnerability lookup by CVE ID, or severity/affected-packages/fix-versions for a specific CVE**: prefer an MCP vulnerability-lookup tool if the JFrog MCP server exposes one. Otherwise read `references/onemodel-query-examples.md` § *Public security domain* for the `searchVulnerabilities` query shape — this is self-contained; do not load the `jfrog-package-curation` skill for pure CVE lookups
## OneModel (GraphQL)
From a2ba544afb2e36742865a398d9373fa9afb7776c Mon Sep 17 00:00:00 2001
From: Michael Sverdlov
Date: Thu, 27 Aug 2026 17:51:51 +0300
Subject: [PATCH 2/2] Align plugin docs with renamed v0.31.1 skill directories.
---
README.md | 12 ++++++------
VENDOR.md | 2 +-
2 files changed, 7 insertions(+), 7 deletions(-)
diff --git a/README.md b/README.md
index a63bba3..eab89e9 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
JFrog plugin for [Devin](https://devin.ai/): JFrog Platform skills for artifact management, security scanning, and supply-chain workflows, plus the JFrog Platform MCP server (remote HTTP + OAuth).
-> **Current version:** `0.3.0` — skills from [jfrog/jfrog-skills](https://github.com/jfrog/jfrog-skills) (pinned at `v0.25.0`) and a bundled JFrog MCP entry.
+> **Current version:** `0.3.0` — skills from [jfrog/jfrog-skills](https://github.com/jfrog/jfrog-skills) (pinned at `v0.31.1`) and a bundled JFrog MCP entry.
## Skills
@@ -11,10 +11,10 @@ JFrog plugin for [Devin](https://devin.ai/): JFrog Platform skills for artifact
| `jfrog` | JFrog Platform operations via CLI and APIs (Artifactory, Xray, access, projects, and more). |
| `jfrog-init` | Plugin readiness / setup (detect CLI, config, MCP, and related bootstrap steps). |
| `jfrog-mcp-management` | Install, list, and remove MCP servers through JFrog Agent Guard; browse the JFrog MCP catalog. |
-| `jfrog-ai-catalog-skills` | Discover, install, manage, and publish agent skills from the JFrog AI Catalog via `jf skills` and Agent Guard. |
+| `jfrog-ai-catalog` | Discover, install, manage, and publish agent skills from the JFrog AI Catalog via `jf skills` and Agent Guard. |
| `jfrog-setup-package-managers` | Bind package managers (npm, pip, Maven, Go, and more) to JFrog Artifactory via `jf setup`. |
| `jfrog-reference-architecture` | JFrog Platform topology, sizing, deployment patterns, and multi-site guidance. |
-| `jfrog-package-safety-and-download` | Check package safety and download via Artifactory. |
+| `jfrog-package-curation` | Check package safety and download via Artifactory. |
After install, Devin exposes them as `/jfrog:` (for example `/jfrog:jfrog-mcp-management`).
@@ -44,7 +44,7 @@ The plugin registers this MCP server (declared in `mcp.json` and referenced from
- **Devin CLI** — see [Devin docs](https://docs.devin.ai/)
- **Devin CLI plugins enabled** for your organization (`devin plugins install` must be allowed)
- **`JFROG_PLATFORM_URL`** — JFrog platform host only (no `https://`, no trailing `/`). Required for the bundled MCP entry.
-- **Skill runtime** (when using the skills) — `jf` CLI, `jq`, and `curl` on `PATH`, plus a configured JFrog instance (`jf config add`). See [jfrog-skills requirements](https://github.com/jfrog/jfrog-skills/blob/v0.25.0/README.md#requirements).
+- **Skill runtime** (when using the skills) — `jf` CLI, `jq`, and `curl` on `PATH`, plus a configured JFrog instance (`jf config add`). See [jfrog-skills requirements](https://github.com/jfrog/jfrog-skills/blob/v0.31.1/README.md#requirements).
## Installation
@@ -79,10 +79,10 @@ devin-plugin/
│ ├── jfrog/
│ ├── jfrog-init/
│ ├── jfrog-mcp-management/
-│ ├── jfrog-ai-catalog-skills/
+│ ├── jfrog-ai-catalog/
│ ├── jfrog-setup-package-managers/
│ ├── jfrog-reference-architecture/
-│ └── jfrog-package-safety-and-download/
+│ └── jfrog-package-curation/
├── .github/scripts/ # sync-skills vendoring
├── LICENSE
├── README.md
diff --git a/VENDOR.md b/VENDOR.md
index c93540c..329885b 100644
--- a/VENDOR.md
+++ b/VENDOR.md
@@ -7,7 +7,7 @@ The skill packages under `skills/` are vendored from **[jfrog/jfrog-skills](http
| **Repository** | https://github.com/jfrog/jfrog-skills |
| **Pinned release** | see `pin` in [`.github/scripts/sync-skills-vendor.json`](.github/scripts/sync-skills-vendor.json) |
-Included directories (as of the pinned release): `jfrog/`, `jfrog-init/`, `jfrog-ai-catalog-skills/`, `jfrog-mcp-management/`, `jfrog-package-safety-and-download/`, `jfrog-reference-architecture/`, `jfrog-setup-package-managers/`.
+Included directories (as of the pinned release): `jfrog/`, `jfrog-init/`, `jfrog-ai-catalog/`, `jfrog-mcp-management/`, `jfrog-package-curation/`, `jfrog-reference-architecture/`, `jfrog-setup-package-managers/`.
## Refreshing