W10 wake-visibility P1s. stderr '- …' lines (NDJSON phase events with
--progress json; --json defaults to none; stdout keeps only the result):
- wake: 'Waking <ws>...', one 'Still waking (Ns)…' line at 10 s,
'<name> is awake (took Ns).', or, when the API answers still waking
after its wait, '<name> is still waking. Check with: …' (exit 0, status
waking kept in the result)
- sleep: 'Putting <ws> to sleep...' / '<name> is asleep (took Ns).'
- worktree create --on cloud: 'Still starting (Ns)…' at 10 s and
'Workspace <id> is running (took Ns).'
Lifecycle handler moved to cloud-lifecycle.ts; shared helper cloud-progress.ts.
* feat(cli,sandbox-control): orca repo add --display-name; cloud sandboxes name the project after its repository
The VM checkout lives at /vercel/sandbox/project, so boot-time registration (#104) named the repo
'project'. repo.add already accepts displayName; the CLI now exposes it as --display-name and
orca-sandbox-start passes the repository basename from ORCA_REPO_URL.
* fix(sandbox-control): golden builder polls detached builds with a bounded wait=true read; image-only merges trigger a rebuild
The provider reports a detached command's exit code only to a wait=true read (W1's finding, #123):
stepBuild's plain GET is what kept finished golden builds 'running' until the deadline. stepBuild and
the operator rotation now use the same bounded wait probe (4 s); the exit-file marker stays as a
fallback. golden-source's VM path list now includes cloud/apps/sandbox-control/image/ (VM scripts,
provision, manifest), so a script-only merge (e.g. orca-desktop-proxy) rebuilds the golden too.
worker-start defaulted --setup to run, so new worker worktrees ran the
setup script even when the project had setup turned off. Without an
explicit --setup, a worker now skips setup when the project skips it by
default; run-by-default and ask keep running it as before. Remote
workers resolve this on the host that owns the project.
Turning in-workspace CLI access off revokes every workspace token, so the
in-VM CLI sees 401, not 403 vm_cli_disabled. Say so and point at the
setting first (verified on a real VM).
* docs: load Orca browser guidance for ordinary web tasks
Extend the Orca CLI skill description to include local and external page opening, reading, testing, and captures while working in Orca. Preserve explicitly chosen browser tools and the Computer Use boundary. Regenerate discovery/install bytes and append the new digest.
Fixes#39880
* fix: route existing Edge windows to desktop browser control
* docs: preserve configured desktop-control tool precedence
* docs(skills): scope orca-cli browser trigger to page work and keep the Computer Use rule
Drop "reading" so doc lookups stay on fetch tools, say plain HTTP/API calls don't need the skill, and restore the original Computer Use sentence and guide body, which the issue didn't ask to change.
* docs(skills): list Edge among existing browser windows in the orca-cli guide
The wider page trigger makes "screenshot my open Edge tab" load orca-cli, and the guide named only Chrome and Safari as windows that go to desktop control.
---------
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
Workspace tokens tell the in-VM orca cloud CLI to call publicOrigin(env), but
that host was only reachable when EGRESS_EXTRA_HOSTS listed it (previews did,
the dev Worker did not), so every in-VM call failed with 'fetch failed'.
extraEgressHostsFor(env) now always adds the public API host. The CLI's
cloud_unreachable hint inside a VM names the egress allowlist.
- drop the duplicate 'cloud' launch root (cloud env already registers it)
- keep cloud env on the runtime: only the cloud API commands ignore --environment
- list cloud messages in root help
- register the 'sender' launch root (parity test was red on integration)
Private build. Talks HTTPS to the Orca Cloud public API, never to the Orca
runtime, so it works inside a VM with no desktop app. Credentials:
ORCA_CLOUD_TOKEN (+ ORCA_CLOUD_API_URL) -> ~/.config/orca-cloud/credentials.json
(written at boot in VMs when vmCliEnabled, or by orca cloud login, 0600).
--json prints { ok, schemaVersion: 1, result }; API failures map to stable
cloud_* codes with next steps (vm_cli_disabled, own_workspace, scopes, 401).
* feat(orchestration): mail agents on a paired server with send --on, replies come back by themselves
* fix(orchestration): gate --on on the carrying Orca, ack retried deliveries, refuse payloads and federated workers
* chore(orchestration): annotate peer-mail row casts and drop a wall-clock wait in its test
* chore(orchestration): name mail-between-servers codes server_mail_unsupported and mail_requires_server_pairing
* docs(cli): list --on in the orchestration reply usage
* fix(orchestration): name --environment, the flag on main, in agent mail refusals and the guide
* chore(orchestration): mark the two deliberate agent-kind branches mail between servers needs
* docs(cli): leave --on out of the reply usage; it is accepted only to refuse it
* fix(orchestration): keep peer conversations to peer ids, survive resets and re-pairs, keep pulling on a registry error
- A server takes only peerconv_ conversation ids, so a paired computer cannot name another Orca's dispatch in the relay.
- A replayed reply after a mail reset is acknowledged, not retried forever; reset tasks keeps replies waiting to be pulled.
- A re-paired server starts a new conversation instead of refusing every later send and reply.
- A failed registry read keeps the pull loop retrying.
- Drop the two ast-grep-ignore lines that only #40193's rule needed.
* fix(orchestration): worker-start --on runs on the caller's own Orca, like send --on
An inherited ORCA_ENVIRONMENT sent worker-start --on to that server, so the
--on command the agent refusal suggests did not work. One rule now keeps
send, reply and worker-start with --on on the caller's own Orca.
* fix(orchestration): refuse reply --on on both sides of a conversation between servers
The side that opened the conversation still took --on when it named the right
server; the reply usage says --on is accepted only to refuse it.
transcribe-cpp is now the only on-device engine on every platform, so
the sherpa-onnx packages, their packaging (extraResources, the darwin
libonnxruntime prune, the native-variant assert and the Linux libstdc++
exemption), the sherpa recognizer in the speech process and the
per-model engine choice all go. Hotwords are written as plain terms.
* feat(speech): run GGUF models on transcribe-cpp, falling back to the CPU
The speech host child can now load a second engine. A model whose files
are GGUF runs on transcribe-cpp (Metal on Apple silicon, Vulkan on
Windows and Linux, CPU otherwise); everything else stays on sherpa-onnx,
which remains the only engine on Intel Macs.
A GPU that fails to load, errors, stalls for 25 s or crashes the process
moves the dictation to a CPU-only process (TRANSCRIBE_BACKENDS=cpu) that
replays the audio the GPU had not decoded yet, so no words are lost or
repeated. A GPU that crashed or would not load is remembered per
transcribe-cpp version and OS release, and voice.speechGpu = 'off' keeps
it on the CPU.
Packaging copies transcribe-cpp, koffi and the target's native package
into resources/node_modules outside asar, fails when a target's package
is missing, and ships the MSVC runtime beside transcribe.dll on Windows.
No catalog model is GGUF yet, so nothing runs on transcribe-cpp until
the catalog change that follows.
* fix(speech): keep the speech queue running after a failed task, and drop audio frames after a discard
* fix(speech): keep the engine's file reads off the main thread's hot paths
The engine lookup and the GPU failure marker are read once per process
instead of on every dictation start and mobile catalog request, the marker
is written asynchronously, and the child reads the hotwords file with
fs/promises. The baseline moves the existing engine presence checks from
stt-worker-paths to the shared package table and adds the once-per-process
marker reads.
## W4: team collaboration on Orca Cloud workspaces
### Control plane (`cloud/apps/sandbox-control`)
- **Registry** (`0024_workspace_registry.sql`, applied on dev D1): owner (reassignable), `created_by`, branch, `visibility` (private default / team), section, last activity, token spend. Reuses 0020's `name`/`archived_at`.
- **Routes under `/v1/team/*`** (W5 owns `/v1/workspaces`): list with Mine/Team/All, By, In, Archived filters; PATCH (rename, share or make private, section, archive, reassign owner); presence heartbeats; wake and lease for teammates; links resolve; org prompts/PR instructions (compare-and-set).
- **Security fix:** `/v1/sandboxes/:id` used to be account-scoped, so any org member could resume a teammate's sandbox and receive its orcad pairing code. It is now owner-only; admins can still suspend and destroy.
- **Per-member, per-device E2EE grants:**
- The VM mints a single-device orcad offer and seals it to the requesting device's X25519 key.
- The control plane stores only the orcad device id.
- Revocation runs `orca pair --revoke`, which closes the device's live sockets, plus an on-disk registry removal.
- When the VM is asleep, the revoke is queued and applied at boot before orcad starts.
- Triggers: explicit revoke, making a workspace private, archive, reassign, member removal (internal route), and phone device-session revoke (W8).
- VMs from older images get the entry points installed on demand.
- **Git as the sender:** a member's own GitHub user-to-server token (App OAuth, envelope-encrypted) is swapped in at egress only for the workspace repo. The VM gets per-member git configs and `orca-git-as`.
- **Cost:** metered compute × billing rate, plus optional token spend.
### orcad (generic)
- New owner-only RPC `pairing.revokeDevice` and `orca pair --revoke <device-id>`: revokes a device and closes its open connections immediately.
### Desktop
- A "Cloud workspaces" section on Home: Team/Mine, By, In and Archived filters; sections; live presence; cost; last activity. Single-click Open on a teammate workspace pairs this device through an E2EE grant. Also a row menu (share/private, move to section, reassign, archive) and copy link.
- Deep links `orca://cloud/w/<id>[/c/<chat>]` (open-url, argv, second instance, sidecar handoff) and the `cloudWorkspace.copyLink` keybinding.
- Messages to agents in shared workspaces carry a sender envelope.
- Uses the W10 shared primitives.
- Two rounds of adversarial design and frontend review.
### Evidence
Real Vercel VMs; see the W4 report. Numbers:
- grant issued in 0.55 s, paired in 1.35 s
- revoke closes the live desktop socket ~30 ms after the PATCH returns
- two members' pushes land on GitHub with their own author identities (shared dev Worker, preview alias w4); a push to another repo gets 403
* feat(cloud): SSH into Orca Cloud workspaces (orca ssh, ssh-proxy, VS Code/Cursor Remote-SSH)
- VM: unprivileged key-only sshd on 127.0.0.1:2222 (orca-sshd), host key and Orca-managed
authorized_keys on the persistent disk; orca-ssh-keys entry point; provision extracts only the
server binaries (dnf or apt, +1.5-2 MB) and unlocks the sandbox user for key logins.
- Control plane: POST/DELETE /v1/sandboxes/:id/ssh-keys runs the fixed entry point and answers
the pinned host key; editor Remote-SSH server hosts on the egress allowlist.
- Desktop: per-workspace ed25519 keys in userData (0600), Orca-owned ssh_config + pinned
known_hosts, ~/.ssh/config Include only after consent; wake -> key -> runtime port forward
(openRuntimePortForward reason 'ssh'); revoke (deferred while asleep); SSH traffic keeps the
workspace awake.
- CLI: orca ssh-proxy <workspace> (ProxyCommand) and orca ssh <workspace>.
- UI: Open in -> VS Code / Cursor over Remote SSH, SSH submenu (Copy SSH Command, Revoke),
include consent dialog, progress/error toasts.
* fix(cloud-ssh): review fixes — no agent forwarding, reinstall per VM boot, wake to revoke
- ForwardAgent/ForwardX11 no in Orca's host blocks; AllowAgentForwarding no in the VM's sshd.
- Reinstall the key (idempotent; restarts sshd, re-pins the host key) once per VM boot, so a
wiped disk, rollover or dead sshd heals on the next connection.
- Revoke wakes the VM to remove its copy; only an unreachable VM falls back to the queue.
- orca-ssh-keys rejects multi-line keys; sshd log truncated per start; audit log entries for
ssh key add/remove; state parsed per entry; % escaped in ssh_config paths; ProxyCommand pinned
to this app's profile; ssh-proxy flushes stdout before exit; --print shell-quotes; editors
open via --folder-uri with a checked path; "Remove from ~/.ssh/config" + one-time backup.
* feat(plugins): add workspace.rename and project names in workspace.list
Plugins that name workspaces had to read Orca's private runtime token and call
worktree.set over the runtime socket, bypassing capability consent. workspace.rename
(workspace:write, worker only, host API 1.5) does the same update as a sidebar
rename. workspace.list rows gain the project name so plugins can prefix names
without reading the runtime's repo list.
* fix(plugins): harden workspace.rename against twin folders and hidden characters
Folder renames require a unique folder id, so twins on two hosts are not both renamed,
and fail when no folder has the id. Names refuse C1, bidi and zero-width characters,
which could make a label read as another workspace's name.
* fix(plugins): workspace.rename matches a sidebar rename for folders and reports kept names
A folder rename also cancels a pending first-agent-message rename, so the automatic
title cannot replace the plugin's name. A rename Orca does not apply (during a WSL
move) is a conflict instead of a silent success. workspace.list's project is optional,
so mocks written for host API 1.4 still validate. More invisible characters are refused.
* refactor: move atomic publication to its filesystem owner
* refactor: group shared browser definitions by feature
* refactor: bind proxy process and session contracts to defining owners
* refactor: consolidate direct session contract type imports
* refactor: retain atomic publication test timing under moved owner
* fix(benchmark): resolve historical tunnel framing source before loading
* feat(cli): add orca vm env doctor to check a workspace environment
Checks required CLIs (git plus what the repo manifests imply), agent CLIs
and their sign-in, Git fetch and a dry-run push, the orca.yaml setup script
(optionally re-running it with Orca's runner), and free disk. Pass/warn/fail
with --json; checks live in src/main/environment-doctor for runtime reuse.
* fix(env-doctor): ship the doctor modules in the packaged CLI and share the check formatter
* fix(env-doctor): run Git probes in the C locale so folder detection is locale-independent
worker-start --on <server> --worktree new-child now tells the server that
orchestration picked the parent, so the server records the child's lineage as
orchestration, as a local child is, instead of cli. Older coordinators omit the
field and keep cli. The guide now shows new-child first and new-top-level as
the no-parent choice.
* refactor: separate execution route and child exit owners
* refactor: move browser data into defining feature owners
* refactor: give runtime RPC entry its shutdown implementation
* refactor: use defining process types and colocate host telemetry test
* docs(process-host): point piped child contract to Node owner
* docs(process-host): clarify both piped contract owners
* feat(cli): create workspaces on environment recipes
`orca worktree create --recipe <id>` creates the workspace on a new
environment from one of the repo's environment recipes, and
`orca vm recipe list` shows which recipes it accepts.
The desktop app on the provisioning computer runs the same main-side
provisioning the composer uses (write-ahead record, per-step timeouts,
cancellation), registers the project on the environment's Orca server,
then creates (orca-worktree) or adopts (provisioned-root) the
workspace there. Named progress steps ride on long-poll keepalive
frames, so the CLI prints them to stderr; older CLIs ignore them. A
failure after the VM exists destroys it through the shared cleanup and
returns recipe_workspace_create_failed with the failed step, the
recipe failure code and whether the destroy finished. Ctrl+C aborts
the request and destroys a started environment.
Paired devices cannot start a recipe create. Hosts advertise
worktree.recipe-create.v1 only when the desktop wires the recipe
service, so orcad and older hosts are refused before anything runs.
Based on #39228 by jutaz, a port of #28439.
Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com>
* fix(cli): report the VM outcome when connecting fails; record no cross-host parent
* fix(vm-recipes): destroy the VM when recording its environment fails; reset exitCode in CLI tests
* perf(types): keep recipe orchestration out of the runtime's type graph
---------
Co-authored-by: Justas Brazauskas <brazauskasjustas@gmail.com>
* refactor: use concrete browser and input owners
* refactor: bind remote runtime callers to concrete transport owners
* Use checked subscription mock argument types
* Type browser lease mock with its subscription contract
* refactor: bind sleeping VM status probe test to socket owner
A reset that reclaims a crashed run's lock now puts that record back on release,
without overwriting a lock another start took, so the next start still reports the
crash. Starts without a rotating marker delete leftover .next staged files (one holds
a secret key); an unreadable marker leaves them for recovery by hand.
Co-authored-by: Claude <noreply@anthropic.com>
Cloning always went into <parent>/<repo name>, so a same-named repository
from another owner (or any non-empty folder of that name) could not be
cloned into the same parent. Before cloning, Orca now checks the target
on the clone host. If it is taken, the clone forms show a Folder name
field with a free suggestion (<repo>-<owner>, then <repo>-2...) and clone
into that instead. RPC repo.clone and `orca project setup-clone` accept
the folder name too.
* feat(cli): list and reload installed browser extensions
* docs(browser): document extension command contracts
* docs(browser): describe extension test fixture factory
* refactor(cli): validate extension reload once and trim list output
The RPC params schema owns the ID-or-path and ID format checks. Reload
drops --profile and the constant scope field, since it always reloads
every profile where the extension is enabled. List no longer returns
icon data URLs or permission lists.
* test(browser): keep five extension reload tests at the command owner
* fix(cli): route orca extension through the packaged Linux launcher
* fix(browser): refresh Settings after an extension reload from the CLI
* test(browser): type the reload fixture list without a cast
---------
Co-authored-by: Kelvin Amoaba <97001695+AmoabaKelvin@users.noreply.github.com>
* Move session search SQLite into dedicated workers
* test: spawn the session search test worker with the shared worker helper
* fix: pass only drain promises to the channel's drain wait
* Repair session search failure and lifecycle boundaries
* Stop indexing tool output and reclaim existing rows
* test: say why the session search worker tests need a longer timeout
* Bound search cleanup and preserve failure and digest semantics
* Use the database row type for tool purge batches
* test: drop the same-connection mid-page write case now that each page reads one snapshot
* test: prove a mid-page delete from the writer can't change that page's hits
* Repair transcript cancellation cleanup and search test runtime admission
* fix: cancel active transcript finalization and enrichment waits
* fix: close transcript handles when cancellation wins delivery
* fix: preserve scan cancellation errors across parser waits
* test: prove cold session search bypasses an active writer batch
* fix: preserve search continuation through background tool cleanup
* fix: preserve search pages during orphan reclamation
* fix: bound typo repair posting visibility probes
* fix: preserve exact search terms when visibility is inconclusive
* test: drop orphan-reclaim cursor staleness case superseded by frozen continuation
* Bound session search work before ranking candidates
* Preserve the limit notice for empty search windows
* Bound session eligibility lookups and reuse FTS scoring statistics
* Index session scopes for population and candidate searches
* Derive search status from the live index after clear
* Preserve disabled search status during settings transitions
* Share planned expressions between spelling probes and search
* Keep identifier fragments out of spelling presence checks
* Report search initialization through its pending transition
* Bound spelling vocabulary work with the search posting budget
* Preserve search fallback while bounding distinct vocabulary seeks
* fix(session-search): drain removals before the worker queue fills; keep aborted close waits from failing teardown
* fix(session-search): hold writer commands when the worker queue is full instead of stopping the writer
* chore(ratchets): baseline the session search worker's one-shot entry check
* Rotate the server pairing identity when ORCA_INSTANCE_ID changes
* Back up replaced identity files, keep the recorded id on reset, keep staged files once the rotating marker is published
* Add identity-reset files to the sync fs baseline and document the backup folder
* Report a reset honestly after finishing an interrupted rotation; keep first backups and the newest one
* fix(vm-recipes): record each VM before create runs so a quit or crash can't leak it
Orca now saves a "provisioning" record for a recipe VM before running its
create command, and updates it when create finishes. If Orca quits or
crashes mid-create, or create fails without returning a result, the VM
stays listed in Settings > Cloud VMs as Failed with its instance id, so the
user can run Cleanup (destroy gets the instance id) or remove it from the
list. On startup, provisioning records with no create running are marked
as interrupted.
Records without a recipe result live in a separate file that older builds
never read, so downgrading keeps working. Records also store the repo path
so Cleanup, Copy command, suspend and resume still work after the repo is
removed or re-added under a new id (#17293).
* fix(vm-recipes): keep no runtime row when create is cancelled or rejected before its script starts
* fix(vm-recipes): harden write-ahead records from review
- Never overwrite a provisioning-records file this build cannot read; refuse new records instead.
- Remove the provisioning-records file when empty instead of rewriting it on every store write.
- Only fall back to the saved repo path while it still defines the same recipe.
- Don't let Cleanup or Attach act on a create that is still running or never returned a result.
- Show Provisioning before Cleanup disabled; stamp running records with the save time.
* fix(vm-recipes): keep new store code off direct sync fs calls and render-path translate
* fix(vm-recipes): detect a missing provisioning-records file without a type assertion
* feat(vm-recipes): optional per-step timeouts for recipe lifecycle commands
A recipe in orca.yaml can set timeoutSeconds (one number, or a map of
create/suspend/resume/destroy). When a step runs past its limit, Orca
stops the whole process tree the same way Cancel does and reports a
recipeTimedOut failure naming the step and the limit. Recipes that do not
set timeoutSeconds keep running with no limit, exactly as before.
Saved runtime records keep a recipe snapshot that older builds parse
strictly, so the snapshot leaves timeoutSeconds out; suspend, resume and
destroy read the current limit from the repo's orca.yaml instead.
Suspend and resume exit failures now go through the failure catalog with
the same English text.
* test(vm-recipes): fire the grandchild timeout only after the grandchild exists
* fix(vm-recipes): only reuse orca.yaml timeouts for the same recipe a runtime was created from
* Project chat-mode worker liveness from the structured host
* Keep chat reach checks out of per-publication attention and Crew rebuilds
* Install the session host before judging structured workers in worker-list and worker-show
* Keep worker-list rows to the liveness fix
* fix(orchestration): refuse a reply to a finished worker's report and name the follow-up that works
* fix(orchestration): say what the action under a finished report does