You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This remains a tracking Issue. The merged developer bridge includes explicit selected-tab/site consent, bounded visible text, open-shadow semantics, safe value receipts, authenticated Windows transport, per-user Windows host registration, and opt-in proven same-origin child reads and DOM activation, and bounded top/child activation effect receipts. Explicit ax_read(target="paired_page") and canonical ax_activate now use the consented page; automatic native-window association, mixed browser-chrome/page snapshots and full packaged-browser acceptance remain pending. The original acceptance criteria below are unchanged.
[nova] fix: revalidate captured top-document activation targets #81 / PR fix: revalidate captured top activation targets (#81) #83: revalidate the exact captured top-document activation target against its existing private role/name/type fingerprint and current bounded actionability before dispatch. All ten changed-target modes dispatch zero times; valid exact targets, own-handler public label/state and fresh reads remain usable. The same twelve regressions reproduced ten stale dispatches before repair and passed after repair; 355 full extension tests and 15 fresh actual owned Chrome/native-host cases passed. Complete independent review and all eight exact-head source CI jobs plus all eight merged-master jobs passed. Accepted source merge is 910deb24b319f7102387c92e4064a93aacff198c.
[nova] feat: retain OS process ownership evidence for the Chrome bridge #84 / PR feat: retain Chrome bridge process ownership evidence (#84) #86: broker-observed native-host/browser process ownership in status, replacing successful worker ownership and stripping forged ownership from error objects while preserving payloads, receipts and pairing revocation. Forty-two native tests and 65 actual Windows tests passed; the three forged status regressions failed before the repair and passed afterward. Fresh owned macOS Chrome acceptance independently matched process PID/start/path hashes, kept 19 terminal receipts (17 successful and two expired pairing attempts), and proved release plus active-pair disconnect/reconnect/re-pair. Complete independent source review and all eight exact candidate checks passed. All eight actual-master checks passed after a failed-only Rust-download retry retained separately in [nova] ci: record macOS rustup network timeout after #86 #87. Accepted source merge is 19dfeaa1e49fd186202f731c92d2f7ec9b6539af; native-window/page association remains unproven.
Each child passed complete independent review and its exact-head CI/acceptance gates. Windows execution uses owned private registry/temp/process fixtures; actual Chrome discovery and packaged GUI are separate. Proven same-origin reads/DOM activation remain partial coverage and do not complete the parent's broader permitted-frame, browser/window identity, canonical routing or trusted-input criteria.
Remaining slices receive focused child Issues before implementation:
Native-window/page association for the observed browser-process identity, then automatic canonical ax_read provider routing.
Broader action/navigation result confirmation and verified trusted-input fallback.
Packaged extension/host smoke on macOS and Windows, plus the full parent regression matrix.
Related #35 owns popup freshness and #36 owns signed distribution under Zenith#185. Do not duplicate that work or equate isolated developer fixtures with production distribution. Source #34/#70 is merged, with manual macOS desktop/cursor acceptance still pending permissions. Zenith#318 / PR#319 delivers the accepted Nova source gitlink at Zenith f45d83bd188e17bae9b2d2f8b894a2b9faeecd0c; both exact-head root PR guards and full independent pointer review passed. The merged-main pointer check passed; the PR-only notes check skips on push. Local root/Nova are synchronized; Bamboo/Bodhi dirty gitlinks and all seven unrelated primary repositories remain unchanged. The already-accepted upstream release config from the fresh pointer base was included by the normal root fast-forward.
There is no monolithic implementation branch for this parent. Every child retains its own bounded scope, estimate, tests and PR. Keep #23 open and all original acceptance boxes unchanged until actual parent-level evidence exists.
[nova] feat: integrate explicitly paired pages with canonical read and activate #88 / PR feat: route paired pages through canonical read and activate (#88) #89: explicitly selected paired pages share canonical read/activate generations; captured Session/full-route binding is revalidated at actual dequeue, valid tokens are consumed before dispatch, and stale bindings preserve newer pairings. Exact-candidate genuine-popup/public-MCP macOS Nova.app and Windows managed-MCP Chrome acceptance passed duplicate-label/decoy routing, mixed states and Unicode budgets, DOM replacement, navigation/release/re-pair, no-effect and owned-host reconnect. Independent full-diff source review and all eight exact-head CI jobs passed. Accepted source merge is 32bf4d90129e944f15e3a66b9e0ca1c72efe0da2. This page-only migration does not claim automatic native-window association or complete the original parent criteria.
Summary
Add a Manifest V3 Chrome/Chromium extension plus a native Nova bridge so browser page content becomes a reliable semantic provider for Nova's ax_read / node-activation contract from #22.
For a Chrome page, Nova should prefer the extension-backed DOM/ARIA snapshot and action channel for page content, while continuing to use operating-system Accessibility for browser chrome such as tabs, toolbar, and address bar. If the extension is absent, disconnected, lacks permission, or cannot instrument the page, Nova must report that reason and follow #22's native-AX → OCR → focused-screenshot fallback rather than pretending the page was empty.
This is a separate Issue from #22 because it introduces a distributable browser extension, Native Messaging registration/lifecycle, tab/frame identity, host permissions, a versioned protocol, and a new security boundary.
Code review: why the current bridge is insufficient
Current master (ff840350) already recognizes that macOS Chrome AX actions are unreliable:
src/server.rs::click_cached_mark tries ElementHandle::try_web_click before AX and coordinate fallback.
src/platform/mac/elements/webclick.rs runs an AppleScript command against active tab of front window, injecting a fixed document.querySelectorAll(...) / document.elementFromPoint(...).click() snippet.
The source explicitly notes that AXPress can return success while doing nothing on web content.
That workaround is useful, but it is not a browser integration contract:
It targets only the front window's active tab, so the tab associated with the AX node is not proven to be the tab that receives the script.
It depends on macOS Automation and Chrome's “Allow JavaScript from Apple Events” setting; failure is collapsed into the generic AX/coordinate fallback.
It returns only a short click description. It cannot supply labels, structured text, form state, links, headings, frame identity, or a page-change signal to ax_read.
The injected script sees only the top document, does not aggregate permitted cross-origin frames, does not traverse open shadow roots, and uses a small hard-coded selector/accessible-name approximation.
HTMLElement.click() does not satisfy every trusted-user-gesture flow. When it fails, Nova lacks a browser-verified fresh element rectangle and an explicit needs_trusted_input result.
There is no extension/native bridge, extension package, installation/status command, permission UX, protocol-version negotiation, or Chrome-specific integration test in the repository.
The model should normally keep calling ax_read and activating returned nodes. Provider selection belongs inside Nova; the prompt should not require the model to choose AppleScript, extension, or AX manually.
Proposed architecture
Nova MCP server
<-> owner-only local IPC (Unix socket on macOS, named pipe on Windows)
<-> `nova browser-host` Native Messaging mode
<-> Chrome `runtime.connectNative` long-lived port
<-> MV3 service worker
<-> per-tab/per-frame content scripts
Native side
Add a dedicated nova browser-host mode that implements Chrome Native Messaging framing over stdin/stdout. Protocol stdout is reserved exclusively for framed JSON; diagnostics go to stderr.
Register a native-host manifest with an exact allowed_origins entry for the published extension ID. Never use a wildcard extension origin.
Add idempotent nova browser-extension install-host, uninstall-host, and status commands for supported Chrome-family browsers/platforms. Report each browser registration path and extension/host version.
Route requests from a running Nova MCP server to the Chrome-launched host through per-user local IPC. Do not expose an unauthenticated localhost HTTP/WebSocket port.
Authenticate/claim the MCP-to-host session with an owner-only runtime token or equivalent lease, bound to one user and one active Nova session. Define deterministic behavior when multiple Nova servers exist; never let the extension broadcast page data to every process.
Use request IDs, deadlines, cancellation, bounded payloads, protocol version negotiation, heartbeats, and reconnect/backoff. Native Messaging messages must remain below Chrome's response-size limit; paginate/truncate snapshots rather than emitting an unbounded DOM.
Extension side
Add a self-contained Manifest V3 extension under a reviewed repository path such as extension/chrome/.
A service worker owns the Native Messaging port and routes structured commands to the exact tabId, frameId, and documentId.
Content scripts are packaged with the extension; do not download or evaluate remote code and do not accept arbitrary JavaScript from Nova/LLM.
Support the top document, permitted child frames, and open shadow roots. Every node is frame/document scoped.
Keep incognito and file:// access off unless the user explicitly enables them in Chrome.
Restricted surfaces (chrome://, Chrome Web Store, extension pages, inaccessible PDF/plugin surfaces, denied origins) return a typed unsupported/permission result.
Permission model
Use least privilege by default:
nativeMessaging, scripting, and activeTab for explicit per-tab enablement.
Optional host permissions for “allow this site” and an explicit user opt-in for broader browsing. Do not silently ship persistent <all_urls> access as the only mode.
Show connection/site-access state in the extension action: disconnected, connected but site denied, enabled for this tab/site, and unsupported page.
Revocation must immediately remove content scripts where possible, invalidate snapshots, and stop returning page data.
chrome.debugger is not an MVP dependency. It provides CDP Accessibility/Input domains, but requires the powerful non-optional debugger permission. If DOM activation plus a real Nova foreground click cannot cover required cases, evaluate a separately consented extension variant/follow-up instead of silently adding debugger access.
Versioned provider protocol
At minimum, define typed messages for:
hello / capabilities / version negotiation
list_targets and exact tab/window selection
snapshot
activate
focus
set_value
scroll_into_view
cancel
navigation/document invalidation events
A snapshot response should fit #22's neutral DTO while retaining browser identity:
include visible semantic text and controls, not raw innerHTML or the entire DOM;
implement/test accessible-name, role, value, description, and state derivation rather than relying only on textContent;
preserve deterministic reading/tree order and frame ancestry;
include links/headings/static text/form values/selection/checked/expanded/disabled/focused state where safe;
redact password fields and sensitive values before filtering, tracing, caching, or IPC;
bound node count, depth, text length, and total payload, with explicit partial/truncated coverage;
do not leak cookies, storage, network bodies, hidden DOM, or arbitrary page globals.
Snapshot identity and stale safety
Node references are ephemeral and must be bound to (browser instance, tabId, frameId, documentId, snapshot generation).
Before every action, the content script must verify that:
the exact tab/frame/document still exists;
the node handle is still connected and visible;
its role/name/actionability still match the captured fingerprint;
the page has not navigated to a different document/origin.
Navigation, content-script restart, permission revocation, or an invalid handle must fail closed with stale_snapshot; Nova then calls ax_read again. Never re-resolve an old node by first matching label text, and never redirect a command to whichever tab is currently frontmost.
Action ladder for Chrome page content
ax_read returns a fresh extension-backed browser node.
activate(snapshot_id, node_id) targets that exact tab/frame/document and revalidates the node.
Prefer a structured DOM action appropriate to the element (click, focus, form-control change, link activation), with an explicit result and post-action document/state observation.
If the site requires trusted input, return needs_trusted_input plus a freshly validated visible rectangle and frame-to-main-viewport mapping.
Nova activates the exact browser window/tab, converts CSS-pixel bounds safely, and performs a real foreground center click; then re-reads through the extension.
Do not report success merely because HTMLElement.click() returned. Confirm an observable state/navigation/focus change when the requested action expects one; otherwise return no_observed_effect and let the agent choose the next safe route.
Typed failure/fallback reasons
At minimum:
extension_not_installed
native_host_not_registered
bridge_disconnected
protocol_mismatch
site_permission_required
unsupported_scheme
restricted_page
tab_not_found
frame_not_accessible
stale_snapshot
ambiguous_target
needs_trusted_input
no_observed_effect
timed_out
partial
These feed #22's fallback policy. Missing site permission is an explicit user-consent state, not evidence that the page has no semantics.
Security invariants
No arbitrary JavaScript/eval/code payload from MCP, LLM, or a web page.
No externally_connectable web origins unless separately justified; ordinary pages must not be able to command Nova.
Validate every message at the service-worker, native-host, and MCP boundaries. Treat content-script messages as untrusted.
Exact extension origin allowlist in the native-host manifest.
Owner-only local IPC and session claim; no network listener exposed to the LAN or other users.
Page data is returned only in response to a scoped Nova request; no continuous bulk scraping by default.
Redact secrets before they cross the content-script boundary.
Actions are limited to the selected tab/site permission and structured verbs.
Surface a visible connected/enabled indicator and provide one-step disconnect/revoke controls.
Acceptance criteria
A packaged MV3 extension and versioned native-host protocol exist, with macOS and Windows host registration/status/uninstall flows.
The extension connects only to Nova's exact registered Native Messaging host; Nova exposes no unauthenticated localhost HTTP/WebSocket endpoint.
ax_read automatically uses provider=chrome_extension for permitted Chrome page content and OS AX/UIA for browser chrome, returning one coherent snapshot contract.
A fixture page returns buttons, links, headings, labels, static text, field values, and widget states in deterministic order without a screenshot.
Permitted child frames and open shadow roots are represented with frame/document-scoped IDs; inaccessible frames are reported as partial coverage.
Password/sensitive values never appear in snapshot output, logs, traces, caches, or native messages.
Activation targets the exact tab/frame/document even when another Chrome tab/window is frontmost.
Navigation and DOM replacement invalidate stale references; old node IDs fail closed.
Same-label nodes return distinct candidates and are never resolved by “first substring match.”
DOM activation reports no_observed_effect or needs_trusted_input when appropriate; Nova can use the fresh element bounds for a verified real click and then re-read.
Default permissions are least-privilege; broader site access is explicit, revocable user consent. Incognito/file access remains opt-in.
The release/plugin prompt describes this as an internal semantic provider and still tells the model to use ax_read, not to inject JavaScript or guess coordinates.
The existing AppleScript web click remains a bounded compatibility fallback during migration and is not claimed as equivalent to the extension provider.
Deterministic test plan
Protocol tests: framing, version mismatch, request IDs, cancellation, timeouts, reconnect, payload limits, malformed/untrusted messages, multiple Nova processes.
Extension unit tests: visibility, accessible names/roles/state, same-label nodes, password redaction, open shadow roots, document invalidation, action/no-effect classification.
Delivery tracker (2026-10-03)
This remains a tracking Issue. The merged developer bridge includes explicit selected-tab/site consent, bounded visible text, open-shadow semantics, safe value receipts, authenticated Windows transport, per-user Windows host registration, and opt-in proven same-origin child reads and DOM activation, and bounded top/child activation effect receipts. Explicit
ax_read(target="paired_page")and canonicalax_activatenow use the consented page; automatic native-window association, mixed browser-chrome/page snapshots and full packaged-browser acceptance remain pending. The original acceptance criteria below are unchanged.Merged and closed acceptance children:
[nova] feat: scope browser content access to explicit consent #56 / PR feat: require explicit browser page access (#56) #58: explicit tab/site permission and revocation.
[nova] feat: include visible static text in browser snapshots #64 / PR feat: read visible browser static text (#64) #65: bounded visible static text, with real owned Chrome acceptance.
[nova] feat: read selected-page open shadow semantics #66 / PR feat: read selected-page open shadow semantics (#66) #68: selected-page open shadow semantics, with real owned Chrome acceptance.
[nova] fix: prepare browser value receipts before HTTP mutations #67 / PR fix: prepare browser value receipts before mutation (#67) #69: HTTP denial before mutation and exact loopback Unicode value receipts, with real owned Chrome acceptance.
[nova] feat: add authenticated Windows Chrome bridge transport to managed MCP #72 / PR feat: add authenticated Windows Chrome bridge (#72) #73: authenticated Windows native pipe and configured managed MCP. Eight fresh CI jobs passed, including genuine Windows transport, ACL, framing, launched-host, reconnect and managed shutdown execution.
[nova] feat: register Windows Chrome native host per user #74 / PR feat: register Windows Chrome native host per user (#74) #75: per-user Windows install/status/uninstall, adjacent copied-host configuration and real managed-MCP round trip. Eight fresh CI jobs passed, including four actual private-HKCU registration fixtures.
[nova] feat: add proven same-origin read-only child frames #76 / PR feat: add proven read-only child frames (#76) #77: explicit per-pairing metadata consent, browser/owner-proven visible same-origin read-only child semantics, partial exclusions and shared budgets. Real owned Chrome/native-host frame, mutation-denial and four lifecycle paths passed; the full extension suite passed 234 tests, independent review passed, and eight exact-head CI jobs passed. Accepted source merge is
d920e7d6b0448a7a7097325483a2c45396ee8b7f.[nova] fix: verify DOM activation effects before success #78 / PR fix: verify DOM activation effects (#78) #79: bounded top-document DOM activation effect confirmation, typed inconclusive outcomes and inspection guidance, shared privacy/deadline budgets and one dispatch without replay. Twenty-two fresh actual owned Chrome/native-host cases, 298 extension tests and complete independent review passed; all eight exact-head source CI jobs passed, and the merged master CI also passed. Accepted source merge is
d25ef59d0be11b4cfb342fe89bb2cf1651a53d04.[nova] feat: activate exact proven same-origin child controls #80 / PR feat: activate exact same-origin child controls (#80) #82: exact browser/owner-proven same-origin child DOM activation, fresh child fingerprint and one consumed aggregate across top/children; an introduced stale-success race was reproduced and repaired using the existing aggregate identity. All 51 fresh actual owned Chrome/native-host cases, 343 full/93 focused tests and complete independent review passed; all eight exact-head source CI jobs and all eight merged-master jobs passed. Accepted source merge is
e0e55a949bda3a0664524eabc88e97fdc88c82bb.[nova] fix: revalidate captured top-document activation targets #81 / PR fix: revalidate captured top activation targets (#81) #83: revalidate the exact captured top-document activation target against its existing private role/name/type fingerprint and current bounded actionability before dispatch. All ten changed-target modes dispatch zero times; valid exact targets, own-handler public label/state and fresh reads remain usable. The same twelve regressions reproduced ten stale dispatches before repair and passed after repair; 355 full extension tests and 15 fresh actual owned Chrome/native-host cases passed. Complete independent review and all eight exact-head source CI jobs plus all eight merged-master jobs passed. Accepted source merge is
910deb24b319f7102387c92e4064a93aacff198c.[nova] feat: retain OS process ownership evidence for the Chrome bridge #84 / PR feat: retain Chrome bridge process ownership evidence (#84) #86: broker-observed native-host/browser process ownership in status, replacing successful worker ownership and stripping forged ownership from error objects while preserving payloads, receipts and pairing revocation. Forty-two native tests and 65 actual Windows tests passed; the three forged status regressions failed before the repair and passed afterward. Fresh owned macOS Chrome acceptance independently matched process PID/start/path hashes, kept 19 terminal receipts (17 successful and two expired pairing attempts), and proved release plus active-pair disconnect/reconnect/re-pair. Complete independent source review and all eight exact candidate checks passed. All eight actual-master checks passed after a failed-only Rust-download retry retained separately in [nova] ci: record macOS rustup network timeout after #86 #87. Accepted source merge is
19dfeaa1e49fd186202f731c92d2f7ec9b6539af; native-window/page association remains unproven.Each child passed complete independent review and its exact-head CI/acceptance gates. Windows execution uses owned private registry/temp/process fixtures; actual Chrome discovery and packaged GUI are separate. Proven same-origin reads/DOM activation remain partial coverage and do not complete the parent's broader permitted-frame, browser/window identity, canonical routing or trusted-input criteria.
Remaining slices receive focused child Issues before implementation:
ax_readprovider routing.Related #35 owns popup freshness and #36 owns signed distribution under Zenith#185. Do not duplicate that work or equate isolated developer fixtures with production distribution. Source #34/#70 is merged, with manual macOS desktop/cursor acceptance still pending permissions. Zenith#318 / PR#319 delivers the accepted Nova source gitlink at Zenith
f45d83bd188e17bae9b2d2f8b894a2b9faeecd0c; both exact-head root PR guards and full independent pointer review passed. The merged-main pointer check passed; the PR-only notes check skips on push. Local root/Nova are synchronized; Bamboo/Bodhi dirty gitlinks and all seven unrelated primary repositories remain unchanged. The already-accepted upstream release config from the fresh pointer base was included by the normal root fast-forward.There is no monolithic implementation branch for this parent. Every child retains its own bounded scope, estimate, tests and PR. Keep #23 open and all original acceptance boxes unchanged until actual parent-level evidence exists.
32bf4d90129e944f15e3a66b9e0ca1c72efe0da2. This page-only migration does not claim automatic native-window association or complete the original parent criteria.Summary
Add a Manifest V3 Chrome/Chromium extension plus a native Nova bridge so browser page content becomes a reliable semantic provider for Nova's
ax_read/ node-activation contract from #22.For a Chrome page, Nova should prefer the extension-backed DOM/ARIA snapshot and action channel for page content, while continuing to use operating-system Accessibility for browser chrome such as tabs, toolbar, and address bar. If the extension is absent, disconnected, lacks permission, or cannot instrument the page, Nova must report that reason and follow #22's native-AX → OCR → focused-screenshot fallback rather than pretending the page was empty.
This is a separate Issue from #22 because it introduces a distributable browser extension, Native Messaging registration/lifecycle, tab/frame identity, host permissions, a versioned protocol, and a new security boundary.
Code review: why the current bridge is insufficient
Current
master(ff840350) already recognizes that macOS Chrome AX actions are unreliable:src/server.rs::click_cached_marktriesElementHandle::try_web_clickbefore AX and coordinate fallback.src/platform/mac/elements/webclick.rsruns an AppleScript command againstactive tab of front window, injecting a fixeddocument.querySelectorAll(...)/document.elementFromPoint(...).click()snippet.AXPresscan return success while doing nothing on web content.That workaround is useful, but it is not a browser integration contract:
ax_read.HTMLElement.click()does not satisfy every trusted-user-gesture flow. When it fails, Nova lacks a browser-verified fresh element rectangle and an explicitneeds_trusted_inputresult.Relationship to #22
#22 owns the platform-neutral
ax:readcapability, canonicalax_readtool, snapshot/node model, action routing, and fallback policy.This Issue owns one provider behind that contract:
The model should normally keep calling
ax_readand activating returned nodes. Provider selection belongs inside Nova; the prompt should not require the model to choose AppleScript, extension, or AX manually.Proposed architecture
Native side
nova browser-hostmode that implements Chrome Native Messaging framing over stdin/stdout. Protocol stdout is reserved exclusively for framed JSON; diagnostics go to stderr.allowed_originsentry for the published extension ID. Never use a wildcard extension origin.nova browser-extension install-host,uninstall-host, andstatuscommands for supported Chrome-family browsers/platforms. Report each browser registration path and extension/host version.Extension side
extension/chrome/.tabId,frameId, anddocumentId.file://access off unless the user explicitly enables them in Chrome.chrome://, Chrome Web Store, extension pages, inaccessible PDF/plugin surfaces, denied origins) return a typed unsupported/permission result.Permission model
Use least privilege by default:
nativeMessaging,scripting, andactiveTabfor explicit per-tab enablement.<all_urls>access as the only mode.chrome.debuggeris not an MVP dependency. It provides CDP Accessibility/Input domains, but requires the powerful non-optionaldebuggerpermission. If DOM activation plus a real Nova foreground click cannot cover required cases, evaluate a separately consented extension variant/follow-up instead of silently adding debugger access.Versioned provider protocol
At minimum, define typed messages for:
hello/capabilities/ version negotiationlist_targetsand exact tab/window selectionsnapshotactivatefocusset_valuescroll_into_viewcancelA snapshot response should fit #22's neutral DTO while retaining browser identity:
{ "provider": "chrome_extension", "snapshot_id": "ephemeral", "target": { "browser": "chrome", "window_id": 3, "tab_id": 41, "frame_id": 0, "document_id": "...", "url": "https://example.test/", "title": "Example" }, "coverage": "complete", "nodes": [ { "id": "document-scoped-node", "role": "button", "name": "Save", "value": null, "states": { "enabled": true, "focused": false }, "actions": ["activate"], "bounds": { "space": "frame_css_px", "x": 12, "y": 40, "w": 80, "h": 32 } } ] }Requirements:
innerHTMLor the entire DOM;textContent;Snapshot identity and stale safety
Node references are ephemeral and must be bound to
(browser instance, tabId, frameId, documentId, snapshot generation).Before every action, the content script must verify that:
Navigation, content-script restart, permission revocation, or an invalid handle must fail closed with
stale_snapshot; Nova then callsax_readagain. Never re-resolve an old node by first matching label text, and never redirect a command to whichever tab is currently frontmost.Action ladder for Chrome page content
ax_readreturns a fresh extension-backed browser node.activate(snapshot_id, node_id)targets that exact tab/frame/document and revalidates the node.click, focus, form-control change, link activation), with an explicit result and post-action document/state observation.needs_trusted_inputplus a freshly validated visible rectangle and frame-to-main-viewport mapping.Every result reports its route, for example:
chrome_domchrome_dom_then_navigationchrome_trusted_input_fallbacknative_axocr_centervisual_coordinateDo not report success merely because
HTMLElement.click()returned. Confirm an observable state/navigation/focus change when the requested action expects one; otherwise returnno_observed_effectand let the agent choose the next safe route.Typed failure/fallback reasons
At minimum:
extension_not_installednative_host_not_registeredbridge_disconnectedprotocol_mismatchsite_permission_requiredunsupported_schemerestricted_pagetab_not_foundframe_not_accessiblestale_snapshotambiguous_targetneeds_trusted_inputno_observed_effecttimed_outpartialThese feed #22's fallback policy. Missing site permission is an explicit user-consent state, not evidence that the page has no semantics.
Security invariants
externally_connectableweb origins unless separately justified; ordinary pages must not be able to command Nova.Acceptance criteria
ax_readautomatically usesprovider=chrome_extensionfor permitted Chrome page content and OS AX/UIA for browser chrome, returning one coherent snapshot contract.no_observed_effectorneeds_trusted_inputwhen appropriate; Nova can use the fresh element bounds for a verified real click and then re-read.ax_read, not to inject JavaScript or guess coordinates.Deterministic test plan
read_ui/click_mark, macOS native AX, Windows UIA, OCR, screenshot, Linux headless introspection, plugin packaging/signing.Non-goals
chrome.debuggerin the first implementation.Primary references
chrome.scriptingframe/document targeting: https://developer.chrome.com/docs/extensions/reference/api/scriptingactiveTabpermission: https://developer.chrome.com/docs/extensions/develop/concepts/activeTab