Welcome to NotT3Chat, a fully-featured, real-time chat application built for the cloneathon.t3.chat. This project serves as a testament to the raw power and elegance of C# and ASP.NET Core, proving that you don't need TypeScript to build amazing, modern web applications. (Sorry, Theo.)
Too much bullshit just take me to Getting Started.
Why build another chat app? Two reasons:
- To participate in the T3 Clone-a-thon and have some fun.
- To lovingly poke at the T3 stack and demonstrate that a robust, type-safe, and high-performance application can be built with the glorious combination of C# on the backend and plain ol' JavaScript on the front. It's a love letter to backend developers who appreciate strongly-typed languages that aren't a superset of JavaScript.
This is far from just a "hello world" chat. We've packed in some serious features:
- π€ Multi-LLM Support: Seamlessly switch between different models and providers (OpenAI, Google, Anthropic, Groq, DeepSeek, and more). Add custom providers via config.
- β‘ Blazing-Fast Real-Time Chat: Built with the magic of SignalR, messages stream in real-time.
- π Advanced Stream Resumption: Did you close your browser tab mid-stream? No problem. Re-open the chat, and the stream will pick up right where it left off.
- π€ Multi-Session Sync: Open the same chat in multiple windows or on different devices, and watch the messages stream in perfect sync across all of them.
- π Flexible Authentication: Email/password login and/or Google OAuth. Configure what you need.
- π¨ Customizable Branding: Custom fonts, logos, titles, and icons via environment variables.
- π Chat History: All your conversations are saved and can be revisited anytime.
- π Smart Message Limits: 64KB message size limit with visual warnings to prevent context overflow.
- π‘οΈ Repetition Loop Detection: Automatically detects and stops infinite LLM loops using n-gram analysis.
This project was a collaboration between human and machine.
The backend was primarily built by me, with some expert consulting from Sonnet 4. The goal was a lean, powerful, and scalable foundation using ASP.NET Core 8. The multi-LLM support is powered by the fantastic LlmTornado.Toolkit library β a huge shout-out for making the integration so seamless. Hoping to move to ASP.NET Core 10 soon.
The UI was mostly crafted with the help of Claude Code. It was a surprisingly smooth experience, resulting in a clean, component-based React app built with Vite and styled with MUI.
- .NET SDK 8.0
- On Ubuntu 22+:
apt update && apt install dotnet-sdk-8.0
- On Ubuntu 22+:
- Node.js v18+
The backend runs on port http://localhost:5128 by default in debug mode.
Configuration:
The backend reads configuration from environment variables and appsettings.json:
# LLM Provider API Keys
# Options: GOOGLE_API_KEY, OAI_API_KEY, OPENROUTER_API_KEY, ANTHROPIC_API_KEY, COHERE_API_KEY, GROQ_API_KEY, DEEPSEEK_API_KEY, MISTRAL_API_KEY, XAI_API_KEY, PERPLEXITY_API_KEY
export XXXXXX_API_KEY=... # or use dotnet user-secrets set, better
# Optional: Filter which models to display
export NOTT3CHAT_MODELS_FILTER=gpt-4o-mini,gemini-2.0-flash-001,gemini-2.0-flash-lite-001
# Optional: Model for chat title generation (default: gemini-2.0-flash-lite-001)
export NOTT3CHAT_TITLE_MODEL=gemini-2.0-flash-lite-001
# Optional: Google OAuth (requires Google Cloud Console setup)
dotnet user-secrets set "Authentication:Google:ClientId" "your-client-id"
dotnet user-secrets set "Authentication:Google:ClientSecret" "your-client-secret"Edit appsettings.json for additional settings:
{
"Authentication": {
"UseGoogle": false, // Enable Google OAuth login
"UseIdentity": true // Enable email/password login
},
"CustomProviders": [ // Add custom LLM providers
{
"Name": "MyProvider",
"BaseUrl": "https://api.example.com/v1",
"ApiKey": "your-key", // can also be specific "CustomProviders:0:ApiKey"
"Models": ["model-name-1", "model-name-2"]
}
],
"FrontEndUrl": "http://localhost:5173" // For OAuth redirects
}Debug Mode:
dotnet run --project backend/NotT3ChatBackend.csprojNote: The first time you run this, it will create a
databse.datSQLite file. When running in debug it will seed it with a default user:
- Username:
[email protected]- Password:
admin
Production Mode:
# Build for production
dotnet publish backend/NotT3ChatBackend.csproj -c Release -o publish
# Run the published app (example on port 5555)
dotnet publish/NotT3ChatBackend.dll --urls http://0.0.0.0:5555A few warnings:
- We use MemoryCache right now for synchronization, we will use Redis in the future but this means that it only works on a single server instance, no load balancer.
- Cors policy right now is any domain allowed, feel free to change it yourself.
- The password requirements are very minimal, feel free to change it yourself.
The frontend dev server will connect to the backend API.
# Navigate to the frontend directory
cd front-end
# Install dependencies
npm install
# Run the dev server
# Make sure this URL matches your backend's URL
VITE_API_URL=http://localhost:5128 npm run devFrontend Configuration:
Create a .env file in the front-end directory with these optional settings:
# Required: Backend API URL
VITE_API_URL=http://localhost:5128
# Optional: Custom branding
VITE_APP_TITLE=NotT3Chat
VITE_APP_SLOGAN=Your AI Chat Companion
VITE_CUSTOM_FONT_URL=https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap
VITE_CUSTOM_FONT_FAMILY=Inter
VITE_CUSTOM_ASSISTANT_ICON_URL=https://example.com/icon.png
VITE_CUSTOM_PROVIDER_FALLBACK_ICON_URL=https://example.com/provider-icon.png
# Optional: Authentication methods (defaults to true for identity, false for google)
VITE_USE_IDENTITY_AUTH=true
VITE_USE_GOOGLE_AUTH=false
# Optional: Terms of Service link
VITE_TERMS_OF_SERVICE_URL=https://example.com/termsHere's a non-exhaustive list of what's planned when I get around to it:
- Attachments (files, images)
- Better syntax highlighting for code blocks
- Even better syntax highlighting, with copy buttons
- Branching conversations
- Tools (like web search)
- Image generation
- Chat sharing via public links
- Bring Your Own Key (BYOK) for API providers
- Regenerate message (or regenerate with a different model)
- Delete chats
- Delete individual messages?
- Intelligent, automatic naming for new chats
- Search through threads
- Make it prettier?
- Thinking models
Some notes on the current state of the codebase for aspiring contributors.
The backend is currently in a single Program.cs file. This is an intentional experiment in anticipation of .NET 10's enhanced support for single-file applications (dotnet run app.cs). We are going to split it into a more traditional file structure for clarity soon. It's a WIP!
To maintain sanity without TypeScript, we follow a few simple styling rules:
- Component Styling: Use components from MUI whenever possible.
- Class Names: For multiple conditional class names on an element, use the
light-classnameslibrary. - No Inline Styles: All styling should be done via class names in dedicated
.cssfiles. No inlinestyleorsxprops. - No
!important: If you feel the need to use!important, take a break, have some water, and refactor.
- Graceful error handling (e.g., 429 Too Many Requests, content filter blocks). (More or less done, can always be improved)
- Streamline adding new models via environment variables instead of code changes.
- Add configuration to easily switch between db providers (In-Memory, SQLite, PostgreSQL, etc.).
- Consider segmenting larger UI components into smaller, more focused ones.
- Add an easy way to specify a default user account via environment variables for local development.
- Logging
- Add configuration to move to redis for distributed cache for better synchronization & locking for actively streaming chats.
- Fix general chat events to always stream (delete, title, new)
Contributions are what make the open-source community such an amazing place to learn, inspire, and create. All contributions are more than welcome! Feel free to fork the repo, create a feature branch, and open a pull request.
This project is licensed under the MIT License.

