Documentation / Extend

Plugins

#What plugins are

A plugin is one script file that adds a block to the toolbox, with its own settings, working like any built-in node. Plugins need a paid plan. The Plugins page has Installed, Library and Editor tabs.

#Four ways to get one

Library — published by the mobyx team, each file checked against a checksum.
Make with AI — describe what you want (or say “make a plugin that …” in the AI Assistant). A model writes it; you read the code; you press Install. Change it edits what is there from a sentence.
From a workflow — the open workflow becomes one block that runs it (once or several times). Passwords and keys are not copied in.
By hand — New Plugin writes a working starter; the Editor edits it.

#How a made-with-AI plugin is checked

Nothing the model writes is trusted or run just by being written. The model is given the real list of phone actions; the file is read against the plugin safety rules; it is then really loaded and its node made, so a plugin that reads well but cannot start is caught; a failed check is shown to the model to fix (twice at most); and it is only installed after you have read it. A plugin that passes has been shown to start: try it in a one-step workflow to see that it does what you meant.

#What a plugin may and may not do

Plugin code runs next to mobyx, so it is kept apart. It may use the public parts (nodes.base.property_node, executors.base_executor, backend.adb_actions, sdk) and Python's own library and installed packages. It may not import the private parts (accounts, plans, payments, AI keys, stored secrets) or use eval, exec, compile, __import__, importlib, ctypes or pickle. This stops mistakes and casual abuse; it is not a separate process, so install a plugin from a stranger as you would any program from a stranger.

#A plugin file

from nodes.base.property_node import PropertyNode
from executors.base_executor import BaseExecutor

class MyNode(PropertyNode):
    __identifier__ = "plugins.custom"
    NODE_NAME = "My block"
    def __init__(self):
        super().__init__()
        self.add_text_property("message", default="Hello", title="Message", group="Settings", order=1)

class MyExecutor(BaseExecutor):
    def can_execute(self, node):
        return self.get_node_name(node) == "My block"
    def execute(self, serial, node, context=None):
        return {"success": True}

NODE_CLASS = MyNode
EXECUTOR_CLASS = MyExecutor
PLUGIN_NAME = "My block"
PLUGIN_DESCRIPTION = "What it does."