Architecture Overview
Komand is built on .NET 10 and Microsoft Orleans 9 — a virtual actor framework that provides fault-tolerant, distributed state management with single-threaded execution guarantees per grain. This architecture was chosen over Node.js (used by open-source agent frameworks) because grains provide natural primitives for session isolation, state persistence, concurrent agent management, and fault tolerance.
System Diagram
Section titled “System Diagram”External Channels (Telegram, Slack, Discord, WhatsApp, Teams, WebChat, Signal, SMS) │ webhooks / WebSocket ▼┌─────────────────────────────────────────────────────┐│ ASP.NET Core Gateway (port 5000) ││ CorrelationId · ApiResponse<T> · Input Validation ││ CORS · SignalR Hub · Health Checks ││ /api/webchat /api/agents /api/sessions ││ /api/skills /health Swagger (dev only) ││ ← SPA serves React frontend from wwwroot → │└────────────────────────┬────────────────────────────┘ │ Orleans Client┌────────────────────────▼────────────────────────────┐│ Orleans Silo (ports 11111 / 30000) ││ AgentGrain SessionGrain SkillRegistryGrain ││ ToolGrain CronGrain ││ (all persist state to PostgreSQL) │└────────────────────────┬────────────────────────────┘ │ ADO.NET / Npgsql┌────────────────────────▼────────────────────────────┐│ PostgreSQL 17 ││ Orleans clustering · Grain storage · Reminders ││ Audit log │└─────────────────────────────────────────────────────┘ │ structured logs ▼ Seq (port 5341)Technology Choices
Section titled “Technology Choices”| Component | Technology | Rationale |
|---|---|---|
| Runtime | .NET 10 | Performance, strong typing, mature ecosystem |
| Actor framework | Microsoft Orleans 9.1 | Virtual actors, automatic state management, clustering |
| Database | PostgreSQL 17 | Reliable, open-source, rich extension ecosystem |
| API layer | ASP.NET Core | First-class Orleans integration, middleware pipeline |
| Frontend | React 19 + Vite 7 + TypeScript | Component model, ecosystem, developer productivity |
| State management | Zustand + TanStack Query | Lightweight client state, server state caching |
| Styling | TailwindCSS 4 | Utility-first, consistent design system |
| Real-time | SignalR | Bi-directional WebSocket communication |
| Observability | Serilog + Seq + OpenTelemetry | Structured logging, distributed tracing |
| Container runtime | Docker Compose | Simple local development, production-ready |
Project Structure
Section titled “Project Structure”The server repository is organized as a .NET solution with six backend projects and a React frontend:
komand-server/├── backend/│ ├── Komand.Shared/ # Domain models, DTOs, enums, configuration│ ├── Komand.Grains.Interfaces/ # Orleans grain contracts (interfaces only)│ ├── Komand.Grains/ # Grain implementations│ ├── Komand.Silo/ # Orleans silo host (console app)│ ├── Komand.Gateway/ # ASP.NET Core API + SPA host│ │ ├── Middleware/ # CorrelationId, CORS│ │ ├── Validation/ # Endpoint input validation│ │ └── Hubs/ # SignalR hubs│ └── Komand.Tests/ # xUnit + FluentAssertions + Orleans TestingHost├── frontend/│ └── src/│ ├── features/ # Page-level components│ ├── components/ # Reusable UI (AppShell, ChatInput, etc.)│ ├── api/ # API client (fetchApi wrapper)│ ├── stores/ # Zustand stores (auth, chat, UI)│ ├── hooks/ # Custom React hooks│ ├── lib/ # Utilities (SignalR, formatting)│ └── types/ # TypeScript interfaces└── docker/ ├── docker-compose.yml # Full stack definition ├── Dockerfile.silo # Orleans silo container ├── Dockerfile.gateway # Gateway + embedded frontend └── init-db/ # PostgreSQL schema initializationDependency Flow
Section titled “Dependency Flow”Komand.Shared (no dependencies — models, DTOs, config) ↑Komand.Grains.Interfaces (grain contracts only) ↑Komand.Grains (implementations + Orleans SDK) ↑Komand.Silo ←── Komand.Gateway (Orleans client)Komand.Shared has no Orleans dependency, making it safe to reference from any project. Grain interfaces are separated from implementations so the Gateway only needs the contracts, not the full Orleans server SDK.
API Response Envelope
Section titled “API Response Envelope”All API endpoints return a consistent ApiResponse<T> envelope:
{ "success": true, "data": { ... }, "error": null, "meta": { "total": 50, "page": 1, "pageSize": 20 }}Error responses follow the same shape:
{ "success": false, "data": null, "error": "Agent 'unknown' not found"}Input Validation
Section titled “Input Validation”The Gateway validates all input at the API boundary using EndpointValidation helpers:
ValidateRequired(value, paramName, maxLength)— rejects null, empty, or oversized stringsValidateOptional(value, paramName, maxLength)— allows null, validates if presentValidateRange(value, paramName, min, max)— numeric range checking- Route parameters have
maxlengthconstraints
All grain calls from the Gateway use .WaitAsync(TimeSpan.FromSeconds(30)). If a grain doesn’t respond, the API returns 504 Gateway Timeout.
CORS Configuration
Section titled “CORS Configuration”| Environment | Allowed Origins |
|---|---|
| Development | localhost only |
| Production | Configurable via Cors:AllowedOrigins in appsettings |
Allowed methods: GET, POST, PUT, DELETE, OPTIONS. Required headers: Content-Type, Authorization, X-Request-Id. Preflight cache: 10 minutes.
Observability
Section titled “Observability”Every request flows through CorrelationIdMiddleware that generates or propagates the X-Request-Id header into the Serilog LogContext. This enables end-to-end tracing from the API gateway through grain calls to the database.
Logging
Section titled “Logging”- Serilog with structured logging (template-based, not string interpolation)
- Seq for search and analysis (UI on port 5341, ingestion on 5342)
- Default level:
Information; Microsoft/Orleans/System overridden toWarning - OpenTelemetry for distributed tracing across silo boundaries in production
Audit Trail
Section titled “Audit Trail”Every significant action is recorded as an AuditLogEntry with a typed action enum:
| Action | When |
|---|---|
MessageReceived | Inbound message arrives |
MessageSent | Outbound response sent |
ToolExecutionStarted | Skill execution begins |
ToolExecutionCompleted | Skill execution succeeds |
ToolExecutionFailed | Skill execution fails |
SkillInstalled | Skill added to agent |
SkillUninstalled | Skill removed from agent |
AgentConfigured | Agent config changed |
SessionCreated | New session started |
SessionEnded | Session closed |
PromptInjectionDetected | Suspicious input flagged |
PermissionDenied | Insufficient permissions |
Each entry captures: actor ID, agent ID, session ID, skill ID, details, and timestamp.
Docker Deployment
Section titled “Docker Deployment”The Docker Compose stack runs four services:
| Service | Port | Resource Limits | Health Check |
|---|---|---|---|
| PostgreSQL 17 | 5432 | 512MB / 1 CPU | pg_isready |
| Seq | 5341 (UI), 5342 (ingest) | 256MB / 0.5 CPU | HTTP endpoint |
| Orleans Silo | 11111, 30000 | 1GB / 2 CPUs | TCP socket 11111 |
| API Gateway | 5000 | 512MB / 1 CPU | curl /health |
Services start in dependency order: PostgreSQL → Silo → Gateway. Each waits for its dependency’s health check before starting.
Container Security
Section titled “Container Security”- Non-root user (
komand) in all application containers - Resource limits (CPU and memory caps) on every service
- Secrets managed via
.envfile (gitignored) - Multi-stage Docker builds (SDK → runtime only)
- The Gateway Dockerfile builds the React frontend and embeds it in
wwwroot/
Environments
Section titled “Environments”| Mode | Clustering | Grain Storage | Reminders |
|---|---|---|---|
| Development | Localhost | In-memory | In-memory |
| Production | PostgreSQL ADO.NET | PostgreSQL ADO.NET | PostgreSQL ADO.NET |
The environment is controlled by DOTNET_ENVIRONMENT / ASPNETCORE_ENVIRONMENT. In development, no external services are required — everything runs in-process with in-memory state.
Key Environment Variables
Section titled “Key Environment Variables”| Variable | Purpose |
|---|---|
DOTNET_ENVIRONMENT | Development or Production |
ConnectionStrings__Orleans | PostgreSQL connection string |
SEQ_URL | Seq ingestion endpoint |
Cors__AllowedOrigins | Comma-separated allowed origins |
VITE_API_URL | Frontend API base URL |
Key Dependencies
Section titled “Key Dependencies”| Package | Version | Purpose |
|---|---|---|
| Microsoft.Orleans.Server | 9.1.2 | Silo hosting |
| Microsoft.Orleans.Client | 9.1.2 | Gateway → silo communication |
| Npgsql | 9.0.3 | PostgreSQL driver |
| Serilog | 9.0.0 | Structured logging |
| OpenTelemetry | 1.12.0 | Distributed tracing |
| xUnit | 2.9.3 | Test framework |
| FluentAssertions | 8.0.1 | Test assertions |