Current state
Dynamic plugins (ENABLE_DYNAMIC_PLUGINS=true, loaded by Yaegi from plugins/dynamic/*.go) can only use the Go standard library and the goblog/plugin package (plugin/symbols.go). The Plugin hooks whose signatures name third-party types therefore can't be implemented dynamically:
| Hook |
Blocked by |
TemplateData(ctx) gin.H |
gin.H |
ScheduledJobs() []ScheduledJob |
ScheduledJob.Run func(db *gorm.DB, …) |
OnInit(db *gorm.DB) error |
*gorm.DB |
RenderPage(ctx, pageType) (string, gin.H) |
gin.H |
So today a dynamic plugin is limited to metadata, Settings, TemplateHead and TemplateFooter (documented in the README and in plugins/dynamic/hello.go.example, #554). Anything that touches the DB, runs on a schedule, feeds template data, or owns a page has to be compiled in.
Proposal
Generate Yaegi symbol maps for the relevant third-party packages and register them in the loader alongside stdlib.Symbols and plugin.Symbols:
yaegi extract github.com/gin-gonic/gin
yaegi extract gorm.io/gorm
- Put the generated files in their own package (e.g.
plugin/symbols/) so they don't bloat plugin/ and can be regenerated with go generate. They will be large; check whether a subset (e.g. gin.H, *gin.Context, *gorm.DB and the query surface) is enough, or whether whole-package extraction is simpler to maintain.
- Yaegi's extract output is Go-version-tagged (
//go:build go1.26); pin the generation to the module's Go version and regenerate when it changes. Both packages are already pinned in go.mod via Renovate.
- Extend the loader test to load a dynamic plugin that implements
TemplateData, ScheduledJobs, OnInit, and Pages/RenderPage, so the new hooks are exercised in CI.
- Update the README "Limits of the interpreted environment" paragraph and the example's header once the limit is lifted.
Why it matters
The plugin directory (#552) and in-admin install/update (#553) only make sense for dynamic plugins, and with the current limit most interesting plugins (anything with data or a page) can't be distributed that way.
Trade-off
Dynamic plugins already run arbitrary Go in-process; this widens what that code can reach (full DB access) but doesn't change the trust model — the directory must remain operator-controlled and curated.
Related: #551, #552, #553, #554.
Current state
Dynamic plugins (
ENABLE_DYNAMIC_PLUGINS=true, loaded by Yaegi fromplugins/dynamic/*.go) can only use the Go standard library and thegoblog/pluginpackage (plugin/symbols.go). ThePluginhooks whose signatures name third-party types therefore can't be implemented dynamically:TemplateData(ctx) gin.Hgin.HScheduledJobs() []ScheduledJobScheduledJob.Run func(db *gorm.DB, …)OnInit(db *gorm.DB) error*gorm.DBRenderPage(ctx, pageType) (string, gin.H)gin.HSo today a dynamic plugin is limited to metadata,
Settings,TemplateHeadandTemplateFooter(documented in the README and inplugins/dynamic/hello.go.example, #554). Anything that touches the DB, runs on a schedule, feeds template data, or owns a page has to be compiled in.Proposal
Generate Yaegi symbol maps for the relevant third-party packages and register them in the loader alongside
stdlib.Symbolsandplugin.Symbols:plugin/symbols/) so they don't bloatplugin/and can be regenerated withgo generate. They will be large; check whether a subset (e.g.gin.H,*gin.Context,*gorm.DBand the query surface) is enough, or whether whole-package extraction is simpler to maintain.//go:build go1.26); pin the generation to the module's Go version and regenerate when it changes. Both packages are already pinned ingo.modvia Renovate.TemplateData,ScheduledJobs,OnInit, andPages/RenderPage, so the new hooks are exercised in CI.Why it matters
The plugin directory (#552) and in-admin install/update (#553) only make sense for dynamic plugins, and with the current limit most interesting plugins (anything with data or a page) can't be distributed that way.
Trade-off
Dynamic plugins already run arbitrary Go in-process; this widens what that code can reach (full DB access) but doesn't change the trust model — the directory must remain operator-controlled and curated.
Related: #551, #552, #553, #554.