title
Plugin System
description
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
EvalRunStarted
OnEvalRunStarted(ctx, suiteID, runID, model)
Evaluation run begins
EvalRunCompleted
OnEvalRunCompleted(ctx, suiteID, runID, passRate, elapsed)
Run finishes successfully
EvalRunFailed
OnEvalRunFailed(ctx, suiteID, runID, err)
Run fails with error
Interface
Method
When it fires
CaseStarted
OnCaseStarted(ctx, runID, caseID)
Case evaluation begins
CaseCompleted
OnCaseCompleted(ctx, runID, caseID, score, elapsed)
Case evaluation finishes
CaseFailed
OnCaseFailed(ctx, runID, caseID, err)
Case evaluation fails
Interface
Method
When it fires
RegressionDetected
OnRegressionDetected(ctx, suiteID, baselineID, delta)
Performance regression found
Interface
Method
When it fires
BaselineSaved
OnBaselineSaved(ctx, suiteID, baselineID)
Baseline saved
Interface
Method
When it fires
RedTeamStarted
OnRedTeamStarted(ctx, suiteID, attackCount)
Red team evaluation begins
RedTeamCompleted
OnRedTeamCompleted(ctx, suiteID, bypassCount, elapsed)
Red team evaluation finishes
Interface
Method
When it fires
PersonaEvalStarted
OnPersonaEvalStarted(ctx, runID, personaName)
Persona-aware evaluation begins
PersonaEvalCompleted
OnPersonaEvalCompleted(ctx, runID, personaName, dimensions)
Persona-aware evaluation finishes
Interface
Method
When it fires
PromptVersionCreated
OnPromptVersionCreated(ctx, suiteID, pvID, version)
Prompt version created
Interface
Method
When it fires
ComparisonCompleted
OnComparisonCompleted(ctx, suiteID, models, elapsed)
Multi-model comparison finishes
Interface
Method
When it fires
Shutdown
OnShutdown(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
Writing a custom extension
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/..." }),
)