# Check macOS Spotlight semantic indexing readiness

> Source: <https://gist.github.com/pointum/22aaa925df98497a40a61d71f0d95a06>
> Published: 2026-09-24 00:59:58+00:00

|  | // Spotlight semantic search readiness, as reported by CoreSpotlight. | 
|  | // Usage: osascript -l JavaScript readiness.js [pipeline] (default: Embedding) | 
|  | // Or paste into Script Editor and pick JavaScript instead of AppleScript language | 
|  | ObjC.import('CoreSpotlight'); | 
|  | const bind = (name, signature) => ObjC.bindFunction(name, signature); | 
|  | bind('xpc_connection_create_mach_service', ['pointer', ['char *', 'pointer', 'unsigned long long']]); | 
|  | bind('xpc_connection_set_event_handler', ['void', ['pointer', 'id']]); | 
|  | bind('xpc_connection_resume', ['void', ['pointer']]); | 
|  | bind('xpc_connection_send_message_with_reply_sync', ['pointer', ['pointer', 'pointer']]); | 
|  | bind('xpc_dictionary_create', ['pointer', ['pointer', 'pointer', 'unsigned long']]); | 
|  | bind('xpc_dictionary_set_string', ['void', ['pointer', 'char *', 'char *']]); | 
|  | bind('xpc_dictionary_set_uint64', ['void', ['pointer', 'char *', 'unsigned long long']]); | 
|  | bind('xpc_dictionary_get_data', ['pointer', ['pointer', 'char *', 'pointer']]); | 
|  | bind('xpc_dictionary_get_uint64', ['unsigned long long', ['pointer', 'char *']]); | 
|  | bind('xpc_dictionary_get_int64', ['long long', ['pointer', 'char *']]); | 
|  | function run(argv) { | 
|  | const pipeline = argv[0] \|\| 'Embedding'; | 
|  | // Same request -[CSSearchableIndex fetchIndexingPipelineOverallCompleteness:completionHandler:] sends | 
|  | const connection = $.xpc_connection_create_mach_service('com.apple.spotlight.IndexAgent', null, 0); | 
|  | $.xpc_connection_set_event_handler(connection, ObjC.block(['void', ['pointer']], () => {})); | 
|  | $.xpc_connection_resume(connection); | 
|  | const request = $.xpc_dictionary_create(null, null, 0); | 
|  | $.xpc_dictionary_set_uint64(request, 'id', 1); | 
|  | $.xpc_dictionary_set_string(request, 'command', 'fetch-indexing-pipeline-completeness'); | 
|  | $.xpc_dictionary_set_string(request, 'command-type', 'index-type'); | 
|  | $.xpc_dictionary_set_string(request, 'n', 'CSSearchableIndexShared'); | 
|  | $.xpc_dictionary_set_uint64(request, 'iopt', 0); | 
|  | $.xpc_dictionary_set_string(request, 'indexing-pipeline', pipeline); | 
|  | const reply = $.xpc_connection_send_message_with_reply_sync(connection, request); | 
|  | // Nonzero status: unknown pipeline, or no report yet (first minutes after install) | 
|  | if (Number($.xpc_dictionary_get_int64(reply, 'status')) !== 0) return `No report for ${pipeline}`; | 
|  | const size = $.xpc_dictionary_get_uint64(reply, 'indexing-pipeline-completeness-size'); | 
|  | const bytes = $.xpc_dictionary_get_data(reply, 'indexing-pipeline-completeness', null); | 
|  | const report = $.NSKeyedUnarchiver.unarchivedObjectOfClassFromDataError( | 
|  | $.NSClassFromString('CSIndexingPipelineOverallCompleteness'), $.NSData.dataWithBytesLength(bytes, size), null); | 
|  | const value = key => ObjC.unwrap(report.valueForKey(key)); | 
|  | const percent = key => value(key) == null ? 'n/a' : (value(key) * 100).toFixed(1) + '%'; | 
|  | const status = value('isSufficientlyComplete') ? 'Ready' : 'Still processing'; | 
|  | return [ | 
|  | `Search readiness: ${percent('overallCompleteness')} — ${status} (${percent('sufficientlyCompleteThreshold')} required)`, | 
|  | `Known app items donated: ${percent('donationCompeleteness')}`, | 
|  | `Search pipeline processed: ${percent('pipelineCompleteness')}`, | 
|  | `Report age: ${(value('pipelineReportAge') / 3600).toFixed(1)} hours`, | 
|  | ].join('\n'); | 
|  | } |
