Welcome to KOS!
KOS is a model-first, event-driven framework designed specifically for building reactive applications that connect to physical devices. Unlike traditional web frameworks that focus on UI components and state management, KOS takes a fundamentally different approach: the model is the application.
This paradigm shift creates applications that are naturally reactive, maintainable, and perfectly suited for device control scenarios where real-world state changes must be reflected instantly in the user interface.
Essential Learning Path
To master KOS development, follow this structured learning approach. Start with understanding the KOS architecture and why model-first design matters for device applications. Then dive into device communication patterns to learn the six ways applications communicate with backend devices. From there, grasp the core concepts that guide KOS development, learn to build your first reactive models, master topic-based communication, and finally connect models to user interfaces through React integration.
This progression builds understanding layer by layer, ensuring you have the conceptual foundation before diving into implementation details.
The Model-First Philosophy
Why Models Matter
In traditional web applications, you manage state in components, stores, or contexts. In KOS, models are your application. This isn’t just a different way of organizing code—it’s a fundamental shift in how you think about application architecture.
Models represent reality. When you’re building an application that controls a coffee machine, the model represents the actual coffee machine, not just data about it. When the physical machine’s temperature changes, the model’s temperature changes. When a user adjusts settings in the UI, the model sends commands to the physical device.
This direct mapping between model and reality eliminates the complexity of keeping UI state synchronized with device state—they’re the same thing. No more worrying about stale data or manual refresh cycles. The model reflects the current state of the physical world, and your UI reflects the model.
The Event-Driven Advantage
KOS models communicate through topics—named channels for events. Instead of models calling methods on each other, they publish events about what happened and subscribe to events they care about.
This creates a loosely coupled architecture where models can evolve independently, new features can be added without modifying existing code, the system naturally scales as complexity grows, and debugging is easier because you can trace event flows.
// Models publish and subscribe to events
@kosTopicHandler({ topic: "dispense:completed" })
handleDispenseCompleted(event: DispenseEvent) {
// Inventory model reacts to dispense events automatically
this.updateStock(event.beverage, event.amount);
}Understanding Device Communication
KOS applications connect to backend devices through six distinct communication patterns. Understanding these patterns is crucial because choosing the right pattern for each use case dramatically affects performance, reliability, and maintainability.
These patterns are:
- Endpoints – For loading initial data and performing operations
- Topics – For real-time updates and events
- Configuration Properties – For operational parameters and settings
- Futures – For long-running operations with progress tracking
- Troubles – For device issue management and health monitoring
- State Beans – For read-only device state monitoring
Each pattern serves specific needs. You wouldn’t use endpoints to monitor real-time sensor readings, just as you wouldn’t use topics to load initial application data. The key is understanding when and why to use each pattern.
Configuration Properties: The KOS Way
One of KOS’s most powerful features is reactive configuration. Instead of manually fetching configuration values, you declare what you need and KOS keeps it synchronized automatically.
@kosConfigProperty({
path: "assembly:core:board:kondra.dispenser.board",
attribute: "displaySimulation"
})
private displaySimulationConfig!: KosConfigProperty<boolean>;
get displaySimulation(): boolean {
return this.displaySimulationConfig.value ?? false;
}This approach eliminates entire categories of bugs related to stale configuration data and manual synchronization. The configuration value is always current, automatically updated when changes occur on the device, and available with full type safety.
Creating Your First Model
The Basic Structure
Every KOS model starts with the same foundation: the @kosModel decorator with a model type string and implements the IKosDataModel interface. This tells KOS this class is a model, enabling all the reactive features.
@kosModel({ modelTypeId: "sensor-model", singleton: false })
export class SensorModelImpl implements IKosDataModel {
// Your model represents something real in the physical world
name: string = "";
isActive: boolean = false;
currentReading?: number;
// Business logic methods
checkStatus(): void {
this.isActive = this.currentReading !== undefined && this.currentReading > 0;
}
}The key insight is that your model should represent something concrete—a sensor, a pump, a dispensing session. Not abstract concepts like “data manager” or “service layer.” When models map directly to real-world concepts, the code becomes intuitive and the architecture naturally makes sense.
Adding Device Integration
KOS models come alive when they connect to the physical world. This happens through decorators that declare your intentions rather than requiring you to write integration code.
@kosModel({ modelTypeId: "pump-model", singleton: false })
export class PumpModelImpl implements IKosDataModel {
// Configuration that affects how the pump operates
@kosConfigProperty({
path: "assembly:core:board:micro:pump:S4",
attribute: "flowRate"
})
private flowRateConfig!: KosConfigProperty<number>;
// Real-time events from the physical pump
@kosTopicHandler({ topic: "pump:status:changed", websocket: true })
handleStatusChange(event: PumpStatusEvent): void {
this.currentStatus = event.status;
this.lastUpdate = new Date();
}
get flowRate(): number {
return this.flowRateConfig.value ?? 1.0;
}
}Notice how the model doesn’t manually fetch data or manage WebSocket connections. The decorators handle all the complexity, leaving you to focus on business logic. This declarative approach makes models easier to understand and maintain.
Event Handling and Communication
Topic-Based Architecture
In KOS, models don’t know about each other directly. Instead, they participate in a topic-based communication system. This might seem more complex at first, but it creates applications that are much easier to modify and extend.
Consider a dispensing operation: when a beverage finishes dispensing, multiple parts of the system need to respond. Inventory must update, the UI must refresh, maintenance schedules might need adjustment, and usage analytics should record the event.
With direct method calls, the dispensing model would need to know about all these other systems. With topics, it simply announces what happened, and any model that cares about dispense completions can subscribe. The dispense model doesn’t need to change when new subscribers are added.
This decoupling makes systems more resilient and easier to extend over time.
Functional Event Patterns
KOS supports advanced event handling patterns like debouncing, throttling, and batching—all through decorator configuration. These patterns help you handle real-world device characteristics like noisy sensors or rapid-fire updates without writing complex manual logic.
// Handle rapid sensor updates efficiently
@kosTopicHandler({
topic: "sensor:temperature:reading",
functionalPattern: {
type: "debounce",
wait: 100 // Only process updates every 100ms
}
})
handleTemperatureReading(event: TemperatureEvent): void {
this.currentTemperature = event.temperature;
}Creating Models with the CLI
When working in a KOS workspace, the kosui CLI can generate models with proper patterns and conventions:
# Create a basic model
kosui model --name sensor --project device-models
# Create with container support (recommended for collections)
kosui model --name ingredient --project app-models --container
# Create singleton model (only one instance allowed)
kosui model --name system-config --project core --singletonThe CLI generates all the necessary files including the model implementation, registration classes, and TypeScript type definitions, following KOS best practices automatically.
Integrating with React
The useKosModel Hook
React integration in KOS is designed to be effortless and automatic. The useKosModel hook connects React components to KOS models, and React automatically re-renders when model state changes.
function SensorPanel({ sensorId }: { sensorId: string }) {
const sensor = useKosModel(SensorModel, { sensorId });
return (
<div className="sensor-panel">
<h3>{sensor.name}</h3>
<div className={`status ${sensor.isActive ? 'active' : 'inactive'}`}>
{sensor.isActive ? 'Active' : 'Inactive'}
</div>
<div className="reading">
Current: {sensor.currentReading ?? 'No Reading'}
</div>
</div>
);
}The component doesn’t manage any state—it simply reflects the model’s current state and calls model methods in response to user actions. This creates UIs that are naturally consistent and always up-to-date.
Best Practices and Mental Models
Think in Models, Not Components
The biggest mental shift in KOS development is starting with the model, not the UI. Before building any interface, ask yourself what real-world thing this represents, what state it needs to track, what events it might publish or subscribe to, and how it connects to the physical device.
This approach naturally leads to better architecture because models that represent real things tend to have clear responsibilities and boundaries.
Embrace Reactive Patterns
KOS is designed to be reactive by default. Instead of manually updating state in response to events, you declare relationships and let the framework handle updates.
// Declare relationships and let KOS handle updates
@kosModelEffect({
dependencies: (model) => [model.inventory.totalItems]
})
handleInventoryChange(): void {
// This runs automatically when inventory changes
this.updateAvailability();
}This reactive approach reduces bugs and makes applications more predictable.
Error Handling Philosophy
KOS uses error-first tuples throughout the framework. This pattern makes error handling explicit and prevents errors from being ignored.
const [error, beverages] = await this.getBeverages();
if (error) {
this.logger.error("Failed to load beverages", error);
return; // Handle the error appropriately
}
// Only process success case after error check
this.beverages = beverages;This approach ensures that errors are always considered and handled appropriately, leading to more robust applications.
Development Environment and Tools
The KOS Ecosystem
KOS development is supported by a rich ecosystem of tools designed to make device application development efficient. KOS Studio provides visual device management and real-time monitoring. CLI tools generate model boilerplate and analyze device services. TypeScript integration offers full type safety and excellent developer experience. React hooks make UI integration seamless and automatic.
Debugging and Monitoring
Because KOS applications are model-centric, debugging focuses on model state and event flows. The framework provides built-in logging and monitoring that makes it easy to understand what’s happening in your application. Model state changes are automatically logged, event publications and subscriptions are tracked, configuration changes are audited, and device communication is monitored.
Common Challenges and Solutions
When Models Aren’t Updating
This usually means an event subscription isn’t configured correctly. Check that topic names match exactly between publisher and subscriber, WebSocket events use websocket: true in the handler decorator, and configuration paths point to existing device configuration.
Choosing Communication Patterns
When you’re unsure which communication pattern to use, refer back to the six patterns and their specific purposes. Use endpoints for initial data loading and operations, topics for real-time updates and events, config properties for operational parameters, futures for long-running operations, troubles for device issue management, and state beans for read-only device monitoring.
Managing Application Complexity
If your application feels too complex, it often indicates models are trying to do too much. KOS works best when models have single, clear responsibilities that map to real-world concepts. Consider breaking large models into smaller, focused ones that communicate through events.
Your Next Steps
Now that you understand the fundamentals, your next steps depend on what you’re building.
For device control applications, study device communication patterns in depth, learn about trouble management and device health monitoring, and explore futures for long-running operations like calibration.
For user interface development, master React integration patterns, learn about model relationships and hierarchies, and understand configuration management for user preferences.
For complex business logic, explore model effects for reactive business logic, study event-driven patterns for system coordination, and learn about model containers for managing collections.
The KOS Advantage
KOS represents a fundamental shift in how we think about device applications. By putting models first and embracing event-driven communication, KOS applications are more reliable because they directly reflect physical reality, easier to maintain because components are loosely coupled, naturally reactive because changes propagate automatically, and scalable because the architecture supports growth without rewrites.
The framework handles the complexity of device communication, state synchronization, and reactive updates, allowing you to focus on building great user experiences that connect people to the physical world.
Welcome to model-first development. Welcome to KOS!
Ready to dive deeper? Continue with our Architecture Guide to understand the philosophy behind KOS, or jump into Device Communication Patterns to master backend integration.
