Skip to main content

nexora-plugin-spi

The plugin contract. Every capability and every plugin you write depends only on this module.

Capability

The core unit of work. Implement this to add something the engine can invoke.

public class SendEmailCapability implements Capability {

@Override
public CapabilityResult execute(CapabilityRequest request) {
String to = (String) request.inputs().get("email");
String subject = (String) request.inputs().get("subject");

emailClient.send(to, subject);

return CapabilityResult.success(Map.of("sent", true));
}
}

Rules:

  • Implementations must be thread-safe. The engine calls execute() concurrently across independent steps.
  • Return CapabilityResult.success(output) on success.
  • Return CapabilityResult.failure(exception) or throw — both are handled.
  • Return CapabilityResult.success(output, amendments) to reshape the remaining plan.

CapabilityContract

Optionally override contract() to declare latency and error-rate SLAs. The engine monitors live metrics and reroutes to the fallback if breached.

public class ChargeCardCapability implements Capability {

@Override
public CapabilityContract contract() {
return CapabilityContract.builder()
.expectedP99Latency(Duration.ofMillis(200))
.maxErrorRate(0.01) // 1%
.fallbackCapabilityId("charge_card_v2")
.build();
}

@Override
public CapabilityResult execute(CapabilityRequest request) { ... }
}

NexoraPlugin

Entry point for a plugin JAR. Discovered via ServiceLoader from META-INF/services/com.nexora.spi.NexoraPlugin.

public class PaymentPlugin implements NexoraPlugin {

@Override
public PluginDescriptor descriptor() {
return new PluginDescriptor("payment-plugin", "1.0.0", List.of());
}

@Override
public void initialize(PluginContext context) {
// acquire resources, read config
}

@Override
public List<CapabilityProvider> capabilityProviders() {
return List.of(
CapabilityProvider.of("charge_card", new ChargeCardCapability()),
CapabilityProvider.of("charge_card_v2", new ChargeCardV2Capability())
);
}

@Override
public void shutdown() {
// release resources; must not throw
}
}

Lifecycle: LOADEDinitialize()ACTIVEshutdown()INACTIVE

PluginDescriptor

new PluginDescriptor(
"my-plugin", // unique plugin ID
"2.1.0", // version string
List.of("base-plugin") // IDs of plugins that must be ACTIVE first
);

CapabilityRequest

Passed to every Capability.execute() call.

MethodReturnsDescription
inputs()Map<String, Object>Resolved input values for this step
context()ExecutionContextTrace context, execution ID, prior step outputs
stepId()StringThe step being executed
capabilityId()StringThe capability ID being invoked