| --- |
| title: "Plugin Sequencing" |
| description: "Control the execution order of custom plugins relative to Bifrost's built-in plugins using placement groups and ordering." |
| icon: "arrow-down-1-9" |
| --- |
|
|
| |
|
|
| When you have multiple plugins β both built-in and custom β the order in which they execute matters. A logging plugin should capture the final request, an auth plugin should validate before anything else runs, and a response transformer should run after the provider returns data. |
|
|
| Plugin sequencing lets you control **where** your custom plugins execute relative to Bifrost's built-in plugins (telemetry, logging, governance, etc.) and **in what order** they execute relative to each other. |
|
|
| --- |
|
|
| |
|
|
| Bifrost organizes plugins into three **placement groups** that execute in a fixed order: |
|
|
| ```mermaid |
| graph LR |
| A["Pre-builtin plugins"] --> B["Built-in plugins"] |
| B --> C["Post-builtin plugins"] |
| ``` |
|
|
| | Placement Group | Pre-hooks (request) | Post-hooks (response) | |
| |-----------------|--------------------|-----------------------| |
| | `pre_builtin` | Runs **first** | Runs **last** | |
| | `builtin` | Runs **second** | Runs **second** | |
| | `post_builtin` | Runs **third** | Runs **first** | |
|
|
| <Info> |
| Post-hooks execute in **reverse order** of pre-hooks (LIFO pattern). This means a `pre_builtin` plugin's `PreLLMHook` runs first, but its `PostLLMHook` runs last β ensuring proper cleanup and state unwinding. |
| </Info> |
|
|
| |
|
|
| Within each placement group, plugins are sorted by their `order` value (lower executes earlier). Plugins with the same order preserve their registration order. |
|
|
| **Example:** Three custom plugins configured as: |
|
|
| | Plugin | Placement | Order | Pre-hook runs | Post-hook runs | |
| |--------|-----------|-------|---------------|----------------| |
| | auth-validator | `pre_builtin` | 0 | 1st | 5th (last) | |
| | request-enricher | `pre_builtin` | 1 | 2nd | 4th | |
| | *Built-in plugins* | β | β | 3rd | 3rd | |
| | response-logger | `post_builtin` | 0 | 4th | 2nd | |
| | analytics | `post_builtin` | 1 | 5th (last) | 1st | |
|
|
| --- |
|
|
| |
|
|
| <Tabs group="config-method"> |
| <Tab title="Web UI"> |
|
|
| 1. Navigate to the **Plugins** page in the sidebar |
| 2. Click the **Edit Plugin Sequence** button (appears when you have at least one custom plugin installed) |
|
|
|  |
|
|
| 3. **Drag** custom plugins above or below the **Built-in Plugins** block: |
| - Plugins **above** the block get `pre_builtin` placement |
| - Plugins **below** the block get `post_builtin` placement |
| 4. The order within each group is determined by position (top = lowest order value) |
| 5. Click **Save Sequence** to apply the changes |
|
|
| <Note> |
| If your `config.json` file has plugin sequence configured, it will take precedence over the sequence configured in the UI after restarting Bifrost. |
| </Note> |
|
|
| </Tab> |
| <Tab title="API"> |
|
|
| Update a plugin's placement and order using the update endpoint: |
|
|
| ```bash |
| curl -X PUT http://localhost:8080/api/plugins/my-plugin \ |
| -H "Content-Type: application/json" \ |
| -d '{ |
| "enabled": true, |
| "path": "/path/to/my-plugin.so", |
| "placement": "pre_builtin", |
| "order": 0 |
| }' |
| ``` |
|
|
| **Response:** |
| ```json |
| { |
| "message": "Plugin updated successfully", |
| "plugin": { |
| "name": "my-plugin", |
| "enabled": true, |
| "isCustom": true, |
| "path": "/path/to/my-plugin.so", |
| "placement": "pre_builtin", |
| "order": 0, |
| "status": { |
| "status": "active" |
| } |
| } |
| } |
| ``` |
|
|
| You can also set placement when creating a plugin: |
|
|
| ```bash |
| curl -X POST http://localhost:8080/api/plugins \ |
| -H "Content-Type: application/json" \ |
| -d '{ |
| "name": "my-plugin", |
| "enabled": true, |
| "path": "/path/to/my-plugin.so", |
| "placement": "pre_builtin", |
| "order": 0 |
| }' |
| ``` |
|
|
| </Tab> |
| <Tab title="config.json"> |
|
|
| Set `placement` and `order` on each plugin in the `plugins` array: |
|
|
| ```json |
| { |
| "plugins": [ |
| { |
| "name": "auth-validator", |
| "enabled": true, |
| "path": "/plugins/auth-validator.so", |
| "placement": "pre_builtin", |
| "order": 0 |
| }, |
| { |
| "name": "request-enricher", |
| "enabled": true, |
| "path": "/plugins/request-enricher.so", |
| "placement": "pre_builtin", |
| "order": 1 |
| }, |
| { |
| "name": "response-logger", |
| "enabled": true, |
| "path": "/plugins/response-logger.so", |
| "placement": "post_builtin", |
| "order": 0 |
| } |
| ] |
| } |
| ``` |
|
|
| | Field | Type | Required | Default | Description | |
| |-------|------|----------|---------|-------------| |
| | `placement` | string | No | `post_builtin` | `"pre_builtin"` or `"post_builtin"`. Controls whether the plugin runs before or after built-in plugins. | |
| | `order` | integer | No | `0` | Position within the placement group. Lower values execute earlier. | |
|
|
| </Tab> |
| </Tabs> |
|
|
| --- |
|
|
| |
|
|
| |
|
|
| Use this when your plugin needs to: |
|
|
| - **Validate or authenticate** requests before any built-in processing |
| - **Enrich requests** with data that built-in plugins should see (e.g., injecting headers or metadata) |
| - **Short-circuit** requests before they reach governance checks or telemetry |
|
|
| |
|
|
| Use this when your plugin needs to: |
|
|
| - **Transform responses** after all built-in processing is complete |
| - **Log or analyze** the final request/response (after governance, telemetry, etc.) |
| - **Add custom headers** or modify the response before it reaches the client |
|
|
| <Tip> |
| When in doubt, use the default `post_builtin` placement. Most custom plugins β logging, analytics, response transformations β work best after built-in plugins have finished their processing. |
| </Tip> |
|
|
| --- |
|
|
| |
|
|
| - **[Writing a Go plugin](./writing-go-plugin)** β Build your first custom plugin with `PreLLMHook` and `PostLLMHook` |
| - **[Writing a WASM plugin](./writing-wasm-plugin)** β Build a portable WASM plugin |
| - **[Plugin architecture](../architecture/core/plugins)** β Deep dive into the plugin lifecycle and hook execution model |
|
|