From david-skills
Imports VCF contacts into Obsidian vault wiki/people/ pages as Markdown files, parsing names/emails/phones, handling Chinese formats, phone masking, and cross-referencing existing pages.
npx claudepluginhub thedavidweng/skillsThis skill uses the workspace's default tool permissions.
Import contacts from a `.vcf` export into wiki/people/ pages in an Obsidian vault.
Guides Next.js Cache Components and Partial Prerendering (PPR): 'use cache' directives, cacheLife(), cacheTag(), revalidateTag() for caching, invalidation, static/dynamic optimization. Auto-activates on cacheComponents: true.
Processes PDFs: extracts text/tables/images, merges/splits/rotates pages, adds watermarks, creates/fills forms, encrypts/decrypts, OCRs scans. Activates on PDF mentions or output requests.
Share bugs, ideas, or general feedback.
Import contacts from a .vcf export into wiki/people/ pages in an Obsidian vault.
inbox/identity/contacts.vcf or similar)wiki/people/ (optional — works for fresh imports too)system/scripts/vault-audit.mjs (optional)import re
vcards = re.split(r'BEGIN:VCARD', open('contacts.vcf').read())[1:]
for v in vcards:
fn = re.search(r'FN:(.+)', v).group(1)
emails = re.findall(r'EMAIL[^:]*:(.+)', v)
tels = re.findall(r'TEL[^:]*:(.+)', v)
Critical: The sandbox runtime may mask phone numbers at the output/display level (+177****6585). The actual VCF file contains complete numbers.
Detection: Occurrences of **** in file: 0 but Python output shows ****.
Fix: Use hex dump to read real numbers from the VCF, then write complete numbers into wiki files:
# Get real number from VCF hex
sed -n 'LINE_START,LINE_ENDp' contacts.vcf | xxd | grep TEL
# Decode hex manually: 2b=+ 31=1 37=7 ...
# Write complete number into wiki (never write **** masked numbers)
Verify with: grep -c '\*\*\*\*' wiki/people/*.md should return 0.
VCF format: givenname surname (e.g., "san zhang")
Wiki convention: surname givenname (e.g., "zhang-san")
File naming: surname-givenname.md using pinyin. NO English aliases in filename.
wang-er.mdwang-er-mother.mdzhao-wu.md → zhao-wu.mdAliases field: Include both Chinese name and English nickname for searchability:
aliases: ['zhang-san', 'John Doe']
Build a lookup map that handles BOTH orderings:
vcf_by_cn = {}
for c in parsed:
cn = ''.join(ch for ch in c['fn'] if '\u4e00' <= ch <= '\u9fff')
if cn:
vcf_by_cn[cn] = c # e.g., "hua li"
parts = c['fn'].split()
if len(parts) == 2 and all('\u4e00' <= ch <= '\u9fff' for ch in ''.join(parts)):
reversed_name = parts[1] + parts[0] # e.g., "li-hua" (matches wiki format)
vcf_by_cn[reversed_name] = c
Then match wiki aliases against this map. Also store by nickname for English name matching.
English nickname collisions — common names (Peter, John, David, Jack, Leo, etc.) may match multiple people. NEVER match by English nickname alone. Verify with QQ number, email, or phone overlap.
Before creating new pages, check for duplicate pages (same person, different filename). Compare aliases, emails, and phone numbers across all existing pages.
---
layer: wiki
kind: person
updated: YYYY-MM-DD
aliases: ['中文名', 'English Name']
tags: [person]
status: active
---
# 中文名 / English Name
Brief description in third person (Wikipedia style, NOT "David's friend").
## Contact
- Email: ...
- Phone: ... (verify no **** masking)
- Birthday: YYYY-MM-DD
## Sources
- [[sources/identity/contacts.vcf]]
Add new pages to system/wiki/index.md People section and update page count.
cd vault-root && node system/scripts/vault-audit.mjs
xxd before writing.\d{17}[\dXx]), school names, hometown addresses, parent contact info. Extract and add to Notes section.YYYYMMDD or --MMDD (year unknown). Convert to YYYY-MM-DD.item2.X-ABRELATEDNAMES with relationship labels (Husband, Father etc.) and item1.X-ABDATE with marriage anniversary. Capture for family wiki pages.status: inactive in frontmatter, note relationship period in body text.