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: LOADED → initialize() → ACTIVE → shutdown() → 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