> ## Documentation Index
> Fetch the complete documentation index at: https://docs.arupa.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# .plg package

> Build and structure the plugin package loaded by the Arupa Kernel.

The `.plg` file is the distribution format for an Arupa plugin. It is a ZIP
archive containing the plugin manifest and the files required by the plugin at
runtime. The Kernel scans files with the `.plg` extension, reads the manifest,
and extracts the package into its configured temporary directory when the
plugin is started.

## Package layout

A valid package has `info.yaml` at its archive root and a `Content` directory:

```text theme={null}
my-plugin.plg
├── info.yaml
└── Content/
    ├── my-plugin.wasm
    ├── pages/
    │   └── index.html
    └── assets/
        └── app.js
```

`Content` is the plugin's runtime root. The Kernel exposes its extracted path
through the `$PLUGIN_ROOT` placeholder in `info.yaml` and in resource
declarations returned during registration. A plugin should keep its executable
and all static resources under this directory.

The package must contain both `info.yaml` and `Content/`. A package that cannot
be read as a ZIP archive, does not have a root-level manifest, or does not have
the content directory cannot be loaded.

## `info.yaml`

The manifest identifies the plugin and tells the Kernel how to start it:

```yaml theme={null}
Name: my-plugin
Version: 1.0.0
Type: wasm
ContractVersion: 1
Command: $PLUGIN_ROOT/my-plugin.wasm
DisplayName: My Plugin

# Optional Metadata
Category: application
Entry: /my-plugin/pages/index.html
```

The required fields are:

| Field             | Description                                                                                      |
| ----------------- | ------------------------------------------------------------------------------------------------ |
| `Name`            | Unique plugin name. The value must also be returned by the plugin's registration response.       |
| `Version`         | Plugin version. It must match the version returned during registration.                          |
| `Type`            | Runtime backend: `wasm` or `grpc`.                                                               |
| `ContractVersion` | Version of the plugin protocol used by the plugin.                                               |
| `Command`         | Executable or WASM module to load. `$PLUGIN_ROOT` is replaced with the extracted `Content` path. |

Other fields are retained as plugin metadata. They can be used by the Kernel's
plugin management features or by the application UI, but they do not replace
the required runtime fields above.

### Backend and command

For a WASM plugin, set `Type` to `wasm` and point `Command` to the module in
`Content`:

```yaml theme={null}
Type: wasm
Command: $PLUGIN_ROOT/my-plugin.wasm
```

For a gRPC plugin, set `Type` to `grpc` and point `Command` to the executable in
`Content`:

```yaml theme={null}
Type: grpc
Command: $PLUGIN_ROOT/my-plugin
```

The Kernel starts a gRPC executable with its working directory set to
`$PLUGIN_ROOT` and provides the `PLUGIN_ROOT` environment variable. This lets
the executable locate resources without depending on the temporary extraction
path chosen by the Kernel.

## Build and package

Build the plugin and assemble the package in the following order.

### 1. Compile the plugin

Compile the plugin for its selected backend. The result is one runtime
artifact: a WASM module for a WASM plugin or an executable for a gRPC plugin.
Keep the artifact available so you can copy it into the package's `Content/`
directory.

### 2. Create the package directory

Create a temporary directory for the package. `info.yaml` and `Content/` must
be directly under this directory:

```sh theme={null}
mkdir -p build/my-plugin/Content
```

The directory will become the root of the ZIP archive. Do not add another
directory level around it when creating the archive.

### 3. Create `info.yaml`

Create `info.yaml` at the package root. Set `Command` to the artifact's path
relative to `Content/` by using `$PLUGIN_ROOT`:

```yaml theme={null}
Name: my-plugin
Version: 1.0.0
Type: wasm
ContractVersion: 1
Command: $PLUGIN_ROOT/my-plugin.wasm
```

Copy the file into the staging directory:

```sh theme={null}
cp info.yaml build/my-plugin/info.yaml
```

For a gRPC artifact, set `Type` to `grpc` and point `Command` to the
executable, for example `Command: $PLUGIN_ROOT/my-plugin`.

### 4. Place the runtime artifact and static resources

Copy the compiled artifact into `Content/`. Its location must match
`info.yaml`:

```sh theme={null}
cp build/my-plugin.wasm build/my-plugin/Content/my-plugin.wasm
```

Place any static resources required by the plugin under the same directory:

```sh theme={null}
cp -R pages build/my-plugin/Content/pages
cp -R assets build/my-plugin/Content/assets
```

The resulting staging directory should look like this:

```text theme={null}
build/my-plugin/
├── info.yaml
└── Content/
    ├── my-plugin.wasm
    ├── pages/
    │   └── index.html
    └── assets/
        └── app.js
```

### 5. Create the ZIP archive

Create the archive from inside the staging directory. This keeps `info.yaml`
and `Content/` at the archive root:

```sh theme={null}
mkdir -p plugins
cd build/my-plugin
zip -qr ../../plugins/my-plugin.plg .
```

The resulting `plugins/my-plugin.plg` is ready to place in the Kernel's
configured `PluginDir`. Scan the directory or restart the Kernel to discover
the package.

## Loading a package

The Kernel's package workflow is:

1. scan `PluginDir` for `.plg` files;
2. read and validate each package's `info.yaml`;
3. extract the selected package into `PluginTempDir`;
4. start the backend described by `Type` and `Command`;
5. call the plugin's registration method; and
6. connect the routes, static mounts, Socket.IO resources, and message handlers
   returned by the plugin.

The package is not considered successfully loaded until registration succeeds.
The `Name` and `Version` in the registration response must match the values in
`info.yaml`; otherwise the Kernel rejects the package.

See [Plugin configuration](../kernel/config-plugins) for startup behavior,
runtime parameters, and the execution user for gRPC plugins.
