Plugins and dynamic registration

Entry-point plugins

Third-party packages can register their own FA_* commands by declaring an automation_file.actions entry point in their pyproject.toml:

[project.entry-points."automation_file.actions"]
my_plugin = "my_plugin:register"

where register is a zero-argument callable returning a Mapping[str, Callable]. Once the plugin is installed into the same virtual environment, build_default_registry() picks it up automatically — no caller changes required:

# my_plugin/__init__.py
def greet(name: str) -> str:
    return f"hello {name}"

def register() -> dict:
    return {"FA_greet": greet}
# consumer code, after `pip install my_plugin`
from automation_file import execute_action
execute_action([["FA_greet", {"name": "world"}]])

Plugin failures (import errors, factory exceptions, wrong return shape, registry rejection) are logged and swallowed so one broken plugin cannot break the library.

Dynamic package registration

from automation_file import package_manager, execute_action

package_manager.add_package_to_executor("math")
execute_action([["math_sqrt", [16.0]]])   # -> 4.0

Warning

package_manager.add_package_to_executor effectively registers every top-level function / class / builtin of a package. Do not expose it to untrusted input (e.g. via the TCP, HTTP, or MCP server (Claude Desktop / Claude Code) servers).