Skip to content

Instantly share code, notes, and snippets.

@pointum
Created September 24, 2026 00:59
Show Gist options
  • Select an option

  • Save pointum/22aaa925df98497a40a61d71f0d95a06 to your computer and use it in GitHub Desktop.

Select an option

Save pointum/22aaa925df98497a40a61d71f0d95a06 to your computer and use it in GitHub Desktop.
Check macOS Spotlight semantic indexing readiness
// 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');
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment