-
Notifications
You must be signed in to change notification settings - Fork 1
Debugging
There is no plugin-side debugger story to invent — a plugin is a .NET class library loaded into the LoupixDeck host process, so you debug it by attaching your IDE to the running host. This page covers the practical loop: where to drop the DLL, how to attach, what to log, and the failure modes you will hit first.
The host scans a per-user plugin root and loads every plugin folder it finds inside. The exact path is owned by the LoupixDeck core (not the SDK); the default conventions are:
| OS | Default plugin root |
|---|---|
| Windows | %AppData%\LoupixDeck\plugins\ |
| Linux |
$XDG_CONFIG_HOME/LoupixDeck/plugins/ (falls back to ~/.config/LoupixDeck/plugins/) |
| macOS | ~/Library/Application Support/LoupixDeck/plugins/ |
If your install diverges from these defaults, check the LoupixDeck core README — the SDK does not encode the path.
Each plugin lives in its own subfolder named after PluginMetadata.Id:
%AppData%\LoupixDeck\plugins\
└── myplugin\
├── MyPlugin.dll
├── (runtime deps)
└── settings.json ← created by the host on first save
-
Build your plugin:
dotnet build(Debug, not Release — you want symbols and unoptimized code). - Stop LoupixDeck if it is running. Windows holds a file lock on loaded DLLs; you cannot overwrite them while the host is up.
-
Copy the build output into
<plugin root>/<id>/. A post-build copy is the most reliable way to keep the folder in sync — see snippet below. - Start LoupixDeck.
-
Attach your debugger to the host process:
-
Rider / Visual Studio: Debug → Attach to Process… → pick the
LoupixDeckprocess. - VS Code (C# Dev Kit): Run → Attach to .NET Process… → pick the host.
-
Rider / Visual Studio: Debug → Attach to Process… → pick the
- Set breakpoints in your plugin code. They bind as soon as the host loads
your assembly (after
Initialize).
Add this to your plugin .csproj so every build lands in the host's plugin
folder. Adjust the path to your OS / install.
<Target Name="CopyToPluginFolder" AfterTargets="Build">
<PropertyGroup>
<PluginInstallDir>$(AppData)\LoupixDeck\plugins\$(AssemblyName.ToLower())</PluginInstallDir>
</PropertyGroup>
<MakeDir Directories="$(PluginInstallDir)" />
<ItemGroup>
<PluginFiles Include="$(OutputPath)**\*.*"
Exclude="$(OutputPath)LoupixDeck.PluginSdk.dll;$(OutputPath)LoupixDeck.PluginSdk.xml" />
</ItemGroup>
<Copy SourceFiles="@(PluginFiles)"
DestinationFolder="$(PluginInstallDir)\%(RecursiveDir)"
SkipUnchangedFiles="true" />
</Target>The Exclude is deliberate — never ship the SDK DLL alongside your plugin
(Packaging & Distribution explains
why).
To start debugging immediately on F5, set the LoupixDeck executable as the
launch target in your plugin project's launchSettings.json:
{
"profiles": {
"LoupixDeck (attach)": {
"commandName": "Executable",
"executablePath": "C:\\Program Files\\LoupixDeck\\LoupixDeck.exe"
}
}
}F5 builds (firing the post-build copy), launches the host, and attaches the debugger to it in one step.
IPluginLogger is the only sanctioned way to surface diagnostic output. Every
log line is scoped to your plugin (tagged with Metadata.Id) so you can grep
the host log for just your plugin's output.
_host.Logger.Info("Connected to backend, polling every 5s");
_host.Logger.Warn($"Slow response: {ms} ms");
_host.Logger.Error("Failed to fetch scenes", ex);Wrap every Execute body in try/catch. Exceptions thrown from Execute
are caught by the host but appear as a generic execution failure with no
context. A two-line try/catch that calls Logger.Error("what was being attempted", ex)
turns a silent failure into an actionable line in the log.
Where the host writes its log file is a core concern — check the LoupixDeck
core README. While debugging, the same lines also appear in the IDE's debug
output (Console.Error / Trace).
IPluginSettings is backed by JSON on disk. While debugging you can open the
file directly:
<plugin root>/<id>/settings.json
Edit it while the host is stopped to seed test state, then start the host.
Don't edit it while the host is running — the host owns the file and may
overwrite your changes on the next Save().
-
The plugin doesn't show up. Check the host log for a load error from your plugin's folder. The usual causes are:
-
SDK major-version mismatch.
PluginMetadata.SdkVersion.Majormust equal the host's SDK major version. Set it toSdkInfo.Versionand rebuild against the matching SDK. -
No concrete
LoupixPluginsubclass. The host scans your assembly for exactly one concrete (non-abstract, public) subclass ofLoupixPlugin. If yours isinternalorabstractit is invisible. -
Bundled SDK DLL. A
LoupixDeck.PluginSdk.dllalongside your plugin fights with the host's own copy. Delete it from the plugin folder.
-
SDK major-version mismatch.
-
The plugin loads but no commands appear.
GetCommands()returned empty, or an exception inInitializepoisoned the plugin. Check the log for an error tagged with your plugin'sId. -
Executedoes "nothing". Almost always a swallowed exception. Add thetry/catch+Logger.Errordescribed above and try again. -
File is lockedduring copy. LoupixDeck is still running. Stop the host before rebuilding — Windows holds a lock on loaded plugin DLLs. -
Breakpoints never hit. Wrong PDB next to the DLL (copy
.pdbalong with.dll), or you attached to the wrong process. Confirm the loaded assembly's path in the debugger's Modules window.
Getting started
API reference
Advanced
Operations
Release notes