Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Core ML, Create ML, Vision framework, Natural Language framework, on-device ML integration. Use when user wants image classification, text analysis, object detection, sound classification, model optimization, or custom model integration. Covers Core ML vs Foundation Models decision.
.claude/skills/rshankras-core-ml/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 92% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 131% | 0% |
| case-21 | ✗→✓ | ▲ Improved | 253% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 139% | 0% |
| case-06 | ✓→✓ | = Same ✓ | 245% | 0% |
Combined advisory, generator, and workflow skill for integrating machine learning into Apple platform apps. Covers Core ML model integration, Vision framework image analysis, NaturalLanguage framework text processing, Create ML training, and on-device model optimization.
Use this skill when the user:
Before generating code, determine which framework is appropriate.
@Generable structured output from natural languageapple-intelligence/foundation-models/ skill for implementationVNRecognizeTextRequestSearch for existing ML integration:
Glob: **/*Model*.swift, **/*Classifier*.swift, **/*Predictor*.swift, **/*.mlmodel, **/*.mlmodelc, **/*.mlpackage
Grep: "import CoreML" or "import Vision" or "import NaturalLanguage"If found, ask user:
Ask user via AskUserQuestion:
.mlmodel or .mlpackage into Xcode project navigator.mlmodelc at build time (optimized for device)swift// Option 1: Auto-generated class (simplest) let model = try MyImageClassifier(configuration: MLModelConfiguration()) // Option 2: Generic MLModel loading (flexible) let url = Bundle.main.url(forResource: "MyModel", withExtension: "mlmodelc")! let config = MLModelConfiguration() config.computeUnits = .all // CPU + GPU + Neural Engine let model = try MLModel(contentsOf: url, configuration: config) // Option 3: Async loading (recommended for large models) let model = try await MLModel.load(contentsOf: url, configuration: config)
swift// Type-safe prediction with auto-generated class let input = MyImageClassifierInput(image: pixelBuffer) let output = try model.prediction(input: input) print(output.classLabel) // "cat" print(output.classLabelProbs) // ["cat": 0.95, "dog": 0.04, ...] // Batch predictions let batch = MLArrayBatchProvider(array: inputs) let results = try model.predictions(from: batch)
| Capability | Request Class | Custom Model Needed? | |---|---|---| | Image classification | VNClassifyImageRequest | No (built-in) | | Object detection | VNDetectObjectsRequest (custom model) | Yes | | Face detection | VNDetectFaceRectanglesRequest | No | | Face landmarks | VNDetectFaceLandmarksRequest | No | | Text recognition (OCR) | VNRecognizeTextRequest | No | | Body pose | VNDetectHumanBodyPoseRequest | No | | Hand pose | VNDetectHumanHandPoseRequest | No | | Barcode detection | VNDetectBarcodesRequest | No | | Image saliency | VNGenerateAttentionBasedSaliencyImageRequest | No | | Horizon detection | VNDetectHorizonRequest | No | | Rectangle detection | VNDetectRectanglesRequest | No | | Image similarity | VNGenerateImageFeaturePrintRequest | No |
swift// Multiple requests on the same image let handler = VNImageRequestHandler(cgImage: cgImage, options: [:]) try handler.perform([ textRequest, // OCR faceRequest, // Face detection barcodeRequest // Barcode scanning ]) // Each request's results are populated independently
swiftlet tagger = NLTagger(tagSchemes: [.sentimentScore]) tagger.string = "This app is amazing!" let (tag, _) = tagger.tag(at: text.startIndex, unit: .paragraph, scheme: .sentimentScore) // tag?.rawValue == "0.9" (positive)
swiftlet language = NLLanguageRecognizer.dominantLanguage(for: "Bonjour le monde") // language == .french
swiftlet tokenizer = NLTokenizer(unit: .word) tokenizer.string = "Hello, world!" tokenizer.enumerateTokens(in: text.startIndex..<text.endIndex) { range, _ in print(text[range]) // "Hello" then "world" return true }
swiftlet tagger = NLTagger(tagSchemes: [.nameType]) tagger.string = "Tim Cook visited Apple Park in Cupertino." tagger.enumerateTags(in: text.startIndex..<text.endIndex, unit: .word, scheme: .nameType) { tag, range in if let tag, tag != .other { print("\(text[range]): \(tag.rawValue)") // "Tim": PersonalName, "Cook": PersonalName // "Apple Park": OrganizationName, "Cupertino": PlaceName } return true }
Reduces model size by lowering numerical precision:
pythonimport coremltools as ct from coremltools.models.neural_network import quantization_utils model = ct.models.MLModel("MyModel.mlmodel") # Float16 quantization (safe default) model_fp16 = quantization_utils.quantize_weights(model, nbits=16) model_fp16.save("MyModel_fp16.mlmodel") # Int8 quantization (aggressive, test accuracy) model_int8 = quantization_utils.quantize_weights(model, nbits=8) model_int8.save("MyModel_int8.mlmodel")
Reduces unique weight values using k-means clustering:
pythonfrom coremltools.optimize.coreml import palettize_weights, OpPalettizerConfig config = OpPalettizerConfig(nbits=4) model_palettized = palettize_weights(model, config)
Removes near-zero weights (sparse model):
pythonfrom coremltools.optimize.torch.pruning import MagnitudePruner, MagnitudePrunerConfig config = MagnitudePrunerConfig(target_sparsity=0.75) pruner = MagnitudePruner(model, config)
swiftlet config = MLModelConfiguration() // Best performance — let system choose CPU, GPU, or Neural Engine config.computeUnits = .all // CPU only — predictable latency, no GPU/NE contention config.computeUnits = .cpuOnly // CPU + Neural Engine — good balance, avoids GPU contention with UI config.computeUnits = .cpuAndNeuralEngine // CPU + GPU — when Neural Engine unavailable config.computeUnits = .cpuAndGPU
swiftfunc classify(_ image: UIImage) async throws -> String { let model = try await MLModelManager.shared.model(named: "Classifier") // Prediction runs off main thread via structured concurrency let input = try MLDictionaryFeatureProvider(dictionary: ["image": image.pixelBuffer!]) let result = try await Task.detached { try model.prediction(from: input) }.value return result.featureValue(for: "classLabel")?.stringValue ?? "unknown" }
swift// Process multiple images efficiently let inputs = images.map { MyModelInput(image: $0.pixelBuffer!) } let batch = MLArrayBatchProvider(array: inputs) let results = try model.predictions(from: batch) for i in 0..<results.count { let output = results.features(at: i) print(output.featureValue(for: "classLabel")?.stringValue ?? "") }
swift// Compile .mlmodel to .mlmodelc at install (not runtime) // This is done automatically when you add .mlmodel to Xcode target // For downloaded models, compile once and cache: let compiledURL = try MLModel.compileModel(at: downloadedModelURL) let permanentURL = appSupportDir.appendingPathComponent("MyModel.mlmodelc") try FileManager.default.copyItem(at: compiledURL, to: permanentURL)
Based on user's answer to configuration questions, select the appropriate template(s) from templates.md.
| Capability | Files Generated | |---|---| | Any Core ML | MLModelManager.swift | | Image classification | ImageClassifier.swift | | Text analysis | TextAnalyzer.swift | | Vision requests | VisionService.swift | | Custom model | ModelConfig.swift + model-specific predictor | | Camera + ML | CameraMLPipeline.swift |
Check project structure:
Sources/ exists -> Sources/ML/App/Services/ exists -> App/Services/ML/App/ exists -> App/ML/ML/After generation, provide:
ML/
├── MLModelManager.swift # Central model lifecycle management
├── ImageClassifier.swift # Vision-based image classification (if needed)
├── TextAnalyzer.swift # NaturalLanguage wrapper (if needed)
├── ModelConfig.swift # Compute unit configuration
└── VisionService.swift # Vision request pipeline (if needed).mlmodel file to Xcode project (if using custom model)Other measured skills in the registry, with their headline benchmark lift.