* feat(native-chat): keep restart recovery available in status bar * fix(native-chat): source the restart offer from the host and retire it on recovery Closing the reconnect dialog spent the durable recovery offer, so looking around before deciding lost the recovery for good. The offer now survives a close, and the status bar carries it — but a durable offer needs a way to die, and it only had a reconnect, an explicit dismiss, and a 24h expiry. The claim's launch-scoped lifecycle moves into its own collaborator, which splits what the host ADVERTISES from the evidence it holds. A resume-capable hold that hands a marked chat its provider child back is the recovery the offer existed to perform, so it stops being advertised and stops being written back at quit, while the marker stays valid evidence — a user who reopened a chat can still ask the agent to carry on. Teardown re-derives the snoozed offer rather than round-tripping raw markers, and this teardown's own witness now outranks the stale claim for the same chat instead of being overwritten by it, which was silently persisting an old turn id and making the next launch refuse the chat that was actually mid-turn. On the renderer the candidate list gets its own producer against agentSession.restartResumable, so the status entry and the dialog read one host-owned answer instead of the dialog pushing its local state at a sibling. The entry re-reads the host before reopening, so a reopened list can never name a chat the host would now refuse; dialog open becomes the external one-shot request rather than a flag mirrored into render state, which is what let a reopen replay the launch answer and re-offer chats already reconnected. Dismiss all is quiet rather than destructive, saves the preference like every other exit, and reports a write the host never confirmed instead of trapping the dialog open. * fix(native-chat): keep a durable offer a launch never read, and settle the one a continuation spent Teardown replaced the recovery capsule with whatever this launch still owed, and a launch that never read the offer owes nothing — so a quit after a failed first read, a disabled flag, or a window that never mounted deleted a recovery the user was never shown. The write-back now distinguishes "claimed and still owed" from "never claimed": the first is re-derived as before, the second carries forward verbatim, because nothing revealed those sessions and the predicate would refuse every one for want of a journal nobody opened. Reconnect and continue spent the same claims Reconnect does but never shrank the offer, leaving the status bar counting chats the host had already handed back and sending the user to an entry that re-reads, finds nothing and does nothing. * fix(native-chat): stop a teardown answering for an offer it could not read Two ways the write-back deleted a durable recovery offer nobody had seen. A take that FAILED left the claim holding an empty list and reporting that this launch had answered for the offer. The markers were still on disk, unread and unknowable, and teardown then overwrote them with its own empty list. It now writes nothing at all unless it has a witness of its own. `owed()` read "has the capsule been touched" where it meant "did anything here LOOK at the offer" — and its own write-back read counted. Teardown is retried when a phase fails, so the second attempt re-derived carried markers against a session map eviction had already emptied, refused every one, and wiped what the first attempt had just carried forward. The flag is now set only by the paths that actually read or act on the offer. The mock guard for the carry could not fail: it indexed the session it claimed nothing had revealed, so re-deriving passed and the verbatim carry was never the reason it went green. It now runs against no indexed session, which is what an unread offer looks like. Also drops the `Not now` row from the preference table, where it was paired with a dismiss method it no longer calls, and asserts the same thing where the snooze is already covered. Splits the marker predicate's journal reader out of the resume host, which was at its line ceiling. * fix(native-chat): clear the corrupt recovery capsule the take refused A capsule whose contents no longer parse made take() throw before it ever reached the clear, so the bad file survived every launch. Nothing else rewrites it now that a teardown owing nothing readable declines to write, and the freshness filter runs after the parse, so the 24h window could not release it either: one corrupt file refused recovery forever. Clear it inside the same transaction that failed to read it, then rethrow, so the poison dies on the next launch while callers still see why the take failed. A clear that fails is swallowed rather than allowed to mask the parse error. Refusing to expose partial candidates is unchanged, and a read that fails for any other reason still writes nothing. * feat(native-chat): make resume the one restart action, and make it actually resume The restart prompt offered two actions: "Reconnect all", which reattached and sent nothing — exactly what opening the chat already does — and "Reconnect and continue", which reattached and asked the agent to carry on. The vacuous one is gone, the "Not now" button and the info popover with it, and the feature is now called resume throughout. "Don't ask again (resume automatically)" now runs the action the button runs: the launch calls agentSession.restartContinue instead of agentSession.restartResume, so the preference means what it says. Several comments asserted the opposite as a structural guarantee and are corrected. agentSession.restartResume stays: no in-app caller is left, but it is a published wire method a non-desktop or older client can call. * fix(native-chat): label the resume button with the number of chats selected The button read "Resume all" whenever every chat happened to be ticked, which described the selection rather than the action. It always acted on the selected chats only. Now it always names that count, with a singular variant so one chat does not read "1 chats". * refactor(native-chat): drop the reconnect vocabulary the resume action left behind Resuming became one action — reattach and ask the agent to carry on — so the notification helpers no longer need to be told which action they are reporting. Every caller passed `continue`; the `reconnect` branch, its helper and its catalog keys are gone. The dialog and the launch path had grown two copies of the same call: same RPC, same response shape, same announce-and-settle. That now lives once in the store module that owns the offer, which also takes the dismiss call, leaving the modal presentational. The two copies had drifted — only the dialog's caught a malformed payload — and the unified one keeps the defensive reading. No behaviour change. `agentSession.restartResume` stays: it is a published wire method even though nothing in the app calls it. * refactor(native-chat): derive the resume selection instead of intersecting it The modal's selection was intersected back against the host's candidate list before every action, as a guard against naming a chat the host never offered. That guard could never fire: the selection was already derived from that same list, so the intersection was the identity. The array of chosen ids is now the derived value and the lookup set falls out of it, which makes the property structural rather than checked. The helper had no other caller and is gone, along with its three tests. Three tests mocked the resume response in the shape the old API returned. Two never reached that branch at all; the third only passed because the unreadable shape happened to exercise the malformed-payload path. All three now use the real shape, and the malformed-payload behaviour — report an unconfirmed delivery, leave the offer standing — gets a test that says so. Also: the candidate reader took two trailing optional parameters, so one caller passed a placeholder `false` to reach the second; they are an options object now. `isFolderWorkspaceId` had no caller outside its own module and is no longer exported. `RestartActionOutcome` only ever describes a continuation row, so it is named for that. `dismissAll` set a busy flag that nothing could render, since it closes the dialog first. Several comments repeated an argument already made in the module they point at. Settings: the automatic-resume description is one sentence again. No behaviour change. * fix(native-chat): make restart recovery explicitly durable * fix(native-chat): preserve dismissal fence across new interruptions
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.50 · Install guide
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 9.
-
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.
The relay that pairs the mobile app with a desktop host is also in this repository under
cloud/, with a separate pnpm workspace and setup 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.










