Loading repository data…
Loading repository data…
berylhu43 / repository
An always-on desktop memo widget that's a proactive personal assistant — floats on your screen, reads your Google Calendar, Gmail & Teams, gives a daily briefing, and plans your goals with you. Tauri + React, local-first, bring-your-own-model (Claude/GPT/DeepSeek/Qwen).
An always-on, frameless desktop memo widget that acts as a proactive personal assistant. It floats on top of your screen showing your goals (collapsed), and expands into a chat + daily-briefing panel that reads your Google Calendar and Gmail (and, optionally, Microsoft Teams) and plans your week with you.
Built with Tauri 2 (Rust shell) + React + TypeScript (Vite). All business logic — SQLite, LLM-provider calls, Google & Microsoft API calls, memory — lives in the TypeScript layer. Rust is only the shell: window management, system tray, and the daily 9 AM timer.
You bring your own model: pick Claude, GPT, DeepSeek, or Qwen in Settings and enter that provider's API key. Keys stay on your machine.
› button in the header or the tray menu.```add-event → creates a Google Calendar event```goal → adds a goal (optionally with daily / weekly / monthly tasks)```commitment → adds a one-off dated task to your local calendar```remember → stores a durable fact/preference in the memories tableSchedule: daily / weekly / monthly / a custom rhythm you type.
Resources & links: Yes → it web-searches real, current resources and attaches links to each step (needs Claude or GPT); No → a quick schedule-only plan from the model's own knowledge (works with any provider). Either way the plan is saved as a goal, so it persists after you close the chat. Researched plans can be exported to Markdown.
You can also update an existing plan — ask to redo/refine a plan you already have and it regenerates that same goal's tasks in place (no duplicate).
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
xcode-select --install).npm install
cp .env.example .env # fill in your Google OAuth client id/secret
npm run tauri dev # IMPORTANT: run inside Tauri, not `npm run dev`
Why not
npm run dev?tauri-plugin-sqlonly works inside the Tauri runtime. Opening the Vite dev server in a plain browser will fail on every DB call. Always usenpm run tauri dev.
On first launch: sign in with Google, then open Settings (⚙) and add an API
key for at least one LLM provider (Claude, GPT, DeepSeek, or Qwen) and pick
which one is active. Keys are stored locally (in the llm_providers table) and
never committed or sent anywhere except that provider's API. Note: building a
plan with researched resources/links uses web search, so that mode works
only with Claude or GPT; schedule-only plans (and everything else) work with
any provider.
npm run tauri build
Output lands in src-tauri/target/release/bundle/ — on macOS an Assistant.app
plus an Assistant_<version>_<arch>.dmg installer (drag into Applications).
Run the built app for everyday use: it's the optimized release binary, so unlike
npm run tauri dev there's no Rust compiler / dev server running — it starts
fast and stays cool. It uses your real assistant.db.
Note: the build is per-OS/per-chip (e.g. a macOS Apple-Silicon build only
runs on Apple Silicon). Anyone who clones the repo builds it themselves via the
steps above — the built app and the Rust target/ cache are git-ignored, so a
clone contains source only. They also supply their own Google OAuth .env and
their own in-app LLM key. Prebuilt cross-platform installers via GitHub Releases
are not set up yet (intentionally deferred).
To showcase the app without touching your real data (and without connecting Google), run:
npm run demo # = VITE_DEMO=1 npm run tauri dev
Demo mode:
assistant-demo.db) — your real assistant.db
is never read or written;LLM key: provider keys live in the database, which is separate in demo mode, so the demo starts with no key — open Settings (⚙), paste a key, Save, and the model becomes selectable. To skip that, pass a key when launching and the demo pre-selects it:
VITE_DEMO_KEY=sk-ant-... npm run demo # defaults to Claude
VITE_DEMO_KEY=sk-... VITE_DEMO_PROVIDER=openai npm run demo
Seeding runs only when the demo DB is empty — delete assistant-demo.db (in the
app-data dir) to reseed. Package a standalone demo build with npm run demo:build.
.env (gitignored), read by Vite at build time:
| Variable | What it is |
|---|---|
VITE_GOOGLE_CLIENT_ID | OAuth 2.0 Web application client ID. |
VITE_GOOGLE_CLIENT_SECRET | OAuth 2.0 client secret. |
VITE_MS_CLIENT_ID | Microsoft (Teams) app registration client ID — Mobile and desktop (public client, no secret). |
VITE_MS_TENANT | Microsoft tenant/org ID. Must be a work/school org (not common); personal accounts can't read Teams chat. |
LLM provider API keys are not env vars — enter them in the in-app Settings
panel (stored locally in the llm_providers table).
| Plugin | Purpose |
|---|---|
tauri-plugin-sql (sqlite) | Local database sqlite:assistant.db, with versioned migrations. |
tauri-plugin-store | Stores the stable local user id + one-time setup flags. (LLM API keys live in the DB's llm_providers table.) |
tauri-plugin-http | Calls LLM-provider & Google/Microsoft APIs from Rust transport (no browser CORS). |
tauri-plugin-dialog / tauri-plugin-fs | File picker + read/write (PDF/doc task extraction, plan export). |
@choochmeque/tauri-plugin-google-auth | Desktop Google OAuth (PKCE + loopback redirect + refresh). |
tauri-plugin-oauth | Loopback redirect listener for Microsoft (Teams) OAuth (PKCE flow runs in TS). |
tauri-plugin-window-state | Remembers the window position only. |
openid, .../auth/userinfo.email, .../auth/userinfo.profilehttps://www.googleapis.com/auth/calendar.readonlyhttps://www.googleapis.com/auth/calendar.eventshttps://www.googleapis.com/auth/gmail.readonlyhttp://localhost.
The desktop plugin runs a loopback redirect server and allocates the port
dynamically, so the bare http://localhost entry is what's required..env.Teams reads your 1:1 direct messages and @mentions through Microsoft Graph. This is a separate connection from Google, with its own app registration. It's optional — the app works without it.
Work/school accounts only. Microsoft Graph does not allow reading Teams chat messages with a personal Microsoft account. The account you connect must be an organizational (Entra) one, and you must register the app in that organization's directory.
Personal Assistant.http://localhost. (The app uses a loopback redirect on a dynamically chosen port; Microsoft
matches that against the bare http://localhost.).envOn the app's Overview page, copy:
| Portal field | .env variable |
|---|---|
| Application (client) ID | VITE_MS_CLIENT_ID |
| Directory (tenant) ID | VITE_MS_TENANT |
Use the tenant ID (a GUID), not
common— personal-account sign-in isn't supported here.
Authentication → scroll to Advanced settings → Allow public client flows → set to Yes → Save. (This app is a public client and uses PKCE with no client secret — so you do not create a client secret.)
API permissions → Add a permission → Microsoft Graph → Delegated permissions, then add:
Chat.Read — read your 1:1 and group chat messagesUser.Read — identify the signed-in user (needed to match @mentions)offline_access — issue a refresh token so the connection auto-renewsopenid, profile, email — basic si