Plugin Developer API¶
Vanguard 0.1.15 introduces a public Plugin Developer API for framework
extensions, project diagnostics, custom registries, metrics, and future Studio
tooling. Plugins integrate through stable hooks instead of mutating Vanguard's
private implementation tables.
Plugins are runtime-local. A server plugin and a client plugin with the same name are separate registrations unless the same ModuleScript is loaded on both runtimes.
Basic Plugin¶
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Vanguard = require(ReplicatedStorage.Packages.Vanguard)
return Vanguard.CreatePlugin({
Name = "DiagnosticsPlugin",
Version = "1.0.0",
Runtime = "Shared",
Priority = 10,
VanguardInit = function(self, context)
context.Logger:Info(`Loaded {self.Name} on {context.Runtime}`)
end,
Hooks = {
ServiceRegistered = function(context, payload)
context.Logger:Debug(`Service registered: {payload.Name}`)
end,
},
})
Load plugins before classes, services, controllers, and components:
Vanguard.Bootstrap({
Plugins = script.Parent.Plugins,
Services = script.Parent.Services,
Classes = script.Parent.Classes,
Options = {
LogLevel = "info",
},
})
On the client, use Controllers instead of Services.
Manifest Fields¶
| Field | Required | Description |
|---|---|---|
Name |
Yes | Non-empty unique plugin name in the current runtime |
Version |
No | Human-readable plugin version for diagnostics |
Runtime |
No | Server, Client, Shared, or nil; nil behaves like Shared |
Priority |
No | Higher-priority plugins run lifecycle hooks first |
DependsOn |
No | Array of plugin names that must run before this plugin |
Disabled |
No | Skips the plugin without removing its registration |
Strict |
No | Makes this plugin's hook errors fail startup |
Logger |
No | Custom logger; otherwise the Vanguard root logger is used |
Hooks |
No | Table of named framework hook callbacks |
Unknown ordinary fields are allowed so plugins can keep their own state and
helper methods. Metadata keys beginning with __ are reserved by Vanguard.
Registration API¶
local plugin = Vanguard.CreatePlugin(definition)
Vanguard.RegisterPlugin(plugin)
Vanguard.AddPlugins(folder)
Vanguard.AddPluginsDeep(folder)
Vanguard.GetPlugin("DiagnosticsPlugin")
Vanguard.HasPlugin("DiagnosticsPlugin")
Vanguard.GetPlugins()
Vanguard.UnregisterPlugin("DiagnosticsPlugin")
LoadPlugins and LoadPluginsDeep are aliases for AddPlugins and
AddPluginsDeep.
Plugins must be registered before Start. This keeps startup ordering and
extension behavior deterministic. A plugin module may either call
CreatePlugin or return a plain plugin definition; folder loaders register the
returned table automatically.
Runtime Scope¶
Runtime = "Server" -- runs only on the server
Runtime = "Client" -- runs only on the client
Runtime = "Shared" -- runs on both runtimes when loaded on both
Runtime scope is evaluated by the current Vanguard runtime. It does not replicate a plugin to the other side. If a shared plugin should exist on both server and client, place it in a folder loaded by both bootstraps.
Dependency Ordering¶
DependsOn is an array of plugin names:
return Vanguard.CreatePlugin({
Name = "MetricsUI",
Runtime = "Client",
DependsOn = { "MetricsCore" },
})
Vanguard topologically sorts plugins before lifecycle hooks and ordered framework hooks run. Dependencies run before the dependent plugin even when the dependent plugin has a higher priority.
Missing dependencies and dependency cycles fail with VG-PLUGIN-003 and link
to the error reference.
Lifecycle Hooks¶
Plugins may define:
function Plugin:VanguardInit(context, payload)
-- Required setup before framework services/controllers initialize.
end
function Plugin:VanguardStart(context, payload)
-- Startup work after framework init hooks complete.
end
Init and Start are supported aliases. VanguardInit runs before service or
controller init. VanguardStart runs after service or controller init and
before framework start hooks are scheduled.
Plugin lifecycle hooks receive:
type PluginContext = {
Vanguard: any,
Runtime: "Server" | "Client",
Plugin: PluginDefinition,
Logger: Logger?,
Hook: string?,
}
The startup payload includes:
Framework Hooks¶
Hooks can be declared in the Hooks table:
Hooks = {
RemoteRegistered = function(context, payload)
context.Logger:Info(payload.ServiceName, payload.RemoteName)
end,
}
or as direct methods:
Available hooks:
| Hook | Runtime | Payload |
|---|---|---|
PluginRegistered |
Both | Plugin, Name |
PluginUnregistered |
Both | Plugin, Name |
ClassRegistered |
Both | Class, Name |
ServiceRegistered |
Server | Service, Name |
ControllerRegistered |
Client | Controller, Name |
ComponentRegistered |
Both | Component, Name |
RemoteRegistered |
Server | Service, ServiceName, RemoteName, RemoteType, Remote |
RemoteDiscovered |
Client | Service, ServiceName, RemoteName, RemoteType, Remote |
NetworkRejected |
Server | Context, Rejection |
BeforeStart |
Both | Options, Runtime |
AfterStart |
Both | Options, Runtime |
Registration hooks that fire while modules are still loading do not enforce dependency ordering. Startup hooks and later framework hooks do enforce dependency ordering.
Error Handling¶
By default, plugin hook errors are isolated and logged with VG-PLUGIN-002.
Startup continues when possible.
Use strict mode when a plugin is required for correctness:
or on one plugin:
Strict hook failures throw a linked Vanguard error and reject startup.
Good Plugin Boundaries¶
Use plugins for:
- diagnostics and metrics;
- project-specific validation;
- custom registries and generators;
- development-only tracing;
- integration glue for future Studio tools.
Avoid plugins that:
- mutate service or controller internals unexpectedly;
- bypass network validation/authentication/verification;
- require remote code at runtime;
- hide authoritative server checks in client code;
- depend on private Vanguard tables not exposed in this guide.
Continue with API Reference, Lifecycle, and Errors.