- local.run-actions: autoRunAfterSetup after a good setup and not after a failed one, Run button,
one trust prompt, Stop -> Stopped, menu Restart replaces the tab, Cmd+Opt+Enter start/restart
- run.nonconcurrent: echo-loop started in B stops A's
- run.ports: ORCA_PORT/ORCA_PORT_COUNT/CONDUCTOR_PORT per terminal, distinct blocks, stable across
an app restart, served locally; cloud half: the action in the VM reachable here via auto-forward
- run.cloud-resume: action back after Sleep/wake and after Restart sandbox
DS-34:
- One billing store (billing-summary-store) replaces the summary, the hook's local state and the
Run-on picker cache; it keeps the last good result through a failed read and still drops answers
from before a team or account switch (DS-17).
- Skeleton while Plan & billing loads.
- '{{count}} sandbox hours left' and '{{count}} sandbox hours over the included amount this month'
as i18n plurals; no bare 'hours'; the unreachable 100% branch is gone.
- Usage warning driven by usageWarningPercent ('Your team has used {{percent}}% of this month's
sandbox hours.'), in Settings, the plans page and the account menu.
- capTooHigh states the maximum ('The spend cap can be at most {{max}}.'), from offers.maxSpendCapCents.
- Plans dialog focuses its heading on open, so Tab reaches the interval toggle before the cards.
- Payment notice uses InlineError; the build card's overage buttons land on the overage section.
- Account menu names the team once and adds the hours-left line.
DS-44: warning tone at 90%+, '$' as an input prefix, neutral paid check, 24px dialog close hit
area, no <p> inside the CheckoutPanel <dl>.
- Agent and worktree come from the terminal orcad verifies from launch
evidence (verifiedCallerTerminalHandle, shared with turn-sender); the
terminalHandle param is gone and a worktree hint is kept only when the
host knows it.
- secrets.* are accepted, and their events sent, only on cloud orcad
(ORCA_IS_CLOUD=1 + ORCA_SANDBOX_ID); already-set never reads orcad's env.
- touchRequest emits secrets.requestUpdated; natural expiry emits
secrets.requestSettled {status: expired}.
- orca-env skips the control plane's reserved names and prefixes, with a
test that reads them from secrets.ts.
- reason drops bidi controls and turns C0/C1 controls into spaces.
Customers keep flat sandbox hours. Each stopped session's activeCpuDurationMs
(from Vercel's stop response or GET session) is stored in a new session_cpu
table (migration 0042), idempotent per session. Recording is best-effort and
never blocks suspend, stop or usage reporting; a 5-minute cron sweep retries
recent sessions still missing CPU. Operator-only GET /v1/internal/fair-use
reports per-account 30-day utilisation sum(active_cpu_ms)/sum(wall_ms*vcpus)
with fairUseFlag above 60%. Nothing reaches usage_outbox, billing or clients.
Live on dev the first capture sealed zero sessions: agentSession.subscribeStatus needs a streaming
transport and the unix socket refuses it, and worktree.ps lists only agents live right now. The
collector now reads orcad's own session records (agent-session-journal.db, read-only): provider,
name and last turn, open tabs first; live worktree.ps rows override status; history still comes
from agentSession.history, with the stored last turn as fallback.
orcad keeps agent-initiated secret requests in memory with the contract's
limits (3 pending, 10/hour, 15 min TTL, touch capped at 60 min, dedupe per
name), derives the agent from the calling terminal, and announces
secrets.requested on runtime.clientEvents (replayed on attach; phones get
status only). The CLI waits on it and prints the D4 reload hint; the VM
ships orca-env and makes zsh read the session env hook.
- 'Save as personal Cloud secret' is offered, and accepted by main, only for names the egress proxy
swaps (a shared list the control-plane test holds equal to the proxy's); anything else would sit
on the VM in full, so main answers not_swappable.
- SSH launches into an Orca Cloud workspace (orca-* aliases or an 'orca ssh-proxy' ProxyCommand
surfaced through ~/.ssh/config Includes) get no desktop keys.
- Defense in depth on the VM: orcad with ORCA_IS_CLOUD=1 drops a carried keyEnv.
Line items: '{{seats}} x {{price}} per seat, billed yearly' / 'per seat per month'
(plural keys); totals '{{total}} per year' / 'per month'; Worker plan labels
'$50 per seat per month' and '$480 per seat, billed yearly'. Drops /mo, /yr,
/year and /seat/month strings.
- COPILOT_GITHUB_TOKEN on api.github.com: GET /user and GET /copilot_internal/* only (normalized
paths; dot or encoded segments refused); the Copilot API hosts are unchanged. It resolves like
an env variable (personal beats team): it is one person's GitHub identity.
- Routine summaries for opencode (JSON events), cursor (JSON result) and copilot (--silent) are the
agent's final message, and every summary has the session's secret values replaced before it can
be posted as a comment or PR body.
- Webhook/GitHub context in a routine prompt is capped at 48 KiB (compact, then cut), so a prompt
passed as one argv entry stays under Linux's 128 KiB limit.
- A test fails if an agent credential is neither swapped nor marked 'Stored on workspace'.
- COPILOT_GITHUB_TOKEN: placeholder in the VM, swapped on api.github.com (Bearer or token form, next to
the workspace token's own route) and on the Copilot API hosts (left open for Copilot's own session
token). GOOGLE_API_KEY: swapped on generativelanguage.googleapis.com and aiplatform.googleapis.com
(Vertex express). A credential may now route to several hosts.
- Routines accept claude, codex, opencode, gemini, cursor and copilot; the in-VM runner has a
headless command for each (checked against a local stand-in model: prompts starting with '-' stay
prompts). The editor picks the agent from a list.
- AWS_* keys (SigV4, signed in the VM) and Bedrock API keys can't be swapped: the secrets UI marks
them 'Stored on workspace' with the reason, in the list, the .env preview, the effective view and
the editor.
- Gemini's auth method is seeded for GOOGLE_API_KEY too (vertex-ai with GOOGLE_GENAI_USE_VERTEXAI);
headless Gemini refuses to start without one.
Copilot prefers GH_TOKEN/GITHUB_TOKEN over a stored /login. In Orca Cloud those hold the workspace
GitHub App placeholder, so every Copilot start said 'Resource not accessible by integration' and a
user who signed in could never use it. A wrapper drops the two placeholders for Copilot only, unless
BYOK is configured (no GitHub sign-in needed; gh in Copilot's shell keeps working).
* feat(cloud): pdx1 default region with iad1 fallback and one golden per region; Standard is 8 vCPU / 16 GB (U17, U18)
- golden_images and environment_builds record their region (0040, backfilled iad1); rotation,
git-source builds, smoke and activation run per region; lifecycle picks the region's golden.
- New creates default to pdx1; a create with no pinned region falls back to iad1 automatically on a
capacity/provider error (VERCEL_FALLBACK_REGIONS). Until pdx1 has an image, creates use iad1.
- Environment builds boot and smoke in their own region; workspaces from a build boot there.
- One size: Standard = 8 vCPU / 16 GB (ORCA_CLOUD_SANDBOX_SPEC). Legacy 'large' requests map to
standard; 0040 rewrites existing large rows.
* merge cloud/integration (ORCA_CLOUD_SANDBOX_SPEC landed in #196)
Hosts with credential rules (model APIs, api.github.com) are answered by Vercel's egress proxy with a
certificate from its CA. Vercel's command env trusts it (NODE_USE_SYSTEM_CA, NODE_EXTRA_CA_CERTS,
SSL_CERT_FILE) but orcad starts under env -i, so Node clients in terminals used Node's bundled roots:
Gemini CLI retried forever ('This is taking a bit longer') while the same call from a command
returned at once. Found on the live proof of the new agents; NODE_USE_SYSTEM_CA=1 in the terminal
fixed it there (1 s to the provider's answer).
Staging sign-in now works end to end in dev without a dev operator key on the user's machine.
Same account ids as billing dev (which trusts staging already); never honored when SANDBOX_ENV=prod;
a staging key cannot pass as the prod issuer.
Security review: a Copilot BYOK key without a usable base URL (or with one from another scope) had
no route, so it went to the VM as itself. Every swappable name now becomes a placeholder, routed or
not, and the Copilot pair resolves like the other agent keys (shared beats personal, as a pair).
The Cursor exchange reply is parsed whatever its content type and cut down to accessToken; headers
(set-cookie) are not passed. opencode.ai is not allowlisted (anonymous share uploads).