Contributing
Tokori is MIT-licensed and accepts external contributions. This page is the developer-facing companion to the project's CONTRIBUTING.md; it covers the conceptual side of working in the codebase. Read the root file for the mechanics (clone, build, PR checklist).
Where to start
If you don't have a change in mind yet, good entry points:
- Issues tagged
good first issueon GitHub — small, contained, well-defined. - Adding a language that isn't bundled yet — the registries make this a one-file change. See Workspaces & languages.
- Writing a study plugin — see the Plugin SDK.
- Documentation. Always.
How the code is organised
A short orientation; the full tour is in Architecture.
src/
components/ UI (React 19 + shadcn/ui + Tailwind 4)
views/ Top-level tab views
settings/ Settings tabs
ui/ shadcn primitives (auto-generated)
dashboard/ Dashboard panels
study/ Flashcard / SRS surfaces
lib/ Everything that isn't a component
dictionaries/ Registry + per-format parsers + lemmatizer
study/plugins/ Built-in study plugins (Vocab Recall, Sentence Mining, …)
addons/ Stage-1 addon loader (manifest validation)
db.ts SQLite + cloud REST bridge (HOSTED-gated)
cloud-client.ts Cloud REST client (HOSTED only)
fsrs.ts FSRS-5 implementation
provider-context.tsx Active LLM provider + streaming
index.css Tailwind + theme tokens
src-tauri/
src/commands.rs Tauri IPC handlers (chat, dict, OCR, addons, …)
src/api_server.rs Local HTTP API on 127.0.0.1:53210
src/providers.rs LLM streaming pipeline (Ollama / OpenAI / …)
src/lib.rs Entry, migrations, plugin registration
mcp-server/ MCP companion (Node, agent-facing)
test/ Vitest suite (not co-located)
docs/ This siteCoding conventions
- No
any. Reach for discriminated unions orunknown+ a type guard. import typefor type-only imports.verbatimModuleSyntax: trueis on, so the build fails otherwise.- Path alias
@/*→src/*. Use it; relative../../..paths get unreadable fast. - Comments explain why, not what. A well-named function with a 3-line implementation doesn't need a docstring; a 30-line function with a non-obvious invariant does.
- No new dependencies without justification. Tokori already has most of what you'll need; if you reach for a package, say in the PR description what it gives us that the existing ones don't.
HOSTEDis a build-time constant. Cloud-only code paths live insideif (HOSTED) { … }so terser dead-strips them out of the desktop bundle. Don't route desktop calls through the cloud "for consistency" — desktop stays local-first.
Adding a new language
The dictionary + language registries are flat data — adding a language is a one-file-each change.
- Add an entry to
LANGUAGE_PROFILESinsrc/lib/language-profiles.ts(ISO code, names, glyph, locale, tokenizer choice, TTS sample). - If the language ships a packaged dictionary, add an entry to
DICTIONARY_PACKSinsrc/lib/dictionaries/registry.tsand pointrecommendedDictat itsid. - If the dict needs a new wire format, add the format string to
DictFormat, add amatcharm insrc-tauri/src/commands.rs::dict_fetch_lang, and write theparse_<format>function next to the existing parsers.
The workspace picker, settings, click-to-define popover, dashboard greeting, and TTS pick up the new language automatically.
Adding a study plugin
Plugins live under src/lib/study/plugins/. The contract is in Plugin SDK. Short version: export a StudyPlugin with a StudyView React component, register it in src/lib/study/registry.ts. The host hands you ctx for all data access — never reach into db.ts directly.
The same contract is the user-installable addon contract.
Tests
Vitest suite at test/. Not co-located — see vitest.config.ts for why. The bar:
- Reducers, hooks, parsers, ranking functions → tests required.
- UI components with trivial wiring → tests optional.
- Anything you'd be sad to break silently → tests required.
Run npm test before opening a PR. CI runs the same set on every push.
What we look for in a PR
- One focused change per PR.
- Surrounding style preserved; no drive-by reformats.
- New non-trivial logic comes with tests.
- No dead code, no
console.log, no commented-out blocks. - User-facing changes come with a doc update.
Reporting bugs and security issues
Bugs and feature requests go on GitHub issues. Use the templates — empty issues are hard to triage.
Security issues do not go on public issues. See SECURITY.md.