Runic.Platform
0.8.0-preview.1
See the version list below for details.
dotnet add package Runic.Platform --version 0.8.0-preview.1
NuGet\Install-Package Runic.Platform -Version 0.8.0-preview.1
<PackageReference Include="Runic.Platform" Version="0.8.0-preview.1" />
<PackageVersion Include="Runic.Platform" Version="0.8.0-preview.1" />
<PackageReference Include="Runic.Platform" />
paket add Runic.Platform --version 0.8.0-preview.1
#r "nuget: Runic.Platform, 0.8.0-preview.1"
#:package Runic.Platform@0.8.0-preview.1
#addin nuget:?package=Runic.Platform&version=0.8.0-preview.1&prerelease
#tool nuget:?package=Runic.Platform&version=0.8.0-preview.1&prerelease
Runic.Platform
Host-independent native-service contracts for Runic applications.
Preview API targeting .NET 10. Native providers are explicitly selected; this package has no Desktop or ASP.NET Core dependency.
Runic.Application.Views.Desktop selects one for each window with services.AddRunicPlatformServices().
Services return PlatformResult<T>: Success, Unavailable with a
PlatformUnavailableReason, or Failed with a PlatformFailureCode. Operations
without a value return PlatformResult<PlatformUnit>. The type names carry the
Platform prefix so they do not collide with System.Reactive.Unit and similar
names when both namespaces are imported.
Branch on the failure code. When a provider observed a native error, Failed.Diagnostic
carries a PlatformDiagnostic with its domain (HRESULT, Win32, errno, an
NSError/GError domain or a D-Bus error name), numeric code and, where the operating system's error table describes the code, its
message. It is for logs and support, not display. Free-form text from native services
(GError and D-Bus messages, NSError descriptions) is left out, so a diagnostic contains
no paths.
IFileDialogs.OpenDirectoryAsync(new OpenDirectoryOptions()) returns a
PickerResult<IDirectoryLease> for one existing local directory. Keep the selected
lease alive while C# filesystem operations use LocalPath; it retains native
access until disposal or presentation close. The path preserves the selected
identity, including Unicode and escaped filename characters. Native paths that
cannot be represented exactly in C# are refused. Leases and native grants remain
in C#; expose only application DTOs to a frontend.
Presentation close releases every lease the presentation still owns; on macOS this
ends security-scoped access, and LocalPath throws once closing starts. Native
owner closure alone does not release leases. When application work that uses a
lease can outlive the window, such as recovery owned by an AcceptedWorkScope,
drain that work before stopping the PresentationLifetime, or dispose the lease
at the end of the work itself:
await acceptedWork.DisposeAsync(); // Work using lease.LocalPath has finished.
await presentationLifetime.DisposeAsync(); // Releases remaining leases.
User dismissal returns Dismissed, caller cancellation throws
OperationCanceledException, and presentation shutdown returns
Unavailable(OwnerClosed). The platform.directories.open capability reports
availability when using PresentationFiles. Existing file-only implementations
remain compatible and report directory selection unavailable. A custom
IPickerBackend that implements OpenDirectoryAsync must also return true from
SupportsDirectorySelection; PresentationFiles always calls the backend's method
and throws InvalidOperationException if an undeclared backend returns a result
other than Unavailable.
PickerResult<T>.Selected and PlatformResult<T>.Success deconstruct, so a
caller can match and take the value in one pattern:
if (await files.OpenFileAsync(new()) is PickerResult<IReadFileLease>.Selected(var lease))
{
await using (lease) { /* read */ }
}
Window services
IWindowPlatformServices groups the file dialogs, text clipboard and file
launcher of one window, and reports their capabilities together under
WindowPlatformServices.CapabilityIds. Host adapters register it, and its
parts, per window scope through services.AddRunicPlatformServices(), so a
ViewModel can take IFileDialogs, ITextClipboard, IDesktopFileLauncher or
IWindowPlatformServices in its constructor. Runic.Application.Views.Desktop binds
them to the native window when it opens. A host without a native owner
registers WindowPlatformServices.Unavailable(reason), whose operations and
capabilities all report that reason. Tests can use the same instance.
IDesktopSettings is application-scoped, so AddRunicPlatformServices()
registers one singleton for it. A host or platform without a provider
registers DesktopSettings.Unavailable(reason): reads return
Unavailable(reason), and a watch emits that value once and then waits.
IDesktopNotifications is registered the same way; without a provider it is
DesktopNotifications.Unavailable(reason), whose requests return
Unavailable(reason) and which never raises Activated.
Privileged actions
IDesktopPrivilegedActions runs a step the application declared at build time,
a fixed program with bounded arguments, as the administrator after the
platform's authorization prompt. The program ran is Success with its exit
code; a refused authorization is Failed(PermissionDenied), a dismissed prompt
Failed(UserDismissed), and no authorization service Unavailable. Arguments
are an argument vector, never a shell command line.
DesktopPrivilegedActions.Unavailable(reason) is the provider for hosts and
platforms without one. Linux uses Polkit and pkexec through
Runic.Platform.Linux.Polkit, Windows a UAC-elevated helper through
Runic.Platform.Windows.Elevation, and macOS a launch daemon and Authorization
Services through Runic.Platform.MacOS
(guide).
Declare privileged actions
Declarations are PrivilegedActionDeclaration values that this package's build
targets generate from RunicPrivilegedAction items, in any project that
references Runic.Platform as a package:
<ItemGroup>
<RunicPrivilegedAction Include="org.example.app.activate"
Program="/usr/libexec/example/example-helper"
Verb="activate"
Description="Activate a system configuration"
Message="Authentication is required to activate the system configuration."
MaximumArguments="1"
ArgumentPattern="[A-Za-z0-9._+-]+" />
</ItemGroup>
| Metadata | Meaning |
|---|---|
| Item identity | The action ID: lowercase reverse-DNS, at least two segments, the same on every platform. |
Program |
The absolute, normalized Unix path of the privileged program. Linux runs it there; other platforms derive their own location from it unless their metadata below says otherwise. Required. |
Verb |
The first argument, which selects the action. Every action needs its own verb, also across programs, and an action without a verb is allowed only on its own (RUNICPA003). |
Description, Message |
What the authorization prompt shows, passed unchanged to the platform packages. Both required. |
MaximumArguments |
Arguments accepted after the verb, 0 to 64. Default 0. |
ArgumentPattern |
A .NET regular expression every argument after the verb must match completely, evaluated with RegexOptions.NonBacktracking. |
Name |
The generated property name, when the last ID segment does not make a good one. |
WindowsProgram |
Windows only: the elevated helper, as a path relative to the application's directory (such as helpers\example-helper.exe) or an absolute path. Default: the file name of Program with .exe, in the application's directory. |
MacProgram |
macOS only: the helper, as a path relative to the application bundle (such as Contents/MacOS/example-helper) or an absolute path. |
Platform packages read further metadata of their own, such as Polkit's
IconName and AllowActive; see their guides. Metadata no package reads is
ignored.
Each build validates the items and writes PrivilegedActions.g.cs under
obj/.../runic-privileged/: an internal static partial class with one
PrivilegedActionDeclaration property per action and All. The application
and its privileged program both use it. Invalid items are build errors
RUNICPA001 to RUNICPA009 and RUNICPA011, described in the
diagnostics catalog.
| Property | Default |
|---|---|
RunicPrivilegedActionsClassName |
PrivilegedActions |
RunicPrivilegedActionsNamespace |
$(RootNamespace) |
RunicPrivilegedActionsReservedNames |
All, MacOSDaemon and WindowsElevation, the property names platform packages generate in other parts of the class. An action's Name cannot be one of them. |
The class name and namespace defaults are set when the package's targets are
evaluated, after the project file, so a project's own RootNamespace applies
and platform targets can read the final values.
A platform package extends the generation with a target that depends on
RunicValidatePrivilegedActions, which validates the items once, and appends
that target to RunicPrivilegedActionsDependsOn; RunicGeneratePrivilegedActions
writes the class only after those targets succeeded. A platform package that
generates its own part of the class uses a reserved property name, and adds any
new one to RunicPrivilegedActionsReservedNames.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages (5)
Showing the top 5 NuGet packages that depend on Runic.Platform:
| Package | Downloads |
|---|---|
|
Runic.Platform.Runtime
Single instance, requests to open files and URLs, and file transfers for Runic applications, and the contract for native platform providers. |
|
|
Runic.Desktop
A managed .NET runtime for web-powered desktop applications. |
|
|
Runic.Platform.Linux.DBus
D-Bus client and service API for Runic applications on Linux: connections, typed values, proxies, exported objects, signals and properties. |
|
|
Runic.Application.Views.CsWebUi
CS-WebUI host adapter for Runic Window and View applications. |
|
|
Runic.Platform.Linux.Polkit
Declared privileged actions for Runic applications on Linux: a generated Polkit policy and pkexec. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.12.0 | 0 | 10/27/2026 |
| 0.11.0 | 3,427 | 10/25/2026 |
| 0.10.0 | 6,794 | 10/22/2026 |
| 0.9.1 | 1,075 | 10/21/2026 |
| 0.9.0 | 287 | 10/21/2026 |
| 0.8.0-preview.6 | 1,665 | 10/19/2026 |
| 0.8.0-preview.5 | 484 | 10/17/2026 |
| 0.8.0-preview.4 | 1,045 | 10/17/2026 |
| 0.8.0-preview.3 | 924 | 10/15/2026 |
| 0.8.0-preview.2 | 180 | 10/15/2026 |
| 0.8.0-preview.1 | 232 | 10/15/2026 |
| 0.7.0-preview.9 | 619 | 10/14/2026 |
| 0.7.0-preview.8 | 144 | 10/12/2026 |
| 0.7.0-preview.7 | 90 | 10/12/2026 |
| 0.7.0-preview.6 | 1,255 | 10/9/2026 |
| 0.7.0-preview.5 | 207 | 10/9/2026 |
| 0.7.0-preview.4 | 114 | 10/8/2026 |
| 0.7.0-preview.3 | 256 | 10/8/2026 |
| 0.7.0-preview.2 | 108 | 10/7/2026 |
| 0.7.0-preview.1 | 606 | 10/7/2026 |