Forge Extension
Mount Cortex into a Forge application as a first-class extension with automatic route registration, migrations, and DI.
Cortex ships a ready-made Forge extension in the extension package. It wires the engine, HTTP API, and lifecycle management into Forge's extension system with one call.
Installation
import "github.com/xraph/cortex/extension"Registering the extension
package main
import (
"github.com/xraph/forge"
"github.com/xraph/cortex/extension"
pgstore "github.com/xraph/cortex/store/postgres"
)
func main() {
app := forge.New()
cortexExt := extension.New(
extension.WithStore(pgstore.New(bunDB)),
)
app.RegisterExtension(cortexExt)
app.Run()
}What the extension does
| Lifecycle event | Behaviour |
|---|---|
Register | Creates the engine, builds the API handler, registers the engine in the DI container via vessel.Provide, mounts all HTTP routes (unless disabled) |
Start | Runs store.Migrate(ctx) (unless disabled), then calls engine.Start(ctx) |
Stop | Calls engine.Stop(ctx) which emits OnShutdown to all plugins |
Health | Calls store.Ping(ctx) to verify database connectivity |
Extension options
| Option | Type | Default | Description |
|---|---|---|---|
WithStore(s) | store.Store | — | Required. Composite persistence store |
WithExtension(x) | plugin.Extension | — | Register a Cortex plugin (lifecycle hooks) |
WithEngineOption(o) | engine.Option | — | Pass any engine option through |
WithConfig(c) | extension.Config | — | Set the full extension config |
WithDisableRoutes() | — | false | Skip HTTP route registration |
WithDisableMigrate() | — | false | Skip auto-migration on Start |
WithBasePath(p) | string | "" | URL prefix for all Cortex routes |
WithLogger(l) | *slog.Logger | slog.Default() | Structured logger |
Extension config struct
type Config struct {
DisableRoutes bool // Skip HTTP route registration
DisableMigrate bool // Skip auto-migration on start
BasePath string // URL prefix for all cortex routes
}Disabling auto-migration
If you manage migrations separately (e.g. with a migration tool), disable auto-migration:
cortexExt := extension.New(
extension.WithStore(store),
extension.WithDisableMigrate(),
)Disabling routes
If you only need the engine (e.g. using Cortex programmatically from another extension), disable route registration:
cortexExt := extension.New(
extension.WithStore(store),
extension.WithDisableRoutes(),
)Accessing the engine from other extensions
After Register is called by Forge, cortexExt.Engine() returns the fully initialised engine:
eng := cortexExt.Engine()
// Use eng.CreateAgent, eng.ListSkills, etc. from another extensionThe engine is also available via Forge's DI container (powered by vessel):
import "github.com/xraph/cortex/engine"
// Inside another extension's Register:
var eng *engine.Engine
if err := vessel.Resolve(fapp.Container(), &eng); err != nil {
return err
}Tenant middleware
In a Forge app, tenant scope is typically set by middleware that reads the JWT or API key:
func tenantMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
tenantID := r.Header.Get("X-Tenant-ID")
appID := r.Header.Get("X-App-ID")
ctx := cortex.WithTenant(r.Context(), tenantID)
ctx = cortex.WithApp(ctx, appID)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
router.Use(tenantMiddleware)Adding plugins
Register Cortex plugins (observability, audit hooks, etc.) alongside the extension:
import (
"github.com/xraph/cortex/extension"
"github.com/xraph/cortex/observability"
audithook "github.com/xraph/cortex/audit_hook"
)
metricsPlugin := observability.NewMetricsExtension()
auditPlugin := audithook.New(myRecorder)
cortexExt := extension.New(
extension.WithStore(store),
extension.WithExtension(metricsPlugin),
extension.WithExtension(auditPlugin),
)Health checks
The extension implements forge.Extension's Health method by pinging the store:
func (e *Extension) Health(ctx context.Context) error {
return e.eng.Store().Ping(ctx)
}Forge surfaces this automatically in its health endpoint.
Complete example
package main
import (
"log/slog"
"os"
"github.com/uptrace/bun"
"github.com/xraph/forge"
"github.com/xraph/cortex/extension"
"github.com/xraph/cortex/observability"
pgstore "github.com/xraph/cortex/store/postgres"
)
func main() {
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
app := forge.New()
db := connectDB() // your *bun.DB connection
store := pgstore.New(db)
cortexExt := extension.New(
extension.WithStore(store),
extension.WithExtension(observability.NewMetricsExtension()),
extension.WithLogger(logger),
)
app.RegisterExtension(cortexExt)
app.Run()
}This gives you a production-ready Cortex deployment with:
- All 36 REST endpoints mounted
- Auto-migration on startup
- Health checks via
store.Ping - Prometheus-compatible metrics
- Graceful shutdown with plugin notification