SDK overview
Small packages, so a plugin depends only on what it uses. Every public member is documented in XML docs and IntelliSense; every package is a compatibility commitment - see the compatibility policy. Package versions follow the Macro Deck release they were built with; each package’s README is its NuGet overview.
Packages
Section titled “Packages”| Package | Install | For | Docs |
|---|---|---|---|
MacroDeck.Plugin.Hosting |
dotnet add package MacroDeck.Plugin.Hosting |
Running an out-of-process plugin on ASP.NET Core; brings MacroDeck.Sdk. |
Plugin hosting |
MacroDeck.Sdk |
dotnet add package MacroDeck.Sdk |
Integration contracts: lifecycle, actions, capabilities, variables, events, profiles, decks, widgets, notifications, config flows, UI session providers. | Capabilities |
MacroDeck.Localization |
dotnet add package MacroDeck.Localization |
Localization keys, deferred LocalizedString/LocalizedText, the culture fallback chain and the reusable MacroDeckStrings catalog. |
Localization |
MacroDeck.Plugin.Analyzers |
dotnet add package MacroDeck.Plugin.Analyzers |
Compile-time diagnostics, and the source generator that turns Localization/*.resx into a typed API. |
Analyzers |
MacroDeck.Plugin.Serilog |
dotnet add package MacroDeck.Plugin.Serilog |
Forwarding Serilog events to the host log. | Logging and health |
MacroDeck.Plugin.Testing |
dotnet add package MacroDeck.Plugin.Testing |
Test host, fakes and the conformance suite. | Testing plugins |
MacroDeck.Plugin.Cli |
dotnet tool install --global MacroDeck.Plugin.Cli --prerelease |
The macrodeck-plugin tool. |
Plugin CLI |
MacroDeck.Ui |
dotnet add package MacroDeck.Ui |
The Macro Deck UI framework: declarative C# DSL and reactive runtime over MacroDeck.Ui.Model. |
Macro Deck UI |
MacroDeck.Ui.Testing |
dotnet add package MacroDeck.Ui.Testing |
Headless testing of Macro Deck UI views. | Macro Deck UI |
MacroDeck.Ui.Model |
dotnet add package MacroDeck.Ui.Model |
Transport-neutral UI tree, events, patches, resources and capability negotiation - the wire contract under the UI framework. | Macro Deck UI |
MacroDeck.Plugin.Packaging |
dotnet add package MacroDeck.Plugin.Packaging |
The manifest and .macroDeckPlugin package model. |
Manifest |
MacroDeck.Plugin.Protocol |
dotnet add package MacroDeck.Plugin.Protocol |
Low-level plugin wire contracts. Most plugins use MacroDeck.Plugin.Hosting instead. |
Plugin protocol |
MacroDeck.Signing |
dotnet add package MacroDeck.Signing |
Ed25519 package signing and verification shared by the CLI, host and Platform. | Security model |
Only -preview versions are published before 3.0, so add --prerelease to dotnet add package too.
First use
Section titled “First use”MacroDeck.Plugin.Hosting
Section titled “MacroDeck.Plugin.Hosting”var plugin = MacroDeckPlugin.CreatePlugin(args) .RegisterIntegration<PluginIntegration>() .Build();
await plugin.RunAsync();MacroDeck.Sdk
Section titled “MacroDeck.Sdk”public sealed class PluginIntegration(ILogger logger) : IPluginIntegration{ public IReadOnlyList<IActionDefinition> Actions { get; } = [new LogMessageAction(logger)]; public Task InitializeAsync(IIntegrationContext context) => Task.CompletedTask; public Task ShutdownAsync() => Task.CompletedTask;}MacroDeck.Localization and MacroDeck.Plugin.Analyzers
Section titled “MacroDeck.Localization and MacroDeck.Plugin.Analyzers”<PackageReference Include="MacroDeck.Localization" /><PackageReference Include="MacroDeck.Plugin.Analyzers" PrivateAssets="all" />public LocalizedText Name => Strings.Actions.SetBrightness.Name(); // generated from Localization/Strings.resxnew Text(MacroDeckStrings.Common.Save()) // the shared catalogPrivateAssets="all" keeps the analyzers a build-time-only dependency.
MacroDeck.Plugin.Serilog
Section titled “MacroDeck.Plugin.Serilog”var plugin = MacroDeckPlugin.CreatePlugin(args) .UseMacroDeckLogging(cfg => cfg.MinimumLevel.Debug()) .RegisterIntegration<PluginIntegration>() .Build();MacroDeck.Plugin.Testing
Section titled “MacroDeck.Plugin.Testing”await using var harness = PluginTestHarness.Create(b => b.RegisterIntegration<PluginIntegration>());await harness.InitializeIntegrationsAsync();
var outcome = await harness.Actions.ExecuteAsync("log-message", new Dictionary<string, object?> { ["message"] = "Hello" });MacroDeck.Plugin.Cli
Section titled “MacroDeck.Plugin.Cli”dotnet tool install --global MacroDeck.Plugin.Cli --prereleasemacrodeck-plugin new --name "Hue Lights" --id com.example.hue-lightsmacrodeck-plugin buildMacroDeck.Ui
Section titled “MacroDeck.Ui”private readonly UiState<string> _apiKey = new(string.Empty);
private UiFlow Build() => new(){ Key = "setup", Children = [new UiStep { Key = "credentials", Children = [new UiStringInput { Key = "apiKey", Binding = Bind.To(_apiKey) }] }],};MacroDeck.Ui.Testing
Section titled “MacroDeck.Ui.Testing”var host = UiTestHost.Render(view);host.ById("apiKey").Change("k-1");await host.SettleAsync();Assert.That(host.ById("apiKey").Text(UiConfigProperties.Value), Is.EqualTo("k-1"));MacroDeck.Ui.Model
Section titled “MacroDeck.Ui.Model”var node = new UiNode { Id = "title", Type = "text" };string json = UiCanonicalJson.Serialize(node);MacroDeck.Plugin.Packaging
Section titled “MacroDeck.Plugin.Packaging”IPluginManifestReader reader = new PluginManifestReader();var result = reader.Read("manifest.json", expectedPluginId: "com.example.hue-lights", expectedVersion: "1.0.0");if (!result.Success) Console.WriteLine($"{result.Error}: {result.ErrorMessage}");MacroDeck.Plugin.Protocol
Section titled “MacroDeck.Plugin.Protocol”var outcome = ProtocolVersionNegotiator.Negotiate(new ProtocolVersionRange { Minimum = 1, Maximum = 3 });if (outcome.Succeeded) Console.WriteLine($"Speaking protocol {outcome.NegotiatedVersion}");MacroDeck.Signing
Section titled “MacroDeck.Signing”var result = await PackageVerifier.VerifyAsync("HueLights.macroDeckPlugin", new PluginManifestReader());Console.WriteLine(result.Success ? $"Signed by {result.CertificateId}" : result.Message);Store artifacts are signed by the Creator Portal; no signing key reaches a plugin author. See Publishing to the Store.
Core integration model
Section titled “Core integration model”An integration exposes actions and opts into more by implementing capability interfaces. Out-of-process
plugins use the same contracts through MacroDeck.Plugin.Hosting.
| Area | Namespace |
|---|---|
| Actions | MacroDeck.Sdk.Actions - IStateProviderActionDefinition lets a configured action instance supply an Action Button’s states and current state |
| Configuration flows | MacroDeck.Sdk.ConfigFlow |
| Variables | MacroDeck.Sdk.Variables |
| Events | MacroDeck.Sdk.Events |
| Profiles and deck navigation | MacroDeck.Sdk.Profiles, MacroDeck.Sdk.Decks |
| Widgets | MacroDeck.Sdk.Widgets - states addressed by stable id; WidgetStateSelector is deprecated, see migrations |
| Music and weather providers | MacroDeck.Sdk.MusicPlayer, MacroDeck.Sdk.Weather |
| Integration issues and logging | MacroDeck.Sdk.Issues, MacroDeck.Sdk.Logging |
| UI session providers | MacroDeck.Sdk.Ui - IUiProvider and IUiSession in MacroDeck.Ui.Model types, so a provider needs no UI framework dependency. See Macro Deck UI. |
Use IntelliSense for individual member contracts.
Logging
Section titled “Logging”Use the SDK logging abstractions for integration diagnostics, and MacroDeck.Plugin.Serilog to forward an
out-of-process plugin’s Serilog events into the host log. Never log credentials or other reusable secrets.
Conditional fields
Section titled “Conditional fields”A configuration input can be conditionally visible while staying part of the form state - unlike structurally omitting an element from a Macro Deck UI tree. See Config and action flows and State and bindings.
Capability identity
Section titled “Capability identity”Declared capability ids are local. Macro Deck qualifies them with the owning integration or plugin identity before registration; do not build qualified ids yourself where an API asks for a local id.
In this section
Section titled “In this section”| Page | What it covers |
|---|---|
| Plugin hosting | Builder API, dependency injection, registration modes, lifecycle, reserved routes. |
| Capabilities | Every capability interface and how to choose. |
| Config and action flows | The two things Macro Deck calls a flow. |
| Macro Deck UI | Authoring, state and bindings, components, serving, headless testing. |
| Localization | Localization/*.resx, the typed API, the fallback chain, MDLOC diagnostics. |
| Logging and health | Serilog forwarding and the health endpoints. |
| Authentication | Credentials, session tokens, pairing. |
| Testing plugins | The harness, the protocol host, what to assert. |
| Conformance suite | Framework-agnostic contract checks. |
| Analyzers | Compile-time diagnostics and suppression. |
| Capability parity | Where out-of-process differs from in-process. |
Beyond the SDK: the plugin CLI builds, validates and packages; the manifest and protocol references document the formats underneath.