Thank you for helping improve ORGII. This project is a Tauri v2 desktop app built with React, TypeScript, webpack, and Rust.
Unless otherwise noted, paths and shell commands are relative to the repository root.
- Search existing issues and pull requests first.
- For larger changes, open an issue or discussion before implementing.
- Set up the app, make a small focused change, and run the checks that match your files.
- Open a pull request with a clear summary, test plan, and passing CLA check.
Keep secrets, private data, generated artifacts, and unrelated formatting changes out of your PR. If you use AI assistance, a human must actively review the design and implementation before submission.
Install the required tools:
| Tool | Version | Notes |
|---|---|---|
| Node.js | 20 or current LTS | Use nvm install --lts or the Node.js installer. |
| pnpm | 9.15 | Install with npm install -g pnpm@9.15. |
| Rust toolchain | 1.85.0 or later | Use rustup toolchain install stable. |
| Tauri system dependencies | Tauri v2 | Follow the Tauri prerequisites guide for your OS. |
| Python 3 | Any 3.x | Only needed for optional asset download scripts. |
From the repository root:
pnpm install
pnpm run tauri:devTauri starts the webpack dev server through its beforeDevCommand, so use the Tauri scripts for normal desktop development.
To try Mobile Remote in production (phone PWA + Cloudflare Relay), see the colleague experience guide. For local relay / Workers deployment, see Mobile Remote dev & production guide.
Copy config/env.example to the repository-root .env only when you need local configuration. .env is gitignored; never commit real secrets.
Build, test, CSS, and commit-message configuration lives in config/. The package scripts and Git hooks select these files explicitly. Use pnpm build, pnpm test, and pnpm test:watch; direct webpack or Vitest commands need --config config/webpack.config.js or --config config/vitest.config.ts, respectively. Editor integrations that ask for a config path should use the files in config/ as well.
ESLint, Prettier, and unimported settings live in package.json so editors and CLI tools can discover them automatically. See linting conventions for the reasoning behind the lint rules.
Restart a running dev server after changing or relocating build configuration. The webpack wrapper loads its config only at startup, so an existing process can keep using old loader paths even after source hot reloads.
For fast desktop iteration against a built app bundle:
pnpm run tauri:build:fastRun the checks that match the files you changed. If you cannot run a relevant check locally, explain why in the PR and include any partial verification you performed.
| Change area | Recommended checks |
|---|---|
| Frontend / TypeScript | pnpm run lint, pnpm run test, pnpm run check:circular |
| Rust / Tauri | pnpm run cargo:check, pnpm run cargo:clippy, pnpm run cargo:test |
| Targeted Rust modules | pnpm run cargo:test:lib (root-package unit tests only), pnpm run cargo:test:agent_core, pnpm run cargo:test:agent_sessions, pnpm run cargo:test:api |
| Chat, session, or UI behavior | E2E tests in tests/e2e; see tests/e2e/README.md |
Core UI end-to-end tests use WebDriverIO with tauri-webdriver-automation:
cargo install tauri-webdriver-automation --locked
cd tests/e2e
pnpm install
pnpm testOne style per directory — never mix. A directory either colocates its tests
beside the source or keeps them in a __tests__/ subdirectory. Both are fine; both
are discovered. What is not fine is a directory that does both, because then nobody
can tell where a new test belongs.
- New directory? Colocate:
foo.tsandfoo.test.tsside by side. - Existing directory? Match whatever is already there.
pnpm run check:test-placementenforces this and runs in CI — it names the offending directory and which file to move. - Name a test after the file it covers:
foo.ts->foo.test.ts. A component whose source isFoo/index.tsxtakesFoo/Foo.test.ts. - When one source file needs several test files, add a facet:
syncEngine.journal.test.ts,syncEngine.retention.test.ts. - A test that covers an invariant rather than a file may be named for the invariant
(
rustTsContract.test.ts,visibilityParity.test.ts). Keep these rare and obvious.
Vitest discovers src/**/*.test.ts only. Two consequences worth knowing:
- A test outside
src/is not run bypnpm test. The e2e suite undertests/e2e/is a separate WebdriverIO run with its own config. - Only
.test.tsis collected — not.test.tsx. Keep test files as.tsand import the component under test, rather than renaming the test to.tsx.
Import the module under test with a relative path (../foo, ./foo) and pull
anything cross-module through the @src/ alias. Most test files use both, and that
is the intended split — not drift.
describe.only / it.only are a lint error in test files. A focused test makes
every other test in its file silently not run while the suite still exits 0, which is
indistinguishable from passing. .skip and .todo are allowed: those show up in the
reporter's skipped count, so they are visible rather than invisible.
On the Rust side, unit tests are inline #[cfg(test)] mod tests in the source file.
Large modules may extract them to a tests/ subdirectory or a sibling tests.rs.
Cross-cutting integration tests live in a crate's top-level tests/. pnpm run cargo:test
runs the whole workspace, including those integration targets.
| Path | Purpose |
|---|---|
src/ |
React, TypeScript, UI, stores, hooks, and frontend services |
src-tauri/ |
Tauri shell and Rust backend |
docs/ |
Living architecture and feature documentation |
scripts/ |
Development, setup, maintenance, and build scripts |
tests/ |
Repository-level tests and test helpers |
Add or update docs when behavior, architecture, setup, or user-visible behavior changes in a way that is not obvious from the code.
Use the repository rules in .cursor/rules/ as the source of truth. The most common expectations are:
- Keep changes focused and remove dead code immediately.
- Use existing shared components, hooks, stores, and design tokens.
- Prefer typed constants and enums over hardcoded domain strings.
- Let errors propagate instead of silently returning empty fallback data.
- Update all supported locales when changing user-facing UI text.
- Follow frontend/backend contract rules when a setting, command, or wire type crosses the TypeScript and Rust boundary.
For deeper guidance, read:
.cursor/rules/orgii-frontend.mdc.cursor/rules/frontend-backend-alignment.mdc.cursor/rules/rust-resource-lifecycle.mdc.cursor/rules/cargo-cleanup.mdc
The complete, repository-wide pull request contract is in
PR_RULES.md. It applies to human contributors and coding
agents. GitHub automation enforces its machine-checkable title, description,
and label rules.
Commit messages and PR titles must use scoped Conventional Commits:
feat(scope): short imperative summary
fix(scope): short imperative summary
Use lowercase kebab-case scopes such as git, settings, workstation, slash-menu, or contributing. Common types include feat, fix, chore, docs, style, test, refactor, perf, build, ci, and revert.
Every non-trivial commit needs a body that explains why the change exists, summarizes important behavior or architecture changes, and mentions notable verification or migration details.
A commit-msg hook runs commitlint, and the pre-commit hook appends a tamper-evidence trailer:
Pre-commit hook ran. Total eslint: N, total circular: N
Do not remove this trailer, and do not bypass hooks with --no-verify, HUSKY=0, or similar unless a maintainer explicitly asks you to do so for emergency recovery. If a hook fails, fix the issue and rerun the command normally.
Before requesting review, make sure the PR has:
- A title, description, and labels that comply with
PR_RULES.md. - One focused issue, feature, or fix.
- Relevant checks passing, or a note explaining what could not be run.
- CLA Assistant passing, plus screenshots or docs when the change needs them.
Also confirm that no secrets, local configuration, generated build output, or unrelated files are included.
ORGII requires contributors to sign the repository Contributor License Agreement before a pull request can be merged. The agreement text is in docs/contributing/CLA.md.
GitHub CLA Assistant will comment with a signing link on your first PR if your GitHub account has not signed the current agreement.
- Sign as an individual when the contribution is your own work and you are legally allowed to submit it.
- Sign as a company only if you are authorized to bind that organization to the CLA.
Maintainers will not merge PRs until the CLA check passes.
Do not report security vulnerabilities in public issues. Use the repository's private security advisory flow when available, or contact the maintainers privately.
Never commit API keys, signing keys, OAuth secrets, personal tokens, private logs, or user data. If you accidentally expose a secret, revoke it immediately and notify maintainers.
Be respectful, constructive, and specific. Keep issue and pull request discussions focused on the work.
By contributing, you agree that your contributions are licensed under AGPL-3.0-or-later and submitted under the Contributor License Agreement in docs/contributing/CLA.md. See LICENSE for the full license text.