Add, enrich, and manage contacts in Joel's Vault. Fire the Inngest enrichment pipeline for full multi-source dossiers, or create quick contacts manually. Use when: 'add a contact', 'enrich this person', 'who is X', 'VIP contact', 'update contact', or any task involving the Vault/Contacts directory.
Add, enrich, and manage contacts in Joel's Vault. Fire the Inngest enrichment pipeline for full multi-source dossiers, or create quick contacts manually. Use when: 'add a contact', 'enrich this person', 'who is X', 'VIP contact', 'update contact', or any task involving the Vault/Contacts directory.
Manage contacts in ~/Vault/Contacts/. Each contact is a markdown file with YAML frontmatter.
Contact File Location
~/Vault/Contacts/<Name>.md
Index file: ~/Vault/Contacts/index.md — wikilink list of all contacts.
Frontmatter Schema
---name:FullNamealiases: [nickname, handle]
role:CurrentRole/Titleorganizations: [Org1, Org2]
vip:true# or falseslack_user_id:U0XXXXXXXslack_dm_channel:D0XXXXXXX# null if unknownwebsite:https://example.comgithub:usernametwitter:handleemail:user@example.comtags: [vip, instructor, creator, family, employee]
---
Sections
# Name## Contact Channels- Slack, email, social handles, website
## Projects- Active projects, courses, collaborations
## Key Context- Relationship notes, working style, history
## Recent Activity- YYYY-MM-DD | channel | summary
See ~/Vault/Contacts/Matt Pocock.md for a fully enriched example.
Adding a Contact
Option 1: Fire the Enrichment Pipeline (preferred)
Send an Inngest event. The contact-enrich function fans out across Slack, Roam, web/GitHub, Granola, Brain-backed recall, and other indexed sources, synthesizes with LLM, and writes the Vault file.
# Via curl (CLI has OTEL import bug under Bun v1.3.9)
curl -s -X POST "http://localhost:8288/e/$INNGEST_EVENT_KEY" \
-H "Content-Type: application/json" \
-d '[{
"name": "contact/enrich.requested",
"data": {
"name": "Person Name",
"depth": "full",
"hints": {
"slack_user_id": "U0XXXXXXX",
"github": "username",
"twitter": "handle",
"email": "user@example.com",
"website": "https://example.com"
}
},
"ts": EPOCH_MS
}]'
Depth modes:
full (~60s, ~$0.05): All 7 sources + LLM synthesis. Use for new contacts or periodic refresh.
quick (~10s, ~$0.01): Slack + memory only. Good for real-time VIP detection.
Hints are optional but help: Any known identifiers (Slack ID, GitHub, email, Twitter, website) seed the search and improve results.
Option 2: Quick Manual Create
For simple contacts where enrichment is overkill:
---
name: Person Name
aliases: []
role: Role
organizations: [Org]
vip: false
slack_user_id: null
website: null
github: null
twitter: null
email: null
tags: [tag1]
---# Person Name## Contact Channels- ...
## Key Context- ...
Write to ~/Vault/Contacts/Person Name.md and add [[Person Name]] to index.md.
Write a Vault/Resources/{name}-media-appearances.md reference doc linking back to contact
Output sections in the vault note:
Background & Story (origin, career timeline)
Teaching/Work Philosophy (or equivalent for non-educators)
Key Relationships (cross-linked [[wikilinks]] to other contacts)
Audience & Reach
Content/Products
Podcast/Collaboration History with Joel
Recent Activity (timestamped)
Ongoing Monitoring (Phase 2-4 of ADR-0151)
Channel
Tool
Signal
Google Alerts
joelclawbot Google account
Name mentions in news, blogs, press
X/Twitter list
joelclaw X account
Tweets, engagement
GitHub activity
GitHub API (polling)
New repos, releases
Podcast RSS
Feed monitoring
New episodes
Website changes
Periodic defuddle + diff
Blog posts, launches, bio changes
High-signal (immediate): course launches, role changes, mentions of Joel/egghead/Skill, fundraising.
Low-signal (daily/weekly digest): regular tweets, blog posts, OSS activity.
Current VIPs
Get notified to Joel via gateway after enrichment
Are refreshed weekly via scheduled cron
Have priority in channel intelligence pipeline (ADR-0131, ADR-0132)
Get ongoing monitoring when ADR-0151 Phase 2+ is implemented
Roam Research Enrichment
Joel's Roam archive (~/Code/joelhooks/egghead-roam-research/) contains the full egghead-era graph (2019-2024). Many contacts have extensive history there.
Quick Search (Python regex)
cd ~/Code/joelhooks/egghead-roam-research
python3 -c "
import re
with open('egghead-2026-01-19-13-09-38.edn', 'r') as f:
content = f.read()
pattern = r':block/string\s+\"([^\"]*?)\"'
matches = []
for m in re.findall(pattern, content):
if '[[SEARCH_TAG]]' in m.lower():
matches.append(m)
print(f'Found {len(matches)} blocks')
for m in matches[:30]:
print(f' - {m[:200]}')
"
People Taxonomy
People are tagged with relationship prefixes in Roam:
[[collaborator/Name]] — Strategic partners (Ian Jones, Alex Hillman)
[[client/Name]] — egghead instructors (Matt Pocock, Jacob Paris)
[[staff/Name]] — egghead team (Will Johnson, Daniel Miller, Maggie Appleton)
[[name]] (no prefix) — Informal references (Zac is [[zac]])
Page Title Search
python3 -c "
import re
with open('egghead-2026-01-19-13-09-38.edn', 'r') as f:
content = f.read()
pattern = r':node/title\s+\"([^\"]*?SEARCH_TERM[^\"]*?)\"'
for m in re.findall(pattern, content):
print(f' page: {m}')
"
Adding to Contacts
When extracting person data from Roam, add roam_tag to frontmatter:
roam_tag:"[[collaborator/Ian Jones]]"
This enables future re-queries and cross-referencing.
Datalog Queries (advanced)
The EDN file is Datomic-style. Clojure scripts exist at scripts/ for structured analysis. See the roam-research skill for full Datalog patterns.
Resolving Unknown People
When you encounter a Slack user ID (<@U0XXXXXXX>):