Cadence is a local macOS calendar app I built because I’ve been timeboxing for 5+ years and wanted a better way to look at my schedule historically. I wanted to answer a few basic questions more clearly: where am I spending most of my time, what patterns show up week by week, and how can I plan my days more efficiently and live a little more intentionally.
- Syncs macOS Calendar through a Swift EventKit helper.
- Imports exported
.icscalendar files as a fallback. - Stores events and analysis locally in SQLite.
- Categorizes events with a layered pipeline: cache, local keyword model, Ollama, then OpenAI for unresolved titles.
- Shows weekly category breakdowns and day-by-day timeline strips.
- Helps me see how full my calendar is at a glance.
- Detects context switches between back-to-back events in different categories.
- Generates thematic day suggestions and weekly insights.
- Tracks category trends across historical weeks.
- Includes a Week Planner agent with a LangGraph flow, streamed trace, human review, approval, and redraft loop.
- Includes an MCP server that can expose local Cadence data to configured MCP clients.
- Electron
- React + Vite
- TypeScript
- SQLite via
better-sqlite3 - Swift + EventKit
ical.js- Vercel AI SDK with OpenAI models
- Ollama for local fallback classification
- LangGraph for the week planner state machine
- MCP SDK
- Tailwind CSS dependency is present, though most current UI is inline styled.
Calendar data enters through electron/calendarSync.ts, either from resources/cadence-helper or an imported .ics file. Events are normalized and written to SQLite by electron/db.ts.
On sync, uncategorized events run through the categorization pipeline in electron/main.ts:
- Exact title cache lookup.
- Local keyword model trained from prior categorized events.
- Ollama classification when available.
- Batched OpenAI classification for remaining unique titles.
Weekly analysis is generated from local event data and rendered in the React app. The renderer talks to Electron through the preload bridge only.
The Week Planner lives in agent/langraph/. It runs:
constraint -> task -> energy -> draft -> human review -> write
Rejected drafts loop back through draft, capped at three rounds.
The MCP server is built at dist-electron/mcpServer.js. It does not connect automatically to Claude Desktop or other clients; those clients need their own MCP config pointing at the built server.
npm install
npm run devBuild the app:
npm run buildRebuild the Swift calendar helper:
./swift-helper/build.shType-check:
npm run typecheckCadence keeps calendar data local. API calls are used only for categorization and analysis steps that cannot be resolved locally.
The layered categorization design is meant to reduce repeat API calls over time by caching user-specific event patterns.
