Appearance
Spec: Plugin/Extension API
Overview
Provide a plugin system that allows users and third parties to extend DigitalWorks with custom components, analysis tools, exporters, and UI panels without modifying the core application.
Motivation
- Users with specialized needs can create custom components (FPGA primitives, industry-specific ICs).
- Educators can build course-specific extensions (grading tools, guided exercises).
- Community can contribute features without core team involvement.
- Keeps the core application lean while enabling unlimited extensibility.
Requirements
Functional Requirements
Plugin System
- Plugin Discovery: Automatically discover plugins in a designated folder.
- Plugin Loading: Load .NET assemblies at runtime as plugins.
- Plugin Lifecycle: Init, Activate, Deactivate, Unload lifecycle hooks.
- Plugin Isolation: Plugins cannot crash the host application.
- Plugin Manager UI: View installed plugins, enable/disable, configure.
- Hot Reload: Reload plugins without restarting the application (dev mode).
Extension Points
- Custom Components: Define new components with custom logic, pins, and rendering.
- Custom Exporters: Add new export formats (File → Export → [plugin format]).
- Custom Importers: Add new import formats.
- Custom Analysis Tools: Add analysis panels/windows.
- Custom Renderers: Override or extend component rendering.
- Menu Extensions: Add custom menu items and commands.
- Toolbox Extensions: Add custom categories and components to the toolbox.
- Context Menu Extensions: Add items to right-click context menus.
- Event Hooks: Subscribe to circuit events (component added, simulation step, etc.).
Scripting (Lightweight Alternative)
- C# Scripting: Write simple components using C# scripting (Roslyn) without full projects.
- Script Editor: Built-in editor for quick component scripts.
- Script Components: Components defined by a script file (evaluate function).
Non-Functional Requirements
- Plugins cannot access the filesystem beyond their own data folder without permission.
- Plugin API is versioned; old plugins work with new app versions (backward compatible).
- Plugin loading adds < 500ms to application startup.
- Plugins are sandboxed: memory limits, no UI thread blocking.
- API is well-documented with examples and templates.
Design
Plugin Architecture
DigitalWorks Host
→ PluginManager
→ discovers plugins in /plugins/ folder
→ loads assemblies via AssemblyLoadContext (isolation)
→ creates plugin instances
→ registers extension points
Plugin Assembly
→ implements IPlugin interface
→ uses DigitalWorks.SDK NuGet package
→ declares capabilities via attributesCore Interfaces
csharp
public interface IPlugin
{
string Name { get; }
string Version { get; }
string Description { get; }
void Initialize(IPluginContext context);
void Activate();
void Deactivate();
}
public interface IPluginContext
{
IComponentRegistry Components { get; }
IExporterRegistry Exporters { get; }
IMenuRegistry Menus { get; }
IEventBus Events { get; }
IStorageProvider Storage { get; } // plugin-local storage
}
public interface ICustomComponent
{
string TypeName { get; }
string Category { get; }
IReadOnlyList<PinDefinition> Pins { get; }
void Evaluate(IEvaluationContext context);
ShapeDefinition GetShape();
}Plugin Manifest
Each plugin folder contains a plugin.json:
json
{
"name": "My Custom Components",
"version": "1.0.0",
"author": "John Doe",
"description": "Adds custom FPGA primitives",
"assembly": "MyPlugin.dll",
"minHostVersion": "2.0.0",
"permissions": ["filesystem:read", "network:none"],
"extensionPoints": ["components", "exporters"]
}Script Component Example
csharp
// File: scripts/my_gate.csx
#r "DigitalWorks.SDK"
[Component("MySpecialGate", Category = "Custom")]
[Pin("A", Direction.Input)]
[Pin("B", Direction.Input)]
[Pin("Y", Direction.Output)]
public void Evaluate(IEvaluationContext ctx)
{
var a = ctx.GetInput("A");
var b = ctx.GetInput("B");
ctx.SetOutput("Y", (a == Signal.High && b == Signal.Low) ? Signal.High : Signal.Low);
}Plugin Manager UI
┌──────────────────────────────────────┐
│ Plugin Manager │
├──────────────────────────────────────┤
│ Installed Plugins: │
│ │
│ [✓] FPGA Primitives v1.2.0 │
│ Adds Xilinx LUT, BRAM, DSP │
│ [Configure] [Disable] [Remove] │
│ │
│ [✓] SPICE Exporter v0.9.0 │
│ Advanced SPICE netlist export │
│ [Configure] [Disable] [Remove] │
│ │
│ [ ] Grading Tool v1.0.0 (disabled) │
│ Auto-grades student circuits │
│ [Configure] [Enable] [Remove] │
│ │
│ [Install from file...] [Open folder]│
└──────────────────────────────────────┘Implementation Tasks
- Design and document the Plugin SDK (interfaces, attributes, base classes).
- Create
DigitalWorks.SDKNuGet package (public API surface). - Implement
PluginManagerwith assembly discovery and loading. - Implement
AssemblyLoadContext-based isolation. - Implement
IComponentRegistryfor custom component registration. - Implement
IExporterRegistryfor custom export formats. - Implement
IMenuRegistryfor menu/toolbar extensions. - Implement
IEventBusfor plugin event subscriptions. - Implement C# scripting engine (Roslyn) for script components.
- Create Plugin Manager UI.
- Create plugin project template (dotnet new template).
- Write SDK documentation and sample plugins.
Risks & Open Questions
- Security: how to sandbox plugins effectively in .NET? (AssemblyLoadContext has limits)
- Should there be a plugin marketplace/repository?
- How to handle plugin conflicts (two plugins register same component name)?
- Performance impact of event bus with many subscribers?
- Should plugins be able to modify the UI (add panels, windows)?
- Versioning: how to handle breaking API changes without breaking all plugins?
Priority
Medium-Low — Significant architecture investment; valuable for ecosystem growth.