@raulanatol40 downloadsObsidian is the source of truth for your contacts; sync a chosen subset one-way to macOS Contacts, with desync alerts.
Obsidian is the source of truth for your contacts. Sync a chosen subset one-way to macOS Contacts, with clear alerts when the two drift out of sync.
macOS only. Contact Forge shells out to osascript (JXA) to talk to Contacts.app,
so it requires a desktop Obsidian on macOS. Nothing leaves your device.
Most Obsidian contact tools pull from Apple/Google/iCloud into your vault. Contact Forge does the opposite: you keep the full record — notes and all — in Obsidian, and push only the fields needed to identify callers, emails, and messages into a dedicated Contacts group. iOS benefits automatically via iCloud.
This is a deliberate inversion of raulanatol/obsidian-mac-sync-contacts
and a plugin-native take on the ideas proven by czottmann/obsidian-people.
Settings — choose the contacts folder, the source Contacts group, and which fields are managed.

Sync report — every run's desync alerts, one row per actionable card, with click-through actions.

Confirm before writing — a summary modal before anything touches Contacts.app.

The contact note — frontmatter holds the managed fields; the body stays freeform.

Contacts/).contact_note. The body is freeform and never synced.obsidian_uid (UUID). On sync, the matching Mac card is
stamped with a cf-uid: marker and an obsidian:// back-link, so matching survives
renames and Contacts re-indexing.Every run writes a Sync Report note. Each contact lands in one bucket:
osascript.This plugin requests capabilities beyond the typical Obsidian plugin because syncing to Contacts.app has no alternative on macOS. For transparency:
child_process): the only way to talk to Contacts.app is
osascript -l JavaScript. There is no Obsidian or Node API for it.fs, outside the vault): JXA payloads are written to a
temp file in os.tmpdir() and passed to osascript by path, then deleted. This
avoids the argv length limits and quoting bugs that come with inlining large
scripts via osascript -e. No vault or user file is ever touched through fs.vault.getMarkdownFiles()): Obsidian has no folder-scoped
listing API, so the plugin lists all markdown files and filters to the configured
contacts folder client-side before reading anything.Community plugin (pending review) or manual — see docs/INSTALLATION.md.
First run: grant System Settings → Privacy & Security → Automation → Obsidian → Contacts. Use the Test Contacts access command to trigger the prompt.
pnpm install
pnpm run dev # esbuild watch
pnpm test # pure unit tests (hash + reconciler)
pnpm run build # typecheck + production bundle
The reconciliation engine (src/sync/Reconciler.ts) and hashing (src/core/hash.ts)
are pure and fully unit-tested. See docs/BUILD_PLAN.md for the
full architecture and the phased build plan.
MIT © Raúl Anatol