Runic.Platform.Runtime
0.8.0-preview.5
See the version list below for details.
dotnet add package Runic.Platform.Runtime --version 0.8.0-preview.5
NuGet\Install-Package Runic.Platform.Runtime -Version 0.8.0-preview.5
<PackageReference Include="Runic.Platform.Runtime" Version="0.8.0-preview.5" />
<PackageVersion Include="Runic.Platform.Runtime" Version="0.8.0-preview.5" />
<PackageReference Include="Runic.Platform.Runtime" />
paket add Runic.Platform.Runtime --version 0.8.0-preview.5
#r "nuget: Runic.Platform.Runtime, 0.8.0-preview.5"
#:package Runic.Platform.Runtime@0.8.0-preview.5
#addin nuget:?package=Runic.Platform.Runtime&version=0.8.0-preview.5&prerelease
#tool nuget:?package=Runic.Platform.Runtime&version=0.8.0-preview.5&prerelease
Runic.Platform.Runtime
Shared scoped lifetime, file leases, atomic writes and native provider infrastructure.
Preview API targeting .NET 10. Native providers are explicitly selected; this package has no Desktop or ASP.NET Core dependency.
Native file pickers
NativePickerBackend turns an INativeFilePicker into IFileDialogs. It passes
each dialog's filters, initial folder and multiplicity as a NativeFileDialogRequest
to INativeFilePicker.SelectAsync(request, cancellationToken), and the initial
folder of a directory dialog to INativeDirectoryPicker.SelectDirectoryAsync(initialDirectory, cancellationToken).
Both have default implementations that call the original single-file methods and
ignore the hints, so a picker written before them keeps working. A picker that
returns more than one selection also returns true from
SupportsMultipleSelection; otherwise OpenFilesAsync reports
Unavailable(BackendUnavailable) without showing a dialog. The backend releases
the access of every selection it does not hand to a lease, including after a
failure or cancellation.
Single instance and replies to later launches
ApplicationInstance.ClaimAsync makes the first launch of an application the
running instance and forwards later launches to it over a Unix domain socket in a
directory only the user can use (on Linux, macOS and Windows). By default a later
launch hands over its arguments and exits, and the running instance raises
IApplicationInstance.Launched.
With ApplicationInstanceOptions.ReplyToLaunches, a later launch, such as a
command line, also waits for the running instance's reply: messages (output lines
or JSON events, as UTF-8 strings of at most 1 MiB) and an exit status. Set it in
every process of the application, so whichever process is the running instance
answers.
var options = new ApplicationInstanceOptions { ReplyToLaunches = true };
var claim = await ApplicationInstance.ClaimAsync("org.example.Manager", ApplicationLaunch.FromProcess(args), options);
// A later launch: print the running instance's messages and exit with its status.
if (claim is PlatformResult<ApplicationInstanceClaim>.Success { Value: ApplicationInstanceClaim.Forwarded { Reply: { } reply } })
{
await using (reply)
{
// Ctrl+C asks the running instance to cancel; its last messages and exit status still arrive.
Console.CancelKeyPress += (_, e) => { e.Cancel = true; _ = reply.CancelAsync(); };
await foreach (var line in reply.ReadMessagesAsync()) Console.WriteLine(line);
return await reply.WaitForExitAsync() is PlatformResult<int>.Success(var code) ? code : 1;
}
}
// The running instance: launches that wait carry a reply; complete each one.
instance.Launched += (_, launch) => _ = Task.Run(async () =>
{
if (launch.Reply is not { } reply) { /* Only handed over: raise the window. */ return; }
await reply.WriteAsync("working");
await reply.CompleteAsync(reply.Cancelled.IsCancellationRequested ? 130 : 0);
});
IApplicationLaunchReply.Cancelledis cancelled when the launching process asks to cancel, disconnects (disposing its reply, or cancelling a read), or when the running instance ends.CancelRequestedis cancelled only for the request (IForwardedLaunchReply.CancelAsync, such as on Ctrl+C), andDisconnectedonly when the reply ends without an exit status; each is cancelled beforeCancelled. PassCancelRequestedto work that should outlive the launching process, such as an operation started over an SSH session that drops. Writes after the launching process went away return false.A write waits while the launching process does not read, so large output is not buffered in memory. Pass a token to
WriteAsyncto bound the wait; a write cancelled that way ends the reply.When the running instance ends or crashes before the exit status, the messages end and
WaitForExitAsyncreportsFailed(IoError).With
ApplicationInstanceOptions.ForwardOnly, the process never becomes the running instance: a command line that talks to a running daemon getsApplicationInstanceClaim.Forwarded, orApplicationInstanceClaim.NotRunningwhen no instance runs, and then does the work itself or reports it. It does not listen meanwhile, so a daemon that starts at the same moment does not wait for it. An instance that is starting is waited for, as with a claim.var options = new ApplicationInstanceOptions { ReplyToLaunches = true, ForwardOnly = true }; switch (await ApplicationInstance.ClaimAsync("org.example.Manager", ApplicationLaunch.FromProcess(args), options)) { case PlatformResult<ApplicationInstanceClaim>.Success { Value: ApplicationInstanceClaim.Forwarded { Reply: { } reply } }: /* Read the reply as above. */ break; case PlatformResult<ApplicationInstanceClaim>.Success { Value: ApplicationInstanceClaim.NotRunning }: /* No daemon: run here. */ break; }An instance claimed without
ReplyToLaunches, or by an SDK before 0.8.0-preview.3, refuses launches that wait: the claim fails withResourceBusyand anApplicationInstancediagnostic, and the launch is not handled. Launches withoutReplyToLauncheskeep the one-way protocol and reach any instance.
Opening files and URLs
ApplicationInstance.CreateOpenRequests(instance, launch, options) turns this
launch and each later launch into IDesktopOpenRequests.Opened requests: the
arguments that are URLs with a registered scheme and, with Files, existing
files. Linux desktop entries (Exec=app %U) and Windows registrations
("app.exe" "%1") pass them that way. The instance's own Launched handlers
still receive every launch. See the
opening files and URLs design.
File transfers
LocalFileTransfers.Create() is the IDesktopFileTransfers engine every
platform uses, and what AddRunicPlatformServices() registers on Runic
Desktop. It copies in 1 MiB blocks under hidden temporary names, renames into
place with an exclusive rename, and moves by renaming within a file system. A
CS-WebUI application can register it itself. See
Copy and move and the
file transfer design.
| 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
- Runic.Platform (= 0.8.0-preview.5)
NuGet packages (8)
Showing the top 5 NuGet packages that depend on Runic.Platform.Runtime:
| Package | Downloads |
|---|---|
|
Runic.Platform.Windows
The Windows provider of the Runic.Platform services: desktop services, status icon, and the window services of Runic hosts. |
|
|
Runic.Platform.Linux.Portal
The Linux provider of the Runic.Platform services, built on XDG desktop portals, D-Bus services and freedesktop.org specifications. |
|
|
Runic.Platform.Linux
The GTK 3 window services (portal parent, GTK dialogs and clipboard) that Runic.Application.Views.Desktop selects on Linux. |
|
|
Runic.Platform.MacOS
AppKit owned file dialogs, scoped file access, text clipboard, desktop services and privileged actions for Runic on macOS. |
|
|
Runic.Platform.Linux.Gtk4
The GTK 4 window services (clipboard and XDG portal parent) that Runic.Application.Views.Desktop selects on Linux. |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.11.0 | 2,098 | 10/25/2026 |
| 0.10.0 | 6,739 | 10/22/2026 |
| 0.9.1 | 1,033 | 10/21/2026 |
| 0.9.0 | 250 | 10/21/2026 |
| 0.8.0-preview.6 | 1,639 | 10/19/2026 |
| 0.8.0-preview.5 | 463 | 10/17/2026 |
| 0.8.0-preview.4 | 1,035 | 10/17/2026 |
| 0.8.0-preview.3 | 913 | 10/15/2026 |
| 0.8.0-preview.2 | 159 | 10/15/2026 |
| 0.8.0-preview.1 | 214 | 10/15/2026 |
| 0.7.0-preview.9 | 611 | 10/14/2026 |
| 0.7.0-preview.8 | 135 | 10/12/2026 |
| 0.7.0-preview.7 | 85 | 10/12/2026 |
| 0.7.0-preview.6 | 1,251 | 10/9/2026 |
| 0.7.0-preview.5 | 199 | 10/9/2026 |
| 0.7.0-preview.4 | 109 | 10/8/2026 |
| 0.7.0-preview.3 | 251 | 10/8/2026 |
| 0.7.0-preview.2 | 109 | 10/7/2026 |
| 0.7.0-preview.1 | 597 | 10/7/2026 |
| 0.6.0-preview.1 | 863 | 10/5/2026 |