Skip to content

Contributing to Oleafly

Thanks for wanting to make Oleafly better! This guide gets you from a fresh clone to a working dev build, and covers how we review and land changes.

  • Report a bug: open a bug report.
  • Request a feature: open a feature request.
  • Report a vulnerability: please do not open a public issue; see SECURITY.md.
  • Send a pull request: see below.

For anything larger than a small fix, open an issue first so we can agree on the approach before you invest time.

Tool Version Notes
Node.js 22.13+ Required by pnpm 11
pnpm 11.9+ Enable Corepack or install the version declared in package.json
Rust stable (1.77+) includes cargo
Platform deps - See the Tauri v2 prerequisites for your OS (on Linux: libwebkit2gtk-4.1-dev, librsvg2-dev, patchelf, …)
Terminal window
git clone https://github.com/Oleafly/Oleafly.git
cd Oleafly
pnpm install
# Find your target with `rustc -vV | grep host`.
bash scripts/fetch-tectonic.sh aarch64-apple-darwin # or your host triple
bash scripts/fetch-typst.sh aarch64-apple-darwin
# Run the app in dev mode (hot-reloads the frontend, rebuilds Rust on change):
pnpm tauri dev

The Tectonic and Typst binaries are git-ignored on purpose - never commit them. The fetch script drops them in src-tauri/binaries/, which is where bundle.externalBin expects them.

Terminal window
pnpm tauri build

Installers land in src-tauri/target/release/bundle/.

src/ React + TypeScript frontend
components/ UI (editor, pdf, ai, layout, files, …)
lib/ framework-agnostic helpers (ai-providers, github, …)
store/ Zustand state slices
src-tauri/src/ Rust backend (Tauri commands)
commands.rs compile pipeline (Tectonic sidecar)
project.rs project/file CRUD (path-sandboxed - see `resolve`)
git.rs git integration
github.rs GitHub OAuth device flow
paths.rs path helpers + project-id validation
docs/ user-facing documentation
scripts/ tooling (Tectonic fetch, icon gen)
Terminal window
pnpm test # frontend unit tests (Vitest)
cd src-tauri && cargo test --lib # Rust backend tests

Backend logic that touches the filesystem, git, or user paths must have a test. The path-sandboxing helpers (resolve_within, validate_project_id) and log/URL parsers are covered in #[cfg(test)] modules - extend them when you change that code. On the frontend, the LaTeX masking that decides what the spell/grammar checker sees is pure and unit-tested in src/components/editor/cm/latex-mask.test.ts - add a case there when you change what counts as prose.

  • TypeScript - the frontend must typecheck and build: pnpm build, and pass the Biome lint gate: pnpm lint (auto-fix what’s safe with pnpm lint:fix). The gate blocks on correctness errors; an existing accessibility/style backlog is reported as non-blocking warnings (see biome.json). Prefer not adding new warnings.
  • Rust - the backend must be cargo fmt-clean and cargo clippy-clean; both are blocking in CI (clippy runs with -D warnings). Run cargo fmt and cargo clippy --all-targets --fix before pushing.
  • Match the surrounding code - comment density, naming, and idiom.
  1. Fork and branch from main (git checkout -b fix/short-description).
  2. Keep the change focused; unrelated refactors belong in their own PR.
  3. Make sure pnpm lint, pnpm build, and cargo test --lib pass locally.
  4. Fill out the PR template - link the issue, describe the change, note how you tested it.
  5. CI must be green (the frontend build and Rust tests are required checks).

We squash-merge, so a clean PR title is the commit message. Conventional-commit style is appreciated but not required (e.g. fix: reject absolute paths in resolve).

Releases are cut by pushing a version tag; the Release workflow builds installers for macOS (Apple Silicon), Windows x64, and Linux x64 and attaches them to a draft GitHub Release for review before publishing.

Terminal window
# Bump the version everywhere it's declared (package.json, Cargo.toml,
# Cargo.lock, tauri.conf.json) in one shot, so the tag can't drift:
./scripts/bump-version.sh 0.2.0
git commit -am "chore: release v0.2.0"
git tag v0.2.0 && git push origin v0.2.0

By contributing, you agree that your contributions are licensed under the project’s GNU Affero General Public License v3.0 or later.