How the Generator Registry Initializes and Manages AI Model Adapters in Modly

The GeneratorRegistry discovers extensions from the filesystem, instantiates generators in direct or subprocess mode, and provides runtime APIs for model switching and hot-reloading.

The Modly platform uses a flexible GeneratorRegistry system to handle AI model adapters (called extensions). This registry eliminates tight coupling between the core application and individual model implementations, allowing dynamic discovery of new generators without code changes. Understanding how the generator registry initializes and manages AI model adapters is essential for extending Modly with custom models or troubleshooting adapter loading issues.

Extension Discovery on Startup

When the application launches, the registry begins its initialization by scanning for available extensions. This discovery phase happens in _discover_extensions(), located in api/services/generator_registry.py at lines 45-53.

The discovery process follows these steps:

  1. Locate the extensions directory – The registry checks for an EXTENSIONS_DIR environment variable. If unset, discovery is skipped entirely.
  2. Validate extension structure – Each subdirectory must contain both manifest.json and generator.py to qualify.
  3. Parse and validate manifests – The manifest is read and verified to be of model type (as opposed to other extension types).
  4. Build the extension map – Valid entries are stored as tuples mapping a full ID ("<ext_id>/<node_id>") to (GeneratorClass, node manifest, extension path).

This approach allows Modly to support an arbitrary number of model extensions without hardcoding their locations or configurations.

Generator Instantiation: Direct vs. Subprocess Mode

After discovery completes, GeneratorRegistry.initialize() (lines 67-81 of generator_registry.py) instantiates each generator. The registry supports two loading strategies depending on what the extension provides:

Direct mode (legacy) – When cls is not None, the registry instantiates the concrete generator class directly. The constructor receives the model-specific directory and workspace folder. Additional manifest fields—hf_repo, hf_skip_prefixes, and params_schema—are attached as instance attributes for later use.

Subprocess mode – When no class is provided (cls is None), the registry verifies that a virtual environment (venv) exists in the extension directory. If valid, it wraps the model in an ExtensionProcess instance that isolates execution in a subprocess. This mode prevents dependency conflicts between models with incompatible requirements.

All successfully created generators populate the _generators dictionary, with their manifests stored in _manifests. Loading failures are captured in _errors for diagnostic access via load_errors().

Runtime Management API

The registry exposes a concise API for the rest of the application to interact with generators without managing their lifecycle directly:

  • get_active() – Returns the currently selected generator (defaulting to SELECTED_MODEL_ID), automatically downloading and loading it if necessary.
  • get_generator(model_id) – Retrieves a specific generator by its full ID.
  • switch_model(model_id) – Unloads the previous generator and activates the requested one.
  • reload() – Re-scans EXTENSIONS_DIR, clears existing state, and re-runs initialize() for hot-reloading without server restart.
  • all_status() / active_status() – Provide metadata (download status, load state, description, VRAM requirements) for UI rendering.

For subprocess-based generators, the registry ensures proper cleanup through ExtensionProcess.stop() when models are switched or shut down.

Code Examples

Obtaining and Using the Active Generator

from api.services.generator_registry import generator_registry

# Initialize the registry at application startup

generator_registry.initialize()

# Retrieve the active model (downloads and loads automatically if needed)

active_gen = generator_registry.get_active()

# Generate using the BaseGenerator API

result = active_gen.generate(prompt="A futuristic cityscape", seed=42)
print("Generated output saved to:", result.output_path)

Switching Models at Runtime

from api.services.generator_registry import generator_registry

# List available models

print("Available models:", list(generator_registry._generators.keys()))

# Switch to the 'sdxl' model

generator_registry.switch_model("sdxl")

# Verify the switch

new_gen = generator_registry.get_active()
print("Now using:", new_gen.__class__.__name__)

Hot-Reloading After Adding Extensions

from api.services.generator_registry import generator_registry

# Assume a new extension was added to EXTENSION_DIR

generator_registry.reload()

# Confirm new models are available

print("Models after reload:", list(generator_registry._generators.keys()))

Key Source Files

File Purpose
api/services/generator_registry.py Core registry implementation with discovery, instantiation, and management logic
api/services/generators/base.py BaseGenerator abstract class defining the interface all adapters must implement
api/services/extension_process.py ExtensionProcess wrapper for isolated subprocess execution
extensions/example/manifest.json Reference manifest showing required metadata fields
extensions/example/generator.py Example concrete generator for direct-mode loading

Summary

  • Discovery is filesystem-driven: Extensions are found by scanning EXTENSIONS_DIR for valid manifest.json + generator.py pairs.
  • Two instantiation modes exist: Direct mode instantiates Python classes directly; subprocess mode isolates models via ExtensionProcess when no class is provided.
  • Runtime flexibility is built-in: Hot-reloading, model switching, and status introspection require no application restarts.
  • Errors are non-fatal: Loading failures are captured and exposed through load_errors() without crashing the registry.

Frequently Asked Questions

How does Modly find new AI model adapters without restarting?

The reload() method re-scans EXTENSIONS_DIR, clears the existing registry state, and re-runs initialize(). This allows administrators to drop new extension folders into the configured directory and activate them immediately via API call or UI action.

What happens if an extension's virtual environment is missing?

For subprocess-mode extensions, the registry verifies venv existence during initialization. If missing, the extension is skipped and an error is recorded in _errors. The registry continues loading other extensions; no single failure prevents the system from starting.

Can the same model run in both direct and subprocess modes?

No—the loading mode is determined per-extension by whether generator.py exports a concrete class. If a class is present, direct mode is used. If cls is None after import, subprocess mode is selected. Extension authors choose this behavior by their implementation structure.

How does get_active() handle models that aren't downloaded yet?

get_active() checks the download status of the target model and triggers the download mechanism if needed. Only after the model assets are present does it proceed to load the generator into memory, ensuring the caller receives a ready-to-use instance.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →