Obsidian plugin, in progress
Your calendar, grafted onto your notes.
Graft reads your Google and Outlook calendars and makes one meeting note per event. Each note links to the people and series already in your vault and uses your own template.
It only reads. It never changes a calendar, and by default you see every change before it's written.
Why graft? Gardeners join a cutting, the scion, to a plant that already has roots, the rootstock, and the two grow into one plant. Here the calendar event is the cutting, your vault is the rooted plant, and the meeting note is the join.
01
Cut
Each calendar is a private ICS address. Copy it from Google Calendar or Outlook and paste it into Graft. You can add as many calendars as you want, and you don't sign in to anything.
Anyone with that address can read the calendar, so on Obsidian 1.11.4 and later Graft stores it in Obsidian's secret storage on your device, outside the plugin's settings file.
Then trim what you don't want as notes. Skip events by title (exact, starts with, ends with or contains), or with an ignore list you edit yourself. Every skipped event keeps its reason, and the preview shows it.
02
Fit
Next Graft looks things up in your vault and links to what's already there.
- People
- Matched by email, aliases included. If nobody matches, Graft makes a small Person note so the next run finds it and nobody gets created twice.
- Series
- A recurring event links to its Series note. If there isn't one, Graft creates it the first time the event shows up.
- Companies
- Optional, and off by default. When it's on, companies are linked to Company notes you already have.
- Meetings
- One note per event, found again by the event's UID and never by title or time, since those are what change.
---
title: Quarterly planning sync
scheduled_start: 2026-10-08T15:00:00Z
scheduled_end: 2026-10-08T15:45:00Z
organizer: "[[Sam Rivera (example.com)]]"
series: "[[Quarterly planning]]"
ics_uid: [email protected]
ics_recurrence_id: 20261006T150000Z
---Retitle this meeting or move it to Thursday and the same note gets updated. The recurrence id keeps the original start, so it still points at the 6th.
03
Bind
Run Preview sync and Graft shows the whole plan before it writes anything: new notes, changes to existing ones with the old and new value of each field, new Person and Series notes, and skipped events with their reasons. Select Apply when it looks right.
- newQuarterly planning syncThu Oct 8, 3:00 PM
- new1:1 with SamFri Oct 9, 10:00 AM
- updateDesign reviewstart moved to 2:30 PM
- stubPriya Nair (example.com)new Person, email only
- skippedFocus timecalendar block
- skippedTeam offsite logisticson your ignore list
A calendar inside Obsidian
Graft has its own calendar view. Open it from the ribbon icon or the Open calendar command, and dock it in a sidebar or keep it in a tab. It's an hourly grid with 3-day and week layouts, covering 14 days back and 30 days ahead.
Calendars are read once and kept in memory, and Refresh reads them again. If one feed fails, the others still show. Select an event and Open note jumps to its Meeting note, if it has one. The view never writes notes.
04
Grow
Syncing is manual by default. Run Preview sync, or Sync now, or turn on Sync on startup. You can also let Graft check on its own.
Automatic sync
Scheduled sync runs every 15 to 1440 minutes (60 by default) while Obsidian is open. It's off until you pick a mode.
- Off
- No background checks.
- Notify
- Checks for changes and tells you how many are waiting, in a notice and the status bar. Click either to open a fresh preview.
- Automatic
- Runs the same check, then applies the changes itself, as if you'd read the preview and pressed Apply.
Automatic has guardrails. It won't apply a plan that has a calendar error or an ambiguous Person. A plan over 25 notes (you can change that limit) is left for you to review. If a note changed after the plan was made, it tries again at the next interval. Pick a sync log note to see what each run wrote.
Graft owns
Title, channel, organizer, invitees, series, start and end, the invite-updated stamp, companies, the two ICS ids, and the Invite Agenda section.
You own
Participants, actual times, transcripts, project links and the rest of the body, byte for byte. The Series Agenda is copied in once when the note is made, and after that it's yours.
If an event drops out of a feed, Graft can't tell a cancellation from a permission change or a broken feed, so it warns you in the preview and leaves the note alone. You can turn on Cancel vanished series, which marks a recurring event cancelled once at least two future dates are missing. It's off by default.
House rules
- It only reads. A feed can't create, move or delete an event, and no model decides anything. Filtering and matching use plain rules you can predict.
- You read the changes first. Preview before apply is on by default, and the preview and the real run use the same plan.
- One kind of network request. It downloads your calendar feeds and makes no other request, with no account and no telemetry.
Smaller things
- Templates
- Optional templates for Meeting, Person and Series notes, with placeholders like {{title}} and {{organizer}}. Templater isn't needed and its scripts aren't run. A placeholder Graft doesn't know stays in the note as written, so a typo is easy to spot.
- Your own schema
- Folders, property names, headings and note types are all settings. There are two presets, and the default is the minimal one.
- Same event twice
- If an invite shows up in two calendars, you get one note, from the calendar higher in your list. The other copy is listed as skipped.
- Clean invites
- Teams, Meet and Zoom join links, passcodes and dial-in numbers are removed from the agenda text. You can turn that off.
- Forwarded titles
- FW:, Fwd: and RE: are stripped from titles before anything else runs. The note is still found by UID, so a forward doesn't create a duplicate.
- Accepted only
- An optional filter that skips events you've declined or haven't answered. It's off by default. Google feeds include responses. Outlook feeds may not, and I haven't tested that yet.
- Sync log
- Optionally point Graft at a note and it adds an entry after each run that wrote something, with links to the notes it touched.
- Sync window
- Days back and days ahead are yours to set. The defaults are 7 and 30.
Written in TypeScript against the Obsidian plugin API, with ical.js, Luxon and esbuild. Read the technical writeup.
Questions
Does it ever change my calendar?
No. It reads a feed and that's all it can do. To ignore an event you edit a plain list yourself.
Why an ICS address and not a sign-in?
Graft needs no registered app and no server. It fetches the feed with Obsidian's own request function, straight from Google or Microsoft.
Can it sync by itself?
Yes, if you turn it on. Scheduled sync can just tell you when changes are waiting, or apply them itself. It's off by default.
Will a resync overwrite what I wrote?
Graft updates a fixed list of calendar fields and the Invite Agenda section. Everything else in the note stays as you wrote it.
What if an event disappears from a feed?
You get a warning in the preview and the note stays. Marking a recurring event cancelled when dates go missing is an option, and it's off by default.
Do I need a specific note setup?
Not really. Folders, property names, headings and templates are settings, so you can point Graft at the layout you already have.
Does it work on mobile?
It isn't desktop-only, so it can run in Obsidian mobile. There's no status bar there, so you only get notices, and the system may pause the timer in the background.
Can I get it?
Not yet. It's built, but I haven't finished testing it against real Google and Outlook feeds, so I'm holding it back. The source is private for now.