* fix(daemon): guard killStaleDaemon against pid recycling The daemon's pid file carried only a bare integer, so killStaleDaemon had no way to verify the current owner of that pid was still the process it forked. Unix pids recycle — on macOS the default ceiling is ~2048 and wraps in minutes under load — so blind SIGTERM/SIGKILL on a recycled pid could hit an unrelated user process (editor, language server, background task) silently. Three moving pieces: 1. Pid file now carries startedAtMs. daemon-spawner exports DaemonPidFile and serializeDaemonPidFile; daemon-init fills startedAtMs from getProcessStartedAtMs(child.pid) right after the daemon signals ready. parseDaemonPidFile tries JSON first and falls back to bare-integer for backward compatibility (startedAtMs: null on legacy files). 2. isDaemonProcess takes expected startedAtMs. In addition to the cmdline match, it consults getProcessStartedAtMs(pid) and compares with a ±1.5s tolerance. Null on either side is fail-open so the guard never strengthens existing behavior negatively (Windows, legacy pid files, kernel-thread /proc failures). 3. SIGKILL re-check. The SIGTERM-then-wait window is up to 3s — long enough for the pid to be recycled if the original daemon dies during the wait. Before escalating to SIGKILL, isDaemonProcess runs again; on mismatch we log reason=pid_recycled and skip SIGKILL. Carried forward from #1323 as a standalone safety fix — independent of that PR's router/drain machinery, which is not shipping. Co-authored-by: Orca <help@stably.ai> * test(daemon): cover pid-recycling guard surface in daemon-health Adds unit coverage for the new Phase 0 surface: - parseDaemonPidFile: JSON round-trip, JSON without startedAtMs, bare-integer fallback for legacy pid files, malformed-input rejection. - startTimeMatches: null-expected fail-open, null-actual fail-open, within-tolerance match, outside-tolerance rejection. - killStaleDaemon: with a mismatched startedAtMs in the pid file, assert that no SIGTERM/SIGKILL is sent even though the liveness probe (process.kill(pid, 0)) runs. startTimeMatches was promoted from module-private to exported so it can be exercised directly — it's a pure function with no internal state. Co-authored-by: Orca <help@stably.ai> * feat(settings): manage sessions panel for daemon staleness UX Add a Manage Sessions settings panel with list/kill-all/kill-one/restart backed by a new pty:management IPC surface. Rows are hover-highlighted and click to reveal the corresponding terminal pane, mirroring the bottom status-bar sessions popover. Kill-all and restart-daemon are icon buttons (Trash2, RotateCw) with tooltips so the restart action doesn't collide with the row-refresh RefreshCw icon. Co-authored-by: Orca <help@stably.ai> * fix(settings): honest killAll counts + suppress post-kill spawn toast killAll now snapshots the initial session IDs and polls listSessions every 100ms for up to 6.5s — past the daemon's 5s SIGTERM→SIGKILL ladder — so well-behaved shells hosting long-running agents finish their SIGTERM handlers before we classify them as "refused to exit." Shutdowns fire once per initial session (no retry spam), and fresh session IDs that appear mid-poll (renderer remounts) don't inflate remainingCount. pty-transport's connect() catch now detects the adapter's TerminalKilledError tombstone rejection ("...was explicitly killed") and suppresses the red "file an issue" toast. After Kill All, a pane remount would call pty:spawn on the dead session ID; surfacing the tombstone as a scary error misrepresented an intentional user action. The pane still renders "Process exited" via the normal lifecycle. Co-authored-by: Orca <help@stably.ai> * feat(daemon): foundation for pty:management IPC surface Adds the plumbing the Manage Sessions settings panel depends on: - daemon-init exports getDaemonProvider / replaceDaemonProvider / restartDaemon / cleanupDaemonForProtocol so the pty:management handlers can access the current provider and coordinate a clean restart without importing window-services internals. - daemon-pty-router exports getAllAdapters so the killAll / listSessions handlers can fan across the current adapter plus any legacy-protocol adapters still attached for in-flight sessions. - daemon-pty-adapter gains a listSessions RPC and readonly protocolVersion so the handlers can annotate each session with the adapter it belongs to and route killOne back to the right adapter. - types.ts exports DaemonSessionInfo (SessionInfo + protocolVersion) as the shared shape the preload API surface mirrors. - ipc/pty.ts, attach-main-window-services, TerminalPane and terminal-search pick up the small bindings required to wire the router through existing code paths without regressions. Co-authored-by: Orca <help@stably.ai> * fix(settings): remove high-session-count warning banner The banner nagged at 20 sessions, which is well within normal use for users with many open worktrees. Count is already visible in the header bar, and the table supports per-row and bulk kills, so the banner added noise without actionable value. Co-authored-by: Orca <help@stably.ai> --------- Co-authored-by: Orca <help@stably.ai>
Orca
The AI Orchestrator for 100x builders.
Run Claude Code, Codex, or OpenCode side-by-side across repos — each in its own worktree, tracked in one place.
Available for macOS, Windows, and Linux.
Supported Agents
Orca supports any CLI agent (not just this list).
Claude Code
Codex
Gemini
Pi
Hermes Agent
OpenCode
Goose
Amp
Auggie
Charm
Cline
Codebuff
Continue
Cursor
Droid
GitHub Copilot
Kilocode
Kimi
Kiro
Mistral Vibe
Qwen Code
Rovo Dev
Features
- No login required — Bring your own Claude Code or Codex subscription.
- Worktree-native — Every feature gets its own worktree. No stashing, no branch juggling. Spin up and switch instantly.
- Multi-agent terminals — Run multiple AI agents side-by-side in tabs and panes. See which ones are active at a glance.
- Built-in source control — Review AI-generated diffs, make quick edits, and commit without leaving Orca.
- GitHub integration — PRs, issues, and Actions checks linked to each worktree automatically.
- SSH support — Connect to remote machines and run agents on them directly from Orca.
- Notifications — Know when an agent finishes or needs attention. Mark threads unread to come back later.
Install
Mac, Linux, Windows
Alternatively, install from a package manager:
macOS (Homebrew)
brew install --cask stablyai/orca/orca
Arch Linux (AUR)
# Precompiled binary
yay -S stably-orca-bin
# Build from GitHub source
yay -S stably-orca-git
[New] Annotate AI Diff
Comment directly on AI-generated diffs.
Annotate any line in an AI-generated diff with your feedback, then send it back to the agent to revise. Keep the review loop tight — no copying line numbers, no context switching.
[New] Hot Swap Codex Accounts
Multiple Codex accounts? Switch in one click.
If you run multiple Codex accounts to get the best token deal, Orca lets you hot-swap between them instantly — no re-login, no config files. Just pick an account and keep building.
[New] Per Worktree Browser & Design Mode
See your app. Click any element. Drop it into the chat.
Orca ships with a built-in browser right inside your worktree. Preview your app as you build, then switch to Design Mode — click any UI element and it lands directly in your AI chat as context. No screenshots, no copy-pasting selectors. Just point at what you want to change and tell the agent what to do.
[New] Introducing the Orca CLI
Agent orchestration from your terminal.
Let your AI agent control your IDE. Use AI to add projects to your IDE, spin up worktrees, and update the current worktree's comment with meaningful progress checkpoints directly from the terminal. Ships with the Orca IDE (install under Settings).
npx skills add https://github.com/stablyai/orca --skill orca-cli
Community & Support
- Discord: Join the community on Discord.
- Twitter / X: Follow @orca_build for updates and announcements.
- Feedback & Ideas: We ship fast. Missing something? Request a new feature.
- Show Support: Star this repo to follow along with our daily ships.
Developing
Want to contribute or run locally? See our CONTRIBUTING.md guide.



