Our family photo library has 247,658 photos. That is twenty years of kids, sunsets, dogs, and blurry thumbs. Bubbles is the assistant the family already texts. I wanted Bubbles to answer “find the pictures from the boat day last summer”. I did not want to scroll for ten minutes.
This plan gives an AI agent access to our most irreplaceable dataset. So the design work was not about the permitted actions. It was about the impossible actions.
Seven verbs
This is what shipped. A small signed native app is the only program on the machine with photo-library access. It gives exactly seven operations over a locked local socket: check status, search, build a contact sheet, describe a photo, export a copy, create an album, add to an album. That is the full vocabulary. Seven verbs.

The verbs that do not exist
These verbs do not exist: delete, edit, hide, favorite, rewrite metadata, remove from album. They are not “blocked by policy”. I never built the operations. There is no code path from the AI to a destructive action. So no bug, no prompt injection, and no confidently wrong model can find one. The most dangerous action Bubbles can take against our photo library is to make an album I did not request. Even album changes need a flag that says I gave an explicit request. Each mutation goes into an audit log. When Bubbles adds the same photo to an album twice, the app politely reports “already there”. It does not make a duplicate.
The photos stay home
The second decision I care about is the captions. A vision model looks at each photo and records what it sees. This runs locally, on Bubbles, on an open-weights model. The family photos do not go to a cloud provider for analysis. Only the derived caption text leaves the house. That text goes out for embedding, so the search works. The photos stay home. The photo indexer does not have a cloud API key. So it cannot leak one.
A slow backfill, on purpose
The backfill has small ambitions on purpose. The indexer runs every 15 minutes, with 25 captions per batch. That is approximately 100 photos per hour. The first pass stops at the newest 5,000 photos, not at all 247,658. The full library at that rate needs approximately 103 days. I did not turn that on. The newest five thousand photos answer almost every real question we ask. The deep archive is rich in photographs of the inside of a pocket. Nobody has ever searched for one. The 2009 archive can wait until the system earns it.
Did it work? The end-to-end canary passed. One photo got a caption, went into the index, and appeared through the assistant. Then one hundred photos in a row passed with zero failures. The test-album mutation behaved. The duplicate-add check behaved. One too-wide system permission entered during development. I revoked it after verification. I kept a snapshot as proof of the change.
I think the pattern applies in general. My first instinct with AI agents was one question: which capabilities do I add? For each thing I care about, I now try the other question first: which capabilities do I withhold permanently? Here, seven verbs are sufficient.