Plugin Package Structure

Minimal Structure

For a directory-based local plugin, the discovery anchor is plugin.py:

example_plugin/
└── plugin.py

An __init__.py file may be included for conventional packaging, but it is not required by AstronomicAL’s local directory loader.

Larger plugins should split implementation code into sibling modules:

example_plugin/
├── plugin.py
├── panel.py
├── actions.py
├── service.py
├── assets/
└── tests/

The Entry Module

plugin.py is the runtime entry module. It should expose the plugin manifest and register(api) function.

Optional lifecycle hooks such as on_enable(...) and on_disable(...) also belong at the plugin entry boundary when they are needed.

Keep plugin.py cheap to import. Development and bundled plugins without a static manifest may be imported during discovery, before the plugin is enabled.

Relative Imports

Local directory plugins are loaded as synthetic Python packages. AstronomicAL loads plugin.py as the package root and places the plugin directory on its package path.

Normal relative imports therefore work:

from . import panel
from .actions import build_result
from .service import create_client

Do not depend on the value of __name__ or assume that the directory name becomes the top-level Python module name. Local plugins receive a generated synthetic package name.

Static Manifests

AstronomicAL can discover a plugin from a static JSON or TOML manifest without importing its Python runtime first. Supported local manifest filenames include forms such as:

astronomical-plugin.json
astronomical-plugin.toml
plugin.json
plugin.toml

The managed user-plugin directory requires static-manifest discovery so third-party Python code does not need to execute merely to appear in Plugin Manager.

Development plugin paths can still use import-based discovery when no static manifest is present.

Heavy Imports

Import optional or expensive dependencies inside the panel factory, action, service factory or implementation module that actually needs them.

For example, a plugin with an optional astronomy client should avoid importing that client merely to expose its manifest.

Caution

Importing or discovering a plugin must not open a network connection, scan a large directory, start a background thread, submit jobs or mutate global application state.

Local Discovery

AstronomicAL searches configured plugin locations for directory plugins containing plugin.py. Development search paths may also contain simple single-file .py plugins.

The application can additionally discover installed Python packages through the AstronomicAL plugin entry-point groups.

For multi-file local plugins, prefer the directory structure above so sibling modules can use ordinary relative imports.

Assets

Keep read-only static assets, templates and small example resources inside the plugin package where practical. Resolve them relative to the plugin package rather than from the process working directory.

Do not write generated results, caches or user data into the installed plugin source directory. Managed plugin updates or uninstall operations may replace or remove that code directory.

Generated tabular working data belongs in datasets, reusable derived results belong in artifacts, and other persistent files should be written to an explicit user, project or configured cache location.