Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
joelhooks avatar

Contacts

  • 3.2k installs
  • 61 repo stars
  • Updated August 4, 2026
  • joelhooks/joelclaw

contacts is a joelclaw skill for Vault contact files, Inngest enrichment pipeline, VIP playbooks, and Roam cross-reference.

About

Contacts manages markdown contact files in ~/Vault/Contacts/ with YAML frontmatter for name, aliases, role, organizations, vip flag, Slack and social identifiers, and tagged sections for channels, projects, context, and recent activity. Preferred enrichment fires an Inngest contact/enrich.requested event via localhost curl because the CLI has an OTEL import bug under Bun. Full depth runs seven sources with LLM synthesis in about sixty seconds while quick depth uses Slack and memory only. Manual create writes a simple markdown file and adds a wikilink to index.md. Updates re-run enrichment with vault_path so synthesizer merges without discarding existing facts. VIP contacts get deep enrichment playbooks covering web, podcast, GitHub, X, Roam archive search, Typesense indexing, and ongoing monitoring channels per ADR-0151. Roam Research enrichment uses Python regex on egghead EDN exports with collaborator, client, and staff taxonomy tags. Resolving unknown Slack users leases a slack_user_token and calls users.info API.

  • Vault Contacts markdown with YAML frontmatter schema.
  • Inngest contact/enrich.requested full and quick depths.
  • VIP deep enrichment and Typesense discoveries indexing.
  • Roam EDN regex search with relationship taxonomy tags.
  • Slack user ID resolution via leased token lookup.

Contacts by the numbers

  • 3,197 all-time installs (skills.sh)
  • +13 installs in the week ending Aug 5, 2026 (Skillselion tracking)
  • Ranked #175 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
  • Security screen: HIGH risk (skills.sh audit)
  • Data as of Aug 5, 2026 (Skillselion catalog sync)
At a glance

contacts capabilities & compatibility

Capabilities
vault markdown contact schema and index wikilink · inngest enrichment event full and quick modes · vip deep enrichment and monitoring playbook · roam edn regex people taxonomy search · typesense discoveries batch upsert indexing · slack users.info resolution with leased tokens
Works with
slack · notion
Use cases
orchestration · project management
Pricing
Bring your own API key
From the docs

What contacts says it does

The synthesizer merges new data with existing content
SKILL.md
npx skills add https://github.com/joelhooks/joelclaw --skill contacts

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs3.2k
repo stars61
Security audit1 / 3 scanners passed
Last updatedAugust 4, 2026
Repositoryjoelhooks/joelclaw

How do I add or refresh a contact dossier in Joel Vault with multi-source enrichment?

Add, enrich, and manage Vault contacts via Inngest pipeline or manual markdown with VIP monitoring playbooks.

Who is it for?

Agents managing personal CRM contacts, VIP dossiers, or Slack identity resolution in joelclaw workflows.

Skip if: Skip for generic CRM SaaS setup or contacts outside Joel Vault directory structure.

When should I use this skill?

User says add contact, enrich person, VIP contact, update Vault contact, or who is X in joelclaw.

What you get

Enriched ~/Vault/Contacts note with frontmatter, sections, optional Typesense index, and VIP monitoring hooks.

  • contact markdown files
  • updated index.md
  • enriched dossiers

By the numbers

  • Skill version 1.0.0
  • Uses ~/Vault/Contacts/ directory with index.md wikilink index

Files

SKILL.mdMarkdownGitHub ↗

Contacts

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: Full Name
aliases: [nickname, handle]
role: Current Role / Title
organizations: [Org1, Org2]
vip: true  # or false
slack_user_id: U0XXXXXXX
slack_dm_channel: D0XXXXXXX  # null if unknown
website: https://example.com
github: username
twitter: handle
email: user@example.com
tags: [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 7 sources (Slack, Roam, web/GitHub, Granola, recall memory, Typesense), 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.

Updating Contacts

Re-run enrichment with the existing vault path:

{
  "name": "contact/enrich.requested",
  "data": {
    "name": "Person Name",
    "vault_path": "Contacts/Person Name.md",
    "depth": "full"
  }
}

The synthesizer merges new data with existing content — it won't discard existing facts unless contradicted.

VIP Contacts (ADR-0151)

Mark vip: true in frontmatter. VIPs get deep enrichment + ongoing monitoring.

Deep Enrichment Playbook (one-time)

Every VIP gets the full treatment. This is what we did for Kent C. Dodds (Feb 26, 2026):

StepSourceWhat to Capture
1. Web presenceWeb search {name} + {org}Bio, role, location, personal details
2. Podcast/interviewsWeb search {name} podcast interviewAppearance list, own podcasts, audiences
3. Joel collaborationsTheir website, appearances pagesJoint podcasts, co-organized events, shared projects
4. Career timelineDefuddle 2-3 key interview transcriptsOrigin story, career arc, key decisions, values
5. GitHub profileGitHub API or webRepos, followers, orgs, contribution patterns
6. X/Twitter profileX API v2 (use x-api skill)Bio, followers, recent tweets, engagement
7. Key relationshipsCross-reference transcripts + contactsWho they work with, who they mention, who we know in common
8. Content catalogWebsite crawl (defuddle)Courses, blog posts, open source projects
9. Audience reachPodcast counts, social followersConference circuit, community presence

Index to Typesense after enrichment:

  • Batch-import appearances/content to discoveries collection (NDJSON, action=upsert)
  • Tag all docs with person's name slug (e.g. kent-c-dodds) for filtering
  • Fields: id, title, url, summary, tags[], timestamp
  • 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)

ChannelToolSignal
Google Alertsjoelclawbot Google accountName mentions in news, blogs, press
X/Twitter listjoelclaw X accountTweets, engagement
GitHub activityGitHub API (polling)New repos, releases
Podcast RSSFeed monitoringNew episodes
Website changesPeriodic defuddle + diffBlog 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>):

# Lease token and look up profile
SLACK_USER=$(secrets lease slack_user_token --ttl 5m)
curl -s "https://slack.com/api/users.info?user=U0XXXXXXX" \
  -H "Authorization: Bearer $SLACK_USER" | jq '.user.real_name, .user.profile.email'
secrets revoke --all

Then fire enrichment with the resolved name and hints.

Inngest Function

  • Function: contact-enrich (packages/system-bus/src/inngest/functions/contact-enrich.ts)
  • Event: contact/enrich.requested
  • ADR: ~/Vault/docs/decisions/0133-contact-enrichment-pipeline.md
  • Concurrency: 3 max
  • Sources: Slack, Slack Connect, Roam archive, GitHub/web, Granola meetings, recall memory, Typesense

Privacy

  • Contact files are in Vault (private, not in public repos)
  • Slack data stays private — never surface in public content
  • Email/phone are stored for Joel's reference only

Related skills

How it compares

Use contacts for markdown vault personal CRM; use team CRM integrations when you need shared SaaS contact databases.

FAQ

Inngest or manual create?

Prefer Inngest contact/enrich.requested for full multi-source dossiers; manual for simple entries.

full or quick depth?

full hits seven sources in about 60s; quick uses Slack and memory in about 10s for VIP detection.

How update existing contact?

Re-send enrich event with vault_path so synthesizer merges new data without dropping facts.

Is Contacts safe to install?

skills.sh reports 1 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.