Application
Overview
Section titled “Overview”Every running process with a Wayland connection to the compositor gets an Application primitive. This is the top-level container for all PCP data about a process: its identity, its capability tier, the surfaces it owns, and its current runtime state.
The Application primitive exists for the lifetime of the process. When a process connects to the compositor, it appears. When it disconnects, the primitive is removed.
JSON Schema
Section titled “JSON Schema”{ "$schema": "http://json-schema.org/draft-07/schema#", "title": "Application", "type": "object", "required": ["id", "process", "surface_tree", "capability_tier", "state"], "properties": { "id": { "type": "string", "pattern": "^app:wl-[0-9]+$", "description": "Unique identifier, stable while the app is running. Derived from Wayland client ID." }, "desktop_id": { "type": ["string", "null"], "description": "From .desktop file (best effort). E.g., 'org.gnome.Evolution'" }, "display_name": { "type": ["string", "null"], "description": "Human-readable app name from .desktop file Name key." }, "icon_name": { "type": ["string", "null"], "description": "Icon name from .desktop file Icon key." }, "process": { "type": "object", "required": ["pid", "executable"], "properties": { "pid": { "type": "integer", "description": "Process ID" }, "executable": { "type": "string", "description": "Absolute path to executable" }, "cmdline": { "type": "array", "items": { "type": "string" }, "description": "Full command line arguments" }, "cgroup": { "type": ["string", "null"], "description": "Cgroup path, useful for identifying sandboxed apps (Flatpak, etc.)" }, "sandbox": { "type": ["string", "null"], "enum": [null, "flatpak", "snap", "bubblewrap", "firejail"], "description": "Sandbox technology, if any." } } }, "surface_tree": { "type": "array", "items": { "type": "string", "pattern": "^surf:[a-z0-9-]+$" }, "description": "IDs of top-level surfaces (windows) owned by this app." }, "capability_tier": { "type": "string", "enum": ["native", "atspi2", "structural", "minimal"], "description": "Deterministic tier based on probing." }, "capability_manifest": { "type": ["object", "null"], "description": "For Tier 1 (native) apps only. Full CapabilityManifest." }, "derived_capabilities": { "type": ["array", "null"], "items": { "$ref": "Capability" }, "description": "For Tier 2 apps only. Capabilities derived by the adapter." }, "state": { "type": "object", "required": ["focused", "has_visible_surface", "started_at"], "properties": { "focused": { "type": "boolean", "description": "True if any surface from this app has keyboard focus." }, "has_visible_surface": { "type": "boolean", "description": "True if at least one surface is visible (not minimized/occluded on all outputs)." }, "started_at": { "type": "string", "format": "date-time", "description": "ISO 8601 timestamp when the app connected to the compositor." }, "unresponsive": { "type": "boolean", "default": false, "description": "True if the app has not responded to pings within the timeout period." }, "unresponsive_since": { "type": ["string", "null"], "format": "date-time" } } } }}Rust Type
Section titled “Rust Type”use chrono::{DateTime, Utc};use serde::{Deserialize, Serialize};use std::collections::HashMap;
#[derive(Debug, Clone, Serialize, Deserialize)]pub struct Application { pub id: AppId, pub desktop_id: Option<String>, pub display_name: Option<String>, pub icon_name: Option<String>, pub process: ProcessInfo, pub surface_tree: Vec<SurfaceId>, pub capability_tier: CapabilityTier, pub capability_manifest: Option<CapabilityManifest>, pub derived_capabilities: Option<Vec<DerivedCapability>>, pub state: AppState,}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]#[serde(transparent)]pub struct AppId(pub String);// Format: "app:wl-{wayland_client_id}"
#[derive(Debug, Clone, Serialize, Deserialize)]pub struct ProcessInfo { pub pid: u32, pub executable: String, pub cmdline: Vec<String>, pub cgroup: Option<String>, pub sandbox: Option<SandboxType>,}
#[derive(Debug, Clone, Serialize, Deserialize)]pub enum SandboxType { Flatpak, Snap, Bubblewrap, Firejail,}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]pub enum CapabilityTier { /// App with shipped CapabilityManifest Native, /// Standard toolkit app with full AT-SPI2 accessibility tree Atspi2, /// Partial AT-SPI2 (window frame + basic widgets, e.g., Wine) Structural, /// Compositor surface metadata only, no accessibility tree Minimal,}
#[derive(Debug, Clone, Serialize, Deserialize)]pub struct AppState { pub focused: bool, pub has_visible_surface: bool, pub started_at: DateTime<Utc>, pub unresponsive: bool, pub unresponsive_since: Option<DateTime<Utc>>,}Field Reference
Section titled “Field Reference”Format app:wl-{N} where N is the Wayland client ID. Stable for the lifetime of the process. If the same app restarts, it gets a new ID.
process
Section titled “process”The cgroup field helps identify sandboxed applications. The sandbox enum covers the four common Linux sandboxing technologies. When sandbox is null, the process runs unsandboxed.
capability_tier
Section titled “capability_tier”The tier is determined automatically by the compositor at startup. It is not declared by the app (except Tier 1, which requires opting in via a manifest). The four tiers, from highest capability to lowest:
| Tier | Value | Description |
|---|---|---|
| 1 | native |
Ships a CapabilityManifest, implements the PCP server trait. Full semantic capabilities with typed parameters and returns. |
| 2 | atspi2 |
Standard toolkit app with a full AT-SPI2 accessibility tree. No developer effort required. |
| 2b | structural |
Partial AT-SPI2 support (window frame and basic widgets). Typical of Wine applications. |
| 3 | minimal |
Compositor surface metadata only. No accessibility tree. Input simulation is the only interaction path. |
The compositor maintains the state object in real time. focused flips whenever keyboard focus moves to or from one of the app’s surfaces. has_visible_surface accounts for minimization, occlusion, and output assignment. The unresponsive flag is set when the app fails to respond to Wayland pings within the configured timeout.
Example: Evolution Mail
Section titled “Example: Evolution Mail”{ "id": "app:wl-47", "desktop_id": "org.gnome.Evolution", "display_name": "Evolution Mail", "icon_name": "evolution-mail", "process": { "pid": 12345, "executable": "/usr/bin/evolution", "cmdline": ["evolution", "--component=mail"], "cgroup": null, "sandbox": null }, "surface_tree": ["surf:47-w1"], "capability_tier": "atspi2", "capability_manifest": null, "derived_capabilities": [ { "id": "mail.search", "name": "Search Mail", "description": "Search across mailboxes using the search bar", "category": "TEXT_QUERY", "confidence": "high", "source_element": "atspi:47-w1-entry-search", "adapter_id": "email-client-v1" }, { "id": "mail.compose", "name": "Compose New Email", "description": "Open the compose window", "category": "ELEMENT_INTERACTION", "confidence": "high", "source_element": "atspi:47-w1-btn-compose", "adapter_id": "email-client-v1" } ], "state": { "focused": true, "has_visible_surface": true, "started_at": "2026-05-08T14:00:00Z", "unresponsive": false, "unresponsive_since": null }}This example shows a Tier 2 application. The capability_manifest is null because Evolution does not ship a manifest. Instead, the PCP adapter derived two capabilities (mail.search and mail.compose) by inspecting the AT-SPI2 accessibility tree. Each derived capability references the element it was discovered from (source_element) and the adapter that produced it.