Contributing to Tusk's Vault
First — thank you. Tusk's Vault is a community-shaped project, and the contributions that matter most aren't always code. There's a list below.
By participating you agree to abide by our Code of Conduct.
Ways to contribute (no code required)
You don't need to ship a pull request to make this project better. A few of the most useful things anyone can do:
- 🐛 File a bug. Found something broken? Open an issue. Include OS, Node version, the command you ran, and the error. Even a partial report helps.
- 💡 Pitch a feature. Roadmap items come from real DMs asking for real things. Open a feature-request issue — the situation you want solved matters more than the feature you have in mind.
- 📝 Improve the docs. Spotted a confusing step in the README or the setup walkthrough? Even one-sentence tweaks are welcome PRs.
- 🎨 Design feedback. The dashboard is heavily themed. If something reads wrong, looks broken, or is hard to use, screenshot it and tell us.
- 🌍 Help translate. A localised dashboard is on the wishlist — if you'd help with strings in another language, open an issue and say which language.
- 📣 Spread the word. ⭐ Star the repo, mention it to your DM friends, write a blog post or tweet about how it worked for your campaign.
- ☕ Sponsor. If the project saves your campaign night, Buy me a coffee. One-off or recurring both welcome.
All of the above counts. None of it is optional or required.
Contributing code
Before you start
For anything bigger than a small fix:
- Open an issue first so we can agree on the approach before you write code. This saves you from sinking hours into a PR that needs a rewrite.
- Pick one thing. PRs are easier to land when they do one thing. If you're tempted to fix five unrelated issues in one PR, split them.
For typo / docs / one-line fixes, skip step 1 and just open the PR.
Setting up a dev environment
git clone https://github.com/KochiTusker/Tusks-Vault.git
cd Tusks-Vault
npm install
npm run dev # starts the server + Vite middleware on http://localhost:3000
The server is a single TypeScript process running through tsx — no build step in dev. Frontend changes hot-reload through Vite middleware; backend changes need a server restart (Ctrl+C then npm run dev).
Project layout
- src/server/ — backend. One concern per file.
llm/— provider adapters (Gemini, OpenRouter, Claude Code, Ollama). Adding a new provider = drop a file here that implements the same interface.routes/— Express route handlers. One file per route group.knowledge/— document loading and parsing.embeddings/— local MiniLM embedding pipeline for clarifications.discord/— bot client and message handler.prompt/— system prompt + prompt assembly.config/— env, paths, settings persistence.
- src/ (outside
server/) — React 19 dashboard. Component files live insrc/components/. - server.ts — entrypoint that boots both Express and Vite.
- scripts/update.mjs — the in-app updater.
Style + conventions
- TypeScript throughout. Avoid
any. Runnpm run lint(which istsc --noEmit) before pushing. - No new dependencies without discussion. We keep the dep tree small on purpose. If you need one, mention it in your issue.
- Match the file's existing style. No new formatters or linters as part of feature PRs.
- Comments: only when the why is non-obvious. Don't narrate what the code already says.
- Commits: small, focused, with a one-line subject and (optional) longer body explaining why. Match the style of existing commits in
git log.
Adding a new LLM provider (base-product, cloud)
- Create
src/server/llm/<name>.tsthat exports the sameLlmAdapterinterface asgemini.ts/openrouter.ts/ollama.ts, and wrap the API call inwithRetryfromllm/retry.ts. - Register it in
src/server/llm/registry.ts. - Add a Key Vault entry in the dashboard (
src/types/keys.tsfor the type,src/components/panels/KeyVaultPanel.tsxfor the UI) if the provider needs an API key. - Update the relevant docs (How it's built, Dependencies) and the
.env.examplefile.
Adding a new provider
There is no plugin system to learn. Vault had one; it gated features that were always present, so it was removed. A provider is just a file.
- Add
src/server/llm/<name>.tsexporting a factory that returns anLlmAdapter— the interface is in src/server/llm/types.ts. - Wrap the outbound call in
withRetryfrom src/server/llm/retry.ts, so rate limits behave like every other provider's. - Add a case to the switch in src/server/llm/registry.ts, and the provider to
LlmProviderin src/server/config/settings.ts. - Pick a reference:
gemini.tsfor a cloud provider with an SDK,ollama.tsfor one that is plain HTTP,claude-code.tsfor one that shells out. - Add it to the probe in src/server/llm/model-probe.ts if "which models can this key call" has a non-obvious answer — it usually does.
- Update Choosing a provider with what it costs and what it needs.
Don't add a dependency unless the provider genuinely needs one, and never lazy-load packages — that makes whether a feature works depend on whether the network is up.
Adding a new ingester (file format)
- Add the parser in
src/server/knowledge/loader.ts— keep parsers small and side-effect-free. - Add an entry to the supported-formats table in Lore/README.md.
Tests
Backend has a Vitest suite (npm test) covering security middleware, path resolution, key store, persona store, prompt assembly, atomic writes, and the Obsidian reader's read-only guard. The React dashboard is intentionally untested today — manual smoke-testing is the standard for frontend changes.
If you're touching backend code, add or update the relevant *.test.ts next to your source file. If you're touching parsing or prompt assembly, include a couple of example documents and queries in the PR description that demonstrate the change behaving as advertised.
A proper frontend test harness is on the Roadmap. Contributions toward that are particularly welcome.
Pull request checklist
- Issue opened first (for non-trivial changes), and approach agreed
-
npm run lintpasses locally - One thing per PR
- PR description explains why and includes a brief test plan
- If you added an LLM provider or file format, the README +
.env.exampleare updated - No secrets, lore folders,
api-keys.json, or.env*files in the diff
Reporting a security vulnerability
Please don't open a public issue. See SECURITY.md for the disclosure process.
Questions?
Open an issue — new-contributor questions are welcome and get answered with a smile, not a sigh. A community Discord with a dedicated support channel is on the roadmap.