{"id":50698,"plugin_id":"plugin_asdk_app_6ac2713d52dc8191913b283379e39840","kind":"skill","collection_source":"plugin_package","comparison_source":null,"observed_at":"2026-10-24T13:44:06.165Z","digest":"6c8f58a9d504d2c3333f12515cfe0e5c31e37d90e06787e230d908f47358a933","against":null,"payload":{"description":"Use when uploading locally trained model weights (YOLO, RF-DETR, YOLO-NAS, PaliGemma, Florence-2) to Roboflow — the client-side Python SDK upload flow, safe API key handling, per-family packaging requirements, and verifying the upload.","included_files":[],"name":"roboflow-custom-weights-upload","skill_md_contents":"---\nname: roboflow-custom-weights-upload\ndescription: Use when uploading locally trained model weights (YOLO, RF-DETR, YOLO-NAS, PaliGemma, Florence-2) to Roboflow — the client-side Python SDK upload flow, safe API key handling, per-family packaging requirements, and verifying the upload.\n---\n\n> **For agents:** This skill is authored in [`roboflow/computer-vision-skills`](https://github.com/roboflow/computer-vision-skills). If your client already has it loaded as a skill (for example from a Roboflow plugin), use that copy. The `roboflow://skills/<name>/...` MCP resources serve the same skills for clients that don't have them loaded.\n\n# Custom Weights Upload\n\nRegister weights from a model trained outside Roboflow (a laptop, a training\nserver, Colab) so Roboflow can convert, host, and serve it.\n\n## Where the upload runs\n\nPackaging reads the checkpoint from disk, so the upload always runs on the\nmachine that has the weights — client-side, with the Python SDK flow below.\n\nThe `models_custom_weights_upload_guide` MCP tool is a guide, not an uploader:\ncalling it returns this recipe and echoes back the arguments you passed\n(its `upload_mode` field says whether they describe a versioned or a\nworkspace upload, or `undetermined` when they pin down neither). It never\npackages or uploads anything, because the MCP server cannot read the user's\nfilesystem.\n\n## Client-side upload with the Python SDK\n\nRun this on the machine that has the weights, ideally in the same Python\nenvironment used for training (it already has `torch` and the matching\n`ultralytics`).\n\n1. **Install the SDK**: both `roboflow>=1.3.13` and `rfdetr` require\n   **Python >= 3.10**; check `python3 --version` first (macOS ships 3.9). If\n   it is too old, create a venv: `uv venv --python 3.12 && source\n   .venv/bin/activate`. Then `pip install \"roboflow>=1.3.13\"`.\n2. **Handle the API key safely**: never ask the user to paste a private API\n   key into chat, and never scan dotfiles, shell profiles, or config files\n   hunting for one — permission systems rightly block that. If\n   `ROBOFLOW_API_KEY` is already set in the environment\n   (`test -n \"$ROBOFLOW_API_KEY\"`) or the working project has a `.env` that\n   defines it, use it. Otherwise mint a scoped key with the MCP\n   `api_keys_create` tool — it returns the secret once (`api_keys_roll` is\n   the only other tool that does; `api_keys_list` / `api_keys_get` return\n   masked metadata) — and write it yourself to a `.gitignore`'d `.env` as\n   `ROBOFLOW_API_KEY`. Writing `.env` does not populate `os.environ`: load it\n   before running. For a `.env` you just wrote yourself,\n   `set -a; source .env; set +a` is fine. For a pre-existing `.env`, never\n   `source` it — sourcing executes any shell in the file and exports every\n   other secret it holds into the process. Read only the one key instead,\n   e.g. with `python-dotenv` (`pip install python-dotenv`) in the script:\n\n   ```python\n   import os\n   from dotenv import dotenv_values\n\n   os.environ[\"ROBOFLOW_API_KEY\"] = dotenv_values(\".env\")[\"ROBOFLOW_API_KEY\"]\n   ```\n\n   Scope the key for the whole deploy flow, not minimally: the SDK's\n   `rf.workspace()` reads the workspace and its project list before\n   deploying, so `project:read` plus `model:deploy` alone fails with missing\n   permissions. Include `workspace:read`, `project:read`, `model:deploy`,\n   and for a versioned deploy also `version:read` and `version:update`.\n   Getting the scopes right at mint time is what protects the upload: the\n   preflight below only confirms the key and the workspace read, not the\n   deploy scope.\n\n   If the `api_keys_create` call is denied (permission systems may flag\n   credential creation during an upload task) or unavailable, do not work\n   around the denial. Ask the user to choose: (a) explicitly authorize\n   minting a temporary scoped key, which you revoke with `api_keys_revoke`\n   after the upload; (b) set `ROBOFLOW_API_KEY` themselves in their shell or\n   a `.env`; or (c) point you at an existing `.env` that already defines it.\n3. **Confirm the destination and the name with the user**: registering a\n   model is not easily undone. Never infer the target project or version from\n   the checkpoint's class count or filename — ask. The same goes for\n   `model_name` on a workspace upload: ask the user what the model should be\n   called; do not invent a name.\n\n### Preflight before packaging\n\nPackaging plus a 100 MB+ upload is slow; run the cheap checks first and\nreport every gap at once instead of failing one step at a time:\n\n1. Python is >= 3.10 (`python3 --version`).\n2. Required imports load: `torch` for YOLO, RF-DETR, and YOLO-NAS;\n   `ultralytics` for YOLO v8/v10/v11/v12/26; `rfdetr>=1.8.0` for raw\n   PyTorch-Lightning RF-DETR checkpoints.\n3. The key is valid and covers the workspace read — one cheap call that\n   exercises the same workspace/project-list read `deploy_model` starts with:\n\n   ```python\n   import os\n   from roboflow import Roboflow\n\n   Roboflow(api_key=os.environ[\"ROBOFLOW_API_KEY\"]).workspace()\n   ```\n\n   Be honest about the limit of this check: it does not exercise\n   `model:deploy`, which the platform only tests at `models/prepareUpload`,\n   after packaging. That is why step 2 mints the key with the full scope set\n   up front — the preflight catches a bad or under-read key, not a missing\n   deploy scope on an existing key.\n\nOnly package and upload after all three pass.\n\nWorkspace model upload (no dataset version required):\n\n```python\nimport os\nfrom roboflow import Roboflow\n\nrf = Roboflow(api_key=os.environ[\"ROBOFLOW_API_KEY\"])\nworkspace = rf.workspace(\"WORKSPACE_SLUG\")\nworkspace.deploy_model(\n    model_type=\"rfdetr-base\",\n    model_path=\"/path/to/training/output\",\n    project_ids=[\"PROJECT_SLUG\"],\n    model_name=\"MODEL_NAME\",\n    filename=\"checkpoint_best_total.pth\",  # relative to model_path\n)\n```\n\nVersioned deploy (attach weights to an existing dataset version):\n\n```python\nimport os\nfrom roboflow import Roboflow\n\nrf = Roboflow(api_key=os.environ[\"ROBOFLOW_API_KEY\"])\nversion = rf.workspace(\"WORKSPACE_SLUG\").project(\"PROJECT_SLUG\").version(3)\nversion.deploy(\n    model_type=\"yolov8n\",\n    model_path=\"/path/to/runs/detect/train\",\n    filename=\"weights/best.pt\",\n)\n```\n\n`model_type` must name the real architecture (`yolov8n`, `yolov11s`,\n`rfdetr-base`, `rfdetr-seg-medium`, `yolonas`, a supported PaliGemma or\nFlorence-2 type). For YOLO families the SDK infers a missing size suffix\nfrom the weights; RF-DETR accepts no bare `rfdetr` — pass the exact variant,\nwhich the SDK cross-checks against the checkpoint.\n\nOn a size/variant or dependency mismatch, `deploy_model` / `version.deploy`\nprint the error and then **interactively prompt** \"Would you like to continue\nanyway? y/n\" — in a headless run the prompt surfaces as an `EOFError` right\nafter the printed error. Recover by error type:\n\n- **Size/variant mismatch**: when the error names the type that fits, fix\n  `model_type` to it and rerun; when it says the size could not be inferred,\n  pass an explicit size.\n- **Dependency mismatch**: the error names a pip pin, not a model type\n  (`yolov8` recommends `ultralytics==8.0.196`, so most current training\n  environments hit this prompt). Install the named version, or — only with\n  the user's explicit confirmation — answer `y` (headless:\n  `printf 'y\\n' | python upload.py`) to continue with the installed version.\n\nNever force past either prompt without the user explicitly confirming the\noverride is intentional.\n\n## Per-family requirements\n\n- **YOLO v8/v10/v11/v12/YOLO26**: needs `torch` and `ultralytics` importable\n  (`yolov8` recommends `ultralytics==8.0.196`; see the dependency-mismatch\n  note above). **Legacy YOLO v5/v7/v9**: needs `torch` plus an `opt.yaml` in\n  `model_path` with `imgsz` (or `img_size`) and `batch_size`; `ultralytics`\n  is not used. There is no yolov6 support.\n- **RF-DETR**: needs `torch` to read the checkpoint. If a `class_names.txt`\n  (one class per line) sits in `model_path` it is used; otherwise class names\n  come from the checkpoint's `args`. Raw PyTorch-Lightning checkpoints\n  additionally need `rfdetr>=1.8.0` installed (the SDK's error names the\n  exact minimum if yours is older). An explicit `filename` that does not\n  exist is a hard error; the default `weights/best.pt` falls back to the\n  first top-level `.pt`/`.pth` file, with a warning.\n- **YOLO-NAS**: `model_type=\"yolonas\"` plus an `opt.yaml` in `model_path`\n  with `imgsz`, `batch_size`, and `architecture`.\n- **PaliGemma / Florence-2**: `model_path` is the Hugging Face save directory\n  (config, tokenizer, and weights files); no `torch` needed.\n\n## Verify the upload\n\nConversion runs server-side after the upload and usually takes a few minutes.\nCheck it with the MCP `models_list` / `models_get` tools or at\n`app.roboflow.com/WORKSPACE/PROJECT/models`, then run a test inference on a\nsample image to confirm classes and predictions look right.\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}