Contributing to OpenDray v2#
Thanks for your interest. v2 is in v1.0-rc; the cutover from
Opendray/opendray (v1) happens after
this release ships.
Finding something to work on#
If you're looking for an easy way in:
- Good first issues: github.com/Opendray/opendray/labels/good first issue. Each one has a clear acceptance criteria and a pointer to where to start.
- Help wanted: github.com/Opendray/opendray/labels/help wanted. Larger pieces of work where outside contribution is especially welcome.
- Discussion #300 (v2.8 roadmap): the "What should we ship in v2.8?" thread lists the ideas currently on the radar. Comment there before starting work on anything bigger than a contained fix, so we can align on scope.
If you'd rather just open a PR for something not in the issue tracker (a small fix, a typo, a missing log line), go ahead. For anything that crosses subsystem boundaries or introduces a new external dependency, please open an issue or discussion first.
Prerequisites#
| Tool | Version | Purpose |
|---|---|---|
| Go | 1.25+ | Backend + embedded web bundle |
| pnpm | 10+ | Web SPA build (app/web/) |
| Node.js | 22+ | pnpm runtime (build only, not needed at deploy) |
| PostgreSQL | 15+ | Required at runtime; v2 has no bundled mode |
Development Setup#
[object Promise]For a full walkthrough including troubleshooting, see
docs/quickstart.md. The condensed path is below.
For HMR-driven frontend work, run the Vite dev server alongside:
[object Promise]Project Structure#
See README.md for the layout. Subsystem responsibilities
are documented inline in each internal/<subsystem>/ package's
doc.go file and in the operator / integration guides under docs/.
Tests#
[object Promise]A subset of tests in internal/memory/summarizer/ exercises a real
Postgres. They t.Skip when OPENDRAY_DEV_DB_URL is unset, so the
default go test ./... is always green even without a database.
To run them locally, point OPENDRAY_DEV_DB_URL at any Postgres 15+
instance with pgvector available (e.g. an apt / brew install, or a
remote PG you control):
Never hard-code DSNs in source. They will leak via git history.
Pull Request Process#
- Fork or branch from
main. - Make focused changes. One PR, one concern.
- Run checks locally:[object Promise]
- Open a pull request against
main. Describe the change, link any related ADR, and include a test plan. - CI must pass before merge.
Commit messages#
Follow Conventional Commits:
feat:, fix:, refactor:, docs:, test:, ci:, chore:. Optional
scope in parens: feat(memory):, fix(backup):.
Architecture changes#
Anything that crosses subsystem boundaries, changes a public API, or introduces a new external dependency needs a clear write-up in the PR description: context, decision, consequences. Reference any relevant operator / integration guide updates from the same PR.
Code Style#
- Go: Standard library style.
gofmtis enforced. Wrap errors with context usingfmt.Errorf("op: %w", err). Return new structs; never mutate in place. - TypeScript: TS strict mode + the rules already enforced by the Vite +
ESLint setup in
app/web/.
Translating opendray#
Translation contributions land in two places.
README translations. Ten languages live alongside README.md at the repo root (README.zh.md, README.fa.md, README.es.md, README.pt-BR.md, README.ja.md, README.ko.md, README.fr.md, README.de.md, README.ru.md). The convention is "Finglish" style: technical product names and OSS terms stay in Latin script (Claude Code, Codex, gateway, session, host, transcript, embedding) while the connective tissue is native. Each language uses its own register:
- ES, PT-BR, FR: informal (tú / você / tu).
- DE: informal "Du".
- JA: です・ます polite-neutral.
- KO: 합니다 register.
- RU: lowercase impersonal "вы" (Habr-style), with the project-wide override of no em-dash тире.
- FA: heavy Latin-English borrowing, RTL-wrapped body.
Style rule that applies to every language: no em-dashes or prose en-dashes anywhere in user-facing text (the U+2014 and U+2013 Unicode characters used as prose punctuation). Use periods, commas, parentheses, or colons instead. Compound-noun hyphens in code identifiers (local-first, --from-source, AI-Coding-CLIs) are the regular hyphen-minus U+002D and stay.
Admin UI translations. The Flutter / React app reads from app/i18n/<lang>.json. Currently shipped: en.json (canonical, ~4 k keys) and zh.json. Adding a new language means copying en.json to <lang>.json, translating the values, and wiring it into the i18next config. See the open good-first-issue for the canonical walkthrough.
Stale translation policy. If your PR changes English-language docs or strings, ideally update the other-language equivalents in the same PR. If that's too much work, flag the affected translations as stale in the PR description and someone will pick them up.
Asking questions#
- General questions, build logs, philosophy: Discussions → General.
- Ideas for new features: Discussions → Ideas.
- Stuck on setup / config / a specific error: Discussions → Q&A.
- Bug reports: Issues → New issue.
Reporting a security vulnerability#
See SECURITY.md. Don't open a public issue.
License#
By contributing, you agree that your contributions are licensed under the
Apache License 2.0 (LICENSE).