Files
orca/AGENTS.md
T
Neil 6bb2b0c6d7 test(runtime): capture real Antigravity transcripts — the detector is inverted on live output (#19983)
* test(runtime): capture real agent PTY transcripts before rewriting Antigravity readiness

Antigravity readiness has been written five times against a five-line screen
typed from memory. There is no Antigravity transcript in this repository, so
every attempt was a guess tested against another guess. This adds the recorder,
the protocol and the fixture-driven suite so the sixth attempt can be written
against evidence, and changes no detector logic.

- config/scripts/capture-agent-pty-transcript.mjs records a live agent session
  through a real PTY, escapes and wrapping intact. Ctrl-] is consumed by the
  recorder and never forwarded, which is the only way to end a capture while a
  dialog still owns the screen.
- config/scripts/pty-transcript-secret-scan.mjs finds account identifiers and
  credentials, redacts them with same-length placeholders so wrapping survives,
  and recognises its own placeholders so a scrubbed file verifies clean.
- src/main/runtime/antigravity-readiness-transcripts.test.ts asserts a verdict
  per transcript and skips by name until the transcripts land, with a
  doc-coverage ratchet and a guard that a fixture contains escape bytes.

The escape-byte guard exists because the three cursor-agent fixtures carry a
comment claiming they were captured verbatim through Orca, yet contain zero ESC
bytes and zero carriage returns. That comment is corrected here to say what
those files are; the fixtures and the rules built on them are untouched.

* test(runtime): capture real Antigravity transcripts, and pin what they prove

`agy` 1.1.25 turned out to be installed, so the transcripts this scaffold was
built for now exist. Six are recorded from live sessions and committed; the
rest are named as skipped, because reaching them would mean signing the
operator out or deleting their config.

The captures invert the story. On real output the shipped detector refuses a
genuinely ready screen and accepts a live `/model` picker:

- Antigravity paints a block-glyph logo down the left, so the model row never
  starts a line. `startsWith('gemini', trimmedStart)` cannot match a real ready
  screen, on any account or model. Stripping the logo flips the same screen to
  ready, which means a decorative glyph decides readiness today.
- The `/model` picker prints `Gemini 3.x Flash` one per line, at line start, and
  a bare `>` composer sits earlier in the tail. Both halves of the rule are
  satisfied while a dialog owns the screen.
- For an API-key user the identity row reads `Gemini API key` — no `@`, no
  domain — and `AGY_CLI_HIDE_ACCOUNT_INFO=1` removes the row entirely. The
  account-row requirement of attempts 4 and 5 can never pass for those users.
- The banner is printed once and never reprinted after a dialog is dismissed, so
  `headerIndex` cannot be the ordering anchor.

Four suite cases are pinned as KNOWN DEFECT: they assert what the detector does
so CI stays honest instead of permanently red, and flip to failing the moment
someone fixes it. No detector logic changed.

The recorder gains `--send "<ms>:<text>"` because a dialog capture has to be
driven and an unattended run has no TTY, and the scrub scanner gains a UUID rule
because agy prints a resumable conversation id on exit.

* test(runtime): capture agy mid-turn, and make the scan file reviewable

Answers the busy-frame question a P1 review raised against attempt six, with
two new captures from a live turn.

At the frame level the review is right: a busy frame parks the caret with the
same bytes as an idle one, `CR ESC[2A ESC[2C`, and the only differing row —
`esc to cancel` versus `? for shortcuts` — is erased by that park.

At the retained-tail level it does not reproduce. Each spinner tick is its own
repaint with its own `CR ESC[2A`, two rows higher than the frame's, which
splices the composer away: a live turn's tail ends on `⣟  Generating...`, with
no bare caret to match. A constructed input that keeps the park and edits only
the status text is not faithful, because a live turn has a spinner row
repainting below the composer.

The residual is the gap between a frame park and the next tick, where the tail
does end on the bare caret. Quiescence-gated paths are safe there because ticks
keep arriving; text-only paths are not, and for those the capture supports one
clause: a braille glyph on the last visible line means working. That predicate
already exists here for cursor-agent and should be reused, scoped to the last
line — a first-run transcript prints `⠾ Signing in...` during startup.

Also in this commit, from the same review:

- pty-transcript-secret-scan.mjs held raw 0x00-0x1f bytes in a character class,
  so the one file gating real PTY data into history was binary to git and
  unreviewable in a diff. It now tests codepoints, which the formatter cannot
  fold back into control bytes.
- Pin `src/main/runtime/__fixtures__/*.txt` as -text. A Windows checkout would
  otherwise normalise line endings and rewrite the CR bytes that make these
  files evidence.

The recorder now stops appending at the stop moment rather than through
shutdown: an agent repaints an idle frame on its way out, which was overwriting
the mid-turn state the capture existed to record.

* test(tooling): allowlist the transcript scan test in the batch-shim ratchet

pty-transcript-secret-scan.test.mjs asserts that the capture recorder routes
an 'agy.cmd' shim through cmd.exe, so the shim literal it names is the
assertion, not a spawn. Fits the existing assert-on-shim-files category.
2026-09-11 01:07:16 -07:00

11 KiB
Raw Blame History

Design System

All UI work — layout, color, typography, spacing, component selection, UX behavior — must follow docs/STYLEGUIDE.md. Use the tokens defined in src/renderer/src/assets/main.css (the canonical source) and the shadcn primitives in src/renderer/src/components/ui/. Don't invent new color values, font sizes, or shadow tiers when a documented one already covers the role. When STYLEGUIDE.md is silent, follow the resolution order in its final section.

Electron UI Validation

Always run tests and agent-launched apps in the background with ORCA_BACKGROUND_LAUNCH=1. Never steal monitor focus or reveal test windows: no show(), showInactive(), bringToFront(), app.focus(), or OS activation. Use CDP screenshots of hidden renderers. Keep native-focus and visible-window tests paused on the user's desktop; run them on an isolated display or CI. Rebuild modified launch-policy code before running an app; stale build wrappers are not safe.

Use the $electron skill and Playwright CDP for rendered Orca UI checks. Do not use computer-use for Orca UI validation.

Style

Reuse Before Reimplementing

Before writing new logic at any scale — a function, component, IPC channel, state store, or whole subsystem/flow — check whether an existing implementation already does the job (or nearly does). Extend or generalize it instead of building a parallel version; only write from scratch when nothing fits. Keep the check proportionate: a quick search for trivial code, a real one before building anything substantial.

Concise/Brief Non-obvious Comments ONLY

  • DO NOT: be verbose, explain the obvious, walk through the code ("WHY not HOW")
  • BE CONCISE. 1 LINE if possible

Lint Rules: Do Not Disable Max Lines

NEVER add a max-lines disable (eslint-disable max-lines, oxlint-disable max-lines, or line-specific variants), and never add a per-file max-lines bump in mobile/.oxlintrc.json.

File and Module Naming

Never use vague names like helpers, utils, common, misc, or shared-stuff for files, folders, or modules. They carry zero info and tend to become dumping grounds. Name files after what they actually contain — prefer the concrete domain concept (e.g. tab-group-state.ts, terminal-orphan-cleanup.ts) over the generic role (tabs-helpers.ts, terminal-utils.ts). If you find yourself reaching for helpers, the file probably has more than one responsibility and should be split, or there's a better name hiding in the code that describes what the functions operate on.

Type Declarations: Prefer .ts Over .d.ts

Verifying Changes

  • Typecheck: pnpm tc (or tc:node / tc:cli / tc:web)
  • Test: pnpm test [path/to/file.test.ts]
  • Lint: oxlint, or pnpm run check:code-quality:changed for changed files (full pnpm lint is slow); format with pnpm format

Considerations

Worktree Safety

Always use the primary working directory (the worktree) for all file reads and edits. Never follow absolute paths from subagent results that point to the main repo.

Cross-Platform Support

Orca targets macOS, Linux, and Windows. Keep all platform-dependent behavior behind runtime checks:

  • Keyboard shortcuts: Never hardcode e.metaKey. Use a platform check (navigator.userAgent.includes('Mac')) to pick metaKey on Mac and ctrlKey on Linux/Windows. Electron menu accelerators should use CmdOrCtrl.
  • Shortcut labels in UI: Display / on Mac and Ctrl+ / Shift+ on other platforms.
  • File paths: Use path.join or Electron/Node path utilities — never assume / or \.
  • Windows setup scripts: the setup/issue-command runner is a .cmd batch file unless the script starts with a #! line — never derive that from the user's terminal-shell preference, and never launch a .cmd runner with a bare cmd.exe /c from a Git Bash pane (MSYS rewrites the /c). See docs/reference/windows-setup-shell.md.
  • Windows child processes: start them through runProcess/spawnProcess in src/shared/child-process/ — never child_process directly. It pins windowsHide, refuses shell: true, and encodes .cmd/.bat arguments so neither CommandLineToArgvW nor cmd.exe mangles them. A ratchet test fails on any new direct import. Recognised npm/pnpm .cmd shims are resolved to their real target so the spawn skips cmd.exe entirely; see docs/reference/windows-cmd-shim-resolution.md before adding a shim shape or debugging one.
  • Windows process enumeration: read the table through src/main/windows/windows-process-table.ts, never by forking powershell.exe. See docs/reference/windows-process-enumeration.md.
  • Windows daemon-host relocation: the terminal daemon runs from a copy of the app runtime under %LOCALAPPDATA%, which is what survives an auto-update. Before touching that copy, its exe name, or the NSIS uninstall macro, read docs/reference/windows-daemon-host-relocation.md.
  • Windows EDR signal: don't add -ExecutionPolicy Bypass, -EncodedCommand, cmd.exe /c with escaped free text, per-operation interpreter spawning, or runtime Add-Type compilation without reading docs/reference/windows-edr-posture.md first — behavioural EDR scores each of those, and being signed does not clear them.
  • WSL commands: build argv with buildWslExecArgs (always --exec — under --, wsl.exe expands $name in every argument and silently rewrites the script), and fence anything whose stdout you parse with buildWslCapturedLoginShellCommand, because the interactive login shell prints the distro banner to stdout. See docs/reference/wsl-command-execution.md.
  • Linux native modules: keep the glibc floor at Ubuntu 20.04 / glibc 2.31. A module compiled from source on a newer runner can reference symbol versions absent on the floor and crash the app on startup. See docs/reference/linux-glibc-compatibility.md; packaging fails if a bundled native binary needs newer glibc.

SSH Use Case

All changes must consider the SSH use case. Don't assume local-only execution. Before changing anything that reports on, stops, or lists remote work, follow docs/reference/ssh-execution-boundary.md: the execution host owns everything that touches execution, and loss of contact is never evidence of process death — the verdict vocabulary is live / unverifiable / exited, with no synonyms.

Folder Workspace Use Case

All changes must consider folder workspaces as well as git worktrees. Don't assume every workspace is a git worktree.

Agent Status

The execution host owns agent status in one store, the hook server's, and every reader (sidebar, worktree ps, mobile, dashboard) subscribes to it. Before adding a producer, a cache, or a reader-side precedence rule, read docs/reference/agent-status-store.md: new producers write into that store, and readers keep only presentation policy.

Agent Terminal Screens

A rule that reads what an agent CLI paints on a terminal — readiness, blocked prompts, idle — must be written against a captured transcript, not a remembered screen. Record one with docs/reference/agent-pty-transcript-capture.md, which keeps escapes and wrapping intact and scrubs account identifiers before they reach git. Antigravity readiness has no transcript yet and five failed attempts without one; before touching it, read docs/reference/antigravity-readiness-evidence.md.

Remote Wire Compatibility

Clients and remote Orca servers update independently, so mixed versions are the normal state. Before changing anything a paired client and host exchange — RPC params, stream frames, or the content either side publishes over them — follow docs/reference/remote-wire-compatibility.md. A new optional field is safe; a new stream opcode must be capability-negotiated because decoders drop unknown opcodes silently; and changing what the host publishes reaches old clients even with no wire change.

Git Binary Compatibility

Orca runs the user's Git binary on native, WSL, and SSH hosts, which may all have different versions. Treat Git 2.25 as the core-workflow baseline and follow docs/reference/git-compatibility.md.

When adding or changing a Git command:

  • Check when every subcommand and option was introduced. For newer behavior, keep a baseline-compatible fallback or degrade safely.
  • Use GitCapabilityCache with a narrow unsupported-error predicate so recurring operations do not retry a known-invalid command. Do not rely only on git --version; wrappers such as simple-git do not remove host-version differences.
  • Scope capability state to the host that executes Git: native, WSL distro, SSH provider, or relay connection. Cover the first fallback, later cached calls, concurrent probes, and relevant host isolation in tests.
  • Keep the real-binary compatibility contract in PR CI current. When adopting a newer Git feature, add its version boundary so the preferred command and fallback both run against representative Git releases.
  • Preserve commands that begin with global Git options such as -c before the subcommand, including auto-maintenance suppression used by worktree-create fetches.

Git Scan Safety

  • Never enumerate every ref and then run git ls-tree -r or git show once per ref. That ref × tree fan-out can retain gigabytes of output before a downstream sort -u or search can make progress.
  • Prefer rg over the checked-out files for source searches. For history or refs, use a named ref, an explicit namespace/path, --max-count, and a bounded output; do not use an unqualified --all scan as a first diagnostic.
  • Keep repository-wide commands targeted to the current repository and worktree. If an unbounded scan is genuinely required, measure the ref count first, explain the cost, and get confirmation before running it.

Git Provider Compatibility

Source-control and review changes must consider GitLab and other supported git providers, not only GitHub. Keep provider-specific behavior behind explicit checks, and avoid GitHub-only naming for generic review concepts.

GitHub CLI Usage

Be mindful of the user's gh CLI API rate limit — batch requests where possible and avoid unnecessary calls. All code, commands, and scripts must be compatible with macOS, Linux, and Windows.