Plugin Template for PCL-ME.
An annotated starter project for a PCL-ME extension. It is based on the official
examples/HelloExtension sample and is meant to be copied
and edited, not published as-is. You can refer to the docs of
PCL-ME for more details.
This is a template, not a demo. The extension id is the placeholder
your.plugin, the UI is intentionally generic, and every place that normally needs your own code is marked with aTODOcomment.
The template builds, packs and installs without changes, so you can verify the toolchain first and then replace the placeholders.
- Copy the folder to a new name, for example
MyPlugin. - Rename
PluginTemplate.csprojand setAssemblyName/RootNamespaceif you want a different assembly name. - Rename the
PluginTemplatenamespace andPluginTemplateExtension/TemplateWorkerclasses inPluginTemplateExtension.cs. - Update
extension.json:id: your lowercase id, for exampleme.myplugin(letters, digits,.and-),name,description,author,version,entryAssembly: the DLL file name, for exampleMyPlugin.dll,entryType: the full type name, for exampleMyPlugin.MyPluginExtension,- command ids and setting keys (and keep them in sync with the code),
titleKeyvalues must exist in every locale file you ship.
The folder name does not have to match the assembly name, but entryAssembly must match the
DLL that is packaged.
PluginTemplateExtension.cs is grouped into marked sections:
| Section | Purpose | Keep? |
|---|---|---|
| Page | Main native Avalonia view opened by the command / menu / search | almost always |
| Instance tab | Per-instance view; receives view.InstanceId |
optional |
| Command | Registered handler for the manifest command(s) | usually |
| Instance action | Adds an entry to the instance right-click menu | optional |
| Search provider | Adds results to the global command palette | optional |
| Event subscription | Listens to launcher events such as instance changes | optional |
| Worker | Separate process for long-running or risky work | optional |
Every TODO comment says what to replace. The important ones:
PageIdand allExtensionAction/ExtensionViewids must start with your extension id plus a dot. The host validates this.context.Settings.Get("greeting", ...)reads a setting declared inextension.json. Add or remove settings in both places.context.Text.Get("key")reads the extension locale; add the matching key to everyLocales/<locale>.jsonfile.context.Launcher.Notify(...)shows a launcher notification; replace it with your action.DisposeAsyncis where you release anything not owned by the host (windows, workers, subscriptions you created yourself).
extension.json cannot contain comments, so the fields are documented here and by the
TODO/REPLACE ME markers in the file.
The project references the public extension SDK from a sibling PCL-ME checkout:
..\PCL-ME\src\PCL.Extensions.Avalonia\PCL.Extensions.Avalonia.csproj
Adjust the ProjectReference in PluginTemplate.csproj if your checkout is elsewhere.
dotnet build .\PluginTemplate.csproj -c Releasedotnet publish .\PluginTemplate.csproj -c Release -o .\artifacts\publish
dotnet run --project ..\PCL-ME\tools\PCL.Tools.Extensions -- pack `
.\artifacts\publish .\artifacts\MyPlugin.pclext
dotnet run --project ..\PCL-ME\tools\PCL.Tools.Extensions -- validate `
.\artifacts\MyPlugin.pclextRename the archive to your plugin name. validate checks the manifest, files and locale keys;
activation is checked when the launcher loads the extension.
- PCL-ME → Settings → Extensions → Install.
- Select the
.pclextarchive. - Enable the extension in the manager.
- Open the page from the Extensions menu, the global search
(Ctrl+Shift+P / Cmd+Shift+P), or the command declared in
extension.json.
A new external extension starts disabled. Updates that replace a loaded assembly take effect after a restart.
- Extension id, name, author and version changed in
extension.json. -
entryAssemblyandentryTypematch the built DLL and class. - All UI contribution ids start with
<your id>.. - Commands/settings declared in the manifest are registered/read in code with the same keys.
- Every
titleKeyexists in every shipped locale. - Unused optional sections removed from code and manifest.
-
DisposeAsyncreleases your own resources. -
pack+validatesucceed. - Tested from a clean install (disable/enable, restart after update).
- Reference only the public SDK (
PCL.Extensions.Avalonia/PCL.Extensions.Contracts). Never referencePCL.Frontend.AvaloniaorPCL.Core.Backend; the loader rejects those. - Use native Avalonia controls; the template uses
PclCard,PclButtonandPclSearchBoxfromPCL.UI, but plain Avalonia controls and XAML are fine too. - Keep extension UI ids and settings keys namespaced. Do not rely on launcher internals or visual-tree structure.
- The extension page is a workspace overlay; use its back button to return to the launcher.
- A worker's stdout is reserved for the host protocol; log diagnostics to stderr.
PluginTemplate.csproj project + SDK reference
PluginTemplateExtension.cs annotated IExtension entry point + worker sample
extension.json manifest: id, command, setting, entry type
Locales/en-US.json English text
Locales/zh-Hans.json Chinese text
README.md this guide