Files
orca/.github/CONTRIBUTING.md
Neil e86cba888b build: reduce native dependency installs to the host platform (#20420)
* Reduce native dependency installs to the host platform

* Remove install policy documentation

* Guard cross-arch packaging and scope release installs to the runner

electron-builder only logs a warning for a missing extraResources source,
so a host-only install silently shipped a foreign-arch slice without its
natives — `pnpm build:mac` on Apple Silicon produced an x64 DMG with no
sherpa-onnx-darwin-x64 and no @parcel/watcher-darwin-x64. The previous
beforePack hook covered only win32.

- Add assertPackagedNativeVariantsInstalled, an arch-aware check over the
  target's sherpa-onnx, @parcel/watcher, and (on Windows) node-gyp addons.
  beforePack now runs it for every platform, with remedies split: another
  architecture comes from install:release, the os:win32 addons need a
  Windows host.
- Drop --os from the release installs. Every packaging job already runs on
  a runner whose OS matches its target, so only the macOS lanes need extra
  breadth, and only on CPU for their x64+arm64 config. Windows and Linux
  packaging return to a plain host-only install.
- Add --frozen-lockfile to install:release so a bare run cannot rewrite
  the lockfile.
- Restore the install policy reference doc and the CONTRIBUTING note, plus
  the rationale comments dropped from the runtime contract test.
- Gate the packaging-closure assertions on whether the Windows addons are
  installed rather than on the host OS, so a cross-arch install exercises
  them off Windows too.
- Make the workflow contract test read `run:` steps as well as retry-action
  commands, and enforce host-only scoping on the non-macOS packaging lanes.
- Remove the unreferenced install measurement script; its numbers live in
  the policy doc.

* Track the install policy doc and index it from AGENTS.md

docs/** is ignored behind a per-file allow-list, so the new reference doc
was only committed via git add -f and future edits would be skipped. Add
it to the allow-list and give it an AGENTS.md entry like every other
tracked reference doc, so the host-only install rule is discoverable
before someone packages a second architecture.

* Route Windows-lane removals through the retrying helper

Adding these four specs to the PR Windows lane pulled them into the
windows-lane-tree-removal-boundary ratchet, which failed on 20 raw
recursive removals. On Windows a bare rmSync races a handle the OS has
not released, throwing EPERM after the assertions already passed and
reporting a green test as a lane failure.

* Adapt the packaging guard to the vendored Windows registry addon

main vendored windows-native-registry as the workspace package
@orca/windows-registry (#20438). A workspace link resolves on every
host, so including it in the installed-Windows-addons checks proved
nothing. @vscode/windows-process-tree is the only os: win32 npm addon
left, so it alone decides whether the win32 resource plan resolves.
2026-09-12 21:25:03 -07:00

7.5 KiB

Contributing to Orca

Thanks for contributing to Orca.

Before You Start

  • Keep changes scoped to a clear user-facing improvement, bug fix, or refactor.
  • Orca targets macOS, Linux, and Windows. Every change must stay compatible with all three platforms unless the code is explicitly guarded by a runtime platform check.
  • For keyboard shortcuts, use runtime platform checks in renderer code and CmdOrCtrl in Electron menu accelerators.
  • For shortcut labels, show and on macOS, and Ctrl+ and Shift+ on Linux and Windows.
  • For file paths, use Node or Electron path utilities such as path.join.
  • Orca must work against local repositories, remote servers, and SSH worktrees. Do not assume a process, file, credential, shell, or network path exists only on the local machine.
  • Orca supports many CLI agents, integrations, and git providers. Keep generic behavior provider-neutral; guard integration-specific logic behind explicit checks.
  • Keep changes well-engineered and performant: follow existing architecture, avoid unnecessary work in hot paths, clean up owned resources, and use concrete module names.
  • For UI work, follow docs/STYLEGUIDE.md, use the tokens and shadcn primitives it specifies, and verify polished behavior across platforms, light/dark mode, and SSH latency.

Local Setup

pnpm install
pnpm dev

Ordinary installs include native optional dependencies for the current OS and CPU only. Before a cross-architecture build (including pnpm build:mac, which produces both x64 and arm64 artifacts by default), run pnpm install:release to add the other CPU's variants. See the install policy.

Branch Naming

Use a clear, descriptive branch name that reflects the change.

Good examples:

  • fix/ctrl-backspace-delete-word
  • feat/shift-enter-newline
  • chore/update-contributor-guide

Avoid vague names like test, misc, or changes.

Before Opening a PR

Run the same checks that CI runs:

pnpm lint
pnpm typecheck
pnpm test
pnpm build

Add high-quality tests for behavior changes and bug fixes. Prefer tests that would actually catch a regression, not shallow coverage that only exercises the happy path.

If your change affects UI or interaction behavior, verify it on the platforms it could impact.

Type Declarations: Prefer .ts Over .d.ts

Project-owned type declarations belong in .ts files. .d.ts is reserved for ambient shims (e.g., env.d.ts, vite/client.d.ts). TypeScript's skipLibCheck: true setting applies globally, including to our own .d.ts files, which means any unresolved type reference in a .d.ts silently becomes any at its call sites. Write your types in .ts files so the compiler actually checks them.

CI enforces this for src/preload/ and src/shared/.

Pull Requests

Each pull request should follow .github/pull_request_template.md. In particular:

  • open with an ELI5 of the change (plain language paragraph; the PR title is the one-liner)
  • explain what changed and why, and stay focused on a single topic when possible
  • for any UI or interaction change, attach before and after screenshots (or short videos); if there is no visual change, say No visual change and why
  • include high-quality tests when behavior changes or bug fixes warrant them
  • include a brief code review summary from your AI coding agent that explicitly checks cross-platform compatibility, SSH/remote/local compatibility, supported agent and integration compatibility, performance risk, UI quality when applicable, and basic security risk
  • mention any platform-specific, remote/SSH-specific, agent-specific, integration-specific, or git-provider-specific behavior and testing notes
  • Include your X (Twitter) handle in the PR template Author section — we shout out contributors when we merge features on @orca_build.

Release Process

Version bumps, tags, and releases are maintainer-managed. Do not include release version changes in a normal contribution unless a maintainer asks for them.

Cutting a release (maintainers)

All releases are cut from the Cut Release GitHub Actions workflow. There is no local pnpm release:* script — running releases locally is too easy to get wrong (dirty tree, wrong branch, stale main).

To cut a release:

  1. Open Actions → Cut Release.
  2. Click Run workflow and pick:
    • kind: one of rc, patch, minor, major.
    • ref: the branch, tag, or SHA to build from. Defaults to main.
  3. Run it.

The workflow resolves the next version from GitHub Releases, bumps package.json, tags, pushes, and runs the multi-platform build + publish inline.

How the next version is chosen:

All stable kinds (patch, minor, major) are computed off the latest stable release, ignoring any RCs in between.

  • kind=rc + last tag was stable (e.g. v1.3.14) → v1.3.15-rc.0.
  • kind=rc + active RC series (e.g. v1.3.15-rc.2) → v1.3.15-rc.3.
  • kind=patch + latest stable v1.3.14v1.3.15 (regardless of any intermediate RCs).
  • kind=minor + latest stable v1.3.14v1.4.0.
  • kind=major + latest stable v1.3.14v2.0.0.

Safety guarantees:

  • Stable releases are refused if the new version isn't strictly greater than the latest published stable. This is the only rule electron-updater actually needs — it compares semver within the latest channel, so a regressing stable is the one thing that breaks auto-update for fresh installs.
  • Complete RC draft releases created by the release workflow are published before cutting a new tag only when the draft tag was built from the current release ref. Stale drafts are skipped so fixes cut a fresh RC instead of exposing old artifacts.
  • If the latest RC tag exists but is still draft-only or missing its GitHub Release, the workflow resumes that tag only when it was built from the current release ref. Otherwise the next RC number is cut.
  • RC numbering also considers release commits on main, so deleting a stale tag does not let a later cut reuse the same RC number.
  • Off-main releases (when ref is not the tip of main) only push the tag. main is never mutated from a non-main ref, so you can safely release an older commit without polluting history.
  • When ref is the tip of main, the version-bump commit is fast-forwarded onto main so local package.json stays in sync with what's shipped.

Common scenarios:

  • Normal release: kind=patch, ref=main.
  • "A bad commit just landed on main, release the commit before it": kind=patch, ref=<good-sha>. main is left alone; the tag points at the good SHA. Fix forward on main afterward.
  • One-off RC for a feature branch: kind=rc, ref=<branch-or-sha>. Produces an RC tag that does not touch main.
  • Minor or major bump: kind=minor or kind=major.

The scheduled 2x/day RC cron in release-rc.yml is independent and continues to run automatically from main.

Release Channels

The public Homebrew cask tracks stable desktop releases:

brew install --cask stablyai/orca/orca

Release candidates use a separate cask token:

brew install --cask stablyai/orca/orca@rc

The two casks conflict because both install Orca.app. Switch channels with a normal brew uninstall --cask followed by the install for the other channel. Do not use --zap unless you intentionally want to remove local Orca state.