---
name: contacts
description: Import from the owner's macOS Contacts (read-only against Contacts) — put names on their iMessage/WhatsApp threads, fill the empty fields of existing People notes from the matching card, look a person up ("what's X's number / e-mail?"), or create People notes for the people the owner names. Use when the owner says "import my contacts", "sync my address book", "put names on my texts / WhatsApp", "add X from my contacts", "what's X's phone number / e-mail", "who do I know at <company>", or "fill in my People notes from Contacts". The owner asks in plain language — never make them run a command. Selective by design — it never bulk-creates a note per address-book card unless the owner explicitly asks for everyone. Runs locally on the owner's Mac (needs Full Disk Access), not an automation host. NOT the iMessage or WhatsApp reader (those read messages; this supplies the names), NOT vault-ingestion for pasted content. Requires the contacts module.
served: false
---

# Contacts — macOS Contacts → the vault (on-demand, read-only against Contacts)

The owner asks in plain language; **they never run a command**. This skill reads the
Mac's Contacts store and brings in exactly what the owner asked for — names for the
messaging readers, details onto existing People notes, a lookup, or a note for a
person they name. The full procedure is canonical in **[[Contacts]]**
(`Agent/docs/Contacts.md`); this is the trigger.

## When this skill fires
The owner says some form of *"import my contacts / sync my address book / put names
on my texts / what's X's number / add X from my contacts / fill in my People notes."*
On-demand and owner-only.

## What to do
1. **Read [[Contacts]]** (`Agent/docs/Contacts.md`) — it wins over anything remembered here.
2. **Scope the ask** to one of the four jobs, then run the importer as plumbing —
   `"${ALEXANDRIA_PYTHON:-python3}" -m alexandria_vault.engine.contacts_import --vault .`:
   - **Names for the readers** → `--handles` (writes the shared, gitignored map the
     iMessage and WhatsApp readers load; safe to re-run — hand-written entries are kept).
   - **Fill existing People notes** → `--enrich --dry-run` first, show the owner what
     would be filled (only *empty* fields are ever touched), then `--enrich` on a yes.
   - **Lookup** → `--search "<name / company / number>"` (prefer `--json`); answer from it.
   - **Create People notes** → `--create "<Full Name>"` per person the owner named
     (`--dry-run` to preview). `--create-all` only when the owner has *explicitly* asked
     for their whole address book, and after saying how many notes that is.
   The owner never sees or types these commands.
3. **Read the stderr coverage line** (`sources N · cards M (people / orgs, me-card
   skipped) · with phone / e-mail`) before relying on the result — zero sources means
   Contacts wasn't readable (see the Full Disk Access rule below).
4. **Commit what landed in the vault** (`contacts: <what> (<n> notes)`) — enriched or
   created People notes are vault content. The handle map is **not** committed (it's
   gitignored PII) and needs no commit.
5. **Answer in the owner's terms** — who got a note, which fields were filled, or the
   number they asked for — not a report of flags.

## Rules (detailed in [[Contacts]])
- **Prerequisite: Full Disk Access.** macOS TCC blocks the AddressBook store until the
  app running the assistant (Claude, or its terminal) has Full Disk Access. It's a
  one-time System Settings grant, not a credential. An exported `.vcf` (`--vcf`) works
  without it.
- **Runs locally**, on the owner's Mac — never on an automation host.
- **Read-only against Contacts, full stop.** The live databases are never opened (a
  snapshot copy is queried); nothing in Contacts is edited, tagged, or deleted.
- **Selective, not bulk.** A People note is for someone the owner *deals with*
  (AGENTS → the direct-dealing test); an address book is mostly not that. Create notes
  for named people; never sweep the whole book in unasked.
- **Never overwrite.** `--enrich` fills blanks only (a value in block form counts as
  filled); an existing note is never replaced by `--create`.
- **The Contacts note field is copied verbatim** into a created note's `## Notes` — people
  keep gate codes and PINs there. Read it before committing; cut secrets, keep facts.
- **The handle map is PII, off-repo.** Only `handles.example.json` ships; the real
  file is gitignored and the importer keeps it that way.
