Universe’s extension system lets you ship new capabilities as standalone JARs without modifying the orchestrator itself. You can add a custom container runtime, a new remote storage backend, or a set of dynamic template variables — all by implementing one of the provider interfaces and registering it in your extension’sDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/ohemilyy/universe/llms.txt
Use this file to discover all available pages before exploring further.
onLoad() hook.
The Extension interface
Every extension must implementExtension from :extensions:extension-api:
id() must be unique across all loaded extensions. version() is used only for display in extension list. The three lifecycle methods are called by Universe at startup, shutdown, and when extension reload is issued.
A minimal extension that does nothing but log its presence looks like this:
Creating a runtime extension
ImplementRuntimeProvider from :api and register it with RuntimeRegistry in onLoad().
1. Implement RuntimeProvider
| Method | Responsibility |
|---|---|
start | Launch the process or container. Return a ProcessHandle representing it. |
stop | Terminate the process or container for the given instance. |
executeCommand | Pipe a command string into the running process’s stdin (or equivalent). |
isRunning | Return true if the process or container is still alive. |
2. Inject RuntimeRegistry and register in onLoad()
"runtime": "my-provider" in any instance configuration file.
Creating a storage extension
ImplementTemplateStorageProvider from :extensions:extension-api and register it with TemplateStorageRegistry.
1. Implement TemplateStorageProvider
storageKey is the value operators write in the "storage" field of a template reference (e.g., "s3", "ftp"). Return true from downloadTemplate and uploadTemplate to signal success.
2. Register in onLoad()
"storage": "my-backend".
Adding custom template variables
ImplementTemplateVariableProvider and register it with TemplateVariableRegistry. Your variables are merged with the built-in set (%PORT%, %INSTANCE_ID%, %MASTER_IP%, etc.) during instance deployment.
onLoad():
Configuration.fileModifications will have %MY_CUSTOM_VAR% replaced with "some-value" when an instance is created.
Build rules
Your extension’sbuild.gradle.kts must follow these constraints:
runtimeDownload for all external JVM libraries (AWS SDK, HTTP clients, etc.). This keeps your JAR small and lets Universe’s classloader manage dependency resolution.
JAR placement and naming
Name your JAR after its category and function, following the convention used by built-in extensions:| Category | Convention | Example |
|---|---|---|
| Runtime | runtime-<name>.jar | runtime-docker.jar |
| Storage | storage-<name>.jar | storage-s3.jar |
| General | <name>.jar | my-extension.jar |
./extensions/ and restart Universe (or run extension reload if hot-reload is sufficient for your extension’s setup):
./extensions/<extension-id>/config.json to match the convention used by the built-in extensions.