Beyond Simple Model State
When building KOS applications, you quickly encounter scenarios where models need access to shared data that doesn’t naturally belong to any single model. Configuration files loaded once at startup, external brand datasets that multiple components need, theme information that affects visual presentation, or user preferences that influence behavior across the entire application.
Traditional approaches like global variables, singleton services, or prop drilling create brittle architectures that become difficult to maintain as applications grow. KOS’s Model Context System provides a sophisticated solution that maintains clean architecture while enabling efficient data sharing across complex model hierarchies.
The context system creates a structured way for parent models to provide data to their children, ensuring that shared information flows naturally through your application’s model tree while preserving type safety and reactive capabilities.
Understanding KOS Context Architecture
The Context Container Pattern
At the heart of the context system lies the KosContext container—a type-safe, hierarchical data store that travels with models throughout their lifecycle. Unlike global state management solutions, context is scoped to specific model hierarchies, making it both powerful and contained.
Context data flows from parent models to their children automatically, creating a natural inheritance pattern where child models have access to all the context data their parents established, plus any additional context they create themselves.
import { KosContext, IKosDataModel, kosModel } from "@kosdev-code/kos-ui-sdk";
@kosModel({ modelTypeId: "example-model", singleton: false })
export class ExampleModelImpl implements IKosDataModel {
private sharedData?: any;
async load(context: KosContext): Promise<void> {
// Access shared data provided by parent models
this.sharedData = context.get("shared-config");
this.logger.debug("Loaded context data");
}
}Loader Infrastructure
The context system’s foundation relies on loader functions that run before models begin their lifecycle. These loaders fetch external data, process configuration files, and prepare shared resources that multiple models will need.
Loaders operate at a higher level than individual models, ensuring that external dependencies are resolved before any model attempts to use them. This creates predictable initialization ordering and eliminates race conditions between models trying to access shared resources.
Context loaders are functions that prepare shared data before model initialization begins. They typically fetch external configuration, process static resources, or establish connections to external systems that multiple models will need to access.
Context Propagation Flow
Context propagation follows a clear, predictable pattern that mirrors the natural parent-child relationships in your model hierarchy:
- Root Context Creation: Top-level loaders create initial context data
- Parent Model Loading: Parent models access and potentially augment context
- Child Model Creation: Child models inherit parent context automatically
- Context Augmentation: Child models can add their own context data
- Nested Propagation: The enhanced context flows to grandchildren and beyond
This creates a natural data flow where information becomes more specific as it moves down the hierarchy, while maintaining access to all parent-provided data.
Context Integration Patterns
Context Loader Concepts
Context loaders execute during application initialization to prepare shared resources that multiple models will need. They return key-value data that becomes available to models through the context system during model lifecycle phases.
Context Registration
Context loaders are registered during application initialization using the extension system. The loaders are associated with specific model types and execute before those models begin their lifecycle.
Context loaders are registered using ext.core.registerModelLoader() with a specific model type and loader function. The loader results are added to the model context automatically before the model’s lifecycle begins.
Parent Model Context Augmentation
Parent models can access context data during their lifecycle and add additional context for their children. This creates layered context where information becomes progressively more specific down the hierarchy.
Parent models can access context data using context.get() and add their own data using context.set(). This allows parent models to provide domain-specific context to their children while accessing shared resources from their own parents.
Context Access Patterns
Safe Context Access
Context access should always be defensive, providing fallback behavior when expected data isn’t available. Models should check for context data existence and provide appropriate defaults when shared resources are unavailable.
Type-Safe Context Operations
The context system provides full TypeScript support through generic type parameters on context.get<T>() calls. This enables compile-time verification of context data types and prevents runtime errors from type mismatches.
Cross-Cutting Concerns Integration
External Data Integration
The context system excels at integrating external data sources that don’t fit naturally into any single model but are needed across multiple components. Context loaders can fetch data from external APIs, process configuration files, or establish connections that multiple models will share.
Configuration Management
Context provides an elegant solution for application configuration that needs to be accessible throughout the model hierarchy without creating tight coupling. Configuration loaders can merge data from multiple sources and provide centralized access to application settings.
Advanced Context Patterns
Hierarchical Context Augmentation
Complex applications often need context data that becomes progressively more specific as it moves down the model hierarchy. Parent models can augment context with domain-specific data while preserving access to shared resources from higher levels.
Context-Driven Model Behavior
Models can adapt their behavior based on context data, creating applications that respond intelligently to different deployment environments, user preferences, and device capabilities. This enables dynamic behavior customization without requiring explicit configuration in each model.
Context Cleanup and Memory Management
The context system automatically manages memory and cleanup as models are created and destroyed. Context data is automatically cleaned up when model hierarchies are torn down, preventing memory leaks in long-running applications.
Best Practices and Patterns
Context Design Principles
When designing context data structures, follow these principles to create maintainable and efficient shared data systems:
Keep Context Data Immutable: Once loaded, context data should not change. This prevents unexpected side effects and makes applications more predictable.
Use Descriptive Keys: Context keys should clearly describe the data they contain. Avoid abbreviations or cryptic names that make code harder to understand.
Provide Fallback Strategies: Always handle missing context gracefully. Applications should degrade elegantly when expected context data isn’t available.
Minimize Context Size: Only include data that multiple models actually need. Avoid putting model-specific data into shared context.
Performance Considerations
Context data is shared across multiple models, so loading expensive resources efficiently becomes important for application startup performance. Context loaders should use parallel loading patterns and efficient data processing to minimize initialization time.
Error Resilience
Context loaders should be resilient to external service failures and provide sensible defaults when resources aren’t available. Individual resource loading should be wrapped in error handling that allows other resources to load successfully even when some fail.
The Context Advantage
The Model Context System transforms how KOS applications handle shared data and cross-cutting concerns. Instead of relying on global state, prop drilling, or tightly coupled dependencies, context provides a structured, type-safe, and hierarchical approach to data sharing.
Applications become more maintainable because shared concerns are clearly separated from model-specific logic. They become more flexible because models can adapt their behavior based on context without needing explicit configuration. They become more reliable because context provides fallback mechanisms and graceful degradation when resources aren’t available.
Most importantly, context preserves the clean architecture principles that make KOS applications scalable. Models remain focused on their specific responsibilities while gaining access to the shared resources they need to function effectively. This creates applications that are both powerful and maintainable as they grow in complexity.
The context system bridges the gap between individual model concerns and application-wide requirements, providing the foundation for building sophisticated device control applications that respond intelligently to their environment while maintaining clean, testable code architecture.
Ready to explore specific implementations? Continue with Container Models to understand how to build collections that leverage context data, or dive into Device Communication Patterns to see how context enhances backend integration.
