Creating Services
Registering a Service
Register shared runtime capabilities through api.register_service(...):
api.register_service(
key="client",
factory=create_client,
lazy=True,
description="Example API client.",
)
For a plugin with ID example.plugin, the local key becomes:
example.plugin.client
Service keys are automatically namespaced unless they are already qualified with the current plugin ID.
Service Factories
A service factory should construct and return the live capability:
def create_client(context, **kwargs):
return ExampleClient()
Keep registration itself declarative. Do not create the client inside
register(api).
Factories are the right place to construct objects such as:
API or archive clients;
authenticated sessions;
database connections;
caches;
resource samplers;
shared domain helpers.
Lazy Services
With lazy=True, the factory is not called until the service is first
requested.
This keeps application startup cheap and avoids opening connections or importing heavy optional dependencies when the service is never used.
Use eager construction only when the capability genuinely must exist as soon as the plugin is enabled.
Using a Service
Retrieve a registered service through context.services:
client = context.services.get("example.plugin.client")
result = client.fetch(...)
Panels and actions should depend on the service key rather than importing the service implementation from another plugin.
A panel can also declare service dependencies in its registration with
uses_services=[...] when those services are required for construction.
Optional Integrations
A plugin can integrate with another plugin through its public service key without importing that plugin’s implementation module.
Optional integrations must still handle the service being unavailable. A missing optional plugin or disabled provider should reduce functionality gracefully rather than breaking unrelated parts of the panel.
For required cross-plugin relationships, declare the plugin dependency in the manifest and the service requirement on the contribution that uses it.
Ownership
Services registered through PluginAPI are associated with the plugin
that registered them.
When the plugin is disabled, PluginManager removes its installed services from the shared registry. Initialized service objects are disposed where possible.
The platform can also register host-owned services, so the registry is not limited to plugin-provided entries.
Cleanup
A service that owns resources should expose one of the standard teardown methods recognised by the registry:
class ExampleClient:
def close(self):
...
The registry attempts common lifecycle methods such as:
dispose();close();shutdown().
Cleanup should be idempotent where practical.
This is especially important for services that own:
network sessions or sockets;
background threads;
temporary directories;
file handles;
database connections;
native resources.
Replacement
Service keys are unique by default.
A registration can explicitly request replacement:
api.register_service(
key="client",
factory=create_client,
lazy=True,
replace=True,
)
Use replacement deliberately. Normal plugins should prefer stable namespaced keys rather than replacing another provider’s service.
If an existing initialized service is replaced or removed, its teardown path is run before the registry discards it.
Authentication
Credentials should come from an appropriate user environment, external secret store or other explicit secure configuration path.
Do not place access tokens, passwords or other secrets in workspace panel state or workspace JSON.
Plugin settings schemas are useful for ordinary configuration, but should not be treated as a dedicated secret vault unless the surrounding application provides a secure storage mechanism for that value.
Services and Persistence
Service objects are live process state and are not persisted as part of a workspace.
Persist only the small information needed to recreate behaviour, such as a selected endpoint name or service mode. Reconstruct the live client through the service factory after the plugin is enabled.
Services and Artifacts
Use a service for a live capability.
Use an artifact for a generated result.
API client/session -> service
downloaded spectrum -> artifact
prediction result -> artifact
database connection -> service
Caution
Do not use the service registry as a generic dictionary for computed outputs,
panel state or datasets. Generated reusable results belong in
context.artifacts, and tabular working inputs belong in
context.datasets.