| name | plugin-architecture |
| description | machNotch plugin architecture rules — NotchPlugin protocol, lifecycle, DI via PluginContext, HUD event bus, PluginSettings. Auto-loaded when working in Plugins/. |
| user-invocable | false |
| paths | **/Plugins/**/*.swift, **/machNotch/**/*.swift |
Plugin Architecture Rules
Full reference: docs/AGENT-GUIDELINES.md → Plugin Architecture sections.
Every Plugin Must
- Conform to
NotchPlugin protocol
- Be
@Observable and @MainActor
- Receive all dependencies via
PluginContext in activate()
- Clean up all resources in
deactivate()
@Observable
@MainActor
final class MyPlugin: NotchPlugin {
let id = "com.machnotch.myplugin"
private var services: ServiceContainer?
func activate(context: PluginContext) async {
self.services = context.services
}
func deactivate() async {
self.services = nil
}
}
HUD / Sneak Peek
Never call coordinator methods directly. Always publish via event bus:
coordinator.showSneakPeek(.music)
PluginEventBus.shared.publish(SneakPeekRequestedEvent(type: .music))
Service Access
Only via PluginContext.services — never import or access services directly:
func activate(context: PluginContext) async {
let music = context.services.music
let battery = context.services.battery
}
Settings
Use namespaced PluginSettings. Never access Defaults directly:
let settings = PluginSettings(namespace: id)
settings.set("volume", value: 0.8)
let volume: Double = settings.get("volume", default: 1.0)
Inter-Plugin Communication
Use PluginEventBus only. Plugins must never import each other:
eventBus.emit(MusicPlaybackChangedEvent(isPlaying: true, track: track))
eventBus.subscribe(to: CalendarEventStartingSoonEvent.self) { [weak self] event in
await self?.handleUpcomingMeeting(event.event)
}
Display Priority
Choose appropriate priority — don't default to .high or .critical:
| Priority | Use case |
|---|
.background | Ambient info, yields to everything |
.normal | Standard plugin content |
.high | Time-sensitive (downloads, timers) |
.critical | Errors, alerts — use sparingly |
Settings Pattern: Dual Environment Keys
@Environment(\.settings) var settings
@Environment(\.bindableSettings) var settings
New Plugin Checklist