System access is a host capability boundary. It is separate from model tool approval, workspace permission rules, account credentials and provider authorization. The product has one capability registry, one live report, one explicit setup path, one wait representation and one recovery policy. A status read never opens a native prompt. A model or a remote client cannot grant an operating-system capability.
The base runtime used two hard-coded macOS rows, screen_recording and accessibility. The backend report, native probe, request route, GUI preflight and Web settings each contained part of that list, while package declarations for other categories lived separately. This created drift and allowed a reconnect to look like an unsolicited permission request.
The implemented registry removes those duplicated capability definitions and keeps ordinary chat, browser and headless use independent from optional desktop access. The old two-capability API remains wire-compatible; its rows are generated by the registry. Package usage descriptions, entitlements, report schema, identity metadata, GUI preflight, settings UI and wait manifests now consume the same declarations.
| Reference | Adopted rule | Boundary |
|---|---|---|
| Apple Screen & System Audio Recording | macOS owns the grant and the user controls it in System Settings. | The product can open the relevant pane and verify the executing identity; it cannot silently enable the grant. |
| AXIsProcessTrustedWithOptions | Accessibility is queried separately and can be requested only from an explicit local-owner action. | Trust is for the named runtime executor; another application or an anonymous Python process is not evidence. |
| Apple privacy controls | Each privacy category has its own consent and revocation lifecycle. | “Configured in the plist” and “signed with an entitlement” are prerequisites, not grants. |
| macOS file and access controls | File access is reported as an operation-specific capability. | Full Disk Access cannot be inferred from a successful read of one path and is never requested as a blanket workaround. |
| Electron systemPreferences | Query and request are separate operations. | Electron APIs do not remove macOS consent or target-specific Apple Events authorization. |
Linux portals and Windows desktop integrity rules remain platform-specific. The registry represents their state without pretending that a macOS setting exists on those platforms. Browser and VM surfaces use their own provider/session boundary and do not inspect local macOS permissions.
openprogram.system_access owns an immutable registry. Every entry has a stable id, category, display label, platform, required/optional policy, target identity, non-prompting check, explicit request mode, settings destination, package declaration, operation mappings, and recovery policy. Backend report, CLI/TUI doctor, HTTP setup, Web settings, wait manifests and tests consume this registry instead of defining capability ids independently. All macOS native checks and requests run through the signed runtime bundle identity ai.openprogram.runtime; a source checkout may fall back to its development interpreter, but an installed app never registers a bare python3 process.
| Field | Meaning |
|---|---|
id | Stable protocol id, for example screen_recording, accessibility, apple_events, calendar, reminders, file_read, file_write, microphone and camera. |
subject | Identity checked by the platform: runtime, containing_app, target_app, user_selected_path or provider_session. |
check | Non-prompting probe. It returns granted, not_granted, unknown, unavailable or unsupported. |
request_mode | native for a supported OS request, settings for a settings-only capability, targeted when a target application must be supplied, operation when only the real operation can verify it, and none when the platform has no request API. |
settings | Fixed, capability-specific System Settings URL or a documented instruction. It is opened only after an owner clicks the action. |
identity | Bundle id and designated requirement, or provider/path identity. Anonymous python3, node and stale cache paths never become OpenProgram identities. |
operations | Tool and operation names that require the capability. GUI desktop requires screen recording and accessibility; browser, VM and ordinary CLI operations do not. |
The registry is validated at import time: ids are unique, every native entry has a non-prompting check and an explicit request style, scoped entries specify their status semantics, every settings action has a fixed destination, and every operation reference points to a declared capability. Package usage descriptions and entitlements are checked against the same ids in build tests.
Each report contains schema, platform, host, executing identity, timestamp, and a capability array. Rows contain id, category, status, detail, instruction, request mode, settings availability, required operations, and recovery metadata. Status means:
GET /api/system/access returns the registry-derived report. POST /api/system/access/setup is the owner-only, loopback-only first-run action: it requests every registered native runtime capability through the signed runtime and returns one consolidated report. POST /api/system/access/{id} is the explicit per-row fallback; it rechecks, optionally performs the declared native request, and returns a fresh row. open_settings=true only opens the declared settings destination and never claims a grant. Existing /waits records use the same ids and schema. Responses are no-store and contain no secrets.
system_access wait only for missing required capabilities. Browser and VM operations bypass this host check. The wait stores the original checkpoint and continues the same execution after every required row is granted.Ordinary status reads, startup reconciliation, retries and duplicate events never run tccutil and never reset another application. A verified stale receipt can authorize one explicit migration for the fixed OpenProgram bundle identity; the marker is written before the OS call and prevents loops. Unverified code, unknown checks, unchanged requirements, Accessibility migration and all other applications require the user to use System Settings. The named runtime and containing application retain stable bundle ids and a persistent local signing requirement. A build or cache path labelled python3 or node is not an accepted identity.
Third-party Apple Events authorization is target-specific. Calendar and Reminders use EventKit-style category consent when the native backend supports it. File access is scoped to the user-selected path or security-scoped bookmark. Microphone and camera are declared and requested only by operations that use them. The product cannot pre-authorize an application it has never targeted, a path the user has never selected, or a permission the user has revoked.
Only the local owner on the execution host can request or open settings. Loopback and Origin checks remain mandatory; forwarded requests and remote clients are rejected. The model can describe a missing capability but cannot invoke the setup endpoint. Native probes run in a fresh bounded process, share one report per reconciliation pass, and do not enumerate screen contents. Requests are serialized per executor. Wait resolution is guarded by execution id, generation, checkpoint version and cancellation state. A failed probe keeps the wait open; a terminal or cancelled execution cannot resume.
Old clients may continue sending screen_recording and accessibility. The API keeps those ids and adds registry metadata. Existing receipts are read with the legacy screen-recording shape. Unknown ids return a client error without opening settings. Existing permission rules and Auto mode are unchanged. No additional application profile, worker or port is created.
This document is the canonical design for the unified registry. The unified registry, native EventKit/AVFoundation checks and requests, schema/versioned report, identity metadata, package consistency checks, explicit setup UI, no-auto-request recovery, operation preflight parity, and terminal handling for unavailable or unsupported desktop access are implemented. Remaining acceptance is installation-specific: verify the installed default /Applications/OpenProgram.app on port 18100 and its current macOS grants; those grants remain controlled by macOS.