# How Palmier Pro Handles Project File Persistence: Inside the .palmier Package System

> Discover how Palmier Pro ensures project file persistence with its atomic .palmier package system. Learn about document-oriented architecture and efficient data management for your projects.

- Repository: [Palmier/palmier-pro](https://github.com/palmier-io/palmier-pro)
- Tags: internals
- Published: 2026-06-23

---

**Palmier Pro implements project file persistence using a document‑oriented architecture that packages project data, media assets, and session logs into an atomic `.palmier` directory, coordinated by the `VideoProject` NSDocument subclass and the `ProjectRegistry`.**

Palmier Pro, an open‑source video editing application from the `palmier‑io/palmier‑pro` repository, implements robust **project file persistence** through a specialized package format and thread‑safe serialization. The system treats each editing session as a self‑contained document bundle, ensuring that timelines, media references, and generation logs remain consistent across saves and relocations.

## The .palmier Package Structure

Palmier Pro stores every editing session as a *project package*—a file bundle that uses the `.palmier` extension defined in `Project.fileExtension` ([`Sources/PalmierPro/Utilities/Constants.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Utilities/Constants.swift)). The package is a directory containing multiple assets that preserve the complete state of an editing session:

- **[`project.json`](https://github.com/palmier-io/palmier-pro/blob/main/project.json)** – The serialized timeline data.
- **[`media.json`](https://github.com/palmier-io/palmier-pro/blob/main/media.json)** – An optional media manifest tracking imported assets.
- **`generation‑log.json`** – A log of generation operations.
- **`thumbnail.jpg`** – A preview image of the project.
- **`media/`** – A subdirectory containing copied or referenced media files.
- **`.chat-session/`** – A hidden directory storing conversation history.

This structure ensures that **project file persistence** remains atomic; moving or sharing a single `.palmier` folder transports both metadata and assets.

## Loading and Deserialization

When opening a project, the `VideoProject` class (an `NSDocument` subclass) orchestrates the loading sequence across background and main threads.

**Background Reading**

The entry point `VideoProject.load(from:)` initiates the process, or the document system invokes `read(from:ofType:)`. These methods call `readProjectPackage` on a background task to parse the JSON timeline and optional manifest:

```swift
// Load a project from a URL (e.g., from the recent-project list)
let url = URL(fileURLWithPath: "/Users/me/Documents/Palmier Pro/MyMovie.palmier")
Task {
    let project = try await VideoProject.load(from: url)
    // The project is now an NSDocument ready to be displayed
    AppState.shared.showEditor(for: project)
}

```

The raw data is stored in temporary properties: `loadedTimeline`, `loadedManifest`, and `loadedGenerationLog`.

**Applying to the View Model**

Once the window controller builds via `makeWindowControllers`, the loaded data transfers into the active view model:

- `editorViewModel.timeline` receives the decoded timeline.
- `editorViewModel.mediaManifest` receives the manifest.
- Media assets restore from the manifest and cache for immediate use.

This separation ensures that heavy I/O occurs off the main thread while UI updates remain responsive.

## Saving and Atomic Writing

The save operation follows a snapshot‑then‑write pattern to guarantee data integrity.

**Capturing State**

When a user triggers a save, `captureSaveSnapshot()` serializes the current `editorViewModel` into a `ProjectPackageSnapshot`. The snapshot temporarily stores in non‑isolated variables (`snapshotTimeline`, `snapshotManifest`, etc.) to prevent blocking the UI:

```swift
// Save the current document (normally invoked by the UI)
if let doc = AppState.shared.activeProject {
    doc.save(to: doc.fileURL!, ofType: VideoProject.typeIdentifier) { error in
        if let err = error {
            print("Save failed: \(err)")
        } else {
            print("Project saved.")
        }
    }
}

```

**Writing the Package**

The `write(to:ofType:)` method delegates to `writeProjectPackage`, which performs the atomic file operations:

1. Creates the package directory structure.
2. Writes [`project.json`](https://github.com/palmier-io/palmier-pro/blob/main/project.json), [`media.json`](https://github.com/palmier-io/palmier-pro/blob/main/media.json), and `generation‑log.json`.
3. Perserves or regenerates `thumbnail.jpg`.
4. Copies the entire `media/` folder if the project location changed.
5. Writes the hidden chat‑session directory.

By executing these steps on a background thread, Palmier Pro maintains **project file persistence** without freezing the interface.

## Project Registry and Storage Management

Palmier Pro tracks recent projects using the `ProjectRegistry` singleton ([`Sources/PalmierPro/Project/ProjectRegistry.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Project/ProjectRegistry.swift)), which maintains a JSON list located at `~/Documents/Palmier Pro/project-registry.json` (defined in `Project.storageDirectory`).

**Registry Operations**

- **`register(_:)`** – Adds a newly opened project to the registry.
- **`updateURL`** – Called automatically when `VideoProject.fileURL` changes (via the setter), handling project moves or renames.
- **`remove(_:)`** and **`delete(_:)`** – Clean up entries when projects close or delete.

The storage directory creates itself on‑demand via `Project.ensureStorageDirectory`, ensuring the registry always has a valid filesystem location:

```swift
// Register a newly-created project (handled automatically when the document is opened)
ProjectRegistry.shared.register(URL(fileURLWithPath: "/Users/me/Documents/Palmier Pro/NewProject.palmier"))

```

## Thread Safety and Document Lifecycle

The **project file persistence** mechanism strictly separates concerns across threads:

- **Read** – `readProjectPackage` decodes JSON on a background thread.
- **Apply** – `makeWindowControllers` injects the model into the view model on the main thread.
- **Write** – `writeProjectPackage` snapshots and writes atomically on a background thread.

This architecture aligns with Apple's `NSDocument` recommendations while providing the performance necessary for video editing workloads.

## Summary

- Palmier Pro uses a `.palmier` package format (defined in [`Constants.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Constants.swift)) containing JSON timelines, media manifests, generation logs, and asset subdirectories.
- The `VideoProject` class (in [`VideoProject.swift`](https://github.com/palmier-io/palmier-pro/blob/main/VideoProject.swift)) handles loading via `load(from:)` and saving via `captureSaveSnapshot()` → `writeProjectPackage()`.
- Media assets persist inside the `media/` subdirectory, copied entirely when projects relocate.
- The `ProjectRegistry` (in [`ProjectRegistry.swift`](https://github.com/palmier-io/palmier-pro/blob/main/ProjectRegistry.swift)) maintains recent project references in `~/Documents/Palmier Pro/project-registry.json`.
- All file I/O operates on background threads, with view‑model updates restricted to the main thread.

## Frequently Asked Questions

### What file extension does Palmier Pro use for project files?

Palmier Pro uses the `.palmier` extension for its project packages. This is defined as a constant in [`Sources/PalmierPro/Utilities/Constants.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Utilities/Constants.swift) (`Project.fileExtension`), and each package is technically a directory bundling JSON metadata and media assets.

### How does Palmier Pro handle media assets during save operations?

During the `writeProjectPackage` phase, the system checks whether the project location has changed. If so, it copies the entire `media/` subdirectory from the previous package to the new destination, ensuring that relative paths in [`media.json`](https://github.com/palmier-io/palmier-pro/blob/main/media.json) remain valid and that **project file persistence** remains self‑contained.

### Where does Palmier Pro store the list of recent projects?

The application stores the recent project list in `~/Documents/Palmier Pro/project-registry.json`, accessed through `Project.storageDirectory`. The `ProjectRegistry` singleton manages this JSON file, updating it automatically when projects open, move, or delete.

### Is the project loading process thread‑safe?

Yes. The loading sequence executes `readProjectPackage` on a background thread to decode [`project.json`](https://github.com/palmier-io/palmier-pro/blob/main/project.json) and [`media.json`](https://github.com/palmier-io/palmier-pro/blob/main/media.json), then transitions to the main thread only when `makeWindowControllers` applies the loaded data to `editorViewModel`. This prevents UI blocking while maintaining thread safety for Cocoa bindings.