Important
This is the AI-based version of RawCull. The main and
version-3.0.0 branches require macOS 27, an Apple Silicon Mac, and Xcode 27
to build. For macOS 26, use version-2.3.4 or version-2.3.3.
RawCull is a native macOS photo review and culling application for Sony ARW RAW files. It combines fast embedded-preview loading with focus-point extraction, sharpness analysis, visual similarity, burst grouping, ratings, and selective export.
The application is written in Swift 6 and SwiftUI. Focused Swift packages own image parsing, analysis, AI inference, shared culling models, JSON encoding, and rsync execution. RawCull owns application state, workflow, caching, persistence, and presentation.
| Branch | Minimum macOS | Development toolchain | Main characteristics |
|---|---|---|---|
main, version-3.0.0 |
macOS 27 | Xcode 27, Swift 6 | AI-based RawCull 3 with local CLIP semantic search and similarity, SAM 3 Deep Review, model validation, and Managed Background Assets support |
version-2.3.4 |
macOS 26.2 | Xcode 26, Swift 6 | macOS 26 release line using built-in Vision feature prints for visual similarity and burst grouping |
version-2.3.3 |
macOS 26.2 | Xcode 26, Swift 6 | Earlier macOS 26 release line, also using Vision feature prints rather than optional CLIP and SAM 3 models |
All versions require an Apple Silicon Mac. The main difference between the macOS 26 and macOS 27 editions is the AI layer, not the basic photo-culling workflow: the macOS 26 branches use Apple's built-in Vision feature prints, whereas RawCull 3 adds local CLIP models for text-to-image search and optional similarity analysis, plus SAM 3 subject segmentation for Deep Review. RawCull 3 falls back to Vision similarity when its selected CLIP model is unavailable.
RawCull 3 is not yet published as a prebuilt download; build this branch from source until its macOS 27 release is available.
- Discover and scan supported RAW files in a selected catalog.
- Read EXIF metadata, dimensions, camera and lens information, ISO, and aperture.
- Extract normalized camera AF points from Sony MakerNotes.
- Display cached thumbnails, embedded full-size JPEG previews, or developed RAW previews.
- Render AF-point overlays and GPU-generated focus masks.
- Score image sharpness using full-frame, salient-subject, and AF-region evidence.
- Apply photo-type presets and fast, balanced, or high-precision scoring.
- Group visually similar neighboring frames into bursts and rank candidates with sharpness, similarity, confidence, and caution details.
- Search by natural-language description when a validated CLIP model is available.
- Run SAM 3 Deep Review to isolate a subject and recommend a burst winner.
- Tag, reject, or assign star ratings to selected images.
- Persist ratings, analysis results, burst decisions, and cache signatures.
- Export embedded or developed JPEG files.
- Copy tagged or rated RAW files with streaming rsync progress.
- Monitor thumbnail-cache usage and macOS memory-pressure events.
RawCull's AI-assisted culling runs locally on Apple Silicon. Photos are not uploaded to an external inference service.
- Similarity and burst grouping: CLIP image embeddings, or Vision feature prints as the fallback, measure visual similarity and help group neighboring frames for comparison.
- Semantic search: CLIP compares a text-query embedding with cached image embeddings to rank photographs by meaning.
- Sharpness and subject evidence: PhotoAnalysisKit combines sharpness, saliency, classification, focus-mask, and camera AF-point evidence to rank candidates and explain cautions.
- Deep Review: SAM 3 isolates the subject, evaluates detail inside the mask, checks whether the AF point falls within the subject, and recommends a winner with confidence and supporting reasons. Mark Winner & Close saves the winner, gives it a three-star rating, and marks the burst reviewed.
- Local caching: Embeddings, masks, scores, and burst decisions are cached so compatible results can be reused in later sessions.
Both are trained neural networks, but they produce different evidence:
| CLIP: vision-language encoder | SAM 3: vision-language segmentation | |
|---|---|---|
| Question answered | “How well does this text match this image?” | “Where are the pixels belonging to this concept?” |
| Inputs | Image or text | Image plus text or visual prompt |
| Output | One fixed-length vector per image or text | Masks, boxes, presence, and confidence scores |
| Spatial information | Compresses most of the image into one vector | Preserves detailed spatial information |
| Training objective | Match related image-caption vectors | Detect and segment prompted objects |
| RawCull use | Search, similarity ranking, and burst grouping | Subject isolation and detailed review |
CLIP
Image ── image encoder ──► vector ─┐
├─► similarity score
Text ── text encoder ──► vector ─┘
SAM 3
Image ── image encoder ────────────┐
├─► detector + mask decoder ─► masks and boxes
Prompt ── text/visual encoder ──────┘
CLIP determines what an image is related to; SAM 3 determines where that thing is in the image.
CLIP image encoding runs once per photograph. Later searches reuse the cached image vectors and only run the text-query path; comparing cached vectors is ordinary mathematical computation, not another neural-network pass. SAM 3 normally runs for each image and prompt, but RawCull can cache and reuse the resulting subject mask.
- Vision feature-print similarity is built into macOS and requires no model download.
- CLIP similarity supports validated, PhotoAIKit-compatible DataComp and OpenAI CLIP Core AI model bundles. RawCull uses the model selected in Settings > AI and falls back to Vision feature prints when it is missing or invalid. Semantic search requires a valid CLIP model.
- Deep Review requires a validated, PhotoAIKit-compatible SAM 3 Core AI model bundle and remains unavailable without one.
- Each bundle must contain
metadata.json, the selected.aimodelor.aimodelcasset, and all resources declared by its manifest. - Models are not bundled with RawCull. Settings > AI > Download AI Models provides the Managed Background Assets flow for licence review, download progress, cancellation, and removal. The current server address is a non-routable placeholder, and production downloads remain blocked until licence and provenance requirements are complete.
- The first use of a portable Core AI model can take longer while macOS specializes it for the current Mac.
Manual installation remains available while model distribution is blocked. Install the resources, open Settings > AI, and select Check Again to validate them. Standard non-sandboxed locations are:
~/Library/Application Support/RawCull/Models/CLIP-DataComp/
~/Library/Application Support/RawCull/Models/CLIP-OpenAI/
~/Library/Application Support/RawCull/Models/SAM3/
Sandboxed builds use:
~/Library/Containers/no.blogspot.RawCull/Data/Library/Application Support/RawCull/Models/CLIP-DataComp/
~/Library/Containers/no.blogspot.RawCull/Data/Library/Application Support/RawCull/Models/CLIP-OpenAI/
~/Library/Containers/no.blogspot.RawCull/Data/Library/Application Support/RawCull/Models/SAM3/
Settings > AI displays the exact expected paths. To enable CLIP, select exactly one of DataComp or OpenAI, validate it, and enable Use selected CLIP model for similarity. To use SAM 3, analyze a catalog into burst groups, choose Deep Review on a burst, select the review target, and run the review.
See Model asset packs for the release blockers, licence and provenance catalogs, packaging steps, and hosting configuration.
flowchart LR
Catalog["RAW catalog"] --> Parser["RawParserKit"]
Parser --> Adapter["RawCull decoding adapters"]
Adapter --> Domain["RawCullCore models"]
Adapter --> Analysis["PhotoAnalysisKit"]
Adapter --> PhotoAI["PhotoAIKit"]
Models["CLIP / SAM 3 Core AI models"] --> PhotoAI
Analysis --> Sharpness["Sharpness, focus mask, saliency"]
PhotoAI --> Similarity["CLIP embeddings / Vision fallback"]
PhotoAI --> Masks["SAM 3 segmentation / mask storage"]
Domain --> Bursts["RawCullCore burst grouping"]
Similarity --> Bursts
Sharpness --> Ranking["RawCull ranking and review policy"]
Bursts --> Ranking
Masks --> DeepReview["Deep Review subject-detail evidence"]
Sharpness --> DeepReview
Domain --> ViewModels["@Observable view models"]
Ranking --> ViewModels
DeepReview --> ViewModels
ViewModels --> UI["SwiftUI views"]
ViewModels --> Cache["RAM and disk caches"]
ViewModels --> Persistence["JSON and burst persistence"]
ViewModels --> Copy["rsync copy workflow"]
RawCull keeps application-specific policy outside the packages:
- RAW source selection and decoding size
- security-scoped folder access
- settings and user preferences
- progress and cancellation presentation
- cache locations and file identity
- ratings, tagging, burst decisions, and the culling workflow
The imported packages own reusable parsing, sharpness analysis, AI inference, model validation, similarity artifacts, segmentation, mask storage, domain models, serialization, and process execution.
Requirements are pinned to exact versions or revisions in the Xcode project
and recorded in Package.resolved.
| Package | Pinned requirement | Responsibility | Main APIs used by RawCull |
|---|---|---|---|
| PhotoAIKit | revision 2cb07d6 |
AI contracts, validated Core AI resources, DataComp and OpenAI CLIP inference, SAM 3 inference, Vision fallback, segmentation workflows, and subject-mask storage | CoreAICLIPProvider, CoreAISAM3Provider, VisionFeaturePrintBackend, SimilarityArtifactIndexer, SegmentationService, SubjectMaskSelector, SubjectMaskMemoryStore, SubjectMaskDiskStore |
| PhotoAnalysisKit | 1.2.0 | Sharpness scoring, focus masks, Vision saliency and classification, calibration, batch analysis, and cache identity | PhotoAnalyzer.analyzeBatch, PhotoAnalyzer.calibrate, PhotoAnalyzer.focusMask, PhotoAnalyzer.analyzeWithFocusMask, PhotoAnalyzer.sharpnessDescriptor, SharpnessPreset, SharpnessQuality |
| RawParserKit | 1.2.8 | RAW discovery, metadata parsing, embedded JPEG extraction, previews, and manufacturer MakerNote parsing | RawFormatRegistry, RawImageLoader.metadata, thumbnailCGImage, thumbnail, previewImage, SonyMakerNoteParser, NikonMakerNoteParser, SupportedFileType |
| RawCullCore | 1.1.2 | Shared file, catalog, EXIF, burst-grouping, ranking, and review-state value types | RawCullFileItem, RawCullSourceCatalog, ExifMetadata, BurstGroupingConfig, BurstGroupingEngine.group, BurstAnalysisResult, BurstCandidateScore, BurstReviewState |
| RsyncArguments | 1.0.0 | Type-safe construction of rsync and synchronization arguments | Parameters, BasicRsyncParameters, OptionalRsyncParameters, SSHParameters, PathConfiguration, RsyncParametersSynchronize.argumentsForSynchronize, computedArguments |
| RsyncProcessStreaming | 1.0.0 | Starts and cancels rsync processes and streams file and progress output | ProcessHandlers, RsyncProcess, executeProcess, cancel |
| ParseRsyncOutput | 1.0.0 | Parses rsync summaries into counts and formatted transfer statistics | ParseRsyncOutput, getstats, numbersonly, and the formatted file and size properties |
| DecodeEncodeGeneric | 1.0.0 | Generic Codable helpers for persistent JSON data | DecodeGeneric.decodeArray, EncodeGeneric.encode |
- The user selects a security-scoped catalog.
ScanFilesdiscovers supported files through RawParserKit.- Metadata and AF information are read concurrently.
- RawCullCore
FileItemvalues are created and published to the main actor. - Ratings and compatible persisted analysis results are restored.
RawParserKitImageLoader adapts package results to RawCull:
RawImageLoader.metadata(for:)becomes RawCullCoreExifMetadata.RawImageLoader.thumbnailCGImagefeeds thumbnail caching, sharpness scoring, and feature generation.RawImageLoader.thumbnailsupplies AppKit thumbnail images.RawImageLoader.previewImagesupplies embedded full-size previews.- MakerNote focus coordinates become normalized
CGPointvalues.
RawFormatRegistry handles supported-file discovery. Diagnostic tools also
call the Sony and Nikon MakerNote parsers directly to report embedded JPEG
locations and focus metadata.
RawCull uses a two-tier thumbnail cache:
SharedMemoryCacheprovides the RAM layer throughNSCache.DiskCacheManagerstores JPEG thumbnails below~/Library/Caches/no.blogspot.RawCull/Thumbnails/.- RawParserKit decodes a thumbnail when both caches miss.
Full-size embedded and developed previews use a separate disk cache. A
DispatchSourceMemoryPressure monitor lets RawCull reduce cache pressure while
keeping diagnostics available in the Memory Console.
PhotoAnalysisKit owns the reusable focus and sharpness pipeline:
- RawCull selects an embedded preview or a Core Image demosaiced RAW image.
RawCullPhotoAnalysisAdaptersupplies asynchronousPhotoAnalysisInputproviders.PhotoAnalyzer.analyzeBatchperforms bounded concurrent analysis and reports progress.- The package performs saliency, classification, Gaussian blur, Metal Laplacian analysis, regional scoring, and failure classification.
SharpnessScoringModelpublishes scores, subject summaries, focus breakdowns, and estimated time to the UI.PhotoAnalyzer.calibratederives a visual focus threshold from a catalog or burst.PhotoAnalyzer.focusMaskandanalyzeWithFocusMaskrender the focus overlay and its supporting evidence.
Each PhotoAnalysisInput carries ISO, aperture, and normalized AF position.
Photo-type and quality choices map to SharpnessPreset and
SharpnessQuality. Persistent results use
PhotoAnalyzer.sharpnessDescriptor(for:), combined with RawCull's scoring
source, decoded size, source-file size, and modification date so stale results
are invalidated when the algorithm or input changes.
PhotoAnalysisKit does not know about FileItem, RAW formats, security-scoped
URLs, application settings, cache directories, or ratings.
RawCull imports six PhotoAIKit products: PhotoAIContracts,
PhotoAIWorkflows, PhotoAIStorage, CoreAICLIPBackend,
CoreAISAM3Backend, and VisionFeaturePrintBackend.
CoreAICLIPProvidercreates normalized CLIP image embeddings and cosine distances.VisionFeaturePrintBackendcreates and compares Codable Vision feature prints.CoreAISAM3Providerperforms in-process subject segmentation with a validated SAM 3 Core AI model.SegmentationServiceandSubjectMaskSelectoracquire and select masks;PhotoAIStoragesupplies their memory and disk stores.- Persisted settings select one DataComp or OpenAI CLIP bundle and enable it when available. Non-finite output is retried once, then retried with a replacement provider; unresolved images are excluded from automatic burst analysis.
For burst analysis, RawParserKit supplies 512-pixel thumbnails, PhotoAIKit
creates and validates CLIP artifacts or uses Vision, and RawCull passes adjacent
distances to BurstGroupingEngine.group. RawCullCore groups the ordered images;
RawCull ranks the candidates and caches the artifacts and decisions. Deep
Review adds SAM 3 subject masks and subject-detail evidence to that workflow.
RawCullAIIntegration validates the model bundles, selects CLIP or the Vision
fallback, constructs SAM 3 mask services, and injects narrow services into the
application models. RawCull retains ownership of RAW decoding, model locations,
settings, subject-detail scoring, recommendation policy, ratings, and review
state.
RawCullCore contains application-neutral domain types. RawCull aliases its central models:
typealias FileItem = RawCullFileItem
typealias ARWSourceCatalog = RawCullSourceCatalog
typealias ExifMetadata = RawCullCore.ExifMetadataRawCullCore also owns the burst-grouping contracts and algorithm. RawCull stores and presents its groups, candidate scores, confidence, cautions, and review state.
Ratings, tags, saliency labels, sharpness signatures, and manual burst winners are stored in:
~/Library/Application Support/RawCull/savedfiles.json
Settings are stored separately in:
~/Library/Application Support/RawCull/settings.json
DecodeGeneric loads the saved Codable array, and EncodeGeneric creates the
data written atomically to Application Support.
The RAW copy workflow uses three rsync packages, coordinated by RawCull:
RsyncArgumentsbuilds the base argument list.- RawCull adds a NUL-separated
--files-fromlist of selected tagged or rated filenames and the security-scoped source and destination paths. RsyncProcessStreamingexecutes/usr/bin/rsync, streams progress, and supports cancellation.ParseRsyncOutputconverts the final output into file counts, transferred sizes, created and deleted counts, and display-ready statistics.
| Framework | Main use |
|---|---|
SwiftUI |
Application scenes, navigation, grids, comparison views, settings, overlays, and controls |
Observation |
@Observable view models and application state |
AppKit |
NSImage, macOS windows, panels, pasteboard, and image bridging |
Foundation |
URLs, file management, Codable, tasks, dates, collections, and persistence |
CoreGraphics |
CGImage, normalized AF coordinates, image sizes, and drawing |
CoreImage |
Optional CIRAWFilter demosaicing for developed-RAW previews and high-precision scoring |
ImageIO |
JPEG properties, orientation, image-source diagnostics, and cache encoding and decoding |
CryptoKit |
Stable MD5-derived disk-cache keys |
Dispatch |
macOS memory-pressure monitoring |
BackgroundAssets |
Managed delivery and removal of optional AI model bundles |
OSLog and os |
Structured logging and lock-backed cache diagnostics |
UniformTypeIdentifiers |
RAW and JPEG file selection and export types |
Vision and Metal sharpness analysis are encapsulated by PhotoAnalysisKit. Core AI inference, AI-side Vision feature prints, and subject-mask storage are encapsulated by PhotoAIKit.
- View models are
@Observable,final, and@MainActor. - Background concerns use actor-per-responsibility isolation.
- Package-boundary values and providers conform to
Sendable. - Dynamic parallel work uses structured task groups with bounded concurrency.
- Long-running scans, analysis, extraction, grouping, and copy operations support cooperative cancellation.
- Results are committed to observable state only after successful completion.
- Superseded similarity and grouping generations cannot publish stale results.
Important actors include:
| Actor | Responsibility |
|---|---|
SharedMemoryCache |
RAM thumbnails, grid-cache admission, memory-pressure handling, and diagnostics |
DiskCacheManager |
Thumbnail JPEG persistence |
FullSizeJPGDiskCache |
Embedded and developed full-size preview persistence |
ScanFiles |
Catalog scanning, metadata extraction, and AF-point collection |
ScanAndCreateThumbnails |
Bounded thumbnail preloading |
ExtractAndSaveJPGs |
Batch JPEG extraction |
PerFileAnalysisArtifactStore |
Atomic, source- and pipeline-validated per-file analysis persistence |
BurstAnalysisCache |
Burst groups, embeddings, sharpness results, signatures, and review-state snapshots |
WriteSavedFilesJSON |
Atomic persistence of culling records |
RawCull/
├── Actors/ Background scanning, caching, extraction, and persistence
├── Main/ App entry point and shared type aliases
├── Model/
│ ├── AIIntegration/ Model validation, inference, downloads, and Deep Review
│ ├── Cache/ Cache configuration and diagnostics
│ ├── Diagnostics/ RAW, ImageIO, and similarity diagnostics
│ ├── Handlers/ App and streaming callbacks
│ ├── JSON/ Codable persistence models
│ ├── ParametersRsync/ RAW copy configuration and execution
│ └── ViewModels/ MainActor application and workflow state
├── Resources/ AI model licence notices
└── Views/ SwiftUI catalog, grid, comparison, settings, and zoom UI
RawCullModelDownloader/ Managed Background Assets extension
ModelAssets/ Model manifests, notices, and provenance catalogs
RawCullTests/ Swift Testing suites and test architecture notes
Debug build without notarization:
make debugRelease archive, signing, notarization, stapling, and DMG generation:
make buildClean generated build output:
make cleanThe Xcode scheme builds for Apple Silicon:
xcodebuild \
-project RawCull.xcodeproj \
-scheme RawCull \
-destination 'platform=OS X,arch=arm64'Tests use Apple's Swift Testing framework. Run fast package-integration and critical smoke coverage with:
make test-smokeRun the full suite with Thread Sanitizer:
make test-fullRun performance and extreme-concurrency coverage:
make test-performanceThe suites cover package and AI integration, model download validation, semantic search, Deep Review, sharpness and focus metrics, structured cancellation, latest-run-wins behavior, memory-cache counters, security-scoped access, disk caches, burst persistence, RAW parsing adapters, and copy startup and cleanup.