Brennan Benson dd39dcba5f feat(orchestration): a native chat gets the orchestration pointer a CLI agent gets, through the same send as your messages (#25078)
* feat(orchestration): agent mail to a busy chat waits in the chat's own queue

A mail notice for a busy structured chat used to wait in the orchestration lane's
own invisible "until the chat is free" gate. It now goes through the queue a
person's message uses: sendAgentTurn(..., { delivery: 'queue', source }) makes
the host hold it as a draft card the person sees and can Steer or delete, and
the queue sends it when the turn ends.

- The lane's busy gate (turnRunning / awaitingHuman) is gone; the queue's own
  hold decides. Its parking now only waits for its own send or card to settle.
- A queued card's hand-off (sent under a fresh id) is matched by
  queuedMessageId, so it stamps the mail once and never sends a second notice.
- A card from before an Orca restart is still the lane's: no second card.
- A card the person deleted counts as handled for that batch; newer mail
  notifies again. No stored flag: read off the card and delivered_at.
- `orchestration check` waits for the lane to withdraw a card whose mail it
  read, so a stale notice is never sent; more mail replaces the card.
- Each card records who queued it in queued_messages.source_json (versioned,
  schema-validated): the person, or Orca for agents, with every distinct
  sender as an orchestration party plus host id, and the mailbox, dispatch,
  run and message ids. The restart pause holds only the person's cards.
- sendAgentTurn answers with a snapshot, not the journal's live submission.

* test(orchestration): type the mail fixture as a pointer batch message

* fix(orchestration): the queue judges an agent's mail notice as it sends it

A mail notice queued in a busy chat could go out stale or twice: it was
kept true from outside the queue, by orchestration check withdrawing it,
which missed other readers, raced an attempt in flight, lost the card
when /clear carried it (a second notice), and moved it to the back when
new mail replaced it. An agent's card behind a person's paused card never
sent after a restart, so an unattended coordinator stalled.

- The drain asks the card's sender, in its own serialized step, whether
  it still stands: send, restate (count and senders of the mail owed
  now, written onto the card in the hand-off's transaction), or withdraw
  as the host. A failing judge sends as written. Send-now restates but
  never withdraws. Orchestration registers the judge on the host.
- check no longer touches any queue (back to main); onMailRead,
  notifyOrchestrationMailRead and the lane's withdrawals are gone.
- One unsettled card per agent message, enforced at insert; new mail is
  counted when the card sends, never replaces or moves it.
- The lane finds its card by what it is (a notice for the mailbox in the
  session the mailbox reaches now); a decline is a withdrawal a person's
  operation stamped. /clear moves agent cards as the host. Pointer rows
  last only while a direct send is in flight and end with the session.
- Pauses (restart, Stop, /clear) hold only a person's cards, and a held
  card never traps an agent's card behind it, keyed on the message kind.
- The source is named for the message (agent-session-message-source),
  one payload shape per message kind, no relative host id.

* fix(orchestration): Orca's mail notice waits in the queue out of sight

The notice card read as something the person typed and came and went on
its own, the transient-state message the queue should not show. It is
hidden until B can label who sent it.

- The host leaves mail-notice cards out of the published queue, so the
  list, its count, Steer/Delete/Edit, steer-newest and the paused header
  never see them, on every client. Keyed on the message kind: D6's task
  card will be shown, labelled, in B. They still count toward the queue
  limit (temporary, until B).
- A refusal no longer returns a hidden card for the person to act on:
  the host withdraws it, and the lane points again only after a turn ran
  since, the rule it already had for a refused notice.
- Send-now no longer restates a card: no one can reach a hidden one.
- The stored sender drops the pane key, a mailbox credential.
- The gate covers an abandoned worker: a mailbox that reaches no session
  withdraws its notice (tested).

* fix(orchestration): a hidden mail notice never waits on the person

Hiding the notice left three paths where it waited on someone who
cannot see it.

- A failed hand-off write put a send_failed hold on it, which only a
  person's Send or Delete clears: that mailbox's notices stopped for
  good. The host now withdraws a hidden card instead and hands its
  mailbox back to the lane through the ordinary redrive, since an idle
  chat gets no other edge. A write that keeps failing is retried once
  per edge.
- A person's Stop while the agent started on the notice put it back to
  waiting, where no pause holds it, so it was sent again at once. The
  host now withdraws it; the lane points again after a turn ran or when
  newer mail makes it a different notice, as on main. A restart still
  puts it back.
- A notice queued before the person's message went first. One order
  rule now: the person's cards go in order and never past one waiting
  on them; a card they cannot see never delays one they can, and goes
  only when none of theirs may.

The drain moves to its own module (structured-agent-session-queued-
drain.ts). Comments that still described the notice as visible are
corrected.

* fix(orchestration): an accepted notice hand-off stamps its mail; a judge that cannot look decides nothing

- When the agent opened its mail in the notice's own turn (the normal
  flow), an open batch left nothing owed, so the lane never marked the
  mail the accepted hand-off carried as delivered, unlike an accepted
  direct send. The lane now stamps exactly the ids a handed-off notice
  carried whenever undelivered mail remains, owed or not. A later
  conversation is no longer told again about mail already opened.
- At quit the host registry is cleared before teardown, so the drain's
  judge could not resolve the mailbox and withdrew the notice. A judge
  that cannot read its inputs now defers: the card waits for a step
  that can look. A mailbox that resolves to another session or none is
  still withdrawn.
- The judge, the owed-batch selection and the notice body move to
  structured-mail-notice.ts. A failing hand-back of a dropped card is
  logged.

* refactor(orchestration): a chat receives the agent's mail itself, queued like a person's message

A structured chat used to get a derived "You have N orchestration messages,
run check" notice, which could go stale while it waited in the chat's queue,
so the queue judged, restated or withdrew it as it sent. It now gets the mail
itself as the turn, through sendAgentTurn with delivery 'queue', the path a
person's message takes.

- One turn per mailbox batch: the mailbox's unread mail at delivery, in mail
  order, each message led by "[message from <sender>]", its type, subject,
  body, payload and reply hint (what check prints). Mail arriving while that
  card is still in the queue waits for the next card; a card is never edited.
- An idle chat takes it at once; a busy one queues it as an ordinary card the
  person sees and can Steer or delete. Mail is marked read when the chat
  accepts the turn, so check does not return it again; a deleted card leaves
  its mail unread for check, and it is not pushed again.
- The card stores who it is from (source_json): every distinct sender, and
  each message's id, run and sender. Kind 'mail-notice' becomes 'mail'.
- Removed: the send-time judge (QueuedAgentCardVerdict), structured-mail-
  notice, structured-pointer-notice-cards, queued-message-restatement, the
  hidden-card rules, the agent-card exemptions from the restart, Stop and
  /clear pauses, the dropped-card hand-back, and the drain split. An agent's
  card now follows the same pauses as a person's.
- Terminal agents are unchanged: they keep the typed pointer and check.

* fix(orchestration): a chat's check skips mail already queued to it; restarts hold only the person's cards

- When a structured chat runs `orchestration check` (consuming, --peek or
  --wait), mail an agent's card in that chat's own queue still carries
  (any card not deleted) is left out: it is on its way as a turn, so the
  agent does not read it twice. Derived from the queued rows at read time;
  a deleted card no longer carries it, so it comes back. Terminal callers
  and every other read are unchanged. New batches pass the exclusion to
  getOrCreateMailboxDelivery; peeks filter it.
- A restart's queue pause now holds only the person's cards: an unattended
  coordinator's agent card sends after an app restart without waiting for a
  Resume, since the mailbox is the record and reading is marked. Stop and
  /clear still hold agent cards. One rule, in queuePauseHolding. An agent
  card queued behind the person's held card still waits behind it: the
  queue never reorders.
- The duplicated direct-mailbox snapshot routing in check-run and
  check-worker becomes one helper, which keeps check-worker under its line
  limit.

* fix(orchestration): the mailbox is the only record of read mail; a chat's check takes its waiting cards

A card held an exclusive claim on its mail that nothing reconciled with the
mailbox: queueing it stamped the mail delivered, and a chat's check hid every
card that was not deleted. So a chat's own check --wait in one turn could not
see a result its waiting card held, a hand-off that ended in doubt or came back
"Not sent" stranded its mail, a check racing the card's build read the mail
twice, and a card left behind by run-use still sent and marked it read.

What a card or send holds is now derived each time from the chat's queue and
its sends: an accepted send marks its mail read; a waiting card or an
unanswered send holds its mail; everything else unread is pushed again or
returned by check. A card the person deleted is recorded as not to be pushed,
at the delete. The lane withdraws returned, partly read and moved cards. A
chat's consuming check withdraws the waiting cards holding what it reads, one
at a time with the lane. The sender is stored on the sent submission too
(host-only), so read state survives the card row's prune. A refusal before
anything started ends its operation; a restart pause is raised only by the
person's cards; an unreadable agent source stays an agent's.

* refactor(orchestration): a chat gets the pointer a terminal agent gets, sent through the chat's own queue

A structured chat now receives exactly what a terminal agent is typed: "You have N orchestration
messages ... run `orca orchestration check`" (formatMessagePointer, same CLI name). It goes
through the shared sendAgentTurn with delivery 'queue', the composer's queue-if-active: an idle
chat gets it at once, a busy chat's queue holds it as a normal card and sends it when the turn
ends. The lane's idle gate is gone; the send decides, as for the person's message.

The lane queues no second pointer while one of its cards still waits, read from the queued rows;
mail arriving meanwhile, or after the card is sent, is pointed again as the terminal lane points
new unread mail. A queued pointer counts as delivered, as an accepted one does. `check` and mail
read state are main's: only `check` reads mail.

The card records who it is from (queued_messages.source_json, kind 'agent', message
'mail-notice', with its senders) for the next PR to render. A restart's pause is raised by and
holds only the person's cards; Stop and /clear still hold an agent's.

Removed from the earlier designs: the message-as-turn batching, the check exclusion and taking,
the derived claims, lock and reconciliation, the sender on submissions, and their tests.

* fix(orchestration): a chat's pointer follows a card that leaves its queue unsent

The lane holds new mail while a pointer card waits, and retried it only on the chat's next
status change. A card that leaves the queue without a turn after it (the person deletes it
while Stop holds it, or its hand-off comes back) made none, so that mail sat unpointed until
something unrelated happened. The shared queue wiring now tells its host when an agent's card
stops waiting, read only when the queue changed, and the runtime redrives that chat's parked
mail. The runtime forwards the new host dep like the others.

Tests: that case end to end, and /clear carrying an agent card keeps who it is from. Agent card
bodies in tests are the pointer text; the restart pause's header says why an agent card may send.

* refactor(orchestration): no special handling for agent notices in the chat queue

A structured chat's orchestration notice is now sent through the chat's own send
like any message: an idle chat takes it as a turn, a busy chat's queue holds it
and sends it at turn end, under the same Stop, restart and /clear pauses as the
person's cards. Native chat no longer branches on who a card is from; the card
only records it.

- Restore main's queue pause logic (no restart exemption for agent cards).
- Remove the queue watch that redrove mail when an agent card left the queue,
  and the host's queued-row read the lane used for it.
- The lane reads nothing of the chat's queue. It sends no second notice while
  mail it already pointed at is unread, read off the mailbox alone.

* fix(orchestration): point new mail like a terminal, even while earlier pointed mail is unread

Drops the native-chat-only rule that held back a notice while the agent had not yet read mail it
was already pointed at. Also fixes main's stop-note test, which still built a provider handle in
the shape #24991 replaced.

* test(native-chat): keep the queued-message rig fixture under the line limit

* fix(test): drop main's duplicate codexProviderHandle import (same line as #25713)
2026-10-05 17:34:06 -07:00
2026-09-26 20:50:46 +00:00
2026-05-04 20:42:03 -07:00
2026-03-16 22:27:51 -07:00
2026-03-28 10:19:14 -07:00

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 · Android APK 0.0.52 · 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   Muse logo Muse   DeepSeek Harness logo DeepSeek Harness   ZCode logo ZCode   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   CodeBuddy logo CodeBuddy   Codebuff logo Codebuff   Freebuff logo Freebuff   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: Scan to join the Orca community WeChat group 11.

    WeChat group 11 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.

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.

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.

S
Description
Orca is the ADE for working with a fleet of parallel agents. Run any coding agent with your own subscription. Available on desktop, mobile and remote runtime.
Readme MIT
1.8 GiB
Languages
TypeScript 95.2%
JavaScript 4.1%
Swift 0.2%
HCL 0.1%
CSS 0.1%