# How the Qwen Code Conversation Store Persists State Across Terminal Restarts

> Learn how Qwen Code preserves conversation state across terminal restarts using VS Code globalState and WebviewPanelSerializer for seamless continuity.

- Repository: [Qwen/qwen-code](https://github.com/qwenlm/qwen-code)
- Tags: internals
- Published: 2026-02-19

---

**The Qwen Code extension uses a dual-layer persistence strategy: the full conversation history is stored in VS Code's `globalState` key-value store, while the active conversation pointer and UI state are preserved through the `WebviewPanelSerializer` API.**

The QwenLM/qwen-code repository implements a robust conversation management system that ensures your chat history survives IDE restarts, window reloads, and accidental panel closures. Understanding how the conversation store persists state across terminal restarts is essential for developers extending the extension or troubleshooting state synchronization issues.

## Global-State Persistence for Conversation Storage

The primary mechanism for long-term conversation storage relies on VS Code's `ExtensionContext.globalState`, a persistent key-value store that survives across workspace and IDE sessions.

In [`packages/vscode-ide-companion/src/services/conversationStore.ts`](https://github.com/QwenLM/qwen-code/blob/main/packages/vscode-ide-companion/src/services/conversationStore.ts), the `ConversationStore` class manages the conversation array. When a user creates a new chat, the `createConversation()` method generates a unique conversation object, appends it to the existing array, and persists the entire collection:

```typescript
// packages/vscode-ide-companion/src/services/conversationStore.ts
export async createConversation(title = 'New Chat'): Promise<Conversation> {
  const conversation: Conversation = {
    id: `conv_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
    title,
    messages: [],
    createdAt: Date.now(),
    updatedAt: Date.now(),
  };

  // Load existing list, add the new one, then persist
  const conversations = await this.getAllConversations();
  conversations.push(conversation);
  await this.context.globalState.update('conversations', conversations);

  // Remember the active conversation in-memory
  this.currentConversationId = conversation.id;
  return conversation;
}

```

On startup, `getAllConversations()` retrieves the array from `globalState`, ensuring the full conversation history is immediately available regardless of how long ago the IDE was closed.

## Web-View Panel Serialization for UI State

While `globalState` preserves the conversation data, the active conversation pointer and UI configuration require a different approach. VS Code's `WebviewPanelSerializer` API handles state preservation when the webview panel is destroyed during window reloads or extension updates.

### Capturing State Before Shutdown

In [`packages/vscode-ide-companion/src/webview/WebViewProvider.ts`](https://github.com/QwenLM/qwen-code/blob/main/packages/vscode-ide-companion/src/webview/WebViewProvider.ts), the `getState()` method captures the current context before the panel closes:

```typescript
// packages/vscode-ide-companion/src/webview/WebViewProvider.ts
/** Called by VS Code when the panel is being serialized */
getState() {
  return {
    conversationId: this.messageHandler.getCurrentConversationId(),
    agentInitialized: this.agentInitialized,
  };
}

```

This returns an object containing the active conversation ID and agent connection status, which VS Code stores internally until the next session.

### Restoring State After Restart

When the IDE restarts, the serializer reconstructs the panel and invokes `restoreState()`:

```typescript
// packages/vscode-ide-companion/src/webview/WebViewProvider.ts
/** Called by VS Code when the panel is recreated */
restoreState(state) {
  this.messageHandler.setCurrentConversationId(state.conversationId);
  this.agentInitialized = state.agentInitialized;
  this.authState = null;               // force a fresh auth check
  const panel = this.panelManager.getPanel();
  if (panel) {
    panel.webview.html = WebViewContent.generate(panel, this.extensionUri);
  }
}

```

The extension registration occurs in [`packages/vscode-ide-companion/src/extension.ts`](https://github.com/QwenLM/qwen-code/blob/main/packages/vscode-ide-companion/src/extension.ts):

```typescript
// packages/vscode-ide-companion/src/extension.ts
context.subscriptions.push(
  vscode.window.registerWebviewPanelSerializer('qwenCode.chat', {
    async deserializeWebviewPanel(webviewPanel, state) {
      const provider = createWebViewProvider();   // new WebViewProvider instance
      await provider.restorePanel(webviewPanel);   // re‑attach listeners
      if (state) {
        provider.restoreState(state as {
          conversationId: string | null;
          agentInitialized: boolean;
        });
      }
    },
  })
);

```

## How the Two Systems Work Together

The conversation store persists state across terminal restarts through a layered architecture:

- **Data Layer**: `globalState` stores the complete conversation array (titles, messages, timestamps) indefinitely
- **Session Layer**: The `WebviewPanelSerializer` remembers which conversation was active and whether the agent was connected

When VS Code restarts, the extension first retrieves all conversations from `globalState`, then uses the serializer state to highlight the previously active chat and restore the agent connection. This ensures users return to the exact context they left, even after upgrading the extension or reloading the window.

## Summary

- The **conversation list** is permanently stored in `ExtensionContext.globalState` via `ConversationStore` in [`conversationStore.ts`](https://github.com/QwenLM/qwen-code/blob/main/conversationStore.ts)
- The **active conversation pointer** is preserved through VS Code's `WebviewPanelSerializer` API implemented in [`WebViewProvider.ts`](https://github.com/QwenLM/qwen-code/blob/main/WebViewProvider.ts)
- On startup, `getAllConversations()` retrieves the full history while `restoreState()` re-establishes the previous UI context
- The serializer registration occurs in [`extension.ts`](https://github.com/QwenLM/qwen-code/blob/main/extension.ts) and handles both panel destruction and reconstruction events

## Frequently Asked Questions

### How does Qwen Code ensure no data is lost when VS Code crashes?

The extension writes every new conversation immediately to `globalState` using `context.globalState.update('conversations', …)` in [`conversationStore.ts`](https://github.com/QwenLM/qwen-code/blob/main/conversationStore.ts). Since `globalState` is backed by VS Code's persistent storage on disk, the data survives crashes, force quits, and system restarts. The webview serializer only handles UI state, so even if the panel state fails to restore, the conversation data remains intact in global storage.

### What happens to the active conversation when I reload the VS Code window?

Before the window reloads, VS Code invokes the registered `WebviewPanelSerializer` and calls `WebViewProvider.getState()`, which captures the current `conversationId` and `agentInitialized` flag. After the reload completes, `deserializeWebviewPanel` reconstructs the panel and invokes `restoreState()`, which reactivates the conversation via `MessageHandler.setCurrentConversationId()`. The user sees the exact chat that was open before the reload.

### Can I access the conversation history from multiple VS Code windows?

Yes, because `globalState` is shared across all VS Code windows for the same extension installation. When you open a new window and activate the Qwen Code extension, `ConversationStore.getAllConversations()` reads the same `'conversations'` key from `globalState`, making the full chat history available. However, the active conversation pointer is per-panel, so each window can focus on a different conversation independently.

### Where is the conversation data physically stored on disk?

VS Code stores `globalState` in a SQLite database located in the extension's global storage path, typically under `%APPDATA%/Code/User/globalStorage/` on Windows, `~/Library/Application Support/Code/User/globalStorage/` on macOS, or `~/.config/Code/User/globalStorage/` on Linux. The specific key `'conversations'` is a JSON-serialized array stored within this database, managed automatically by the `ExtensionContext.globalState` API.