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

# Plugins

> Plugin configuration reference

This page documents the complete `plugin.toml` manifest schema. For conceptual information, see [Plugin Configuration](/plugin-system/configuration).

## Full example

```toml theme={null}
[plugin]
name = "my-plugin"
version = "0.1.0"
description = "My analysis plugin"
authors = ["Your Name"]
type = "guest"                        # or "host"
binary = "my-plugin.exe"              # optional, defaults to directory name

[runtime]
state = "ephemeral"                   # or "persistent", "scoped"
execution = "exclusive"               # or "sequential", "parallel", "unrestricted"
port = 50051                          # gRPC listen port (default: 50051)
log_filter = "info"                   # tracing filter (default: "info")
analysis_timeout = 300                # max analysis time in seconds (default: 300)

[runtime.paths]
sample_dir       = "C:\\malbox\\samples"
artifact_dir     = "C:\\malbox\\artifacts"
stash_dir        = "C:\\malbox\\stash"
log_dir          = "C:\\malbox\\logs"
external_log_dir = "C:\\malbox\\ext-logs"

[runtime.stash]
threshold_bytes = 1048576
ttl_secs = 120

[runtime.auto_collect.artifacts]
enabled  = true
include  = ["**/*"]
exclude  = []
max_file_size = 52428800

[runtime.auto_collect.external_logs]
enabled  = true
include  = ["**/*"]
exclude  = []
max_file_size = 52428800

[events]
subscribe = ["string-extractor", "network-analyzer"]

[events.filters.PluginResultAvailable]
from_plugins = ["string-extractor"]

[scope]
plugins = ["related-plugin"]
task_types = ["full-analysis"]

[results.my_result]
description = "What this result contains"
user_visible = true
display_name = "My Result"
render = "json"
```

## `[plugin]`

Core plugin identity. This section is required.

| Field         | Type       | Required | Description                                                                                            |
| ------------- | ---------- | -------- | ------------------------------------------------------------------------------------------------------ |
| `name`        | `string`   | Yes      | Unique plugin name. Must be alphanumeric, `-`, or `_` only.                                            |
| `version`     | `string`   | Yes      | Semantic version (e.g. `"0.1.0"`). Must be valid [semver](https://semver.org/).                        |
| `description` | `string`   | No       | Human-readable description.                                                                            |
| `authors`     | `string[]` | No       | List of author names.                                                                                  |
| `type`        | `string`   | Yes      | Plugin type: `"host"` or `"guest"`.                                                                    |
| `binary`      | `string`   | No       | Executable filename. Defaults to the plugin directory name. Relevant for Python plugins (`"main.py"`). |

## `[runtime]`

Controls how the plugin runtime behaves. For guest plugins, the build process bakes these values into the plugin binary. For host plugins, the daemon reads them at registry scan time.

| Field              | Type      | Required | Default  | Description                                                                                                                    |
| ------------------ | --------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------ |
| `state`            | `string`  | Yes      | -        | Plugin state management mode (`"ephemeral"`, `"persistent"`, or `"scoped"`).                                                   |
| `execution`        | `string`  | Yes      | -        | Execution context (`"exclusive"`, `"sequential"`, `"parallel"`, or `"unrestricted"`).                                          |
| `port`             | `u16`     | No       | `50051`  | gRPC listen port. Must be >= 1024. Guest plugins only.                                                                         |
| `log_filter`       | `string`  | No       | `"info"` | Tracing directive string (same syntax as `tracing_subscriber::EnvFilter`). Examples: `"info"`, `"debug"`, `"info,hyper=warn"`. |
| `analysis_timeout` | `integer` | No       | `300`    | Maximum analysis time in seconds. Must be >= 1. The daemon wraps this with an additional grace period for result flushing.     |

### Plugin types

| Type      | Description                                                                                               |
| --------- | --------------------------------------------------------------------------------------------------------- |
| `"guest"` | Executes inside a sandboxed VM. Communicates via gRPC. Terminated with the sandbox after task completion. |
| `"host"`  | Executes directly on the host system via iceoryx2 IPC. Can persist across multiple tasks.                 |

### Execution contexts

| Value            | Description                                                |
| ---------------- | ---------------------------------------------------------- |
| `"exclusive"`    | Only one instance runs at a time across the entire daemon. |
| `"sequential"`   | Tasks are dispatched one at a time, in order.              |
| `"parallel"`     | Multiple tasks may run concurrently.                       |
| `"unrestricted"` | No constraints on concurrency or ordering.                 |

### State management

| Value          | Description                                                                               |
| -------------- | ----------------------------------------------------------------------------------------- |
| `"persistent"` | Stays running between tasks. Host plugins only.                                           |
| `"ephemeral"`  | Spun up per task and torn down immediately after.                                         |
| `"scoped"`     | Lives for the duration of an analysis scope (e.g. a batch). Requires a `[scope]` section. |

<Warning>
  `"scoped"` state is not yet implemented. Plugins configured with `state = "scoped"` will fail to start.
</Warning>

### `[runtime.paths]`

All paths must be absolute. Guest plugins may use Windows-style absolute paths (e.g. `C:\malbox\samples`).

| Field              | Type     | Default (unix)          | Default (windows)     | Description                                                                                 |
| ------------------ | -------- | ----------------------- | --------------------- | ------------------------------------------------------------------------------------------- |
| `sample_dir`       | `string` | `/tmp/malbox/samples`   | `C:\malbox\samples`   | Where the daemon pushes the sample for analysis.                                            |
| `artifact_dir`     | `string` | `/tmp/malbox/artifacts` | `C:\malbox\artifacts` | Where the plugin writes output artifacts. Auto-collected after task execution.              |
| `stash_dir`        | `string` | `/tmp/malbox/stash`     | `C:\malbox\stash`     | Internal result stash spillover directory.                                                  |
| `log_dir`          | `string` | `/tmp/malbox/logs`      | `C:\malbox\logs`      | SDK-internal log overflow files directory.                                                  |
| `external_log_dir` | `string` | `/tmp/malbox/ext-logs`  | `C:\malbox\ext-logs`  | External log files from kernel drivers or other tools. Auto-collected after task execution. |

### `[runtime.stash]`

| Field             | Type      | Default           | Description                                                                                 |
| ----------------- | --------- | ----------------- | ------------------------------------------------------------------------------------------- |
| `threshold_bytes` | `integer` | `1048576` (1 MiB) | Result payloads larger than this are spilled to disk via the result stash. Must be >= 4096. |
| `ttl_secs`        | `integer` | `120`             | How long stashed result entries are kept before TTL sweep reclaims them. Must be >= 1.      |

### `[runtime.auto_collect]`

Controls automatic file collection from `artifact_dir` and `external_log_dir` after each task completes. The runtime streams files in these directories back to the daemon as results, so your plugin does not need to send them explicitly.

<Note>
  For artifacts, the runtime skips files you already sent explicitly (via `ctx.results().push(PluginResult::file(...))`) or marked with `ctx.mark_collected()` to avoid duplicates. External logs are always collected without deduplication.
</Note>

#### `[runtime.auto_collect.artifacts]`

| Field           | Type       | Default             | Description                                        |
| --------------- | ---------- | ------------------- | -------------------------------------------------- |
| `enabled`       | `bool`     | `true`              | Whether to auto-collect files from `artifact_dir`. |
| `include`       | `string[]` | `["**/*"]`          | Glob patterns for files to include.                |
| `exclude`       | `string[]` | `[]`                | Glob patterns for files to exclude.                |
| `max_file_size` | `integer`  | `52428800` (50 MiB) | Files larger than this are skipped.                |

#### `[runtime.auto_collect.external_logs]`

| Field           | Type       | Default             | Description                                            |
| --------------- | ---------- | ------------------- | ------------------------------------------------------ |
| `enabled`       | `bool`     | `true`              | Whether to auto-collect files from `external_log_dir`. |
| `include`       | `string[]` | `["**/*"]`          | Glob patterns for files to include.                    |
| `exclude`       | `string[]` | `[]`                | Glob patterns for files to exclude.                    |
| `max_file_size` | `integer`  | `52428800` (50 MiB) | Files larger than this are skipped.                    |

## `[events]`

Configures event subscriptions for host plugins. Guest plugins do not support event hooks.

| Field       | Type       | Required | Description                                                                                               |
| ----------- | ---------- | -------- | --------------------------------------------------------------------------------------------------------- |
| `subscribe` | `string[]` | No       | List of plugin names to subscribe to. Your plugin will receive events from these plugins' event channels. |

### `[events.filters.<EventName>]`

Per-event-type filters. `<EventName>` is the event variant name (e.g. `PluginResultAvailable`).

| Field          | Type       | Required | Description                                                                |
| -------------- | ---------- | -------- | -------------------------------------------------------------------------- |
| `from_plugins` | `string[]` | No       | Only deliver this event type when it originates from one of these plugins. |

## `[scope]`

Required when `state = "scoped"`. Defines the scope boundary for the plugin's lifetime.

| Field        | Type       | Required | Description                       |
| ------------ | ---------- | -------- | --------------------------------- |
| `plugins`    | `string[]` | No       | Plugins that share this scope.    |
| `task_types` | `string[]` | No       | Task types that share this scope. |

## `[results.<name>]`

Declares result entries that this plugin may produce. Each key under `[results]` is a result name that matches what you pass to `PluginResult::json("name", ...)`, `PluginResult::bytes("name", ...)`, or `PluginResult::file("name", ...)`.

| Field          | Type     | Required | Description                                             |
| -------------- | -------- | -------- | ------------------------------------------------------- |
| `description`  | `string` | No       | What this result contains.                              |
| `user_visible` | `bool`   | No       | Whether this result should be shown in the frontend UI. |
| `display_name` | `string` | No       | Human-readable name for display in the UI.              |
| `render`       | `string` | No       | Rendering hint for the frontend (e.g. `"json"`).        |

## Validation

The daemon validates the manifest when scanning plugin directories. It marks plugins with invalid manifests as `Invalid` in the registry and does not start them. The daemon enforces the following constraints:

| Constraint         | Rule                                                                   |
| ------------------ | ---------------------------------------------------------------------- |
| Plugin name        | Must be non-empty. Only alphanumeric characters, `-`, and `_` allowed. |
| Version            | Must be valid [semver](https://semver.org/).                           |
| Port               | Must be >= 1024.                                                       |
| All paths          | Must be absolute (unix-style or Windows-style for guest plugins).      |
| `threshold_bytes`  | Must be >= 4096.                                                       |
| `ttl_secs`         | Must be >= 1.                                                          |
| `analysis_timeout` | Must be >= 1.                                                          |
| `log_filter`       | Must be a valid `tracing_subscriber::EnvFilter` directive.             |
| Scoped state       | Requires a `[scope]` section.                                          |

<Note>
  Changing any runtime setting requires rebuilding the plugin (for guest plugins) or restarting the daemon (for host plugins).
</Note>
