# Session Resync Process and Data Version Migration in Agentsview: A Complete Guide

> Agentsview's session resync process rebuilds stale SQLite databases to migrate data safely. Learn how Agentsview ensures data integrity through atomic rebuilds and user data preservation.

- Repository: [Kenn Software/agentsview](https://github.com/kenn-io/agentsview)
- Tags: migration-guide
- Published: 2026-06-15

---

**Agentsview detects stale SQLite databases using a built-in `dataVersion` constant and executes an atomic full-database rebuild via `Engine.ResyncAll` to migrate data forward without losing user-generated metadata or orphaned sessions.**

Agentsview is an open-source session analytics platform that persists parsed agent data in a local SQLite database. When parser logic evolves—adding columns, altering field formats, or extracting new metadata—the existing database schema becomes incompatible. This guide explains the **session resync process and data version migration in agentsview**, detailing how the system detects version mismatches and safely rebuilds the database while preserving user insights, trashed items, and orphaned historical data.

## How Data Version Migration Works

Agentsview tracks schema compatibility through a **data version** system defined in [`internal/db/db.go`](https://github.com/kenn-io/agentsview/blob/main/internal/db/db.go). The current constant is set to **41**, and each increment represents a breaking change in parser output that requires existing data to be reprocessed.

```go
// dataVersion tracks parser changes that require a full
// re-sync. Increment this when parsing logic changes in ways
// that affect stored data …
const dataVersion = 41

```

When the database opens via `db.Open()`, the `probeDatabase` function queries SQLite’s `PRAGMA user_version` and compares it against the built-in `dataVersion` constant. If the stored version is lower, `needsDataResync` sets `db.dataStale = true` and emits a log entry: `data version outdated; full resync required`. Applications can check this state explicitly by calling `db.NeedsResync()`, which returns the stale flag.

Once flagged, the migration path requires a full resync. The sync engine ([`internal/sync/engine.go`](https://github.com/kenn-io/agentsview/blob/main/internal/sync/engine.go)) reads this flag and triggers `Engine.ResyncAll`, which constructs a fresh database with the updated schema, bulk-reimports all source files, and atomically swaps the old file for the new one.

## The Session Resync Architecture

The `ResyncAll` method implements a **copy-on-write migration strategy**. Rather than modifying the existing database in place—which risks corruption during schema changes—the engine builds a temporary database file, populates it from source data, copies over user-managed metadata, and performs an atomic file rename. This approach ensures that the original database remains intact until the very last moment, allowing safe rollback if the process aborts.

Key safety mechanisms include **abort-swap logic** that cancels the migration if the sync discovers no files or fails on more sessions than it succeeds, and **WAL file cleanup** that removes SQLite write-ahead logs after the swap to prevent version conflicts.

## Step-by-Step Breakdown of ResyncAll

The `ResyncAll` function in [`internal/sync/engine.go`](https://github.com/kenn-io/agentsview/blob/main/internal/sync/engine.go) executes a 15-phase pipeline to ensure zero data loss during migration.

### Phase 1: Preparation and Isolation

The process begins by creating a temporary database at `origPath + "-resync"` and removing any stale temporary files from previous attempts. The engine saves the in-memory `skipCache`—which tracks files to ignore during incremental syncs—and clears it so the new database starts with a clean state.

```go
removeTempDB(tempPath)
savedSkipCache := e.skipCache
newDB, err := db.Open(tempPath)

```

### Phase 2: Preservation of User Data

Before bulk loading begins, the engine copies user-managed data that cannot be reconstructed from source files:

- **Excluded and trashed sessions**: `CopyExcludedSessionsFrom` and `CopyTrashedDataFrom` preserve permanently deleted or user-trashed items so they do not reappear after the rebuild.
- **Orphaned sessions**: `CopyOrphanedDataFromExcluding` copies sessions whose source files have vanished, ensuring archived data survives the migration.
- **Insights and metadata**: `CopyInsightsFrom` transfers user-generated notes, tags, and stars, while `CopySessionMetadataFrom` restores display names, soft-deletes, pins, and other UI state.

### Phase 3: Bulk Data Loading

To maximize throughput, the engine drops FTS5 (Full-Text Search) tables temporarily to avoid per-row trigger costs during bulk insertion. It then redirects the sync engine to the temporary database and invokes `syncAllLocked` with the `syncWriteBulk` strategy, parsing all session files and inserting them in large batches.

```go
newDB.DropFTS()
stats = e.syncAllLocked(ctx, newDB, syncWriteBulk)

```

### Phase 4: Reconstruction and Validation

After bulk loading, the engine runs several backfill operations:

- **Sub-agent relinking**: `LinkSubagentSessions` reconnects child sessions that may have been disjointed during the orphan copy phase.
- **Automated flag backfill**: `ForceBackfillIsAutomated` recomputes `is_automated` flags for orphaned rows using the current classifier hash, ensuring stale automation markers are corrected.
- **FTS rebuild**: If FTS was dropped earlier, `RebuildFTS` reconstructs and indexes the search tables.

### Phase 5: Atomic Swap and Finalization

The engine performs safety checks to ensure the sync succeeded (more successes than failures, and at least some files processed). It then closes connections to the original database and executes an atomic rename:

```go
os.Rename(tempPath, origPath)

```

This overwrites the old database file with the new one. The engine removes WAL files to prevent SQLite version mismatches, reopens the handle pointing to the new file, and persists the saved `skipCache` into the fresh database. Finally, it notifies any listeners via an optional `Emitter` that the full resync has completed.

## Practical Implementation Examples

### Detecting a Required Resync

Use the `NeedsResync` method to check database compatibility before running operations:

```go
db, err := db.Open("path/to/agentsview.db")
if err != nil {
    log.Fatalf("open db: %v", err)
}
if db.NeedsResync() {
    fmt.Println("Database schema out-of-date – full resync required.")
}

```

*Source*: `db.NeedsResync` implementation in [`internal/db/db.go`](https://github.com/kenn-io/agentsview/blob/main/internal/db/db.go) (lines 38-44).

### Triggering a Programmatic Resync

Execute a blocking resync with progress callbacks:

```go
engine := sync.NewEngine(db, sync.EngineConfig{
    AgentDirs: map[parser.AgentType][]string{ /* … */ },
    Machine:   "my-host",
})

stats := engine.ResyncAll(context.Background(), func(p sync.Progress) {
    log.Printf("Resync progress: %d/%d files", p.Done, p.Total)
})

log.Printf("Resync complete – %d synced, %d failed", stats.Synced, stats.Failed)

```

*Source*: `Engine.ResyncAll` signature in [`internal/sync/engine.go`](https://github.com/kenn-io/agentsview/blob/main/internal/sync/engine.go) (lines 66-78).

### Incrementing the Data Version

When modifying parsers in [`internal/parser/types.go`](https://github.com/kenn-io/agentsview/blob/main/internal/parser/types.go) or altering output formats, increment the constant in [`internal/db/db.go`](https://github.com/kenn-io/agentsview/blob/main/internal/db/db.go):

```go
const dataVersion = 42 // Added session_name field extraction

```

Recompiling the binary causes existing databases to set `dataStale = true` on next open, automatically queueing a resync.

## Summary

- **Version Detection**: Agentsview stores a `dataVersion` constant (currently 41) in [`internal/db/db.go`](https://github.com/kenn-io/agentsview/blob/main/internal/db/db.go) and compares it against SQLite’s `PRAGMA user_version` via `probeDatabase` to detect stale schemas.
- **Atomic Migration**: The `ResyncAll` method in [`internal/sync/engine.go`](https://github.com/kenn-io/agentsview/blob/main/internal/sync/engine.go) builds a temporary database, bulk-loads source data, and performs an atomic file swap to minimize downtime and risk.
- **Data Preservation**: The process explicitly copies excluded sessions, trashed data, orphaned rows, user insights, and session metadata to prevent data loss during rebuilds.
- **Performance Optimization**: FTS tables are dropped during bulk insertion and rebuilt afterward to avoid trigger overhead.
- **Safety Mechanisms**: Abort-swap logic cancels the migration if sync failures exceed successes, ensuring the original database remains untouched if the process fails.

## Frequently Asked Questions

### What triggers a data version migration in Agentsview?

A migration triggers when the `dataVersion` constant in [`internal/db/db.go`](https://github.com/kenn-io/agentsview/blob/main/internal/db/db.go) is incremented by developers to reflect breaking parser changes. When users open an existing database with a newer binary, `probeDatabase` detects that the SQLite `PRAGMA user_version` is lower than the constant, setting `db.dataStale = true` and requiring a full resync to rebuild the schema.

### Is user data lost during the session resync process?

No. The `ResyncAll` pipeline explicitly preserves user-managed data through dedicated copy operations: `CopyExcludedSessionsFrom`, `CopyTrashedDataFrom`, `CopyOrphanedDataFromExcluding`, `CopyInsightsFrom`, and `CopySessionMetadataFrom` ensure that trashed items, orphaned historical sessions, notes, tags, and UI state survive the atomic swap intact.

### How does Agentsview handle resync failures?

The engine implements abort-swap safety checks in [`internal/sync/engine.go`](https://github.com/kenn-io/agentsview/blob/main/internal/sync/engine.go) (lines 1620-1640). If the sync process discovers no files, is manually aborted, or fails on more sessions than it successfully processes, the temporary database is discarded and the original file remains unchanged, preventing data corruption or loss.

### Can I manually trigger a session resync?

Yes. While the sync engine automatically checks `db.NeedsResync()` during initialization, you can force a resync programmatically by calling `engine.ResyncAll(ctx, progressCallback)`, or via the CLI using `agentsview pg resync` (if implemented in your build). This rebuilds the database immediately rather than waiting for the next automatic sync cycle.