Andrea Grandi14 downloadsSync meeting transcripts, notes, and AI summaries from MacParakeet and Fellow into your vault.
Obsidian plugin that syncs your meeting transcripts, notes, and AI summaries into your vault — from MacParakeet and Fellow, one folder per meeting. A meeting recorded by both sources merges into a single folder instead of duplicating.
Summary (MacParakeet).md, Summary (Fellow).md), so a meeting captured by both stays unambiguous.merge-confidence: low for review.Meetings/2026/06 - June/2 - Weekly Standup - Jun 11th/
2 - Weekly Standup - Jun 11th.md ← index: macparakeet-id + fellow-id + interval
Summary (MacParakeet).md
Transcript (MacParakeet).md
Notes.md
Summary (Fellow).md
Action Items (Fellow).md
Transcript (Fellow).md
Each source is toggled independently; a disabled source is completely inert — no requests, writes, or notices.
Reads meetings from macparakeet-cli (no network, no accounts, no database access). Requires macOS with MacParakeet installed (the CLI ships inside the app) or the standalone CLI (brew install moona3k/tap/macparakeet-cli), and Obsidian desktop. The plugin auto-detects the CLI (Homebrew paths, then the app bundle); override the path in settings if needed, and the health check confirms it. Enable it in Settings → Meeting Notes Sync.
Polls Fellow's REST Developer API for cloud AI recaps. Setup:
acme in acme.fellow.app) and key, then use Check connection to verify.⚠️ The Fellow key is stored in plaintext in
data.json(standard for API-backed plugins). If your vault is in git or a synced folder, exclude that file and treat the key as a secret; revoke it in Fellow if it leaks.
Pending community-store review — until it lands there, install via BRAT (Add beta plugin → andreagrandi/obsidian-meeting-notes-sync), or manually drop main.js + manifest.json from a release into <vault>/.obsidian/plugins/meeting-notes-sync/ and enable the plugin. To build from source:
git clone https://github.com/andreagrandi/obsidian-meeting-notes-sync
cd obsidian-meeting-notes-sync && npm install && npm run build
# copy main.js + manifest.json into <vault>/.obsidian/plugins/meeting-notes-sync/
If you used an earlier build under the macparakeet-sync id: quit Obsidian, rename <vault>/.obsidian/plugins/macparakeet-sync/ → meeting-notes-sync/, reopen, and re-enable. This keeps data.json (numbering, snapshots, file ownership) so the next sync is a no-op instead of re-importing. Existing folders keep their names; only new artifacts get the source suffix.
Sync runs shortly after launch and every 30 minutes (configurable; 0 disables), or on demand via the ribbon icon / Sync now. The main settings:
Meetings/… is the root).{year} · {month} · {monthName} (June) · {monthShort} (Jun) · {day} · {dayOrdinal} (2nd) · {date} (YYYY-MM-DD) · {n} (per-month number) · {title}. Unknown tokens are left as-is.
Default: Meetings/{year}/{month} - {monthName}/{n} - {title} - {monthShort} {dayOrdinal} → Meetings/2026/06 - June/4 - Core sync-discovery - Jun 2nd. The trailing date disambiguates recurring meetings that share a title.
Overlap threshold (fraction of the shorter meeting, default 0.5) and minimum overlap (minutes) govern when two sources' meetings are treated as one. Raise them to merge more conservatively.
| Command | What it does |
|---|---|
Sync now |
Sync enabled sources; reports X new, Y updated, Z unchanged |
Check connection |
Verify macparakeet-cli is reachable (Fellow's check lives in settings) |
Force re-sync |
Re-process all in-scope meetings (picks up in-place regenerated summaries) |
{n}) and the folder name are frozen on first import and never change — a later source merges in without renumbering.Each source sits behind a common adapter and a source-agnostic engine: MacParakeet via macparakeet-cli (meetings list/show/results list --json), Fellow via its REST API (/me, /recordings, /recording/{id}, /note/{id}) with updated_at change detection. Meetings are merged across sources by interval overlap, and sync state (numbering, per-file ownership, per-source snapshots) lives in data.json. Details in PLAN.md.
npm install
npm run dev # esbuild watch
npm test # vitest
npm run build # typecheck + production bundle
CI runs build + tests on every push and PR.
Live Fellow test — npx -y tsx scripts/fellow-live-test.mts runs the real engine (local CLI + live Fellow API) into a temp vault. It reads FELLOW_SUBDOMAIN / FELLOW_API_KEY from .env (see .env.example) for the harness only; the plugin itself never reads the environment — end users configure the subdomain and key in the settings UI.
Releasing — npm run release <major.minor.patch> (e.g. npm run release 0.3.1) bumps package.json, manifest.json, versions.json, and the lockfile, then commits and creates the unprefixed X.Y.Z tag. Push it (git push origin master && git push origin <version>) to trigger .github/workflows/release.yml, which attests main.js's build provenance and attaches main.js + manifest.json to a GitHub release (Obsidian downloads only those two; versions.json is read from the repo). A plain npm run script is used (not the npm version lifecycle hook) so it works regardless of a global ignore-scripts=true. Community-store submission to obsidianmd/obsidian-releases is a one-time manual step after the first release.