# VIPR Plugins

VIPR uses a modular plugin architecture to extend functionality. Plugins can add new handlers, hooks, filters, and complete workflows.

## Built-in Plugins

These plugins are included with vipr-core and provide core functionality:

- **[Inference Plugin](built-in/inference.md)** - 5-step ML inference workflow system
  - Domain-agnostic design for ML/AI inference
  - Handler system for pluggable components
  - Hook and filter system for extensibility
  - Configuration-driven pipeline

- **[Adapter Plugin](built-in/adapter.md)** - Function-based plugin integration path
  - Decorator API for existing Python functions
  - Automatic wrapper generation for VIPR handlers/callbacks
  - `vipr adapter init-config` scaffold command for workflow YAML

- **[Normalizers Plugin](built-in/normalizers.md)** - Data normalization methods
  - MinMax, Z-Score, and Log normalization
  - Filter-based architecture for Step 3 of inference workflow
  - DataSet-aware transformations with error propagation support

- **[API Plugin](built-in/api/)** - FastAPI endpoint generation and data collection
  - @api decorator for automatic endpoint generation from CLI controllers
  - DataCollector for structured UI data (tables, diagrams, images, logs)
  - UUID-based result storage with automatic file extraction

- **[HuggingFace Plugin](built-in/huggingface.md)** - HuggingFace model management
  - Model sync from HuggingFace repositories
  - Support for multiple repositories and models
  - Configurable storage paths for weights and configs
  - CLI command for explicit model provisioning

- **[Discovery Plugin](built-in/discovery.md)** - Component registry and introspection
  - Decorator-based discovery for handlers, hooks, and filters
  - CLI/API endpoints for component listing and filtering

- **[Registry Plugin](built-in/registry.md)** - Model package registry for reproducible loading
  - ModelPackage manifest + artifact contract
  - Versioned URIs (`vipr://...`) and alias promotion
  - Generic registry loader with domain builder dispatch

- **[Performance Plugin](built-in/performance.md)** - Inference execution time tracking
  - Automatic timing metrics for workflow and steps
  - Persisted performance metadata in result output

## Domain-Specific Plugins

Plugins that extend VIPR for specific scientific domains:

- **[Reflectometry Plugin](external/reflectometry/index.md)** - Reflectometry analysis
  - Reflectorch model integration
  - RefNx physics-based refinement
  - Specialized data loaders and visualizations

- **[GID Plugin](external/gid/index.md)** - GIWAXS/GID Bragg peak detection
  - TIFF and HDF5 loaders
  - ONNX inference via mlgidDETECT
  - Structured peak table + detection image outputs

## Plugin Management

### Installing Plugins

External plugins can be installed via pip:

```bash
# Example: Install the reflectometry plugin
pip install git+https://codebase.helmholtz.cloud/vipr/vipr-reflectometry-plugin.git
```

Plugins are automatically discovered through Python entry points defined in `pyproject.toml`. VIPR loads plugins in two stages:

1. **Internal plugins** - Built-in plugins from vipr-core (loaded via Cement's plugin system)
2. **External plugins** - Installed packages (loaded via `discover_and_load_external_plugins()` during app setup)

This two-stage loading ensures proper initialization order and allows external plugins to extend core functionality.

### Listing Installed Plugins

```bash
# List all installed plugins
vipr plugins list

# Show discovery registry summary
vipr discovery plugins
```

### Plugin Configuration

Plugins can be controlled via YAML files (e.g., `vipr-plugins.yaml` in your working directory):

```yaml
plugin.my_plugin:
  enabled: true
  # Plugin-specific configuration
```

**Note:** The key `plugin.my_plugin` matches the entry point name defined in the plugin's `pyproject.toml`, not the package name.

## Developing Plugins

### Quick Start

For a working example, check out [example-plugin](../../../example-plugin).

### Naming Convention

**Recommended package naming:** `vipr_{plugin_name}`

While not technically required, this convention:
- **Enables automatic discovery filtering**: Discovery commands can filter by plugin name
- **Creates consistency**: Entry point name matches package structure
- **Simplifies component discovery**: Pattern matching works automatically

**Example:**
```toml
# pyproject.toml
[project]
name = "vipr-reflectometry"  # PyPI package name (with dash)

[project.entry-points."vipr.plugins"]
reflectometry = "vipr_reflectometry:load"  # Plugin name → package:load_function
```

**Entry Point Format:** `plugin_name = "package_name:load_function"`
- `reflectometry` - Plugin identifier
- `vipr_reflectometry` - Python package to import
- `:load` - Function to call for plugin initialization (receives `app` parameter)

**Understanding Entry Points:**

Entry points are Python's standard plugin discovery mechanism. When a package is installed (via pip), its entry points are registered in the Python environment. This allows applications to automatically discover installed plugins without knowing their names or import paths.

**How VIPR uses entry points:**

1. **Automatic Plugin Discovery**: 
   ```python
   # In vipr-core/vipr/main.py
   entry_points = importlib.metadata.entry_points(group="vipr.plugins")
   # Finds all packages with [project.entry-points."vipr.plugins"]
   ```
   VIPR queries Python for all packages that registered under the `"vipr.plugins"` group.

2. **Load Function Resolution and Execution**:
   The entry point specifies both the package and the load function:
   ```python
   # Entry point: reflectometry = "vipr_reflectometry:load"
   from vipr_reflectometry import load  # Import the load function
   load(app)  # Call it with VIPR app instance
   ```
   The `:load` part tells Python which function to call for plugin initialization.

3. **Plugin Identifier**: 
   The entry point name (`reflectometry`) is used in logs, CLI output, and configuration

**Why this matters:**
- **No manual registration needed**: Installing a plugin via pip automatically makes it available to VIPR
- **Clean separation**: Each plugin is an independent Python package
- **Standard Python mechanism**: Uses Python's built-in plugin architecture

**Important Distinction:**
- Entry point name **"reflectometry"** = Plugin identifier for loading/config
- Package name **"vipr_reflectometry"** = Module path used for component filtering

```bash
# Plugin filtering uses the PACKAGE name, not entry point name
vipr discovery hooks --plugin reflectometry
# → Matches module paths starting with: vipr_reflectometry.*
```

**Package structure:**
```
vipr_reflectometry/           # Root package (matches entry point)
├── __init__.py
├── reflectorch/
│   ├── model_loader/
│   └── ...
└── shared/
    ├── data_loader/
    └── ...
```

This naming allows filtering components by plugin:
```bash
vipr discovery hooks --plugin reflectometry  # Matches vipr_reflectometry.*
```

See [Discovery Plugin documentation](built-in/discovery.md#plugin-filtering) for technical details on how plugin filtering works.

### Full Plugin Development Guide

See **[Developing Plugins](developing.md)** for a step-by-step guide on creating your own plugins.

## Plugin Architecture

VIPR plugins can:
- Register **handlers** for component interfaces (data loaders, model loaders, etc.)
- Register **hooks** for event-driven callbacks
- Register **filters** for data transformation
- Define **CLI controllers** for command-line interface
- Provide **configuration schemas** for validation
