Advanced windows and commands
The immutable API remains the precise, stable layer beneath convention-first applications. Use it for generators, reusable plugins, infrastructure, dynamic manifests, or cases where every protocol-facing object should be visible.
Declare the application explicitly
Section titled “Declare the application explicitly”$app = Application::make( id: 'com.example.my-app', name: 'My desktop app', version: '1.0.0', window: Window::create('My desktop app') ->load('resources/index.html') ->size(1120, 720) ->minimumSize(720, 520) ->theme(WindowTheme::Dark),) ->description('A PHP-first desktop application.') ->publisher('My team') ->category(ApplicationCategory::Development);Register commands explicitly
Section titled “Register commands explicitly”$app->command('greet', static function (CommandContext $command): CommandResult { $name = $command->string('name', 'world');
return CommandResult::success(['message' => "Hello, {$name}!"]) ->effect(WindowEffect::title("Hello, {$name}", $command->windowId)) ->event(new ClientEvent('greeting.completed', compact('name')));});The worker accepts ordinary PHP values too; only use CommandResult when the
handler needs to attach effects or events manually.
Frontend invocation
Section titled “Frontend invocation”const result = await window.pam.invoke( "greet", { name: "Ada" }, { timeout: 5_000 },);Every request carries its exact source window, gateway origin, and ephemeral
bridge token. AbortSignal cancellation and hard deadlines are supported.
Recovery contract
Section titled “Recovery contract”Commands, frontend events, and background jobs run through supervised PHP workers. On timeout, cancellation, crash, invalid output, or message overflow, PAM kills and reaps the generation before accepting new work. Interrupted commands are never retried automatically because their side effects may have completed immediately before failure.