Controlplane
Preview (test fixture)
Older
You are reading Preview (test fixture). The current release is documented here.
Docs/Controlplane/Forge Extension
Open

Reading3 min
Updated31 Jul 2026
Sourcev1/guides/forge-extension.mdx
Inherited from v1

Ctrl Plane can run as a Forge extension. This lets you embed instance management into a larger Forge-based application and share authentication, middleware, and the HTTP server.

Basic setup01

package main

import (
    "github.com/xraph/forge"
    cpext "github.com/xraph/ctrlplane/extension"
    "github.com/xraph/ctrlplane/provider/docker"
)

func main() {
    dockerProv, _ := docker.New(docker.Config{
        Host: "unix:///var/run/docker.sock",
    })

    app := forge.New()
    app.Use(cpext.New(
        cpext.WithProvider("docker", dockerProv),
    ))
    app.Run()
}

The extension registers itself with Forge and mounts the Ctrl Plane HTTP API at the configured base path.

File-based configuration02

When running inside Forge, Ctrl Plane automatically loads configuration from the application's YAML config file. The extension looks for settings under two keys (in order):

  1. extensions.ctrlplane (namespaced, recommended)

  2. ctrlplane (legacy shorthand)

extensions:
  ctrlplane:
    database_url: "postgres://localhost:5432/ctrlplane"
    default_provider: "k8s"
    base_path: "/ctrlplane"
    health_interval: "30s"
    telemetry_flush_interval: "10s"
    max_instances_per_tenant: 100
    audit_enabled: true
    disable_routes: false
    disable_migrate: false

Merge behavior

File-based and programmatic configuration are merged together with these rules:

CategoryPrecedence
Boolean flags (disable_routes, disable_migrate)Programmatic true wins
String fields (base_path, database_url, default_provider)YAML takes precedence; programmatic fills gaps
Duration/int fields (health_interval, max_instances_per_tenant, etc.)YAML takes precedence; programmatic fills gaps
AuthProviderAlways programmatic (cannot be set from YAML)

Any remaining zero-valued fields are filled from DefaultConfig().

Requiring file config

If your deployment relies on the config file being present, use WithRequireConfig:

app.Use(cpext.New(
    cpext.WithRequireConfig(true),
))

When RequireConfig is true and no config is found under either key, Register returns an error.

Extension options03

OptionPurpose
WithAuthProvider(p)Set the auth provider
WithProvider(name, p)Register a cloud provider
WithBasePath(path)Set the URL prefix (default: /ctrlplane)
WithConfig(cfg)Set extension configuration directly
WithStore(opt)Pass a store option to the underlying Ctrl Plane
WithExtension(x)Register a plugin extension (lifecycle hooks)
WithDisableRoutes()Disable automatic route registration
WithDisableMigrate()Disable automatic database migration on Register
WithRequireConfig(bool)Require config to be present in YAML files

With Authsome04

If you're using Authsome for authentication, connect it through the adapter:

package main

import (
    "github.com/xraph/forge"
    "github.com/xraph/authsome"
    cpext "github.com/xraph/ctrlplane/extension"
    authadapter "github.com/xraph/ctrlplane/auth/authsome"
)

func main() {
    app := forge.New()

    // Mount Authsome first
    authProvider := authsome.New(/* ... */)
    app.Use(authProvider.Extension())

    // Mount Ctrl Plane with the Authsome adapter
    app.Use(cpext.New(
        cpext.WithAuthProvider(authadapter.New(authProvider)),
        cpext.WithProvider("k8s", kubernetesProvider),
    ))

    app.Run()
}

The Authsome adapter translates Authsome's user and session model into Ctrl Plane's auth.Claims format.

Lifecycle05

The extension implements the forge.Extension interface:

  1. Register(fapp) -- Loads configuration from YAML files (or programmatic defaults), initializes the Ctrl Plane instance, runs migrations, registers routes, and provides the instance to the DI container.

  2. Start(ctx) -- Starts background workers.

  3. Stop(ctx) -- Gracefully shuts down background workers.

  4. Health(ctx) -- Returns an error if the extension is not initialized.

Forge calls these methods in order during its own startup and shutdown sequence.

Accessing the Ctrl Plane06

If you need to call Ctrl Plane services from other parts of your Forge application:

ext := cpext.New(/* ... */)
app.Use(ext)

// After init, access the underlying Ctrl Plane
cp := ext.CtrlPlane()
instance, err := cp.Instances.Get(ctx, instanceID)