# Plugin: Manual Start

**Audience:** Integrators who need a plugin registered with the orchestrator but not started automatically when the agent starts.

Setting `autoStart: false` registers the plugin — the orchestrator knows it exists, its topic permissions are declared, and its settings are available via `/api/PluginSettings/{id}` — but the binary is not launched at agent startup. The plugin runs only when explicitly started on demand. This pattern suits resource-intensive components that should not always be running, plugins that need to start in a specific sequence controlled externally, or components used only for occasional maintenance or diagnostics.

This example uses Windows paths. Apply the path changes from [Plugin: Minimal Linux](/keeperpam/endpoint-privilege-manager/integrations/examples/plugin-minimal-linux.md) or [Plugin: Minimal macOS](/keeperpam/endpoint-privilege-manager/integrations/examples/plugin-minimal-macos.md) for other platforms.

## The Plugin JSON

```json
{
  "id": "MyOnDemand",
  "name": "My On-Demand Component",
  "description": "Registered plugin that starts only when explicitly triggered.",
  "version": "1.0.0",

  "pluginType": "Executable",
  "executablePath": "bin/MyOnDemand/MyOnDemand.exe",
  "supportedPlatforms": ["Windows"],

  "Subscription": {
    "Topic": "MyOnDemand",
    "Qos": 2,
    "CleanSession": true
  },

  "metadata": {
    "mqttRole": ["subscriber", "publisher"],
    "mqttTopics": {
      "publish": ["KeeperLogger"],
      "subscribe": ["MyOnDemand"]
    }
  },

  "startupPriority": 80,
  "autoStart": false,
  "executionContext": "Service",
  "requiresMonitoring": false,
  "autoRestart": false
}
```

## What to Change

<table data-header-hidden="false" data-header-sticky><thead><tr><th width="281.3333740234375">Field</th><th>What to Put Here</th></tr></thead><tbody><tr><td><code>id</code></td><td>A stable, unique identifier matching the filename: <code>MyOnDemand.json</code> for <code>"id": "MyOnDemand"</code>.</td></tr><tr><td><code>executablePath</code></td><td>Full or relative path to your binary.</td></tr><tr><td><code>supportedPlatforms</code></td><td>Platforms you support.</td></tr><tr><td><code>Subscription.Topic</code></td><td>The primary MQTT topic for this plugin. By convention, use the plugin <code>id</code>.</td></tr><tr><td><code>metadata.mqttTopics.publish</code></td><td>Every topic your binary publishes to when it runs. Declare these accurately even though the plugin does not start automatically — the broker enforces them whenever the binary does run.</td></tr><tr><td><code>metadata.mqttTopics.subscribe</code></td><td>Every topic your binary subscribes to beyond the primary <code>Subscription.Topic</code>.</td></tr></tbody></table>

## How This Works

**`autoStart: false`** is the single change that defines this pattern. Everything else — the plugin JSON, the binary, the MQTT topic declarations — is identical to an auto-started plugin. The orchestrator registers the plugin at agent startup but does not launch the binary.

**`requiresMonitoring: false`** and **`autoRestart: false`** follow naturally. Monitoring and auto-restart only make sense for a process that is supposed to stay running. For an on-demand component, the expected behavior is that it runs, does its work, and exits — or stays running until explicitly stopped. The orchestrator should not interpret an exit as a failure requiring a restart.

**`startupPriority: 80`** has no effect on a plugin with `autoStart: false` since nothing is being started at agent startup. It is set to a low-priority value as a convention — if `autoStart` is ever changed to `true`, the plugin will start late in the sequence, giving other components time to initialize first.

**`metadata.mqttTopics` must still be accurate.** Even though the plugin does not start automatically, its topic declarations are registered with the broker when the agent loads the plugin JSON. When the binary does run — however it is started — the broker enforces these permissions. Declare what the binary actually uses, not a placeholder.

**How the plugin gets started.** With `autoStart: false`, the plugin is not started by the orchestrator at agent startup. Starting it requires one of:

* A job task that launches the binary directly via `executablePath` — the most common approach. Create a job with a task pointing at the same binary, triggered on demand or by schedule.
* A product-level orchestration mechanism — confirm available options with your administrator, as these vary by agent version and deployment configuration.

When started via a job task, the binary runs under job task process trust rules — not plugin process trust rules — even though a plugin JSON exists for it. MQTT client ID format, topic permission checks, and Plugin Settings authentication all follow the job task path for that execution. See the [Custom Job Integration Guide](https://claude.ai/integration/custom-job-guide) for job task process trust details.

## Before You Deploy

1. Sign the binary per platform requirements.
2. Place the binary at the path resolved by `executablePath`.
3. Place the JSON file at `{AgentRoot}\Plugins\MyOnDemand.json`. The filename must match `id`.
4. Restart the agent so the orchestrator registers the plugin.
5. Confirm the plugin appears as registered but not running in the agent logs before testing any trigger mechanism.

## Verify

After the agent restarts, the plugin should be registered but not running. Start it via your chosen trigger mechanism, then confirm it connected by checking the agent logs and verifying MQTT activity on the `MyOnDemand` topic. If you are using a job task to trigger it, use `POST /api/Jobs/{jobId}/trigger` and watch for the expected log output:

```powershell
Invoke-RestMethod -Method Post `
  -Uri "https://127.0.0.1:6889/api/Jobs/my-trigger-job/trigger" `
  -ContentType "application/json" `
  -Certificate $adminClientCert `
  -Body "{}"
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.keeper.io/keeperpam/endpoint-privilege-manager/integrations/examples/plugin-manual-start.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
