Browser Extension
Chrome MV3 · Search + tagging · Claude.ai + ChatGPT
The loci browser extension is the collector: it reads your AI chat conversations as you have them, indexes them locally, and makes them available for search.
What it does not do: make any network calls. Everything stays in your browser.
What it does
The extension attaches a MutationObserver to conversation containers on supported platforms. As you chat, it:
- Detects new conversation turns (user + assistant messages) via DOM mutation events
- Extracts message content and metadata (timestamp, role, conversation ID)
- Sanitises content (strips scripts, normalises whitespace)
- Writes raw conversation data to
IndexedDB(origin-isolated storage) - Updates the MiniSearch 7.x index incrementally
- Serialises the updated index to
chrome.storage.local
The extension provides two search surfaces: a quick-access overlay (triggered by keyboard shortcut) and a persistent side panel for deeper navigation.
Supported platforms
| Platform | URL patterns | Selector strategy | Status |
|---|---|---|---|
| Claude.ai | claude.ai/* | [data-testid="conversation-turn-list"] container, [data-testid="user-message"] / [data-testid="assistant-message"] for turns | Targeted |
| ChatGPT | chatgpt.com/*, chat.openai.com/* | article[data-turn] (primary), [data-message-author-role] (fallback) | Targeted |
| Gemini | gemini.google.com/* | : | v0.2 planned |
Selectors are maintained in src/platforms/platforms.config.ts. This is the first file to update when a site redesigns.
Build from source
git clone https://github.com/huximaxi/Loci
cd Loci/packages/extension
npm install
npm run buildLoad the built extension:
- Navigate to
chrome://extensions - Enable "Developer mode" (toggle in top-right)
- Click "Load unpacked"
- Select the
packages/extension/dist/directory
The extension icon appears in your toolbar. Pin it for quick access to the side panel.
The command-K overlay
Press Cmd+K (Mac) or Ctrl+K (Windows/Linux) on any supported AI chat page to open the search overlay.
| Shortcut | Action |
|---|---|
Cmd/Ctrl+K | Open overlay |
Escape | Close overlay |
Enter | Open selected conversation |
Up/Down | Navigate results |
Cmd/Ctrl+Enter | Open in loci desktop app |
The overlay renders in Shadow DOM, isolated from page styles. Results display: conversation title, platform icon, date, and matched excerpt with highlighted terms.
Click "Open in loci" to jump directly to the conversation in the desktop app (if installed) or open it in a new tab.
The side panel
Open via the toolbar icon or Cmd+Shift+L (Mac) / Ctrl+Shift+L (Windows).
The side panel persists across page navigation. Features:
- Full conversation list: browse all indexed conversations, sorted by recency
- Search: same MiniSearch-powered search as the overlay
- Tag management: add, remove, and filter by tags
- Room assignment (Wizard tier): drag conversations into rooms, or right-click to assign
- Crystallise action: convert a conversation into a permanent locus
Permissions explained
| Permission | Why |
|---|---|
storage | Read/write chrome.storage.local for the serialised search index |
unlimitedStorage | Remove the default 10 MB cap on chrome.storage.local: required for heavy users |
scripting | Inject content scripts dynamically (MV3 requirement) |
activeTab | Access the current tab's DOM when the user invokes the extension |
sidePanel | Register and display the persistent side panel |
Host permissions (*://*.claude.ai/*, etc.) | Run content scripts on supported platforms |
No permissions beyond what is required. No webRequest, no tabs (beyond activeTab), no history, no cookies.
Storage architecture
| Store | Technology | Contents | Approx. size (2000 conversations) |
|---|---|---|---|
| Raw content | IndexedDB | Full conversation text + metadata | ~50 MB |
| Search index | chrome.storage.local | Serialised MiniSearch blob | ~10 MB |
| Tags | chrome.storage.local | { conversationId: string[] } | ~500 KB |
IndexedDB is origin-isolated to chrome-extension://{extension-id}/. Other extensions and websites cannot access it.
MV3 service worker lifecycle
Chrome MV3 terminates service workers after 30 seconds of inactivity. This would destroy any in-memory search index.
loci handles this cleanly:
- After every index update, call
index.toJSON()and write tochrome.storage.local - On service worker wake (triggered by any extension event), check if index is loaded
- If not, call
MiniSearch.loadJSON(stored)to restore the index
Restoration cost: ~50ms for 2000 conversations. Imperceptible.
Known limitations
v0.1 limitations
- No retroactive import: the extension only indexes conversations that occur after installation. Existing chat history is not imported.
- No offline export: JSON/Markdown export is planned for v0.2.
- Chrome only: Firefox and Safari ports are planned for v1.0.
Roadmap
| Version | Features |
|---|---|
| v0.1 | Chrome · Claude.ai + ChatGPT · Search + tagging · Overlay + side panel |
| v0.2 | Full-text search · Gemini support · Export to JSON/Markdown |
| v0.3 | Semantic search (local embedding model) · Room assignment UI polish |
| v1.0 | Chrome Web Store submission · Firefox port · Safari Web Extension |
Architecture
packages/extension/
├── manifest.json
├── src/
│ ├── background/
│ │ └── service-worker.ts # MiniSearch instance, IndexedDB read/write
│ ├── content/
│ │ ├── claude.ts # MutationObserver for claude.ai
│ │ ├── chatgpt.ts # MutationObserver for chatgpt.com
│ │ └── overlay.ts # Cmd+K search overlay (Shadow DOM)
│ ├── sidepanel/
│ │ └── index.html # Persistent side panel UI
│ ├── platforms/
│ │ └── platforms.config.ts # DOM selector map (single source of truth)
│ └── shared/
│ ├── index.ts # MiniSearch wrapper + IndexedDB helpers
│ └── types.ts # Conversation, Turn, Tag types
└── vite.config.ts # vite-plugin-web-extension configKnown risks
| Risk | Mitigation |
|---|---|
| DOM selector instability | All selectors centralised in platforms.config.ts. Quarterly maintenance releases planned. |
| Site CSP blocking injected UI | Shadow DOM isolation. Extension content scripts run in an isolated world, not subject to page CSP. |
| IndexedDB read by other extensions | Origin-isolated to chrome-extension://{id}/. Inaccessible to other extensions and websites. |
| CWS rejection | Standard MV3 permissions, no remote code execution, privacy policy stating no data leaves device. |
See Security for the full security model.