MiniTensor's plugin module provides version metadata, Python-side plugin registries, lightweight custom-layer wrappers, and optional native shared-library loading. It is separate from the Rust custom-operation registry described in the custom operations guide: the current Python plugin API can store callbacks and metadata, but it does not expose a Python API that turns arbitrary Python functions into engine-level tensor kernels.
Plugins use semantic-version-like VersionInfo values. A plugin can declare the
minimum supported MiniTensor version and, optionally, a maximum supported
version.
import minitensor.plugins as plugins
current_version = plugins.VersionInfo.current()
minimum = plugins.VersionInfo(0, 1, 0)
if current_version.is_compatible_with(minimum):
print(f"MiniTensor {current_version} satisfies the minimum requirement")PluginBuilder creates a CustomPlugin after all required metadata fields are
provided.
import minitensor.plugins as plugins
plugin = (
plugins.PluginBuilder()
.name("my_custom_plugin")
.version(plugins.VersionInfo(1, 0, 0))
.description("A custom plugin for project-specific extensions")
.author("Your Name")
.min_minitensor_version(plugins.VersionInfo(0, 1, 0))
.build()
)
info = plugin.info
print(info.name, info.version, info.author)If name, version, description, author, or min_minitensor_version is
missing, build() raises ValueError.
A CustomPlugin can hold Python callbacks for initialization, cleanup, and a
custom-operations list. PluginRegistry stores these Python plugin objects by
name and rejects duplicate registrations.
import minitensor.plugins as plugins
plugin = (
plugins.PluginBuilder()
.name("example_plugin")
.version(plugins.VersionInfo(1, 0, 0))
.description("Demonstrates Python plugin metadata and callbacks")
.author("Plugin Developer")
.min_minitensor_version(plugins.VersionInfo(0, 1, 0))
.build()
)
def initialize_plugin(registry):
print("Plugin initialized")
def cleanup_plugin(registry):
print("Plugin cleaned up")
def get_custom_operations():
# The current Python API stores this callback but does not automatically
# convert Python callables into Rust-engine CustomOp registrations.
return []
plugin.set_initialize_fn(initialize_plugin)
plugin.set_cleanup_fn(cleanup_plugin)
plugin.set_custom_operations_fn(get_custom_operations)
registry = plugins.PluginRegistry()
registry.register(plugin)
assert registry.is_registered("example_plugin")
print(registry.get_plugin("example_plugin").info)
registry.unregister("example_plugin")CustomLayer is a small Python-callable wrapper. It stores named parameters and
calls a user-provided forward function with the input list supplied to
forward(...).
import minitensor as mt
import minitensor.plugins as plugins
layer = plugins.CustomLayer("scale")
layer.add_parameter("weight", mt.Tensor([2.0]))
def forward(inputs):
x = inputs[0]
weight = layer.get_parameter("weight")
return x * weight
layer.set_forward(forward)
out = layer.forward([mt.Tensor([3.0])])
print(out)If no forward function is set, forward(...) raises NotImplementedError. If a
parameter name is missing, get_parameter(name) raises KeyError.
The plugins.load_plugin(path) function is available in the Python module, but
it only loads shared libraries when the extension was compiled with the
dynamic-loading Cargo feature. Without that feature it raises
NotImplementedError.
import minitensor.plugins as plugins
try:
plugins.load_plugin("./my_plugin.so")
except NotImplementedError:
print("This MiniTensor build does not enable dynamic plugin loading")Other global helpers delegate to the Rust engine's native plugin registry:
list_plugins()returns loaded native plugin metadata.get_plugin_info(name)returns metadata for one loaded native plugin.is_plugin_loaded(name)checks native registry membership.unload_plugin(name)unloads a native plugin by name.
A compiled plugin implements the Rust Plugin trait and exports a constructor
symbol. The exact ABI is controlled by the engine crate and by whether the
consumer build enables dynamic loading.
use minitensor_engine::{CustomOp, CustomOpRegistry, Plugin, PluginInfo, Result, VersionInfo};
use std::sync::Arc;
pub struct ExamplePlugin {
info: PluginInfo,
}
impl ExamplePlugin {
pub fn new() -> Self {
Self {
info: PluginInfo {
name: "example_rust_plugin".to_string(),
version: VersionInfo::new(1, 0, 0),
description: "Example Rust plugin".to_string(),
author: "Rust Developer".to_string(),
min_minitensor_version: VersionInfo::new(0, 1, 0),
max_minitensor_version: None,
},
}
}
}
impl Plugin for ExamplePlugin {
fn info(&self) -> &PluginInfo {
&self.info
}
fn initialize(&self, _registry: &CustomOpRegistry) -> Result<()> {
Ok(())
}
fn cleanup(&self, _registry: &CustomOpRegistry) -> Result<()> {
Ok(())
}
fn custom_operations(&self) -> Vec<Arc<dyn CustomOp>> {
vec![]
}
}
#[no_mangle]
pub extern "C" fn create_plugin() -> *mut dyn Plugin {
Box::into_raw(Box::new(ExamplePlugin::new()))
}A typical Cargo manifest uses a cdylib crate type and depends on the engine
crate from an appropriate path or published package:
[lib]
crate-type = ["cdylib"]
[dependencies]
minitensor-engine = { path = "../engine" }- Treat plugin names as globally unique registry keys.
- Declare realistic minimum and maximum supported MiniTensor versions.
- Keep initialization and cleanup idempotent where possible.
- Validate tensor shapes, dtypes, and devices in Rust
CustomOpcode. - Test duplicate registration, missing plugin names, missing parameters, and
builds without the
dynamic-loadingfeature. - Document clearly whether code is a Python metadata plugin, a
CustomLayer, or a native plugin that can register engine custom operations.
VersionInfo(major, minor, patch)withparse(...),current(),is_compatible_with(...), and read-onlymajor,minor,patchfields.PluginInfowithname,version,description,author,min_minitensor_version, and optionalmax_minitensor_version.CustomPluginwithset_initialize_fn(...),set_cleanup_fn(...),set_custom_operations_fn(...), andinfo.PluginRegistrywithregister(...),unregister(...),list_plugins(),get_plugin(...), andis_registered(...).CustomLayerwithset_forward(...),add_parameter(...),get_parameter(...),list_parameters(),name, andforward(...).PluginBuilderwith fluent metadata setters andbuild().
load_plugin(path)unload_plugin(name)list_plugins()get_plugin_info(name)is_plugin_loaded(name)