Roboflow manages computer vision datasets and model deployment. pip install roboflow. rf = roboflow.Roboflow(api_key="KEY"). workspace = rf.workspace("my-workspace"). project = workspace.project("defect-detection"). version = project.version(3). Download dataset: dataset = version.download("yolov8") — returns local path. Train with ultralytics: from ultralytics import YOLO, model = YOLO("yolov8n.pt"), model.train(data=f"{dataset.location}/data.yaml", epochs=100, imgsz=640). Validate: model.val(). Export: model.export(format="onnx"). Deploy to Roboflow Hosted API: project.deploy(model_type="yolov8", model_path="runs/detect/train/weights/best.pt"). Inference: model = project.version(3).model, prediction = model.predict("image.jpg", confidence=40, overlap=30).json(). model.predict("image.jpg").save("output.jpg"). Upload images for active learning: project.upload("new_image.jpg", annotation_path="new_image.xml", batch_name="active_learning_batch"). Augmentation preview: version.download("yolov8", location="./dataset") applies the augmentations configured in Roboflow UI (flip, rotate, crop, mosaic, cutout). Export formats: "yolov8", "coco", "voc", "tensorflow", "tfrecord", "createml". workspace.list_projects() shows all projects. project.get_annotations_stats() shows label distribution. version.generate_version(settings={"preprocessing": {...}, "augmentation": {...}}) creates a new dataset version programmatically. Hosted API inference: POST /detect/{model_id}?api_key=KEY with image as form data. Claude Code generates Roboflow dataset pipelines, YOLO training scripts, active learning uploads, augmentation configs, and TypeScript inference clients.
CLAUDE.md for Roboflow
## Roboflow Stack
- SDK: roboflow >= 1.1 + ultralytics >= 8.2 for YOLO training
- Init: Roboflow(api_key) → workspace(slug) → project(slug) → version(n)
- Download: version.download("yolov8") → dataset.location/data.yaml
- Train: YOLO("yolov8n.pt").train(data=data.yaml, epochs=100, imgsz=640)
- Deploy: project.deploy(model_type="yolov8", model_path="best.pt")
- Infer: project.version(n).model.predict(image).json()
- Upload: project.upload(image, annotation_path, batch_name)
- Export: "yolov8"/"coco"/"voc"/"tensorflow"/"tfrecord"
Dataset Pipeline
# cv/roboflow_pipeline.py — dataset management and YOLO training
from __future__ import annotations
import json
import os
from pathlib import Path
import roboflow
from roboflow import Roboflow
RF_API_KEY = os.environ.get("ROBOFLOW_API_KEY", "")
WORKSPACE = os.environ.get("ROBOFLOW_WORKSPACE", "my-workspace")
def get_project(project_slug: str, version_num: int = 1):
"""Get a Roboflow project version."""
rf = Roboflow(api_key=RF_API_KEY)
workspace = rf.workspace(WORKSPACE)
project = workspace.project(project_slug)
return project, project.version(version_num)
# ── Dataset download ─────────────────────────────────────────────────────────
def download_dataset(
project_slug: str,
version_num: int = 1,
export_fmt: str = "yolov8",
location: str = "./datasets",
) -> str:
"""Download a dataset in the specified format."""
_, version = get_project(project_slug, version_num)
dataset = version.download(export_fmt, location=location)
print(f"Dataset downloaded: {dataset.location}")
print(f"Classes: {dataset.classes}")
return dataset.location
# ── YOLO training with ultralytics ───────────────────────────────────────────
def train_yolo(
project_slug: str,
version_num: int = 1,
model_size: str = "yolov8m", # n/s/m/l/x
epochs: int = 100,
imgsz: int = 640,
batch: int = 16,
pretrained: bool = True,
device: str = "0", # GPU id or "cpu"
) -> str:
"""Download dataset and train YOLO model."""
from ultralytics import YOLO
# Download dataset
dataset_dir = download_dataset(project_slug, version_num, "yolov8")
data_yaml = f"{dataset_dir}/data.yaml"
# Load pretrained model and fine-tune
weights_path = f"{model_size}.pt" if pretrained else f"{model_size}.yaml"
model = YOLO(weights_path)
results = model.train(
data=data_yaml,
epochs=epochs,
imgsz=imgsz,
batch=batch,
device=device,
project="runs/detect",
name=f"{project_slug}_v{version_num}",
save=True,
workers=8,
optimizer="AdamW",
lr0=0.001,
lrf=0.01,
warmup_epochs=3,
close_mosaic=10,
)
best_weights = str(Path(results.save_dir) / "weights" / "best.pt")
print(f"\nTraining complete. Best weights: {best_weights}")
print(f"mAP50: {results.maps[0]:.4f}")
return best_weights
# ── Deploy to Roboflow Hosted API ─────────────────────────────────────────────
def deploy_model(
project_slug: str,
weights_path: str,
model_type: str = "yolov8",
version_num: int = 1,
) -> None:
"""Upload trained weights to Roboflow for inference hosting."""
project, _ = get_project(project_slug, version_num)
project.deploy(
model_type=model_type,
model_path=weights_path,
)
print(f"Model deployed to Roboflow Hosted API for project '{project_slug}'")
# ── Inference ────────────────────────────────────────────────────────────────
def run_inference(
project_slug: str,
version_num: int,
image_path: str,
confidence: int = 40,
overlap: int = 30,
save_output: bool = True,
) -> list[dict]:
"""Run inference using Roboflow Hosted API."""
_, version = get_project(project_slug, version_num)
model = version.model
prediction = model.predict(image_path, confidence=confidence, overlap=overlap)
if save_output:
out_path = image_path.replace(".", "_prediction.")
prediction.save(out_path)
print(f"Annotated image saved: {out_path}")
result = prediction.json()
print(f"Found {len(result.get('predictions', []))} objects:")
for pred in result.get("predictions", []):
print(f" {pred['class']} ({pred['confidence']:.2f}) @ "
f"({pred['x']:.0f},{pred['y']:.0f}) {pred['width']:.0f}×{pred['height']:.0f}")
return result.get("predictions", [])
# ── Active learning upload ────────────────────────────────────────────────────
def upload_for_active_learning(
project_slug: str,
image_paths: list[str],
annotation_dir: str | None = None,
batch_name: str = "active_learning",
) -> None:
"""Upload unlabeled images to Roboflow for annotation."""
project, _ = get_project(project_slug)
for image_path in image_paths:
annotation_path = None
if annotation_dir:
stem = Path(image_path).stem
for ext in [".xml", ".txt", ".json"]:
candidate = Path(annotation_dir) / f"{stem}{ext}"
if candidate.exists():
annotation_path = str(candidate)
break
try:
project.upload(
image_path=image_path,
annotation_path=annotation_path,
batch_name=batch_name,
is_prediction=annotation_path is not None,
)
status = "with annotation" if annotation_path else "unlabeled"
print(f"Uploaded {Path(image_path).name} ({status})")
except Exception as e:
print(f"Failed to upload {image_path}: {e}")
print(f"\nUploaded {len(image_paths)} images to batch '{batch_name}'")
# ── Dataset statistics ────────────────────────────────────────────────────────
def print_dataset_stats(project_slug: str, version_num: int = 1) -> None:
"""Print label distribution and dataset overview."""
project, version = get_project(project_slug, version_num)
stats = project.get_annotations_stats()
print(f"\nProject: {project_slug}")
print(f"Version: {version_num}")
print(f"Total images: {stats.get('total', 0)}")
print("\nLabel distribution:")
for label, count in sorted(
stats.get("labels", {}).items(), key=lambda x: -x[1]
):
print(f" {label}: {count}")
if __name__ == "__main__":
# Example workflow
print_dataset_stats("defect-detection", version_num=3)
weights = train_yolo("defect-detection", version_num=3, epochs=50)
deploy_model("defect-detection", weights)
TypeScript Inference Client
// lib/roboflow/client.ts — Roboflow Hosted API TypeScript client
const RF_API_KEY = process.env.ROBOFLOW_API_KEY ?? ""
const RF_API_URL = "https://detect.roboflow.com"
export type RoboflowPrediction = {
x: number
y: number
width: number
height: number
confidence: number
class: string
class_id: number
detection_id: string
}
export type RoboflowResponse = {
predictions: RoboflowPrediction[]
image: { width: number; height: number }
time: number
}
/** Detect objects in an image URL using Roboflow Hosted API */
export async function detect(
modelId: string,
versionNum: number,
imageUrl: string,
confidence: number = 40,
overlap: number = 30,
): Promise<RoboflowResponse> {
const url = `${RF_API_URL}/${modelId}/${versionNum}` +
`?api_key=${RF_API_KEY}&confidence=${confidence}&overlap=${overlap}` +
`&image=${encodeURIComponent(imageUrl)}`
const res = await fetch(url, { method: "POST" })
if (!res.ok) throw new Error(`Roboflow ${res.status}: ${await res.text()}`)
return res.json()
}
/** Detect from base64-encoded image */
export async function detectBase64(
modelId: string,
versionNum: number,
base64Image: string,
confidence: number = 40,
): Promise<RoboflowResponse> {
const url = `${RF_API_URL}/${modelId}/${versionNum}?api_key=${RF_API_KEY}&confidence=${confidence}`
const res = await fetch(url, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: base64Image,
})
if (!res.ok) throw new Error(`Roboflow ${res.status}: ${await res.text()}`)
return res.json()
}
For the Label Studio alternative when needing a fully customizable annotation platform for multi-modal data (text, images, audio, video, time series) with an ML backend for pre-labeling and a self-hosted web UI accessible to non-technical annotators — Label Studio is more general-purpose while Roboflow is purpose-built for computer vision with tighter YOLO/ultralytics integration, built-in augmentation pipelines configured via a UI, and one-click Hosted API deployment for image/video inference. For the CVAT (Computer Vision Annotation Tool) alternative when needing free, open-source annotation for video tracking, semi-automatic annotation with OpenCV/DL, and enterprise features via CVAT Cloud without per-image pricing — CVAT handles video tracking use cases better while Roboflow’s dataset versioning, augmentation pipeline builder, and public dataset universe make it the better choice for teams training and iterating on YOLO models. The Claude Skills 360 bundle includes Roboflow skill sets covering dataset download, YOLO training scripts, active learning uploads, deployment, and TypeScript inference clients. Start with the free tier to try computer vision pipeline generation.