# How PI-Desktop Plugins Are Packaged and Distributed: Understanding the .piplug Format

> Learn how PI-Desktop plugins are packaged and distributed using the .piplug format. Discover the store-only ZIP archive and its contents, vital for plugin development with the plugin-devkit toolchain.

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

---

**A `.piplug` file is a store-only (uncompressed) ZIP archive that contains a validated plugin directory, produced by the `@pi-desktop/plugin-devkit` toolchain and extracted by the Rust-based host-core.**

PI-Desktop treats plugins as self-contained artifacts distributed via the `.piplug` format. Unlike custom binary formats, these archives use standard ZIP structures with specific constraints to ensure compatibility between the TypeScript devkit and the Rust host-core extraction logic.

## What Is a .piplug File?

A `.piplug` file is **not a custom binary format**. According to the `vastsa/PI-Desktop` source code, it is a **store-only ZIP archive**—meaning files are stored without compression—that follows a strict layout expected by [`crates/host-core/src/plugins.rs`](https://github.com/vastsa/PI-Desktop/blob/main/crates/host-core/src/plugins.rs). The host-core extractor (`extract_zip_bytes`) explicitly requires store-compressed archives and will reject standard compressed ZIP entries.

This design choice ensures that the Rust extraction engine can parse the local file headers, central directory, and end-of-central-directory (EOCD) records without decompressing data, providing deterministic, cross-language compatibility between the Node.js packaging tools and the native Rust runtime.

## The Packaging Pipeline

The plugin development kit implements a four-stage pipeline defined in [`packages/plugin-devkit/src/pack.ts`](https://github.com/vastsa/PI-Desktop/blob/main/packages/plugin-devkit/src/pack.ts). Each stage enforces security and integrity constraints before the final archive is written to `dist/<plugin-id>-<plugin-version>.piplug`.

### Step 1 – Validation and Security Checks

Before archiving begins, the `check` routine ([`packages/plugin-devkit/src/check.ts`](https://github.com/vastsa/PI-Desktop/blob/main/packages/plugin-devkit/src/check.ts)) validates the plugin manifest. This routine verifies that the plugin ID and version conform to required patterns and **removes any credential files** detected in the source tree. This security step prevents accidental leakage of secrets into distributable artifacts.

### Step 2 – Selective File Walking

The `selectPackageFiles` function in [`packages/plugin-devkit/src/walk.ts`](https://github.com/vastsa/PI-Desktop/blob/main/packages/plugin-devkit/src/walk.ts) traverses the plugin directory tree and explicitly excludes secret files and development artifacts. Only production-necessary files are selected for inclusion, ensuring minimal package size and eliminating sensitive data that might have bypassed initial checks.

### Step 3 – Store-Only ZIP Construction

The `buildStoreZip` function constructs the raw ZIP bytes using the **"store" compression method** (compression level 0). This function manually builds:
- Local file headers for each entry
- Central directory records
- End-of-central-directory record

This implementation mirrors the Rust host-core expectations exactly, guaranteeing that the resulting byte stream can be parsed by `extract_zip_bytes` without additional decompression logic.

### Step 4 – Naming and Integrity Hashing

The completed archive is written to disk with the naming convention:

```text
<plugin-dir>/dist/<plugin-id>-<plugin-version>.piplug

```

Immediately after writing, the packager calculates a **SHA-256 hash** (`shasum`) of the archive bytes. This hash is used for integrity verification when the plugin is later installed via the UI or programmatic APIs.

## Installing .piplug Archives

Distribution supports both manual user interaction and automated programmatic installation through the Electron main process.

### Manual Installation via the UI

End-users can install plugins through the **Plugins page** in the PI-Desktop application. The interface accepts drag-and-drop events or file picker selections. When a `.piplug` file is provided, the renderer process forwards the raw bytes to the main process via IPC channels.

### Programmatic Installation via IPC

For automated workflows, the Electron main process receives plugin bytes through the `plugin-install` IPC channel defined in [`apps/desktop/electron/main/ipc/plugin-ipc.ts`](https://github.com/vastsa/PI-Desktop/blob/main/apps/desktop/electron/main/ipc/plugin-ipc.ts).

```typescript
// Renderer process – send file bytes to main
await window.ipc.send('plugin-install', { bytes: fileBuffer });

```

```typescript
// Main process (apps/desktop/electron/main/ipc/plugin-ipc.ts)
ipcMain.handle('plugin-install', async (_, { bytes }) => {
  // Host-core extracts the store-only zip and registers the plugin
  await hostCore.installPluginFromBytes(bytes);
});

```

The `hostCore.installPluginFromBytes` method delegates to the Rust implementation in [`crates/host-core/src/plugins.rs`](https://github.com/vastsa/PI-Desktop/blob/main/crates/host-core/src/plugins.rs), which validates the store-only constraint and extracts the archive contents to the plugins directory.

## Packaging from the Command Line

The `@pi-desktop/plugin-devkit` provides CLI commands for plugin authors. The following example demonstrates the end-to-end packaging workflow:

```bash

# From the root of a plugin directory

pnpm pi-plugin check .   # Validates manifest and scrubs credentials

pnpm pi-plugin pack .    # Creates dist/<id>-<version>.piplug

# Example output: writes dist/git-insights-1.5.0.piplug

```

### Programmatic Packaging (Node.js)

Plugin marketplaces or CI pipelines can invoke the packager programmatically:

```javascript
import { pack } from '@pi-desktop/plugin-devkit';

(async () => {
  const result = await pack('/path/to/my-plugin');
  console.log('Package written to:', result.packagePath);
  console.log('SHA-256:', result.shasum);
})();

```

## Summary

- A `.piplug` file is a **store-only ZIP archive** (no compression) required by the host-core Rust extractor.
- The packaging workflow in [`packages/plugin-devkit/src/pack.ts`](https://github.com/vastsa/PI-Desktop/blob/main/packages/plugin-devkit/src/pack.ts) implements **validation → file selection → ZIP construction → integrity hashing**.
- The `buildStoreZip` function ensures cross-language compatibility with [`crates/host-core/src/plugins.rs`](https://github.com/vastsa/PI-Desktop/blob/main/crates/host-core/src/plugins.rs) by using raw storage methods.
- Distribution occurs via **drag-and-drop UI** or **IPC channels** handled in [`apps/desktop/electron/main/ipc/plugin-ipc.ts`](https://github.com/vastsa/PI-Desktop/blob/main/apps/desktop/electron/main/ipc/plugin-ipc.ts).
- SHA-256 hashes generated during packaging enable integrity verification during installation.

## Frequently Asked Questions

### Is .piplug a proprietary binary format?

No. A `.piplug` file is a standard ZIP archive that uses the "store" compression method (uncompressed storage). While any standard ZIP utility can extract its contents, only PI-Desktop's host-core will successfully install it because the extractor enforces the store-only requirement for security and performance reasons.

### Why does PI-Desktop use store-only compression instead of standard ZIP compression?

The host-core extraction logic (`extract_zip_bytes` in [`crates/host-core/src/plugins.rs`](https://github.com/vastsa/PI-Desktop/blob/main/crates/host-core/src/plugins.rs)) is optimized to handle store-only archives. This eliminates decompression overhead and complexity in the Rust runtime, allowing the host-core to validate and extract plugins using simple byte offset calculations rather than implementing full DEFLATE decompression.

### How does the host-core validate a .piplug file during installation?

The host-core validates that the ZIP uses only store-compression methods during the extraction process. Additionally, the installation pipeline can verify the SHA-256 hash (`shasum`) generated during packaging to ensure the archive has not been corrupted or tampered with since it left the build environment.

### Can I extract a .piplug file with standard ZIP utilities?

Yes. Because the format follows standard ZIP specifications, tools like `unzip`, 7-Zip, or the `zipfile` Python module can open and inspect `.piplug` contents. However, modifying and repackaging the archive may result in compressed entries that the PI-Desktop host-core will reject during installation.