Skip to content

Convention-first authoring

PAM Desktop is convention-first where convention is safe and explicit where authority matters.

#[Desktop(id: 'com.example.hello', name: 'Hello')]
final class HelloApp extends App
{
#[Command]
public function greet(string $name = 'world'): array
{
return ['message' => "Hello, {$name}!"];
}
}

PAM supplies resources/index.html, a responsive 1120 × 720 main window, a 720 × 520 minimum, system theme, a 30-second command deadline, and no native permissions. Call HelloApp::run() from the project entry point.

protected function configure(Desktop $desktop): void
{
$desktop
->permissions(static fn (Permissions $permissions) => $permissions
->filesystem('data', __DIR__.'/../storage', read: true, write: true)
->database('app', 'storage/app.sqlite')
->http('api', 'https://api.example.com/v1')
->dialogs()
->clipboard()
->notifications()
)
->timeout(10_000)
->workers(4);
}

Permissions compile to the same immutable Capabilities value used by the advanced API. Rust validates the manifest and enforces each operation. Source code discovery never grants native authority.

Concrete classes are autowired through constructor types. Bind interfaces and preconfigured instances explicitly:

protected static function bindings(): array
{
return [
Clock::class => new SystemClock(),
DocumentRepository::class => new SqliteDocumentRepository(),
];
}

Bindings are cloned into invocation scopes. Contextual services such as the current window and event collector exist only while a handler is running.

app/
├── MyApp.php
├── Commands/
│ ├── SaveDocument.php
│ └── DeleteDocument.php
├── Events/
│ └── DocumentSaved.php
├── Menus/
│ └── ApplicationMenu.php
└── Windows/
└── SettingsWindow.php
resources/
├── index.html
└── settings.html
storage/

Register command, menu, and window classes in the corresponding protected methods. This is deliberate discovery: predictable in production, friendly to static analysis, and free of filesystem scanning during command dispatch.