Plugin System Lifecycle hooks for metrics, audit trails, and custom processing.
Sentinel uses an opt-in plugin system where extensions subscribe to lifecycle events by implementing specific interfaces. The base interface requires only a Name() method — all hooks are optional.
type Extension interface {
Name () string
}
There are 16 hook interfaces organized by category. Extensions implement only the hooks they need.
Interface Method When it fires EvalRunStartedOnEvalRunStarted(ctx, suiteID, runID, model)Evaluation run begins EvalRunCompletedOnEvalRunCompleted(ctx, suiteID, runID, passRate, elapsed)Run finishes successfully EvalRunFailedOnEvalRunFailed(ctx, suiteID, runID, err)Run fails with error
Interface Method When it fires CaseStartedOnCaseStarted(ctx, runID, caseID)Case evaluation begins CaseCompletedOnCaseCompleted(ctx, runID, caseID, score, elapsed)Case evaluation finishes CaseFailedOnCaseFailed(ctx, runID, caseID, err)Case evaluation fails
Interface Method When it fires RegressionDetectedOnRegressionDetected(ctx, suiteID, baselineID, delta)Performance regression found
Interface Method When it fires BaselineSavedOnBaselineSaved(ctx, suiteID, baselineID)Baseline saved
Interface Method When it fires RedTeamStartedOnRedTeamStarted(ctx, suiteID, attackCount)Red team evaluation begins RedTeamCompletedOnRedTeamCompleted(ctx, suiteID, bypassCount, elapsed)Red team evaluation finishes
Interface Method When it fires PersonaEvalStartedOnPersonaEvalStarted(ctx, runID, personaName)Persona-aware evaluation begins PersonaEvalCompletedOnPersonaEvalCompleted(ctx, runID, personaName, dimensions)Persona-aware evaluation finishes
Interface Method When it fires PromptVersionCreatedOnPromptVersionCreated(ctx, suiteID, pvID, version)Prompt version created
Interface Method When it fires ComparisonCompletedOnComparisonCompleted(ctx, suiteID, models, elapsed)Multi-model comparison finishes
Interface Method When it fires ShutdownOnShutdown(ctx)Graceful shutdown
The plugin.Registry type-caches extensions at registration time:
registry := plugin. NewRegistry (logger)
registry. Register (metricsExt)
registry. Register (auditExt)
When events are emitted, only extensions implementing the relevant hook are called:
registry. EmitEvalRunStarted (ctx, suiteID, runID, model)
// Only calls extensions that implement EvalRunStarted
Hook errors are logged but never propagated . Hooks must not block the evaluation pipeline.
observability.MetricsExtension — Counters for all lifecycle events
audithook.Extension — Bridges events to an audit trail backend
type SlackNotifier struct {
webhookURL string
}
func ( s * SlackNotifier ) Name () string { return "slack-notifier" }
func ( s * SlackNotifier ) OnRegressionDetected ( ctx context . Context , suiteID id . SuiteID , baselineID id . BaselineID , delta float64 ) error {
return postToSlack (s.webhookURL, fmt. Sprintf ( "Regression detected in suite %s : %.1f%% drop" , suiteID, delta * 100 ))
}
// Register:
eng, _ := engine. New (
engine. WithExtension ( & SlackNotifier {webhookURL: "https://hooks.slack.com/..." }),
)