# How Fabric Solves the AI Integration Problem: A Plugin-Based Architecture Guide

> Learn how Fabric integrates AI by abstracting LLM vendor APIs into a unified interface that simplifies authentication and model discovery. Discover the plugin-based architecture.

- Repository: [Daniel Miessler 🛡️/fabric](https://github.com/danielmiessler/fabric)
- Tags: architecture
- Published: 2026-02-28

---

**Fabric eliminates the AI integration problem by abstracting disparate LLM vendor APIs into a single, unified interface that normalizes authentication, request formatting, and model discovery across all providers.**

The `danielmiessler/fabric` repository addresses the fragmentation of modern AI services by treating every large language model provider as a **plugin**. Rather than forcing developers to manage unique endpoints for OpenAI, Anthropic, Groq, and Azure, Fabric implements a vendor-agnostic architecture that routes all requests through standardized interfaces. This design pattern effectively solves the AI integration problem by decoupling application logic from provider-specific implementation details.

## The Vendor Interface Abstraction

At the heart of Fabric’s solution is the **`Vendor`** interface defined in [`internal/plugins/ai/vendor.go`](https://github.com/danielmiessler/fabric/blob/main/internal/plugins/ai/vendor.go). Every AI provider—whether a first-class integration or an OpenAI-compatible endpoint—must implement this contract, ensuring consistent behavior across the ecosystem.

The `VendorsManager` struct in [`internal/plugins/ai/vendors.go`](https://github.com/danielmiessler/fabric/blob/main/internal/plugins/ai/vendors.go) maintains a registry of all available vendors in a map keyed by lower-cased names. This enables **O(1) lookup** when resolving provider requests, eliminating the latency and complexity of searching through heterogeneous API documentation during runtime.

## OpenAI-Compatible Normalization Layer

Fabric solves format inconsistencies through the **`openai_compatible`** package located in [`internal/plugins/ai/openai_compatible/providers_config.go`](https://github.com/danielmiessler/fabric/blob/main/internal/plugins/ai/openai_compatible/providers_config.go). This layer treats any provider that speaks the OpenAI API shape as a native citizen, normalizing request and response formats across disparate backends.

The `ProviderConfig` struct describes essential metadata including base URL, optional model-listing endpoints, and support for the newer *Responses* API. The `NewClient` function constructs an `openai.Client`-compatible object that can fall back to raw HTTP calls when necessary. This abstraction allows Fabric to integrate new providers by adding a configuration entry rather than writing custom integration code.

## Runtime Model Discovery and Resolution

### Concurrent Model Fetching

Fabric eliminates manual model catalog maintenance through automated discovery. The `VendorsManager.readModels` method initiates a **concurrent fetch** of `ListModels()` across every configured vendor, aggregating results into a unified `VendorsModels` structure.

This approach provides a **single source of truth** for available models, accessible via [`internal/core/plugin_registry.go`](https://github.com/danielmiessler/fabric/blob/main/internal/core/plugin_registry.go) through the `GetModels()` method. The concurrent design ensures that slow or unresponsive providers do not block the discovery of models from other sources.

### Vendor Resolution Logic

When processing a chat request, `PluginRegistry.GetChatter` in [`internal/core/plugin_registry.go`](https://github.com/danielmiessler/fabric/blob/main/internal/core/plugin_registry.go) implements a hierarchical resolution strategy:

1. **Explicit CLI flags** (`--model`, `--vendor`) take highest precedence
2. **Configured defaults** apply when no flags are present
3. **Model-to-vendor mapping** resolves ambiguous references (case-insensitive)

If multiple vendors offer the same model, Fabric selects the first match while logging a warning, allowing users to force a specific provider via `--vendor`. This logic ensures that the AI integration problem remains invisible to end users while maintaining flexibility for power users.

## Practical Implementation: Code Examples

### Listing Available Vendors

The CLI exposes all configured AI providers through a simple command:

```bash
$ fabric vendors

```

This invokes `registry.ListVendors` in [`internal/cli/cli.go`](https://github.com/danielmiessler/fabric/blob/main/internal/cli/cli.go), which iterates over `registry.VendorsAll.Vendors` populated during `NewPluginRegistry` initialization.

### Targeting Specific Providers

Execute requests against specific backends without modifying global configuration:

```bash

# Route to Groq's Llama 3.1 70B model

$ fabric chat "Explain quantum entanglement" \
      --model llama-3.1-70b --vendor Groq

```

Internally, `PluginRegistry.GetChatter` locates the `Groq` vendor via `VendorsManager.FindByName`, validates the model exists in the cached `VendorsModels`, and instantiates the vendor-specific `Chat` method.

### Programmatic Model Discovery

Fetch available models across all providers using Fabric's Go API:

```go
package main

import (
	"fmt"
	"github.com/danielmiessler/fabric/internal/core"
)

func main() {
	// Initialize registry with all built-in vendors
	reg, _ := core.NewPluginRegistry(nil)
	
	// Concurrent fetch of all models
	models, _ := reg.GetModels()

	for vendor, list := range models.Groups {
		fmt.Printf("=== %s ===\n", vendor)
		for _, m := range list {
			fmt.Println("  -", m)
		}
	}
}

```

This demonstrates `VendorsManager.readModels` performing concurrent `ListModels()` calls across the vendor map defined in [`internal/plugins/ai/vendors.go`](https://github.com/danielmiessler/fabric/blob/main/internal/plugins/ai/vendors.go).

### Disabling Experimental APIs

Force compatibility mode for older providers:

```bash
$ fabric --disable-responses-api chat "Summarize this article"

```

The `configureOpenAIResponsesAPI` function in [`internal/cli/cli.go`](https://github.com/danielmiessler/fabric/blob/main/internal/cli/cli.go) (lines 73-85) toggles `SetResponsesAPIEnabled` on the underlying OpenAI client based on this flag.

## Summary

Fabric solves the AI integration problem through architectural patterns that prioritize abstraction over adaptation:

- **Unified Interface**: The `Vendor` contract in [`internal/plugins/ai/vendor.go`](https://github.com/danielmiessler/fabric/blob/main/internal/plugins/ai/vendor.go) standardizes all provider interactions regardless of underlying API differences.
- **Normalization Layer**: The `openai_compatible` package converts disparate response formats into a consistent shape, enabling rapid integration of new providers through configuration rather than code.
- **Concurrent Discovery**: `VendorsManager.readModels` automatically aggregates available models across all vendors, eliminating manual catalog maintenance.
- **Hierarchical Resolution**: `PluginRegistry.GetChatter` implements intelligent fallback logic that resolves vendor/model ambiguity while respecting explicit user preferences.

## Frequently Asked Questions

### How does Fabric handle authentication for different AI providers?

Fabric delegates authentication to individual vendor implementations while standardizing the configuration interface. Each vendor struct in `internal/plugins/ai/` reads environment variables or configuration files specific to its service (e.g., `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`), but exposes these through the common `Vendor` interface. This allows the CLI in [`internal/cli/cli.go`](https://github.com/danielmiessler/fabric/blob/main/internal/cli/cli.go) to remain agnostic about whether the backend requires bearer tokens, API keys, or Azure Active Directory credentials.

### Can I add a custom AI provider that isn't officially supported?

Yes, Fabric supports adding OpenAI-compatible providers without modifying core code. You can add entries to the `ProviderMap` in [`internal/plugins/ai/openai_compatible/providers_config.go`](https://github.com/danielmiessler/fabric/blob/main/internal/plugins/ai/openai_compatible/providers_config.go), specifying the base URL, model listing endpoint, and API version. Because the `openai_compatible` layer normalizes requests to the OpenAI API shape, any provider speaking that protocol works immediately. For non-OpenAI protocols, you would implement the `Vendor` interface in a new package under `internal/plugins/ai/`.

### What happens if two vendors offer the same model name?

Fabric resolves ambiguity through a deterministic priority system implemented in `PluginRegistry.GetChatter` ([`internal/core/plugin_registry.go`](https://github.com/danielmiessler/fabric/blob/main/internal/core/plugin_registry.go)). When multiple vendors offer an identically named model, the system selects the first match found in the vendor registry while emitting a warning to stderr. Users can override this behavior by specifying `--vendor` explicitly, forcing the system to use the named provider regardless of registry order. This ensures predictable behavior while maintaining flexibility for power users who need specific provider features.

### Does Fabric support streaming responses from AI providers?

Yes, streaming is supported through the `Vendor` interface's `ChatStream` method, which all providers implement. The interface design in [`internal/plugins/ai/vendor.go`](https://github.com/danielmiessler/fabric/blob/main/internal/plugins/ai/vendor.go) ensures that whether the underlying API uses Server-Sent Events (like OpenAI) or WebSockets, the consumer receives a unified stream abstraction. The CLI in [`internal/cli/cli.go`](https://github.com/danielmiessler/fabric/blob/main/internal/cli/cli.go) handles these streams identically regardless of vendor, allowing real-time output for long-form generation tasks without vendor-specific handling code in the application layer.