JFrog — Setup Package Managers for Artifactory
Apply the session hook's repo pick via jf setup,
then record it in .jfrog/local/package-resolution.json.
jf setup writes package-manager-native config (.npmrc, pip.conf, uv.toml, …); the binding
lets the hook re-apply on later sessions.
Scope (this skill vs session hook)
Session-start hook: resolves repo keys per package type, injects the
"Resolved URLs for this session" table, refreshes the global cache. The same
renderer is available on demand via modules/package-resolution/scripts/print-policy.mjs (the enforce
notice embeds the exact command), so the policy can be loaded after setup.
This skill: reads that output, runs jf setup, and persists the workspace
binding at .jfrog/local/package-resolution.json when package-manager config is still missing.
Honor the injected policy's governed scope. The session policy lists the
package managers it governs. Do not proactively onboard a package manager the policy
doesn't govern (e.g. a stray Dockerfile when only pypi/npm are governed) —
those are intentionally out of scope. An explicit user request to set up any
package manager still works (Step 1's user-mention signal and Step 2's AskQuestion for an
unlisted package manager apply as usual).
Prerequisites
jf setup mutates user state (~/.npmrc, ~/.docker/config.json, …).
Confirm before the first jf setup in a session unless the user explicitly
requests silent/non-interactive setup.
- Reading
../jfrog/SKILL.md is required — done as Step 0.1 below.
Out of scope: CLI install/login (../jfrog/references/…).
Gotchas
- Always pass
--repo and --server-id — omitting --repo fails when
multiple repos match. See jf-setup-command.md.
jf setup overwrites package-manager config without backup — skip package managers whose binding
already matches (Step 1, signal 2).
- Docker / Podman — prefix or stop.
jf setup docker writes creds only;
bare docker pull <img> hits Docker Hub. Complete setup, then pull via
<host>/<repoKey>/<img>.
- Binding holds decisions, not credentials — never write tokens into
.jfrog/local/package-resolution.json.
gradle ≠ maven. Bind under repositories.gradle, never repositories.maven.
- Yarn / Poetry — not APR zero-touch; bind only on explicit user ask (Step 1).
References
| File |
When to read |
references/jf-setup-command.md |
CLI flags, supported package managers, exit-code contract, jf setup --help |
references/global-cache-file.md |
Global cache shape, resolution classes, jq one-liners |
references/workspace-binding.md |
Workspace binding schema, package-manager → type map, merge semantics |
Step 0 — Read the base skill, then ensure jf is ready
- Read
../jfrog/SKILL.md fully first — always, before any
jf command, even when jf is already configured. It carries the jf
invariants this skill relies on. After reading, run that skill's
Environment check (and export JFROG_CLI_USER_AGENT) before the first
jf call.
- Ensure
jf + a configured server (<SID>). If jf config show already
succeeds, skip to Step 1; otherwise:
- Do not run
jf setup until both succeed. Confirm before install/login.
Step 1 — Identify package managers to bind
Combine four signals, in order; intersect with jf setup --help supported list:
Explicit user mention. Map aliases: python → pip/uv/pipenv (and
poetry only if the user named Poetry); java → maven/gradle; node →
npm/pnpm by lockfile (yarn only if the user named Yarn).
Workspace binding — read .jfrog/local/package-resolution.json. Drop
package managers already bound to the same key unless recovering from 401/403
(re-run same key). Package-manager → type table:
workspace-binding.md.
Workspace manifests when still ambiguous (several package managers of one
type may apply — e.g. requirements.txt and uv.lock):
| Manifest / signal |
Package manager |
package.json, pnpm-lock.yaml |
npm (+ pnpm if pnpm-lock.yaml present) |
yarn.lock (alone) |
npm — do not auto-select yarn |
requirements.txt |
pip |
Pipfile |
pipenv |
uv.lock |
uv — suppresses bare pyproject.toml → pip; keep requirements.txt + uv.lock as multi-PM |
pyproject.toml |
[tool.uv] → uv; [tool.poetry] → poetry only on explicit user ask, else not applicable (do not select pip); bare PEP 621 with no uv.lock → pip |
pom.xml |
maven |
build.gradle, build.gradle.kts |
gradle (bind under type gradle) |
go.mod |
go |
Dockerfile, compose.yaml, docker-compose.yml |
docker / podman |
*.csproj, NuGet.Config |
nuget / dotnet |
Chart.yaml |
helm |
Binary gate (client tools only): missing client on PATH → skip as not
applicable; do not substitute another package manager or report setup
success. Exempt maven / gradle (config-only). Details:
jf-setup-command.md.
jf setup --help — filter candidates; never hardcode the list. See
jf-setup-command.md. Unsupported → report
gap, skip.
Step 2 — Get the resolved repo
For each <package-manager>, recover <repoKey> and <serverId> from the first source
available:
- "Resolved URLs for this session" table (default). Parse
<repoKey>
from URL; <serverId> from host.
- Workspace binding — if table was trimmed.
repositories.<type>
(gradle → repositories.gradle, not maven).
- Global cache — last resort only; never overrides (1) or (2). See
global-cache-file.md.
Cache disagreeing with (1)/(2) is not a reason to change the repo.
Don't choose a repo yourself: no listing, enumerating, probing, or iterating
--server-id to pick one, and don't second-guess the resolver — use resolver
output only. If the user explicitly asks to browse repos, list them via
jf api "/artifactory/api/repositories?type=virtual&packageType=<pkgType>"
(Artifactory package type from the binding map — gradle not maven;
uv / pip / pipenv / poetry → pypi), then let the user choose; the
agent still never makes the choice on its own.
Unresolved repo key
Ask via AskQuestion (include the resolver/setup failure text verbatim):
No default repo for <package-manager> on <SID>.
Failure: <verbatim failure>
Which Artifactory repository should I use? (repo key, or abort.)
Cap at 2 answers per package manager, then abort. User may override repo only, never server.
Step 3 — Confirm, run jf setup, persist binding
Present the plan, one row per package manager:
<package-manager> → <repoKey> on <SID> (source: resolver)
<package-manager> → <repoKey> on <SID> (source: user-supplied)
Show binding diffs when the repo key changes.
Confirm via AskQuestion (apply / change repos / abort) unless the
user explicitly requested silent/non-interactive setup — then run directly.
Sequentially, one package manager at a time:
jf setup <package-manager> --server-id <SID> --repo <repoKey> [--project <key>]
Exit code 0 = success — merge binding (step 6). On non-zero, stop,
surface CLI output verbatim, offer alternate repo or abort (2-answer cap).
On success, merge into .jfrog/local/package-resolution.json per
workspace-binding.md:
{ "repositories": { "<pkgType>": "<repoKey>" } }
Map package manager → type via the reference table (gradle → gradle).
Merge atomically.
Step 4 — Load the routing policy
If this session started with the "routing NOT READY" (enforce) notice, that
notice includes a refresh command (node <plugin>/modules/package-resolution/scripts/print-policy.mjs).
After Step 3 succeeds, run that exact command and treat its stdout as the
authoritative, now-current policy — it prints the resolved Artifactory URLs and
hard rules. Continue the original request using those URLs.
If the command prints nothing, routing is off by config
(packageResolution.enabled is not true) — an admin opt-in. Report that to
the user and let them decide whether to enable it.
1---2name: jfrog-setup-package-managers-33description: Use this skill when the user asks to set up, configure, bind, or connect a package manager (npm, pip, uv, pipenv, maven, gradle, go, docker, helm, ...) to JFrog Artifactory via `jf setup` and `.jfrog/local/package-resolution.json`; when a workspace manifest exists with no matching binding entry; or when a session hook reports package-manager config missing. Skip when the binding already has the same repo key. Never pick a repo by discovery; use resolver output only (unless the user names or asks to browse repos). On unresolved or failed setup, ask with the failure verbatim — never switch servers.4---56# JFrog — Setup Package Managers for Artifactory78Apply the session hook's repo pick via [`jf setup`](references/jf-setup-command.md),9then record it in [`.jfrog/local/package-resolution.json`](references/workspace-binding.md).10`jf setup` writes package-manager-native config (`.npmrc`, `pip.conf`, `uv.toml`, …); the binding11lets the hook re-apply on later sessions.1213## Scope (this skill vs session hook)1415**Session-start hook:** resolves repo keys per package type, injects the16"Resolved URLs for this session" table, refreshes the global cache. The same17renderer is available on demand via `modules/package-resolution/scripts/print-policy.mjs` (the enforce18notice embeds the exact command), so the policy can be loaded after setup.1920**This skill:** reads that output, runs `jf setup`, and persists the workspace21binding at `.jfrog/local/package-resolution.json` when package-manager config is still missing.2223**Honor the injected policy's governed scope.** The session policy lists the24package managers it governs. Do **not** *proactively* onboard a package manager the policy25doesn't govern (e.g. a stray `Dockerfile` when only `pypi`/`npm` are governed) —26those are intentionally out of scope. An **explicit user request** to set up any27package manager still works (Step 1's user-mention signal and Step 2's AskQuestion for an28unlisted package manager apply as usual).2930## Prerequisites3132- `jf setup` **mutates user state** (`~/.npmrc`, `~/.docker/config.json`, …).33 Confirm before the first `jf setup` in a session unless the user explicitly34 requests silent/non-interactive setup.35- Reading [`../jfrog/SKILL.md`](../jfrog/SKILL.md) is required — done as Step 0.1 below.3637**Out of scope:** CLI install/login (`../jfrog/references/…`).3839## Gotchas4041- **Always pass `--repo` and `--server-id`** — omitting `--repo` fails when42 multiple repos match. See [`jf-setup-command.md`](references/jf-setup-command.md).43- **`jf setup` overwrites package-manager config** without backup — skip package managers whose binding44 already matches (Step 1, signal 2).45- **Docker / Podman — prefix or stop.** `jf setup docker` writes creds only;46 bare `docker pull <img>` hits Docker Hub. Complete setup, then pull via47 `<host>/<repoKey>/<img>`.48- **Binding holds decisions, not credentials** — never write tokens into49 `.jfrog/local/package-resolution.json`.50- **`gradle` ≠ `maven`.** Bind under `repositories.gradle`, never `repositories.maven`.51- **Yarn / Poetry** — not APR zero-touch; bind only on explicit user ask (Step 1).5253## References5455| File | When to read |56|------|--------------|57| [`references/jf-setup-command.md`](references/jf-setup-command.md) | CLI flags, supported package managers, exit-code contract, `jf setup --help` |58| [`references/global-cache-file.md`](references/global-cache-file.md) | Global cache shape, resolution classes, jq one-liners |59| [`references/workspace-binding.md`](references/workspace-binding.md) | Workspace binding schema, package-manager → type map, merge semantics |6061## Step 0 — Read the base skill, then ensure `jf` is ready62631. **Read [`../jfrog/SKILL.md`](../jfrog/SKILL.md) fully first — always, before any64 `jf` command, even when `jf` is already configured.** It carries the `jf`65 invariants this skill relies on. After reading, run that skill's66 *Environment check* (and export `JFROG_CLI_USER_AGENT`) before the first67 `jf` call.682. Ensure `jf` + a configured server (`<SID>`). If `jf config show` already69 succeeds, skip to Step 1; otherwise:70 - **`jf --version`** missing → install per71 [`../jfrog/references/jfrog-cli-install-upgrade.md`](../jfrog/references/jfrog-cli-install-upgrade.md).72 - **`jf config show`** empty → login per73 [`../jfrog/references/jfrog-login-flow.md`](../jfrog/references/jfrog-login-flow.md)74 or `jf config add` with access-token (Bearer-only).753. Do not run `jf setup` until both succeed. Confirm before install/login.7677## Step 1 — Identify package managers to bind7879Combine four signals, in order; intersect with `jf setup --help` supported list:80811. **Explicit user mention.** Map aliases: python → `pip`/`uv`/`pipenv` (and82 `poetry` only if the user named Poetry); java → `maven`/`gradle`; node →83 `npm`/`pnpm` by lockfile (`yarn` only if the user named Yarn).842. **Workspace binding** — read `.jfrog/local/package-resolution.json`. Drop85 package managers already bound to the same key unless recovering from 401/40386 (re-run same key). Package-manager → type table:87 [`workspace-binding.md`](references/workspace-binding.md).883. **Workspace manifests** when still ambiguous (several package managers of one89 type may apply — e.g. `requirements.txt` **and** `uv.lock`):9091 | Manifest / signal | Package manager |92 |---|---|93 | `package.json`, `pnpm-lock.yaml` | `npm` (+ `pnpm` if `pnpm-lock.yaml` present) |94 | `yarn.lock` (alone) | `npm` — do **not** auto-select `yarn` |95 | `requirements.txt` | `pip` |96 | `Pipfile` | `pipenv` |97 | `uv.lock` | `uv` — suppresses bare `pyproject.toml` → `pip`; keep `requirements.txt` + `uv.lock` as multi-PM |98 | `pyproject.toml` | `[tool.uv]` → `uv`; `[tool.poetry]` → `poetry` only on explicit user ask, else **not applicable** (do not select `pip`); bare PEP 621 with **no** `uv.lock` → `pip` |99 | `pom.xml` | `maven` |100 | `build.gradle`, `build.gradle.kts` | `gradle` (bind under type **`gradle`**) |101 | `go.mod` | `go` |102 | `Dockerfile`, `compose.yaml`, `docker-compose.yml` | `docker` / `podman` |103 | `*.csproj`, `NuGet.Config` | `nuget` / `dotnet` |104 | `Chart.yaml` | `helm` |105106 **Binary gate (client tools only):** missing client on `PATH` → skip as not107 applicable; do **not** substitute another package manager or report setup108 success. **Exempt `maven` / `gradle`** (config-only). Details:109 [`jf-setup-command.md`](references/jf-setup-command.md).1101114. **`jf setup --help`** — filter candidates; never hardcode the list. See112 [`jf-setup-command.md`](references/jf-setup-command.md). Unsupported → report113 gap, skip.114115## Step 2 — Get the resolved repo116117For each `<package-manager>`, recover `<repoKey>` and `<serverId>` from the first source118available:1191201. **"Resolved URLs for this session"** table (default). Parse `<repoKey>`121 from URL; `<serverId>` from host.1222. **Workspace binding** — if table was trimmed. `repositories.<type>`123 (`gradle` → `repositories.gradle`, not `maven`).1243. **Global cache** — last resort only; never overrides (1) or (2). See125 [`global-cache-file.md`](references/global-cache-file.md).126127Cache disagreeing with (1)/(2) is not a reason to change the repo.128129**Don't choose a repo yourself:** no listing, enumerating, probing, or iterating130`--server-id` to pick one, and don't second-guess the resolver — use resolver131output only. If the user explicitly asks to browse repos, list them via132`jf api "/artifactory/api/repositories?type=virtual&packageType=<pkgType>"`133(Artifactory **package type** from the binding map — `gradle` not `maven`;134`uv` / `pip` / `pipenv` / `poetry` → `pypi`), then let the user choose; the135agent still never makes the choice on its own.136137### Unresolved repo key138139Ask via AskQuestion (include the resolver/setup failure text verbatim):140141> No default repo for `<package-manager>` on `<SID>`.142> Failure: `<verbatim failure>`143> Which Artifactory repository should I use? (repo key, or `abort`.)144145Cap at **2 answers per package manager**, then abort. User may override repo only, never server.146147## Step 3 — Confirm, run `jf setup`, persist binding1481491. Present the plan, one row per package manager:150151 ```text152 <package-manager> → <repoKey> on <SID> (source: resolver)153 <package-manager> → <repoKey> on <SID> (source: user-supplied)154 ```1551562. Show binding diffs when the repo key changes.1571583. **Confirm** via AskQuestion (`apply` / `change repos` / `abort`) unless the159 user explicitly requested silent/non-interactive setup — then run directly.1601614. Sequentially, one package manager at a time:162163 ```bash164 jf setup <package-manager> --server-id <SID> --repo <repoKey> [--project <key>]165 ```1661675. **Exit code `0` = success** — merge binding (step 6). On non-zero, **stop**,168 surface CLI output verbatim, offer alternate repo or `abort` (2-answer cap).1691706. On success, merge into `.jfrog/local/package-resolution.json` per171 [`workspace-binding.md`](references/workspace-binding.md):172173 ```json174 { "repositories": { "<pkgType>": "<repoKey>" } }175 ```176177 Map package manager → type via the reference table (`gradle` → `gradle`).178 Merge atomically.179180## Step 4 — Load the routing policy181182If this session started with the "routing NOT READY" (enforce) notice, that183notice includes a refresh command (`node <plugin>/modules/package-resolution/scripts/print-policy.mjs`).184After Step 3 succeeds, run that exact command and treat its stdout as the185authoritative, now-current policy — it prints the resolved Artifactory URLs and186hard rules. Continue the original request using those URLs.187188If the command prints nothing, routing is off by config189(`packageResolution.enabled` is not `true`) — an admin opt-in. Report that to190the user and let them decide whether to enable it.