Skip to main content
A trigger starts a workflow run in response to an external event. A plugin trigger is a polling trigger: the platform calls it on an interval, and it returns any new events plus the state it wants to see on the next poll. The platform owns everything hard about triggers — scheduling, state persistence, and routing events to workflow runs — exactly as it does for built-in triggers. Your trigger only answers one question: given my config and the state from last time, what’s new?
Trigger poll() runs inside the plugin’s sandbox worker, invoked over JSON-RPC (trigger.poll). Read How plugins run for the execution model — network posture, logging to stderr, and file callbacks all apply here too.

The interface

A trigger subclasses BasePollingTrigger[ConfigType] and implements poll.

Class attributes

ConfigType is your TriggerConfiguration subclass (a NodeConfiguration, so its fields are Parameter(...) with optional display= widgets, just like a node’s config). It reaches your instance as self.config.

poll contract

  • state is whatever your previous poll returned as its second element (an empty dict on the first poll). Use it as a cursor — a last-seen id, a timestamp, a page token.
  • Return (events, new_state). events is a list of JSON-serializable dicts; each dict’s fields become the trigger inputs for one workflow run. Return [] when nothing is new. new_state is persisted by the platform and handed back on the next poll.
Emit one event per thing that happened. The platform turns each event into a run; your outputs map tells the editor which fields the event carries so they can be bound to workflow inputs.
A dropped connection mid-poll is not retried (see at-most-once side effects). Advance your cursor in new_state only for events you actually returned, so a re-poll after a failure re-emits rather than skips.

Using credentials

If a trigger needs to authenticate to an external service, declare the credential type(s) it uses and read them from ctx:
The credential type is defined by a BaseIntegration / BaseCredentials pair in the same plugin — see Creating integrations.

Registering the trigger

Return your trigger classes from the plugin’s triggers() method:
Each trigger is serialized into the plugin manifest (TriggerDefinition) at packaging time. Regenerate manifest.json whenever a trigger’s name, config, or outputs change.
A plugin must provide at least one node, integration, or data source — triggers alone don’t make a valid plugin. Ship a trigger alongside the node or integration it drives.
On the platform side, an installed plugin trigger is resolved on demand from the plugin components table (a read-through in the trigger registry), so it works without being eagerly registered at startup.

Testing

  • Locally, noxus plugin serve exercises your plugin’s surfaces, except trigger.poll — polling is driven only by the platform, so the local dev server does not expose it. Test poll directly instead:
  • End to end, install the plugin against a running stack and let the platform schedule the poll and create runs. The reference plugin in tests/plugins/ and its run_plugin_e2e.py driver exercise a trigger this way.

How plugins run

The sandbox execution model behind trigger.poll.

Creating integrations

Define the credentials a trigger reads from ctx.