Skip to content

yuvanadarsh/meridian

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

205 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Meridian

A local-first personal AI operating system — voice-enabled, email-aware, with a PostgreSQL memory layer.

Meridian Dashboard

A local-first personal AI operating system. Meridian manages your email accounts, calendars, and daily information — and lets you interact with all of it through a voice-enabled animated interface. All data is stored locally; the only outbound calls are to Claude, VoyageAI, ElevenLabs, and Google APIs.

Knowledge Graph


Features (Phase 1)

  • Animated orb UI with idle, listening, thinking, and speaking states
  • Gmail OAuth for multiple accounts with email sweep and triage
    • Correct MIME tree body parsing (multipart, nested parts, base64url)
    • Case-insensitive header extraction
    • Rate limiting with exponential backoff on 429s
    • Resumable sweep (progress tracked in the database)
  • Claude-powered email triage (trash / archive / keep) with user approval before any Gmail mutation
  • Google Calendar sync with today and upcoming event queries
  • Text chat and push-to-talk voice via Claude + ElevenLabs
  • Live token usage counter (polls the database)
  • All data stored locally — nothing leaves your machine except API calls

Features (Phase 2)

  • Dot-sphere orb — a canvas-rendered rotating sphere of dots replaces the CSS blob, with distinct idle / listening / thinking / speaking motion
  • Chat modal — full-screen blurred overlay with markdown-rendered replies, a textarea that grows with its content, and conversation history pre-loaded from the database on page load (the last reply shows as a subtitle under the orb)
  • Onboarding flow — connect an account, then: choose how much to sweep (all / last N / since a date) → watch live progress → review the AI triage → approve → build memory (vectorize)
    • Sweep, triage classification, and a one-sentence summary per email happen in a single pass (25 emails per Claude call)
    • Per-category review with individual checkboxes and recategorization; only your changes are sent on approval
    • Keep + Archive emails are embedded with VoyageAI right after approval
  • Unlimited accounts — add and remove any number of Google accounts; no fixed role slots
  • PostgreSQL memory layer — conversations, email/contact summaries, and sent mail are written directly to the notes table and embedded on write, then retrieved (RAG) into the chat context
  • Fixes: the assistant knows the calendar is read-only (no hallucinated scheduling), the ?connected= OAuth param is stripped after sign-in, and chat history survives a refresh

Features (Phase 3 — Intelligence)

  • Email drafting in your voice — RAG over your own sent mail builds a style profile, then Claude drafts replies that match it; drafts are reviewed in the Drafts panel before anything is sent
  • Daily brief — calendar, email, news, and stock watchlist, cached in the database and served instantly on open (refresh forces a rebuild)
  • Calendar writes — Claude can create events via an action-token protocol
  • Settings — response tone, agent name, timezone, voice toggle

Features (Phase 4 — Memory, Intelligence, and Scale)

  • Email threading — messages are grouped into conversations; chat RAG retrieves whole threads instead of fragmented messages
  • Hybrid search — pgvector similarity fused with Postgres full-text (BM25) ranking via Reciprocal Rank Fusion for far better email retrieval
  • Contact intelligence — a contact graph built from email history (counts, recency, topics) is injected into chat context and browsable in Connections
  • Multi-provider AI — store and toggle Anthropic, OpenAI, Gemini, DeepSeek, and Ollama keys, with per-task (chat / classify / draft) model selection; keys are encrypted at rest
  • Configurable embeddings — pick the embedding model in Settings and re-embed all data (columns auto-resize when the dimension changes)
  • Supercharge import — upload a Claude / ChatGPT / Gemini conversation export to parse it into the memory layer and vectorize it for RAG
  • Scheduled digest — pre-builds at your set time in your timezone so the Brief loads instantly in the morning
  • Brief as a centered modal, and a triage mode setting (aggressive / normal / safe)
  • Fix: draft intent detection no longer triggers on plain email questions

Features (Phase 5A — Unified Memory)

  • PostgreSQL as the knowledge layer — email threads and contacts are written to the notes table as embedded notes, making PostgreSQL the single source of truth for long-term memory (a /graph page to browse it is coming soon)
    • email notes — one per thread with an AI-generated summary and participants, linked back to email_threads via source_id
    • contact notes — one per contact with email count and topics, linked back to contacts via source_id
    • Export triggers automatically after triage approval for new accounts; existing accounts have a manual "Export" button in the Connections panel
  • Tiered retrieval pipeline — chat context is assembled in order of richness:
    1. Tier 1 — semantic search over email/contact note embeddings
    2. Tier 2 — triggered by follow-up phrases ("tell me more", "full details"); searches by participant name first, then vector similarity, then fetches the complete thread live from the Gmail API, writes an enriched note to memory, and injects the full message bodies into the Claude context in the same request
    3. Fallback — raw email thread embeddings if memory has no relevant notes yet
  • Name-aware thread lookup — extracts person names from queries and searches email_threads.participants directly before falling back to vector similarity, so "what did Alex email me about?" reliably finds Alex's threads
  • Relevance threshold — tier 2 skips the Gmail fetch if the best vector match scores below 0.3 similarity, preventing irrelevant fetches on unrelated queries
  • Previous-query substitution — pure follow-up phrases ("tell me more", "yes") use the last substantive user message as the search query instead of the follow-up itself, which has no semantic relationship to any email thread

Features (Phase 5B — Scheduling, Review, and Intelligence)

  • Task registry — background work follows a single BaseTask pattern in backend/services/tasks/. Adding a scheduled task is one subclass file plus one registry entry; the registry also drives the "add task" form in Settings
  • Dynamic scheduler — a generic scheduler reads the scheduled_tasks table instead of hardcoded times, so any task can be enabled/disabled and rescheduled from the Settings panel. Each run records its status and summary
  • Gmail polling — new mail is fetched from every connected account every 15 minutes with no AI calls, stored as pending for review (same MIME parsing, batching, and 429 backoff as the full sweep)
  • Afternoon email review — once a day, the day's pending emails are triaged, summarized, and (when a reply seems expected) given a queued draft. Nothing is applied to Gmail until you approve
  • Daily Review panel — a newspaper-style digest grouped into Action Required, FYI, and Cleaned Up. Approve all pushes triage to Gmail and saves summaries to the memory layer; Dismiss takes no action
  • Calendar conflict detection — creating an event from chat checks for overlapping events first and asks you to confirm before scheduling over them
  • Event suggestions from email — emails that read like a meeting proposal get an "Add to calendar" button in the review panel that opens the chat pre-filled
  • Single-name contact lookup — chat resolves "draft an email to Kalpana" by extracting capitalized name candidates and doing a partial ILIKE match against contacts.display_name, so a first name alone reliably finds the right contact
  • Bug fixes:
    • Contacts panel now loads up to 500 contacts (was 200)
    • Calendar event times are converted to the user's configured timezone before being injected into Claude's context (were shown as raw UTC)

Features (UI Redesign)

  • Sidebar navigation — persistent left sidebar replaces the hamburger-menu modal, giving every section its own page with React Router v6
  • React Router — proper page routing at /, /analytics, /chat, /chat/:id, /drafts, /drafts/:id, /inbox, /calendar, /contacts, /connections, /settings
  • Persistent chat (/chat) — conversations that never get wiped; auto-generated titles on first assistant reply; each thread is mirrored to a Chats/ note in the memory layer as an append-only note; deleting a chat leaves the memory note intact
  • Analytics page — Recharts bar chart showing token usage and cost broken down by provider (Anthropic, VoyageAI, ElevenLabs) across daily, weekly, monthly, and yearly timeframes
  • Calendar page — read-only weekly view of synced events with links to Google Calendar; prev/next week navigation
  • Contacts page — searchable, sortable list of all contacts with topic tags and email counts
  • Settings redesign — full-width card layout for General, Voice, AI Providers, Memory & Embeddings, and Scheduled Tasks sections

Features (Inbox Redesign)

This phase simplifies the email pipeline and removes the daily brief.

  • Continuous triage — the 15-minute email poll now classifies each new message on arrival into one of trash / archive / keep / draft and adds it to a persistent email_queue, instead of a once-a-day batch review
  • Inbox page (/inbox) — a live queue grouped by category, updated every 15 minutes (or on demand with "Run triage now"). Reclassify any email inline, dismiss, or Apply & approve all to push trash/archive to Gmail in one go — the single point where the inbox mutates Gmail
  • Approve & Generate Draftdraft-classified mail gets a reply drafted on demand in your voice; a spinner shows progress, then a link to the draft
  • Draft detail page (/drafts/:id) — edit a draft inline and send it; sending records the sent email as a sent note in the memory layer
  • Inbox-aware chat — "what emails are pending?" is answered directly from the queue with no extra tool call
  • Removed — the daily brief (news, stocks, world events), the morning brief and afternoon review scheduled tasks, the Brief page, and the Daily Review panel

Prerequisites

  • macOS or Linux
  • Docker and Docker Compose
  • Node.js 18+
  • Python 3.11+
  • PostgreSQL (local install) with the pgvector extension available

Setup

  1. Clone the repo and configure environment:

    git clone https://github.com/yuvanadarsh/meridian.git
    cd meridian
    cp .env.example .env
    # Edit .env with your API keys and local postgres credentials
  2. Create the local database and schema:

    Fresh install — run init.sql only. It contains the complete schema through all migrations:

    psql -U your_user -c "CREATE DATABASE meridian;"
    psql -U your_user -d meridian -f backend/db/init.sql

    Existing install — run only the migrations you haven't applied yet. Each file in backend/db/migrations/ is idempotent (IF NOT EXISTS / ON CONFLICT DO NOTHING). Check your current state and apply from where you left off:

    # Example: upgrading from Phase 1 (no migrations yet)
    psql -U your_user -d meridian -f backend/db/migrations/002_obsidian_notes.sql
    psql -U your_user -d meridian -f backend/db/migrations/003_email_summary.sql
    psql -U your_user -d meridian -f backend/db/migrations/004_sweep_completed_at.sql
    psql -U your_user -d meridian -f backend/db/migrations/005_fix_embedding_dimensions.sql
    psql -U your_user -d meridian -f backend/db/migrations/006_drafts.sql
    psql -U your_user -d meridian -f backend/db/migrations/007_settings.sql
    psql -U your_user -d meridian -f backend/db/migrations/008_add_timezone_setting.sql
    psql -U your_user -d meridian -f backend/db/migrations/009_digest_cache.sql
    psql -U your_user -d meridian -f backend/db/migrations/010_email_threads.sql
    psql -U your_user -d meridian -f backend/db/migrations/011_hybrid_search.sql
    psql -U your_user -d meridian -f backend/db/migrations/011b_threads_fts.sql
    psql -U your_user -d meridian -f backend/db/migrations/012_contacts_graph.sql
    psql -U your_user -d meridian -f backend/db/migrations/013_ai_providers.sql
    psql -U your_user -d meridian -f backend/db/migrations/014_supercharge.sql
    psql -U your_user -d meridian -f backend/db/migrations/015_triage_mode.sql
    psql -U your_user -d meridian -f backend/db/migrations/016_scheduled_tasks.sql
    psql -U your_user -d meridian -f backend/db/migrations/017_afternoon_reviews.sql
    psql -U your_user -d meridian -f backend/db/migrations/018_usage_log.sql
    psql -U your_user -d meridian -f backend/db/migrations/019_oauth_state.sql
    psql -U your_user -d meridian -f backend/db/migrations/020_persistent_chats.sql
    psql -U your_user -d meridian -f backend/db/migrations/021_email_queue.sql
    psql -U your_user -d meridian -f backend/db/migrations/022_notes_table.sql

    Migration 022 renames obsidian_notes to notes and adds the note_type, source_id, and wikilinks columns. Existing rows and embeddings are preserved — the table is renamed, not dropped.

  3. Start Meridian:

    docker compose up --build
  4. Open http://localhost:5173 in Chrome — push-to-talk voice relies on the Web Speech API, which other browsers don't fully support.

  5. Connect your Gmail account via the Connections page (sidebar navigation), which drops you straight into the onboarding flow. You can also connect from the CLI:

    python scripts/setup_oauth.py --label personal

Running the backend without Docker

cd backend
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
uvicorn main:app --reload --port 8000

API Keys Required

See .env.example for all required keys:

  • Anthropic (Claude API) — reasoning, drafting, and triage
  • ElevenLabs (TTS) — voice responses
  • VoyageAI (embeddings) — used from Phase 2
  • Google OAuth credentials (from the Google Cloud Console) — Gmail + Calendar
  • SECRET_KEY — encrypts AI-provider API keys at rest. Generate one with openssl rand -hex 32 and set it in .env before storing any provider key.

Additional AI-provider keys (OpenAI, Gemini, DeepSeek, Ollama) are entered in the Settings → AI Providers panel and stored encrypted in the database, not in .env.

OAuth tokens are stored in the database after first authentication, never in .env.

Architecture

  • Frontend: React + Vite + TypeScript + Tailwind + Framer Motion; sidebar navigation with React Router v6 across 11 pages
  • Backend: FastAPI (Python), async SQLAlchemy, 14 routers
  • Database: PostgreSQL + pgvector (runs on the host, not containerized); 19 tables spanning email, calendar, chat, memory, tasks, and cost tracking
  • AI: Claude (claude-sonnet-4-6 for reasoning/drafting, claude-haiku-4-5 for batch classification) by default, with a pluggable provider layer (OpenAI / Gemini / DeepSeek / Ollama over OpenAI-compatible endpoints); API keys stored encrypted in the database; VoyageAI for embeddings (configurable model and dimension); ElevenLabs for TTS
  • Memory: a PostgreSQL notes table — email threads and contacts are written as embedded notes, daily conversation notes are appended after each exchange, and persistent chats are mirrored to Chats/ notes. Notes are embedded on write (no filesystem vault, no background watcher). Retrieval is tiered: memory note search → live Gmail API thread fetch → raw email thread embeddings
  • Retrieval: thread-aware hybrid search (pgvector cosine similarity fused with Postgres full-text BM25 via Reciprocal Rank Fusion) with name-aware participant lookup and a relevance threshold before any live Gmail fetch
  • Scheduled tasks: a generic scheduler reads a scheduled_tasks DB table once per minute; two registered tasks — email poll (15-min interval, triages new mail on arrival) and calendar sync — are configurable from the Settings panel

Only the api and frontend services run in Docker; the API container reaches your host PostgreSQL via host.docker.internal.

See docs/ARCHITECTURE.md for the full system architecture diagram and pipeline descriptions.

Roadmap

Done:

  • Email threading and hybrid search (Phase 4)
  • Contact intelligence graph (Phase 4)
  • Multi-provider AI keys with per-task model selection (Phase 4)
  • Configurable embeddings with live re-vectorize (Phase 4)
  • Supercharge import — parse Claude/ChatGPT/Gemini exports into the memory layer (Phase 4)
  • Scheduled digest pre-built in user timezone (Phase 4)
  • Unified memory — emails and contacts written as embedded notes (Phase 5A)
  • Tiered RAG retrieval (memory notes → Gmail API → raw vectors) (Phase 5A)
  • Scheduled background tasks with configurable scheduler (Phase 5B)
  • Gmail polling every 15 minutes across all accounts (Phase 5B)
  • Afternoon email review with user-approval before any Gmail mutation (Phase 5B)
  • Calendar conflict detection before event creation (Phase 5B)
  • Provider-aware cost tracking logged per API call (Phase 5B)
  • Sidebar navigation and full React Router page routing (UI Redesign)
  • Persistent chat mirrored to the memory layer (UI Redesign)
  • Analytics page with cost/token breakdown by provider (UI Redesign)
  • Calendar weekly view page (UI Redesign)
  • Contacts page with search and topic tags (UI Redesign)
  • Continuous triage into a persistent inbox queue (Inbox Redesign)
  • Inbox page with approve and on-demand draft generation (Inbox Redesign)
  • Draft detail page — edit and send, with send-then-record to memory (Inbox Redesign)
  • Obsidian removed — notes stored directly in PostgreSQL and embedded on write (v2)

Coming next:

  • Calendar event deletion from chat and the calendar page
  • Connect multiple Gmail accounts through the existing onboarding UI
  • Setup wizard for first-time users
  • Docker Hub image for one-command install
  • Always-on wake word (currently push-to-talk only)
  • Slack integration
  • In-app knowledge graph viewer (/graph page over the notes table)
  • One-time export of notes to an Obsidian vault (export_to_obsidian stub)
  • Agent orchestration and MCP integration

Contributing

PRs welcome. If you clone Meridian and build something on top of it, open an issue to share what you made — integrations, embedding model support, new UI panels, and wake-word implementations are all good starting points.

License

MIT

About

No description, website, or topics provided.

Resources

License

Stars

2 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors