Jinwoo Hong e736a9f29b feat(mobile): take the session screen's inputs, links, clipboard and routers through the platform seams (OTA phase C, C7.2) (#21790)
* feat(mobile): put the session screen's nine text inputs on the web font seam (OTA phase C, C7.2)

The landed text-input census, run over `app/h/[hostId]/session/[worktreeId].tsx`,
reports nine sizes that do not come from `TEXT_INPUT_FONT_SIZE`. Six declare the
app's body size and move in place, which is the same number natively. Three do
not — a 22px key-capture field and the chat's two 15px fields — so each gets a
`.web.ts` sibling of the address bar's shape, with a shared base so the two
halves can differ in nothing but the size.

The capture field is the one the move shrinks rather than raises: 22 already
clears the focus-zoom floor, and the census reads the seam as a binding rather
than as a number, so there is no expression that keeps 22 and still says where
the size came from.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* fix(mobile): drop the theme import the composer's style split left behind

`oxlint` over the whole tree, which CI runs, reads it as an error.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* feat(mobile): open the session screen's three external URLs through the platform seam (OTA phase C, C7.2)

The landed external-link census, run over the session route's closure, reports
three modules reaching react-native's `Linking`: a terminal link tap whose open
mode is the phone's browser, and the two WebView-backed readers, each of which
sends a tapped link to the system browser rather than navigating the artifact
away.

Inside the shell `Linking.openURL` calls `window.open`, which both shells refuse
and which resolves either way, so all three reported success into a tap that did
nothing. The seam also stops swallowing the failure: each site caught and
discarded, and `openExternalLink` names it.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* feat(mobile): take the session screen's seven clipboard sites through the platform seam (OTA phase C, C7.2)

`expo-clipboard` resolves to `navigator.clipboard` on the web, which needs a
secure context — iOS serves the page from a custom scheme and Android from
`https`, so that path works on one platform and silently not on the other. The
landed census now reports the module out of the route's closure entirely.

The seam grows its reader half, on the landed `native.clipboard.read` verb: text,
a PNG, and a presence probe. Two degradations are recorded rather than implied.
No shell serves an image, so the page answers null and the terminal's paste takes
the branch an empty clipboard already took; and the shell serves no presence verb,
so `contents` answers what this side knows rather than reading to find out, which
would raise iOS's paste-consent prompt on every foreground.

The copy-path sheet gains the failure toast its two neighbours already had: it
showed "Path copied" before the write, and the seam rejects rather than returning
false.

The route parity pin moves with it: five clipboard hooks join the expanded route
and one runtime string joins the sheet.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* feat(mobile): take the session domain's three routers through the handoff seam (OTA phase C, C7.2)

Inside the page a screen is one document standing in for one screen, and
`useRouteHandoff` is the only thing that knows which targets the page keeps and
which it hands back to the app. The three holders here are the workspace-missing
bounce, the file-tap preview push, and the pane-tap param consume.

The domain's census is narrower than the two landed ones because it has to be:
eight of its hooks take `useFocusEffect` and two take `useLocalSearchParams`,
neither of which can navigate, so the rule is a closed list of names rather than
a ban on any value import — which also catches expo-router's module-singleton
`router`, a spelling a `useRouter` rule would have read as clean.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* feat(mobile): list the two style siblings the session screen's inputs added (OTA phase C, C7.2)

The overrides census fails on an unlisted `.web.*`. One raises the chat's two
15px fields past the focus-zoom floor; the other lowers a 22px capture field onto
the seam, and its entry says why a reduction is the right answer there.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* feat(mobile): let the text-input census read a literal already clear of the floor (OTA phase C, C7.2, ruling 12)

The floor is the rule and the seam is the mechanism. A binding rule alone made
the custom-key capture field an offender at 22, where nothing can zoom, and the
only way to satisfy it was to lower a one-character field to 16 — the tail
wagging the dog.

The seam's web half now exports the floor it already computed `Math.max` against,
and the census reads that number out of that file rather than carrying a second
copy of 16. The rule becomes "the seam's binding, or a literal at or above the
floor", with no per-site exemption: a literal under the floor is still reported,
which is the case the seam exists for. A tree whose seam declares no floor is
refused rather than judged against a number the census invented.

So the capture field goes back to 22 on both platforms and its split, its
override entry and its parity test go with it. The chat's two fields stay split,
because 15 is under the floor however it is spelled.

Red-first: with the rule removed, a planted literal 16 and a literal 22 are both
reported and the refusal case does not throw; a literal 15 is reported either
way. All three route closures that run this census — session, source-control,
review — report 0 offenders and 0 unresolved.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* fix(mobile): answer clipboard reads on the read grant and catch refused writes

`contents()` reported no text on a route that granted `native.clipboard.read`
without the write, because it read `verbs.granted`, which is write AND read. The
verbs hook now exposes the two grants separately and the web seam answers on the
read one; `granted` keeps its meaning for the callers that need both.

The Markdown copy action was the one write of eight in the session domain with
nowhere for a rejection to go: the seam rejects when the pasteboard refused the
text, the callback had no failure branch, and its caller drops the promise, so a
refused write raised an unhandled rejection and still left "Copied" on screen. It
now takes the error haptic and the "Couldn't copy" toast the other copy paths
show. A census over `src/session` fails if any `writeText` call site lacks a
failure branch, so the ninth site cannot arrive without one.

The route parity pin moves with it: one callback body, one runtime string. Its
refresh note claimed six clipboard hook sites for a delta of five; the walk from
`SessionScreen` reaches five, and the terminal's paste is not among them.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* fix(mobile): probe both clipboard kinds at once and judge sizes against the floor

Moving the two clipboard probes into an object literal serialised them: the
migrated `contents()` awaited `hasStringAsync` before `hasImageAsync` was called,
where both callers had used `Promise.all`. That path runs on mount, on every
AppState foreground and on every select-mode toggle. Restored, with an ordering
probe that deadlocks unless both probes start before either answers.

The floor case could not fail for the reason it named: its fixture declared 16,
so a census carrying its own copy of 16 passed it. It now plants a seam declaring
20 and a literal 18, the size that is clean under one floor and an offence under
the other.

Two stale wordings from the reverted split: one closure case still said "both
split style modules" over a one-element list.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* fix(mobile): buzz the quick-command row when a copy is refused

The last of the seven migrated writes without the error haptic. The row already
said "Couldn't copy" on its own control, in red, for the 1500 ms the toast the
other six show would have lasted, so it never claimed a refused write had landed;
what it had no way to say was anything the thumb still on the button could feel.

Its first test, on the harness its list already uses: the seam rejects when the
pasteboard refuses, and the two cases are the difference between the row that
shows a green check over nothing copied and the row that does not. The list's own
test gains the haptics mock the row's new import needs.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* fix(mobile): make the clipboard census require the await its rule depends on

`hasFailureBranch` accepted any enclosing `try` with a `catch`, so the one shape
the census exists to stop passed it: `void clipboard.writeText(...)` inside a
try/catch is an unhandled rejection with a handler three lines above it that can
never run, because the block returns before the promise settles. It now requires
the call to be awaited inside the try's own block, or to carry a `.catch` along
its own chain. The boundary walk stopped only at function and method
declarations, so a `catch` outside an arrow answered for the call left running
inside it; every function-like node ends the search now.

Five cases over snippets read through the same reader, because a `void` write
would have to be committed to be tested against the real tree. Control on a real
site: making the Markdown write un-awaited inside its own try reports it.

Two provenance fixes. The runtime-string delta across C7.2 is two literals, not
one: "Couldn't copy path" took the count from 532 to 533 and "Couldn't copy" took
it to 534. And main's C7.4 made `BRIDGE_CLIPBOARD_MIMES` `['text']`, so an image
mime is a value the schema does not admit rather than a refusal the verb spells
out, with `native.media.pick { source: 'clipboard' }` waiting on C7.6; the web
seam and its test said otherwise. Behaviour unchanged.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* fix(mobile): let an unmounted quick-command row emit nothing on a refusal

The haptic I added ran before the mounted guard, so a copy pressed on a row that
then scrolled out of the list, or a sheet closed over it, still buzzed when the
rejection arrived. A buzz with no row to explain it is feedback for nothing, and
the guard was already there for the feedback state one line below.

Red-first: press, unmount, then reject. The success path already guarded first.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb

* fix(mobile): make the clipboard census require a catch with something in it

Any `.catch` property access counted as a failure branch, so two shapes that
handle nothing passed: `clipboard.writeText(text).catch` reads the handler's name
and registers nothing, and `.catch()` swallows the rejection while the caller goes
on to say the write landed. The rule now requires `.catch` to be the callee of a
call carrying at least one argument.

Red-first with both shapes in the snippet reader, the accepting cases unchanged.
Control on the real tree: emptying the notes sheet's handler reports
`MobileSessionSheets.tsx:174`, and restoring it greens.

Claude-Session: https://claude.ai/code/session_01JNnE9qzUZMMnqpZWCqM3nb
2026-09-20 09:49:59 -04: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 · TestFlight · Android APK 0.0.50 · 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: Scan to join the Orca community WeChat group 8. Group 8 may be full; if so, scan the Group 9 QR code instead.

    WeChat group 8 QR code for the Orca community  WeChat group 9 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.5 GiB
Languages
TypeScript 95.2%
JavaScript 4%
Swift 0.2%
CSS 0.2%
HCL 0.1%