Capability Tiers
Overview
Section titled “Overview”PCP does not require every application to support the same level of integration. Instead, it assigns each application a capability tier based on what that application can declare about its own interface. The result is a progressive-fidelity model: deeper integration yields richer, more precise capabilities, but every application on the system receives at least basic control through PCP.
The three tiers exist on a spectrum. Tier 1 applications ship a cryptographically signed capability manifest and expose typed, domain-specific operations directly. Tier 2 applications rely on the OS accessibility infrastructure, letting PCP derive semantic capabilities from structural patterns in their widget trees. Tier 3 applications expose nothing beyond surface metadata, so PCP falls back to window-level input simulation.
Tier assignment is fully automatic. PCP evaluates each application at install time and on every session start, populates the capability registry, and makes the results available to System Intelligence without any developer intervention. The developer can opt into a higher tier by providing more integration, but no application is excluded from the PCP ecosystem.
graph TD
subgraph Tiers
T1["Tier 1: SI-Native"]
T2["Tier 2: Accessibility Bridging"]
T3["Tier 3: Universal Fallback"]
end
T1 -->|"signed manifest, typed operations"| SI["System Intelligence"]
T2 -->|"derived from accessibility trees"| SI
T3 -->|"surface metadata, input simulation"| SI
T1 -.->|"most precise"| Q1["Highest fidelity"]
T2 -.->|"structural semantics"| Q2["Medium fidelity"]
T3 -.->|"positional only"| Q3["Basic fidelity"]
Tier 1: SI-Native
Section titled “Tier 1: SI-Native”Tier 1 is the highest integration level. An application at this tier ships a cryptographically signed CapabilityManifest alongside its binary. The manifest declares the semantic operations the application supports, the data types those operations accept and return, and the resource paths they act on. The compositor verifies the manifest’s signature at load time and registers the declared capabilities directly into the PCP capability registry.
The manifest is not a configuration file that SI reads and interprets. It is a compiled declaration that maps directly to Rust trait implementations inside the compositor. When SI invokes a capability on a Tier 1 application, the invocation is a typed function call. Parameters are checked at compile time, return values are typed, and failures propagate through the same error-handling paths the compositor uses internally.
The CapabilityHandler trait
Section titled “The CapabilityHandler trait”Each operation in the manifest corresponds to an implementation of the CapabilityHandler trait:
pub trait CapabilityHandler { type Input; type Output;
fn invoke(&self, input: Self::Input) -> Result<Self::Output, CapabilityError>;}The compositor maintains a dispatch table that maps capability identifiers to handler instances. When SI calls mail.compose, the dispatch table resolves the identifier to the registered CapabilityHandler for that application, deserializes the input type (if it arrived over the wire), and calls invoke. The typed result flows back to SI through the same path.
Manifest example
Section titled “Manifest example”A minimal manifest for an email client might declare:
[manifest]app_id = "com.example.mailclient"signer = "keys/example.pub"
[[capabilities]]id = "mail.compose"description = "Open a new compose window with pre-filled fields"input_type = "ComposeRequest"output_type = "ComposeResult"access = "read-write"The input_type and output_type fields reference schema definitions that the compositor validates against the registered handler’s generic parameters. If the types do not match, the manifest is rejected at load time.
Script injection is forbidden
Section titled “Script injection is forbidden”Tier 1 explicitly prohibits script injection and DOM manipulation. An application’s capabilities must operate on its own data model through typed handlers, not by injecting JavaScript, evaluating arbitrary code, or manipulating UI element trees from outside the application’s process. This restriction exists for three reasons.
First, auditability. Every capability invocation in PCP is logged with a timestamp, target, parameters, and result. Script injection breaks that guarantee because the injected code can perform arbitrary operations that the audit trail never captures.
Second, determinism. Typed handlers have fixed behavior defined at compile time. Script injection introduces dynamic, unpredictable execution paths. The compositor cannot reason about what an injected script will do, and neither can SI.
Third, trust. The manifest’s cryptographic signature binds the declared capabilities to a specific identity. If the application could inject arbitrary code, the signature would be meaningless. The signature guarantees that the declared operations are the only operations available through the PCP interface.
Developer effort
Section titled “Developer effort”Tier 1 requires the most developer work: writing a manifest, implementing the handler trait, and managing the signing pipeline. In return, it provides the richest possible integration. SI can read and write application data, invoke domain-specific operations with typed parameters, and receive structured results. No probing, no heuristics, no approximation.
Tier 2: Accessibility Bridging
Section titled “Tier 2: Accessibility Bridging”Most desktop applications never ship a capability manifest. They expose their interfaces through standard toolkit widgets that participate in the OS accessibility infrastructure: AT-SPI2 on Linux, MSAA and UI Automation on Windows, and their equivalents on other platforms. Tier 2 targets these applications.
How it works
Section titled “How it works”The accessibility adapter walks each application’s accessibility tree, extracts element roles, states, text content, and action sets, and maps them to the PCP Element model. The result is a semantic representation of the application’s interface that SI can query and act on without any developer cooperation.
The mapping from accessibility tree to PCP Element is largely structural. AT-SPI2 roles map to PCP roles (an ROLE_PUSH_BUTTON node becomes a Button element). States map directly (the STATE_FOCUSABLE flag becomes the focusable property). Text content, value ranges, selection boundaries, and caret positions transfer without transformation.
The harder problem is deriving capabilities from raw structural data. An accessibility tree tells you that a button exists, what it is labeled, and what actions it supports. It does not tell you that clicking that button composes a new email. That gap is where pattern recognition enters.
Pattern recognition
Section titled “Pattern recognition”PCP maintains a set of application category templates. Each template defines the structural pattern expected for a known application type, the roles that must be present, and the approximate layout those roles should occupy relative to one another.
When the accessibility adapter finishes walking an application’s tree, PCP scores the result against each template. The scoring system is straightforward:
| Condition | Score |
|---|---|
| Expected role present in expected location | +1.0 |
| Expected role present in unexpected location | +0.3 |
| Required role missing | -2.0 |
The sum produces a confidence value between 0 and the total expected roles. If that value exceeds the match threshold (0.6), the application is assigned the corresponding category and its derived capabilities are registered.
Application categories
Section titled “Application categories”| Category | Detection Pattern | Derived Capabilities |
|---|---|---|
| Email Client | message_list + search_bar + compose_button + folder_tree |
mail.search, mail.compose, mail.reply |
| Text Editor | document + toolbar + find_replace |
editor.read, editor.edit, editor.save |
| Web Browser | address_bar + tabs + content_area |
browser.navigate, browser.read_page |
| File Manager | directory_tree + file_list + path_bar |
files.list, files.copy, files.rename |
| Terminal | text_buffer + shell_prompt |
terminal.run_command, terminal.read_output |
The “expected location” in the scoring system refers to the role’s position in the accessibility tree hierarchy, not its pixel coordinates. A compose button nested inside a toolbar under the main window is in the expected location. The same button floating in an unrelated dialog is in an unexpected location and receives a lower score.
Adapter lifecycle
Section titled “Adapter lifecycle”The Tier 2 adapter follows a four-phase lifecycle for each application:
-
Detection. At session start, the adapter queries installed applications through their
.desktopfiles (on Linux) or equivalent platform metadata. This static detection identifies the application’s category, executable, and toolkit before the application launches. -
Matching. When the application starts, the adapter walks its accessibility tree and scores it against the category templates. If the match exceeds the confidence threshold, the category is confirmed and derived capabilities are registered.
-
Derivation. PCP maps the matched category to its capability set. Each derived capability is backed by the accessibility adapter’s element model. Invoking
mail.composeactivates the compose button in the application’s tree. -
Execution. SI invokes derived capabilities through PCP Core. The adapter resolves the capability to a specific element action, fires the action, and returns the result. No script injection, no input simulation. The action travels through the accessibility framework’s own activation mechanism.
If an application’s interface changes at runtime (a panel is closed, a layout is rearranged), the adapter re-scores the tree and updates the capability set accordingly.
Tier 3: Universal Fallback
Section titled “Tier 3: Universal Fallback”Not every application exposes an accessibility tree. Games render their interfaces through custom graphics engines. Scientific visualization tools draw directly to hardware surfaces. Legacy applications built on frameworks that predate modern accessibility APIs may expose nothing beyond a raw window.
Tier 3 handles these cases. The adapter operates on compositor surface metadata alone: window position, size, title, z-order stacking, and state flags (minimized, maximized, fullscreen). No semantic element access is available at this tier.
What works
Section titled “What works”Window management is fully functional. SI can focus, minimize, maximize, move, resize, close, and tile Tier 3 windows. It can query which windows are visible, which workspace they occupy, and their relative z-order. These operations rely on compositor state, not application cooperation, so they work regardless of what the application renders.
What does not work
Section titled “What does not work”Element-level interaction is unavailable. SI cannot read text content, click specific buttons, or identify UI roles inside a Tier 3 window. Interaction collapses to synthetic input simulation: the adapter generates keystroke and pointer events targeted at the window’s surface coordinates. This is the same mechanism used by external automation frameworks, and it carries the same fragility. If the application moves a button, the coordinate target misses. If the application renders text as pixels rather than through a text API, the content is invisible to SI.
Why this is acceptable
Section titled “Why this is acceptable”Tier 3 is the fallback of last resort, and PCP makes no pretense that it provides rich interaction. What it provides is ecosystem inclusion. A game, a rendering tool, or a legacy application still appears in the desktop model. SI knows it exists, can manage its window, and can switch to it when the user requests. The application participates in the PCP ecosystem at a basic level, and the user retains control over it alongside Tier 1 and Tier 2 applications.
Tier Comparison
Section titled “Tier Comparison”| Dimension | Tier 1: SI-Native | Tier 2: Accessibility Bridging | Tier 3: Universal Fallback |
|---|---|---|---|
| Detection method | Signed manifest at load time | Static .desktop scan + runtime accessibility walk |
Compositor surface enumeration |
| Capability source | Developer-declared handlers | Pattern-matched derivation from accessibility tree | Window management only |
| Semantic depth | Full typed operations on application data model | Structural roles and actions from accessibility API | Window title, geometry, state flags |
| Interaction method | Direct trait invocation | Accessibility action activation | Synthetic input simulation |
| Developer effort | High (manifest + handler + signing) | None | None |
| Example applications | Purpose-built PCP applications | GTK, Qt, Electron, Firefox apps | Games, custom renderers, legacy software |
Adapter State Machine
Section titled “Adapter State Machine”Each adapter instance follows a defined lifecycle state machine. Understanding this lifecycle is relevant for implementing custom adapters and for debugging capability registration issues. The full specification of adapter states is covered in the capability registry documentation.
The states, in brief:
stateDiagram-v2
[*] --> Idle
Idle --> Detecting : app installed / session start
Detecting --> Matched : confidence > 0.6
Detecting --> Idle : confidence < 0.6
Matched --> Active : capabilities registered
Active --> Stale : interface change detected
Stale --> Detecting : re-scan triggered
Active --> Idle : app closed
Idle. The adapter has no work to do. The application is not running or has not been detected.
Detecting. The adapter is scanning the application’s accessibility tree (Tier 2) or surface metadata (Tier 3) and scoring it against category templates.
Matched. The application has been assigned a category with sufficient confidence, but capabilities have not yet been registered with PCP Core.
Active. Capabilities are registered and available for SI invocation. The adapter monitors for structural changes.
Stale. The application’s interface has changed enough that the previous match may no longer be valid. The adapter re-enters the detection phase without deregistering existing capabilities.
When an adapter transitions from Active back to Idle (application closed), all capabilities derived from that application are removed from the registry. SI receives a capability-removal event and can update its desktop model accordingly.