Native capabilities
No native capability is enabled by default. PHP declares policy, and the frontend receives only named, typed APIs for the enabled surface.
Declare policy
Section titled “Declare policy”use Pam\Desktop\Capabilities;use Pam\Desktop\FileSystemRoot;
$app->capabilities( Capabilities::none() ->filesystem( FileSystemRoot::read( 'assets', __DIR__.'/assets', ), FileSystemRoot::readWrite( 'data', __DIR__.'/storage', ), ) ->dialogs() ->clipboard(read: true, write: true) ->notifications() ->dragAndDrop(),);Root directories must already exist. Root IDs use the same bounded identifier grammar as windows and commands.
Filesystem access
Section titled “Filesystem access”File access is an integer-backed enum:
| ID | Case | Permission |
|---|---|---|
1 |
Read | Metadata, list, and read text |
2 |
Write | Create directories and write text |
3 |
ReadWrite | Both permission sets |
Frontend methods use a named root and relative path:
const target = { root: "data", path: "notes/today.txt",};
await pam.fs.createDirectory({ root: "data", path: "notes",});
await pam.fs.writeText(target, "Hello, PAM.");const text = await pam.fs.readText(target);const metadata = await pam.fs.metadata(target);const entries = await pam.fs.list({ root: "data", path: "notes",});Text reads and writes are UTF-8 and limited to 8 MiB. Paths must be relative and cannot contain parent components. Symbolic links are not returned or opened.
Directory entries contain a name, relative path, integer kind (1 file or 2 directory), and byte size.
Dialogs and grants
Section titled “Dialogs and grants”const file = await pam.dialog.openFile({ title: "Open a document", filters: [ { name: "Text", extensions: ["txt", "md"], }, ],});
const files = await pam.dialog.openFiles();const destination = await pam.dialog.saveFile({ fileName: "report.txt",});const directory = await pam.dialog.openDirectory({ access: 3,});A cancelled single-selection dialog returns null; a cancelled multi-selection dialog returns an empty array.
Selected resources contain:
{ grantId: "opaque-256-bit-token", name: "report.txt", kind: 1, access: 1}The frontend never receives the ambient filesystem path. Pass the granted object to pam.fs. Directory grants may include a child relative path.
Grants are random, process-lifetime capabilities. They expire when the host restarts or capability policy is hot-reloaded.
Clipboard
Section titled “Clipboard”const text = await pam.clipboard.readText();await pam.clipboard.writeText("Copied from PAM");await pam.clipboard.clear();Read and write permissions are independent. Clipboard content remains owned by the host so it stays available after the immediate operation.
Notifications
Section titled “Notifications”await pam.notification.show({ title: "Export complete", body: "The report is ready.", urgency: 2,});Urgency is a sequential integer: 1 low, 2 normal, 3 critical.
Operating-system notification support and permission behavior remain platform-specific.
Drag and drop
Section titled “Drag and drop”Dropped files become opaque grants under the same filesystem API. The page receives metadata and a grant, not a host path.
Timeouts
Section titled “Timeouts”All native methods except dialogs accept optional client timeout and AbortSignal values:
await pam.fs.readText(target, { timeout: 5_000, signal: controller.signal,});Adjacent native surfaces
Section titled “Adjacent native surfaces”Menus, tray behavior, global shortcuts, periodic PHP jobs, PHP plugins, process-isolated Rust plugins, and signed updates are implemented as separate, typed policies. They do not broaden the filesystem grants declared here.
Read native shell, background jobs, plugins, and signed updates. A generic shell, arbitrary process bridge, or unrestricted filesystem bridge remains deliberately unsupported.