---
title: Forge Extension
description: Run Nexus as a forge.Extension with auto-discovery and DI.
---

## Setup

```go
import (
    "github.com/xraph/forge"
    nexusext "github.com/xraph/nexus/extension"
)

app := forge.New(
    forge.WithExtension(nexusext.New(
        nexusext.WithProvider(openai.New(key)),
    )),
)
app.Start(ctx)
```

## Auto-Discovery

When running in a Forge application, the Nexus extension automatically discovers other Forge extensions via vessel DI:

- **Chronicle** — Wires `audit_hook` with Chronicle recorder
- **Shield** — Wires Shield as a guardrail adapter
- **Relay** — Wires `relay_hook` with Relay sender
- **Authsome** — Wires Authsome as auth provider
- **Metrics** — Wires observability with `gu.MetricFactory`

## YAML configuration

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

1. `extensions.nexus` (namespaced, recommended)
2. `nexus` (legacy shorthand)

```yaml title="forge.yaml"
extensions:
  nexus:
    base_path: "/ai"
    default_timeout: "30s"
    default_max_retries: 2
    global_rate_limit: 1000
    log_level: "info"
    enable_usage: true
    enable_cache: false
    grove_database: ""
    disable_routes: false
    disable_migrate: false
```

### Configuration reference

| Field | YAML key | Type | Default | Description |
|-------|----------|------|---------|-------------|
| `BasePath` | `base_path` | `string` | `"/ai"` | URL prefix for gateway routes |
| `DefaultTimeout` | `default_timeout` | `duration` | `30s` | Default timeout for provider requests |
| `DefaultMaxRetries` | `default_max_retries` | `int` | `2` | Default retries per request |
| `GlobalRateLimit` | `global_rate_limit` | `int` | `0` | Global rate limit in RPM (0 = unlimited) |
| `LogLevel` | `log_level` | `string` | `"info"` | Gateway log level |
| `EnableUsage` | `enable_usage` | `bool` | `true` | Enable usage tracking |
| `EnableCache` | `enable_cache` | `bool` | `false` | Enable response caching |
| `GroveDatabase` | `grove_database` | `string` | `""` | Name of grove.DB to resolve from DI |
| `DisableRoutes` | `disable_routes` | `bool` | `false` | Disable automatic route registration |
| `DisableMigrate` | `disable_migrate` | `bool` | `false` | Disable automatic store migration |

### Merge behavior

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

| Category | Precedence |
|----------|------------|
| Boolean flags (`disable_routes`, `disable_migrate`, `enable_cache`) | Programmatic `true` wins |
| String fields (`base_path`, `log_level`, `grove_database`) | YAML takes precedence; programmatic fills gaps |
| Duration/int fields (`default_timeout`, `default_max_retries`, `global_rate_limit`) | YAML takes precedence; programmatic fills gaps |
| Pointer fields (`enable_usage`) | YAML takes precedence; programmatic fills gaps |

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

### Requiring file config

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

```go
app := forge.New(
    forge.WithExtension(nexusext.New(
        nexusext.WithRequireConfig(true),
    )),
)
```

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

## Extension options

| Option | Purpose |
|--------|---------|
| `WithProvider(p)` | Register an LLM provider |
| `WithDatabase(s)` | Set the persistence store directly |
| `WithGatewayOption(opt)` | Pass a raw `nexus.Option` to the gateway |
| `WithBasePath(path)` | Set the HTTP base path (default: `/ai`) |
| `WithConfig(cfg)` | Set extension configuration directly |
| `WithDisableRoutes()` | Disable automatic route registration |
| `WithDisableMigrate()` | Disable automatic store migration |
| `WithRequireConfig(bool)` | Require config to be present in YAML files |
| `WithGroveDatabase(name)` | Resolve a grove.DB from DI by name |

## Grove database integration

When your Forge app uses the [Grove extension](https://github.com/xraph/grove) to manage database connections, Nexus can automatically resolve a `grove.DB` from the DI container and construct the correct store backend based on the driver type.

### Using the default grove database

If the Grove extension registers a single database (or a default in multi-DB mode), use `WithGroveDatabase` with an empty name:

```go
ext := nexusext.New(
    nexusext.WithGroveDatabase(""),
    nexusext.WithProvider(openai.New(key)),
)
```

### Using a named grove database

In multi-database setups, reference a specific database by name:

```go
ext := nexusext.New(
    nexusext.WithGroveDatabase("nexus"),
    nexusext.WithProvider(openai.New(key)),
)
```

This resolves the grove.DB named `"nexus"` from the DI container and auto-constructs the matching store. The driver type is detected automatically -- you do not need to import individual store packages.

### Via YAML

Grove database can also be configured via the YAML config file:

```yaml
extensions:
  nexus:
    grove_database: "nexus"
```

When `grove_database` is set in YAML, the extension enables grove resolution automatically.

### Store resolution order

The extension resolves its store in this order:

1. **Explicit store** -- if `WithDatabase(s)` was called, it is used directly and grove is ignored.
2. **Grove database** -- if `WithGroveDatabase(name)` was called, the named or default `grove.DB` is resolved from DI.
3. **In-memory fallback** -- if neither is configured, an in-memory store is used.

## DI Registration

The extension registers the Gateway in the vessel container:

```go
// Other extensions can resolve it
gw, err := vessel.Resolve[*nexus.Gateway](container)
```
