{"id":50547671,"url":"https://github.com/parthha12/easy-jot","last_synced_at":"2026-06-04T00:03:50.067Z","repository":{"id":339568071,"uuid":"1161172217","full_name":"parthha12/easy-jot","owner":"parthha12","description":null,"archived":false,"fork":false,"pushed_at":"2026-04-05T10:20:57.000Z","size":385,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-29T22:43:10.631Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/parthha12.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":"docs/roadmap.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-18T20:16:02.000Z","updated_at":"2026-04-05T10:21:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/parthha12/easy-jot","commit_stats":null,"previous_names":["torrap11/jot","torrap11/easy-jot","parthha12/easy-jot"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/parthha12/easy-jot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parthha12%2Feasy-jot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parthha12%2Feasy-jot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parthha12%2Feasy-jot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parthha12%2Feasy-jot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/parthha12","download_url":"https://codeload.github.com/parthha12/easy-jot/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/parthha12%2Feasy-jot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33884763,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-03T02:00:06.370Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-04T00:03:49.375Z","updated_at":"2026-06-04T00:03:50.049Z","avatar_url":"https://github.com/parthha12.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Jot\n\nA local-first, always-on-top desktop app for capturing and recalling intentions by voice.\n\nEverything you capture is a **jot** to you: plain notes, timed reminders, or “when I’m on Netflix…”. Under the hood the app sorts them so the right ones can surface when you switch apps or sites (if the workflow watcher is on). Context alerts are **silent by default**; set `speakTriggerMemories` if you want TTS. The AI agent still works across all your jots.\n\nBuilt with Electron, SQLite, Smallest AI Waves (Pulse STT + Lightning TTS), and OpenAI.\n\n---\n\n## Two apps in this repo\n\n| App | Directory | Description |\n|---|---|---|\n| **Jot** (v1) | *(repo root)* | Voice-first sticky notes, context triggers, scheduled reminders, TTS — documented below |\n| **Easy Jot** (v2) | [`easy-jot/`](easy-jot/) | Semantic memory OS — React + Vite + TypeScript + OpenAI embeddings. See [`easy-jot/README.md`](easy-jot/README.md) |\n\n---\n\n## Quick Start\n\n**Requirements**: Node.js 18+, macOS (Windows/Linux: Cmd → Ctrl shortcuts)\n\n```bash\ngit clone \u003crepo\u003e\ncd jot\nnpm install\n```\n\nCreate the config file at `~/Library/Application Support/easy-jot/config.json`. You can start from the repo template **`config.example.json`** (copy and rename), which includes `\"workflowWatcherEnabled\": true` for context surfacing.\n\n```json\n{\n  \"openaiApiKey\": \"sk-...\",\n  \"smallestAiKey\": \"your-smallest-ai-key\"\n}\n```\n\n```bash\nnpm start\n```\n\nThe app hides in the background with no dock icon. Press **Cmd+E** to show it.\n\n### Downloadable app (no Terminal)\n\nTo produce a **`.app` / `.dmg`** other people can install without Node or `npm start`:\n\n```bash\nnpm install\nnpm run dist\n```\n\nOpen **`dist/`** for the DMG and ZIP. Full notes (Ollama vs cloud, signing): [docs/releasing.md](docs/releasing.md).\n\nSee [Configuration](#configuration) for all options and the [API key matrix](#api-keys) for what each key enables.\n\n---\n\n## What It Does\n\n### Voice memory\nUse the in-app **mic** or global **`Cmd+M`** → speak → review transcript → save. The LLM extracts a trigger context when relevant. Save confirmations can use TTS if Smallest AI is configured.\n\n### Context triggers\nClick a trigger button (Netflix, LinkedIn, Gmail, Work) to simulate that context. With **`workflowWatcherEnabled`**, Jot can also detect the **frontmost macOS app** and the **active tab URL** in supported browsers (Chrome, Safari, Brave, Edge, Arc) via AppleScript — e.g. **netflix.com** maps to the same trigger as the Netflix app. See [Workflow Watcher](#workflow-watcher-automatic-trigger-surfacing).\n\n### Scheduled reminders\nWrite `at 10 PM remind me to drink water` and press Back. Jot parses the time automatically, converts the note to a scheduled reminder, and fires it at the right time with a spoken notification.\n\n### Notes and folders\nPlain text and image notes with folder organization, autosave, and Cmd+Z undo. An AI agent accepts natural-language commands to search, create, and organize.\n\n---\n\n## Keyboard Shortcuts\n\n### Global (work in any app)\n\n| Shortcut | Action |\n|---|---|\n| `Cmd+E` | Show / hide Jot |\n| `Cmd+M` | Universal voice command (dictate, set reminder, save memory, or prompt agent) |\n\n### In-app\n\n| Shortcut | Action |\n|---|---|\n| `Cmd+N` | New note |\n| `Cmd+I` | New note from image file |\n| `Cmd+S` | Save + open folder picker |\n| `Cmd+Z` | Undo last delete |\n| `Cmd+F` | Toggle folder organize view |\n| `Cmd+J` | Focus / open AI agent panel |\n| `Escape` | Contextual: note → list → folder view → close |\n| `↑ / ↓` | Navigate note list |\n| `Enter` | Open selected note |\n| `Delete / Backspace` | Delete selected note (in list) |\n| `Ctrl+Tab` | Cycle folder filter forward |\n| `Ctrl+Shift+Tab` | Cycle folder filter backward |\n\n---\n\n## Configuration\n\nConfig is read from `~/Library/Application Support/easy-jot/config.json` on every API call. Environment variables take precedence.\n\n```json\n{\n  \"openaiApiKey\":          \"sk-...\",\n  \"smallestAiKey\":         \"...\",\n  \"model\":                 \"gpt-4o-mini\",\n  \"useOllama\":             false,\n  \"ollamaBaseURL\":         \"http://localhost:11434/v1\",\n  \"ttsVoice\":              \"emily\",\n  \"ttsSampleRate\":         24000,\n  \"sttLanguage\":           \"en\",\n  \"workflowWatcherEnabled\": false,\n  \"speakTriggerMemories\":   false\n}\n```\n\n| Key | Env var | Default | Description |\n|---|---|---|---|\n| `openaiApiKey` | `EASY_JOT_OPENAI_API_KEY` | — | OpenAI API key |\n| `smallestAiKey` | `SMALLEST_AI_KEY` or `EASY_JOT_SMALLEST_AI_KEY` | — | Smallest AI key (Pulse STT + Lightning TTS only) |\n| `model` | — | `gpt-4o-mini` | OpenAI GPT model id for agent + intent parsing |\n| `useOllama` | `EASY_JOT_USE_OLLAMA=1` | `false` | Use local Ollama instead of OpenAI |\n| `ollamaBaseURL` | — | `http://localhost:11434/v1` | Ollama endpoint |\n| `ttsVoice` | — | `emily` | Smallest AI voice ID |\n| `ttsSampleRate` | — | `24000` | TTS audio sample rate |\n| `sttLanguage` | — | `en` | STT language code (BCP-47) |\n| `workflowWatcherEnabled` | — | `false` | Auto-detect frontmost app + browser tab URL (supported browsers) and surface matching memories. Requires Accessibility (see below). |\n| `speakTriggerMemories` | — | `false` | When `true`, context-trigger overlays use TTS read-back. Default is silent overlays. |\n\n### API keys\n\n| Feature | Provider | Key needed |\n|---|---|---|\n| Voice STT | Smallest AI Pulse | `smallestAiKey` only |\n| TTS read-back | Smallest AI Lightning | `smallestAiKey` |\n| AI agent + intent parsing | OpenAI GPT (`model` in config) | `openaiApiKey` |\n| AI agent (local, no cloud) | Ollama | none |\n\n**Minimum for full stack**: `smallestAiKey` (voice + TTS) and `openaiApiKey` (GPT agent). You can use either alone for partial features.\n\n### Ollama (local LLM)\n\n```bash\nollama pull llama3.2\n```\n\nSet `\"useOllama\": true` in config.json. Note: Ollama has no STT or TTS — voice still needs `smallestAiKey`.\n\n### Workflow Watcher (automatic trigger surfacing)\n\nSet `\"workflowWatcherEnabled\": true` in config.json to enable automatic surfacing when your **foreground context** matches a known trigger.\n\n**Step-by-step (macOS permissions + Atlas):** see [docs/macos-workflow-setup.md](docs/macos-workflow-setup.md).\n\n**Required permission**: System Settings → Privacy \u0026 Security → **Accessibility** → enable for your **Jot** app, **Electron** (dev), or **Terminal** if you start the app from there. AppleScript needs this to read the frontmost app.\n\n**Automation** (Privacy \u0026 Security → **Automation**): allow Jot/Electron/Terminal to control each browser you use (**ChatGPT Atlas**, Chrome, Safari, Brave, Edge, Arc, Chromium) so Jot can read the **active tab URL**.\n\n**Native apps** (process name / bundle id): Netflix, Spotify, Slack, VS Code, Xcode, Microsoft Teams → same mapping as before.\n\n**Websites** (active tab URL via AppleScript): when the frontmost app is **ChatGPT Atlas**, **Google Chrome, Safari, Brave Browser, Microsoft Edge, Arc, or Chromium**, Jot reads the tab URL and maps the hostname — e.g. `netflix.com`, `open.spotify.com`, `mail.google.com`, `linkedin.com`. This is **best-effort** and can break with browser updates; there is no browser extension in this repo.\n\n**Cooldown**: 30 minutes per canonical trigger id. **Snooze / Done / Why?** on the overlay still apply.\n\n**Silent by default**: context overlays do not call TTS unless you set `\"speakTriggerMemories\": true`.\n\n---\n\n## Architecture\n\nSee [docs/architecture.md](docs/architecture.md) for the full module map, IPC flow, and data models.\n\n```\nMain process (Node.js)\n├── main.js          — window lifecycle, global shortcuts, IPC handlers\n├── database.js      — SQLite (better-sqlite3), 4 tables\n├── llm.js           — OpenAI / Ollama client\n├── config.js        — reads env + config.json on every call\n├── voice.js         — Pulse STT (Smallest AI only)\n├── tts.js           — Lightning TTS, returns WAV buffer\n├── intentParser.js  — LLM → structured { trigger, content, category }\n├── triggerEngine.js — canonical trigger IDs and normalization\n├── scheduler.js     — 30s poll for scheduled reminders\n├── reminderParser.js — deterministic regex time parser\n├── keybinds.js      — shortcut definitions (data only)\n├── contextMap.js    — hostname / bundle id → canonical trigger id\n├── workflowWatcher.js — osascript: front app + browser URL → runTrigger, 30-min cooldown\n└── intelligence/\n    └── executor.js  — action dispatcher (search, create, move, organize, memories, reminders)\n\npreload.js           — contextBridge: exposes window.api (contextIsolation: true)\n\nRenderer (Chromium)\n└── renderer/\n    ├── index.html   — DOM structure\n    ├── renderer.js  — all UI logic (~1400 lines)\n    └── style.css    — sticky-note aesthetic\n```\n\n---\n\n## Data Storage\n\n```\n~/Library/Application Support/easy-jot/\n├── easy-jot.db      — SQLite database (WAL mode)\n└── config.json      — API keys and settings (never commit this file)\n```\n\nDatabase tables: `notes`, `folders`, `intent_memories`, `scheduled_reminders`.\n\n---\n\n## Troubleshooting\n\n**App doesn't appear**\nPress `Cmd+E`. Check the terminal for startup errors.\n\n**Microphone not working**\nmacOS: System Settings → Privacy \u0026 Security → Microphone → enable for Electron or your terminal.\n\n**\"Voice input needs a Smallest AI key\"**\nAdd `smallestAiKey` to config.json (or `SMALLEST_AI_KEY` / `EASY_JOT_SMALLEST_AI_KEY`). OpenAI is not used for STT.\n\n**TTS not speaking**\nTTS requires `smallestAiKey`. Check the status bar at the top of the app.\n\n**\"No LLM configured\"**\nAdd `openaiApiKey` to config.json, or set `\"useOllama\": true`.\n\n**`npm install` fails (native module error)**\n`better-sqlite3` requires native compilation. Make sure Xcode Command Line Tools are installed: `xcode-select --install`. The `postinstall` script runs `electron-rebuild` automatically.\n\n**Workflow watcher never fires on a website**\nEnsure `workflowWatcherEnabled` is `true`, Accessibility is granted, and the browser allows **Automation** for Jot/Electron when macOS prompts. AppleScript tab URLs can fail on some browser versions — try Google Chrome first.\n\n**Context triggers are silent**\nDefault is no TTS on trigger overlays. Set `\"speakTriggerMemories\": true` in config.json if you want spoken read-back.\n\n---\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## Roadmap\n\nSee [docs/roadmap.md](docs/roadmap.md).\n\n## Known Issues\n\nSee [docs/known-issues.md](docs/known-issues.md).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparthha12%2Feasy-jot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fparthha12%2Feasy-jot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fparthha12%2Feasy-jot/lists"}