ADE for working with a fleet of parallel agents
Go to file
Neil 995ee88891
perf(persistence): single full-state serialization per save (#9381)
## Description

Every durable save serialized the ~1.5 MB durable state **twice**, synchronously on the main Electron thread: once in `computeStateHash()` (the plaintext hash for the no-op-write guard) and again in `buildStateToSave()` (the encrypted on-disk payload). The guard couldn't hash the payload directly because `encrypt()` on random-IV platforms produces different bytes each save for identical state.

This PR collapses the two into **one** `JSON.stringify`. `buildStateToSave()` now returns `{ payload, stateHash }`: each encrypted secret slot is serialized as a **fresh per-slot random sentinel** (`orca-secret-slot-<uuid>`), and after the single stringify each sentinel is substituted exactly once — to its ciphertext for the on-disk `payload`, and to its plaintext for the guard `hashInput`. The guard hash is therefore a pure function of the plaintext state (`hashInput === JSON.stringify(plaintext durable state)`), and the on-disk `payload` is byte-identical to the previous two-stringify output.

No change to the save API, debounce timings, guard semantics, or on-disk format (compact JSON, same 3 encrypted fields).

### Why sentinels (not a string replace of the ciphertext)

The substitution must be **position-exact**. A naive `payload.replace(ciphertext, plaintext)` — or even a `"key":"ciphertext"`-anchored replace — can be **mimicked by user-controlled state**, which would substitute the wrong site and let two *distinct* states normalize to the same guard hash → a real change is silently **not written** (data loss). This is reachable on deterministic-IV platforms (macOS / legacy-Linux OSCrypt use a constant IV, so a user can read their own ciphertext out of `orca-data.json`):

- **Value vector**: a plaintext free-text field (e.g. `httpProxyBypassRules`) whose value equals a secret's ciphertext.
- **Key vector**: `agentDefaultEnv` lets the user name an env var exactly after a secret field (e.g. `browserKagiSessionLink`) with a ciphertext value, producing a `"browserKagiSessionLink":"<ciphertext>"` token inside `settings` (before `ui`).

A per-slot random sentinel is minted **after** all user data is captured, so it cannot occur anywhere else in the serialized state and matches only the intended secret slot — closing the entire class. (Both vectors were found by an adversarial fable→gpt-5.6-sol review loop; each has a store-level regression test that fails on the earlier approaches and passes now.)

The empty-secret / `safeStorage`-unavailable / encrypt-failure cases (`blob === plaintext`) get no sentinel and reproduce `main`'s behavior byte-for-byte.

## Evidence

- Full-state `JSON.stringify` calls per changed save: **2 → 1** (call-counting test).
- Frontier-review benchmark on an 8 MiB real-method state: **no perf regression** (median 12.73 ms sentinel vs 13.77 ms two-stringify baseline).
- Independent review modeled 625 adversarial durable states: every payload byte-identical to the pre-PR implementation, and every distinct state produced a distinct guard hash (no dropped-write collision).

## No-Regression Proof

`src/main/persistence-single-serialize.test.ts` (nondeterministic **and** deterministic cipher mocks):

- identical state with secrets set → no-op (inode unchanged); real change (incl. secret rotation) → writes
- on-disk payload is ciphertext (plaintext appears nowhere), round-trips through reload/decrypt
- empty secret + `isEncryptionAvailable() === false` → plaintext payload, guard still skips
- sync `flushOrThrow()` also skips on identical state
- exactly one full-state serialization per save
- **regression (value vector)**: a plaintext field equal to a secret's ciphertext, then swapped → write is not skipped, round-trips
- **regression (key vector)**: an `agentDefaultEnv` var named after a secret field holding its ciphertext, then swapped → write is not skipped, round-trips

Suites: `persistence-single-serialize.test.ts` + `persistence.test.ts` all green; `pnpm run typecheck:node` clean; oxlint clean.

## ELI5

Orca saves your app state whenever something changes, and it used to build the whole (large) state twice each time — once to check "did anything actually change?" and once to write the file. Now it builds it once and reuses that copy for both jobs. To compare states safely it swaps each encrypted secret for a random one-time marker while checking, so no value you type can ever be mistaken for a secret and trick it into skipping a real save. What lands on disk is exactly the same, and your secrets stay encrypted.

Made with [Orca](https://github.com/stablyai/orca) 🐋
2026-07-20 19:47:58 -07:00
.github test(e2e): prove the terminal daemon survives a main-process crash on Windows (#7742) (#9311) 2026-07-19 11:27:29 -07:00
.husky fix(win32): resolve EPERM on userData writes, batch-file spawn failures, and native dep rebuild (#1152) 2026-04-26 22:29:58 -07:00
Casks Put the orca CLI on PATH at install time for headless hosts (#5842) 2026-06-19 15:46:29 -07:00
build-plugins feat(codex): real-home routing + self-contained multi-account homes (#9501) 2026-07-20 14:34:53 -07:00
config fix(ssh): patch node-pty helper in Windows relay (#9638) 2026-07-20 19:09:18 -07:00
docs docs(headless-server): add upgrade SOP for orca serve on Linux (#9575) 2026-07-20 21:38:39 -04:00
mobile fix(github): load PR diffs for Enterprise remotes (#8932) 2026-07-20 18:55:45 -07:00
native fix(cli): preserve multiline arguments on Windows (#8374) 2026-07-12 02:13:41 -07:00
resources feat(skills): ship orca-cli as a first-generation hybrid stub (#9238) 2026-07-20 13:13:21 -07:00
skill-guides Tighten orchestration worktree isolation policy (#9482) 2026-07-19 17:17:40 -07:00
skill-stubs feat(skills): ship orca-cli as a first-generation hybrid stub (#9238) 2026-07-20 13:13:21 -07:00
skills feat(skills): ship orca-cli as a first-generation hybrid stub (#9238) 2026-07-20 13:13:21 -07:00
src perf(persistence): single full-state serialization per save (#9381) 2026-07-20 19:47:58 -07:00
tests Keep embedded browser commands on the registered Orca target (#9633) 2026-07-20 22:04:01 -04:00
tools feat(codex): real-home routing + self-contained multi-account homes (#9501) 2026-07-20 14:34:53 -07:00
.gitattributes feat(skills): ship orca-cli as a first-generation hybrid stub (#9238) 2026-07-20 13:13:21 -07:00
.gitignore Add native chat skill picker with host-aware discovery (#9480) 2026-07-19 17:31:34 -07:00
.npmrc Update .npmrc 2026-07-11 20:53:20 -07:00
.oxfmtrc.json
.oxlintrc.json lint(unicorn): enable prefer-number-properties, prefer-array-find, prefer-array-index-of (#7516) 2026-07-05 23:56:37 -07:00
AGENTS.md Update code comments section in AGENTS.md 2026-07-19 21:40:49 -07:00
CLAUDE.md Link CLAUDE.md to AGENTS.md 2026-05-04 20:42:03 -07:00
LICENSE
README.md docs(readme): drop Windows RC download notice 2026-07-20 11:40:17 -07:00
components.json
electron.vite.config.ts feat(dashboard): add agent dashboard popout (#9604) 2026-07-20 17:11:23 -07:00
orca.yaml Fix Windows setup hook script (#2106) 2026-05-16 17:44:42 -04:00
package.json release: v1.4.148-rc.1 2026-07-21 02:01:29 +00:00
pnpm-lock.yaml fix(cli): avoid Windows PATH status timeout (#9483) 2026-07-19 21:59:22 -04:00
tsconfig.json
vite.web.config.ts chore(lint): upgrade oxlint to 1.71 + enable 7 new rules (autofixed backlog) (#6841) 2026-06-29 22:38:29 -07:00

README.md

Orca Orca

GitHub stars Total downloads across all releases License: MIT Join the Orca Discord Follow Orca on X Supported platforms: macOS, Windows, and Linux

中文 · 日本語 · 한국어 · 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

Orca desktop app running agents in parallel worktrees, with the Orca mobile companion app in the corner

Features

Mobile Companion

Monitor and steer your agents from your phone — get notified when an agent finishes and send follow-ups from anywhere.

iOS App Store · TestFlight · Android APK 0.0.31 · Docs →

Orca desktop with the mobile companion app

Parallel Worktrees

Fan one prompt across five agents, each in its own isolated git worktree — compare the results and merge the winner.

Docs →

Parallel worktree orchestration

Terminal Splits

Ghostty-class terminals with WebGL rendering, infinite splits, and scrollback that survives restarts.

Docs →

Terminal splits

Design Mode

Click any UI element in a real Chromium window to send its HTML, CSS, and a cropped screenshot straight into your agent's prompt.

Docs →

Embedded browser and Design Mode

GitHub & Linear, Native

Browse PRs, issues, and project boards in-app — open a worktree from any task and review without a context switch.

Docs →

GitHub and Linear task workflows in Orca

SSH Worktrees

Run agents on a beefy remote box with full file editing, git, and terminals — auto-reconnect and port forwarding included.

Docs →

Remote worktrees over SSH

Annotate AI Diffs

Drop comments on any diff line and ship them back to the agent — review, edit, and commit without leaving Orca.

Docs →

Annotate AI-generated diffs

Drag Files to Agents

VS Code's editor with autosave everywhere — drag files or images straight into an agent prompt.

Docs →

Drag files and images into an agent prompt

Orca CLI

Agents drive Orca too — script every workflow with orca worktree create, snapshot, click, and fill.

Docs →

Script Orca from the CLI

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 logo Claude Code   Codex logo Codex   Grok logo Grok   Cursor logo Cursor   GitHub Copilot logo GitHub Copilot   OpenCode logo OpenCode   MiMo Code logo MiMo Code   Amp logo Amp   OpenClaude logo OpenClaude   Antigravity logo Antigravity   Pi logo Pi   oh-my-pi logo oh-my-pi   Hermes Agent logo Hermes Agent   Devin logo Devin   Goose logo Goose   Auggie logo Auggie   Autohand Code logo Autohand Code   Charm logo Charm   Cline logo Cline   Codebuff logo Codebuff   Command Code logo Command Code   Continue logo Continue   Droid logo Droid   Kilocode logo Kilocode   Kimi logo Kimi   Kiro logo Kiro   Mistral Vibe logo Mistral Vibe   Qwen Code logo Qwen Code   Rovo Dev logo Rovo Dev   + any CLI agent


Install

Desktop — macOS, Windows, Linux

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.


Community & Support

  • Discord: Join the community on Discord.

  • Twitter / X: Follow @orca_build for updates and announcements.

  • WeChat: Groups 1 and 2 are both full — now you can join the third one.

    WeChat QR code for the Orca community
  • 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.

Orca contributors

GitHub star history chart for stablyai/orca

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.