All UI work — layout, color, typography, spacing, component selection, UX behavior — must follow docs/STYLEGUIDE.md. Most of it is linted: pnpm run check:code-quality:changed fails on new restyles of a components/ui/ primitive, raw palette colors, and computed className strings; pnpm lint fails on any class Tailwind cannot generate. See the Enforcement section of the style guide before suppressing either. 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. In components/native-chat/, the "Chat type scale" and "Chat text colour, hover and focus" sections are binding, and pnpm lint fails on arbitrary font sizes, softened text-foreground, and weakened focus rings there.
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.
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.
- DO NOT: be verbose, explain the obvious, walk through the code ("WHY not HOW")
- BE CONCISE. 1 LINE if possible
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.
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.
Avoid type assertions except as const. Unavoidable casts need a line-specific SAFETY: explanation:
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: Explain the verified invariant here.- Typecheck:
pnpm tc(ortc:node/tc:cli/tc:web) - Test:
pnpm test [path/to/file.test.ts] - Lint:
oxlint, orpnpm run check:code-quality:changedfor changed files (fullpnpm lintis slow); format withpnpm format - Design system:
pnpm run lint:design-systemfor the full renderer report (not a gate); the changed-lines gate above is what CI enforces - Real Claude CLI: when you change Claude structured-session code (
src/main/claude/claude-structured-*), runORCA_REAL_CLAUDE_CLI_TEST=1 pnpm test src/main/claude/claude-structured-real-cli.test.ts src/main/claude/claude-structured-real-cli-fold.test.ts; it uses your real Claude login
Fill in .github/pull_request_template.md, written for a reviewer who has never seen this code:
- No jargon — plain language, no internal shorthand.
- The before and after as the user experiences it.
- The mechanism you changed, not just the symptom.
- Why this approach over the alternatives you considered.
Cover all four concisely. Don't pad or walk the diff.
Before merging, verify that the required checks and aggregate gate in the full PR workflow have passed for the exact current PR commit. For GitHub, identify the .github/workflows/pr.yml run and its aggregate PR checks passed (job ID verify); Mobile Checks is separate and never substitutes for it. Check workflow identity as well as the displayed job name. If the head changes, repeat the check for the new head.
Pending, failed, cancelled, or missing required checks block agent merges even when repository settings allow them. gh pr merge --auto is not proof that CI passed: GitHub may merge immediately when checks are optional. Never use --admin or disable protection to bypass a failed check. An explicit user instruction to make an emergency exception overrides this default; otherwise fix the failure or wait. Use --match-head-commit to prevent merging a different commit after validation.
CI changes must exercise the affected checks in the PR. Required check names must be unique across workflows, and workflow changes must preserve the full aggregate's failure handling and conditional job requirements.
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.
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 pickmetaKeyon Mac andctrlKeyon Linux/Windows. Electron menu accelerators should useCmdOrCtrl. - Shortcut labels in UI: Display
⌘/⇧on Mac andCtrl+/Shift+on other platforms. - File paths: Use
path.joinor Electron/Node path utilities — never assume/or\. - Windows terminal shells:
--shellpicks the shell a terminal is;--commandis typed into whatever shell the host spawned, so a shell choice routed throughcommandsilently becomes a child process. - Windows setup scripts: the setup/issue-command runner is a
.cmdbatch file unless the script starts with a#!line — never derive that from the user's terminal-shell preference, and never launch a.cmdrunner with a barecmd.exe /cfrom a Git Bash pane (MSYS rewrites the/c). - Windows child processes: start them through
runProcess/spawnProcessfrom@orca/process-host— neverchild_processdirectly. It pinswindowsHide, refusesshell: true, and encodes.cmd/.batarguments so neitherCommandLineToArgvWnorcmd.exemangles them. Recognised npm/pnpm.cmdshims are resolved to their real target so the spawn skipscmd.exeentirely. - Ripgrep: Orca bundles
rgfor every platform, WSL, and SSH remotes. Spawn it throughspawnBundledRipgrep(main) orresolveRelayRipgrepCommand(relay), never a bare'rg'— Windows resolves a bare name in the spawn cwd before PATH. Don't add git/readdir fallbacks locally; the relay's chain exists only for hosts an upload never reached. - Windows process enumeration: read the table through
src/main/windows/windows-process-table.ts, never by forkingpowershell.exe. - Windows MSYS/Git Bash panes: their children break away from the per-PTY job unless it is created without
JOB_OBJECT_LIMIT_BREAKAWAY_OK, and aconpty.nodebuilt before that fix passes every existing gate. - Windows daemon-host relocation: the terminal daemon runs from a copy of the app runtime under
%LOCALAPPDATA%, which is what survives an auto-update. - macOS daemon launch: packaged macOS runs the terminal daemon from a copy of the signed terminal host helper through launchd, so an update cannot sever its privacy grants. Before touching that copy, its cleanup, or the fork fallback, read
docs/reference/macos-daemon-tcc-attribution.md. - Windows EDR signal: don't add
-ExecutionPolicy Bypass,-EncodedCommand,cmd.exe /cwith escaped free text, per-operation interpreter spawning, or runtimeAdd-Typecompilation without reviewing the EDR impact first — behavioural EDR scores each of those, and being signed does not clear them. - WSL commands: build argv with
buildWslExecArgs(always--exec— under--,wsl.exeexpands$namein every argument and silently rewrites the script), and fence anything whose stdout you parse withbuildWslCapturedLoginShellCommand, because the interactive login shell prints the distro banner to stdout. - 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. Packaging fails if a bundled native binary needs newer glibc.
Ordinary pnpm install covers the host OS and CPU only. Before packaging for another architecture — including pnpm build:mac, which builds x64 and arm64 by default — run pnpm install:release. electron-builder only warns on a missing extraResources source, so the beforePack guard is what turns a thin install into a build failure instead of a silently broken artifact.
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, 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.
All changes must consider folder workspaces as well as git worktrees. Don't assume every workspace is a git worktree.
The execution host owns agent status in one store, the hook server's, and every reader (sidebar, worktree ps, mobile, dashboard) subscribes to it. New producers write into that store, and readers keep only presentation policy.
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. Use config/scripts/capture-agent-pty-transcript.mjs to keep escapes and wrapping intact and scrub account identifiers before they reach git.
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 — preserve compatibility with older peers. 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.
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.
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
GitCapabilityCachewith a narrow unsupported-error predicate so recurring operations do not retry a known-invalid command. Do not rely only ongit --version; wrappers such assimple-gitdo 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
-cbefore the subcommand, including auto-maintenance suppression used by worktree-create fetches.
- Never enumerate every ref and then run
git ls-tree -rorgit showonce per ref. That ref × tree fan-out can retain gigabytes of output before a downstreamsort -uor search can make progress. - Prefer
rgover 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--allscan 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.
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.
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.