Morgana is a modern and flexible conversational AI framework designed to handle complex scenarios through a sophisticated multi-agent, intent-driven architecture. Built on cutting-edge .NET 10 and leveraging the actor model via Akka.NET, Morgana orchestrates specialized AI agents that collaborate to understand, classify and resolve customer inquiries with precision and context awareness.
The system is powered by Microsoft.Agents.AI, enabling seamless integration with Large Language Models (LLMs) while maintaining strict governance through guard rails and policy enforcement.
| Cauldron (Web Channel) | ||||
|---|---|---|---|---|
|
|
|
|
|
| Grimoire (TTY Channel) | ||||
|
|
|
|
|
Traditional chatbot systems struggle with complexity. They either become monolithic and unmaintainable, or lack the contextual awareness needed for sophisticated interactions.
Morgana reimagines conversational AI through 4 foundational pillars that work in harmony to deliver an orchestration framework that is powerful yet remarkably simple to configure.
๐ญ Actor System | ๐ค Agent System | ๐ Prompting System | ๐พ Context System
Resilient multi-channel orchestration through Akka.NET message-driven architecture
Morgana leverages the actor model to create a fault-tolerant, scalable orchestration layer. Each conversation is managed by a hierarchy of specialized actors that collaborate through asynchronous message passing:
- ConversationManager: Stable entry point owning the lifecycle of a single user session
- ConversationSupervisor: Orchestrates the entire conversation flow and coordinates child actors
- Guard: Validates every interaction against business policies and brand guidelines
- Classifier: Analyzes user intent through LLM-powered classification
- Router: Dynamically routes requests to appropriate agents
This architecture ensures that failures are isolated, system state remains consistent, and conversations can scale horizontally without bottlenecks.
Actors Conversation Flow
graph LR
U@{shape: circle, label: "๐ค User"}
%% Channels (reference clients, out-of-the-box)
subgraph Channels["Channels"]
CLD@{shape: rounded, label: "๐ Cauldron"}
RUN@{shape: rounded, label: "๐ Grimoire"}
end
%% Backend boundary
subgraph Morgana["Morgana"]
CM@{shape: rounded, label: "Manager"}
SV@{shape: rounded, label: "Supervisor"}
G@{shape: rounded, label: "Guard"}
C@{shape: rounded, label: "Classifier"}
R@{shape: rounded, label: "Router"}
MA@{shape: rounded, label: "Agent"}
end
%% User โ Channel
U -- HTML --> CLD
U -- TTY --> RUN
%% Channel โ BE
CLD -- SignalR --> CM
RUN -- Webhook --> CM
CM -- 1. Creates conversation and activates actor --> SV
%% Internal BE flow
SV -- 2. Asks for language compliance --> G
SV -- 4. Asks for intent classification --> C
SV -- 6. Asks for agent routing --> R
R -- 7. Activates agent for intent handling --> MA
%% External systems
G -. 3 Prompts for language compliance .-> LLM@{shape: braces, label: "LLM (Anthropic, Azure OpenAI, Ollama, OpenAI)"}
C -. 5 Prompts for intent classification .-> LLM
MA -. 8 MCP tool discovery .-> MCP@{shape: das, label: "MCP Server"}
MA -. 9 Intent handling .-> LLM
Declarative specialization with automatic discovery and dynamic capabilities
Agents in Morgana are domain specialists that self-register through declarative attributes, eliminating manual configuration and enabling true plugin-based extensibility. Each agent inherits from MorganaAgent and declares its responsibilities through simple annotations:
[HandlesIntent("billing")]
public class BillingAgent : MorganaAgent { ... }At startup, Morgana automatically discovers all agents across configured assemblies and validates bidirectional consistency between declared intents and classifier configurationโfail-fast guarantees ensure errors are caught before reaching production.
Agents express their capabilities through tools, which can be native implementations (inherited from MorganaTool) or dynamically acquired from external MCP servers:
[ProvidesToolForIntent("billing")]
public class BillingTool : MorganaTool
{
public async Task<string> GetInvoices(string userId, int count) { ... }
}
[HandlesIntent("monkeys")]
[UsesMCPServer("https://func-monkeymcp-3t4eixuap5dfm.azurewebsites.net/")]
public class MonkeyAgent : MorganaAgent { ... } // Acquires tools at runtime!The MCP integration is particularly powerful: agents can extend their capabilities by consuming Model Context Protocol servers, where external tools become indistinguishable from native implementations. This enables rapid prototyping, microservice integration, and ecosystem-driven feature developmentโall without writing a single line of tool implementation code.
The framework provides adapters (MorganaAgentAdapter, MorganaToolAdapter) that bridge the declarative configuration with runtime activation, handling validation, dependency injection, and lifecycle management transparently.
Agents Conversation Flow
graph LR
U@{shape: circle, label: "๐ค User"}
%% Channels (reference clients, out-of-the-box)
subgraph Channels["Channels"]
CLD@{shape: rounded, label: "๐ Cauldron"}
RUN@{shape: rounded, label: "๐ Grimoire"}
end
%% Backend boundary
subgraph Morgana["Morgana"]
CM@{shape: rounded, label: "Manager"}
SV@{shape: rounded, label: "Supervisor"}
G@{shape: rounded, label: "Guard"}
MA@{shape: rounded, label: "Agent"}
end
%% User โ Channel
U -- HTML --> CLD
U -- TTY --> RUN
%% Channel โ BE
CLD -- SignalR --> CM
RUN -- Webhook --> CM
CM -- 1. Continues conversation and engages actor --> SV
%% Internal BE flow
SV -- 2. Asks for language compliance --> G
SV -- 4. Engages agent for intent handling --> MA
%% External systems
G -. 3 Prompts for language compliance .-> LLM@{shape: braces, label: "LLM (Anthropic, Azure OpenAI, Ollama, OpenAI)"}
MA -. 5 Intent handling .-> LLM
First-class artifacts with layered personality architecture and structured behavioral policies
Prompts are not hardcoded strings in Morganaโthey are versioned, maintainable project artifacts managed through the IPromptResolverService. This separation of concerns enables prompt engineering teams to iterate independently from application logic, supporting A/B testing, localization, and behavioral evolution without redeployment.
The system distinguishes between two prompt categories:
- System prompts (
morgana.json): Define actor behaviors, global policies, and orchestration rules - Domain prompts (
agents.json): Define agent personalities, instructions, and tool configurations
A unique characteristic of Morgana is its Layered Personality System. Every interaction maintains a consistent global personality (Morgana's core character) while allowing agents to express domain-appropriate specializations:
- Global Layer: Defines Morgana's fundamental character, tone, and values
- Agent Layer: Adds contextual traits that complement (never contradict) the global personality
For example, BillingAgent might be "a pragmatic and concrete witch" while ContractAgent is "a patient and empathetic witch"โboth remain recognizably "Morgana" while adapting to domain-specific user needs. This creates vertical consistency across conversations with horizontal variation per expertise area, delivering a unified brand experience that feels naturally specialized.
Prompts also define Global Policies (critical rules like context handling, interaction tokens) that are automatically composed into agent instructions, ensuring system-wide behavioral consistency without repetition.
Distributed memory with encrypted persistence and first-write-wins shared registry
Morgana extends Microsoft.Agents.AI framework with a sophisticated context management layer that balances isolation, sharing and persistence. Each agent maintains its own isolated context through MorganaAIContextProvider, a custom implementation that manages both conversation history and stateful variables.
Context isolation ensures agents operate independentlyโtheir memories, variables, and state remain private by default. However, the system enables selective shared context synchronization for variables declared in configuration:
{
"Name": "userId",
"Scope": "context",
"Shared": true
}When one agent writes a shared variable (e.g., userId), the value is persisted into a conversation-scoped shared_context SQLite table with first-write-wins semantics. At the start of each turn, every agent loads the registry and merges incoming shared variables into its local context (again using first-write-wins: existing local values are never overwritten). This eliminates redundant user interactionsโinformation provided once becomes available everywhere, creating a seamless multi-agent experience while remaining resilient to actor lifecycle changes.
Conversation persistence is handled through the IConversationPersistenceService abstraction, with a default SQLite implementation providing enterprise-grade security. The schema includes both per-agent AgentSession BLOBs (encrypted with AES-256-CBC) and a shared_context table for cross-agent variables. Sessions can resume across application restarts without losing context or requiring all actors to remain in memory.
The persistence layer supports multi-agent history reconciliation: while agents maintain isolated threads, Morgana reconstructs a unified timeline for UI presentation, giving users an uninterrupted conversational experience regardless of which agents participated behind the scenes.
This architecture delivers 3 critical benefitsโall configurable through declarative JSON rather than coding:
- data security through encryption and isolation
- intelligent context sharing via persistent, first-write-wins registry
- resilient conversations that survive actor decommission and system restarts
To use latest images from Docker Hub (showcase for what Morgana looks like and how it works):
# ๐ Copy the production template
cp production.env.template .env
# โ๏ธ Configure your secrets
nano .env # or use your favorite editor
# ๐ณ Start the containers (Morgana + Cauldron)
docker compose up
# โ
Open your browser at http://localhost:5002
# ๐ฌ (Optional) Chat with Morgana via Grimoire's TUI in a separate terminal
# Grimoire owns the terminal (Spectre.Console Live UI), so it must be launched
# interactively with `run --service-ports`, not via `up`. `--use-aliases`
# registers `grimoire` as a network alias so Morgana's webhook callback resolves.
docker compose run --rm --service-ports --use-aliases grimoire
# ๐ Stop the containers
docker compose downFor developers who want to build from source code (recommended, since you will give Morgana your domain in terms of intents, agents, prompts and tools):
# ๐ Copy the development template
cp development.env.template .env
# โ๏ธ Configure your secrets
nano .env
# ๐จ Build .NET projects (from project root)
dotnet build ./Morgana
dotnet build ./Channels/Cauldron
dotnet build ./Channels/Grimoire
dotnet build ./Channels/Rune
# ๐ณ Build Docker images
docker compose --env-file .env --env-file .env.versions build
# ๐ Start the containers (Morgana + Cauldron)
docker compose --env-file .env --env-file .env.versions up
# โ
Open your browser at http://localhost:5002
# ๐ฌ (Optional) Chat with Morgana via Grimoire's TUI in a separate terminal
# Grimoire owns the terminal (Spectre.Console Live UI), so it must be launched
# interactively with `run --service-ports`, not via `up`. `--use-aliases`
# registers `grimoire` as a network alias so Morgana's webhook callback resolves.
docker compose --env-file .env --env-file .env.versions run --rm --service-ports --use-aliases grimoire
# ๐ Stop the containers
docker compose --env-file .env --env-file .env.versions downMorgana.AI is also available as NuGet, so you can build your agents without touching Morgana at all.
Just reference it in your project, model your agents (MorganaAgent) and tools (MorganaTool), prepare their prompts with an agents.json compiled as embedded resource, then build: the resulting assembly is a ready-to-use Morgana plugin!
Drop it into the plugins/ folder of your Morgana instance (or any of the configured plugin directories) and it will be automatically discovered and executed at startup, giving Morgana new domain-driven capabilities and traits.
A concrete example is already in front of you: Morgana.Examples is exactly such a plugin, defining 3 specialized agents which empower the production (showcase) Docker distribution of Morgana out of the box. Your agents will have the same standard structure. The only difference is the reference: because Morgana.Examples ships inside this repository it points at Morgana.AI via a direct project reference, whereas your own plugins will reference the Morgana.AI as a NuGet package.
This is the foundation of the Morgana Agent Ecosystem: independent, shareable, domain-specific plugin agents that can be developed, distributed and adopted across any Morgana-powered application.









