Smart Contact Capture
Works with Evergreen, a local-first personal CRM for macOS. Get it on the Mac App Store.
When to Use
- Someone shares a business card or email signature
- You have raw text with contact details (from a conference, email thread, or LinkedIn)
- You need to batch-create contacts from meeting notes or an event attendee list
- You received an introduction email and want to add the new person
How It Works
- Parse the unstructured text to extract: name, title, organization, email, phone, location, and any contextual notes
- Search existing contacts with
search_contacts to check for duplicates
- If the contact doesn't exist, create it with
create_contact
- Add relevant tags via the contact's
tags field with update_contact (e.g., "met-at-conference", "investor", "lead")
- Record context in the contact's
notes field with update_contact (how you met, who introduced you, conversation topics)
- If someone introduced you to this new contact, resolve that introducer to an existing contact with
search_contacts. If they're already in the CRM, call record_introduction(introducerId, newContactId, notes?) to record the introducedBy edge (who brought this person into your network). Keep the free-text note from step 5 regardless — the edge complements it. If the introducer isn't a known contact, skip the call and rely on the note alone.
- If an introduction, log the interaction with
log_interaction
Extraction Patterns
| Source |
What to Extract |
| Email signature |
Name, title, org, email, phone, address |
| LinkedIn URL |
Name, headline as title, company as org |
| Business card text |
All fields, watch for multiple phone/email |
| Meeting notes |
Names, affiliations, discussion context |
| Introduction email |
Both parties, relationship context, reason for intro |
Example
Input:
Hey, great meeting Sarah Chen at the AI dinner last night. She's the
CTO at Meridian Health, based in Atlanta. Her email is sarah@meridianhealth.com
and she's really interested in our API work. David Kim introduced us.
Actions:
1. search_contacts({ query: "Sarah Chen" }) → no match
2. create_contact({
name: "Sarah Chen",
title: "CTO",
organization: "Meridian Health",
emails: ["sarah@meridianhealth.com"],
location: "Atlanta"
}) → sarah_id
3. update_contact({ contactId: sarah_id, tags: ["ai", "healthcare", "atlanta"] })
4. update_contact({ contactId: sarah_id, notes: "Met at Atlanta AI Dinner. Introduced by David Kim. Interested in our API work." })
5. search_contacts({ query: "David Kim" }) → matches contact david_id
6. record_introduction({ introducerId: david_id, newContactId: sarah_id, notes: "Introduced Sarah at the Atlanta AI Dinner" })
7. log_interaction({ contactId: sarah_id, type: "meeting", description: "Met at Atlanta AI Dinner — discussed API work" })
(If search_contacts finds no match for the introducer, skip step 6 and keep the note from step 4.)
Checklist
Contact Capture:
- [ ] Full name captured in the single `name` field (no first/last split)
- [ ] Duplicate check performed before creating
- [ ] All available fields populated
- [ ] Tags applied for context/source
- [ ] Meeting context saved in notes
- [ ] Introducer edge recorded with `record_introduction` when the intro's source is a known contact
- [ ] Initial interaction logged
Learn More
1---2name: capturing-contacts-in-evergreen3description: Parses unstructured text (email signatures, business cards, LinkedIn profiles, meeting notes) into structured Evergreen CRM contacts. Use when adding new contacts from raw text, importing contacts from emails or messages, or batch-creating contacts from event notes.4---56# Smart Contact Capture78> Works with [Evergreen](https://heltonlabs.com/evergreen), a local-first personal CRM for macOS. [Get it on the Mac App Store](https://apps.apple.com/us/app/evergreencrm/id6753191506?mt=12).910## When to Use1112- Someone shares a business card or email signature13- You have raw text with contact details (from a conference, email thread, or LinkedIn)14- You need to batch-create contacts from meeting notes or an event attendee list15- You received an introduction email and want to add the new person1617## How It Works18191. Parse the unstructured text to extract: name, title, organization, email, phone, location, and any contextual notes202. Search existing contacts with `search_contacts` to check for duplicates213. If the contact doesn't exist, create it with `create_contact`224. Add relevant tags via the contact's `tags` field with `update_contact` (e.g., "met-at-conference", "investor", "lead")235. Record context in the contact's `notes` field with `update_contact` (how you met, who introduced you, conversation topics)246. If someone introduced you to this new contact, resolve that introducer to an existing contact with `search_contacts`. If they're already in the CRM, call `record_introduction(introducerId, newContactId, notes?)` to record the `introducedBy` edge (who brought this person into your network). Keep the free-text note from step 5 regardless — the edge complements it. If the introducer isn't a known contact, skip the call and rely on the note alone.257. If an introduction, log the interaction with `log_interaction`2627## Extraction Patterns2829| Source | What to Extract |30|--------|----------------|31| Email signature | Name, title, org, email, phone, address |32| LinkedIn URL | Name, headline as title, company as org |33| Business card text | All fields, watch for multiple phone/email |34| Meeting notes | Names, affiliations, discussion context |35| Introduction email | Both parties, relationship context, reason for intro |3637## Example3839**Input:**40```41Hey, great meeting Sarah Chen at the AI dinner last night. She's the42CTO at Meridian Health, based in Atlanta. Her email is sarah@meridianhealth.com43and she's really interested in our API work. David Kim introduced us.44```4546**Actions:**47```481. search_contacts({ query: "Sarah Chen" }) → no match492. create_contact({50 name: "Sarah Chen",51 title: "CTO",52 organization: "Meridian Health",53 emails: ["sarah@meridianhealth.com"],54 location: "Atlanta"55 }) → sarah_id563. update_contact({ contactId: sarah_id, tags: ["ai", "healthcare", "atlanta"] })574. update_contact({ contactId: sarah_id, notes: "Met at Atlanta AI Dinner. Introduced by David Kim. Interested in our API work." })585. search_contacts({ query: "David Kim" }) → matches contact david_id596. record_introduction({ introducerId: david_id, newContactId: sarah_id, notes: "Introduced Sarah at the Atlanta AI Dinner" })607. log_interaction({ contactId: sarah_id, type: "meeting", description: "Met at Atlanta AI Dinner — discussed API work" })61```62(If `search_contacts` finds no match for the introducer, skip step 6 and keep the note from step 4.)6364## Checklist6566```67Contact Capture:68- [ ] Full name captured in the single `name` field (no first/last split)69- [ ] Duplicate check performed before creating70- [ ] All available fields populated71- [ ] Tags applied for context/source72- [ ] Meeting context saved in notes73- [ ] Introducer edge recorded with `record_introduction` when the intro's source is a known contact74- [ ] Initial interaction logged75```7677## Learn More7879- [Evergreen — Local-First Personal CRM](https://heltonlabs.com/evergreen)80- [Vibe Coding a Personal CRM](https://mcginniscommawill.com/posts/2025-09-05-vibe-coding-personal-crm/)81- [Evergreen Gets Serious](https://mcginniscommawill.com/posts/2025-10-08-evergreen-gets-serious/)82- [Evergreen Gets Even Evergreener](https://mcginniscommawill.com/posts/2026-01-26-evergreen-gets-even-evergreener/)