Iris
A conversational AI platform with personas and real-time streaming.
Iris is an AI chat app for talking to personas that each have their own system prompt, preferred model, and conversation history. I built it because I wanted one place to reach different AI models through different personas, without being locked into a single provider.

Why it exists
I wanted a single place to talk to different AI models through different personas. Each persona has its own system prompt and preferred model. I switch between them depending on what I'm working on. Most AI chat tools are single-threaded and locked to one provider. This one isn't.
How it's built
The backend is .NET 10 with a layered architecture: API, Application, Domain, and Infrastructure. Commands and queries go through MediatR, keeping the request handling thin. The frontend is React with TypeScript. Real-time message streaming runs over SignalR, so responses come in chunk by chunk.
Event sourcing
Conversations are event-sourced. Every state change (message sent, response completed, model changed) is stored as an event. Read models are projected from the event stream asynchronously. It means there's a full audit trail of every conversation, and rebuilding state from scratch is straightforward.
Provider abstraction
The chat provider sits behind an interface. Right now it talks to OpenRouter, which reaches most models (Claude, GPT, Grok), and swapping in a direct Anthropic or OpenAI call would just be another implementation of the same interface. Because the model is a setting on the conversation, you can switch it partway through and the full history carries over to the new one. A background worker pulls conversation turns from a queue and runs them independently of the request pipeline.
Testing
Around 100 tests split roughly half and half between unit and integration. The integration tests run against a real PostgreSQL instance. I find that balance works well for a project this size: unit tests for domain logic, integration tests for the full command/query pipeline.
What's next
The current version handles the basics well. Next up is tool use, memory extraction across conversations, and better model controls. The event-sourced foundation makes adding these features easier since the conversation history is already fully preserved.