contacts

contacts

在 Joel 的 Vault 中新增、豐富與管理聯絡人。觸發 Inngest 豐富化管線以取得完整的多來源檔案,或手動快速建立聯絡人。適用於:「新增聯絡人」、「豐富此人資料」、「X 是誰」、「VIP 聯絡人」、「更新聯絡人」或任何涉及 Vault/Contacts 目錄的任務。

61星標
3分支
更新於 2026/7/23
SKILL.md
唯讀
名稱
contacts
描述

在 Joel 的 Vault 中新增、豐富與管理聯絡人。觸發 Inngest 豐富化管線以取得完整的多來源檔案,或手動快速建立聯絡人。適用於:「新增聯絡人」、「豐富此人資料」、「X 是誰」、「VIP 聯絡人」、「更新聯絡人」或任何涉及 Vault/Contacts 目錄的任務。

版本
1.0.0

Contacts

管理 ~/Vault/Contacts/ 中的聯絡人。每個聯絡人是一個帶有 YAML 前置資料的 Markdown 檔案。

聯絡人檔案位置

~/Vault/Contacts/<Name>.md

索引檔案:~/Vault/Contacts/index.md — 所有聯絡人的 wikilink 列表。

前置資料結構

---
name: Full Name
aliases: [nickname, handle]
role: Current Role / Title
organizations: [Org1, Org2]
vip: true  # 或 false
slack_user_id: U0XXXXXXX
slack_dm_channel: D0XXXXXXX  # 未知則為 null
website: https://example.com
github: username
twitter: handle
email: user@example.com
tags: [vip, instructor, creator, family, employee]
---

區段

# Name

## Contact Channels
- Slack, email, 社群帳號, 網站

## Projects
- 進行中的專案、課程、合作

## Key Context
- 關係備註、工作風格、歷史

## Recent Activity
- YYYY-MM-DD | 頻道 | 摘要

完整豐富範例請見 ~/Vault/Contacts/Matt Pocock.md

新增聯絡人

選項 1:觸發豐富化管線(建議)

發送 Inngest 事件。contact-enrich 函數會分散查詢 Slack、Roam、網頁/GitHub、Granola、Brain-backed 回憶及其他索引來源,透過 LLM 綜合處理,並寫入 Vault 檔案。

# 透過 curl(CLI 在 Bun v1.3.9 下有 OTEL 匯入錯誤)
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
  }]'

深度模式:

  • full(約 60 秒,約 $0.05):所有 7 個來源 + LLM 綜合。適用於新聯絡人或定期更新。
  • quick(約 10 秒,約 $0.01):僅 Slack + 記憶。適合即時 VIP 偵測。

提示為選填,但有助於搜尋: 任何已知識別碼(Slack ID、GitHub、email、Twitter、網站)可引導搜尋並改善結果。

選項 2:快速手動建立

適用於簡單聯絡人,無需豐富化:

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

寫入 ~/Vault/Contacts/Person Name.md,並將 [[Person Name]] 加入 index.md

更新聯絡人

使用現有 Vault 路徑重新執行豐富化:

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

綜合器會將新資料與現有內容合併 — 除非矛盾,否則不會捨棄既有事實。

VIP 聯絡人(ADR-0151)

在前置資料中標記 vip: true。VIP 會獲得深度豐富化 + 持續監控

深度豐富化操作手冊(一次性)

每位 VIP 都會接受完整處理。以下是我們為 Kent C. Dodds 所做的(2026 年 2 月 26 日):

步驟 來源 要擷取的內容
1. 網路足跡 網路搜尋 {name} + {org} 簡介、角色、地點、個人細節
2. Podcast/訪談 網路搜尋 {name} podcast interview 露面列表、自有 podcast、聽眾
3. Joel 合作 他們的網站、露面頁面 共同 podcast、共同舉辦活動、共享專案
4. 職涯時間軸 Defuddle 2-3 篇關鍵訪談逐字稿 起源故事、職涯軌跡、關鍵決策、價值觀
5. GitHub 個人檔案 GitHub API 或網頁 儲存庫、跟隨者、組織、貢獻模式
6. X/Twitter 個人檔案 X API v2(使用 x-api 技能) 簡介、跟隨者、近期推文、互動
7. 關鍵關係 交叉比對逐字稿 + 聯絡人 他們與誰合作、提及誰、我們共同認識誰
8. 內容目錄 網站爬取(defuddle) 課程、部落格文章、開源專案
9. 受眾觸及 Podcast 集數、社群跟隨者數 會議巡迴、社群影響力

豐富化後索引至 Typesense:

  • 批次匯入露面/內容至 discoveries 集合(NDJSON,action=upsert
  • 為所有文件加上人物名稱 slug 標籤(例如 kent-c-dodds)以便篩選
  • 欄位:idtitleurlsummarytags[]timestamp
  • 撰寫 Vault/Resources/{name}-media-appearances.md 參考文件,連結回聯絡人

Vault 筆記中的輸出區段:

  • Background & Story(起源、職涯時間軸)
  • Teaching/Work Philosophy(或非教育者的對應內容)
  • Key Relationships(交叉連結 [[wikilinks]] 至其他聯絡人)
  • Audience & Reach
  • Content/Products
  • Podcast/Collaboration History with Joel
  • Recent Activity(附時間戳)

持續監控(ADR-0151 第 2-4 階段)

頻道 工具 訊號
Google 快訊 joelclawbot Google 帳號 新聞、部落格、媒體中提及姓名
X/Twitter 列表 joelclaw X 帳號 推文、互動
GitHub 活動 GitHub API(輪詢) 新儲存庫、發行版本
Podcast RSS Feed 監控 新集數
網站變更 定期 defuddle + 差異比對 部落格文章、發布、簡介變更

高訊號(立即):課程發布、角色變更、提及 Joel/egghead/Skill、募資。
低訊號(每日/週摘要):一般推文、部落格文章、開源活動。

現有 VIP

  • 豐富化後透過閘道通知 Joel
  • 每週透過排程 cron 更新
  • 在頻道情報管線中擁有優先權(ADR-0131、ADR-0132)
  • 當 ADR-0151 第 2 階段以上實作後,將獲得持續監控

Roam Research 豐富化

Joel 的 Roam 存檔(~/Code/joelhooks/egghead-roam-research/)包含完整的 egghead 時代圖譜(2019-2024)。許多聯絡人在其中有豐富的歷史。

快速搜尋(Python 正規表示式)

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'找到 {len(matches)} 個區塊')
for m in matches[:30]:
    print(f'  - {m[:200]}')
"

人物分類

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

頁面標題搜尋

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'  頁面: {m}')
"

加入聯絡人

從 Roam 擷取人物資料時,在前置資料中加入 roam_tag

roam_tag: "[[collaborator/Ian Jones]]"

這有助於未來重新查詢與交叉比對。

Datalog 查詢(進階)

EDN 檔案是 Datomic 風格。Clojure 腳本位於 scripts/ 目錄,用於結構化分析。完整 Datalog 模式請參閱 roam-research 技能。

解析未知人物

當遇到 Slack 使用者 ID(<@U0XXXXXXX>)時:

# 取得臨時 token 並查詢個人檔案
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 函數

  • 函數:contact-enrichpackages/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 會議、Brain-backed 回憶及其他索引來源

隱私

  • 聯絡人檔案位於 Vault(私人,不在公開儲存庫中)
  • Slack 資料保持私密 — 絕不公開顯示
  • Email/電話僅供 Joel 參考