# How TUUI Manages Global State with Pinia Store Architecture

> Discover how TUUI manages global state with its Pinia store architecture. Learn how reactive, singleton stores orchestrate chat inference, tool execution, and UI state in their Electron-Vue app.

- Repository: [AIQL/tuui](https://github.com/ai-ql/tuui)
- Tags: architecture
- Published: 2026-02-23

---

**TUUI leverages Pinia enhanced with a state-persistence plugin to create a reactive, singleton-based store system where domain-specific stores communicate directly to orchestrate chat inference, MCP tool execution, and UI state across the Electron-Vue application.**

TUUI is an open-source Electron application that provides a chat interface for Large Language Models and Model-Context-Protocol (MCP) tools. According to the `ai-ql/tuui` source code, the application implements a modular Pinia architecture that serves as a single source of truth, enabling seamless data flow between the renderer process, background workers, and the main thread while automatically persisting critical state to `localStorage`.

## Pinia Initialization and State Persistence

The global state layer is bootstrapped in the renderer entry point at **[`src/renderer/main.ts`](https://github.com/ai-ql/tuui/blob/main/src/renderer/main.ts)**. Here, the application creates a single Pinia instance and enhances it with the `createStatePersistence` plugin to ensure stores survive page reloads and application restarts.

```typescript
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import { createStatePersistence } from 'pinia-plugin-state-persistence'
import App from '@/renderer/App.vue'

const app = createApp(App)
const pinia = createPinia()

pinia.use(createStatePersistence())  // Enables automatic localStorage persistence

app.use(pinia).mount('#app')

```

The persistence plugin automatically serializes each store's state to `localStorage` under unique keys, restoring data when the app launches. This mechanism requires no additional configuration beyond the plugin registration, making stores like `layoutStore` and `localeStore` instantly resilient to reloads.

## Domain-Specific Store Architecture

TUUI organizes its global state into logical domains under **`src/renderer/store/`**, with each store defined using Pinia's `defineStore` convention. This separation of concerns allows the `messageStore` to handle active chat sessions while delegating history management and tool execution to specialized stores.

### Message Store

The **[`src/renderer/store/message.ts`](https://github.com/ai-ql/tuui/blob/main/src/renderer/store/message.ts)** file defines the core chat logic through `useMessageStore`. This store maintains the active `conversation`, `userMessage` input, and `generating` flags, while exposing actions like `sendMessage()`, `startInference()`, and `processInference()` that orchestrate the full inference lifecycle.

### History Store

Located at **[`src/renderer/store/history.ts`](https://github.com/ai-ql/tuui/blob/main/src/renderer/store/history.ts)**, the `useHistoryStore` maintains a registry of all chat sessions. It provides CRUD helpers including `init()`, `find()`, `save()`, and `remove()` that the message store invokes to persist completed conversations or retrieve prior context for new sessions.

### MCP Store

The **[`src/renderer/store/mcp.ts`](https://github.com/ai-ql/tuui/blob/main/src/renderer/store/mcp.ts)** wraps the Model-Context-Protocol server APIs via `useMcpStore`. It dynamically merges MCP server definitions with user-defined STDIO configurations and exposes `listServerTools()`, `loadServerTools()`, and `callTool()` methods. When an LLM returns a tool call, the message store invokes `mcpStore.callTool()` to execute external functions and process results.

### UI State Stores

TUUI manages interface state through dedicated stores that follow the same architectural pattern:

- **[`snackbar.ts`](https://github.com/ai-ql/tuui/blob/main/snackbar.ts)** – Global notification system for info, warning, and error messages
- **[`layout.ts`](https://github.com/ai-ql/tuui/blob/main/layout.ts)** – Sidebar and panel visibility toggles that persist user preferences
- **[`locale.ts`](https://github.com/ai-ql/tuui/blob/main/locale.ts)** – Internationalization state and current language selection
- **[`counter.ts`](https://github.com/ai-ql/tuui/blob/main/counter.ts)** – Simple reactive demonstration store for component testing

## Cross-Store Communication Patterns

Because all stores register on the same Pinia instance, TUUI implements direct store-to-store communication without event buses or global emitters. Stores reference each other within actions to coordinate complex workflows.

```typescript
// Inside messageStore actions
const historyStore = useHistoryStore()
const mcpStore = useMcpStore()

// Persist conversation after generation
historyStore.save(this.conversation)

// Execute MCP tool when LLM requests it
const toolResult = await mcpStore.callTool(toolName, args)
this.postToolCall(toolResult)

```

This pattern ensures that history updates, tool executions, and UI notifications remain synchronized. For example, when `sendMessage()` triggers an inference that requires an MCP tool, the message store awaits `mcpStore.callTool()` and then updates the conversation state, with all changes propagating reactively to subscribed components.

## Consuming State in Vue Components

Components interact with global state by importing the composable store hooks and binding directly to reactive properties. The following pattern demonstrates how the message input