Rust SDK
Overview
Section titled “Overview”PCP’s reference implementation is a Rust workspace of sixteen crates, each with a single responsibility. The centerpiece is the daemon binary: a standalone service that owns the capability registry, the event bus, and the audit log. A companion CLI binary, pcp, connects to the daemon socket as an ordinary client and exercises the full wire protocol.
The crate structure enforces separation of concerns at the dependency level. Core types and traits are isolated in pcp-core, which has zero platform dependencies. Wire framing lives in pcp-stream. Everything that speaks a socket layers on top of those two.
Workspace Layout
Section titled “Workspace Layout”pcp/├── core/ # pcp-core — types, traits, errors, gates, permission,│ # audit, transactions, signing, events├── registry/ # pcp-registry — registry + detection pipeline├── native/ # pcp-native — Tier 1 detection (desktop entries, manifests, binary probing)├── atspi2/ # pcp-atspi2 — Tier 2 adapter, tree walker, live event stream├── wine/ # pcp-wine — Wine/MSAA accessibility bridge├── simulator/ # pcp-simulator — Tier 3 input injection fallback├── push/ # pcp-push — push event bus, V2 subscriptions, overflow├── platform/ # pcp-platform — system.* + compositor.* capability domains├── stream/ # pcp-stream — framing, 27 message types, socket transport├── ipc/ # pcp-ipc — PcpServerRunner + AppClientManager (Tier 1)├── daemon/ # the daemon binary + IPC handler + dispatch├── learning/ # pcp-learning — Learning Runtime├── recovery/ # pcp-recovery — Recovery Runtime├── coordination/ # pcp-coordination — multi-app primitives├── inspection/ # pcp-inspection — deep inspection└── cli/ # pcp-cli — the `pcp` binaryDependency Graph
Section titled “Dependency Graph” pcp-core ┌────────┬────────┼──────────┬───────────┬─────────┐ registry native atspi2 wine simulator push │ │ │ │ │ │ └────────┴───┬────┴──────────┴───────────┴─────────┘ │ stream ────────────► (framing for everything below) │ ipc (PcpServerRunner / AppClient, layered on stream) │ learning recovery coordination inspection ── (runtime servers, depend on core) \ │ │ / └──────┴────┬────┴─────────┘ the daemon binary (depends on all of the above) │ cli (the `pcp` binary; a client over the daemon socket)pcp-core sits at the bottom. Every other crate depends on it for shared types, but nothing else is universal. The graph is deliberately shallow: most crates are one or two hops from core.
pcp-stream is the framing layer for everything that crosses a socket. pcp-ipc layers the Tier 1 serving and connecting machinery on top of it. The daemon binary composes all of it; the CLI depends only on the client-side pieces.
Crate Responsibilities
Section titled “Crate Responsibilities”pcp-core
Section titled “pcp-core”The foundation. Defines every shared type, trait, and error variant used across the workspace: capability and element types, intents, domains, auth levels, permission decisions, confirmation gates, audit entries, transactions, and signing helpers. Has zero platform dependencies; it compiles on any target that supports Rust.
Key exports: the Adapter and PcpServer traits, CapabilityId, ElementId, SurfaceId, AppId, Domain, AuthLevel, error types, and all stream message structs.
Dependencies: serde, serde_json, chrono, thiserror, ed25519-dalek.
pcp-registry
Section titled “pcp-registry”The daemon’s live database of all capabilities from all running apps. Handles registration, deregistration, queries, and capability diffs. Listens to adapter lifecycle events and updates the registry in real time.
Dependencies: pcp-core.
pcp-native
Section titled “pcp-native”Tier 1 detection: desktop entry files, signed capability manifests, and binary probing. Loads a manifest, verifies its Ed25519 signature, probes the binary, and hands the result to the registry.
Dependencies: pcp-core.
pcp-atspi2
Section titled “pcp-atspi2”The accessibility adapter for Tier 2 apps. Connects to the D-Bus accessibility bus, builds the element tree, maps accessibility roles to the PCP element model, and streams live tree-change events.
Dependencies: pcp-core, zbus, atspi.
pcp-wine
Section titled “pcp-wine”The accessibility bridge for Windows applications running under Wine. Translates MSAA and UI Automation trees into the PCP element model, the same way the AT-SPI2 adapter maps native Linux toolkits.
Dependencies: pcp-core.
pcp-simulator
Section titled “pcp-simulator”Input simulation for the Tier 3 fallback. When no accessibility API is available and the app is not native, pcp-simulator injects keyboard and pointer events through the compositor’s input subsystem.
Dependencies: pcp-core.
pcp-push
Section titled “pcp-push”The push event delivery system. Provides the event bus, V2 subscriptions with per-subscription filters, overflow strategies, and sequence tracking for resume and dedup. Channels are bounded; a full channel drops with a counted overflow rather than blocking the bus.
Dependencies: pcp-core, tokio, serde, chrono, crc32fast, dashmap.
pcp-stream
Section titled “pcp-stream”The wire protocol. Frame encoding and decoding, the 27 message types, and the socket transport shared by the daemon socket and per-app sockets.
Dependencies: pcp-core, tokio, postcard, crc32fast, serde_json.
pcp-ipc
Section titled “pcp-ipc”The Tier 1 serving and connecting layer. PcpServerRunner lets an application serve its PcpServer implementation on a socket; the daemon’s AppClientManager connects to those sockets and dispatches invocations. Owns reconnection, concurrency, and socket lifecycle.
Dependencies: pcp-core, pcp-stream, tokio, dashmap, async-trait.
The daemon binary
Section titled “The daemon binary”Composes every crate into the standalone service: binds the daemon socket, runs the detection pipeline, hosts the registry, event bus, and audit log, and connects out to Tier 1 app sockets. The runtime services — learning, recovery, inspection, coordination — are registered as in-process servers inside the daemon.
Dependencies: all PCP crates.
Runtime crates
Section titled “Runtime crates”pcp-learning, pcp-recovery, pcp-coordination, and pcp-inspection implement the runtime services the daemon hosts. Each is an independent server over pcp-core types, registered in-process with the daemon’s dispatcher.
Dependencies: pcp-core.
pcp-cli
Section titled “pcp-cli”The pcp binary. A full protocol client over the daemon socket: registry queries, detection, execution, event subscription. Useful for scripting, debugging, and as a reference for client implementations.
Dependencies: clap, pcp-stream, pcp-core, pcp-registry, pcp-native, pcp-atspi2.
The PcpServer Trait
Section titled “The PcpServer Trait”The PcpServer trait is the contract every Tier 1 application implements. Six async methods cover the full server surface:
#[async_trait]pub trait PcpServer: Send + Sync { async fn manifest(&self) -> CapabilityManifest; async fn invoke(&self, capability_id: &str, ctx: &InvocationContext, params: Value) -> Result<CapabilityResult, PcpError>; async fn validate_params(&self, capability_id: &str, params: &Value) -> Result<(), PcpError>; async fn subscribe_events(&self, event_types: Vec<String>) -> Result<(), PcpError>; async fn query_dynamic_state(&self, capability_id: &str) -> Result<Value, PcpError>; async fn shutdown(&self);}invoke executes a capability. validate_params checks a payload against the manifest schema before execution. subscribe_events and query_dynamic_state support event streams and dynamic state queries. shutdown gives the application a clean teardown hook.
Serving and Connecting
Section titled “Serving and Connecting”A Tier 1 application wraps its PcpServer in a PcpServerRunner from pcp-ipc. The runner listens on the application’s socket, decodes frames, and dispatches to the trait methods.
On the other side, the daemon’s AppClientManager connects to each registered application’s socket and routes invocations to it. If an application crashes, its socket disappears; the daemon surfaces the failure, and reconnects when the application returns.
The two sides are symmetric: both speak the same framing and the same message types, defined in pcp-stream.
Push Events
Section titled “Push Events”The push system in pcp-push delivers events without polling. Subscribers register through the V2 subscription API with per-subscription filters and an overflow strategy. Channels are bounded; when a channel is full, events are dropped with a dropped_count counter rather than blocking the bus.
Every pushed event carries a last_sequence value. Subscribers use it to resume after a disconnect and to deduplicate anything the overflow strategy dropped.
Integration Notes
Section titled “Integration Notes”The daemon runs as a standalone service, a sibling process to the compositor. System Intelligence connects to it as a client over the daemon socket and invokes capabilities through the wire protocol — the same path a CLI tool or script takes.
The runtime services are the one deliberate exception: learning, recovery, inspection, and coordination are registered as in-process servers inside the daemon, invoked without a socket crossing. This is the embedding path the protocol defines for hosts that own their servers.
Fault isolation is by process boundary: daemon, compositor, and each Tier 1 application run in separate processes, so a crash in one does not cascade. Hosts that embed PCP servers inside a larger process can use the supervision library shipped in pcp-core for analogous watchdog and recovery guarantees.
When adding a new crate to the workspace, the dependency graph must remain shallow. New crates should depend on pcp-core for types and at most one other crate for domain-specific logic. Circular dependencies are forbidden by the workspace’s Cargo.toml configuration.
A conforming implementation passes the workspace test suites: framing round-trip and fuzz targets in pcp-stream, the Tier 1 socket lifecycle, reconnect, and concurrency suites in pcp-ipc, and the daemon integration suite.