Skip to content

Askimo Desktop Architecture Guide

The Askimo Desktop application is a native desktop client built with Jetpack Compose for Desktop. It provides a rich, responsive user interface for interacting with AI assistants across multiple providers.

  • UI Framework: Jetpack Compose for Desktop
  • Language: Kotlin
  • Architecture Pattern: MVVM (Model-View-ViewModel)
  • Dependency Injection: Koin
  • Concurrency: Kotlin Coroutines
  • Persistence: Shared with CLI module (SQLite via Exposed)

The desktop application follows a layered architecture with clear separation of concerns:

graph TD
    A[UI Layer
Jetpack Compose Views & Components] B[ViewModel Layer
State Management & UI Logic] C[Service Layer
Business Logic & Coordination] D[Core Layer
Shared Module: Providers, Session, Repository] A --> B B --> C C --> D style A fill:#e1f5ff,stroke:#0288d1,stroke-width:2px style B fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px style C fill:#fff3e0,stroke:#ef6c00,stroke-width:2px style D fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
  1. Separation of Concerns: Each layer has a specific responsibility
  2. Unidirectional Data Flow: Data flows down, events flow up
  3. Reactive Programming: UI automatically updates when state changes
  4. Single Source of Truth: State is owned by ViewModels
  5. Dependency Injection: Loose coupling between components

The desktop module is organized into the following key packages:

desktop/
├── Main.kt # Application entry point
├── viewmodel/ # ViewModels (UI state management)
├── service/ # Business logic services
├── ui/ # UI components
│ ├── views/ # Main application views
│ ├── components/ # Reusable UI components
│ └── theme/ # Theming and styling
├── model/ # UI data models
├── di/ # Dependency injection configuration
├── i18n/ # Internationalization
├── keymap/ # Keyboard shortcuts
└── util/ # Utility classes
PackagePurpose
viewmodel/Manages UI state and handles user actions
service/Contains business logic and coordinates operations
ui/views/Main application screens (Chat, Sessions, Settings)
ui/components/Reusable UI elements (dialogs, message bubbles, etc.)
ui/theme/Color schemes, typography, and theme management
model/Data classes for UI representation
di/Koin dependency injection modules
i18n/Multi-language support
keymap/Keyboard shortcut management
util/Helper functions and utilities

The presentation layer built with Compose for Desktop. Responsible for rendering the user interface and capturing user interactions.

Main Views:

  • ChatView: Primary chat interface
  • SessionsView: Session list and management
  • SettingsView: Application configuration
  • AboutView: Application information

Reusable Components:

  • Message bubbles with markdown and code highlighting
  • File attachment handling
  • Dialogs and modals
  • Tooltips and dropdowns
  • Theme-aware styling

Manages UI state and handles user actions. Acts as the bridge between UI and business logic.

ViewModels:

  • ChatViewModel: Chat state, messages, streaming responses
  • SessionsViewModel: Session list, operations (star, delete, rename)
  • SettingsViewModel: Configuration and preferences

Responsibilities:

  • Maintain UI state
  • Handle user actions
  • Coordinate with services
  • Manage lifecycle and cleanup

Contains business logic and coordinates operations between ViewModels and the Core layer.

Key Services:

  • ChatService: Chat operations and session management
  • StreamingService: AI response streaming coordination
  • ThemePreferences: User preference persistence

Responsibilities:

  • Encapsulate business rules
  • Provide clean APIs to ViewModels
  • Handle concurrent operations
  • Manage resource lifecycle

Shared functionality used by both CLI and Desktop applications. Provides core AI chat capabilities.

Components:

  • Session: Chat session management
  • Providers: AI provider integrations (OpenAI, Anthropic, etc.)
  • Repository: Data persistence layer
  • Models: Domain models

Dependency Injection (Koin):

  • Manages component lifecycle
  • Provides loose coupling
  • Supports testability

Internationalization:

  • Multi-language support (English, Japanese, Vietnamese)
  • Localized UI strings
  • Parameter substitution

Platform Utilities:

  • OS detection (macOS, Windows, Linux)
  • Keyboard shortcut management
  • Platform-specific behaviors

The application follows a unidirectional data flow pattern:

graph TD
    A[User Input] --> B[ViewModel]
    B --> C[Service]
    C --> D[Core]
    B -->|State Update| E[UI Update]

    style A fill:#e1f5ff,stroke:#0288d1,stroke-width:2px
    style B fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
    style C fill:#fff3e0,stroke:#ef6c00,stroke-width:2px
    style D fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
    style E fill:#fce4ec,stroke:#c2185b,stroke-width:2px

Sending a Message:

  1. User types message in ChatView
  2. ChatViewModel processes the input
  3. ChatService coordinates with Core layer
  4. AI provider streams the response
  5. ViewModel updates state reactively
  6. UI automatically recomposes to show response

Loading a Session:

  1. User selects session from list
  2. ViewModel requests session data
  3. Repository loads from database
  4. ViewModel updates message list
  5. UI renders the chat history

The application uses the MVVM pattern to separate concerns:

  • View (UI): Jetpack Compose components that display data
  • ViewModel: Manages UI state and handles user actions
  • Model: Data layer (repositories, services, domain models)

State changes automatically trigger UI updates:

  • ViewModels expose state using Compose’s mutableStateOf
  • UI observes state changes and recomposes automatically
  • Kotlin Flows handle streaming data

Koin provides loose coupling between components:

  • Dependencies are injected via constructors
  • Lifecycle management is handled automatically
  • Easy to swap implementations for testing

Data access is abstracted through repositories:

  • ViewModels don’t directly access the database
  • Repositories provide a clean API for data operations
  • Easy to add caching or remote data sources

The desktop application runs on multiple platforms with platform-specific adaptations:

  • macOS: Full native integration with system menu and keyboard shortcuts
  • Windows: Native look and feel with Windows-specific shortcuts
  • Linux: Cross-desktop environment support

OS Detection:

  • Centralized detection of the current operating system
  • Platform-specific keyboard shortcuts (Command vs. Ctrl)
  • Adaptive UI elements based on platform conventions

Keyboard Shortcuts:

  • Platform-aware shortcut management
  • Consistent shortcuts across platforms where possible
  • Platform-specific shortcuts where appropriate (e.g., ⌘+Q vs. Alt+F4)
  • Separation of Concerns: Keep UI, business logic, and data layers separate
  • Single Responsibility: Each class should have one clear purpose
  • Dependency Injection: Use Koin for managing dependencies
  • Reactive State: Leverage Kotlin Flows and Compose state management
  • ViewModels own and manage UI state
  • State is immutable and exposed as read-only properties
  • UI reacts automatically to state changes
  • State is scoped to ViewModel lifecycle
  • Use Kotlin Coroutines for all async operations
  • Scope coroutines to ViewModel lifecycle
  • Handle cancellation gracefully
  • Use appropriate dispatchers (IO, Default, Main)
  • Keep Composables small and focused
  • Extract reusable components
  • Use theming system for consistent styling
  • Never put business logic in Composables

When contributing to the desktop module, please:

  1. Follow the MVVM architecture pattern
  2. Keep layers properly separated
  3. Write tests for new features
  4. Update documentation as needed
  5. Follow Kotlin coding conventions