* perf(renderer): index project host ownership on repo catalog refresh mergeFetchedProjectCompatibilityForHost runs synchronously inside a zustand set() on every repo catalog refresh and was O(projects x (setups + repos)): getProjectHostIds / getExplicitProjectHostIds rescanned all setups and all repos once per project, and mergePreviousProjectMetadata rebuilt a full catalog repo key-set per project. Precompute the indexes once and hand each helper only its own project's slice. No ownership logic is reimplemented — the same resolvers run, just on pre-sliced inputs, memoized per project object. 200 repos 1.1 ms -> 0.2 ms (5.2x) 600 repos 11.2 ms -> 0.7 ms (15.3x) 1200 repos 43.0 ms -> 1.6 ms (26.6x) Verified against 4,000 randomized differential cases (duplicate repo ids, dangling sourceRepoIds, empty-repoId and orphan setups, dropped setups, local/SSH/runtime host mixes) comparing output element provenance and order against the previous implementation, not just deep structure. Each of the three index helpers was negative-controlled: breaking any one of them turns the differential red. Co-authored-by: Orca <help@stably.ai> * perf(renderer): keep the repo filter array identity across no-op refetches Three fetch sites unconditionally reallocated filterRepoIds (`s.filterRepoIds.filter(...)`) on every repo catalog refresh, even when nothing was pruned. Six identity-sensitive subscribers select this array, including App.tsx at the root, so every refresh woke the whole tree. retainValidFilterRepoIds returns the input when every id is still valid; `.every` short-circuits so the common case allocates nothing at all. It lives in its own module rather than ui.ts: repos.ts does not import ui.ts and this codebase has a documented circular-slice-import hazard. The store type widens to `readonly string[]`, which takes three more declaration edits (visible-worktrees, add-repo-skip-finalization, the setter). PersistedUI.filterRepoIds deliberately stays `string[]`: main owns that array, and widening it would fail the ui-state schema-parity assertion unless the zod schema gained `.readonly()`, which Object.freeze()s every parsed `ui.set` payload arriving from a paired client. Copy at the App.tsx IPC boundary instead — one allocation per debounced 150ms persist, not per render. Co-authored-by: Orca <help@stably.ai> * perf(renderer): reconcile projects and host setups across no-op refetches mergeFetchedProjectCompatibilityForHost always allocates — sourceRepoIds is rebuilt per project and fetched setups arrive freshly cloned over IPC — so `projects` and `projectHostSetups` lost both array and element identity on every catalog refresh. #13770's identity work covered only projectGroups and folderWorkspaces. Reconcile both at the merge's single return site (five callers) against `previous`, keyed on what each merge already dedups by: project.id, and getProjectHostSetupOwnerKey for setups. setup.id is deliberately not the setup key — the repo-derived fallback sets id = repo.id, so one repo on two hosts yields two setups sharing an id, and keying on it would splice the wrong host's routing metadata into a row. filterSetupsForPrunedRepoRows had to stop returning `[...setups]` unconditionally: three callers feed its result in as `previous`, so the throwaway copy defeated the reconcile even though element identity survived. Rather than add a third parallel deep-equality helper, generalize reconcileFetchedRepos (#13744) into reconcileCatalogRows and delete repos.ts's isPlainCatalogObject + areCatalogEntriesEqual (#13770). The two were the same algorithm modulo the null-prototype branch; the survivor takes the union of both prototype guards, which is strictly more permissive and so can only reconcile more, never mask a change. repos-catalog-merge-identity.test.ts and repo-identity-reconcile.test.ts stay green unmodified as the proof. Element-level reuse means a consumer mutating a Project or ProjectHostSetup in place would corrupt the previous render's object, so RepoSlice['projects'], ['projectHostSetups'] and ProjectHostSetupProjection widen to readonly. That is the safety mechanism, not polish — it caught two real in-place accumulators (ai-vault-scope-paths and the runtime-host purge in worktrees.ts), which now annotate mutable locals per the repo's readonly precedent. No casts added. Co-authored-by: Orca <help@stably.ai> * test(renderer): cover repo catalog refresh identity A dedicated file — repos.test.ts is already at the max-lines ceiling and these are a distinct concern. The fixture is production-shaped on purpose. A scalar-only repo reconciles even when the structural compare is broken, which is how an earlier version of this work shipped green while being completely inert; addedAt is pinned non-zero because project-host-setup-projection falls back to `repo.addedAt || now`, so a zero timestamp stamps Date.now() into every projection and nothing ever reconciles. Every mocked fetch returns a structuredClone so identity can never match by accident. Every identity assertion was verified red against reverted source: - drop reconcileCatalogRows from the merge return -> no-op-refetch identity and per-element reuse fail - filterSetupsForPrunedRepoRows back to `[...setups]` -> no-op-refetch identity fails - retainValidFilterRepoIds back to `.filter(...)` -> both filter-identity cases fail - areValuesEqual reduced to `a === b` -> all three reconcile cases fail - areValuesEqual forced to `true` -> all six change-propagation cases fail - setup key switched to setup.id -> the two-hosts-one-repo-id case fails Co-authored-by: Orca <help@stably.ai> --------- Co-authored-by: Orca <help@stably.ai>
Orca
中文 · 日本語 · 한국어 · Español · Français · Português
The AI Orchestrator for 100x builders.
Run Codex, ClaudeCode, OpenCode or Pi side-by-side — each in its own worktree, tracked in one place.
Download Orca
Features
Also in the box:
- Quick open — Search across worktrees, files, agents, commands, and repo context without leaving your flow.
- Account switcher & usage tracking — See Claude and Codex usage and rate-limit resets, and hot-swap accounts without re-logging in.
- Rich repo previews — Preview Markdown, images, PDFs, and repo docs in the workspace.
- Computer Use — Let agents operate desktop apps and visible UI when a workflow needs real interaction.
- Notifications and unread state — Know when an agent finishes or needs attention, then mark threads unread to come back later.
- And many, many more — we ship daily, so this list is perpetually behind. The changelog is the real feature list.
Supported Agents
Works with any CLI agent — if it runs in a terminal, it runs in Orca.
Claude Code
Codex
Grok
Cursor
GitHub Copilot
OpenCode
MiMo Code
Amp
OpenClaude
Antigravity
Pi
oh-my-pi
Hermes Agent
Devin
Goose
Auggie
Autohand Code
Charm
Cline
Codebuff
Command Code
Continue
Droid
Kilocode
Kimi
Kiro
Mistral Vibe
Qwen Code
Rovo Dev
+ any CLI agent
Install
Desktop — macOS, Windows, Linux
- Download from onOrca.dev
- Or grab a build directly: macOS Apple Silicon · macOS Intel · Windows (.exe) · Linux AppImage · All builds
- Running
orca serveon a headless Linux server? See the headless Linux server guide.
Or via a package manager:
# macOS (Homebrew)
brew install --cask stablyai/orca/orca
# Arch Linux (AUR) — or stably-orca-git to build from source
yay -S stably-orca-bin
Mobile Companion — iOS, Android
Pair with your desktop app to monitor and steer your agents from your phone.
- iOS: Download on the App Store or join TestFlight
- Android: Download APK 0.0.42
Community & Support
-
Discord: Join the community on Discord.
-
Twitter / X: Follow @orca_build for updates and announcements.
-
WeChat: Scan to join the Orca community WeChat group 7.
-
Feedback & Ideas: We ship fast. Missing something? Request a new feature.
-
Privacy: See the privacy & telemetry docs for what anonymous usage data Orca collects and how to opt out.
-
Show Support: Star this repo to follow along with our daily ships.
Developing
Want to contribute or run locally? See our CONTRIBUTING.md guide.
Signed Builds
Windows code signing sponored/provided by SignPath.io, certificate by SignPath Foundation.
License
Orca is free and open source under the MIT License.










