# How to Import Existing Sessions from Other Agents into PI-Desktop

> Learn how to import existing sessions from other agents into PI-Desktop using its two-step IPC workflow. Seamlessly convert external formats to native SQLite sessions.

- Repository: [Lan/PI-Desktop](https://github.com/vastsa/PI-Desktop)
- Tags: how-to-guide
- Published: 2026-09-12

---

**PI-Desktop imports external chat sessions through a two-step IPC workflow where the renderer scans for candidates via `scanSessionImportCandidates()` and imports them via `importSessions()`, converting external formats into native SQLite-backed sessions through the Rust host core.**

PI-Desktop provides a robust mechanism to migrate conversations from other AI agents into its unified chat interface. This guide explains how to import existing sessions from other agents into PI-Desktop using the **IPC bridge** and **Rust host core**, based on the actual implementation in the `vastsa/PI-Desktop` repository.

## Understanding the Session Import Architecture

The import system relies on **type-safe IPC communication** between the Electron renderer and main process. When importing sessions from other agents, PI-Desktop executes a two-phase workflow: first scanning for available external sessions, then converting and persisting them into the internal SQLite database.

The IPC channel names defined in [`packages/shared/src/protocol.ts`](https://github.com/vastsa/PI-Desktop/blob/main/packages/shared/src/protocol.ts) guarantee consistent communication:

```typescript
// packages/shared/src/protocol.ts
sessionImportScan: "pi-desktop/session/importScan",
sessionImportRun: "pi-desktop/session/importRun",

```

These identifiers map to `IPC.invoke.sessionImportScan` and `IPC.invoke.sessionImportRun`, ensuring the renderer and main process speak the same protocol.

## Step 1: Scanning for Importable Sessions

The discovery phase begins when the renderer requests an enumeration of supported external session sources. In [`apps/desktop/electron/main/ipc/session-ipc.ts`](https://github.com/vastsa/PI-Desktop/blob/main/apps/desktop/electron/main/ipc/session-ipc.ts), the handler for `IPC.invoke.sessionImportScan` calls `scanAllSources()` to identify candidates from other agents.

```typescript
// apps/desktop/electron/main/ipc/session-ipc.ts (lines 59-66)
IPC.handle("sessionImportScan", async () => {
  const candidates = await scanAllSources();
  return { sessions: candidates };
});

```

The function returns an array of `ImportCandidate` objects, each containing metadata such as `source`, `externalId`, and `name`. This allows the UI to present available sessions without loading their full content until selected.

## Step 2: Converting and Importing Sessions

Once you select candidate sessions, the main process handles the `IPC.invoke.sessionImportRun` invocation. The implementation in [`apps/desktop/electron/main/ipc/session-ipc.ts`](https://github.com/vastsa/PI-Desktop/blob/main/apps/desktop/electron/main/ipc/session-ipc.ts) (lines 69-104) iterates through selections, converts each external session using `convertSession(item)`, and commits them via the `"session.import"` RPC to the Rust host core.

```typescript
// apps/desktop/electron/main/ipc/session-ipc.ts (lines 69-104)
IPC.handle("sessionImportRun", async (_, selections) => {
  const results = { imported: 0, skipped: 0, failed: 0 };
  
  for (const item of selections) {
    try {
      const session = convertSession(item);
      await host.call("session.import", session);
      results.imported++;
    } catch (error) {
      console.error(`Failed to import session ${item.externalId}:`, error);
      results.failed++;
    }
  }
  
  return results;
});

```

Because the actual import logic lives in the **host core**, imported sessions become first-class citizens in PI-Desktop—they appear in the session list, support editing, and are stored in the same SQLite database as native sessions.

## Renderer-Side API Integration

The frontend consumes these IPC channels through convenient wrappers in [`apps/desktop/src/lib/api.ts`](https://github.com/vastsa/PI-Desktop/blob/main/apps/desktop/src/lib/api.ts). These helpers abstract the raw IPC calls and provide typed interfaces for the renderer process.

```typescript
// apps/desktop/src/lib/api.ts
export async function scanSessionImportCandidates() {
  return invoke<{ sessions: ImportCandidate[] }>(IPC.invoke.sessionImportScan);
}

export async function importSessions(selections: ImportCandidate[]) {
  return invoke<ImportRunResult>(IPC.invoke.sessionImportRun, selections);
}

```

Use `scanSessionImportCandidates()` to populate the import dialog, then pass user selections to `importSessions()` to execute the migration.

## Practical Implementation Examples

### Import All Available External Sessions

This example demonstrates scanning for all candidates and importing them unconditionally:

```typescript
import { scanSessionImportCandidates, importSessions } from "./api";

async function importAll() {
  // Step 1: Scan for candidates
  const { sessions } = await scanSessionImportCandidates();

  // Step 2: Import everything (filter here if needed)
  const selections = sessions;

  // Step 3: Run the import
  const result = await importSessions(selections);
  console.log(`Imported: ${result.imported}, Skipped: ${result.skipped}, Failed: ${result.failed}`);
}

importAll().catch(console.error);

```

### Import from a Specific Agent Source

To import sessions only from a particular external agent, filter the candidates by source ID before calling `importSessions()`:

```typescript
import { scanSessionImportCandidates, importSessions } from "./api";

async function importFromSource(sourceId: string) {
  const { sessions } = await scanSessionImportCandidates();

  const candidate = sessions.find(c => c.source === sourceId);
  if (!candidate) {
    console.warn(`No session found for source ${sourceId}`);
    return;
  }

  const { imported, skipped, failed } = await importSessions([candidate]);
  console.log(`Result – imported: ${imported}, skipped: ${skipped}, failed: ${failed}`);
}

```

## Summary

- **PI-Desktop** stores sessions in a Rust host core with SQLite persistence, making imported sessions indistinguishable from native ones.
- The **two-step import process** requires first scanning with `scanAllSources()` in [`session-ipc.ts`](https://github.com/vastsa/PI-Desktop/blob/main/session-ipc.ts), then converting and importing via `host.call("session.import", …)`.
- **IPC channels** are type-safe constants defined in [`packages/shared/src/protocol.ts`](https://github.com/vastsa/PI-Desktop/blob/main/packages/shared/src/protocol.ts), accessed through `IPC.invoke.sessionImportScan` and `IPC.invoke.sessionImportRun`.
- The **renderer API** in [`apps/desktop/src/lib/api.ts`](https://github.com/vastsa/PI-Desktop/blob/main/apps/desktop/src/lib/api.ts) provides `scanSessionImportCandidates()` and `importSessions()` to simplify frontend integration.
- Imported sessions support full editing capabilities and persist in the native database alongside sessions created within PI-Desktop.

## Frequently Asked Questions

### What external agent formats does PI-Desktop support for session import?

The specific formats depend on the implementation of `scanAllSources()` in the main process. The architecture is designed to support any external agent that can provide session metadata (name, externalId, source) and conversation content. You can extend support by modifying the scanner logic in [`apps/desktop/electron/main/ipc/session-ipc.ts`](https://github.com/vastsa/PI-Desktop/blob/main/apps/desktop/electron/main/ipc/session-ipc.ts).

### Are imported sessions editable after migration?

Yes. Because the `convertSession()` function transforms external formats into PI-Desktop's internal session structure before calling `host.call("session.import", …)`, imported sessions become first-class citizens. They appear in the session list, support editing, and persist in the SQLite database exactly like native sessions.

### Where does PI-Desktop store imported sessions?

According to the source code in `vastsa/PI-Desktop`, imported sessions are handed to the **Rust host core** via the `"session.import"` RPC. The host core stores all sessions—whether native or imported—in the same SQLite database, ensuring consistent data management and retrieval performance.

### Can I import multiple sessions simultaneously?

Yes. The `importSessions()` API accepts an array of `ImportCandidate` objects, and the IPC handler in [`session-ipc.ts`](https://github.com/vastsa/PI-Desktop/blob/main/session-ipc.ts) iterates through all selections in a single invocation. The function returns aggregate statistics (`imported`, `skipped`, `failed`) for the entire batch operation.