Collective decision making through structured AI deliberation — with RAG, pgvector, Knowledge Keeper, 🛠️ Operator (MCP tools), Chairman, 🔥 Context Compression, ✂️ AutoChunking, 💉 Dependency Injection & 📋 Execution Logging
Delibera is a C# / .NET 10 framework that orchestrates multi-model deliberations between LLMs. Multiple AI models reason through a question across structured rounds, critique each other's answers, and a Chairman weighs the arguments to synthesise a balanced final verdict — enriched by a Knowledge Keeper backed by Qdrant or PostgreSQL/pgvector (RAG), with intelligent context compression to minimise token usage.
The name comes from deliberation — the careful weighing of evidence and viewpoints before reaching a decision. Delibera brings that discipline to AI, helping teams reach thoughtful, well-reasoned outcomes rather than single-model guesses.
| Feature | Description |
|---|---|
| 🏛️ Multi-Model Councils | Orchestrate any number of LLM participants across structured debate rounds |
| ⚖️ Chairman Synthesis | A dedicated moderator opens, regulates, and synthesises the final verdict |
| 📚 Knowledge Keeper (RAG) | Per-round semantic retrieval with structured, cited responses |
| 🛠️ Operator (MCP Tools) | A micro-agent that delegates tasks to MCP servers (web, files, Marp, Notion, …) on demand during the debate |
| 🐘 Qdrant + pgvector | Pluggable vector stores — use a dedicated DB or your existing PostgreSQL |
| 🗜️ Context Compression | 4 strategies (Semantic, Deduplication, Summarization, Hybrid) save 30–70% of tokens |
| ✂️ AutoChunking | Progressive disclosure of large documents across rounds — respects model context windows |
| 💉 Dependency Injection | AddDelibera() extension for IServiceCollection with full options binding |
| 📋 Execution Logging | ExecutionLog model with LogLevel — Chairman, KK, Compression & participant events |
| 📁 Separate File Output | Export result.md, statistics.md, and logs.md independently |
| 🔌 Interface-First | Clean abstractions for providers, factories, builders and executors |
| 🤝 Microsoft.Extensions.AI | First-class support for IChatClient / IEmbeddingGenerator — plug in OpenAI, Azure OpenAI, Ollama or any compatible backend, with middleware (function calling, logging) |
| 🛑 Cooperative Cancellation | Every public async method accepts a CancellationToken; a host shutdown or user cancel aborts the debate mid-flight (rounds, LLM calls, MCP tools, RAG, file saves) |
| 🧱 Modern C# 15 (preview) | Built on .NET 10 with LangVersion=preview, file-scoped namespaces, records, span/SIMD hot paths |
| Feature | Description |
|---|---|
| 🌊 Async Streaming Council | ICouncilExecutor.StreamDebateAsync yields each DebateRound live via an internal Channel<DebateRound> bridge — perfect for ASP.NET Core SSE, WebSocket, Blazor, and CLI live output. DebateRound.Total + IsFinal + LastStreamedResult round metadata included. |
| 🗳️ Pluggable Vote Engine | IVotingStrategy with built-in MajorityVotingStrategy, BordaCountVotingStrategy, WeightedVotingStrategy (per-member MemberWeights). Chairman.CreateVoting(...) swaps the synthesis path for a verifiable decision tally rendered as a 🗳️ Voting Tally section in the Markdown output. |
| 💾 Debate Persistence & Resume | IDebateStore + FileDebateStore (atomic JSON write-then-rename, RetentionDays) + InMemoryDebateStore. CouncilBuilder.WithPersistence(...) saves a checkpoint after every round; ResumeFrom(debateId) continues from the last completed round after a crash or pause. |
| 🧠 Agent Memory | IAgentMemory with InMemoryAgentMemory (Jaccard similarity), QdrantAgentMemory (per-agent collection), PgVectorAgentMemory (shared table filtered by agent_name). CouncilBuilder.WithAgentMemory(...) recalls before + persists after every debate. |
| 📊 OpenTelemetry-style Observability | DeliberaActivitySource + DeliberaMeter with histograms, counters, and gauge for spans like delibera.council.execute, delibera.council.round, delibera.compression. Zero-overhead when no listener is attached. CouncilBuilder.WithTelemetry(...) enables it. |
| 📋 Structured Output | IStructuredOutputSerializer + JsonSchemaOutputSerializer (uses .NET 10 JsonSchemaExporter). ICouncilExecutor.ExecuteTypedAsync<TVerdict> returns a strongly-typed verdict deserialised from the Chairman's response. One automatic retry on deserialisation failure. |
| 🔄 Adaptive Strategy Switching | IStrategySelector + AdaptiveStrategySelector swap the debate strategy mid-flight when responses stagnate (StagnationThreshold consecutive low-diversity rounds, Levenshtein fallback when no embedding provider). |
| 📋 Debate Templates | 6 built-in templates (DebateTemplate.ArchitectureReview, RiskAssessment, CodeReview, ProductDecision, SecurityAudit, DataArchitecture) with pre-configured participants, personas, strategies, and chairmen. |
| ⚡ Quick Wins | DebateResult.ToHtml() + SaveToHtmlAsync(); CouncilBuilder.WithTimeout(TimeSpan); Persona presets; CouncilBenchmark for side-by-side model comparison; WithParticipantLimit(int) safety guard. |
See CHANGELOG.md for the full v10.2.6 release notes and docs/v10.2.6.md for the original roadmap.
- Quick Start
- Dependency Injection
- Operator (MCP Tools)
- Context Compression
- AutoChunking
- RAG Integration
- Debate Strategies
- Output Files Structure
- Cancellation Support
- ConsoleApp Examples
- Installation & Build
- Architecture
- Contributing
- License
- .NET 10 SDK (≥ 10.0.301) — the project targets
net10.0and builds withLangVersion=previewto enable C# 15 features. See docs/NET10-Upgrade.md for the full migration notes. - A running Ollama instance — local (
ollama serve) or Ollama Cloud (just an API key, no install). - The minimal set of models listed below.
- Optional — for the Operator role: Node.js + npx to launch MCP servers
(e.g.
@playwright/mcp,@marp-team/marp-cli). See Operator (MCP Tools).
Suitable for smoke-testing, low-end hardware, and quick CLI runs.
| Purpose | Model | Size | Pull command |
|---|---|---|---|
| Council member | llama3.2:1b |
1.3 GB | ollama pull llama3.2:1b |
| Council member | qwen2.5:1.5b |
1.1 GB | ollama pull qwen2.5:1.5b |
| Embeddings (RAG) | nomic-embed-text |
274 MB | ollama pull nomic-embed-text |
Good reasoning quality with low latency. This is the default set used throughout the README.
| Purpose | Model | Size | Pull command |
|---|---|---|---|
| Council member | llama3.2:3b |
2.0 GB | ollama pull llama3.2:3b |
| Council member | qwen2.5:7b |
4.7 GB | ollama pull qwen2.5:7b |
| Embeddings (RAG) | nomic-embed-text |
274 MB | ollama pull nomic-embed-text |
Heavier local models, recommended on GPUs with ≥ 24 GB VRAM or on Ollama Cloud.
| Purpose | Model | Size | Pull command |
|---|---|---|---|
| Council member | llama3.1:8b |
4.9 GB | ollama pull llama3.1:8b |
| Council member | qwen2.5:14b |
9.0 GB | ollama pull qwen2.5:14b |
| Council member | mistral:7b |
4.4 GB | ollama pull mistral:7b |
| Chairman | qwen2.5:14b (or larger) |
9.0 GB | ollama pull qwen2.5:14b |
| Embeddings (RAG) | nomic-embed-text |
274 MB | ollama pull nomic-embed-text |
💡 Ollama Cloud has the same model names but doesn't require local disk space — you only need an API key. See the Configuration section for setting it.
dotnet add package Delibera.Coreusing Delibera.Core.Council;
using Delibera.Core.Providers;
using var factory = new ProviderFactory();
var ollama = factory.CreateOllama("http://localhost:11434");
var result = await new CouncilBuilder()
.AddMember("llama3.2:3b", ollama, "Analyst")
.AddMember("qwen2.5:7b", ollama, "Strategist")
.SetChairman(Chairman.CreateStandard("qwen2.5:7b", ollama))
.WithStandardDebate()
.WithSystemPrompt("You are a software architecture expert.")
.WithUserPrompt("Microservices vs Monolith for a 5-person startup?")
.WithMaxRounds(4)
.SaveResultTo("./deliberation.md")
.Build()
.ExecuteAsync();
Console.WriteLine(result.FinalVerdict);📄 See docs/QuickStart.md for a step-by-step walkthrough.
dotnet runDelibera will run a structured, multi-round debate and write the full transcript and the
Chairman's verdict to deliberation.md.
Register all Delibera services in one line:
using Delibera.Core.DependencyInjection;
// Option A: With configuration binding (binds the "Delibera" section)
services.AddDelibera(configuration, "Delibera");
// Option B: With options delegate
services.AddDelibera(options =>
{
options.Strategy = "Standard";
options.MaxRounds = 4;
options.Temperature = 0.7f;
options.Compression.Enabled = true;
options.Compression.Strategy = "Hybrid";
options.Compression.TargetRatio = 0.5;
});
// Option C: Defaults only
services.AddDelibera();Resolves these interfaces from DI:
| Interface | Implementation | Lifetime |
|---|---|---|
ILLMProviderFactory |
ProviderFactory |
Singleton |
IRagProviderFactory |
RagProviderFactory |
Singleton |
ICompressionFactory |
CompressionService |
Singleton |
ICouncilBuilder |
CouncilBuilder |
Transient |
{
"Delibera": {
"Strategy": "Standard",
"MaxRounds": 4,
"Temperature": 0.7,
"SystemPrompt": "You are a knowledgeable AI expert participating in a council debate.",
"Providers": {
"DefaultType": "Ollama",
"DefaultEndpoint": "http://localhost:11434",
"ApiKey": "",
"EmbeddingModel": "nomic-embed-text"
},
"Compression": {
"Enabled": true,
"Strategy": "Hybrid",
"TargetRatio": 0.5,
"EnableCache": true,
"MaxCacheEntries": 256
},
"Rag": {
"Enabled": false,
"ProviderType": "Qdrant",
"Host": "localhost",
"Port": 6334,
"CollectionName": "council_knowledge",
"ConnectionString": null
},
"Output": {
"Directory": "./debate_results",
"SeparateFiles": true,
"FilePrefix": null
}
}
}To use Ollama Cloud, set Providers:DefaultEndpoint to https://api.ollama.com and put your
key in Providers:ApiKey (or OllamaCloud:ApiKey in the DeliberaApp section used by the
console app — see ConsoleApp Examples).
The Operator is a lightweight micro-agent that connects the council to the outside world through MCP (Model Context Protocol) servers. It exposes whatever tools those servers provide — web browsing, file system access, Marp presentation generation, Notion, PostgreSQL, etc. — to the debate participants.
How it works
-
The Operator connects to one or more MCP servers and discovers their tools on
InitializeAsync. -
Participants are told (in their system prompt) what the Operator can do, and can delegate a task at any moment during the debate by writing a marker in their message:
[[OPERATOR: open https://modelcontextprotocol.io and summarize what MCP is]] -
The Operator interprets the request with its own (cheaper) LLM model, picks and calls the right MCP tools, interprets the results, and returns a concise answer that is injected into the next round.
-
If the council uses context compression, the Operator can reuse the same strategy to compress large tool outputs before they re-enter the debate. Its
DisposeAsyncis aValueTask(.NET 10IAsyncDisposable) so MCP clients are released without aTaskallocation.
All Operator interactions are recorded per round and rendered in the final Markdown report under a 🛠️ Operator Interactions block.
using Delibera.Core.Models;
var servers = new[]
{
// stdio transport — launches a local MCP server process
McpServerConfig.Stdio(
name: "browser",
command: "npx",
arguments: new[] { "-y", "@playwright/mcp@latest", "--headless" }),
McpServerConfig.Stdio(
name: "marp",
command: "npx",
arguments: new[] { "-y", "@marp-team/marp-cli", "--server", "./out" }),
// …or an HTTP/SSE transport for a remote MCP server
// McpServerConfig.Http(
// name: "remote",
// endpoint: "https://my-mcp-host.example.com/mcp",
// additionalHeaders: new Dictionary<string, string> { ["Authorization"] = "Bearer <token>" }),
};| Server | Transport | Launch command | What it provides |
|---|---|---|---|
🌐 browser |
stdio | npx -y @playwright/mcp@latest --headless |
Site navigation, page reading, clicks, screenshots |
🎯 marp |
stdio | npx -y @marp-team/marp-cli --server <dir> |
Generating presentations (HTML/PDF/PPTX) from Markdown |
using Delibera.Core.Council;
using Delibera.Core.Providers.LLM;
var ollama = new OllamaProvider("http://localhost:11434");
var council = new CouncilBuilder()
.AddMember("llama3.2:3b", ollama, "Optimist")
.AddMember("qwen2.5:7b", ollama, "Skeptic")
.SetChairman(Chairman.CreateStandard("qwen2.5:7b", ollama))
// Operator uses its own cheaper model; reuseCompression shares the council's compressor
.WithOperator("llama3.2:3b", ollama, servers, reuseCompression: true)
.WithStandardDebate()
.WithUserPrompt("Research the latest .NET 10 features and prepare a short summary.")
.WithMaxRounds(4)
.Build()
.ExecuteAsync();Prefer to build the Operator yourself? Pass a pre-built instance:
using Delibera.Core.Council;
using Delibera.Core.Interfaces;
using Delibera.Core.Models;
using Delibera.Core.Providers.Mcp;
var @operator = new Operator(
new CouncilMember("llama3.2:3b", ollama, "Operator"),
new IMcpClient[] { new McpClientAdapter(servers[0]), new McpClientAdapter(servers[1]) },
compressor: null, // optional IContextCompressor
compressionOptions: null); // optional CompressionOptions
var council = new CouncilBuilder()
/* …members… */
.WithOperator(@operator)
.Build();await using var @operator = new Operator(
new CouncilMember("llama3.2:3b", ollama, "Operator"),
new IMcpClient[] { new McpClientAdapter(servers[0]), new McpClientAdapter(servers[1]) });
await @operator.InitializeAsync();
var result = await @operator.ExecuteTaskAsync(
"Open https://modelcontextprotocol.io and briefly summarize what MCP is.");
Console.WriteLine(result.FinalAnswer);Configure the Operator declaratively in appsettings.json under Delibera:Operator:
{
"Delibera": {
"Operator": {
"Enabled": true,
"ModelName": "llama3.2:3b",
"ReuseCompression": true,
"McpServers": [
{
"Name": "browser",
"Transport": "Stdio",
"Command": "npx",
"Arguments": [ "-y", "@playwright/mcp@latest", "--headless" ]
},
{
"Name": "remote",
"Transport": "Http",
"Endpoint": "https://my-mcp-host.example.com/mcp",
"AdditionalHeaders": { "Authorization": "Bearer <token>" }
}
]
}
}
}
▶️ A complete, runnable demo lives inOperatorMcpToolsExample.cs. Run it withdotnet run --project src/Delibera.ConsoleApp -- --operator-mcp. For the full technical write-up, see docs/NET10-Upgrade.md.
Automatically compress context between deliberation rounds — save 30–70% of tokens without losing meaning.
| Strategy | How It Works | Best For |
|---|---|---|
| Semantic | Embeds sentences, ranks by relevance to topic, keeps top-N | Large knowledge contexts |
| Deduplication | Removes semantically similar sentences across participants | Multi-model debates with overlap |
| Summarization | LLM produces a concise summary preserving key facts | Maximum compression ratio |
| Hybrid | Dedup → Semantic → Summarize pipeline | Best overall quality |
| None | Pass-through (when disabled) | Debugging |
using Delibera.Core.Compression;
using Delibera.Core.Providers.LLM;
var ollama = new OllamaProvider("http://localhost:11434");
var embeddings = new OllamaEmbeddingProvider(ollama, "nomic-embed-text");
var result = await new CouncilBuilder()
.AddMember("llama3.2:3b", ollama, "Analyst")
.AddMember("qwen2.5:7b", ollama, "Strategist")
.SetChairman(Chairman.CreateStandard("qwen2.5:7b", ollama))
.WithCompression(CompressionStrategy.Hybrid,
llmProvider: ollama,
modelName: "llama3.2:3b",
embeddingProvider: embeddings)
.WithCompressionOptions(new CompressionOptions { TargetRatio = 0.5 })
.WithCompressionCache()
.WithUserPrompt("Analyze our architecture options...")
.WithMaxRounds(4)
.Build()
.ExecuteAsync();
Console.WriteLine(result.TokenStats?.ToSummary());IContextCompressor
├── SemanticCompressor ← Embedding-based sentence ranking
├── DeduplicationCompressor ← Similarity-based duplicate removal
├── SummarizationCompressor ← LLM-powered summarization
├── HybridCompressor ← Multi-stage pipeline (Dedup → Semantic → Summarize)
└── PassThroughCompressor ← No-op (when disabled)
CompressionFactory ← Static factory (Create by enum or string)
CompressionService ← DI-friendly wrapper around CompressionFactory
CompressionCache ← SHA-256 keyed LRU cache
TokenCounter ← Heuristic token estimation
Automatically split large knowledge documents (contracts, reports, articles) into context-window-sized chunks distributed across debate rounds via progressive disclosure. When a document exceeds the smallest model's context window, the orchestrator creates a chunking plan and distributes chunks evenly — every model receives a complete view by the final round.
- Model discovery — queries each model's context window via
GetModelCapabilitiesAsync()(Ollama/api/show, or the built-in registry of 40+ models). - Overhead calculation — system prompt + user question + response buffer + history.
- Chunking plan — splits the document on semantic boundaries (Markdown headers →
paragraphs → sentences), each chunk ≤
minWindow − overhead − safetyMargin. - Progressive disclosure — Round 1 gets chunks 1..N/3, Round 2 gets N/3+1..2N/3, etc.
Each round sees
[Chunk X/Y] SectionTitlemarkers + a summary of previous rounds.
// Path 1: Fluent API
var executor = new CouncilBuilder()
.WithAutoChunking(new AutoChunkingOptions
{
Strategy = ChunkingStrategy.SemanticBoundary,
SafetyMargin = 0.15,
MaxChunksPerRound = 3
})
/* …members, chairman, knowledge… */
.Build();
// Path 2: CouncilOptions snapshot (from DI or manual)
var options = new CouncilOptions
{
AutoChunking = new AutoChunkingConfig { Enabled = true, Strategy = "SemanticBoundary" }
};
var executor = new CouncilBuilder(options) // or .WithOptions(options)
/* … */
.Build();
// Path 3: Lambda configuration
var executor = new CouncilBuilder()
.WithOptions(o =>
{
o.AutoChunking.Enabled = true;
o.AutoChunking.MaxChunksPerRound = 2;
})
/* … */
.Build();{
"Delibera": {
"AutoChunking": {
"Enabled": true,
"Strategy": "SemanticBoundary",
"SafetyMargin": 0.15,
"MaxChunksPerRound": 3,
"EnableMapReduce": true,
"EnableProgressiveDisclosure": true,
"ModelContextWindows": {
"my-custom-model": 65536
}
}
}
}// Query known models
var window = ModelContextWindowRegistry.GetContextWindow("llama3.2"); // → 131072
var window = ModelContextWindowRegistry.GetContextWindow("phi3:mini"); // → 4096
// Register custom models
ModelContextWindowRegistry.Register("my-fine-tuned-model", 65536);
▶️ Run the demo:dotnet run --project src/Delibera.ConsoleApp -- --autochunking
Use a dedicated Qdrant instance or your existing PostgreSQL/pgvector database as a vector store.
using Delibera.Core.Council;
using Delibera.Core.Models;
using Delibera.Core.Providers.LLM;
using Delibera.Core.Providers.RAG;
var ollama = new OllamaProvider("http://localhost:11434");
var embeddings = new OllamaEmbeddingProvider(ollama, "nomic-embed-text");
// pgvector — just add a connection string
var ragFactory = new RagProviderFactory();
var rag = ragFactory.CreatePgVector(
embeddings,
"Host=localhost;Database=council_vectors;Username=postgres;Password=postgres");
await rag.IndexDocumentAsync("my_collection", documentText);
var results = await rag.SearchAsync("my_collection", "query", limit: 5);
// Wire into a Knowledge Keeper
var kkMember = new CouncilMember("llama3.2:3b", ollama, "Knowledge Keeper");
var keeper = new KnowledgeKeeper(rag, kkMember, "my_knowledge");
await keeper.IndexFileAsync("./docs/architecture.md");IRagProvider
├── QdrantRagProvider
│ └── QdrantVectorStore ← Qdrant gRPC
└── PgVectorRagProvider
└── PgVectorStore ← PostgreSQL/pgvector
IEmbeddingProvider
└── OllamaEmbeddingProvider
The Knowledge Keeper is then attached to the council via WithKnowledgeKeeper(...) — see
the RAG example for a full working demo.
| Strategy | Flow | Use Case |
|---|---|---|
| StandardDebate | Initial → Critique → Improved → Verdict | General analysis |
| CritiqueDebate | Position → Attack → Defence → Judge | Hypothesis testing |
| ConsensusDebate | Perspectives → Common Ground → Consensus → Facilitator | Optimal solution search |
Each strategy is implemented as an IDebateStrategy — see
src/Delibera.Core/Debate/ for the full source.
| Pattern | Usage |
|---|---|
| Factory | ProviderFactory, RagProviderFactory, CompressionFactory, Chairman |
| Strategy | IDebateStrategy, IContextCompressor |
| Builder | CouncilBuilder fluent API |
| Template Method | DebateScenario abstract base class |
| Cache | CompressionCache with SHA-256 keys |
| Observer | OnRoundCompleted event on CouncilExecutor |
Each deliberation can be exported as a single file or as three separate Markdown documents:
var result = await executor.ExecuteAsync();
// Save to 3 separate files
var (resultPath, statsPath, logsPath) = await result.SaveAllAsync("./output");
// Creates: debate_20260604_120000_result.md
// debate_20260604_120000_statistics.md
// debate_20260604_120000_logs.md
// Or save individually
await result.SaveToMarkdownAsync("result.md");
await result.SaveStatisticsAsync("statistics.md");
await result.SaveLogsAsync("logs.md");| File | Contents |
|---|---|
*_result.md |
Full deliberation transcript, rounds, and the Chairman's final verdict |
*_statistics.md |
Token usage statistics with per-round breakdown |
*_logs.md |
Execution logs (ExecutionLog) for Chairman, KK, compression & participants |
Every public async method in Delibera honors a CancellationToken cooperatively. A single
cancel signal aborts the entire pipeline — rounds, chairman synthesis, LLM calls, MCP tools,
RAG queries and even file writes — via OperationCanceledException.
using var cts = new CancellationTokenSource(TimeSpan.FromMinutes(5));
var result = await executor.ExecuteAsync(cts.Token);ASP.NET Core / Worker Services can link the token to IHostApplicationLifetime.ApplicationStopping
via the Delibera.Core.Extensions.CouncilExecutorLifetimeExtensions.ExecuteAsync(executor, lifetime, ct)
helper. Console apps can wire Console.CancelKeyPress to the same CancellationTokenSource.
The Delibera.ConsoleApp includes a --cancellation demo that exercises this end-to-end.
See the Cancellation section in Delibera.Core README
for the full table of cancellable operations and the linked-token pattern.
The repository ships with Delibera.ConsoleApp, a runnable demo
project that exercises every feature. Run it from the repo root:
# Clone the repository
git clone https://github.com/delibera/Delibera.git
cd Delibera/src/Delibera.ConsoleApp
# Run a specific example
dotnet run -- --di # Dependency Injection
dotnet run -- --separate-files # Save result.md, statistics.md, logs.md
dotnet run -- --compression # Context compression demo
dotnet run -- --multiprovider # Multi-provider (cloud + local) council
dotnet run -- --rag # Qdrant-backed RAG with Knowledge Keeper
dotnet run -- --pgvector # pgvector-backed RAG
dotnet run -- --operator # Operator role basics (MCP tools)
dotnet run -- --operator-mcp # 🆕 Operator with browser + Marp MCP servers
dotnet run -- --autochunking # 🆕 AutoChunking demo (large documents)
# Or run the full default demo (reads appsettings.json)
dotnet runThe console app reads appsettings.json which uses
the DeliberaApp section — by default it points at Ollama Cloud and shows you how to wire
multiple providers, RAG, and compression in one place.
git clone https://github.com/delibera/Delibera.git
cd Delibera
# Build the entire solution
dotnet build --configuration Release
# Run the console demo
cd src/Delibera.ConsoleApp
dotnet runSpin up Qdrant + PostgreSQL/pgvector in one shot. (Ollama is intentionally not included — install it natively so the GPU driver is used directly.)
# From the repo root
docker compose up -d
# In another terminal, run the console app
cd src/Delibera.ConsoleApp
dotnet runThe compose stack exposes:
| Service | URL | Purpose |
|---|---|---|
| Qdrant (REST) | http://localhost:6333 |
Vector store UI / REST |
| Qdrant (gRPC) | localhost:6334 |
gRPC client (used by Delibera) |
| PostgreSQL | localhost:5432 |
pgvector RAG store |
Default credentials: postgres / postgres, database council_vectors.
If you already have these services running natively, just skip
docker composeand point the console app at them —appsettings.jsondefaults tolocalhost.
# Run with Qdrant (Docker)
docker run -d -p 6333:6333 -p 6334:6334 qdrant/qdrant
# Run with pgvector (Docker)
docker run -d -p 5432:5432 -e POSTGRES_PASSWORD=postgres pgvector/pgvector:pg16
# Then enable the pgvector extension
docker exec -it <container> psql -U postgres -d council_vectors -c "CREATE EXTENSION IF NOT EXISTS vector;"| Package | Purpose |
|---|---|
OllamaSharp |
Ollama API client |
Qdrant.Client |
Qdrant vector DB gRPC client |
Npgsql |
PostgreSQL ADO.NET provider |
Pgvector |
pgvector type support for Npgsql |
ModelContextProtocol |
MCP client for the Operator role |
Microsoft.Extensions.AI |
Unified IChatClient / IEmbeddingGenerator AI abstractions & middleware |
Microsoft.Extensions.* |
Configuration, DI and Options |
Delibera integrates with Microsoft.Extensions.AI
(v10.7.0) — the standard .NET abstraction layer for generative-AI services. This lets you drive a
council with any backend that ships an IChatClient (OpenAI, Azure OpenAI, Ollama, Anthropic,
LM Studio / LocalAI / vLLM, …) and compose a middleware pipeline (function/tool invocation,
logging, caching, telemetry) — all without writing a provider per vendor.
| Type | Role |
|---|---|
ChatClientLLMProvider |
Adapts any IChatClient to Delibera's ILLMProvider (with streaming via ChatStreamAsync) |
EmbeddingGeneratorProvider |
Adapts any IEmbeddingGenerator<string, Embedding<float>> to IEmbeddingProvider for RAG |
MicrosoftAIExtensions |
Bridge helpers: AsLLMProvider(), AsEmbeddingProvider(), AsChatClient(), WithMiddleware() |
ProviderFactory.CreateFromChatClient(...) |
Build a cached provider straight from an IChatClient |
AddDeliberaChatClient(...) / AddDeliberaEmbeddingGenerator(...) |
Register the standard AI services in DI |
using Delibera.Core.Extensions;
using Microsoft.Extensions.AI;
// 1) Bring your own IChatClient. For OpenAI:
// dotnet add package Microsoft.Extensions.AI.OpenAI
IChatClient client = new OpenAI.Chat.ChatClient("gpt-4o-mini", apiKey).AsIChatClient();
// 2) (optional) compose middleware — function calling + logging
client = client.WithMiddleware(enableFunctionInvocation: true, loggerFactory);
// 3) expose it to Delibera
ILLMProvider provider = client.AsLLMProvider("OpenAI");
var executor = new CouncilBuilder()
.AddMember("gpt-4o-mini", provider, "Architect")
.AddMember("gpt-4o-mini", provider, "Skeptic")
.SetChairman(Chairman.CreateStandard("gpt-4o-mini", provider))
.WithStandardDebate()
.WithUserPrompt("Modular monolith or microservices for a 5-person team?")
.Build();Ollama works out of the box because OllamaSharp's OllamaApiClient natively implements
IChatClient and IEmbeddingGenerator:
using var ollama = new OllamaProvider("http://localhost:11434");
IChatClient chat = ollama.AsChatClient(); // ready for middleware
ILLMProvider provider = chat.AsLLMProvider("Ollama");
IEmbeddingProvider embeddings = ollama.AsEmbeddingGenerator().AsEmbeddingProvider("nomic-embed-text");await foreach (var chunk in provider.ChatStreamAsync("gpt-4o-mini", systemPrompt, userPrompt))
Console.Write(chunk);ChatStreamAsync is an additive default method on ILLMProvider — providers backed by an
IChatClient stream token-by-token, while older providers transparently fall back to a single call.
services.AddDeliberaChatClient(
sp => new OpenAI.Chat.ChatClient("gpt-4o-mini", apiKey)
.AsIChatClient()
.WithMiddleware(enableFunctionInvocation: true),
providerName: "OpenAI");
services.AddDeliberaEmbeddingGenerator(
sp => /* your IEmbeddingGenerator */,
modelName: "text-embedding-3-small");Try it:
dotnet run --project src/Delibera.ConsoleApp -- --msai
Delibera.Core
├── Council/ ← CouncilBuilder, CouncilExecutor, Chairman, KnowledgeKeeper, Operator
├── Debate/ ← StandardDebate, CritiqueDebate, ConsensusDebate
├── Compression/ ← Semantic / Deduplication / Summarization / Hybrid
├── Chunking/ ← AutoChunker, AutoChunkingOrchestrator, AutoChunkingOptions
├── Providers/
│ ├── LLM/ ← OllamaProvider, ChatClientLLMProvider, EmbeddingGeneratorProvider
│ ├── RAG/ ← QdrantRagProvider, PgVectorRagProvider
│ └── Mcp/ ← McpClientAdapter (Operator ↔ MCP servers)
├── Extensions/ ← MicrosoftAIExtensions (IChatClient ↔ ILLMProvider bridges)
├── DependencyInjection/ ← AddDelibera() / AddDeliberaChatClient() + CouncilOptions
├── Knowledge/ ← MarkdownKnowledgeBase
├── Models/ ← CouncilMember, DebateResult, DebateRound, TokenStatistics, ...
└── Interfaces/ ← ILLMProvider, IRagProvider, IContextCompressor, IOperator, IMcpClient, ...
Contributions are welcome! Please read CONTRIBUTING.md for guidelines on development setup, coding standards, and the pull-request process.
Delibera is released under the MIT License.
Copyright © 2026 Delibera Project.
⚖️ Delibera — Thoughtful AI Decisions
Built with care for AI-powered collective intelligence