~/blog/feature-computer-use-native
tech notes #features#agents#workflow Wakii team 7 min read

Native computer use: agents that reach the desktop

Native computer use: agents that reach the desktop

Wakii’s agents read code, run commands, open pull requests — all of it inside the terminal and the IDE. Ask one to touch a real desktop app — press a button, fill a form, drag a slider — and no tool in the kit covers it. Native computer use is that missing piece: a module living inside the app that lets an agent operate the machine like a human user would, and — just as important — makes each action report honestly what it did. This post dissects the module at src/main/computer/, the CI path that shipped it inside a DMG, and one memorable decision: deleting a silent left-click fallback outright.

TL;DR:

  • The problem: agents live in the terminal and the IDE; desktop UI is a world none of their tools can reach.
  • The approach: src/main/computer/ is split into layers — platform-aware provider selection, parameter validation before execution, clipboard paste limits, and explicit verification stamped on each action result.
  • The ship: CI on a GitHub-hosted runner runs the full build chain including build:computer-macos, renames the DMG and uploads it straight to release v1.4.198.
  • The honesty: PR #14721 removed the silent left-click fallback on macOS — an action doing something else while reporting success is a design bug, not a feature.
  • Every path, commit and quote in this post comes from the real product repo, retrieved 2026-09-08.

The agent trapped in the terminal

An agent’s tools cover the inside of the dev machine densely: read and write files, run shell commands, run tests, open pull requests. Outside that border lies the world users actually live in — native apps, menus, system dialogs, input fields that belong to no terminal. The two worlds share no meeting point:

two working worlds — the agent on one side, the desktop on the other

  agent's world                     desktop world
  ├── read / write files            ├── native apps, menus, dialogs
  ├── run shell, run tests          ├── input fields, buttons
  └── open PRs, write docs          └── driven by mouse + keyboard

  between the two: no shared tool at all
  → an agent cannot "act like a user"

Source: conceptual diagram illustrating the gap the src/main/computer/ module exists to close, retrieved 2026-09-08.

The gap is not agent carelessness — it is a boundary of tooling. However finely a team of nine agents divides its work, one kind of task stays unclaimed: the part that means “touch the UI”. Native computer use exists so that part of the work has an owner.

Inside the module: one responsibility per layer

src/main/computer/ is not one large file but small layers. Six files carry the computer- prefix without being tests — five of them are the layers this post follows, and the sixth (computer-sidecar-paste-validation.ts) belongs to the sidecar family:

$ ls src/main/computer/ | grep '^computer-' | grep -v '\.test\.'
computer-action-verification-normalization.ts
computer-clipboard-paste-validation.ts
computer-provider-action-validation.ts
computer-provider-lifecycle.ts
computer-provider-unavailable-message.ts
computer-sidecar-paste-validation.ts

Source: ls src/main/computer/ | grep '^computer-' | grep -v '\.test\.', retrieved 2026-09-08; the same directory also hosts the desktop-script-*, macos-native-provider-* and sidecar-* families.

Reading each layer’s role from the code. computer-provider-lifecycle.ts picks the provider per platform: on macOS it prefers the native provider when available, otherwise it falls back to the desktop-script provider; the instance is cached and shutdown cleans both up. computer-provider-action-validation.ts stands in front of the provider: nine action families are enumerated explicitly in a switch — click, performSecondaryAction, scroll, drag, typeText, pressKey, hotkey, pasteText, setValue — while a wrong parameter type, a missing coordinate pair, or using both windowId and windowIndex is rejected with invalid_argument before anything touches the machine. computer-clipboard-paste-validation.ts blocks paste text beyond the size limit; large payloads are measured with a yield so the main process is not monopolized — the comment in the code says exactly that. computer-action-verification-normalization.ts closes the final promise: an action result lacking verification gets an explicit unverified state stamped on, with the reason derived from the execution path (synthetic_input, clipboard_paste or accessibility_action_unasserted). computer-provider-unavailable-message.ts is the error layer that states things plainly: no provider means the cause is named, along with the local fix.

Data flows through the module in one direction:

agent intent → action validation → provider → verification

  agent decides          validateComputerProviderActionParams()
  "click button X"  ───►  gate first: bad params → invalid_argument,
                           nothing touches the machine

                    provider chosen by the lifecycle
                    (native macOS or desktop-script)

                    normalizeComputerActionResult()
                    stamps an explicit verification state
                    (default: unverified + reason)

Source: built from computer-provider-action-validation.ts, computer-provider-lifecycle.ts and computer-action-verification-normalization.ts in src/main/computer/, retrieved 2026-09-08.

Shipping: full-chain CI, DMG straight to the release

The native macOS module is written in Swift and needs the Swift 6 toolchain, which means Xcode 16 — a local build environment does not necessarily have it. Commit 787766bfcf adds the .github/workflows/macos-build.yml workflow (71 lines) running on a GitHub macos-15 runner, selects Xcode 16, then runs the full chain:

# Full chain — INCLUDING build:computer-macos (needs Swift 6 tools = Xcode 16)
pnpm run build:desktop
pnpm run build:computer-macos
pnpm run build:keyboard-layout-macos
pnpm run build:notification-status-macos
pnpm run ensure:electron-runtime
node config/scripts/build-mac-local.mjs

Source: commit 787766bfcf, .github/workflows/macos-build.yml, step “Build native helpers + app”, retrieved 2026-09-08.

The steps that follow collect the artifacts, rename orca-macos-arm64.dmg to Wakii-1.4.198-arm64.dmg, then run gh release upload v1.4.198 … --clobber — the DMG is replaced in place. The v1.4.198 release notes document exactly this, quoted verbatim:

macOS arm64 is being rebuilt on a GitHub-hosted runner (Xcode 16) to include the computer-use native module — the DMG will be replaced in place when it finishes.

Source: v1.4.198 release notes, wakii-dev/wakii repo, retrieved 2026-09-08.

Removing the silent fallback: honesty as a design decision

Commit 66dfdc456f (PR #14721, shipped since v1.4.186 and included in the v1.4.198/v1.4.199 tags) is the textbook case for the “state your limits” principle. On macOS, a click --mouse-button middle command used to read the raw parameter string unvalidated, fall through the accessibility path, execute as a left click — and report success with path: "accessibility". The entire fix fits in one diff line:

-        let button = params["mouseButton"]?.string ?? "left"
+        let button = try mouseButton(params["mouseButton"]?.string)

Source: commit 66dfdc456f, diff of native/computer-use-macos/Sources/OrcaComputerUseMacOS/main.swift, retrieved 2026-09-08.

Why a silent fallback is a design flaw rather than a missing feature: an agent reasons from what tools report. An action that did something else but reported success is wrong ground truth at the bottom layer — the layers above trust a world that does not exist. The fix matches the module’s own philosophy: the normalization layer stamps unverified instead of assuming success; the validation layer rejects early instead of swallowing errors; and the silent fallback was deleted, not “improved”. The test inside that very commit states it plainly: “An unvalidated raw string reaches AXPress and reports a left click as success.”

Stating current limits plainly: the evidence in this post centers on macOS — the v1.4.198 notes describe the arm64 rebuild specifically to include the computer-use native module; a darwin machine without the native app gets an explicit error message, quoted verbatim: “computer-use has no native provider for darwin because Orca Computer Use.app was not found or this macOS version is unsupported. For local development, run pnpm build:computer-macos and restart Orca from this worktree.”; and middle click on macOS rides the otherMouseDown/otherMouseUp event family because macOS has no dedicated middle-click events.

Reaching the desktop does not replace the nine-agent team from Nine agents, separated powers — it hands that team a pair of hands for the part of the world living outside the editor. What each kit component owns is listed on the agents & kit page.

To see it yourself: open Wakii, hand the team a task that touches desktop UI, then read the action result it returns — verification state included. Or read the diff of 66dfdc456f to see what a single ?? "left" cost, and why it had to go.

Wakii is an agentic IDE with a built-in superpowers team.

get wakii ← all posts