# The Role of AppRuntime in BitChat V2 Architecture: Centralized Composition Root

> Discover how AppRuntime acts as the central composition root in BitChat V2, managing startup, lifecycle, notifications, and DI for the decentralized app.

- Repository: [permissionlesstech/bitchat](https://github.com/permissionlesstech/bitchat)
- Tags: architecture
- Published: 2026-08-23

---

**AppRuntime serves as the central composition root in BitChat's V2 architecture, replacing monolithic view models by orchestrating startup sequencing, lifecycle management, notification routing, and dependency injection for the decentralized messaging app.**

The V2 redesign of the `permissionlesstech/bitchat` repository restructures the iOS client's architecture to improve separation of concerns and testability. At the heart of this refactor lies `AppRuntime`, a dedicated coordinator that abstracts app-wide orchestration from the SwiftUI view layer, allowing UI components to consume only the feature-specific models they require.

## Core Responsibilities of AppRuntime

### Owning Core Feature Models

In [`bitchat/App/AppRuntime.swift`](https://github.com/permissionlesstech/bitchat/blob/main/bitchat/App/AppRuntime.swift) (lines 14-31), the runtime initializes and retains the application's single source of truth. It creates and owns **ConversationStore**, along with feature-scoped models including `PublicChatModel`, `PrivateInboxModel`, `LocationChannelsModel`, `PeerListModel`, `VerificationModel`, and `AppChromeModel`.

This ownership pattern ensures that state persists throughout the app lifecycle and that all feature models reference the same underlying data sources rather than maintaining independent caches.

### Coordinating Application Lifecycle

The **`start()`** method, implemented in [`AppRuntime.swift`](https://github.com/permissionlesstech/bitchat/blob/main/AppRuntime.swift) (lines 29-40), wires up critical services during app initialization. This method activates Tor networking, enables network services, broadcasts geohash presence, announces initial Tor status, and records launch events.

By centralizing startup logic, `AppRuntime` guarantees deterministic sequencing—services initialize in the correct order before any UI component attempts to access them.

### Routing System Notifications

Lines 75-88 in [`AppRuntime.swift`](https://github.com/permissionlesstech/bitchat/blob/main/AppRuntime.swift) implement the notification delegate protocol. The runtime receives system events such as URL opens and app-active transitions, forwarding them to appropriate models.

When a user opens BitChat via a shared link, **`handleOpenURL(url)`** checks for shared content and records the event, ensuring the `ChatViewModel` reacts to external intents without direct coupling to the `AppDelegate`.

### Enforcing Single-Writer Data Access

According to [`ConversationStore.swift`](https://github.com/permissionlesstech/bitchat/blob/main/ConversationStore.swift) (lines 28-33), `AppRuntime` owns the sole instance of conversation state. All feature models read and mutate message data through this unified intent API, preventing race conditions and ensuring data consistency across the decentralized messaging layer.

This single-writer pattern guarantees that `ConversationStore` remains the authoritative source for message history, verification states, and peer lists.

### Dependency Injection Hub

Lines 43-50 in [`AppRuntime.swift`](https://github.com/permissionlesstech/bitchat/blob/main/AppRuntime.swift) demonstrate the runtime supplying `ChatViewModel` with required services including the keychain, identity bridge, and location manager. It also passes itself to the notification delegate, allowing low-level events to be handled centrally rather than scattered across view controllers.

## Architectural Impact of the Composition Root Pattern

This composition root pattern eliminates the monolithic `ChatViewModel` anti-pattern present in earlier versions. UI components such as `ContentView` and `MessageListView` now consume only feature-specific models they require, rather than reaching into a centralized view model.

As documented in [`docs/ARCHITECTURE_V2.md`](https://github.com/permissionlesstech/bitchat/blob/main/docs/ARCHITECTURE_V2.md) (lines 7-18), this separation improves **performance**, **reliability**, and **maintainability** while preparing the codebase for further modularization. The abstraction allows developers to modify service implementations (such as swapping Tor providers) without refactoring SwiftUI views.

## Implementing AppRuntime in Practice

Instantiate the runtime once in the app entry point:

```swift
// Creating the runtime – done in BitchatApp.swift
@StateObject private var runtime = AppRuntime()

```

Access feature models from SwiftUI views:

```swift
struct MessageListView: View {
    @ObservedObject var conversationUI: ConversationUIModel = runtime.conversationUIModel
    // Now the view can read/write messages via the store owned by AppRuntime
}

```

Trigger the startup sequence:

```swift
// Starting the runtime (called once from BitchatApp)
runtime.start()   // Triggers service wiring, Tor status, and media maintenance

```

Handle incoming shared content:

```swift
// Handling an incoming “share” URL
runtime.handleOpenURL(url)   // Checks for shared content and records the event

```

Update conversation state through the single-writer API:

```swift
// Updating the conversation store via the intent API
runtime.conversations.append(message, to: conversationID)   // Single‑writer path

```

## Summary

- **AppRuntime** replaces `BitchatApp` and `ChatViewModel` as the central coordinator in V2 architecture.
- It owns all core models including `ConversationStore`, `PublicChatModel`, and `PrivateInboxModel` via composition.
- The **`start()`** method manages deterministic initialization of Tor, networking, and geohash services.
- **`handleOpenURL()`** and related methods centralize notification routing and shared-content intake.
- By enforcing single-writer access to `ConversationStore`, it prevents data races and ensures consistency across the decentralized app.
- It injects dependencies into `ChatViewModel` and other consumers, decoupling UI from service implementations.

## Frequently Asked Questions

### How does AppRuntime differ from the previous BitchatApp and ChatViewModel pattern?

In the previous architecture, `BitchatApp` and `ChatViewModel` directly owned operational logic, creating tight coupling between UI and business logic. `AppRuntime` extracts these concerns into a dedicated composition root, allowing view models to focus on presentation while the runtime handles service coordination and state ownership.

### Why does AppRuntime exclusively own ConversationStore?

Centralizing conversation state within `AppRuntime` (as seen in [`ConversationStore.swift`](https://github.com/permissionlesstech/bitchat/blob/main/ConversationStore.swift) lines 28-33) enforces a single-writer pattern. This prevents race conditions and ensures all feature models mutate message data through a unified intent API rather than holding independent copies of state that could diverge during peer-to-peer synchronization.

### What triggers the AppRuntime lifecycle methods?

The **`start()`** method is invoked once from [`BitchatApp.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BitchatApp.swift) during application launch, initiating Tor services, network activation, and geohash presence. Subsequent lifecycle events such as app backgrounding or URL opens trigger **`handleOpenURL()`** and related routing methods defined in [`AppRuntime.swift`](https://github.com/permissionlesstech/bitchat/blob/main/AppRuntime.swift) (lines 75-88).

### Can AppRuntime be instantiated multiple times?

No. Like a composition root, `AppRuntime` is designed as a singleton-owned `@StateObject` within the SwiftUI hierarchy (instantiated in [`BitchatApp.swift`](https://github.com/permissionlesstech/bitchat/blob/main/BitchatApp.swift)). Creating multiple instances would violate the single-writer constraint and duplicate service connections such as Tor and location management, leading to resource exhaustion and inconsistent state.