Thank you for your interest in contributing.
- Node.js 20+
- Google Chrome (or any Chromium-based browser)
- Git
# Install all dependencies
npm install
# Build the extension (TypeScript check + Vite bundle)
npm run build
# Generate extension icons from the SVG source
npm run gen-icons- Open
chrome://extensionsin Chrome. - Enable Developer mode (toggle in the top-right).
- Click Load unpacked and select the
dist/directory. - Navigate to a supported AI chat page (e.g.
chatgpt.com) — the floating dial should appear.
For live reload during development:
npm run devVite + @crxjs/vite-plugin provides HMR. Changes to content scripts, popup, and options page are reflected automatically.
src/
manifest.ts ← Chrome extension manifest (MV3)
background/
index.ts ← Service worker — message router
content-scripts/
mount.tsx ← Shadow-DOM-free mount helper
FloatingDial.tsx ← Floating UI injected on chat pages
SaveButton.tsx ← Save conversation trigger
RestoreButton.tsx ← Restore / seed prompt trigger
chatgpt.tsx ← ChatGPT content script
claude.tsx ← Claude content script
gemini.tsx ← Gemini content script
perplexity.tsx ← Perplexity content script
grok.tsx ← Grok content script
bridge.ts ← Page ↔ content-script bridge
extractors/
base.ts ← Extractor interface
index.ts ← Provider → extractor registry
chatgpt.ts ← ChatGPT extractor
claude.ts ← Claude extractor
gemini.ts ← Gemini extractor
perplexity.ts ← Perplexity extractor
grok.ts ← Grok extractor
utils/
vault.ts ← chrome.storage.local wrapper
seeder.ts ← Seed prompt generator
helpers.ts ← Shared utilities
types/
schema.ts ← Thread, Message, Attachment, Provider
messages.ts ← Content-script ↔ background message types
index.ts ← Re-exports
popup/
App.tsx ← Per-provider count summary
main.tsx ← React entry point
options/
App.tsx ← Vault Dashboard
main.tsx ← React entry point
styles/
global.css ← Tailwind entry
components/
HacklmIcon.tsx ← Shared icon component
scripts/
gen-icons.mjs ← Icon generation (Sharp)
| Rule | Detail |
|---|---|
Extractors implement Extractor from base.ts |
Every provider extractor must implement fetchThread() and listConversations(). |
All vault access goes through vault.ts |
Never call chrome.storage.local directly outside vault.ts. |
| Messages use typed contracts | All content-script ↔ background messages use types from messages.ts. No raw string message types. |
| Schema normalisation | Extractor output must conform to the Thread / Message schema in schema.ts. Content is Markdown. Timestamps are ISO-8601. |
| TypeScript strict mode | tsconfig.json has "strict": true. No any without justification. |
| No emojis in code | — |
| Inline styles in content scripts | Content scripts use inline styles and fixed positioning — no external CSS that could clash with host pages. |
Use conventional commits:
feat: add Mistral extractor
fix: handle empty message list in Claude extractor
docs: update architecture diagram
chore: bump vite to v7.4
Before opening a PR:
-
npm run buildsucceeds without errors - Extension loads in Chrome and the floating dial appears on a supported site
- New extractor follows the
Extractorinterface frombase.ts - New behaviour is documented in
docs/if it affects architecture or schema - No direct
chrome.storage.localcalls outsidevault.ts - No raw string message types — use
messages.tscontracts
By contributing, you agree your contributions are licensed under the GNU General Public License v3.0.