contacts

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Contacts

联系人

Manage contacts in
~/Vault/Contacts/
. Each contact is a markdown file with YAML frontmatter.
~/Vault/Contacts/
中管理联系人。每个联系人对应一个带有YAML前置元数据的Markdown文件。

Contact File Location

联系人文件位置

~/Vault/Contacts/<Name>.md
Index file:
~/Vault/Contacts/index.md
— wikilink list of all contacts.
~/Vault/Contacts/<Name>.md
索引文件:
~/Vault/Contacts/index.md
— 所有联系人的维基链接列表。

Frontmatter Schema

前置元数据Schema

yaml
---
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]
---
yaml
---
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

文档章节

markdown
undefined
markdown
undefined

Name

Name

Contact Channels

联系渠道

  • Slack, email, social handles, website
  • Slack、邮箱、社交账号、网站

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.
  • YYYY-MM-DD | 渠道 | 摘要

可参考`~/Vault/Contacts/Matt Pocock.md`查看完整的富信息示例。

Adding a Contact

添加联系人

Option 1: Fire the Enrichment Pipeline (preferred)

选项1:触发Enrichment管道(推荐方式)

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.
bash
undefined
发送一个Inngest事件。
contact-enrich
函数会从7个来源(Slack、Roam、网页/GitHub、Granola、记忆召回、Typesense)获取信息,通过LLM进行合成,然后写入Vault文件。
bash
undefined

Via curl (CLI has OTEL import bug under Bun v1.3.9)

Via curl (CLI has OTEL import bug under Bun v1.3.9)

curl -s -X POST http://localhost:8288/e/37aa349b89692d657d276a40e0e47a15
-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.
curl -s -X POST http://localhost:8288/e/37aa349b89692d657d276a40e0e47a15
-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 }]'

**深度模式:**
- `full`(约60秒,成本约0.05美元):覆盖全部7个来源 + LLM合成。适用于新增联系人或定期刷新信息。
- `quick`(约10秒,成本约0.01美元):仅从Slack和记忆库获取信息。适合实时VIP检测场景。

**提示信息为可选但能提升效果:** 任何已知的标识信息(Slack ID、GitHub账号、邮箱、Twitter账号、网站)都能作为搜索种子,提升结果准确性。

Option 2: Quick Manual Create

选项2:手动快速创建

For simple contacts where enrichment is overkill:
markdown
---
name: Person Name
aliases: []
role: Role
organizations: [Org]
vip: false
slack_user_id: null
website: null
github: null
twitter: null
email: null
tags: [tag1]
---
适用于无需复杂信息丰富的简单联系人:
markdown
---
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

Person Name

Contact Channels

联系渠道

  • ...
  • ...

Key Context

关键背景

  • ...

Write to `~/Vault/Contacts/Person Name.md` and add `[[Person Name]]` to `index.md`.
  • ...

将文件写入`~/Vault/Contacts/Person Name.md`,并在`index.md`中添加`[[Person Name]]`。

Updating Contacts

更新联系人

Re-run enrichment with the existing vault path:
json
{
  "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.
通过指定现有Vault路径重新触发 enrichment 流程:
json
{
  "name": "contact/enrich.requested",
  "data": {
    "name": "Person Name",
    "vault_path": "Contacts/Person Name.md",
    "depth": "full"
  }
}
合成器会将新数据与现有内容合并,除非存在矛盾信息,否则不会丢弃已有的事实。

VIP Contacts (ADR-0151)

VIP联系人(ADR-0151)

Mark
vip: true
in frontmatter. VIPs get deep enrichment + ongoing monitoring.
在前置元数据中标记
vip: true
。VIP联系人会获得深度信息丰富 + 持续监控服务。

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 interview
Appearance 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)
每个VIP联系人都会获得完整的信息处理。以下是2026年2月26日为Kent C. Dodds执行的流程:
步骤来源采集内容
1. 网络存在感网页搜索
{name} + {org}
个人简介、职位、所在地、个人细节
2. 播客/访谈网页搜索
{name} podcast interview
参与节目列表、自有播客、受众群体
3. 与Joel的合作个人网站、参与页面联合播客、共同组织的活动、合作项目
4. 职业 timeline解析2-3份关键访谈记录起源故事、职业发展轨迹、关键决策、价值观
5. GitHub档案GitHub API或网页仓库、关注者、所属组织、贡献模式
6. X/Twitter档案X API v2(使用x-api skill)个人简介、关注者、近期推文、互动数据
7. 关键关系交叉引用访谈记录 + 联系人列表合作对象、提及的人、共同认识的人
8. 内容目录网站爬取(defuddle)课程、博客文章、开源项目
9. 受众覆盖播客订阅量、社交平台关注者会议参与情况、社区影响力
信息丰富后导入Typesense:
  • 将参与的节目/内容批量导入
    discoveries
    集合(NDJSON格式,
    action=upsert
  • 为所有文档添加联系人名称的短标识(如
    kent-c-dodds
    )以便筛选
  • 字段:
    id
    title
    url
    summary
    tags[]
    timestamp
  • 创建
    Vault/Resources/{name}-media-appearances.md
    参考文档,关联到对应的联系人
Vault笔记中的输出章节:
  • 背景与经历(起源、职业 timeline)
  • 教学/工作理念(非教育从业者可调整为对应内容)
  • 关键关系(通过
    [[维基链接]]
    关联到其他联系人)
  • 受众与覆盖范围
  • 内容/产品
  • 与Joel的播客/合作历史
  • 近期活动(带时间戳)

Ongoing Monitoring (Phase 2-4 of ADR-0151)

持续监控(ADR-0151的第2-4阶段)

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.
渠道工具信号
Google Alertsjoelclawbot Google账号新闻、博客、媒体中的姓名提及
X/Twitter列表joelclaw X账号推文、互动数据
GitHub活动GitHub API(轮询)新仓库、新版本发布
播客RSS订阅源监控新节目上线
网站变更定期爬取(defuddle)+ 差异对比博客文章、新功能上线、个人简介变更
高优先级信号(立即通知):课程发布、职位变更、提及Joel/egghead/Skill、融资信息。 低优先级信号(每日/每周汇总):常规推文、博客文章、开源项目活动。

Current VIPs

当前VIP联系人权益

  • 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
  • 信息丰富完成后通过网关通知Joel
  • 每周通过定时任务自动刷新信息
  • 在渠道智能管道中享有优先级(ADR-0131、ADR-0132)
  • 当ADR-0151第2+阶段落地后,将获得持续监控服务

Roam Research Enrichment

Roam Research信息丰富

Joel's Roam archive (
~/Code/joelhooks/egghead-roam-research/
) contains the full egghead-era graph (2019-2024). Many contacts have extensive history there.
Joel的Roam存档(
~/Code/joelhooks/egghead-roam-research/
)包含2019-2024年egghead时期的完整图谱。许多联系人在其中有详细的历史记录。

Quick Search (Python regex)

快速搜索(Python正则表达式)

bash
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]}')
"
bash
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]]
    )
在Roam中,人员通过关系前缀进行标记:
  • [[collaborator/Name]]
    — 战略合作伙伴(Ian Jones、Alex Hillman)
  • [[client/Name]]
    — egghead讲师(Matt Pocock、Jacob Paris)
  • [[staff/Name]]
    — egghead团队成员(Will Johnson、Daniel Miller、Maggie Appleton)
  • [[name]]
    (无前缀) — 非正式提及(Zac标记为
    [[zac]]

Page Title Search

页面标题搜索

bash
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}')
"
bash
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:
yaml
roam_tag: "[[collaborator/Ian Jones]]"
This enables future re-queries and cross-referencing.
从Roam提取人员数据时,在前置元数据中添加
roam_tag
yaml
roam_tag: "[[collaborator/Ian Jones]]"
这将支持后续的重新查询和交叉引用。

Datalog Queries (advanced)

Datalog查询(进阶)

The EDN file is Datomic-style. Clojure scripts exist at
scripts/
for structured analysis. See the
roam-research
skill for full Datalog patterns.
EDN文件采用Datomic风格。
scripts/
目录下有Clojure脚本用于结构化分析。完整的Datalog模式可参考
roam-research
skill。

Resolving Unknown People

未知人员身份解析

When you encounter a Slack user ID (
<@U0XXXXXXX>
):
bash
undefined
当遇到Slack用户ID(
<@U0XXXXXXX>
)时:
bash
undefined

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.
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

然后使用解析出的姓名和提示信息触发信息丰富流程。

Inngest Function

Inngest函数

  • 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
  • 函数:
    contact-enrich
    packages/system-bus/src/inngest/functions/contact-enrich.ts
  • 事件:
    contact/enrich.requested
  • 决策记录(ADR):
    ~/Vault/docs/decisions/0133-contact-enrichment-pipeline.md
  • 并发限制:最多3个
  • 数据源:Slack、Slack Connect、Roam存档、GitHub/网页、Granola会议、记忆召回、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
  • 联系人文件存储在Vault中(私有,不提交到公开仓库)
  • Slack数据保持私有,绝不会出现在公开内容中
  • 邮箱/电话仅用于Joel的个人参考