https://github.com/dev-tayyab/plume
The minimalist, resilient AI client for .NET â one unified API across OpenAI, Anthropic Claude, Google Gemini, and Ollama with built-in failover. Tiny, AOT-friendly, .NET 8/9/10.
https://github.com/dev-tayyab/plume
ai anthropic aot chatgpt claude csharp dotnet dotnet-library failover gemini llm nuget ollama openai resilience streaming
Last synced: about 7 hours ago
JSON representation
The minimalist, resilient AI client for .NET â one unified API across OpenAI, Anthropic Claude, Google Gemini, and Ollama with built-in failover. Tiny, AOT-friendly, .NET 8/9/10.
- Host: GitHub
- URL: https://github.com/dev-tayyab/plume
- Owner: dev-tayyab
- License: mit
- Created: 2026-05-01T07:53:29.000Z (2 months ago)
- Default Branch: main
- Last Pushed: 2026-05-02T11:47:41.000Z (2 months ago)
- Last Synced: 2026-06-03T22:04:38.739Z (about 1 month ago)
- Topics: ai, anthropic, aot, chatgpt, claude, csharp, dotnet, dotnet-library, failover, gemini, llm, nuget, ollama, openai, resilience, streaming
- Language: C#
- Homepage: https://www.nuget.org/packages/Plume
- Size: 122 KB
- Stars: 2
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Plume ðŠķ
**The minimalist, resilient AI client for .NET.**
One unified API. Multiple providers. Built-in failover.
[](https://www.nuget.org/packages/Plume)
[](https://www.nuget.org/packages/Plume)
[](https://github.com/dev-tayyab/Plume/actions/workflows/ci.yml)
[](https://github.com/dev-tayyab/Plume/blob/main/LICENSE)
[](https://dotnet.microsoft.com/)
| Package | Version |
| --- | --- |
| [Plume](https://www.nuget.org/packages/Plume) | [](https://www.nuget.org/packages/Plume) |
| [Plume.OpenAI](https://www.nuget.org/packages/Plume.OpenAI) | [](https://www.nuget.org/packages/Plume.OpenAI) |
| [Plume.Anthropic](https://www.nuget.org/packages/Plume.Anthropic) | [](https://www.nuget.org/packages/Plume.Anthropic) |
| [Plume.Google](https://www.nuget.org/packages/Plume.Google) | [](https://www.nuget.org/packages/Plume.Google) |
| [Plume.Ollama](https://www.nuget.org/packages/Plume.Ollama) | [](https://www.nuget.org/packages/Plume.Ollama) |
```csharp
using var http = new HttpClient();
var ai = PlumeClient.CreateBuilder()
.Use(new OpenAIProvider(http, new() { ApiKey = "sk-..." }))
.WithDefaultModel("gpt-4o-mini")
.Build();
string answer = await ai.AskAsync("What is the capital of France?");
```
That's it. From zero to a working LLM call in two lines. No `KernelBuilder`, no plugins, no ceremony.
---
## Why Plume?
The .NET AI ecosystem is dominated by heavyweight frameworks designed for enterprise. Plume is for the rest of us:
- **Tiny.** Core package has minimal dependencies. No Azure SDK pulled in transitively.
- **Multi-provider.** OpenAI, Anthropic Claude, Google Gemini, Ollama â same API, swap at will.
- **Resilient by default.** Provider down? Plume fails over silently to the next one. Your app keeps responding.
- **Async-first.** `IAsyncEnumerable` streaming. `CancellationToken` everywhere. Modern .NET 8+.
- **AOT-ready.** Source-generated JSON, trim-safe, Native AOT compatible.
## Install
```bash
dotnet add package Plume
dotnet add package Plume.OpenAI # optional
dotnet add package Plume.Anthropic # optional
dotnet add package Plume.Google # optional
dotnet add package Plume.Ollama # optional
```
Install only the providers you use. Plume itself does not depend on any specific provider.
## Quick start (DI / ASP.NET)
```csharp
using Plume.DependencyInjection;
using Plume.OpenAI;
builder.Services.AddPlume(options =>
{
options.UseOpenAI(builder.Configuration["OpenAI:ApiKey"]!);
options.DefaultModel = "gpt-4o-mini";
});
// Anywhere in your app:
public class SummaryService(IPlumeClient ai)
{
public Task Summarize(string text) =>
ai.AskAsync($"Summarize in 2 lines: {text}");
}
```
## Streaming
```csharp
await foreach (var chunk in ai.StreamAsync("Write a haiku about rain"))
Console.Write(chunk);
```
## Multi-turn conversations
```csharp
var chat = ai.NewChat(system: "You are a senior C# code reviewer.");
await chat.AskAsync("Review: public string Hi() => \"hi\";");
await chat.AskAsync("How can I make it more idiomatic?");
// Persist or restore
foreach (var message in chat.History)
SaveToDatabase(message);
```
## Failover â the killer feature
```csharp
using Plume.Anthropic;
using Plume.OpenAI;
using Plume.Google;
using Plume.Ollama;
builder.Services.AddPlume(options =>
{
options.UseAnthropic(anthropicKey); // primary
options.FallbackToOpenAI(openAiKey); // if Anthropic fails transiently
options.FallbackToGoogle(googleKey); // then Google
options.FallbackToOllama(); // local last resort
options.DefaultModel = "claude-sonnet-4";
});
```
If Anthropic returns 429 or 503, Plume silently fails over to OpenAI, then Google, then your local Ollama. Your application keeps responding. No code changes, no try/catch. **This is the gap nothing else in the .NET ecosystem fills.**
What counts as transient (failover happens):
- HTTP 429 (rate limit) â uses `Retry-After` if provided
- HTTP 503/504/502/408 (server unavailable, gateway timeout)
- `HttpRequestException` (network failure)
- Timeouts
What does NOT count as transient (failover does NOT happen):
- HTTP 4xx other than 429 (bad request, auth failure, not found)
- Cancellation requested by your `CancellationToken`
## Provider-specific options (strongly typed)
```csharp
var answer = await ai.AskAsync("Generate a story",
new AskOptions
{
Temperature = 0.9,
Extensions = new OpenAIExtensions
{
FrequencyPenalty = 0.5,
Seed = 42
}
});
```
IntelliSense works. Compile-time safety. No stringly-typed dictionaries.
Provider-specific extensions are silently ignored if the request fails over to a different provider â so you can use them safely with failover enabled.
## Supported providers
| Provider | Package | Model prefix | Streaming |
| -------- | ------- | ------------ | :-------: |
| OpenAI (and Azure / OpenRouter / compatible) | `Plume.OpenAI` | `gpt-*`, `o1*`, `o3*`, `o4*` | â
|
| Anthropic Claude | `Plume.Anthropic` | `claude-*` | â
|
| Google Gemini | `Plume.Google` | `gemini*` | â
|
| Ollama (local models) | `Plume.Ollama` | any | â
|
## Samples
Runnable end-to-end samples live in [`samples/`](https://github.com/dev-tayyab/Plume/tree/main/samples). Each is a single-file program â clone the repo, set the relevant `*_API_KEY` env var, and `dotnet run`.
| Sample | What it shows |
| --- | --- |
| [Console](https://github.com/dev-tayyab/Plume/tree/main/samples/Plume.Sample.Console) | Streaming + multi-turn chat against OpenAI in ~20 lines |
| [Console.Google](https://github.com/dev-tayyab/Plume/tree/main/samples/Plume.Sample.Console.Google) | Same flow against Google Gemini â drop-in provider swap |
| [Failover](https://github.com/dev-tayyab/Plume/tree/main/samples/Plume.Sample.Failover) | Anthropic â OpenAI â Google â Ollama failover chain |
| [ToolCalling](https://github.com/dev-tayyab/Plume/tree/main/samples/Plume.Sample.ToolCalling) | Provider-agnostic function/tool calling |
| [StructuredOutput](https://github.com/dev-tayyab/Plume/tree/main/samples/Plume.Sample.StructuredOutput) | Source-generated typed responses (JSON schema, no reflection) |
| [Embeddings](https://github.com/dev-tayyab/Plume/tree/main/samples/Plume.Sample.Embeddings) | Embedding vectors with the same provider abstraction |
## Status
ð§ **v0.1.0-alpha** â under active development, API may evolve before 1.0.
The roadmap:
| Version | Focus |
| :-----: | --- |
| 0.1 | Core API: ask, stream, chat, failover. 4 providers shipping. |
| 0.2 | Source-generated typed responses. Tool calling. |
| 0.3 | MCP client support. Embeddings. |
| 0.4 | Vision/multimodal input. |
| 0.5 | Retrieval helpers (RAG). |
| 1.0 | API freeze. Production-ready. |
## Contributing
Issues and PRs welcome.
## License
MIT. Use it freely in commercial projects.
---
Built with âĪïļ for .NET developers who want their AI code to read like it was written, not generated.