Contributing
Monorepo structure. Conventional commits. Local-first ethos.
loci is open source. Contributions welcome.
Repository structure
Loci/
├── packages/
│ ├── extension/ # Chrome MV3 extension (Vite + TypeScript)
│ ├── desktop/ # Tauri v2 desktop app (Rust + WebView)
│ └── server/ # MCP server (Rust)
├── docs/ # VitePress documentation (you are here)
├── landing/ # loci.garden landing page
└── package.json # Root workspace configEach package has its own package.json (for JS) or Cargo.toml (for Rust).
Development setup
Extension
bash
cd packages/extension
npm install
npm run dev # Watch mode with hot reloadLoad the extension in Chrome:
chrome://extensions> Enable Developer Mode- Load unpacked > select
packages/extension/dist/
The extension reloads automatically on file changes.
Desktop app
bash
cd packages/desktop
npm install
npm run tauri dev # Runs Tauri in dev modeRequires Rust toolchain. See Tauri prerequisites.
MCP server
bash
cd packages/server
cargo run # Runs on localhost:3721Docs
bash
cd docs
npm install
npm run dev # VitePress dev serverAdding a new platform
To add support for a new AI chat platform (e.g., Gemini):
- Add selectors to
packages/extension/src/platforms/platforms.config.ts:
typescript
export const platforms = {
// ...existing
gemini: {
hostPatterns: ["gemini.google.com"],
containerSelector: "[data-message-id]",
userSelector: "[data-author='user']",
assistantSelector: "[data-author='model']",
},
};- Create content script at
packages/extension/src/content/gemini.ts:
typescript
import { attachObserver } from "./observer";
import { platforms } from "../platforms/platforms.config";
attachObserver(platforms.gemini);- Register in manifest at
packages/extension/manifest.json:
json
{
"content_scripts": [
{
"matches": ["*://gemini.google.com/*"],
"js": ["src/content/gemini.ts"]
}
]
}Test on the live site. Verify MutationObserver captures turns correctly.
Update docs: add the platform to the supported platforms table in
/docs/extension/index.md.
Commit format
Use Conventional Commits:
<type>(<scope>): <description>
[optional body]Types:
| Type | Use for |
|---|---|
feat | New feature |
fix | Bug fix |
docs | Documentation only |
refactor | Code change that neither fixes a bug nor adds a feature |
test | Adding or updating tests |
chore | Build process, dependencies, tooling |
Scopes:
| Scope | Package |
|---|---|
extension | Browser extension |
desktop | Tauri app |
server | MCP server |
docs | Documentation |
landing | Landing page |
Examples:
feat(extension): add Gemini platform support
fix(server): handle empty room context gracefully
docs: add MCP API reference
chore(extension): upgrade MiniSearch to 7.1.0Pull requests
- Fork the repo
- Create a feature branch (
git checkout -b feat/gemini-support) - Make your changes
- Run tests (
npm testin relevant package) - Commit with conventional commit format
- Push and open a PR against
main
PRs require one approval before merge.
Issue labels
| Label | Meaning |
|---|---|
bug | Something is broken |
feature | New functionality request |
docs | Documentation improvement |
good-first-issue | Suitable for new contributors |
platform | New platform support request |
security | Security-related (handled privately) |
Code style
- TypeScript: Strict mode, no
anyunless unavoidable - Rust:
cargo fmtandcargo clippyclean - Naming: camelCase for JS, snake_case for Rust
No linter wars. Match the existing code.
Questions
Open a GitHub Discussion or reach out at hux@nymtech.net.