# Voicebox Generation Version System and Lineage Tracking: Technical Implementation Guide

> Explore Voicebox generation version system and lineage tracking. Learn how Voicebox tracks every audio version with full provenance for derivative creations. Dive into the technical implementation.

- Repository: [Jamie Pine/voicebox](https://github.com/jamiepine/voicebox)
- Tags: technical-implementation-guide
- Published: 2026-04-14

---

**Voicebox implements a mutable artifact system where every speech generation maintains multiple audio versions with full lineage tracking, allowing users to create derivative versions from existing ones while preserving the complete provenance chain.**

The open-source Voicebox repository (`jamiepine/voicebox`) treats speech synthesis outputs as **evolvable artifacts** rather than static files. This architecture enables non-destructive editing workflows where users can apply effects chains, fork new variations, and revert to previous states. The Voicebox generation version system and lineage tracking capabilities rely on a relational database model that links derivative versions to their source ancestors through explicit foreign key relationships.

## Data Model Architecture

The foundation resides in [`backend/database/models.py`](https://github.com/jamiepine/voicebox/blob/main/backend/database/models.py), which defines the core entities that power the versioning system.

### Generation and GenerationVersion Models

The **`Generation`** model stores the original synthesis record including text prompts, language codes, and status metadata. Its one-to-many child, **`GenerationVersion`**, resides in the same file and contains:

- **Version metadata**: Labels, file storage paths under `config.STORAGE_ROOT`, applied effects, and creation timestamps
- **Lineage pointers**: The `source_version_id` field establishes parent-child relationships between versions
- **Default flags**: A boolean `is_default` indicating which version serves as the canonical output for playback and export

Pydantic schemas in [`backend/models.py`](https://github.com/jamiepine/voicebox/blob/main/backend/models.py) (lines 665-678) define `GenerationVersionResponse`, which standardizes API responses to clients. Audio processing parameters serialize through the `EffectConfig` schema (lines 221-226), describing effect types, enabled states, and parameter dictionaries.

## Version Lifecycle Operations

All mutation logic lives in [`backend/services/versions.py`](https://github.com/jamiepine/voicebox/blob/main/backend/services/versions.py), wrapped in atomic SQLAlchemy transactions to ensure consistency between database records and filesystem assets.

### Creating Derivative Versions

The **`create_version()`** function (lines 82-119) instantiates new `GenerationVersion` records. When invoked with `is_default=True`, it atomically clears existing default flags on sibling versions and updates the parent `Generation.audio_path` to reference the new file.

Users trigger this workflow via the `POST /generations/:generationId/versions/apply-effects` endpoint, supplying an `effects_chain` array and optional `source_version_id`. If `source_version_id` is null, the system uses the original clean audio as the processing source.

```bash
curl -X POST http://localhost:17493/generations/abcd1234/versions/apply-effects \
  -H "Content-Type: application/json" \
  -d '{
        "effects_chain": [
          {"type":"reverb","enabled":true,"params":{"room_size":0.8}},
          {"type":"pitch_shift","enabled":true,"params":{"semitones":-2}}
        ],
        "source_version_id": "v-001",
        "label": "Deep Reverb",
        "set_as_default": true
      }'

```

### Managing Default Versions

The **`set_default_version(version_id, db)`** function (lines 122-139) handles promotion logic. It clears the previous default flag, sets the target version as default, and synchronizes the parent `Generation.audio_path` to maintain referential integrity.

Retrieving version lists uses **`list_versions(generation_id, db)`** (lines 43-52), which returns records ordered by creation time. The TypeScript client in [`app/src/lib/api/client.ts`](https://github.com/jamiepine/voicebox/blob/main/app/src/lib/api/client.ts) exposes this via `apiClient.listGenerationVersions()`:

```typescript
import { apiClient } from '@/lib/api/client';

async function showVersions(genId: string) {
  const versions = await apiClient.listGenerationVersions(genId);
  const activeVersion = versions.find(v => v.is_default);
  console.log('Current default:', activeVersion?.id);
}

```

### Safe Deletion Constraints

The **`delete_version(version_id, db)`** function (lines 142-184) enforces critical safety invariants. It removes the underlying audio file using `config.resolve_storage_path()`, then verifies that at least one version remains. If the deleted version held the default status, the system automatically promotes the earliest remaining version (lines 168-179). Attempting to delete the final version raises an error, ensuring every generation maintains a playable asset.

```python
from backend.services import versions
from sqlalchemy.orm import Session

def remove_version(version_id: str, db: Session):
    success = versions.delete_version(version_id, db)
    if not success:
        raise ValueError("Cannot delete the last remaining version")

```

## Lineage Tracking and Provenance

Voicebox maintains complete **provenance chains** through the `source_version_id` field on `GenerationVersion`. When creating a derived version, the backend persists the parent ID, enabling recursive traversal of the derivation history.

The frontend renders this metadata as a lineage graph, displaying relationships like "Version 2 → derived from Version 1 (original)." This information is stored in the database column and returned in every `GenerationVersionResponse`, allowing UI components to visualize the evolution of audio artifacts across time.

## Frontend State Integration

The **`generationStore`** ([`app/src/stores/generationStore.ts`](https://github.com/jamiepine/voicebox/blob/main/app/src/stores/generationStore.ts)) manages client-side state for the current generation, its version array, and the active version ID. When users apply effects, the store constructs an `ApplyEffectsRequest`, invokes `apiClient.applyEffectsToGeneration()`, and refreshes the version list via `apiClient.listGenerationVersions()`.

Story-specific version pinning uses `apiClient.setStoryItemVersion()`, which persists `version_id` on `StoryItemDetail` records. During playback resolution, [`backend/services/stories.py`](https://github.com/jamiepine/voicebox/blob/main/backend/services/stories.py) retrieves the specific generation and calls `_get_versions_for_generation()` from [`backend/services/history.py`](https://github.com/jamiepine/voicebox/blob/main/backend/services/history.py) (lines 18-52) to resolve the pinned version, ensuring the correct audio streams via `GET /audio/version/:versionId`.

## Summary

- **Mutable Artifacts**: Every generation supports multiple audio versions stored in `GenerationVersion` records with full metadata and effects chains.
- **Lineage Tracking**: The `source_version_id` field creates a directed graph of derivations, enabling users to trace processing history back to original syntheses.
- **Transactional Safety**: All version operations in [`backend/services/versions.py`](https://github.com/jamiepine/voicebox/blob/main/backend/services/versions.py) use database transactions to synchronize SQLAlchemy records with filesystem storage under `config.STORAGE_ROOT`.
- **Default Guarantees**: The system maintains exactly one default version per generation and prevents deletion of the final remaining version to ensure data integrity.
- **API Consistency**: REST endpoints in the TypeScript client ([`app/src/lib/api/client.ts`](https://github.com/jamiepine/voicebox/blob/main/app/src/lib/api/client.ts)) provide type-safe access to version creation, listing, default-setting, and deletion operations.

## Frequently Asked Questions

### How does Voicebox track which audio version was used to create a new version?

Voicebox stores the parent version's identifier in the `source_version_id` field of the `GenerationVersion` model defined in [`backend/database/models.py`](https://github.com/jamiepine/voicebox/blob/main/backend/database/models.py). When a user applies effects through the `applyEffectsToGeneration` API, the backend persists this lineage reference, creating a chain of provenance that the frontend renders as a derivation graph mapping version ancestry.

### What happens when I delete the default version of a generation?

The `delete_version()` function in [`backend/services/versions.py`](https://github.com/jamiepine/voicebox/blob/main/backend/services/versions.py) automatically promotes the earliest remaining version to default status if the deleted version was marked as default. The system prevents deletion of the final remaining version, ensuring every generation retains at least one playable audio asset and maintains referential integrity with `Generation.audio_path`.

### Can I revert a generation to its original unprocessed audio?

Yes, by invoking `setDefaultVersion()` or calling the `PUT /generations/:generationId/versions/:versionId/set-default` endpoint on the version containing the original synthesis. The original audio exists as a `GenerationVersion` record (typically with `source_version_id` set to null), allowing you to restore it as the canonical output at any time without destructive operations.

### How does the frontend know which version to play when rendering a story?

When a version is pinned to a story item via `setStoryItemVersion()`, the backend stores the `version_id` on the `StoryItemDetail` record. During playback resolution, [`backend/services/stories.py`](https://github.com/jamiepine/voicebox/blob/main/backend/services/stories.py) utilizes `_get_versions_for_generation()` from [`backend/services/history.py`](https://github.com/jamiepine/voicebox/blob/main/backend/services/history.py) to retrieve the specific version metadata and generates the streaming URL via `apiClient.getVersionAudioUrl(versionId)`, ensuring the correct audio file serves the request.