cortex

Chronote Architecture

Overview

Chronote is an Obsidian plugin that combines spaced repetition (SRS), Google Calendar integration, and AI-powered study planning into a single command center — all running locally inside your vault.

High-level Architecture

┌─────────────────────────────────────────────────────────────┐
│                    Obsidian Plugin Host                      │
│  ┌─────────────┐  ┌──────────────┐  ┌─────────────────────┐ │
│  │  main.ts    │  │  settings.ts │  │  ChronoteDashboardView │ │
│  │  (lifecycle)│  │  (config)    │  │  (UI / data hub)     │ │
│  └──────┬──────┘  └──────────────┘  └─────────────────────┘ │
│         │                                                    │
│  ┌──────▼──────┐  ┌─────────────┐  ┌─────────────────────┐ │
│  │  Commands   │  │ TestService │  │ GoogleCalendarService│ │
│  │  (review,   │  │  (tests)    │  │  (OAuth / REST)      │ │
│  │   tests)    │  └─────────────┘  └─────────────────────┘ │
│  └────────────┘                                │             │
│                                                 ▼             │
│  ┌──────────────────────────────┐  ┌─────────────────────┐   │
│  │   AI Service Registry        │  │   Vector Index      │   │
│  │ (Gemini / OpenAI-compat /    │  │  (local embeddings, │   │
│  │  Anthropic / Chronote Cloud)   │  │   RAG search)       │   │
│  └──────────────────────────────┘  └─────────────────────┘   │
└─────────────────────────────────────────────────────────────┘

Plugin Lifecycle

Entry point: src/main.ts

  1. onload()
    • Loads settings via this.loadData() (merges with DEFAULT_SETTINGS from src/settings.ts).
    • Registers the custom view chronote-dashboard (src/views/ChronoteDashboardView.ts).
    • Detaches any stale dashboard leaves from previous loads.
    • Registers the Obsidian protocol handler chronote-auth to receive Google OAuth tokens after the browser flow.
    • Adds the ribbon icon and core commands (open-chronote-dashboard, plus the SRS and test commands).
    • Delegates SRS/test commands to Commands (src/commands.ts).
    • Adds the settings tab (ChronoteSettingTab).
  2. onunload()
    • Detaches all dashboard leaves.
    • The vector index is kept on disk; nothing in memory needs explicit teardown.

SRS Subsystem

Core logic: src/utils/srsLogic.ts
Frontmatter writer: src/commands.ts (applyReviewToFrontmatter)

Spaced repetition data lives in each note’s YAML frontmatter:

Algorithm (calculateNextReview):

The dashboard and chat modals read this data via app.metadataCache.getFileCache() — no separate database.

Test Subsystem

Owner: src/services/testService.ts

Tests are stored in plugin settings (ChronoteSettings.tests) as an array of:

{ id: string; name: string; date: string; filePaths: string[]; done?: boolean }

Calendar Integration

Owner: src/services/googleCalendarService.ts

AI Integration

Owner: src/services/ai/* (GeminiAdapter, OpenAICompatAdapter, AnthropicAdapter, createAdapter)

Vault Search (RAG)

Owner: src/agent/vectorIndex/*

Dashboard View Architecture

File: src/views/ChronoteDashboardView.ts

The dashboard is a single custom ItemView rendered into the workspace. It has three main panels:

  1. Google Calendar schedule — date-navigable; 30-second fetch cache; shows event times + links.
  2. Due Reviews — date-navigable; filterable by test and sortable by confidence score; overdue items are highlighted.
  3. Upcoming Tests — expandable test cards with progress bars, linked notes, exclude toggles, and done/delete actions.

Re-rendering is debounced: metadata changes from typing trigger a 2-second delay so the dashboard does not refetch the calendar on every keystroke.

Data Flow

User edits a note
    │
    ▼
Obsidian metadataCache updates frontmatter (confidence, interval, next_review, exam_date)
    │
    ├──► Dashboard reads metadataCache → renders due reviews + test progress
    │
    ├──► AI service reads metadataCache (via chat modal) → builds study plan context
    │
    ├──► GoogleCalendarService reads free/busy time → AI uses it for planning
    │
    ▼
AI returns suggested events → user approves in chat modal
    │
    ▼
GoogleCalendarService.createEvent() → POST to Google Calendar API
    │
    ▼
Dashboard re-fetches calendar → shows new events in schedule panel

Key conventions: