Native runtime
How Action.app and the Action agent split native responsibilities
This page describes the runtime split that currently makes action behave like
a real macOS app instead of a command wrapper pretending to be one.
The split
There are two native roles:
Action.app
Owns:
- AppKit lifecycle
- menus and app-switcher behavior
- WebKit windows
- launcher UI
- permission UX
- recording probe execution
Main file:
Local agent runtime
Action.app starts the agent as a child helper,
Contents/Helpers/ActionAgent.app, on ws://127.0.0.1:4319. The helper exits
with its parent.
Owns:
- WebSocket transport
- automation-facing request handling
- local runtime methods
- bridge-friendly command orchestration
Main files:
Why this exists
Two important failures pushed the design here:
1. WebKit
WebKit behaved unreliably when UI modes were entered through the wrong runtime path. The fix was to let AppKit own the UI lifecycle cleanly.
2. ScreenCaptureKit recording
Recording was not reliable when attempted inside the wrong lifecycle context.
The stable path now launches a fresh Action.app instance in recording-probe
mode for the actual capture work.
The lesson is simple:
AppKit-dependent work should run inside a real app lifecycle.
Current execution flow
For normal operator usage:
Action.applaunches- launcher UI comes up
- local agent is started if needed
- UI talks to the agent for runtime state and automation methods
For recording:
- command or UI requests recording
- host talks to the local agent
- agent launches
Action.appagain inrecording-probemode - probe performs the actual
ScreenCaptureKitrecording - artifacts and finished markers are written
Important boundaries
Keep these rules intact:
- do not move WebKit lifecycle back into a fake headless command path
- do not move recording implementation back into the plain headless agent path
- keep the agent useful for orchestration and transport
- keep AppKit-owned concerns in the app process
Private-layer discovery
Use lats action capabilities and the active MCP capabilities / tools/list
for build provenance and routing. Check host quarantine before opening a private
display. Native support, runtime health, and version strings do not establish
physical desktop preservation. See Agent layer.
native:doctor builds and signs. Run it on an authorized development host.
On an installation target, preserve the installed bundle and rollback; deploy
a matched app and MCP runtime instead of rebuilding implicitly. Reconnect MCP
after runtime changes.
To assemble a matched runtime candidate on the development host, use:
bun scripts/package-agent-runtime.ts --app /path/Action.app --output /new/action-runtime --instructions-root /path/to/lattices-docs-checkoutThe command verifies the signed app's recorded MCP source fingerprint, bundles
the source and locked production dependencies, and includes the selected layer
docs and Action skill. It rejects a mismatched pair or existing output and does
not install anything. runtime-provenance.json records the artifact identities
and marks host desktop-isolation acceptance as uncertified. Keep the previous
runtime for rollback and preserve host quarantine when installing a candidate.
The extracted archive contains sibling bin/ and products/ directories.
Set ACTION_ROOT=<extract>/products/action, not the extraction root, and keep
bin/host-pairing.ts in place; the runtime imports that canonical dependency.
Scripts and helpers
Call native work through package.json scripts from products/action:
bun run native:app:build
bun run native:doctor
bun run native:launch
bun run native:relaunch
bun run native:host -- status
bun run native:test:screenshot
bun run native:test:recordThe scripts wrap helpers in native/engine/scripts. The most important wrappers are:
build-app.shdoctor.shrun-app-host.shtest-screenshot.shtest-record.sh