8.9 KiB
O365 Calendar Integration — Design Spec
Goal
Integrate Microsoft Office 365 calendar with the Obsidian vault to enable meeting note creation with automatic participant matching, series recognition, and agenda pre-population. Two creation paths: manual (Templater) and Claude-assisted (MCP).
Scope
- In scope: Calendar read access, meeting note creation, participant matching, series recognition, agenda import
- Out of scope: Email integration (Phase 2), write-back to O365, automatic background sync, Copilot/Work IQ integration
Architecture Overview
┌─────────────────────────────────────────────────┐
│ Obsidian Vault │
│ │
│ 03 Bereiche/Meetings/ 00 Kontext/Personen/ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Meeting Notes │◄───│ Person Notes │ │
│ │ (per instance) │ │ (email matching) │ │
│ └──────────────────┘ └──────────────────┘ │
│ ▲ ▲ ▲ │
│ │ │ │ │
│ Templater Claude Person-Matcher │
│ Template (MCP) (shared logic) │
│ │ │ │
└──────────┼──────────┼─────────────────────────────┘
│ │
▼ ▼
┌──────────────────────┐
│ Microsoft Graph API │
│ (Azure App Reg) │
└──────────────────────┘
Components
| Component | Purpose | Location |
|---|---|---|
| MCP Server (Softeria) | Claude reads O365 calendar | ~/.claude/ config |
| Node.js User Script | Templater reads O365 calendar | scripts/o365-calendar.js |
| Person Matcher | Email → person note, auto-create | scripts/person-matcher.js |
| Meeting Template | Unified format for both paths | Templater template folder |
| Frontmatter extensions | email on persons, domain on companies |
Existing notes |
Vault Structure Changes
New folder
03 Bereiche/Meetings/— all meeting notes, flat, filenameYYYY-MM-DD Title.md
Person frontmatter extension
# New field added to all person notes
email: christopher.klein@krah.de # Primary match key
Company frontmatter extension
# New field added to company notes
domain: krah-gruppe.de # For auto-assignment person → company via email domain
Auto-created person notes
When a meeting participant has no match in the vault:
---
tags: [person]
vorname: Max
nachname: Müller
email: max.mueller@landata.de
kategorie: Extern
firma: "[[LANdata]]" # Wikilink if company note with matching domain exists
# Plain text "landata.de" otherwise
status: ungeprüft # Flag for manual review
---
# Max Müller
## Zur Person
- **E-Mail:** max.mueller@landata.de
- **Firma:** LANdata (landata.de)
## Notizen
Auto-created company notes
Companies are NOT auto-created. Only the domain is stored as plain text in the person note until a company note is manually created.
Meeting Note Template
---
tags: [meeting]
date: YYYY-MM-DD
start: "HH:MM"
end: "HH:MM"
serie: "Serie Name" # Empty if not recurring
projekt: # Wikilink to project if assignable
teilnehmer:
- "[[Person 1]]"
- "[[Person 2]]"
status: offen # offen / abgeschlossen
o365_id: "AAMkAG..." # For back-reference to O365
---
# Meeting Title
## Teilnehmer
- [[Person 1]] — Role/Context
- [[Person 2]]
## Agenda
- Imported agenda items
## Notizen
## Entscheidungen
## Aufgaben
Matching Logic
Participant matching (priority order)
- Email match: Search
00 Kontext/Personen/for matchingemailfrontmatter field - Name fallback: Compare O365
displayNameagainstvorname+nachnamein person notes - Auto-create: No match → create new person note with
status: ungeprüft, derive company from email domain
Company matching via email domain
- Extract domain from email address (e.g.,
landata.defrommax@landata.de) - Search
00 Kontext/Firmen/for matchingdomainfrontmatter field - Match found → Wikilink to company note
- No match → store domain as plain text
Series recognition
- Check O365 event for
seriesMasterId→ recurring meeting - Match event title against folder names in
03 Bereiche/Jour Fixe/*/Agenda.md - Match found → populate
seriefield, link to Jour Fixe agenda
Agenda pre-population (priority order)
- Jour Fixe agenda: Series recognized → import open items (
🔴 Offensection) from03 Bereiche/Jour Fixe/[Serie]/Agenda.md - O365 event body: No series or Jour Fixe empty → use calendar event body text
- Empty: Both empty → empty agenda section
Creation Path A: Manual via Templater
- User triggers template (hotkey or command palette)
- Templater User Script calls Node.js helper
- Node.js script authenticates via Azure App Registration (Delegated OAuth2 flow)
- Fetches calendar events (today + next 7 days)
- Presents selection list:
📅 14:00-15:00 IT Team Weekly | 📅 16:00-16:30 Call mit LANdata - User selects → script returns event data as JSON
- Templater renders note, runs participant matching, writes file to
03 Bereiche/Meetings/
Components
scripts/o365-calendar.js— Node.js script, Graph API client, OAuth2 token managementscripts/person-matcher.js— Reads person notes, matches by email/name, creates new person notes- Templater template referencing both scripts
Creation Path B: Via Claude (MCP)
- User says "Leg Meeting-Notiz an" or similar
- Claude calls MCP tools:
list-calendar-events→ find event →get-event-details - Claude applies same matching logic (persons, series, agenda)
- Claude creates note in same format
MCP Server
- Server:
softeria/graph-mcp-server(or best available alternative at implementation time) - Config:
~/.claude/MCP server configuration - Auth: Same Azure App Registration as Templater path
- Scope: Read-only calendar access
Matching rules in CLAUDE.md
The matching rules (email → person, domain → company, title → series) are documented in CLAUDE.md so Claude applies them consistently without the Node.js scripts.
Boundaries
Meeting Notes vs. Daily Notes
- Daily Notes remain unchanged: daily log, decisions, short notes
- Meeting Notes are standalone documents in
03 Bereiche/Meetings/ - Connection via wikilinks: Daily Note can link to meeting note
Meeting Notes vs. Jour Fixe
- Jour Fixe remains the running agenda management (Offen/Postponed/Dauerläufer)
- Meeting Notes are per-instance protocols
- For Jour Fixe series: typically NO meeting note created, work directly in agenda
- If created: agenda imported from Jour Fixe, meeting note links back
What does NOT happen
- No automatic background synchronization
- No email copies in vault (calendar only in Phase 1)
- No write-back to O365
- No automatic meeting note creation — always conscious decision
Documentation
A user-facing documentation note will be created at 03 Bereiche/IT-Management/O365 Kalender Integration.md. This note explains:
- What the integration does and how it works (non-technical overview)
- How to create a meeting note manually (Templater workflow, step by step)
- How to create a meeting note via Claude
- How participant matching works (email → person, auto-creation)
- How series recognition and agenda import work
- Where meeting notes are stored and how to find them
- Known limitations and planned future extensions (email integration)
This is a living document, updated as the integration evolves.
Prerequisites
- Add
emailfield to all existing person notes (6 KRAH employees) - Add
domain: krah-gruppe.deto KRAH company note - OAuth2 flow: Application (Client Credentials) — app-only access to user's calendar
- Node.js available on system
- Evaluate Softeria MCP server compatibility at implementation time
- Create user documentation at
03 Bereiche/IT-Management/O365 Kalender Integration.md
Open Questions
- Exact OAuth2 token storage/refresh strategy for Templater Node.js script
- Softeria MCP server: verify it supports delegated auth and calendar event listing with sufficient detail (body, attendees, recurrence)
- Fallback if Softeria is insufficient: build minimal custom MCP server against Graph API