KiFinder is a Mac app that finds photos of one person in a large mixed album. I built it because my daughter's preschool sends several zip files with hundreds of class photos each month, and I had to find her pictures by hand. The albums include other families' children, so the matching runs on the Mac and does not upload their photos.
How it works
I enroll a person with several reference photos. KiFinder detects the faces, builds an ArcFace embedding profile, and scans a folder, loose images, or the original zip files. It sorts the results into three piles: confident matches, photos worth another look, and the rest. Group photos show every detected face so I can select the person I meant rather than accepting the app's first guess.
The review flow keeps borderline results visible without mixing them into the confident matches. For these demo images I enrolled myself and used synthetic faces for the other people.
Choosing the similarity threshold involves a product decision, not a fixed property of the model. A high value misses side profiles and blurry candid shots. A low value fills the review with other children. The calibration command takes labeled positive and negative examples and recommends the highest threshold that still catches every known real match, but it does not apply the value for me. I want to choose explicitly whether to risk missing a real photo.
Each scan writes its scores and face embeddings to a manifest. When I keep a real match or reject a look-alike, KiFinder adds that correction to an exemplar bundle beside the original references. It can then re-score an old album without loading the images or running the model again.
Enrollment crops the reference faces on the Mac. The app asks for five to twelve photos so the profile includes more than one angle.
Verification
The review screen makes the model's decision inspectable instead of presenting a final folder with no explanation. I found one important regression only by running the real engine after enabling the App Sandbox. Core ML compiled its model under a hard-coded path in /private/tmp, which the sandbox could not write. A swallowed error turned every embedding into nil, so the scan completed with zero faces. Moving the scratch directory into the container fixed it, and a live-engine check over saved photos produced five and six embeddings where the broken build produced none.
The library groups kept photos by person and month before export to Photos.
Why I keep it source-only
I decided not to ship KiFinder as an app, free or paid, mostly out of respect for people's right to privacy. The photos it works on are full of other families' children. Running face matching on them on my own Mac for my own daughter is one thing. Handing anyone a signed app that does it to any album is another.
The model made that harder, too. The ArcFace weights I use were trained on MS-Celeb-1M, a dataset that was withdrawn because it was built from people's faces without their consent. That's workable for a personal tool, but I don't want to distribute it. A real release would mean finding or training a model on consented data, plus the support and review work that comes with an app.
Instead, the source lives on GitHub under GPLv3. Anyone can read it or build it for themselves, and derivative work has to stay open.
Current state
KiFinder remains an active personal tool. Next I want more repeatable on-device coverage around model setup and sandbox permissions.