Describe the bug
For a Swift trigger plugin conforming to BTTTriggerPluginInterface, BTT instantiates the plugin and calls startObserving() and stopObserving() as expected, but didReceiveNewConfigurationValues is never invoked — neither at instantiation (to deliver saved config) nor after the user edits a form field and clicks Save.
Additionally, BTT does not appear to persist the form field's value: no plugin_var_* variable is created in the variable inspector, and calling delegate.getVariable("plugin_var_") from startObserving returns nil after the user saves.
The plugin is otherwise correctly recognized:
- respondsToSelector:@selector(didReceiveNewConfigurationValues:) returns YES on the instance.
- BTT's plugin manager does not log "Failed to load bundle" or "does not conform to BTTTriggerPluginInterface".
- BTT's internal log shows "save", "saving", "did rebuild form" on the save action.
but our callback is never reached.
Minimal reproduction:
- Create a trigger plugin matching the structure of the docs'
FileWatcherTriggersample (with [String: Any]? → [AnyHashable: Any]? and .string → BTTFormDataString to satisfy the bundled BTTSwiftPluginHeader.h). - Install, add the trigger, edit the field, click Save → callback never fires.
Related issues observed during diagnosis:
- BTT caches the form definition per trigger instance: changing configurationFormItems() and recompiling shows the OLD form until the trigger is deleted and re-added.
- BTTFormTypeCheckbox and BTTFormTypePopupButton both exhibit the same non-delivery as TextField.
- BTTFormTypePopupButton additionally triggers a SwiftUI Array.== brk-1 crash inside AttributeGraph::LayoutDescriptor::Compare during form render when no defaultValue is set.
- Setting formItem.autoSave = true on a TextField causes the field's contents to clear after every keystroke.
Affected input device
Not applicable — this is a Swift plugin / configuration-form issue, not an input device.
Screenshots
N/A (issue is in the plugin protocol delivery, not visible UI).
Device information
Type of Mac: MacBook Pro (MacBookPro18,4 — 14"/16" M1 Pro/Max)
macOS version: 26.4.1 (build 25E253)
BetterTouchTool version: 6.503 (build 2026050808)
Additional information
-
The plugin compiles cleanly against /Applications/BetterTouchTool.app/Contents/Resources/BTTSwiftPluginHeader.h. The header declares:
-(void)didReceiveNewConfigurationValues:(NSDictionary * _Nullable)configurationValues;
(untyped NSDictionary, imported into Swift as [AnyHashable: Any]?) -
The defaultConfiguration() class method referenced in BTT's binary strings was implemented as an experiment and did not change the behavior.
-
Expected: didReceiveNewConfigurationValues: should be invoked at trigger instantiation with any saved config, and again whenever the user changes a form field and saves. Form-field values should be persisted by BTT and surfaced as plugin_var_* variables (or accessible via delegate.getVariable).