* fix(activity): align unread dot with row icon Anchor the unread mini-dot to the icon's own bounding box (relative inline-flex with -top-1 -left-1) instead of the 24x24 cell. The previous absolute positioning was relative to the cell, so the dot landed visibly off-center against the centered AgentStateDot/Plus glyph. Adds a ring-2 ring-background halo for contrast against the row's tinted unread background. Applies to both AgentEventRow and WorktreeEventRow. Co-authored-by: Orca <help@stably.ai> * fix(activity): drop top padding so content sits flush with titlebar Outer wrapper used py-3, plus the right-pane <section> had pt-2 and the thread-list header had py-2 — the stacked top whitespace produced a visible gap above the first row against the titlebar. The ActivityTitlebarControls bar already provides the breathing-room band. Drop the wrapper's top padding (py-3 → pb-3), drop the right-pane section's pt-2, and tighten the thread-list header to pt-1.5 pb-2 so the WORKTREES label aligns with the right-pane worktree title row. Co-authored-by: Orca <help@stably.ai> * fix(activity): make event row the click target for navigate + ack The inline "Jump to agent" button only rendered when agentAlive was true, so retained-done rows had no jump affordance, and in compact mode it was hover-only. Users naturally click anywhere on the row expecting it to navigate. Move the navigate-and-ack logic onto the row's onClick (with role, tabIndex, and Enter/Space keyboard support) and drop the inline buttons. Per the design doc (option 1), drop the agentAlive gate entirely: activateAndRevealWorktree is safe unconditionally and activateTabAndFocusPane silently no-ops on a missing tab id, so a stale-tab click is a soft no-op. Mirror the same pattern on WorktreeEventRow so clicking a "Worktree created" row navigates to that worktree. Co-authored-by: Orca <help@stably.ai> * fix(activity): bell glyph for unread + larger row state icon The unread mini-dot stacked on the AgentStateDot competed with the dot itself for the eye and read like a status badge on the agent state. Replace it with a small BellDot glyph at the icon's top-right corner so the unread cue rhymes with the bell button on ThreadRow — one unread vocabulary across both surfaces. While here, bump the row state icon to a new 'lg' AgentStateDot size (18px) so the green check sits center-of-mass in its 32px column instead of floating small and high. Bump the WorktreeEventRow Plus glyph to match. Co-authored-by: Orca <help@stably.ai> * fix(activity): drop left padding so thread list reaches the window edge The page wrapper used px-4, which left a 16px gap to the left of the thread list — visually inconsistent with how sidebars abut the window chrome elsewhere. Switch to pr-4 (keep right padding for the right pane). Inner thread-list and right-pane padding remain unchanged. Co-authored-by: Orca <help@stably.ai> * fix(activity): use left-edge bar for unread instead of an icon overlay Mini-dot and bell-glyph attempts both crowded the AgentStateDot/Plus icon column. Switch to the same left-edge primary bar that ThreadRow already uses for unread — a row-level cue keeps the icon column clean and unifies the unread vocabulary across both panes. Co-authored-by: Orca <help@stably.ai> * fix(activity): page extends to both edges, restore right-pane top padding, rename to "workspace" - Drop horizontal padding on the page wrapper (pr-4 → none) so the thread list reaches the left edge and the right pane reaches the right edge — matches how sidebars abut the chrome elsewhere. - Restore a small top padding (pt-2) on the right-pane title row so the workspace heading isn't pinned to the titlebar. Earlier Fix 2 over-corrected by removing it entirely. - Rename user-facing "Worktree(s)" → "Workspace(s)" (column label, event title "Worktree created", description copy, "Jump to worktree" button, empty state). Internal identifiers stay as worktree* since that's the data-model name. Co-authored-by: Orca <help@stably.ai> * fix(activity): remove redundant "Jump to workspace" header button Clicking any event row already calls markThreadRead + activateAndRevealWorktree (plus a tab focus, so it's a strict superset of what the header button did). The button's only unique behavior was "go to the workspace without picking a tab" — thin justification when the latest event is one row down. cursor-pointer + hover already signal that rows are clickable. Co-authored-by: Orca <help@stably.ai> * fix(activity): wrap agent summary instead of truncating The summary line used 'truncate' with a max-width, hiding the rest of the agent's message behind an ellipsis. The Activity page is meant to let users scan what each agent said without leaving the surface, so truncation defeats its purpose. Switch to break-words + whitespace-pre-wrap so the full message renders and multi-line output keeps its line breaks. Co-authored-by: Orca <help@stably.ai> * fix(activity): clamp agent summary to 3 lines Showing the full message made tall rows for chatty agents. Cap at 3 lines (line-clamp-3) — long enough to convey what happened, short enough that rows stay scannable. Users open the workspace if they want the full transcript. Co-authored-by: Orca <help@stably.ai> * feat(activity): switch left list from workspaces to agent panes Restructure the activity feed so each thread is one *agent pane* (a terminal tab + pane id) rather than one workspace. Internal model goes from WorktreeThread → AgentPaneThread keyed on paneKey. Renderer changes: - Left list: each row shows the pane title (with agent icon + repo badge), then the workspace name as secondary context. Section label changes "Workspaces" → "Agents". - Right pane: header shows the pane title, agent icon, repo badge, and the workspace name beneath. Drops the Today/Yesterday/Earlier day grouping per design — the relative timestamp on each row is enough orientation, and a flat chronological list scans more cleanly. - Drops the workspace-created event kind entirely (and the WorktreeEventRow + ActivityRow union dispatcher), since the surface is now strictly agent activity. Side effects: - Mark-read no longer needs the locallyReadEventIds layer or the worktree-unread store calls (markWorktreeUnread/clearWorktreeUnread). Acknowledge by paneKey is the only persistence path. - Removes Plus and groupForTimestamp (unused after the refactor). Co-authored-by: Orca <help@stably.ai> * feat(activity): label panes like the per-workspace agents dropdown Pane labels now follow the same hierarchy DashboardAgentRow uses inside the WorktreeCardAgents dropdown: customTitle (user rename) > non-default OSC title > last prompt > defaultTitle / "Terminal" The prompt fallback is the important one — agents that haven't been renamed and don't set an OSC title now render with what the user asked the agent to do (e.g. "Fix the unread dot alignment") instead of the generic "Terminal 1" placeholder. Matches the visual + naming pattern on each workspace card so the activity page reads as a flat-feed extension of that surface. Co-authored-by: Orca <help@stably.ai> * fix(activity): smaller titles, allow 2-line prompt clamp Long prompts were getting truncated at one line, hiding most of the ask. Switch the thread row title from truncate to line-clamp-2, with break-words so long words wrap, and tighten size to text-[13px] + leading-snug so two clamped lines don't dominate the row vertically. Anchor the agent icon to the first line via items-start + pt-[3px]. Right-pane heading drops text-base → text-sm to match. Co-authored-by: Orca <help@stably.ai> * fix(activity): right-pane title gets the same 2-line clamp + smaller size Mirror the ThreadRow change on the right-pane heading: line-clamp-2 + break-words + leading-snug so a long prompt title shows two lines instead of a single-line ellipsis. The repo badge moves down to the secondary line (next to the workspace name) so it doesn't shift with the title height. Co-authored-by: Orca <help@stably.ai> * fix(activity): match WorktreeCard's selected/hover/unread cues Three stacked tints (selected + unread row tint + hover) made an unread hovered row look identical to a selected row, and hover even fought selected. Mirror WorktreeCard: - selected → solid black/white tint + faint shadow, hover suppressed (the active class wins so the row stays visually fixed) - non-selected → only then does hover apply (bg-accent/40) - unread → weight + left-edge primary bar carry the cue; row tint removed (matches WorktreeCard's "weight alone carries the unread signal") Co-authored-by: Orca <help@stably.ai> * feat(activity): portal selected agent terminal Co-authored-by: Orca <help@stably.ai> * fix(activity): keep completed entries after terminal input Co-authored-by: Orca <help@stably.ai> * fix(activity): tighten portal target, unread count, and selection edges - activity-terminal-portal: replace document.body MutationObserver with a module-level pub/sub registry; the page publishes the target via a ref callback, Terminal subscribes. Removes body-wide DOM observation. - Terminal: memoize activityTerminalPortal so WorktreeSplitSurface's React.memo bail-out is preserved across unrelated Terminal re-renders. - ActivityPrototypePage: cap events per-pane (5) so a chatty pane can't push quiet panes off the left list; render an empty-state when a retained thread's tab is gone; skip workspace mutation in activateThreadTerminal when the tab is no longer live; keep the selected thread visible in unread-only mode after auto-mark-read. - ActivityTitlebarControls: walk stateHistory in the unread accumulator (mirrors the new feed semantics); drop worktree-created counting since the new feed has no surface to dismiss them. - AgentStateDot: remove the dead 'lg' size variant. - App: hide worktree sidebar on the Activity view and include it in the back/forward shortcut + button cluster. Co-authored-by: Orca <help@stably.ai> * fix(activity): double-buffer portal slots to remove cold-mount flash Switching threads on the Activity page used to expose xterm's empty canvas for ~133ms while a newly-mounted TerminalPane attached. Replace the single portal target with a double-buffered set of slots: keep the previously displayed terminal visible while the next selected terminal mounts in an invisible same-size slot, then flip slots once the staged slot contains the selected terminal DOM with xterm's screen and PTY binding (with one extra frame only after observing an empty mount). Skips publishing a portal target when the selected retained thread no longer has a live tab so the previous tab's target doesn't linger. Co-authored-by: Orca <help@stably.ai> * fix(activity): remove single-option Display style settings dropdown The activity page's gear menu only held a "Compact list" toggle. Drop the dropdown along with the leftSidebarCompact state, the ActivityDensity type, and the unused dropdown-menu / Settings imports. The thread list keeps the compact layout (the previous default). Co-authored-by: Orca <help@stably.ai> * fix(activity): vertically center Jump to workspace button The header row uses items-start so a 2-line prompt clamps without the badge jumping. self-center on the button overrides that just for the action so it sits in the middle of the title block instead of pinned to the top edge. Co-authored-by: Orca <help@stably.ai> * fix(activity): prefer prompt over OSC live title for thread label paneTitleForEvent put the non-default tab.title ahead of the prompt, so agent CLIs that set "Claude Code" / "Codex" via OSC pinned every row and the right-pane heading to the agent name. The dashboard row this function claims to mirror uses the prompt directly. Re-order to: customTitle (explicit rename) → prompt → non-default liveTitle → defaultTitle, so sending "hi" actually shows "hi" in the title. Co-authored-by: Orca <help@stably.ai> * fix(activity): drop extra row height when prompt is one line The thread row's right column stacked time over the count badge with a gap, which forced the row to ~48px even when the left column's prompt was a single line. Collapse the right column into one horizontal cluster (count + time/bell) so single-line rows stay tight, while two-line prompts still drive the row taller as before. Co-authored-by: Orca <help@stably.ai> * fix(activity): add top/bottom padding to thread rows Bump py-1.5 → py-2.5 so single-line rows breathe and don't sit flush against the row dividers. Co-authored-by: Orca <help@stably.ai> * fix(activity): even out optical row padding (top read heavier than bottom) Symmetric py-2.5 looked top-heavy because the title's leading-snug adds internal whitespace above the cap-height that the secondary row doesn't have below it. Trim the top to pt-2 / pb-2.5 so the row reads balanced. 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
Autohand Code
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] View Live Status of All Agents
See what every agent is doing — at a glance.
Track the live status of every agent across every worktree from one place. Spot which agents are working, waiting on input, or done — without clicking through tabs.
[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.
- 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.




