All notable changes to CouncilEx are documented here.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Unreleased
0.1.0 - 2026-05-31
First public release. CouncilEx is a framework for building multi-model, multi-agent LLM council workflows in Elixir: define a council of members, run structured rounds, aggregate or judge their outputs, and synthesize a final answer. Provider-agnostic, OTP-supervised, single-BEAM by default.
Added
Councils & runs
- Static & dynamic councils — declare councils with the
use CouncilExDSL, or build them as data via%CouncilEx.DynamicCouncil{}(pipeable builder, JSON ser/de, registry-by-string-name). - Polymorphic dispatch —
CouncilEx.run/3,start/3, andstart_link/3accept either a module-form council or a%DynamicCouncil{}; one execution path, identical semantics. - Sync + async runs — blocking
run/3for short workflows;start/3(GenServer.start/3semantics: unsupervised, unlinked) andstart_link/3(linked) for async, both returning{:ok, pid}. Communicate with the runner via message passing. - Pre-run validation —
CouncilEx.validate/1returns structured[%{path, code, message}]errors for module-form and%DynamicCouncil{}councils.start/3gates on it, so config errors return{:error, {:invalid_council, errs}}before any process spawns or token is spent. - Optional run grouping —
CouncilEx.Supervisor, a thinDynamicSupervisorwrapper for tenant isolation, bulk-terminate, and in-flight visibility. Runs are unsupervised by default (caller-owned pids). Failure handling — per-round
failure_mode: :continue | :fail_fast, retry policies, member timeouts, run-levelcancel/1, and structured%CouncilEx.Error{}.- Sub-councils — nest a council as a member (registered name, module
atom, or nested
%DynamicCouncil{}) with optional input mappers. - Routers — dynamic next-step selection between members or rounds, declared inline or registered by name.
- Registry — config + runtime registration of profiles, tools, schemas, routers, rounds, sub-councils, and input mappers, all resolvable by string name.
Rounds, councils & aggregators
- Round library —
IndependentAnalysis,Critique,Vote,Synthesis,WeightedSynthesis,Iterate,Ranking,PairwiseElimination,PeerReview,AnonymizedPeerReview, plus a custom-round behaviour. - Built-in councils —
ParallelPanel,PeerReview,Voting,Specialist,Consensus,Tournament,Chairman,WeightedConsensus,JuryWithRetry. - Confidence-triggered retry —
Councils.JuryWithRetryruns K judges in parallel and re-samples on low average confidence (default threshold0.7, max2iterations). Judges do not see each other across retries — independent re-sample, not debate (respects Wu et al. Can LLM Agents Really Debate?, arXiv:2511.07784). - Reliability-weighted consensus —
Councils.WeightedConsensusweights members by static:weight, per-member:confidence, or historicalReliabilitylookups. Inspired by Wu et al. Council Mode (arXiv:2604.02923); mapping indocs/COUNCIL_MODE_PAPER.md. - Aggregators —
Plurality,Borda,Condorcet,WeightedMean,Median,PeerRanking.
AutoCouncil
- AutoCouncil — opt-in routing layer: a council that picks itself.
Pluggable strategies (
:rules,:cascade, plus stub:embedding/:llm_classify/:llm_build) select an existing council per prompt or synthesize a fresh%DynamicCouncil{}. SameCouncilEx.run/3entry; routing decision surfaced inresult.metadata.auto.
Per-member capabilities
- Profiles — reusable per-member capability bundles (provider, model,
temperature, tools, retry); 9 prebaked profiles plus user-defined
use CouncilEx.Profilemodules. - Structured output — Ecto-schema or inline JSON Schema per member, with
native
responseSchema(Gemini) and tool-shaped fallback (OpenAI/Anthropic). - Streaming — token-level streaming with sink callbacks, integrated with the tool-loop so tool-spanning turns read as one continuous response.
- Tool calling — parallel tool execution with concurrency + timeout knobs,
multi-iteration tool-loops in both
complete/2andstream/3, and:tool_choice(:auto | :required | :none | "name"). - RAG via tools — council-level
add_council_tool/2shares a toolset across members; per-member:toolskeeps specialist corpora private.CouncilEx.Tools.InMemoryDocsis a zero-dep BM25 retrieval tool. Seedocs/RAG.md. - Per-member confidence — opt-in
:confidencestrategies (:self_report,:logprob) populate%MemberResult{}.confidencefor downstream weighting.
Providers
- Built-in adapters — OpenAI, Anthropic, Gemini, and OpenRouter implement
the
CouncilEx.Provider.Adapterbehaviour; Ollama ships as a config preset over the OpenAI adapter. - Pluggable providers — implement
CouncilEx.Provider.Adapterfor any backend. - Mock provider — scriptable in-memory provider
(
CouncilEx.Providers.Mock.script/2) for tests and example fixtures; not for production.
Reliability & bias
- Reliability store —
CouncilEx.Reliability(ETS default, pluggable) tracks per-member historical accuracy by query features; feedsWeightedConsensus. - BiasDetector — diagnostic-only
CouncilEx.BiasDetector.analyze/2flags when member disagreement correlates with demographic axes. Lexicon backend in core.
Persistence (optional)
- Optional backends —
*.Ectobackends forReliability,Registry, andRecorder, plus*.RedisforReliabilityandRegistry. - Oban worker —
CouncilEx.Workers.Obanfor running councils as background jobs. Seedocs/RUNNING_WITH_OBAN.md. - Config
:modeknob —:single_node/:multi_nodeflips all backends in one place; migration + recovery helpers underCouncilEx.Persistence.
Observability
- PubSub events — 10 frozen events on
"council_ex:run:#{run_id}"(CouncilEx.Events); idempotent subscribe across:pgand Phoenix.PubSub adapters. Telemetry —
[:council_ex, :run | :round | :member | :tool, :*]events with full parity on the async path (~3µs/event overhead), enriched with per-member token, model, provider, round, and confidence metadata.Verbose tracer —
verbose: true | :debugprints a human-readable per-run timeline; pure event consumer, zero production cost when off.- Diagram tooling —
CouncilEx.Diagram.{to_ir, topology, sequence}for both council shapes (ASCII / Mermaid / sequence), plus themix council.diagramtask. IR is React-Flow-friendly JSON.
Testing
CouncilEx.Test— helpers for asserting on runs and capturing emitted events. Seedocs/UNIT_TESTING.mdanddocs/TESTING.md.